|
1 | 1 | import { useEffect, useRef } from "react"; |
2 | 2 | import { EventsOn } from "../../../wailsjs/runtime/runtime"; |
3 | 3 | import { events } from "../../events"; |
4 | | -import { logs } from "../../logs"; |
| 4 | +import { LogLevel, logs } from "../../logs"; |
5 | 5 | import { SaveLogs } from "../../../wailsjs/go/main/App"; |
6 | 6 | import { alert } from "../../utils/alert"; |
| 7 | +import { useForm } from "react-hook-form"; |
| 8 | +import clsx from "clsx"; |
| 9 | + |
| 10 | +type FormValues = { |
| 11 | + /* debug | info | error */ |
| 12 | + loglevel: 0 | 1 | 2; |
| 13 | +}; |
7 | 14 |
|
8 | 15 | export const LogsTab = () => { |
9 | 16 | const logsRef = useRef<HTMLDivElement | null>(null); |
| 17 | + const form = useForm<FormValues>({ |
| 18 | + defaultValues: { |
| 19 | + loglevel: 1, |
| 20 | + }, |
| 21 | + }); |
| 22 | + const loglevel = form.watch("loglevel"); |
10 | 23 |
|
11 | 24 | const handleSave = () => { |
12 | | - SaveLogs(logs).catch((err) => alert(String(err), "error")); |
| 25 | + SaveLogs(logs.map(([, msg]) => msg)).catch((err) => |
| 26 | + alert(String(err), "error"), |
| 27 | + ); |
13 | 28 | }; |
14 | 29 |
|
15 | 30 | useEffect(() => { |
16 | 31 | /* add initial logs once */ |
| 32 | + console.log(logs); |
17 | 33 | if (logsRef.current) { |
18 | | - logsRef.current.innerHTML = ""; |
| 34 | + logsRef.current.replaceChildren(); |
19 | 35 | } |
20 | 36 | if (logsRef.current && logs.length) { |
21 | 37 | const LOGS_LIMIT = 1000; |
22 | 38 | const logsSlice = logs.slice(-LOGS_LIMIT); |
23 | | - const textNode = document.createTextNode( |
24 | | - (logs.length > LOGS_LIMIT |
25 | | - ? "\n...only showing the last 1000 logs, for all logs please save them as a file...\n\n" + |
26 | | - logsSlice.join("\n") |
27 | | - : logs.join("\n")) + "\n", |
| 39 | + logsRef.current.appendChild( |
| 40 | + document.createTextNode( |
| 41 | + "\n...only showing the last 1000 logs, for all logs please save them as a file...\n\n", |
| 42 | + ), |
28 | 43 | ); |
29 | | - logsRef.current.appendChild(textNode); |
| 44 | + for (const [loglevel, msg] of logsSlice) { |
| 45 | + const span = document.createElement("span"); |
| 46 | + span.dataset.loglevel = loglevel; |
| 47 | + span.appendChild(document.createTextNode(msg + "\n")); |
| 48 | + logsRef.current.appendChild(span); |
| 49 | + } |
30 | 50 | } |
31 | 51 | }, []); |
32 | 52 |
|
33 | 53 | useEffect(() => { |
34 | | - return EventsOn(events.log, (msg: string) => { |
| 54 | + const handleLogMessageReceived = (level: LogLevel, msg: string) => { |
35 | 55 | /* add new logs as they come in */ |
36 | 56 | requestAnimationFrame(() => { |
37 | 57 | if (logsRef.current) { |
38 | 58 | const isNearBottom = |
39 | 59 | document.documentElement.scrollTop + window.innerHeight >= |
40 | 60 | document.documentElement.scrollHeight - window.innerHeight * 0.1; |
41 | | - const textNode = document.createTextNode(msg + "\n"); |
42 | | - logsRef.current.appendChild(textNode); |
| 61 | + const span = document.createElement("span"); |
| 62 | + span.dataset.loglevel = level; |
| 63 | + span.appendChild(document.createTextNode(msg + "\n")); |
| 64 | + logsRef.current.appendChild(span); |
43 | 65 | if (isNearBottom) { |
44 | 66 | /* scroll bottom if near bottom */ |
45 | 67 | document.documentElement.scrollTop = |
46 | 68 | document.documentElement.scrollHeight; |
47 | 69 | } |
48 | 70 | } |
49 | 71 | }); |
50 | | - }); |
| 72 | + }; |
| 73 | + |
| 74 | + const unsubscribe_debug = EventsOn(events.log.debug, (msg: string) => |
| 75 | + handleLogMessageReceived("debug", msg), |
| 76 | + ); |
| 77 | + const unsubscribe_info = EventsOn(events.log.info, (msg: string) => |
| 78 | + handleLogMessageReceived("info", msg), |
| 79 | + ); |
| 80 | + const unsubscribe_error = EventsOn(events.log.error, (msg: string) => |
| 81 | + handleLogMessageReceived("error", msg), |
| 82 | + ); |
| 83 | + |
| 84 | + return () => { |
| 85 | + unsubscribe_debug(); |
| 86 | + unsubscribe_info(); |
| 87 | + unsubscribe_error(); |
| 88 | + }; |
51 | 89 | }, []); |
52 | 90 |
|
53 | 91 | return ( |
54 | 92 | <div> |
55 | 93 | <div |
56 | 94 | ref={logsRef} |
57 | 95 | key="logs" |
58 | | - className="whitespace-pre-wrap text-xs font-mono w-full overflow-hidden peer" |
| 96 | + className={clsx( |
| 97 | + "whitespace-pre-wrap text-xs font-mono w-full overflow-hidden peer *:data-[loglevel=error]:text-error", |
| 98 | + { |
| 99 | + "*:data-[loglevel=debug]:hidden": loglevel > 0, |
| 100 | + "*:data-[loglevel=info]:hidden": loglevel > 1, |
| 101 | + "*:data-[loglevel=error]:hidden": loglevel > 2, |
| 102 | + }, |
| 103 | + )} |
59 | 104 | /> |
60 | | - <div className="sticky bottom-0 left-0 right-0 py-3 bg-[var(--root-bg,var(--color-base-100))] border-t border-t-base-100 peer-empty:hidden"> |
61 | | - <button className="btn btn-primary btn-xs" onClick={handleSave}> |
62 | | - Save logs |
63 | | - </button> |
| 105 | + <div className="sticky bottom-0 left-0 right-0 py-3 bg-(--root-bg,var(--color-base-100)) border-t border-t-base-100"> |
| 106 | + <div className="flex items-center gap-2"> |
| 107 | + <select |
| 108 | + className="select select-xs w-20" |
| 109 | + {...form.register("loglevel", { valueAsNumber: true })} |
| 110 | + > |
| 111 | + <option value="0">Debug</option> |
| 112 | + <option value="1">Info</option> |
| 113 | + <option value="2">Error</option> |
| 114 | + </select> |
| 115 | + <button className="btn btn-primary btn-xs" onClick={handleSave}> |
| 116 | + Save logs |
| 117 | + </button> |
| 118 | + </div> |
64 | 119 | </div> |
65 | 120 | </div> |
66 | 121 | ); |
|
0 commit comments