@64mb/freelens-power 2.1.0 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. package/README.md +4 -4
  2. package/out/main/common/power-logs.js.map +1 -1
  3. package/out/main/common/resource-search.js.map +1 -1
  4. package/out/main/power-logs-child.js +3 -3
  5. package/out/main/power-logs-child.js.map +1 -1
  6. package/out/main/power-logs-database.js +165 -7
  7. package/out/main/power-logs-database.js.map +1 -1
  8. package/out/main/power-logs-ipc.js +12 -3
  9. package/out/main/power-logs-ipc.js.map +1 -1
  10. package/out/main/power-logs-worker.js +29 -7
  11. package/out/main/power-logs-worker.js.map +1 -1
  12. package/out/main/resource-search-database.js +3 -2
  13. package/out/main/resource-search-database.js.map +1 -1
  14. package/out/main/resource-search.js +2 -1
  15. package/out/main/resource-search.js.map +1 -1
  16. package/out/renderer/_virtual/_global-external_react.js +2 -1
  17. package/out/renderer/ai-context-mutations.js +14 -0
  18. package/out/renderer/ai-context-mutations.js.map +1 -0
  19. package/out/renderer/ai-copy-answer.js +18 -15
  20. package/out/renderer/ai-copy-answer.js.map +1 -1
  21. package/out/renderer/ai-diagnostic-handoff.js +2 -2
  22. package/out/renderer/ai-diagnostic-handoff.js.map +1 -1
  23. package/out/renderer/ai-extras.js +41 -38
  24. package/out/renderer/ai-extras.js.map +1 -1
  25. package/out/renderer/ai-message.js +50 -39
  26. package/out/renderer/ai-message.js.map +1 -1
  27. package/out/renderer/ai-provider-icon.js +39 -32
  28. package/out/renderer/ai-provider-icon.js.map +1 -1
  29. package/out/renderer/ai-resize.js +40 -37
  30. package/out/renderer/ai-resize.js.map +1 -1
  31. package/out/renderer/ai-shortcuts.js +20 -17
  32. package/out/renderer/ai-shortcuts.js.map +1 -1
  33. package/out/renderer/ai-terminal-context.js +42 -48
  34. package/out/renderer/ai-terminal-context.js.map +1 -1
  35. package/out/renderer/ai.js +137 -111
  36. package/out/renderer/ai.js.map +1 -1
  37. package/out/renderer/cluster-icon-colors.js +10 -7
  38. package/out/renderer/cluster-icon-colors.js.map +1 -1
  39. package/out/renderer/cluster-icons.js +47 -40
  40. package/out/renderer/cluster-icons.js.map +1 -1
  41. package/out/renderer/details/service-diagnostics-details.js +25 -23
  42. package/out/renderer/details/service-diagnostics-details.js.map +1 -1
  43. package/out/renderer/diagnostic-explain-button.js +7 -4
  44. package/out/renderer/diagnostic-explain-button.js.map +1 -1
  45. package/out/renderer/diagnostics-screen-finding.js +51 -0
  46. package/out/renderer/diagnostics-screen-finding.js.map +1 -0
  47. package/out/renderer/diagnostics.css.js +1 -1
  48. package/out/renderer/diagnostics.css.js.map +1 -1
  49. package/out/renderer/diagnostics.js +146 -107
  50. package/out/renderer/diagnostics.js.map +1 -1
  51. package/out/renderer/incident-copy-button.js +24 -21
  52. package/out/renderer/incident-copy-button.js.map +1 -1
  53. package/out/renderer/index.js +2 -0
  54. package/out/renderer/index.js.map +1 -1
  55. package/out/renderer/monitoring.js +19 -22
  56. package/out/renderer/monitoring.js.map +1 -1
  57. package/out/renderer/native-tooltip.js +22 -0
  58. package/out/renderer/native-tooltip.js.map +1 -0
  59. package/out/renderer/pod-details-enhancements.js +106 -0
  60. package/out/renderer/pod-details-enhancements.js.map +1 -0
  61. package/out/renderer/power-log-json-cell.js +44 -38
  62. package/out/renderer/power-log-json-cell.js.map +1 -1
  63. package/out/renderer/power-log-json.js +17 -10
  64. package/out/renderer/power-log-json.js.map +1 -1
  65. package/out/renderer/power-log-sql-editor.js +31 -2
  66. package/out/renderer/power-log-sql-editor.js.map +1 -1
  67. package/out/renderer/power-logs-client.js +5 -0
  68. package/out/renderer/power-logs-client.js.map +1 -1
  69. package/out/renderer/power-logs-entrypoints.js +10 -36
  70. package/out/renderer/power-logs-entrypoints.js.map +1 -1
  71. package/out/renderer/power-logs.css.js +9 -2
  72. package/out/renderer/power-logs.css.js.map +1 -1
  73. package/out/renderer/power-logs.js +376 -214
  74. package/out/renderer/power-logs.js.map +1 -1
  75. package/out/renderer/preferences/dashboard-preferences.js +42 -35
  76. package/out/renderer/preferences/dashboard-preferences.js.map +1 -1
  77. package/out/renderer/preferences/logs-preferences.js +1 -1
  78. package/out/renderer/preferences/logs-preferences.js.map +1 -1
  79. package/out/renderer/preferences/monitoring-preferences.js +7 -4
  80. package/out/renderer/preferences/monitoring-preferences.js.map +1 -1
  81. package/out/renderer/preferences/preferences.js +2 -2
  82. package/out/renderer/preferences/preferences.js.map +1 -1
  83. package/out/renderer/preferences/settings-icon-action.js +12 -11
  84. package/out/renderer/preferences/settings-icon-action.js.map +1 -1
  85. package/out/renderer/relationship-map-finding.js +53 -0
  86. package/out/renderer/relationship-map-finding.js.map +1 -0
  87. package/out/renderer/resource-relationships.css.js +6 -0
  88. package/out/renderer/resource-relationships.css.js.map +1 -1
  89. package/out/renderer/resource-relationships.js +94 -47
  90. package/out/renderer/resource-relationships.js.map +1 -1
  91. package/out/renderer/resource-search-client.js.map +1 -1
  92. package/out/renderer/resource-search.js +88 -35
  93. package/out/renderer/resource-search.js.map +1 -1
  94. package/out/renderer/src/common/gateway-relationships.js +8 -7
  95. package/out/renderer/src/common/gateway-relationships.js.map +1 -1
  96. package/out/renderer/src/common/power-log-json-filter-sql.js +12 -0
  97. package/out/renderer/src/common/power-log-json-filter-sql.js.map +1 -1
  98. package/out/renderer/src/common/power-log-json-preset.js +2 -2
  99. package/out/renderer/src/common/power-log-json-preset.js.map +1 -1
  100. package/out/renderer/src/common/power-logs.js.map +1 -1
  101. package/out/renderer/src/common/resource-relationships.js +10 -8
  102. package/out/renderer/src/common/resource-relationships.js.map +1 -1
  103. package/out/renderer/src/common/resource-search.js.map +1 -1
  104. package/out/renderer/welcome.js +16 -1
  105. package/out/renderer/welcome.js.map +1 -1
  106. package/package.json +1 -1
@@ -0,0 +1,106 @@
1
+ const require_extensions = require("./_virtual/_global-external_@freelensapp/extensions.js");
2
+ const require__global_external_mobx = require("./_virtual/_global-external_mobx.js");
3
+ const require__global_external_react_dom = require("./_virtual/_global-external_react-dom.js");
4
+ const require_jsx_runtime = require("./_virtual/_global-external_react/jsx-runtime.js");
5
+ //#region src/renderer/pod-details-enhancements.tsx
6
+ var cellMarker = "data-power-pod-name";
7
+ var hoverMarker = "data-power-pod-name-hover";
8
+ var selector = ".KubeObjectDetails :is(.DeploymentDetails, .ReplicaSetDetails, .StatefulSetDetails, .DaemonSetDetails, .JobDetails, .CronJobDetails, .ReplicationControllerDetails) .PodDetailsList .TableRow .TableCell.name a[href]";
9
+ function podPath(link) {
10
+ try {
11
+ const path = new URL(link.href, window.location.href).searchParams.get("kube-details");
12
+ return path && /^\/api\/v1\/namespaces\/[^/]+\/pods\/[^/]+$/.test(path) ? path : void 0;
13
+ } catch {
14
+ return;
15
+ }
16
+ }
17
+ function startPodDetailsEnhancements() {
18
+ const mounted = /* @__PURE__ */ new Map();
19
+ const style = document.createElement("style");
20
+ style.dataset.freelensPower = "pod-details-enhancements";
21
+ style.textContent = `
22
+ [${cellMarker}] > .power-pod-status { display:inline-flex;align-items:center;vertical-align:middle;margin-right:8px; }
23
+ [${cellMarker}] > .power-pod-status .StatusBrick { margin-right:0; }
24
+ [${hoverMarker}]:hover { background-color:transparent!important; }
25
+ `;
26
+ document.head.append(style);
27
+ let stopped = false;
28
+ let scheduled = false;
29
+ const remove = (link, item) => {
30
+ require__global_external_react_dom.default.unmountComponentAtNode(item.host);
31
+ item.host.remove();
32
+ item.cell.removeAttribute(cellMarker);
33
+ for (const badge of item.badges) badge.removeAttribute(hoverMarker);
34
+ mounted.delete(link);
35
+ };
36
+ const update = () => {
37
+ scheduled = false;
38
+ if (stopped) return;
39
+ const pods = new Map(require_extensions.Renderer.K8sApi.podsStore.items.map((pod) => [pod.selfLink, pod]));
40
+ const links = new Set(document.querySelectorAll(selector));
41
+ for (const [link, item] of mounted) if (!links.has(link) || !pods.has(podPath(link) ?? "")) remove(link, item);
42
+ for (const link of links) {
43
+ const path = podPath(link);
44
+ const pod = path ? pods.get(path) : void 0;
45
+ const cell = link.closest(".TableCell.name");
46
+ if (!pod || !cell) continue;
47
+ let item = mounted.get(link);
48
+ if (!item) {
49
+ const host = document.createElement("span");
50
+ host.className = "power-pod-status";
51
+ const badges = [link.parentElement, link.firstElementChild].filter((element) => !!element && element !== cell);
52
+ item = {
53
+ host,
54
+ cell,
55
+ badges,
56
+ signature: ""
57
+ };
58
+ cell.setAttribute(cellMarker, "");
59
+ for (const badge of badges) badge.setAttribute(hoverMarker, "");
60
+ cell.prepend(host);
61
+ mounted.set(link, item);
62
+ }
63
+ const status = pod.getStatus();
64
+ const message = pod.getStatusMessage();
65
+ const signature = JSON.stringify([
66
+ path,
67
+ status,
68
+ message
69
+ ]);
70
+ if (signature === item.signature) continue;
71
+ item.signature = signature;
72
+ require__global_external_react_dom.default.render(/* @__PURE__ */ require_jsx_runtime.jsx(require_extensions.Renderer.Component.StatusBrick, {
73
+ className: status.toLowerCase(),
74
+ tooltip: message
75
+ }), item.host);
76
+ }
77
+ };
78
+ const schedule = () => {
79
+ if (scheduled || stopped) return;
80
+ scheduled = true;
81
+ queueMicrotask(update);
82
+ };
83
+ const observer = new MutationObserver(schedule);
84
+ observer.observe(document.body, {
85
+ subtree: true,
86
+ childList: true,
87
+ attributes: true,
88
+ attributeFilter: ["href"]
89
+ });
90
+ const stopReaction = require__global_external_mobx.reaction(() => [require_extensions.Renderer.Catalog.activeCluster.get()?.metadata.uid, require_extensions.Renderer.K8sApi.podsStore.items.map((pod) => [
91
+ pod.selfLink,
92
+ pod.getStatus(),
93
+ pod.getStatusMessage()
94
+ ])], schedule, { fireImmediately: true });
95
+ return () => {
96
+ stopped = true;
97
+ observer.disconnect();
98
+ stopReaction();
99
+ for (const [link, item] of mounted) remove(link, item);
100
+ style.remove();
101
+ };
102
+ }
103
+ //#endregion
104
+ exports.startPodDetailsEnhancements = startPodDetailsEnhancements;
105
+
106
+ //# sourceMappingURL=pod-details-enhancements.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pod-details-enhancements.js","names":[],"sources":["../../src/renderer/pod-details-enhancements.tsx"],"sourcesContent":["import { Renderer } from \"@freelensapp/extensions\";\nimport { reaction } from \"mobx\";\nimport ReactDOM from \"react-dom\";\n\nconst cellMarker = \"data-power-pod-name\";\nconst hoverMarker = \"data-power-pod-name-hover\";\nconst selector =\n \".KubeObjectDetails :is(.DeploymentDetails, .ReplicaSetDetails, .StatefulSetDetails, .DaemonSetDetails, .JobDetails, .CronJobDetails, .ReplicationControllerDetails) .PodDetailsList .TableRow .TableCell.name a[href]\";\n\ntype Mounted = {\n host: HTMLSpanElement;\n cell: HTMLElement;\n badges: Element[];\n signature: string;\n};\n\nfunction podPath(link: HTMLAnchorElement): string | undefined {\n try {\n const path = new URL(link.href, window.location.href).searchParams.get(\"kube-details\");\n return path && /^\\/api\\/v1\\/namespaces\\/[^/]+\\/pods\\/[^/]+$/.test(path) ? path : undefined;\n } catch {\n return;\n }\n}\n\nexport function startPodDetailsEnhancements(): () => void {\n const mounted = new Map<HTMLAnchorElement, Mounted>();\n const style = document.createElement(\"style\");\n style.dataset.freelensPower = \"pod-details-enhancements\";\n style.textContent = `\n [${cellMarker}] > .power-pod-status { display:inline-flex;align-items:center;vertical-align:middle;margin-right:8px; }\n [${cellMarker}] > .power-pod-status .StatusBrick { margin-right:0; }\n [${hoverMarker}]:hover { background-color:transparent!important; }\n `;\n document.head.append(style);\n let stopped = false;\n let scheduled = false;\n const remove = (link: HTMLAnchorElement, item: Mounted) => {\n ReactDOM.unmountComponentAtNode(item.host);\n item.host.remove();\n item.cell.removeAttribute(cellMarker);\n for (const badge of item.badges) badge.removeAttribute(hoverMarker);\n mounted.delete(link);\n };\n const update = () => {\n scheduled = false;\n if (stopped) return;\n const pods = new Map(Renderer.K8sApi.podsStore.items.map((pod) => [pod.selfLink, pod]));\n const links = new Set(document.querySelectorAll<HTMLAnchorElement>(selector));\n for (const [link, item] of mounted) {\n if (!links.has(link) || !pods.has(podPath(link) ?? \"\")) remove(link, item);\n }\n for (const link of links) {\n const path = podPath(link);\n const pod = path ? pods.get(path) : undefined;\n const cell = link.closest<HTMLElement>(\".TableCell.name\");\n if (!pod || !cell) continue;\n let item = mounted.get(link);\n if (!item) {\n const host = document.createElement(\"span\");\n host.className = \"power-pod-status\";\n const badges = [link.parentElement, link.firstElementChild].filter(\n (element): element is HTMLElement => !!element && element !== cell,\n );\n item = { host, cell, badges, signature: \"\" };\n cell.setAttribute(cellMarker, \"\");\n for (const badge of badges) badge.setAttribute(hoverMarker, \"\");\n cell.prepend(host);\n mounted.set(link, item);\n }\n const status = pod.getStatus();\n const message = pod.getStatusMessage();\n const signature = JSON.stringify([path, status, message]);\n if (signature === item.signature) continue;\n item.signature = signature;\n ReactDOM.render(<Renderer.Component.StatusBrick className={status.toLowerCase()} tooltip={message} />, item.host);\n }\n };\n const schedule = () => {\n if (scheduled || stopped) return;\n scheduled = true;\n queueMicrotask(update);\n };\n const observer = new MutationObserver(schedule);\n observer.observe(document.body, { subtree: true, childList: true, attributes: true, attributeFilter: [\"href\"] });\n const stopReaction = reaction(\n () => [\n Renderer.Catalog.activeCluster.get()?.metadata.uid,\n Renderer.K8sApi.podsStore.items.map((pod) => [pod.selfLink, pod.getStatus(), pod.getStatusMessage()]),\n ],\n schedule,\n { fireImmediately: true },\n );\n return () => {\n stopped = true;\n observer.disconnect();\n stopReaction();\n for (const [link, item] of mounted) remove(link, item);\n style.remove();\n };\n}\n"],"mappings":"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"}
@@ -1,70 +1,76 @@
1
1
  const require__global_external_react = require("./_virtual/_global-external_react.js");
2
2
  const require_jsx_runtime = require("./_virtual/_global-external_react/jsx-runtime.js");
3
+ const require_native_tooltip = require("./native-tooltip.js");
4
+ const require_date_time = require("./src/common/date-time.js");
3
5
  const require_power_log_sql_level = require("./src/common/power-log-sql-level.js");
4
6
  const require_power_log_json_fields = require("./power-log-json-fields.js");
5
7
  const require_power_log_json = require("./power-log-json.js");
6
8
  const require_power_log_message = require("./power-log-message.js");
7
9
  let electron = require("electron");
8
10
  //#region src/renderer/power-log-json-cell.tsx
9
- function LogJsonCell({ value, column, rawValue, Icon, onFilter }) {
11
+ function LogJsonCell({ value, column, rawValue, Icon }) {
10
12
  const preview = require__global_external_react.useMemo(() => {
11
13
  if (value === null || !/^[\s]*[\[{]/.test(value)) return null;
12
14
  try {
13
15
  const parsed = JSON.parse(value);
14
16
  if (!parsed || typeof parsed !== "object") return null;
15
17
  const compact = require_power_log_json_fields.compactJsonLiteral(value);
16
- return {
17
- text: compact.length > 2048 ? `${compact.slice(0, 2048)}…` : compact,
18
- full: compact,
19
- fieldsEnabled: !require_power_log_json_fields.jsonHasDuplicateKeys(value)
20
- };
18
+ return { text: compact.length > 2048 ? `${compact.slice(0, 2048)}…` : compact };
21
19
  } catch {
22
20
  return null;
23
21
  }
24
22
  }, [value]);
25
23
  const [feedback, setFeedback] = require__global_external_react.useState("");
26
24
  require__global_external_react.useEffect(() => setFeedback(""), [value]);
25
+ if ((column?.toLowerCase() === "timestamp" || column?.toLowerCase() === "minute") && typeof rawValue === "number" && Number.isFinite(new Date(rawValue).getTime())) {
26
+ const formatted = require_date_time.formatDateTime(rawValue);
27
+ return /* @__PURE__ */ require_jsx_runtime.jsx(require_native_tooltip.NativeTooltip, {
28
+ title: `${formatted} · ${rawValue}`,
29
+ children: /* @__PURE__ */ require_jsx_runtime.jsx("span", {
30
+ className: "power-logs-cell",
31
+ children: column?.toLowerCase() === "minute" ? formatted.slice(0, -3) : formatted.slice(-8)
32
+ })
33
+ });
34
+ }
27
35
  if (preview === null) {
28
36
  const level = require_power_log_sql_level.sqlCellLevel(column ?? "", rawValue === void 0 ? value : rawValue);
29
- return /* @__PURE__ */ require_jsx_runtime.jsx("span", {
30
- className: "power-logs-cell",
37
+ return /* @__PURE__ */ require_jsx_runtime.jsx(require_native_tooltip.NativeTooltip, {
31
38
  title: value ?? "NULL",
32
- children: value === null ? "NULL" : level !== "unknown" ? /* @__PURE__ */ require_jsx_runtime.jsx("span", {
33
- className: "power-logs-level-label",
34
- "data-level": level,
35
- children: typeof rawValue === "number" ? value : value.toUpperCase()
36
- }) : /* @__PURE__ */ require_jsx_runtime.jsx(require_power_log_message.LogMessage, { text: value })
39
+ children: /* @__PURE__ */ require_jsx_runtime.jsx("span", {
40
+ className: "power-logs-cell",
41
+ children: value === null ? "NULL" : level !== "unknown" ? /* @__PURE__ */ require_jsx_runtime.jsx("span", {
42
+ className: "power-logs-level-label",
43
+ "data-level": level,
44
+ children: typeof rawValue === "number" ? value : value.toUpperCase()
45
+ }) : /* @__PURE__ */ require_jsx_runtime.jsx(require_power_log_message.LogMessage, { text: value })
46
+ })
37
47
  });
38
48
  }
39
49
  return /* @__PURE__ */ require_jsx_runtime.jsxs("div", {
40
50
  className: "power-logs-cell power-logs-json-cell",
41
51
  children: [
42
- /* @__PURE__ */ require_jsx_runtime.jsx(require_power_log_json.LogJson, {
43
- text: preview.text,
44
- fieldText: preview.full,
45
- fieldsEnabled: preview.fieldsEnabled,
46
- Icon,
47
- onFilter
48
- }),
49
- /* @__PURE__ */ require_jsx_runtime.jsx("button", {
50
- type: "button",
51
- className: "power-logs-json-copy",
52
- "aria-label": "Copy JSON",
52
+ /* @__PURE__ */ require_jsx_runtime.jsx(require_power_log_json.LogJson, { text: preview.text }),
53
+ /* @__PURE__ */ require_jsx_runtime.jsx(require_native_tooltip.NativeTooltip, {
53
54
  title: feedback || "Copy JSON",
54
- onKeyDown: (event) => event.stopPropagation(),
55
- onKeyUp: (event) => event.stopPropagation(),
56
- onClick: (event) => {
57
- event.stopPropagation();
58
- try {
59
- electron.clipboard.writeText(value);
60
- setFeedback("Copied");
61
- } catch {
62
- setFeedback("Unable to copy JSON");
63
- }
64
- },
65
- children: /* @__PURE__ */ require_jsx_runtime.jsx(Icon, {
66
- material: feedback === "Copied" ? "check" : "content_copy",
67
- size: 14
55
+ children: /* @__PURE__ */ require_jsx_runtime.jsx("button", {
56
+ type: "button",
57
+ className: "power-logs-json-copy",
58
+ "aria-label": "Copy JSON",
59
+ onKeyDown: (event) => event.stopPropagation(),
60
+ onKeyUp: (event) => event.stopPropagation(),
61
+ onClick: (event) => {
62
+ event.stopPropagation();
63
+ try {
64
+ electron.clipboard.writeText(require_power_log_json_fields.formatJsonLiteral(value));
65
+ setFeedback("Copied");
66
+ } catch {
67
+ setFeedback("Unable to copy JSON");
68
+ }
69
+ },
70
+ children: /* @__PURE__ */ require_jsx_runtime.jsx(Icon, {
71
+ material: feedback === "Copied" ? "check" : "content_copy",
72
+ size: 14
73
+ })
68
74
  })
69
75
  }),
70
76
  /* @__PURE__ */ require_jsx_runtime.jsx("span", {
@@ -1 +1 @@
1
- {"version":3,"file":"power-log-json-cell.js","names":[],"sources":["../../src/renderer/power-log-json-cell.tsx"],"sourcesContent":["import { clipboard } from \"electron\";\nimport { type ComponentType, useEffect, useMemo, useState } from \"react\";\nimport { sqlCellLevel } from \"../common/power-log-sql-level\";\nimport { LogJson } from \"./power-log-json\";\nimport { compactJsonLiteral, jsonHasDuplicateKeys } from \"./power-log-json-fields\";\nimport { LogMessage } from \"./power-log-message\";\n\nimport type { JsonFieldFilter } from \"../common/power-log-field-filters\";\nimport type { LogCell } from \"../common/power-logs\";\n\nexport function LogJsonCell({\n value,\n column,\n rawValue,\n Icon,\n onFilter,\n}: {\n value: string | null;\n message?: boolean;\n column?: string;\n rawValue?: LogCell;\n onFilter?: (filter: JsonFieldFilter) => void;\n Icon: ComponentType<{ material: string; size?: number }>;\n}) {\n const preview = useMemo(() => {\n if (value === null || !/^[\\s]*[\\[{]/.test(value)) return null;\n try {\n const parsed: unknown = JSON.parse(value);\n if (!parsed || typeof parsed !== \"object\") return null;\n const compact = compactJsonLiteral(value);\n return {\n text: compact.length > 2048 ? `${compact.slice(0, 2048)}…` : compact,\n full: compact,\n fieldsEnabled: !jsonHasDuplicateKeys(value),\n };\n } catch {\n return null;\n }\n }, [value]);\n const [feedback, setFeedback] = useState(\"\");\n useEffect(() => setFeedback(\"\"), [value]);\n if (preview === null) {\n const level = sqlCellLevel(column ?? \"\", rawValue === undefined ? value : rawValue);\n return (\n <span className=\"power-logs-cell\" title={value ?? \"NULL\"}>\n {value === null ? (\n \"NULL\"\n ) : level !== \"unknown\" ? (\n <span className=\"power-logs-level-label\" data-level={level}>\n {typeof rawValue === \"number\" ? value : value.toUpperCase()}\n </span>\n ) : (\n <LogMessage text={value} />\n )}\n </span>\n );\n }\n return (\n <div className=\"power-logs-cell power-logs-json-cell\">\n <LogJson\n text={preview.text}\n fieldText={preview.full}\n fieldsEnabled={preview.fieldsEnabled}\n Icon={Icon}\n onFilter={onFilter}\n />\n <button\n type=\"button\"\n className=\"power-logs-json-copy\"\n aria-label=\"Copy JSON\"\n title={feedback || \"Copy JSON\"}\n onKeyDown={(event) => event.stopPropagation()}\n onKeyUp={(event) => event.stopPropagation()}\n onClick={(event) => {\n event.stopPropagation();\n try {\n clipboard.writeText(value!);\n setFeedback(\"Copied\");\n } catch {\n setFeedback(\"Unable to copy JSON\");\n }\n }}\n >\n <Icon material={feedback === \"Copied\" ? \"check\" : \"content_copy\"} size={14} />\n </button>\n <span className=\"power-logs-json-copy-feedback\" role=\"status\" aria-live=\"polite\">\n {feedback}\n </span>\n </div>\n );\n}\n"],"mappings":";;;;;;;;AAUA,SAAgB,YAAY,EAC1B,OACA,QACA,UACA,MACA,YAQC;CACD,MAAM,UAAU,+BAAA,cAAc;EAC5B,IAAI,UAAU,QAAQ,CAAC,cAAc,KAAK,KAAK,GAAG,OAAO;EACzD,IAAI;GACF,MAAM,SAAkB,KAAK,MAAM,KAAK;GACxC,IAAI,CAAC,UAAU,OAAO,WAAW,UAAU,OAAO;GAClD,MAAM,UAAU,8BAAA,mBAAmB,KAAK;GACxC,OAAO;IACL,MAAM,QAAQ,SAAS,OAAO,GAAG,QAAQ,MAAM,GAAG,IAAI,EAAE,KAAK;IAC7D,MAAM;IACN,eAAe,CAAC,8BAAA,qBAAqB,KAAK;GAC5C;EACF,QAAQ;GACN,OAAO;EACT;CACF,GAAG,CAAC,KAAK,CAAC;CACV,MAAM,CAAC,UAAU,eAAe,+BAAA,SAAS,EAAE;CAC3C,+BAAA,gBAAgB,YAAY,EAAE,GAAG,CAAC,KAAK,CAAC;CACxC,IAAI,YAAY,MAAM;EACpB,MAAM,QAAQ,4BAAA,aAAa,UAAU,IAAI,aAAa,KAAA,IAAY,QAAQ,QAAQ;EAClF,OACE,oCAAA,IAAC,QAAD;GAAM,WAAU;GAAkB,OAAO,SAAS;aAC/C,UAAU,OACT,SACE,UAAU,YACZ,oCAAA,IAAC,QAAD;IAAM,WAAU;IAAyB,cAAY;cAClD,OAAO,aAAa,WAAW,QAAQ,MAAM,YAAY;GACtD,CAAA,IAEN,oCAAA,IAAC,0BAAA,YAAD,EAAY,MAAM,MAAQ,CAAA;EAExB,CAAA;CAEV;CACA,OACE,oCAAA,KAAC,OAAD;EAAK,WAAU;YAAf;GACE,oCAAA,IAAC,uBAAA,SAAD;IACE,MAAM,QAAQ;IACd,WAAW,QAAQ;IACnB,eAAe,QAAQ;IACjB;IACI;GACX,CAAA;GACD,oCAAA,IAAC,UAAD;IACE,MAAK;IACL,WAAU;IACV,cAAW;IACX,OAAO,YAAY;IACnB,YAAY,UAAU,MAAM,gBAAgB;IAC5C,UAAU,UAAU,MAAM,gBAAgB;IAC1C,UAAU,UAAU;KAClB,MAAM,gBAAgB;KACtB,IAAI;MACF,SAAA,UAAU,UAAU,KAAM;MAC1B,YAAY,QAAQ;KACtB,QAAQ;MACN,YAAY,qBAAqB;KACnC;IACF;cAEA,oCAAA,IAAC,MAAD;KAAM,UAAU,aAAa,WAAW,UAAU;KAAgB,MAAM;IAAK,CAAA;GACvE,CAAA;GACR,oCAAA,IAAC,QAAD;IAAM,WAAU;IAAgC,MAAK;IAAS,aAAU;cACrE;GACG,CAAA;EACH;;AAET"}
1
+ {"version":3,"file":"power-log-json-cell.js","names":[],"sources":["../../src/renderer/power-log-json-cell.tsx"],"sourcesContent":["import { clipboard } from \"electron\";\nimport { type ComponentType, useEffect, useMemo, useState } from \"react\";\nimport { formatDateTime } from \"../common/date-time\";\nimport { sqlCellLevel } from \"../common/power-log-sql-level\";\nimport { NativeTooltip } from \"./native-tooltip\";\nimport { LogJson } from \"./power-log-json\";\nimport { compactJsonLiteral, formatJsonLiteral } from \"./power-log-json-fields\";\nimport { LogMessage } from \"./power-log-message\";\n\nimport type { LogCell } from \"../common/power-logs\";\n\nexport function LogJsonCell({\n value,\n column,\n rawValue,\n Icon,\n}: {\n value: string | null;\n message?: boolean;\n column?: string;\n rawValue?: LogCell;\n Icon: ComponentType<{ material: string; size?: number }>;\n}) {\n const preview = useMemo(() => {\n if (value === null || !/^[\\s]*[\\[{]/.test(value)) return null;\n try {\n const parsed: unknown = JSON.parse(value);\n if (!parsed || typeof parsed !== \"object\") return null;\n const compact = compactJsonLiteral(value);\n return {\n text: compact.length > 2048 ? `${compact.slice(0, 2048)}…` : compact,\n };\n } catch {\n return null;\n }\n }, [value]);\n const [feedback, setFeedback] = useState(\"\");\n useEffect(() => setFeedback(\"\"), [value]);\n if (\n (column?.toLowerCase() === \"timestamp\" || column?.toLowerCase() === \"minute\") &&\n typeof rawValue === \"number\" &&\n Number.isFinite(new Date(rawValue).getTime())\n ) {\n const formatted = formatDateTime(rawValue);\n return (\n <NativeTooltip title={`${formatted} · ${rawValue}`}>\n <span className=\"power-logs-cell\">\n {column?.toLowerCase() === \"minute\" ? formatted.slice(0, -3) : formatted.slice(-8)}\n </span>\n </NativeTooltip>\n );\n }\n if (preview === null) {\n const level = sqlCellLevel(column ?? \"\", rawValue === undefined ? value : rawValue);\n return (\n <NativeTooltip title={value ?? \"NULL\"}>\n <span className=\"power-logs-cell\">\n {value === null ? (\n \"NULL\"\n ) : level !== \"unknown\" ? (\n <span className=\"power-logs-level-label\" data-level={level}>\n {typeof rawValue === \"number\" ? value : value.toUpperCase()}\n </span>\n ) : (\n <LogMessage text={value} />\n )}\n </span>\n </NativeTooltip>\n );\n }\n return (\n <div className=\"power-logs-cell power-logs-json-cell\">\n <LogJson text={preview.text} />\n <NativeTooltip title={feedback || \"Copy JSON\"}>\n <button\n type=\"button\"\n className=\"power-logs-json-copy\"\n aria-label=\"Copy JSON\"\n onKeyDown={(event) => event.stopPropagation()}\n onKeyUp={(event) => event.stopPropagation()}\n onClick={(event) => {\n event.stopPropagation();\n try {\n clipboard.writeText(formatJsonLiteral(value!));\n setFeedback(\"Copied\");\n } catch {\n setFeedback(\"Unable to copy JSON\");\n }\n }}\n >\n <Icon material={feedback === \"Copied\" ? \"check\" : \"content_copy\"} size={14} />\n </button>\n </NativeTooltip>\n <span className=\"power-logs-json-copy-feedback\" role=\"status\" aria-live=\"polite\">\n {feedback}\n </span>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;AAWA,SAAgB,YAAY,EAC1B,OACA,QACA,UACA,QAOC;CACD,MAAM,UAAU,+BAAA,cAAc;EAC5B,IAAI,UAAU,QAAQ,CAAC,cAAc,KAAK,KAAK,GAAG,OAAO;EACzD,IAAI;GACF,MAAM,SAAkB,KAAK,MAAM,KAAK;GACxC,IAAI,CAAC,UAAU,OAAO,WAAW,UAAU,OAAO;GAClD,MAAM,UAAU,8BAAA,mBAAmB,KAAK;GACxC,OAAO,EACL,MAAM,QAAQ,SAAS,OAAO,GAAG,QAAQ,MAAM,GAAG,IAAI,EAAE,KAAK,QAC/D;EACF,QAAQ;GACN,OAAO;EACT;CACF,GAAG,CAAC,KAAK,CAAC;CACV,MAAM,CAAC,UAAU,eAAe,+BAAA,SAAS,EAAE;CAC3C,+BAAA,gBAAgB,YAAY,EAAE,GAAG,CAAC,KAAK,CAAC;CACxC,KACG,QAAQ,YAAY,MAAM,eAAe,QAAQ,YAAY,MAAM,aACpE,OAAO,aAAa,YACpB,OAAO,SAAS,IAAI,KAAK,QAAQ,CAAC,CAAC,QAAQ,CAAC,GAC5C;EACA,MAAM,YAAY,kBAAA,eAAe,QAAQ;EACzC,OACE,oCAAA,IAAC,uBAAA,eAAD;GAAe,OAAO,GAAG,UAAU,KAAK;aACtC,oCAAA,IAAC,QAAD;IAAM,WAAU;cACb,QAAQ,YAAY,MAAM,WAAW,UAAU,MAAM,GAAG,EAAE,IAAI,UAAU,MAAM,EAAE;GAC7E,CAAA;EACO,CAAA;CAEnB;CACA,IAAI,YAAY,MAAM;EACpB,MAAM,QAAQ,4BAAA,aAAa,UAAU,IAAI,aAAa,KAAA,IAAY,QAAQ,QAAQ;EAClF,OACE,oCAAA,IAAC,uBAAA,eAAD;GAAe,OAAO,SAAS;aAC7B,oCAAA,IAAC,QAAD;IAAM,WAAU;cACb,UAAU,OACT,SACE,UAAU,YACZ,oCAAA,IAAC,QAAD;KAAM,WAAU;KAAyB,cAAY;eAClD,OAAO,aAAa,WAAW,QAAQ,MAAM,YAAY;IACtD,CAAA,IAEN,oCAAA,IAAC,0BAAA,YAAD,EAAY,MAAM,MAAQ,CAAA;GAExB,CAAA;EACO,CAAA;CAEnB;CACA,OACE,oCAAA,KAAC,OAAD;EAAK,WAAU;YAAf;GACE,oCAAA,IAAC,uBAAA,SAAD,EAAS,MAAM,QAAQ,KAAO,CAAA;GAC9B,oCAAA,IAAC,uBAAA,eAAD;IAAe,OAAO,YAAY;cAChC,oCAAA,IAAC,UAAD;KACE,MAAK;KACL,WAAU;KACV,cAAW;KACX,YAAY,UAAU,MAAM,gBAAgB;KAC5C,UAAU,UAAU,MAAM,gBAAgB;KAC1C,UAAU,UAAU;MAClB,MAAM,gBAAgB;MACtB,IAAI;OACF,SAAA,UAAU,UAAU,8BAAA,kBAAkB,KAAM,CAAC;OAC7C,YAAY,QAAQ;MACtB,QAAQ;OACN,YAAY,qBAAqB;MACnC;KACF;eAEA,oCAAA,IAAC,MAAD;MAAM,UAAU,aAAa,WAAW,UAAU;MAAgB,MAAM;KAAK,CAAA;IACvE,CAAA;GACK,CAAA;GACf,oCAAA,IAAC,QAAD;IAAM,WAAU;IAAgC,MAAK;IAAS,aAAU;cACrE;GACG,CAAA;EACH;;AAET"}
@@ -13,7 +13,6 @@ var fieldButtonStyle = {
13
13
  border: 0,
14
14
  borderRadius: 0,
15
15
  background: "transparent",
16
- color: "inherit",
17
16
  display: "inline-flex",
18
17
  alignItems: "center",
19
18
  justifyContent: "center",
@@ -58,6 +57,8 @@ function LogJson({ text, fieldText, fieldsEnabled = true, Icon, onFilter }) {
58
57
  clearTimeout(leaveTimer.current);
59
58
  const rect = element.getBoundingClientRect();
60
59
  let lineRight = rect.right;
60
+ let actionTop = rect.top;
61
+ let actionHeight = Math.min(rect.height, Number.parseFloat(getComputedStyle(element).lineHeight) || 20);
61
62
  const pre = element.closest("pre");
62
63
  if (pre) {
63
64
  const lineEnd = text.indexOf("\n", start);
@@ -72,7 +73,13 @@ function LogJson({ text, fieldText, fieldsEnabled = true, Icon, onFilter }) {
72
73
  range.setStart(element, 0);
73
74
  range.setEnd(node, remaining);
74
75
  if (typeof range.getClientRects === "function") {
75
- for (const fragment of Array.from(range.getClientRects())) if (Math.abs(fragment.top - rect.top) < Math.max(1, rect.height / 2)) lineRight = Math.max(lineRight, fragment.right);
76
+ const fragments = Array.from(range.getClientRects()).filter((fragment) => fragment.width > 0 && fragment.height > 0);
77
+ if (fragments.length) {
78
+ actionTop = Math.max(...fragments.map((fragment) => fragment.top));
79
+ const lastLine = fragments.filter((fragment) => Math.abs(fragment.top - actionTop) < 1);
80
+ lineRight = Math.max(...lastLine.map((fragment) => fragment.right));
81
+ actionHeight = lastLine[0].height;
82
+ }
76
83
  }
77
84
  break;
78
85
  }
@@ -82,8 +89,9 @@ function LogJson({ text, fieldText, fieldsEnabled = true, Icon, onFilter }) {
82
89
  setActive({
83
90
  field,
84
91
  text: identity,
92
+ lineTop: rect.top,
85
93
  x: Math.max(4, Math.min(lineRight + 4, visibleRight - 64)),
86
- y: Math.max(0, Math.min(rect.top, window.innerHeight - 20))
94
+ y: Math.max(0, Math.min(actionTop + (actionHeight - 20) / 2, window.innerHeight - 20))
87
95
  });
88
96
  setFeedback("");
89
97
  };
@@ -93,7 +101,8 @@ function LogJson({ text, fieldText, fieldsEnabled = true, Icon, onFilter }) {
93
101
  onMouseEnter: field ? (event) => {
94
102
  keepOpen();
95
103
  const element = event.currentTarget;
96
- if (activeField.current?.text === identity && activeField.current.field !== field) hoverTimer.current = setTimeout(() => activate(element), 180);
104
+ const rect = element.getBoundingClientRect();
105
+ if (activeField.current?.text === identity && activeField.current.field !== field && Math.abs(activeField.current.lineTop - rect.top) < 1) hoverTimer.current = setTimeout(() => activate(element), 180);
97
106
  else activate(element);
98
107
  } : void 0,
99
108
  onMouseLeave: field ? () => clearTimeout(hoverTimer.current) : void 0,
@@ -139,6 +148,7 @@ function LogJson({ text, fieldText, fieldsEnabled = true, Icon, onFilter }) {
139
148
  }
140
149
  },
141
150
  children: [pre, selected && /* @__PURE__ */ require_jsx_runtime.jsxs("div", {
151
+ className: "power-log-json-actions",
142
152
  role: "toolbar",
143
153
  "aria-label": "JSON field actions",
144
154
  style: {
@@ -164,7 +174,6 @@ function LogJson({ text, fieldText, fieldsEnabled = true, Icon, onFilter }) {
164
174
  /* @__PURE__ */ require_jsx_runtime.jsx("button", {
165
175
  type: "button",
166
176
  style: fieldButtonStyle,
167
- title: Icon ? void 0 : "Copy value",
168
177
  "aria-label": "Copy value",
169
178
  onClick: () => {
170
179
  try {
@@ -177,14 +186,13 @@ function LogJson({ text, fieldText, fieldsEnabled = true, Icon, onFilter }) {
177
186
  },
178
187
  children: Icon ? /* @__PURE__ */ require_jsx_runtime.jsx(Icon, {
179
188
  material: "content_copy",
180
- size: 14,
189
+ size: 12,
181
190
  tooltip: "Copy value"
182
191
  }) : "⧉"
183
192
  }),
184
193
  onFilter && /* @__PURE__ */ require_jsx_runtime.jsxs(require_jsx_runtime.Fragment, { children: [/* @__PURE__ */ require_jsx_runtime.jsx("button", {
185
194
  type: "button",
186
195
  style: fieldButtonStyle,
187
- title: Icon ? void 0 : "Include value",
188
196
  "aria-label": "Include value",
189
197
  onClick: () => onFilter({
190
198
  path: selected.field.path,
@@ -193,13 +201,12 @@ function LogJson({ text, fieldText, fieldsEnabled = true, Icon, onFilter }) {
193
201
  }),
194
202
  children: Icon ? /* @__PURE__ */ require_jsx_runtime.jsx(Icon, {
195
203
  material: "filter_alt",
196
- size: 14,
204
+ size: 12,
197
205
  tooltip: "Include value"
198
206
  }) : "="
199
207
  }), /* @__PURE__ */ require_jsx_runtime.jsx("button", {
200
208
  type: "button",
201
209
  style: fieldButtonStyle,
202
- title: Icon ? void 0 : "Exclude value",
203
210
  "aria-label": "Exclude value",
204
211
  onClick: () => onFilter({
205
212
  path: selected.field.path,
@@ -208,7 +215,7 @@ function LogJson({ text, fieldText, fieldsEnabled = true, Icon, onFilter }) {
208
215
  }),
209
216
  children: Icon ? /* @__PURE__ */ require_jsx_runtime.jsx(Icon, {
210
217
  material: "filter_alt_off",
211
- size: 14,
218
+ size: 12,
212
219
  tooltip: "Exclude value"
213
220
  }) : "!="
214
221
  })] }),
@@ -1 +1 @@
1
- {"version":3,"file":"power-log-json.js","names":[],"sources":["../../src/renderer/power-log-json.tsx"],"sourcesContent":["import { clipboard } from \"electron\";\nimport { type ComponentType, type CSSProperties, type ReactNode, useEffect, useMemo, useRef, useState } from \"react\";\nimport { type JsonField, jsonFieldLiteral, jsonFields, maxJsonTokens } from \"./power-log-json-fields\";\n\nimport type { JsonFieldFilter } from \"../common/power-log-field-filters\";\n\nexport interface LogJsonProps {\n text: string;\n fieldText?: string;\n fieldsEnabled?: boolean;\n Icon?: ComponentType<{ material: string; size?: number; tooltip?: string }>;\n onFilter?: (filter: JsonFieldFilter) => void;\n}\n\nconst fieldButtonStyle: CSSProperties = {\n width: 20,\n height: 20,\n minHeight: 0,\n minWidth: 0,\n padding: 0,\n margin: 0,\n border: 0,\n borderRadius: 0,\n background: \"transparent\",\n color: \"inherit\",\n display: \"inline-flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n cursor: \"pointer\",\n};\n\nexport function LogJson({ text, fieldText, fieldsEnabled = true, Icon, onFilter }: LogJsonProps) {\n const leaveTimer = useRef<ReturnType<typeof setTimeout>>();\n const hoverTimer = useRef<ReturnType<typeof setTimeout>>();\n const keepOpen = () => {\n clearTimeout(leaveTimer.current);\n clearTimeout(hoverTimer.current);\n };\n useEffect(\n () => () => {\n clearTimeout(leaveTimer.current);\n clearTimeout(hoverTimer.current);\n },\n [],\n );\n const identity = fieldText ?? text;\n const interactive = fieldsEnabled && Boolean(Icon || onFilter);\n const fields = useMemo(\n () => (interactive ? jsonFields(identity) : new Map<number, JsonField>()),\n [identity, interactive],\n );\n const [active, setActive] = useState<{ field: JsonField; text: string; x: number; y: number }>();\n const activeField = useRef(active);\n activeField.current = active;\n const [feedback, setFeedback] = useState(\"\");\n const selected = fieldsEnabled && active?.text === identity ? active : undefined;\n const tokens = useMemo(() => {\n const tokens: ReactNode[] = [];\n const pattern = /\"(?:\\\\.|[^\"\\\\])*\"(?:\\s*:)?|\\b(?:true|false|null)\\b|-?\\d+(?:\\.\\d+)?(?:[eE][+-]?\\d+)?|[\\[{]/g;\n let cursor = 0;\n let count = 0;\n for (const match of text.matchAll(pattern)) {\n if (++count > maxJsonTokens) break;\n const start = match.index!;\n tokens.push(text.slice(cursor, start));\n const value = match[0];\n const key = value.startsWith('\"') && value.endsWith(\":\");\n const kind = key\n ? \"key\"\n : value.startsWith('\"')\n ? \"string\"\n : /^(true|false|null)$/.test(value)\n ? \"literal\"\n : /^[\\[{]$/.test(value)\n ? undefined\n : \"number\";\n const field = fields.get(start);\n const activate = (element: HTMLElement) => {\n if (!field) return;\n clearTimeout(leaveTimer.current);\n const rect = element.getBoundingClientRect();\n let lineRight = rect.right;\n const pre = element.closest(\"pre\");\n if (pre) {\n const lineEnd = text.indexOf(\"\\n\", start);\n let remaining = lineEnd < 0 ? text.length : lineEnd;\n const walker = document.createTreeWalker(pre, NodeFilter.SHOW_TEXT);\n for (let node = walker.nextNode(); node; node = walker.nextNode()) {\n if (remaining > (node.textContent?.length ?? 0)) {\n remaining -= node.textContent?.length ?? 0;\n continue;\n }\n const range = document.createRange();\n range.setStart(element, 0);\n range.setEnd(node, remaining);\n if (typeof range.getClientRects === \"function\") {\n for (const fragment of Array.from(range.getClientRects())) {\n if (Math.abs(fragment.top - rect.top) < Math.max(1, rect.height / 2)) {\n lineRight = Math.max(lineRight, fragment.right);\n }\n }\n }\n break;\n }\n }\n const wrapperRight = element.closest(\".power-log-json-fields\")?.getBoundingClientRect().right;\n const visibleRight = Math.min(\n window.innerWidth,\n wrapperRight && wrapperRight > 0 ? wrapperRight : window.innerWidth,\n );\n setActive({\n field,\n text: identity,\n x: Math.max(4, Math.min(lineRight + 4, visibleRight - 64)),\n y: Math.max(0, Math.min(rect.top, window.innerHeight - 20)),\n });\n setFeedback(\"\");\n };\n tokens.push(\n <span\n key={start}\n data-token={kind}\n tabIndex={field ? 0 : undefined}\n onMouseEnter={\n field\n ? (event) => {\n keepOpen();\n const element = event.currentTarget;\n if (activeField.current?.text === identity && activeField.current.field !== field) {\n hoverTimer.current = setTimeout(() => activate(element), 180);\n } else activate(element);\n }\n : undefined\n }\n onMouseLeave={field ? () => clearTimeout(hoverTimer.current) : undefined}\n onFocus={\n field\n ? (event) => {\n keepOpen();\n activate(event.currentTarget);\n }\n : undefined\n }\n onKeyDown={\n field\n ? (event) => {\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n event.stopPropagation();\n event.currentTarget\n .closest(\".power-log-json-fields\")\n ?.querySelector<HTMLButtonElement>('[role=\"toolbar\"] button')\n ?.focus();\n }\n }\n : undefined\n }\n >\n {key ? value.slice(0, -1) : value}\n </span>,\n );\n if (key) tokens.push(\":\");\n cursor = start + value.length;\n }\n tokens.push(text.slice(cursor));\n return tokens;\n }, [text, fields, identity]);\n const pre = <pre className=\"power-log-json\">{tokens}</pre>;\n if (!Icon && !onFilter) return pre;\n return (\n <div\n className=\"power-log-json-fields\"\n style={{ paddingRight: 76 }}\n onMouseEnter={keepOpen}\n onMouseLeave={() => {\n leaveTimer.current = setTimeout(() => setActive(undefined), 150);\n }}\n onBlur={(event) => {\n if (!event.currentTarget.contains(event.relatedTarget as Node)) setActive(undefined);\n }}\n onKeyDown={(event) => {\n if (event.key === \"Escape\") {\n event.stopPropagation();\n setActive(undefined);\n }\n }}\n >\n {pre}\n {selected && (\n <div\n role=\"toolbar\"\n aria-label=\"JSON field actions\"\n style={{\n position: \"fixed\",\n left: selected.x,\n top: selected.y,\n zIndex: 1000,\n display: \"flex\",\n gap: 2,\n padding: 0,\n background: \"transparent\",\n border: 0,\n alignItems: \"center\",\n height: 20,\n }}\n onMouseEnter={keepOpen}\n onClick={(event) => event.stopPropagation()}\n onKeyDown={(event) => {\n event.stopPropagation();\n if (event.key === \"Escape\") setActive(undefined);\n }}\n >\n <button\n type=\"button\"\n style={fieldButtonStyle}\n title={Icon ? undefined : \"Copy value\"}\n aria-label=\"Copy value\"\n onClick={() => {\n try {\n const value = selected.field.value;\n clipboard.writeText(typeof value === \"string\" ? value : jsonFieldLiteral(identity, selected.field));\n setFeedback(\"Copied\");\n } catch {\n setFeedback(\"Copy failed\");\n }\n }}\n >\n {Icon ? <Icon material=\"content_copy\" size={14} tooltip=\"Copy value\" /> : \"⧉\"}\n </button>\n {onFilter && (\n <>\n <button\n type=\"button\"\n style={fieldButtonStyle}\n title={Icon ? undefined : \"Include value\"}\n aria-label=\"Include value\"\n onClick={() => onFilter({ path: selected.field.path, value: selected.field.value, operator: \"eq\" })}\n >\n {Icon ? <Icon material=\"filter_alt\" size={14} tooltip=\"Include value\" /> : \"=\"}\n </button>\n <button\n type=\"button\"\n style={fieldButtonStyle}\n title={Icon ? undefined : \"Exclude value\"}\n aria-label=\"Exclude value\"\n onClick={() => onFilter({ path: selected.field.path, value: selected.field.value, operator: \"neq\" })}\n >\n {Icon ? <Icon material=\"filter_alt_off\" size={14} tooltip=\"Exclude value\" /> : \"!=\"}\n </button>\n </>\n )}\n {feedback && (\n <span role=\"status\" style={{ position: \"absolute\", top: 22, right: 0, whiteSpace: \"nowrap\" }}>\n {feedback}\n </span>\n )}\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"power-log-json.js","names":[],"sources":["../../src/renderer/power-log-json.tsx"],"sourcesContent":["import { clipboard } from \"electron\";\nimport { type ComponentType, type CSSProperties, type ReactNode, useEffect, useMemo, useRef, useState } from \"react\";\nimport { type JsonField, jsonFieldLiteral, jsonFields, maxJsonTokens } from \"./power-log-json-fields\";\n\nimport type { JsonFieldFilter } from \"../common/power-log-field-filters\";\n\nexport interface LogJsonProps {\n text: string;\n fieldText?: string;\n fieldsEnabled?: boolean;\n Icon?: ComponentType<{ material: string; size?: number; tooltip?: string }>;\n onFilter?: (filter: JsonFieldFilter) => void;\n}\n\nconst fieldButtonStyle: CSSProperties = {\n width: 20,\n height: 20,\n minHeight: 0,\n minWidth: 0,\n padding: 0,\n margin: 0,\n border: 0,\n borderRadius: 0,\n background: \"transparent\",\n display: \"inline-flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n cursor: \"pointer\",\n};\n\nexport function LogJson({ text, fieldText, fieldsEnabled = true, Icon, onFilter }: LogJsonProps) {\n const leaveTimer = useRef<ReturnType<typeof setTimeout>>();\n const hoverTimer = useRef<ReturnType<typeof setTimeout>>();\n const keepOpen = () => {\n clearTimeout(leaveTimer.current);\n clearTimeout(hoverTimer.current);\n };\n useEffect(\n () => () => {\n clearTimeout(leaveTimer.current);\n clearTimeout(hoverTimer.current);\n },\n [],\n );\n const identity = fieldText ?? text;\n const interactive = fieldsEnabled && Boolean(Icon || onFilter);\n const fields = useMemo(\n () => (interactive ? jsonFields(identity) : new Map<number, JsonField>()),\n [identity, interactive],\n );\n const [active, setActive] = useState<{ field: JsonField; text: string; x: number; y: number; lineTop: number }>();\n const activeField = useRef(active);\n activeField.current = active;\n const [feedback, setFeedback] = useState(\"\");\n const selected = fieldsEnabled && active?.text === identity ? active : undefined;\n const tokens = useMemo(() => {\n const tokens: ReactNode[] = [];\n const pattern = /\"(?:\\\\.|[^\"\\\\])*\"(?:\\s*:)?|\\b(?:true|false|null)\\b|-?\\d+(?:\\.\\d+)?(?:[eE][+-]?\\d+)?|[\\[{]/g;\n let cursor = 0;\n let count = 0;\n for (const match of text.matchAll(pattern)) {\n if (++count > maxJsonTokens) break;\n const start = match.index!;\n tokens.push(text.slice(cursor, start));\n const value = match[0];\n const key = value.startsWith('\"') && value.endsWith(\":\");\n const kind = key\n ? \"key\"\n : value.startsWith('\"')\n ? \"string\"\n : /^(true|false|null)$/.test(value)\n ? \"literal\"\n : /^[\\[{]$/.test(value)\n ? undefined\n : \"number\";\n const field = fields.get(start);\n const activate = (element: HTMLElement) => {\n if (!field) return;\n clearTimeout(leaveTimer.current);\n const rect = element.getBoundingClientRect();\n let lineRight = rect.right;\n let actionTop = rect.top;\n let actionHeight = Math.min(rect.height, Number.parseFloat(getComputedStyle(element).lineHeight) || 20);\n const pre = element.closest(\"pre\");\n if (pre) {\n const lineEnd = text.indexOf(\"\\n\", start);\n let remaining = lineEnd < 0 ? text.length : lineEnd;\n const walker = document.createTreeWalker(pre, NodeFilter.SHOW_TEXT);\n for (let node = walker.nextNode(); node; node = walker.nextNode()) {\n if (remaining > (node.textContent?.length ?? 0)) {\n remaining -= node.textContent?.length ?? 0;\n continue;\n }\n const range = document.createRange();\n range.setStart(element, 0);\n range.setEnd(node, remaining);\n if (typeof range.getClientRects === \"function\") {\n const fragments = Array.from(range.getClientRects()).filter(\n (fragment) => fragment.width > 0 && fragment.height > 0,\n );\n if (fragments.length) {\n actionTop = Math.max(...fragments.map((fragment) => fragment.top));\n const lastLine = fragments.filter((fragment) => Math.abs(fragment.top - actionTop) < 1);\n lineRight = Math.max(...lastLine.map((fragment) => fragment.right));\n actionHeight = lastLine[0].height;\n }\n }\n break;\n }\n }\n const wrapperRight = element.closest(\".power-log-json-fields\")?.getBoundingClientRect().right;\n const visibleRight = Math.min(\n window.innerWidth,\n wrapperRight && wrapperRight > 0 ? wrapperRight : window.innerWidth,\n );\n setActive({\n field,\n text: identity,\n lineTop: rect.top,\n x: Math.max(4, Math.min(lineRight + 4, visibleRight - 64)),\n y: Math.max(0, Math.min(actionTop + (actionHeight - 20) / 2, window.innerHeight - 20)),\n });\n setFeedback(\"\");\n };\n tokens.push(\n <span\n key={start}\n data-token={kind}\n tabIndex={field ? 0 : undefined}\n onMouseEnter={\n field\n ? (event) => {\n keepOpen();\n const element = event.currentTarget;\n const rect = element.getBoundingClientRect();\n if (\n activeField.current?.text === identity &&\n activeField.current.field !== field &&\n Math.abs(activeField.current.lineTop - rect.top) < 1\n ) {\n hoverTimer.current = setTimeout(() => activate(element), 180);\n } else activate(element);\n }\n : undefined\n }\n onMouseLeave={field ? () => clearTimeout(hoverTimer.current) : undefined}\n onFocus={\n field\n ? (event) => {\n keepOpen();\n activate(event.currentTarget);\n }\n : undefined\n }\n onKeyDown={\n field\n ? (event) => {\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n event.stopPropagation();\n event.currentTarget\n .closest(\".power-log-json-fields\")\n ?.querySelector<HTMLButtonElement>('[role=\"toolbar\"] button')\n ?.focus();\n }\n }\n : undefined\n }\n >\n {key ? value.slice(0, -1) : value}\n </span>,\n );\n if (key) tokens.push(\":\");\n cursor = start + value.length;\n }\n tokens.push(text.slice(cursor));\n return tokens;\n }, [text, fields, identity]);\n const pre = <pre className=\"power-log-json\">{tokens}</pre>;\n if (!Icon && !onFilter) return pre;\n return (\n <div\n className=\"power-log-json-fields\"\n style={{ paddingRight: 76 }}\n onMouseEnter={keepOpen}\n onMouseLeave={() => {\n leaveTimer.current = setTimeout(() => setActive(undefined), 150);\n }}\n onBlur={(event) => {\n if (!event.currentTarget.contains(event.relatedTarget as Node)) setActive(undefined);\n }}\n onKeyDown={(event) => {\n if (event.key === \"Escape\") {\n event.stopPropagation();\n setActive(undefined);\n }\n }}\n >\n {pre}\n {selected && (\n <div\n className=\"power-log-json-actions\"\n role=\"toolbar\"\n aria-label=\"JSON field actions\"\n style={{\n position: \"fixed\",\n left: selected.x,\n top: selected.y,\n zIndex: 1000,\n display: \"flex\",\n gap: 2,\n padding: 0,\n background: \"transparent\",\n border: 0,\n alignItems: \"center\",\n height: 20,\n }}\n onMouseEnter={keepOpen}\n onClick={(event) => event.stopPropagation()}\n onKeyDown={(event) => {\n event.stopPropagation();\n if (event.key === \"Escape\") setActive(undefined);\n }}\n >\n <button\n type=\"button\"\n style={fieldButtonStyle}\n aria-label=\"Copy value\"\n onClick={() => {\n try {\n const value = selected.field.value;\n clipboard.writeText(typeof value === \"string\" ? value : jsonFieldLiteral(identity, selected.field));\n setFeedback(\"Copied\");\n } catch {\n setFeedback(\"Copy failed\");\n }\n }}\n >\n {Icon ? <Icon material=\"content_copy\" size={12} tooltip=\"Copy value\" /> : \"⧉\"}\n </button>\n {onFilter && (\n <>\n <button\n type=\"button\"\n style={fieldButtonStyle}\n aria-label=\"Include value\"\n onClick={() => onFilter({ path: selected.field.path, value: selected.field.value, operator: \"eq\" })}\n >\n {Icon ? <Icon material=\"filter_alt\" size={12} tooltip=\"Include value\" /> : \"=\"}\n </button>\n <button\n type=\"button\"\n style={fieldButtonStyle}\n aria-label=\"Exclude value\"\n onClick={() => onFilter({ path: selected.field.path, value: selected.field.value, operator: \"neq\" })}\n >\n {Icon ? <Icon material=\"filter_alt_off\" size={12} tooltip=\"Exclude value\" /> : \"!=\"}\n </button>\n </>\n )}\n {feedback && (\n <span role=\"status\" style={{ position: \"absolute\", top: 22, right: 0, whiteSpace: \"nowrap\" }}>\n {feedback}\n </span>\n )}\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
@@ -26,7 +26,7 @@ function tokenizeSql(value) {
26
26
  return tokens;
27
27
  }
28
28
  var styles = `
29
- .power-logs .power-logs-sql-editor{position:relative;box-sizing:border-box;width:100%;height:56px;min-height:48px;max-height:120px;flex-shrink:0;resize:vertical;overflow:hidden;border:1px solid var(--borderColor);border-radius:4px;background:var(--inputControlBackground,var(--contentColor));--sql-string:#e6a28c;--sql-number:#98c78e;--sql-function:#81b9e6;--sql-identifier:var(--textColorPrimary)}
29
+ .power-logs .power-logs-sql-editor{position:relative;box-sizing:border-box;width:100%;height:56px;min-height:48px;max-height:var(--sql-content-max-height,120px);flex-shrink:0;resize:vertical;overflow:hidden;border:1px solid var(--borderColor);border-radius:4px;background:var(--inputControlBackground,var(--contentColor));--sql-string:#e6a28c;--sql-number:#98c78e;--sql-function:#81b9e6;--sql-identifier:var(--textColorPrimary)}
30
30
  .power-logs .power-logs-sql-editor::-webkit-resizer{border:0;background:linear-gradient(135deg,transparent 45%,var(--borderColor) 46% 53%,transparent 54% 70%,var(--borderColor) 71% 78%,transparent 79%) center/10px 10px no-repeat}
31
31
  .theme-light .power-logs-sql-editor{--sql-string:#9e2b1a;--sql-number:#17642d;--sql-function:#005a9e;--sql-identifier:#684c9b}
32
32
  .power-logs .power-logs-sql-editor>textarea,.power-logs .power-logs-sql-editor>pre{position:absolute;inset:0;box-sizing:border-box;width:100%;height:100%;min-height:0;max-height:none;margin:0;padding:4px 8px;border:0;border-radius:0;font:12px/1.6 var(--font-monospace,monospace);letter-spacing:normal;white-space:pre-wrap;overflow-wrap:anywhere;tab-size:2;overflow:auto;scrollbar-gutter:stable;resize:none}
@@ -40,7 +40,8 @@ var styles = `
40
40
  .power-logs-sql-editor [data-sql-token=number]{color:var(--sql-number)}
41
41
  .power-logs-sql-editor [data-sql-token=comment]{color:var(--textColorSecondary)}
42
42
  `;
43
- function SqlEditor({ id, value, onChange }) {
43
+ function SqlEditor({ id, value, onChange, fitVersion = 0 }) {
44
+ const fitted = require__global_external_react.useRef(0);
44
45
  const textarea = require__global_external_react.useRef(null);
45
46
  const highlight = require__global_external_react.useRef(null);
46
47
  const tokens = require__global_external_react.useMemo(() => tokenizeSql(value), [value]);
@@ -50,6 +51,34 @@ function SqlEditor({ id, value, onChange }) {
50
51
  highlight.current.scrollLeft = textarea.current.scrollLeft;
51
52
  };
52
53
  require__global_external_react.useLayoutEffect(syncScroll, [value]);
54
+ require__global_external_react.useLayoutEffect(() => {
55
+ const pre = highlight.current;
56
+ const editor = pre?.parentElement;
57
+ if (!pre || !editor) return;
58
+ const measure = () => {
59
+ pre.style.height = "auto";
60
+ pre.style.bottom = "auto";
61
+ const height = pre.getBoundingClientRect().height;
62
+ pre.style.removeProperty("height");
63
+ pre.style.removeProperty("bottom");
64
+ editor.style.setProperty("--sql-content-max-height", `${Math.max(120, Math.min(240, Math.ceil(height) + 10))}px`);
65
+ if (fitVersion !== fitted.current) {
66
+ editor.style.height = `${Math.max(48, Math.min(240, Math.ceil(height) + 2))}px`;
67
+ fitted.current = fitVersion;
68
+ }
69
+ syncScroll();
70
+ };
71
+ measure();
72
+ let width = editor.clientWidth;
73
+ if (typeof ResizeObserver === "undefined") return;
74
+ const observer = new ResizeObserver(() => {
75
+ if (editor.clientWidth === width) return;
76
+ width = editor.clientWidth;
77
+ measure();
78
+ });
79
+ observer.observe(editor);
80
+ return () => observer.disconnect();
81
+ }, [value, fitVersion]);
53
82
  const selectQuery = (event) => {
54
83
  if (event.detail < 3) return;
55
84
  event.preventDefault();
@@ -1 +1 @@
1
- {"version":3,"file":"power-log-sql-editor.js","names":[],"sources":["../../src/renderer/power-log-sql-editor.tsx"],"sourcesContent":["import { useLayoutEffect, useMemo, useRef } from \"react\";\n\nimport type { MouseEvent } from \"react\";\n\ntype SqlToken = { text: string; kind?: \"keyword\" | \"function\" | \"string\" | \"identifier\" | \"number\" | \"comment\" };\nconst keywords = new Set(\n \"SELECT FROM WHERE AS AND OR NOT NULL IS IN LIKE GLOB BETWEEN EXISTS CASE WHEN THEN ELSE END DISTINCT ALL JOIN LEFT RIGHT INNER OUTER CROSS FULL ON USING GROUP BY HAVING ORDER ASC DESC LIMIT OFFSET UNION INTERSECT EXCEPT WITH RECURSIVE OVER PARTITION ROWS RANGE UNBOUNDED PRECEDING FOLLOWING CURRENT ROW NULLS FIRST LAST TRUE FALSE COLLATE CAST FILTER WINDOW VALUES EXPLAIN QUERY PLAN\".split(\n \" \",\n ),\n);\nconst lexeme =\n /--[^\\n]*(?:\\n|$)|\\/\\*[\\s\\S]*?(?:\\*\\/|$)|'(?:''|[^'])*(?:'|$)|\"(?:\"\"|[^\"])*(?:\"|$)|`(?:``|[^`])*(?:`|$)|\\[[^\\]]*(?:\\]|$)|\\b(?:0x[\\da-f]+|\\d+(?:\\.\\d*)?(?:e[+-]?\\d+)?)(?![\\w])|\\b[a-z_]\\w*\\b/gi;\n\nfunction isFunction(source: string, offset: number): boolean {\n while (offset < source.length && /\\s/.test(source[offset])) offset++;\n return source[offset] === \"(\";\n}\n\nexport function tokenizeSql(value: string): SqlToken[] {\n const source = value.slice(0, 65536);\n const tokens: SqlToken[] = [];\n let offset = 0;\n lexeme.lastIndex = 0;\n for (let match = lexeme.exec(source); match && tokens.length < 9998; match = lexeme.exec(source)) {\n if (match.index > offset) tokens.push({ text: source.slice(offset, match.index) });\n const text = match[0];\n const kind =\n text.startsWith(\"--\") || text.startsWith(\"/*\")\n ? \"comment\"\n : text.startsWith(\"'\")\n ? \"string\"\n : text.startsWith('\"') || text.startsWith(\"`\") || text.startsWith(\"[\")\n ? \"identifier\"\n : /^\\d/.test(text)\n ? \"number\"\n : keywords.has(text.toUpperCase())\n ? \"keyword\"\n : isFunction(source, match.index + text.length)\n ? \"function\"\n : undefined;\n tokens.push({ text, kind });\n offset = match.index + text.length;\n }\n if (offset < value.length) tokens.push({ text: value.slice(offset) });\n return tokens;\n}\n\nconst styles = `\n.power-logs .power-logs-sql-editor{position:relative;box-sizing:border-box;width:100%;height:56px;min-height:48px;max-height:120px;flex-shrink:0;resize:vertical;overflow:hidden;border:1px solid var(--borderColor);border-radius:4px;background:var(--inputControlBackground,var(--contentColor));--sql-string:#e6a28c;--sql-number:#98c78e;--sql-function:#81b9e6;--sql-identifier:var(--textColorPrimary)}\n.power-logs .power-logs-sql-editor::-webkit-resizer{border:0;background:linear-gradient(135deg,transparent 45%,var(--borderColor) 46% 53%,transparent 54% 70%,var(--borderColor) 71% 78%,transparent 79%) center/10px 10px no-repeat}\n.theme-light .power-logs-sql-editor{--sql-string:#9e2b1a;--sql-number:#17642d;--sql-function:#005a9e;--sql-identifier:#684c9b}\n.power-logs .power-logs-sql-editor>textarea,.power-logs .power-logs-sql-editor>pre{position:absolute;inset:0;box-sizing:border-box;width:100%;height:100%;min-height:0;max-height:none;margin:0;padding:4px 8px;border:0;border-radius:0;font:12px/1.6 var(--font-monospace,monospace);letter-spacing:normal;white-space:pre-wrap;overflow-wrap:anywhere;tab-size:2;overflow:auto;scrollbar-gutter:stable;resize:none}\n.power-logs .power-logs-sql-editor>pre{pointer-events:none;color:var(--textColorPrimary);background:transparent;user-select:none}\n.power-logs .power-logs-sql-editor>textarea{color:transparent;background:transparent;caret-color:var(--textColorPrimary);-webkit-text-fill-color:transparent}\n.power-logs .power-logs-sql-editor>textarea::selection{background:rgba(100,150,240,.35);color:transparent}\n.power-logs-sql-editor [data-sql-token=keyword]{color:var(--primary)}\n.power-logs-sql-editor [data-sql-token=function]{color:var(--sql-function)}\n.power-logs-sql-editor [data-sql-token=string]{color:var(--sql-string)}\n.power-logs-sql-editor [data-sql-token=identifier]{color:var(--sql-identifier)}\n.power-logs-sql-editor [data-sql-token=number]{color:var(--sql-number)}\n.power-logs-sql-editor [data-sql-token=comment]{color:var(--textColorSecondary)}\n`;\n\nexport function SqlEditor({ id, value, onChange }: { id: string; value: string; onChange(value: string): void }) {\n const textarea = useRef<HTMLTextAreaElement>(null);\n const highlight = useRef<HTMLPreElement>(null);\n const tokens = useMemo(() => tokenizeSql(value), [value]);\n const syncScroll = () => {\n if (!textarea.current || !highlight.current) return;\n highlight.current.scrollTop = textarea.current.scrollTop;\n highlight.current.scrollLeft = textarea.current.scrollLeft;\n };\n useLayoutEffect(syncScroll, [value]);\n const selectQuery = (event: MouseEvent<HTMLTextAreaElement>) => {\n if (event.detail < 3) return;\n event.preventDefault();\n event.stopPropagation();\n window.getSelection()?.removeAllRanges();\n event.currentTarget.focus();\n event.currentTarget.select();\n };\n return (\n <div className=\"power-logs-sql-editor\">\n <style>{styles}</style>\n <pre ref={highlight} aria-hidden=\"true\">\n {tokens.map((token, index) => (\n <span key={index} data-sql-token={token.kind}>\n {token.text}\n </span>\n ))}\n {value.endsWith(\"\\n\") && \" \"}\n </pre>\n <textarea\n ref={textarea}\n id={id}\n value={value}\n maxLength={65536}\n spellCheck={false}\n onChange={(event) => onChange(event.target.value.slice(0, 65536))}\n onScroll={syncScroll}\n onMouseDown={selectQuery}\n onClick={selectQuery}\n />\n </div>\n );\n}\n"],"mappings":";;;AAKA,IAAM,WAAW,IAAI,IACnB,kYAAkY,MAChY,GACF,CACF;AACA,IAAM,SACJ;AAEF,SAAS,WAAW,QAAgB,QAAyB;CAC3D,OAAO,SAAS,OAAO,UAAU,KAAK,KAAK,OAAO,OAAO,GAAG;CAC5D,OAAO,OAAO,YAAY;AAC5B;AAEA,SAAgB,YAAY,OAA2B;CACrD,MAAM,SAAS,MAAM,MAAM,GAAG,KAAK;CACnC,MAAM,SAAqB,CAAC;CAC5B,IAAI,SAAS;CACb,OAAO,YAAY;CACnB,KAAK,IAAI,QAAQ,OAAO,KAAK,MAAM,GAAG,SAAS,OAAO,SAAS,MAAM,QAAQ,OAAO,KAAK,MAAM,GAAG;EAChG,IAAI,MAAM,QAAQ,QAAQ,OAAO,KAAK,EAAE,MAAM,OAAO,MAAM,QAAQ,MAAM,KAAK,EAAE,CAAC;EACjF,MAAM,OAAO,MAAM;EACnB,MAAM,OACJ,KAAK,WAAW,IAAI,KAAK,KAAK,WAAW,IAAI,IACzC,YACA,KAAK,WAAW,GAAG,IACjB,WACA,KAAK,WAAW,IAAG,KAAK,KAAK,WAAW,GAAG,KAAK,KAAK,WAAW,GAAG,IACjE,eACA,MAAM,KAAK,IAAI,IACb,WACA,SAAS,IAAI,KAAK,YAAY,CAAC,IAC7B,YACA,WAAW,QAAQ,MAAM,QAAQ,KAAK,MAAM,IAC1C,aACA,KAAA;EAChB,OAAO,KAAK;GAAE;GAAM;EAAK,CAAC;EAC1B,SAAS,MAAM,QAAQ,KAAK;CAC9B;CACA,IAAI,SAAS,MAAM,QAAQ,OAAO,KAAK,EAAE,MAAM,MAAM,MAAM,MAAM,EAAE,CAAC;CACpE,OAAO;AACT;AAEA,IAAM,SAAS;;;;;;;;;;;;;;;AAgBf,SAAgB,UAAU,EAAE,IAAI,OAAO,YAA0E;CAC/G,MAAM,WAAW,+BAAA,OAA4B,IAAI;CACjD,MAAM,YAAY,+BAAA,OAAuB,IAAI;CAC7C,MAAM,SAAS,+BAAA,cAAc,YAAY,KAAK,GAAG,CAAC,KAAK,CAAC;CACxD,MAAM,mBAAmB;EACvB,IAAI,CAAC,SAAS,WAAW,CAAC,UAAU,SAAS;EAC7C,UAAU,QAAQ,YAAY,SAAS,QAAQ;EAC/C,UAAU,QAAQ,aAAa,SAAS,QAAQ;CAClD;CACA,+BAAA,gBAAgB,YAAY,CAAC,KAAK,CAAC;CACnC,MAAM,eAAe,UAA2C;EAC9D,IAAI,MAAM,SAAS,GAAG;EACtB,MAAM,eAAe;EACrB,MAAM,gBAAgB;EACtB,OAAO,aAAa,CAAC,EAAE,gBAAgB;EACvC,MAAM,cAAc,MAAM;EAC1B,MAAM,cAAc,OAAO;CAC7B;CACA,OACE,oCAAA,KAAC,OAAD;EAAK,WAAU;YAAf;GACE,oCAAA,IAAC,SAAD,EAAA,UAAQ,OAAc,CAAA;GACtB,oCAAA,KAAC,OAAD;IAAK,KAAK;IAAW,eAAY;cAAjC,CACG,OAAO,KAAK,OAAO,UAClB,oCAAA,IAAC,QAAD;KAAkB,kBAAgB,MAAM;eACrC,MAAM;IACH,GAFK,KAEL,CACP,GACA,MAAM,SAAS,IAAI,KAAK,GACtB;;GACL,oCAAA,IAAC,YAAD;IACE,KAAK;IACD;IACG;IACP,WAAW;IACX,YAAY;IACZ,WAAW,UAAU,SAAS,MAAM,OAAO,MAAM,MAAM,GAAG,KAAK,CAAC;IAChE,UAAU;IACV,aAAa;IACb,SAAS;GACV,CAAA;EACE;;AAET"}
1
+ {"version":3,"file":"power-log-sql-editor.js","names":[],"sources":["../../src/renderer/power-log-sql-editor.tsx"],"sourcesContent":["import { useLayoutEffect, useMemo, useRef } from \"react\";\n\nimport type { MouseEvent } from \"react\";\n\ntype SqlToken = { text: string; kind?: \"keyword\" | \"function\" | \"string\" | \"identifier\" | \"number\" | \"comment\" };\nconst keywords = new Set(\n \"SELECT FROM WHERE AS AND OR NOT NULL IS IN LIKE GLOB BETWEEN EXISTS CASE WHEN THEN ELSE END DISTINCT ALL JOIN LEFT RIGHT INNER OUTER CROSS FULL ON USING GROUP BY HAVING ORDER ASC DESC LIMIT OFFSET UNION INTERSECT EXCEPT WITH RECURSIVE OVER PARTITION ROWS RANGE UNBOUNDED PRECEDING FOLLOWING CURRENT ROW NULLS FIRST LAST TRUE FALSE COLLATE CAST FILTER WINDOW VALUES EXPLAIN QUERY PLAN\".split(\n \" \",\n ),\n);\nconst lexeme =\n /--[^\\n]*(?:\\n|$)|\\/\\*[\\s\\S]*?(?:\\*\\/|$)|'(?:''|[^'])*(?:'|$)|\"(?:\"\"|[^\"])*(?:\"|$)|`(?:``|[^`])*(?:`|$)|\\[[^\\]]*(?:\\]|$)|\\b(?:0x[\\da-f]+|\\d+(?:\\.\\d*)?(?:e[+-]?\\d+)?)(?![\\w])|\\b[a-z_]\\w*\\b/gi;\n\nfunction isFunction(source: string, offset: number): boolean {\n while (offset < source.length && /\\s/.test(source[offset])) offset++;\n return source[offset] === \"(\";\n}\n\nexport function tokenizeSql(value: string): SqlToken[] {\n const source = value.slice(0, 65536);\n const tokens: SqlToken[] = [];\n let offset = 0;\n lexeme.lastIndex = 0;\n for (let match = lexeme.exec(source); match && tokens.length < 9998; match = lexeme.exec(source)) {\n if (match.index > offset) tokens.push({ text: source.slice(offset, match.index) });\n const text = match[0];\n const kind =\n text.startsWith(\"--\") || text.startsWith(\"/*\")\n ? \"comment\"\n : text.startsWith(\"'\")\n ? \"string\"\n : text.startsWith('\"') || text.startsWith(\"`\") || text.startsWith(\"[\")\n ? \"identifier\"\n : /^\\d/.test(text)\n ? \"number\"\n : keywords.has(text.toUpperCase())\n ? \"keyword\"\n : isFunction(source, match.index + text.length)\n ? \"function\"\n : undefined;\n tokens.push({ text, kind });\n offset = match.index + text.length;\n }\n if (offset < value.length) tokens.push({ text: value.slice(offset) });\n return tokens;\n}\n\nconst styles = `\n.power-logs .power-logs-sql-editor{position:relative;box-sizing:border-box;width:100%;height:56px;min-height:48px;max-height:var(--sql-content-max-height,120px);flex-shrink:0;resize:vertical;overflow:hidden;border:1px solid var(--borderColor);border-radius:4px;background:var(--inputControlBackground,var(--contentColor));--sql-string:#e6a28c;--sql-number:#98c78e;--sql-function:#81b9e6;--sql-identifier:var(--textColorPrimary)}\n.power-logs .power-logs-sql-editor::-webkit-resizer{border:0;background:linear-gradient(135deg,transparent 45%,var(--borderColor) 46% 53%,transparent 54% 70%,var(--borderColor) 71% 78%,transparent 79%) center/10px 10px no-repeat}\n.theme-light .power-logs-sql-editor{--sql-string:#9e2b1a;--sql-number:#17642d;--sql-function:#005a9e;--sql-identifier:#684c9b}\n.power-logs .power-logs-sql-editor>textarea,.power-logs .power-logs-sql-editor>pre{position:absolute;inset:0;box-sizing:border-box;width:100%;height:100%;min-height:0;max-height:none;margin:0;padding:4px 8px;border:0;border-radius:0;font:12px/1.6 var(--font-monospace,monospace);letter-spacing:normal;white-space:pre-wrap;overflow-wrap:anywhere;tab-size:2;overflow:auto;scrollbar-gutter:stable;resize:none}\n.power-logs .power-logs-sql-editor>pre{pointer-events:none;color:var(--textColorPrimary);background:transparent;user-select:none}\n.power-logs .power-logs-sql-editor>textarea{color:transparent;background:transparent;caret-color:var(--textColorPrimary);-webkit-text-fill-color:transparent}\n.power-logs .power-logs-sql-editor>textarea::selection{background:rgba(100,150,240,.35);color:transparent}\n.power-logs-sql-editor [data-sql-token=keyword]{color:var(--primary)}\n.power-logs-sql-editor [data-sql-token=function]{color:var(--sql-function)}\n.power-logs-sql-editor [data-sql-token=string]{color:var(--sql-string)}\n.power-logs-sql-editor [data-sql-token=identifier]{color:var(--sql-identifier)}\n.power-logs-sql-editor [data-sql-token=number]{color:var(--sql-number)}\n.power-logs-sql-editor [data-sql-token=comment]{color:var(--textColorSecondary)}\n`;\n\nexport function SqlEditor({\n id,\n value,\n onChange,\n fitVersion = 0,\n}: {\n id: string;\n value: string;\n onChange(value: string): void;\n fitVersion?: number;\n}) {\n const fitted = useRef(0);\n const textarea = useRef<HTMLTextAreaElement>(null);\n const highlight = useRef<HTMLPreElement>(null);\n const tokens = useMemo(() => tokenizeSql(value), [value]);\n const syncScroll = () => {\n if (!textarea.current || !highlight.current) return;\n highlight.current.scrollTop = textarea.current.scrollTop;\n highlight.current.scrollLeft = textarea.current.scrollLeft;\n };\n useLayoutEffect(syncScroll, [value]);\n useLayoutEffect(() => {\n const pre = highlight.current;\n const editor = pre?.parentElement;\n if (!pre || !editor) return;\n const measure = () => {\n pre.style.height = \"auto\";\n pre.style.bottom = \"auto\";\n const height = pre.getBoundingClientRect().height;\n pre.style.removeProperty(\"height\");\n pre.style.removeProperty(\"bottom\");\n editor.style.setProperty(\"--sql-content-max-height\", `${Math.max(120, Math.min(240, Math.ceil(height) + 10))}px`);\n if (fitVersion !== fitted.current) {\n editor.style.height = `${Math.max(48, Math.min(240, Math.ceil(height) + 2))}px`;\n fitted.current = fitVersion;\n }\n syncScroll();\n };\n measure();\n let width = editor.clientWidth;\n if (typeof ResizeObserver === \"undefined\") return;\n const observer = new ResizeObserver(() => {\n if (editor.clientWidth === width) return;\n width = editor.clientWidth;\n measure();\n });\n observer.observe(editor);\n return () => observer.disconnect();\n }, [value, fitVersion]);\n const selectQuery = (event: MouseEvent<HTMLTextAreaElement>) => {\n if (event.detail < 3) return;\n event.preventDefault();\n event.stopPropagation();\n window.getSelection()?.removeAllRanges();\n event.currentTarget.focus();\n event.currentTarget.select();\n };\n return (\n <div className=\"power-logs-sql-editor\">\n <style>{styles}</style>\n <pre ref={highlight} aria-hidden=\"true\">\n {tokens.map((token, index) => (\n <span key={index} data-sql-token={token.kind}>\n {token.text}\n </span>\n ))}\n {value.endsWith(\"\\n\") && \" \"}\n </pre>\n <textarea\n ref={textarea}\n id={id}\n value={value}\n maxLength={65536}\n spellCheck={false}\n onChange={(event) => onChange(event.target.value.slice(0, 65536))}\n onScroll={syncScroll}\n onMouseDown={selectQuery}\n onClick={selectQuery}\n />\n </div>\n );\n}\n"],"mappings":";;;AAKA,IAAM,WAAW,IAAI,IACnB,kYAAkY,MAChY,GACF,CACF;AACA,IAAM,SACJ;AAEF,SAAS,WAAW,QAAgB,QAAyB;CAC3D,OAAO,SAAS,OAAO,UAAU,KAAK,KAAK,OAAO,OAAO,GAAG;CAC5D,OAAO,OAAO,YAAY;AAC5B;AAEA,SAAgB,YAAY,OAA2B;CACrD,MAAM,SAAS,MAAM,MAAM,GAAG,KAAK;CACnC,MAAM,SAAqB,CAAC;CAC5B,IAAI,SAAS;CACb,OAAO,YAAY;CACnB,KAAK,IAAI,QAAQ,OAAO,KAAK,MAAM,GAAG,SAAS,OAAO,SAAS,MAAM,QAAQ,OAAO,KAAK,MAAM,GAAG;EAChG,IAAI,MAAM,QAAQ,QAAQ,OAAO,KAAK,EAAE,MAAM,OAAO,MAAM,QAAQ,MAAM,KAAK,EAAE,CAAC;EACjF,MAAM,OAAO,MAAM;EACnB,MAAM,OACJ,KAAK,WAAW,IAAI,KAAK,KAAK,WAAW,IAAI,IACzC,YACA,KAAK,WAAW,GAAG,IACjB,WACA,KAAK,WAAW,IAAG,KAAK,KAAK,WAAW,GAAG,KAAK,KAAK,WAAW,GAAG,IACjE,eACA,MAAM,KAAK,IAAI,IACb,WACA,SAAS,IAAI,KAAK,YAAY,CAAC,IAC7B,YACA,WAAW,QAAQ,MAAM,QAAQ,KAAK,MAAM,IAC1C,aACA,KAAA;EAChB,OAAO,KAAK;GAAE;GAAM;EAAK,CAAC;EAC1B,SAAS,MAAM,QAAQ,KAAK;CAC9B;CACA,IAAI,SAAS,MAAM,QAAQ,OAAO,KAAK,EAAE,MAAM,MAAM,MAAM,MAAM,EAAE,CAAC;CACpE,OAAO;AACT;AAEA,IAAM,SAAS;;;;;;;;;;;;;;;AAgBf,SAAgB,UAAU,EACxB,IACA,OACA,UACA,aAAa,KAMZ;CACD,MAAM,SAAS,+BAAA,OAAO,CAAC;CACvB,MAAM,WAAW,+BAAA,OAA4B,IAAI;CACjD,MAAM,YAAY,+BAAA,OAAuB,IAAI;CAC7C,MAAM,SAAS,+BAAA,cAAc,YAAY,KAAK,GAAG,CAAC,KAAK,CAAC;CACxD,MAAM,mBAAmB;EACvB,IAAI,CAAC,SAAS,WAAW,CAAC,UAAU,SAAS;EAC7C,UAAU,QAAQ,YAAY,SAAS,QAAQ;EAC/C,UAAU,QAAQ,aAAa,SAAS,QAAQ;CAClD;CACA,+BAAA,gBAAgB,YAAY,CAAC,KAAK,CAAC;CACnC,+BAAA,sBAAsB;EACpB,MAAM,MAAM,UAAU;EACtB,MAAM,SAAS,KAAK;EACpB,IAAI,CAAC,OAAO,CAAC,QAAQ;EACrB,MAAM,gBAAgB;GACpB,IAAI,MAAM,SAAS;GACnB,IAAI,MAAM,SAAS;GACnB,MAAM,SAAS,IAAI,sBAAsB,CAAC,CAAC;GAC3C,IAAI,MAAM,eAAe,QAAQ;GACjC,IAAI,MAAM,eAAe,QAAQ;GACjC,OAAO,MAAM,YAAY,4BAA4B,GAAG,KAAK,IAAI,KAAK,KAAK,IAAI,KAAK,KAAK,KAAK,MAAM,IAAI,EAAE,CAAC,EAAE,GAAG;GAChH,IAAI,eAAe,OAAO,SAAS;IACjC,OAAO,MAAM,SAAS,GAAG,KAAK,IAAI,IAAI,KAAK,IAAI,KAAK,KAAK,KAAK,MAAM,IAAI,CAAC,CAAC,EAAE;IAC5E,OAAO,UAAU;GACnB;GACA,WAAW;EACb;EACA,QAAQ;EACR,IAAI,QAAQ,OAAO;EACnB,IAAI,OAAO,mBAAmB,aAAa;EAC3C,MAAM,WAAW,IAAI,qBAAqB;GACxC,IAAI,OAAO,gBAAgB,OAAO;GAClC,QAAQ,OAAO;GACf,QAAQ;EACV,CAAC;EACD,SAAS,QAAQ,MAAM;EACvB,aAAa,SAAS,WAAW;CACnC,GAAG,CAAC,OAAO,UAAU,CAAC;CACtB,MAAM,eAAe,UAA2C;EAC9D,IAAI,MAAM,SAAS,GAAG;EACtB,MAAM,eAAe;EACrB,MAAM,gBAAgB;EACtB,OAAO,aAAa,CAAC,EAAE,gBAAgB;EACvC,MAAM,cAAc,MAAM;EAC1B,MAAM,cAAc,OAAO;CAC7B;CACA,OACE,oCAAA,KAAC,OAAD;EAAK,WAAU;YAAf;GACE,oCAAA,IAAC,SAAD,EAAA,UAAQ,OAAc,CAAA;GACtB,oCAAA,KAAC,OAAD;IAAK,KAAK;IAAW,eAAY;cAAjC,CACG,OAAO,KAAK,OAAO,UAClB,oCAAA,IAAC,QAAD;KAAkB,kBAAgB,MAAM;eACrC,MAAM;IACH,GAFK,KAEL,CACP,GACA,MAAM,SAAS,IAAI,KAAK,GACtB;;GACL,oCAAA,IAAC,YAAD;IACE,KAAK;IACD;IACG;IACP,WAAW;IACX,YAAY;IACZ,WAAW,UAAU,SAAS,MAAM,OAAO,MAAM,MAAM,GAAG,KAAK,CAAC;IAChE,UAAU;IACV,aAAa;IACb,SAAS;GACV,CAAA;EACE;;AAET"}
@@ -8,6 +8,7 @@ function createPowerLogsClient(partition) {
8
8
  ...fields
9
9
  });
10
10
  return {
11
+ clearPersistent: () => invoke("clear-persistent"),
11
12
  list: () => invoke("list"),
12
13
  create: (target) => invoke("create", { target }),
13
14
  append: (captureId, records) => invoke("append", {
@@ -20,6 +21,10 @@ function createPowerLogsClient(partition) {
20
21
  notes
21
22
  }),
22
23
  delete: (captureId) => invoke("delete", { captureId }),
24
+ setPersistent: (captureId, persistent) => invoke("set-persistent", {
25
+ captureId,
26
+ persistent
27
+ }),
23
28
  saveSql: (captureId, sql) => invoke("save-sql", {
24
29
  captureId,
25
30
  sql
@@ -1 +1 @@
1
- {"version":3,"file":"power-logs-client.js","names":[],"sources":["../../src/renderer/power-logs-client.ts"],"sourcesContent":["import { ipcRenderer } from \"electron\";\nimport {\n type LogCapture,\n type LogPartition,\n type LogQueryResult,\n type LogRecord,\n type LogTarget,\n POWER_LOGS_CHANNEL,\n} from \"../common/power-logs\";\n\nexport function createPowerLogsClient(partition: LogPartition) {\n const invoke = <T>(operation: string, fields: object = {}): Promise<T> =>\n ipcRenderer.invoke(POWER_LOGS_CHANNEL, { ...partition, operation, ...fields });\n return {\n list: () => invoke<LogCapture[]>(\"list\"),\n create: (target: LogTarget) => invoke<LogCapture>(\"create\", { target }),\n append: (captureId: string, records: LogRecord[]) => invoke<LogCapture>(\"append\", { captureId, records }),\n finish: (captureId: string, partial: boolean, notes: string[]) =>\n invoke<LogCapture>(\"finish\", { captureId, partial, notes }),\n delete: (captureId: string) => invoke<boolean>(\"delete\", { captureId }),\n saveSql: (captureId: string, sql: string) => invoke<LogCapture>(\"save-sql\", { captureId, sql }),\n query: (captureId: string, queryId: string, sql: string) =>\n invoke<LogQueryResult>(\"query\", { captureId, queryId, sql }),\n cancel: (queryId: string) => invoke<boolean>(\"cancel\", { queryId }),\n export: (captureId: string) => invoke<boolean>(\"export\", { captureId }),\n };\n}\n"],"mappings":";;;AAUA,SAAgB,sBAAsB,WAAyB;CAC7D,MAAM,UAAa,WAAmB,SAAiB,CAAC,MACtD,SAAA,YAAY,OAAO,mBAAA,oBAAoB;EAAE,GAAG;EAAW;EAAW,GAAG;CAAO,CAAC;CAC/E,OAAO;EACL,YAAY,OAAqB,MAAM;EACvC,SAAS,WAAsB,OAAmB,UAAU,EAAE,OAAO,CAAC;EACtE,SAAS,WAAmB,YAAyB,OAAmB,UAAU;GAAE;GAAW;EAAQ,CAAC;EACxG,SAAS,WAAmB,SAAkB,UAC5C,OAAmB,UAAU;GAAE;GAAW;GAAS;EAAM,CAAC;EAC5D,SAAS,cAAsB,OAAgB,UAAU,EAAE,UAAU,CAAC;EACtE,UAAU,WAAmB,QAAgB,OAAmB,YAAY;GAAE;GAAW;EAAI,CAAC;EAC9F,QAAQ,WAAmB,SAAiB,QAC1C,OAAuB,SAAS;GAAE;GAAW;GAAS;EAAI,CAAC;EAC7D,SAAS,YAAoB,OAAgB,UAAU,EAAE,QAAQ,CAAC;EAClE,SAAS,cAAsB,OAAgB,UAAU,EAAE,UAAU,CAAC;CACxE;AACF"}
1
+ {"version":3,"file":"power-logs-client.js","names":[],"sources":["../../src/renderer/power-logs-client.ts"],"sourcesContent":["import { ipcRenderer } from \"electron\";\nimport {\n type LogCapture,\n type LogPartition,\n type LogQueryResult,\n type LogRecord,\n type LogTarget,\n POWER_LOGS_CHANNEL,\n} from \"../common/power-logs\";\n\nexport function createPowerLogsClient(partition: LogPartition) {\n const invoke = <T>(operation: string, fields: object = {}): Promise<T> =>\n ipcRenderer.invoke(POWER_LOGS_CHANNEL, { ...partition, operation, ...fields });\n return {\n clearPersistent: () => invoke<boolean>(\"clear-persistent\"),\n list: () => invoke<LogCapture[]>(\"list\"),\n create: (target: LogTarget) => invoke<LogCapture>(\"create\", { target }),\n append: (captureId: string, records: LogRecord[]) => invoke<LogCapture>(\"append\", { captureId, records }),\n finish: (captureId: string, partial: boolean, notes: string[]) =>\n invoke<LogCapture>(\"finish\", { captureId, partial, notes }),\n delete: (captureId: string) => invoke<boolean>(\"delete\", { captureId }),\n setPersistent: (captureId: string, persistent: boolean) =>\n invoke<LogCapture>(\"set-persistent\", { captureId, persistent }),\n saveSql: (captureId: string, sql: string) => invoke<LogCapture>(\"save-sql\", { captureId, sql }),\n query: (captureId: string, queryId: string, sql: string) =>\n invoke<LogQueryResult>(\"query\", { captureId, queryId, sql }),\n cancel: (queryId: string) => invoke<boolean>(\"cancel\", { queryId }),\n export: (captureId: string) => invoke<boolean>(\"export\", { captureId }),\n };\n}\n"],"mappings":";;;AAUA,SAAgB,sBAAsB,WAAyB;CAC7D,MAAM,UAAa,WAAmB,SAAiB,CAAC,MACtD,SAAA,YAAY,OAAO,mBAAA,oBAAoB;EAAE,GAAG;EAAW;EAAW,GAAG;CAAO,CAAC;CAC/E,OAAO;EACL,uBAAuB,OAAgB,kBAAkB;EACzD,YAAY,OAAqB,MAAM;EACvC,SAAS,WAAsB,OAAmB,UAAU,EAAE,OAAO,CAAC;EACtE,SAAS,WAAmB,YAAyB,OAAmB,UAAU;GAAE;GAAW;EAAQ,CAAC;EACxG,SAAS,WAAmB,SAAkB,UAC5C,OAAmB,UAAU;GAAE;GAAW;GAAS;EAAM,CAAC;EAC5D,SAAS,cAAsB,OAAgB,UAAU,EAAE,UAAU,CAAC;EACtE,gBAAgB,WAAmB,eACjC,OAAmB,kBAAkB;GAAE;GAAW;EAAW,CAAC;EAChE,UAAU,WAAmB,QAAgB,OAAmB,YAAY;GAAE;GAAW;EAAI,CAAC;EAC9F,QAAQ,WAAmB,SAAiB,QAC1C,OAAuB,SAAS;GAAE;GAAW;GAAS;EAAI,CAAC;EAC7D,SAAS,YAAoB,OAAgB,UAAU,EAAE,QAAQ,CAAC;EAClE,SAAS,cAAsB,OAAgB,UAAU,EAAE,UAAU,CAAC;CACxE;AACF"}