@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
@@ -5,6 +5,7 @@ const require_dashboard = require("../src/common/dashboard.js");
5
5
  const require_dashboard_preferences_store = require("../src/common/store/dashboard-preferences-store.js");
6
6
  const require__global_external_react = require("../_virtual/_global-external_react.js");
7
7
  const require_jsx_runtime = require("../_virtual/_global-external_react/jsx-runtime.js");
8
+ const require_native_tooltip = require("../native-tooltip.js");
8
9
  const require_settings_modal = require("./settings-modal.js");
9
10
  const require_dashboard_views = require("../src/common/dashboard-views.js");
10
11
  const require_settings_icon_action = require("./settings-icon-action.js");
@@ -313,25 +314,27 @@ var DashboardPreferences = require__global_external_mobx_react.observer(() => {
313
314
  opacity: draggingId === card.id ? .5 : 1
314
315
  },
315
316
  children: [
316
- /* @__PURE__ */ require_jsx_runtime.jsx("button", {
317
- type: "button",
318
- className: "power-dashboard-drag-handle",
319
- draggable: true,
320
- "aria-label": `Reorder ${card.title}`,
317
+ /* @__PURE__ */ require_jsx_runtime.jsx(require_native_tooltip.NativeTooltip, {
321
318
  title: "Drag to reorder, or use the Up and Down arrow keys",
322
- onDragStart: (event) => {
323
- event.dataTransfer.effectAllowed = "move";
324
- event.dataTransfer.setData("text/plain", card.id);
325
- setDraggingId(card.id);
326
- },
327
- onDragEnd: finishDrag,
328
- onKeyDown: (event) => {
329
- if (event.key !== "ArrowUp" && event.key !== "ArrowDown") return;
330
- event.preventDefault();
331
- event.stopPropagation();
332
- moveCard(card, Math.max(0, Math.min(preferences.cards.length - 1, index + (event.key === "ArrowUp" ? -1 : 1))));
333
- },
334
- children: /* @__PURE__ */ require_jsx_runtime.jsx(Icon, { material: "drag_indicator" })
319
+ children: /* @__PURE__ */ require_jsx_runtime.jsx("button", {
320
+ type: "button",
321
+ className: "power-dashboard-drag-handle",
322
+ draggable: true,
323
+ "aria-label": `Reorder ${card.title}`,
324
+ onDragStart: (event) => {
325
+ event.dataTransfer.effectAllowed = "move";
326
+ event.dataTransfer.setData("text/plain", card.id);
327
+ setDraggingId(card.id);
328
+ },
329
+ onDragEnd: finishDrag,
330
+ onKeyDown: (event) => {
331
+ if (event.key !== "ArrowUp" && event.key !== "ArrowDown") return;
332
+ event.preventDefault();
333
+ event.stopPropagation();
334
+ moveCard(card, Math.max(0, Math.min(preferences.cards.length - 1, index + (event.key === "ArrowUp" ? -1 : 1))));
335
+ },
336
+ children: /* @__PURE__ */ require_jsx_runtime.jsx(Icon, { material: "drag_indicator" })
337
+ })
335
338
  }),
336
339
  /* @__PURE__ */ require_jsx_runtime.jsx(WebsiteIcon, {
337
340
  url: card.url,
@@ -342,25 +345,29 @@ var DashboardPreferences = require__global_external_mobx_react.observer(() => {
342
345
  flex: 1,
343
346
  minWidth: 0
344
347
  },
345
- children: [/* @__PURE__ */ require_jsx_runtime.jsx("div", {
348
+ children: [/* @__PURE__ */ require_jsx_runtime.jsx(require_native_tooltip.NativeTooltip, {
346
349
  title: card.title,
347
- style: {
348
- fontWeight: 600,
349
- overflow: "hidden",
350
- textOverflow: "ellipsis",
351
- whiteSpace: "nowrap"
352
- },
353
- children: card.title
354
- }), /* @__PURE__ */ require_jsx_runtime.jsx("div", {
355
- className: "power-settings-hint",
350
+ children: /* @__PURE__ */ require_jsx_runtime.jsx("div", {
351
+ style: {
352
+ fontWeight: 600,
353
+ overflow: "hidden",
354
+ textOverflow: "ellipsis",
355
+ whiteSpace: "nowrap"
356
+ },
357
+ children: card.title
358
+ })
359
+ }), /* @__PURE__ */ require_jsx_runtime.jsx(require_native_tooltip.NativeTooltip, {
356
360
  title: card.url,
357
- style: {
358
- overflow: "hidden",
359
- textOverflow: "ellipsis",
360
- whiteSpace: "nowrap",
361
- marginTop: 3
362
- },
363
- children: card.url
361
+ children: /* @__PURE__ */ require_jsx_runtime.jsx("div", {
362
+ className: "power-settings-hint",
363
+ style: {
364
+ overflow: "hidden",
365
+ textOverflow: "ellipsis",
366
+ whiteSpace: "nowrap",
367
+ marginTop: 3
368
+ },
369
+ children: card.url
370
+ })
364
371
  })]
365
372
  }),
366
373
  /* @__PURE__ */ require_jsx_runtime.jsxs("span", {
@@ -1 +1 @@
1
- {"version":3,"file":"dashboard-preferences.js","names":[],"sources":["../../../src/renderer/preferences/dashboard-preferences.tsx"],"sourcesContent":["import { Renderer } from \"@freelensapp/extensions\";\nimport { ipcRenderer } from \"electron\";\nimport { observer } from \"mobx-react\";\nimport { useEffect, useState } from \"react\";\nimport { type DashboardCard, type DashboardCardSize, normalizeDashboardUrl } from \"../../common/dashboard\";\nimport { DASHBOARD_PICK_ELEMENT, type DashboardPickerResult } from \"../../common/dashboard-picker\";\nimport { dashboardSelectorLimit, normalizeDashboardSelector } from \"../../common/dashboard-selector\";\nimport { DASHBOARD_SITE_ICONS, type DashboardSiteIcon } from \"../../common/dashboard-views\";\nimport { DashboardPreferencesStore } from \"../../common/store/dashboard-preferences-store\";\nimport { SettingsIconAction } from \"./settings-icon-action\";\nimport { SettingsField, SettingsModal } from \"./settings-modal\";\n\nconst { Input, Select, Button, Icon, Checkbox } = Renderer.Component;\nconst sizeOptions = [\n { value: \"xs\" as const, label: \"XS · Extra small\" },\n { value: \"s\" as const, label: \"S · Small\" },\n { value: \"m\" as const, label: \"M · Medium\" },\n { value: \"l\" as const, label: \"L · Large\" },\n { value: \"xl\" as const, label: \"XL · Extra large\" },\n];\n\nfunction CardEditor({\n card,\n onSave,\n onClose,\n}: {\n card?: DashboardCard;\n onSave: (card: DashboardCard) => void;\n onClose: () => void;\n}) {\n const [title, setTitle] = useState(card?.title ?? \"\");\n const [url, setUrl] = useState(card?.url ?? \"\");\n const [size, setSize] = useState<DashboardCardSize>(card?.size ?? \"m\");\n const [autoRefresh, setAutoRefresh] = useState(card ? card.autoRefresh === true : true);\n const [selector, setSelector] = useState(card?.selector ?? \"\");\n const selectorInvalid = selector.trim().length > 0 && !normalizeDashboardSelector(selector);\n const [picking, setPicking] = useState(false);\n const [pickerError, setPickerError] = useState(false);\n const [submitted, setSubmitted] = useState(false);\n const id = `freelens-power-dashboard-${card?.id ?? \"new\"}`;\n const normalizedUrl = normalizeDashboardUrl(url);\n const invalid = (submitted || url.length > 0) && !normalizedUrl;\n\n function save() {\n setSubmitted(true);\n if (!normalizedUrl || selectorInvalid) return;\n onSave({\n id: card?.id ?? crypto.randomUUID(),\n title: title.trim() || new URL(normalizedUrl).hostname,\n url: normalizedUrl,\n size,\n autoRefresh,\n ...(card?.refreshEvery10Seconds ? { refreshEvery10Seconds: true } : {}),\n selector: normalizeDashboardSelector(selector),\n });\n onClose();\n }\n\n return (\n <SettingsModal id={id} title={card ? \"Edit card\" : \"Add a card\"} onClose={onClose}>\n <SettingsField id={`${id}-title`} label=\"Title\">\n <Input autoFocus id={`${id}-title`} value={title} placeholder=\"Website name\" onChange={setTitle} />\n </SettingsField>\n <SettingsField id={`${id}-url`} label=\"URL\">\n <Input\n id={`${id}-url`}\n value={url}\n placeholder=\"https://example.com\"\n onChange={setUrl}\n aria-invalid={invalid}\n aria-describedby={invalid ? `${id}-error` : undefined}\n />\n {invalid && (\n <div id={`${id}-error`} role=\"alert\" style={{ color: \"var(--colorError)\", marginTop: 6 }}>\n Enter a valid HTTP or HTTPS URL.\n </div>\n )}\n </SettingsField>\n <SettingsField id={`${id}-selector`} label=\"CSS selector (optional)\">\n <div className=\"power-dashboard-selector-editor\">\n <div className=\"power-dashboard-selector-field\">\n <Input\n className=\"power-dashboard-selector-input\"\n id={`${id}-selector`}\n value={selector}\n onChange={setSelector}\n placeholder=\"main .chart\"\n aria-invalid={selectorInvalid}\n />\n {selector && (\n <SettingsIconAction\n material=\"close\"\n label=\"Clear selector\"\n disabled={picking}\n onClick={() => setSelector(\"\")}\n />\n )}\n <SettingsIconAction\n material=\"center_focus_strong\"\n label={picking ? \"Selecting element…\" : \"Pick element on website\"}\n disabled={!normalizedUrl || picking}\n onClick={() => {\n if (!normalizedUrl || picking) return;\n setPicking(true);\n setPickerError(false);\n void ipcRenderer\n .invoke(DASHBOARD_PICK_ELEMENT, { url: normalizedUrl })\n .then((result: DashboardPickerResult) => {\n if (result?.status === \"selected\") {\n const selected = normalizeDashboardSelector(result.selector);\n if (selected) setSelector(selected);\n else setPickerError(true);\n } else if (result?.status !== \"canceled\") setPickerError(true);\n })\n .catch(() => setPickerError(true))\n .finally(() => setPicking(false));\n }}\n />\n </div>\n {selectorInvalid && (\n <div role=\"alert\">Use at most {dashboardSelectorLimit} characters without control characters.</div>\n )}\n {pickerError && <div role=\"alert\">Could not select an element. Try again or enter a CSS selector.</div>}\n </div>\n </SettingsField>\n <SettingsField id={`${id}-size`} label=\"Card size\">\n <Select\n id={`${id}-size`}\n aria-label=\"Card size\"\n styles={{ menuPortal: (base) => ({ ...base, zIndex: 12010 }) }}\n options={sizeOptions}\n value={size}\n isSearchable={false}\n isClearable={false}\n onChange={(option) => {\n if (option) setSize(option.value);\n }}\n />\n </SettingsField>\n <SettingsField\n id={`${id}-autorefresh`}\n label={\n <span style={{ display: \"inline-flex\", alignItems: \"center\", gap: 6 }}>\n Background refresh\n <Icon\n material=\"info_outline\"\n size={14}\n tooltip={{\n children: \"Refresh cached pages every 10 minutes while the dashboard is closed\",\n style: { zIndex: 12020 },\n }}\n />\n </span>\n }\n >\n <Checkbox {...{ id: `${id}-autorefresh` }} value={autoRefresh} onChange={setAutoRefresh} />\n </SettingsField>\n <div style={{ display: \"flex\", justifyContent: \"flex-end\", gap: 12 }}>\n <Button label=\"Cancel\" onClick={onClose} />\n <Button primary label={card ? \"Save card\" : \"Add card\"} onClick={save} />\n </div>\n </SettingsModal>\n );\n}\n\nfunction WebsiteIcon({ url, favicon }: { url: string; favicon?: string }) {\n const source = favicon || new URL(\"/favicon.ico\", url).href;\n const [failedSource, setFailedSource] = useState<string>();\n return failedSource === source ? (\n <span aria-hidden=\"true\">🌐</span>\n ) : (\n <img\n src={source}\n alt=\"\"\n width={20}\n height={20}\n loading=\"lazy\"\n referrerPolicy=\"no-referrer\"\n onError={() => setFailedSource(source)}\n />\n );\n}\n\nexport const DashboardPreferences = observer(() => {\n const preferences = DashboardPreferencesStore.getInstanceOrCreate<DashboardPreferencesStore>();\n const [siteIcons, setSiteIcons] = useState<DashboardSiteIcon[]>([]);\n const cardIdentity = JSON.stringify(preferences.cards.map(({ id, url }) => ({ id, url })));\n useEffect(() => {\n let active = true;\n const refreshIcons = () =>\n void ipcRenderer\n .invoke(DASHBOARD_SITE_ICONS)\n .then((icons: DashboardSiteIcon[]) => {\n if (active && Array.isArray(icons)) setSiteIcons(icons);\n })\n .catch(() => {});\n refreshIcons();\n ipcRenderer.on(DASHBOARD_SITE_ICONS, refreshIcons);\n return () => {\n active = false;\n ipcRenderer.removeListener(DASHBOARD_SITE_ICONS, refreshIcons);\n };\n }, [cardIdentity]);\n const [editing, setEditing] = useState<DashboardCard | \"new\" | null>(null);\n const [draggingId, setDraggingId] = useState<string | null>(null);\n const [dropId, setDropId] = useState<string | null>(null);\n const [announcement, setAnnouncement] = useState(\"\");\n\n function moveCard(card: DashboardCard, index: number) {\n preferences.moveCard(card.id, index);\n setAnnouncement(\n `${card.title} moved to position ${preferences.cards.findIndex((entry) => entry.id === card.id) + 1}`,\n );\n }\n\n function finishDrag() {\n setDraggingId(null);\n setDropId(null);\n }\n\n return (\n <div style={{ display: \"grid\", gap: 8 }}>\n <div className=\"power-settings-hint\">\n Display websites in responsive dashboard cards. Some websites block embedding.\n </div>\n <style>{`\n .power-dashboard-drag-handle { display: inline-flex; align-items: center; padding: 4px; border: 0; border-radius: 4px; background: transparent; color: var(--textColorSecondary); cursor: grab; flex-shrink: 0; }\n .power-dashboard-drag-handle:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }\n .power-dashboard-drag-handle:active { cursor: grabbing; }\n `}</style>\n <div\n role=\"status\"\n aria-live=\"polite\"\n style={{ position: \"absolute\", width: 1, height: 1, overflow: \"hidden\", clipPath: \"inset(50%)\" }}\n >\n {announcement}\n </div>\n {preferences.cards.map((card, index) => (\n <div\n key={card.id}\n data-dashboard-card-id={card.id}\n onDragOver={(event) => {\n if (!draggingId || draggingId === card.id) return;\n event.preventDefault();\n event.dataTransfer.dropEffect = \"move\";\n setDropId(card.id);\n }}\n onDrop={(event) => {\n if (!draggingId) return;\n event.preventDefault();\n const dragged = preferences.cards.find((entry) => entry.id === draggingId);\n if (dragged) moveCard(dragged, index);\n finishDrag();\n }}\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: 12,\n minWidth: 0,\n padding: \"8px 0\",\n borderBottom: \"1px solid var(--borderFaintColor)\",\n boxShadow:\n dropId === card.id && draggingId !== card.id\n ? `0 ${preferences.cards.findIndex((entry) => entry.id === draggingId) < index ? 2 : -2}px 0 var(--primary)`\n : undefined,\n opacity: draggingId === card.id ? 0.5 : 1,\n }}\n >\n <button\n type=\"button\"\n className=\"power-dashboard-drag-handle\"\n draggable\n aria-label={`Reorder ${card.title}`}\n title=\"Drag to reorder, or use the Up and Down arrow keys\"\n onDragStart={(event) => {\n event.dataTransfer.effectAllowed = \"move\";\n event.dataTransfer.setData(\"text/plain\", card.id);\n setDraggingId(card.id);\n }}\n onDragEnd={finishDrag}\n onKeyDown={(event) => {\n if (event.key !== \"ArrowUp\" && event.key !== \"ArrowDown\") return;\n event.preventDefault();\n event.stopPropagation();\n moveCard(\n card,\n Math.max(0, Math.min(preferences.cards.length - 1, index + (event.key === \"ArrowUp\" ? -1 : 1))),\n );\n }}\n >\n <Icon material=\"drag_indicator\" />\n </button>\n <WebsiteIcon\n key={card.url}\n url={card.url}\n favicon={\n siteIcons.find((icon) => icon.id === card.id && icon.pageUrl === normalizeDashboardUrl(card.url))?.dataUrl\n }\n />\n <div style={{ flex: 1, minWidth: 0 }}>\n <div\n title={card.title}\n style={{ fontWeight: 600, overflow: \"hidden\", textOverflow: \"ellipsis\", whiteSpace: \"nowrap\" }}\n >\n {card.title}\n </div>\n <div\n className=\"power-settings-hint\"\n title={card.url}\n style={{ overflow: \"hidden\", textOverflow: \"ellipsis\", whiteSpace: \"nowrap\", marginTop: 3 }}\n >\n {card.url}\n </div>\n </div>\n <span\n aria-label={`Card size ${card.size.toUpperCase()}`}\n style={{\n flexShrink: 0,\n marginRight: 10,\n padding: \"3px 7px\",\n border: \"1px solid var(--borderFaintColor)\",\n borderRadius: 6,\n fontSize: 11,\n fontFamily: \"var(--font-monospace, monospace)\",\n lineHeight: \"18px\",\n color: \"var(--textColorSecondary)\",\n }}\n >\n Size: {card.size.toUpperCase()}\n </span>\n <SettingsIconAction material=\"edit\" label={`Edit ${card.title}`} onClick={() => setEditing(card)} />\n <SettingsIconAction\n material=\"delete_outline\"\n label={`Remove ${card.title}`}\n onClick={() => preferences.removeCard(card.id)}\n />\n </div>\n ))}\n <div style={{ display: \"flex\", justifyContent: \"flex-end\" }}>\n <Button\n primary\n style={{ display: \"inline-flex\", alignItems: \"center\", gap: 6 }}\n onClick={() => setEditing(\"new\")}\n >\n <Renderer.Component.Icon material=\"add\" size={16} />\n <span>Add card</span>\n </Button>\n </div>\n {editing && (\n <CardEditor\n card={editing === \"new\" ? undefined : editing}\n onSave={(value) => preferences.upsertCard(value)}\n onClose={() => setEditing(null)}\n />\n )}\n </div>\n );\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"dashboard-preferences.js","names":[],"sources":["../../../src/renderer/preferences/dashboard-preferences.tsx"],"sourcesContent":["import { Renderer } from \"@freelensapp/extensions\";\nimport { ipcRenderer } from \"electron\";\nimport { observer } from \"mobx-react\";\nimport { useEffect, useState } from \"react\";\nimport { type DashboardCard, type DashboardCardSize, normalizeDashboardUrl } from \"../../common/dashboard\";\nimport { DASHBOARD_PICK_ELEMENT, type DashboardPickerResult } from \"../../common/dashboard-picker\";\nimport { dashboardSelectorLimit, normalizeDashboardSelector } from \"../../common/dashboard-selector\";\nimport { DASHBOARD_SITE_ICONS, type DashboardSiteIcon } from \"../../common/dashboard-views\";\nimport { DashboardPreferencesStore } from \"../../common/store/dashboard-preferences-store\";\nimport { NativeTooltip } from \"../native-tooltip\";\nimport { SettingsIconAction } from \"./settings-icon-action\";\nimport { SettingsField, SettingsModal } from \"./settings-modal\";\n\nconst { Input, Select, Button, Icon, Checkbox } = Renderer.Component;\nconst sizeOptions = [\n { value: \"xs\" as const, label: \"XS · Extra small\" },\n { value: \"s\" as const, label: \"S · Small\" },\n { value: \"m\" as const, label: \"M · Medium\" },\n { value: \"l\" as const, label: \"L · Large\" },\n { value: \"xl\" as const, label: \"XL · Extra large\" },\n];\n\nfunction CardEditor({\n card,\n onSave,\n onClose,\n}: {\n card?: DashboardCard;\n onSave: (card: DashboardCard) => void;\n onClose: () => void;\n}) {\n const [title, setTitle] = useState(card?.title ?? \"\");\n const [url, setUrl] = useState(card?.url ?? \"\");\n const [size, setSize] = useState<DashboardCardSize>(card?.size ?? \"m\");\n const [autoRefresh, setAutoRefresh] = useState(card ? card.autoRefresh === true : true);\n const [selector, setSelector] = useState(card?.selector ?? \"\");\n const selectorInvalid = selector.trim().length > 0 && !normalizeDashboardSelector(selector);\n const [picking, setPicking] = useState(false);\n const [pickerError, setPickerError] = useState(false);\n const [submitted, setSubmitted] = useState(false);\n const id = `freelens-power-dashboard-${card?.id ?? \"new\"}`;\n const normalizedUrl = normalizeDashboardUrl(url);\n const invalid = (submitted || url.length > 0) && !normalizedUrl;\n\n function save() {\n setSubmitted(true);\n if (!normalizedUrl || selectorInvalid) return;\n onSave({\n id: card?.id ?? crypto.randomUUID(),\n title: title.trim() || new URL(normalizedUrl).hostname,\n url: normalizedUrl,\n size,\n autoRefresh,\n ...(card?.refreshEvery10Seconds ? { refreshEvery10Seconds: true } : {}),\n selector: normalizeDashboardSelector(selector),\n });\n onClose();\n }\n\n return (\n <SettingsModal id={id} title={card ? \"Edit card\" : \"Add a card\"} onClose={onClose}>\n <SettingsField id={`${id}-title`} label=\"Title\">\n <Input autoFocus id={`${id}-title`} value={title} placeholder=\"Website name\" onChange={setTitle} />\n </SettingsField>\n <SettingsField id={`${id}-url`} label=\"URL\">\n <Input\n id={`${id}-url`}\n value={url}\n placeholder=\"https://example.com\"\n onChange={setUrl}\n aria-invalid={invalid}\n aria-describedby={invalid ? `${id}-error` : undefined}\n />\n {invalid && (\n <div id={`${id}-error`} role=\"alert\" style={{ color: \"var(--colorError)\", marginTop: 6 }}>\n Enter a valid HTTP or HTTPS URL.\n </div>\n )}\n </SettingsField>\n <SettingsField id={`${id}-selector`} label=\"CSS selector (optional)\">\n <div className=\"power-dashboard-selector-editor\">\n <div className=\"power-dashboard-selector-field\">\n <Input\n className=\"power-dashboard-selector-input\"\n id={`${id}-selector`}\n value={selector}\n onChange={setSelector}\n placeholder=\"main .chart\"\n aria-invalid={selectorInvalid}\n />\n {selector && (\n <SettingsIconAction\n material=\"close\"\n label=\"Clear selector\"\n disabled={picking}\n onClick={() => setSelector(\"\")}\n />\n )}\n <SettingsIconAction\n material=\"center_focus_strong\"\n label={picking ? \"Selecting element…\" : \"Pick element on website\"}\n disabled={!normalizedUrl || picking}\n onClick={() => {\n if (!normalizedUrl || picking) return;\n setPicking(true);\n setPickerError(false);\n void ipcRenderer\n .invoke(DASHBOARD_PICK_ELEMENT, { url: normalizedUrl })\n .then((result: DashboardPickerResult) => {\n if (result?.status === \"selected\") {\n const selected = normalizeDashboardSelector(result.selector);\n if (selected) setSelector(selected);\n else setPickerError(true);\n } else if (result?.status !== \"canceled\") setPickerError(true);\n })\n .catch(() => setPickerError(true))\n .finally(() => setPicking(false));\n }}\n />\n </div>\n {selectorInvalid && (\n <div role=\"alert\">Use at most {dashboardSelectorLimit} characters without control characters.</div>\n )}\n {pickerError && <div role=\"alert\">Could not select an element. Try again or enter a CSS selector.</div>}\n </div>\n </SettingsField>\n <SettingsField id={`${id}-size`} label=\"Card size\">\n <Select\n id={`${id}-size`}\n aria-label=\"Card size\"\n styles={{ menuPortal: (base) => ({ ...base, zIndex: 12010 }) }}\n options={sizeOptions}\n value={size}\n isSearchable={false}\n isClearable={false}\n onChange={(option) => {\n if (option) setSize(option.value);\n }}\n />\n </SettingsField>\n <SettingsField\n id={`${id}-autorefresh`}\n label={\n <span style={{ display: \"inline-flex\", alignItems: \"center\", gap: 6 }}>\n Background refresh\n <Icon\n material=\"info_outline\"\n size={14}\n tooltip={{\n children: \"Refresh cached pages every 10 minutes while the dashboard is closed\",\n style: { zIndex: 12020 },\n }}\n />\n </span>\n }\n >\n <Checkbox {...{ id: `${id}-autorefresh` }} value={autoRefresh} onChange={setAutoRefresh} />\n </SettingsField>\n <div style={{ display: \"flex\", justifyContent: \"flex-end\", gap: 12 }}>\n <Button label=\"Cancel\" onClick={onClose} />\n <Button primary label={card ? \"Save card\" : \"Add card\"} onClick={save} />\n </div>\n </SettingsModal>\n );\n}\n\nfunction WebsiteIcon({ url, favicon }: { url: string; favicon?: string }) {\n const source = favicon || new URL(\"/favicon.ico\", url).href;\n const [failedSource, setFailedSource] = useState<string>();\n return failedSource === source ? (\n <span aria-hidden=\"true\">🌐</span>\n ) : (\n <img\n src={source}\n alt=\"\"\n width={20}\n height={20}\n loading=\"lazy\"\n referrerPolicy=\"no-referrer\"\n onError={() => setFailedSource(source)}\n />\n );\n}\n\nexport const DashboardPreferences = observer(() => {\n const preferences = DashboardPreferencesStore.getInstanceOrCreate<DashboardPreferencesStore>();\n const [siteIcons, setSiteIcons] = useState<DashboardSiteIcon[]>([]);\n const cardIdentity = JSON.stringify(preferences.cards.map(({ id, url }) => ({ id, url })));\n useEffect(() => {\n let active = true;\n const refreshIcons = () =>\n void ipcRenderer\n .invoke(DASHBOARD_SITE_ICONS)\n .then((icons: DashboardSiteIcon[]) => {\n if (active && Array.isArray(icons)) setSiteIcons(icons);\n })\n .catch(() => {});\n refreshIcons();\n ipcRenderer.on(DASHBOARD_SITE_ICONS, refreshIcons);\n return () => {\n active = false;\n ipcRenderer.removeListener(DASHBOARD_SITE_ICONS, refreshIcons);\n };\n }, [cardIdentity]);\n const [editing, setEditing] = useState<DashboardCard | \"new\" | null>(null);\n const [draggingId, setDraggingId] = useState<string | null>(null);\n const [dropId, setDropId] = useState<string | null>(null);\n const [announcement, setAnnouncement] = useState(\"\");\n\n function moveCard(card: DashboardCard, index: number) {\n preferences.moveCard(card.id, index);\n setAnnouncement(\n `${card.title} moved to position ${preferences.cards.findIndex((entry) => entry.id === card.id) + 1}`,\n );\n }\n\n function finishDrag() {\n setDraggingId(null);\n setDropId(null);\n }\n\n return (\n <div style={{ display: \"grid\", gap: 8 }}>\n <div className=\"power-settings-hint\">\n Display websites in responsive dashboard cards. Some websites block embedding.\n </div>\n <style>{`\n .power-dashboard-drag-handle { display: inline-flex; align-items: center; padding: 4px; border: 0; border-radius: 4px; background: transparent; color: var(--textColorSecondary); cursor: grab; flex-shrink: 0; }\n .power-dashboard-drag-handle:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }\n .power-dashboard-drag-handle:active { cursor: grabbing; }\n `}</style>\n <div\n role=\"status\"\n aria-live=\"polite\"\n style={{ position: \"absolute\", width: 1, height: 1, overflow: \"hidden\", clipPath: \"inset(50%)\" }}\n >\n {announcement}\n </div>\n {preferences.cards.map((card, index) => (\n <div\n key={card.id}\n data-dashboard-card-id={card.id}\n onDragOver={(event) => {\n if (!draggingId || draggingId === card.id) return;\n event.preventDefault();\n event.dataTransfer.dropEffect = \"move\";\n setDropId(card.id);\n }}\n onDrop={(event) => {\n if (!draggingId) return;\n event.preventDefault();\n const dragged = preferences.cards.find((entry) => entry.id === draggingId);\n if (dragged) moveCard(dragged, index);\n finishDrag();\n }}\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: 12,\n minWidth: 0,\n padding: \"8px 0\",\n borderBottom: \"1px solid var(--borderFaintColor)\",\n boxShadow:\n dropId === card.id && draggingId !== card.id\n ? `0 ${preferences.cards.findIndex((entry) => entry.id === draggingId) < index ? 2 : -2}px 0 var(--primary)`\n : undefined,\n opacity: draggingId === card.id ? 0.5 : 1,\n }}\n >\n <NativeTooltip title=\"Drag to reorder, or use the Up and Down arrow keys\">\n <button\n type=\"button\"\n className=\"power-dashboard-drag-handle\"\n draggable\n aria-label={`Reorder ${card.title}`}\n onDragStart={(event) => {\n event.dataTransfer.effectAllowed = \"move\";\n event.dataTransfer.setData(\"text/plain\", card.id);\n setDraggingId(card.id);\n }}\n onDragEnd={finishDrag}\n onKeyDown={(event) => {\n if (event.key !== \"ArrowUp\" && event.key !== \"ArrowDown\") return;\n event.preventDefault();\n event.stopPropagation();\n moveCard(\n card,\n Math.max(0, Math.min(preferences.cards.length - 1, index + (event.key === \"ArrowUp\" ? -1 : 1))),\n );\n }}\n >\n <Icon material=\"drag_indicator\" />\n </button>\n </NativeTooltip>\n <WebsiteIcon\n key={card.url}\n url={card.url}\n favicon={\n siteIcons.find((icon) => icon.id === card.id && icon.pageUrl === normalizeDashboardUrl(card.url))?.dataUrl\n }\n />\n <div style={{ flex: 1, minWidth: 0 }}>\n <NativeTooltip title={card.title}>\n <div style={{ fontWeight: 600, overflow: \"hidden\", textOverflow: \"ellipsis\", whiteSpace: \"nowrap\" }}>\n {card.title}\n </div>\n </NativeTooltip>\n <NativeTooltip title={card.url}>\n <div\n className=\"power-settings-hint\"\n style={{ overflow: \"hidden\", textOverflow: \"ellipsis\", whiteSpace: \"nowrap\", marginTop: 3 }}\n >\n {card.url}\n </div>\n </NativeTooltip>\n </div>\n <span\n aria-label={`Card size ${card.size.toUpperCase()}`}\n style={{\n flexShrink: 0,\n marginRight: 10,\n padding: \"3px 7px\",\n border: \"1px solid var(--borderFaintColor)\",\n borderRadius: 6,\n fontSize: 11,\n fontFamily: \"var(--font-monospace, monospace)\",\n lineHeight: \"18px\",\n color: \"var(--textColorSecondary)\",\n }}\n >\n Size: {card.size.toUpperCase()}\n </span>\n <SettingsIconAction material=\"edit\" label={`Edit ${card.title}`} onClick={() => setEditing(card)} />\n <SettingsIconAction\n material=\"delete_outline\"\n label={`Remove ${card.title}`}\n onClick={() => preferences.removeCard(card.id)}\n />\n </div>\n ))}\n <div style={{ display: \"flex\", justifyContent: \"flex-end\" }}>\n <Button\n primary\n style={{ display: \"inline-flex\", alignItems: \"center\", gap: 6 }}\n onClick={() => setEditing(\"new\")}\n >\n <Renderer.Component.Icon material=\"add\" size={16} />\n <span>Add card</span>\n </Button>\n </div>\n {editing && (\n <CardEditor\n card={editing === \"new\" ? undefined : editing}\n onSave={(value) => preferences.upsertCard(value)}\n onClose={() => setEditing(null)}\n />\n )}\n </div>\n );\n});\n"],"mappings":"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"}
@@ -179,7 +179,7 @@ var LogsPreferences = require__global_external_mobx_react.observer(() => {
179
179
  children: "Use Power Logs"
180
180
  }), /* @__PURE__ */ require_jsx_runtime.jsx("div", {
181
181
  className: "power-settings-hint",
182
- children: "Colored workload logs and temporary SQLite captures for SQL analysis. Native logs return when disabled. Temporary captures follow the retention settings below and are deleted when Power Logs stops."
182
+ children: "Colored workload logs and temporary SQLite captures for SQL analysis. Native logs return when disabled. Temporary captures follow the retention settings below and are deleted when Power Logs stops. Pinned snapshots remain until manually deleted."
183
183
  })] }),
184
184
  /* @__PURE__ */ require_jsx_runtime.jsx("div", {
185
185
  className: "power-settings-hint",
@@ -1 +1 @@
1
- {"version":3,"file":"logs-preferences.js","names":[],"sources":["../../../src/renderer/preferences/logs-preferences.tsx"],"sourcesContent":["import { Renderer } from \"@freelensapp/extensions\";\nimport { observer } from \"mobx-react\";\nimport { POWER_LOGS_DEFAULT_LIMITS, type PowerLogsLimits } from \"../../common/power-logs\";\nimport { applyPowerLogsLimits } from \"../../common/power-logs-limits\";\nimport { LogsPreferencesStore } from \"../../common/store/logs-preferences-store\";\n\nconst MiB = 1024 * 1024;\ninterface LimitPreset {\n label: string;\n limits: Partial<PowerLogsLimits>;\n}\ninterface LimitSetting {\n key: keyof PowerLogsLimits;\n label: string;\n hint: string;\n presets: LimitPreset[];\n describe(limits: PowerLogsLimits): string;\n}\nconst settings: LimitSetting[] = [\n {\n key: \"liveRows\",\n label: \"Live buffer\",\n hint: \"Maximum rows and memory kept in the live log view.\",\n presets: [1000, 5000, 10000, 50000, 100000].map((liveRows, index) => ({\n label: `${liveRows.toLocaleString(\"en-US\")} rows / ${[2, 8, 16, 80, 160][index]} MiB`,\n limits: { liveRows, liveBytes: [2, 8, 16, 80, 160][index] * MiB },\n })),\n describe: (limits) => `${limits.liveRows.toLocaleString(\"en-US\")} rows / ${limits.liveBytes / MiB} MiB`,\n },\n {\n key: \"historyLines\",\n label: \"History per container\",\n hint: \"Maximum recent lines and data fetched for each container.\",\n presets: [500, 1000, 5000].map((historyLines, index) => ({\n label: `${historyLines.toLocaleString(\"en-US\")} lines / ${[0.5, 1, 5][index]} MiB`,\n limits: { historyLines, historyBytes: [0.5, 1, 5][index] * MiB },\n })),\n describe: (limits) => `${limits.historyLines.toLocaleString(\"en-US\")} lines / ${limits.historyBytes / MiB} MiB`,\n },\n {\n key: \"captureBytes\",\n label: \"Capture size\",\n hint: \"Maximum data stored in each temporary capture.\",\n presets: [64, 128, 256, 512].map((size) => ({\n label: `${size} MiB`,\n limits: { captureBytes: size * MiB },\n })),\n describe: (limits) => `${limits.captureBytes / MiB} MiB`,\n },\n {\n key: \"captures\",\n label: \"Saved captures\",\n hint: \"Maximum number of temporary captures retained.\",\n presets: [1, 3, 5, 10].map((captures) => ({\n label: `${captures} ${captures === 1 ? \"capture\" : \"captures\"}`,\n limits: { captures },\n })),\n describe: (limits) => `${limits.captures} captures`,\n },\n {\n key: \"ttlMs\",\n label: \"Retention\",\n hint: \"How long temporary captures remain available.\",\n presets: [30, 60, 360, 1440, 4320].map((minutes) => ({\n label:\n minutes >= 1440\n ? `${minutes / 1440} ${minutes === 1440 ? \"day\" : \"days\"}`\n : minutes < 60\n ? `${minutes} minutes`\n : `${minutes / 60} ${minutes === 60 ? \"hour\" : \"hours\"}`,\n limits: { ttlMs: minutes * 60000 },\n })),\n describe: (limits) => `${limits.ttlMs / 60000} minutes`,\n },\n];\n\nconst LogLimitSelect = observer(function LogLimitSelect({\n setting,\n preferences,\n}: {\n setting: LimitSetting;\n preferences: LogsPreferencesStore;\n}) {\n const selected = setting.presets.findIndex((preset) =>\n Object.entries(preset.limits).every(([key, value]) => preferences.limits[key as keyof PowerLogsLimits] === value),\n );\n const options = setting.presets.map((preset, index) => ({ value: String(index), label: preset.label }));\n if (selected === -1) options.push({ value: \"custom\", label: `Custom: ${setting.describe(preferences.limits)}` });\n const id = `freelens-power-logs-${setting.key}`;\n return (\n <div\n className=\"power-settings-row\"\n style={{ display: \"flex\", alignItems: \"center\", justifyContent: \"space-between\", gap: 20 }}\n >\n <div>\n <label id={`${id}-label`} htmlFor={id}>\n {setting.label}\n </label>\n <div className=\"power-settings-hint\">{setting.hint}</div>\n </div>\n <div style={{ width: 260, maxWidth: \"100%\", flexShrink: 0 }}>\n <Renderer.Component.Select\n id={id}\n aria-labelledby={`${id}-label`}\n options={options}\n value={selected === -1 ? \"custom\" : String(selected)}\n isSearchable={false}\n isClearable={false}\n onChange={(option) => {\n if (!option || option.value === \"custom\") return;\n const preset = setting.presets[Number(option.value)];\n if (!preset) return;\n preferences.limits = { ...preferences.limits, ...preset.limits };\n applyPowerLogsLimits(preferences.limits);\n }}\n />\n </div>\n </div>\n );\n});\n\nexport const LogsPreferences = observer(() => {\n const preferences = LogsPreferencesStore.getInstanceOrCreate<LogsPreferencesStore>();\n return (\n <div style={{ display: \"grid\", gap: 20 }}>\n <div>\n <Renderer.Component.Switch\n checked={preferences.enabled}\n onChange={(value) => {\n preferences.enabled = value;\n }}\n >\n Use Power Logs\n </Renderer.Component.Switch>\n <div className=\"power-settings-hint\">\n Colored workload logs and temporary SQLite captures for SQL analysis. Native logs return when disabled.\n Temporary captures follow the retention settings below and are deleted when Power Logs stops.\n </div>\n </div>\n <div className=\"power-settings-hint\">\n Changes apply to new requests, captures and SQL queries. Existing captures retain their capacity and expiry.\n </div>\n {settings.map((setting) => (\n <LogLimitSelect key={setting.key} setting={setting} preferences={preferences} />\n ))}\n <div style={{ display: \"flex\", justifyContent: \"flex-end\" }}>\n <Renderer.Component.Button\n onClick={() => {\n preferences.limits = { ...POWER_LOGS_DEFAULT_LIMITS };\n applyPowerLogsLimits(preferences.limits);\n }}\n >\n <Renderer.Component.Icon material=\"restore\" size={16} /> Reset log limits\n </Renderer.Component.Button>\n </div>\n </div>\n );\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"logs-preferences.js","names":[],"sources":["../../../src/renderer/preferences/logs-preferences.tsx"],"sourcesContent":["import { Renderer } from \"@freelensapp/extensions\";\nimport { observer } from \"mobx-react\";\nimport { POWER_LOGS_DEFAULT_LIMITS, type PowerLogsLimits } from \"../../common/power-logs\";\nimport { applyPowerLogsLimits } from \"../../common/power-logs-limits\";\nimport { LogsPreferencesStore } from \"../../common/store/logs-preferences-store\";\n\nconst MiB = 1024 * 1024;\ninterface LimitPreset {\n label: string;\n limits: Partial<PowerLogsLimits>;\n}\ninterface LimitSetting {\n key: keyof PowerLogsLimits;\n label: string;\n hint: string;\n presets: LimitPreset[];\n describe(limits: PowerLogsLimits): string;\n}\nconst settings: LimitSetting[] = [\n {\n key: \"liveRows\",\n label: \"Live buffer\",\n hint: \"Maximum rows and memory kept in the live log view.\",\n presets: [1000, 5000, 10000, 50000, 100000].map((liveRows, index) => ({\n label: `${liveRows.toLocaleString(\"en-US\")} rows / ${[2, 8, 16, 80, 160][index]} MiB`,\n limits: { liveRows, liveBytes: [2, 8, 16, 80, 160][index] * MiB },\n })),\n describe: (limits) => `${limits.liveRows.toLocaleString(\"en-US\")} rows / ${limits.liveBytes / MiB} MiB`,\n },\n {\n key: \"historyLines\",\n label: \"History per container\",\n hint: \"Maximum recent lines and data fetched for each container.\",\n presets: [500, 1000, 5000].map((historyLines, index) => ({\n label: `${historyLines.toLocaleString(\"en-US\")} lines / ${[0.5, 1, 5][index]} MiB`,\n limits: { historyLines, historyBytes: [0.5, 1, 5][index] * MiB },\n })),\n describe: (limits) => `${limits.historyLines.toLocaleString(\"en-US\")} lines / ${limits.historyBytes / MiB} MiB`,\n },\n {\n key: \"captureBytes\",\n label: \"Capture size\",\n hint: \"Maximum data stored in each temporary capture.\",\n presets: [64, 128, 256, 512].map((size) => ({\n label: `${size} MiB`,\n limits: { captureBytes: size * MiB },\n })),\n describe: (limits) => `${limits.captureBytes / MiB} MiB`,\n },\n {\n key: \"captures\",\n label: \"Saved captures\",\n hint: \"Maximum number of temporary captures retained.\",\n presets: [1, 3, 5, 10].map((captures) => ({\n label: `${captures} ${captures === 1 ? \"capture\" : \"captures\"}`,\n limits: { captures },\n })),\n describe: (limits) => `${limits.captures} captures`,\n },\n {\n key: \"ttlMs\",\n label: \"Retention\",\n hint: \"How long temporary captures remain available.\",\n presets: [30, 60, 360, 1440, 4320].map((minutes) => ({\n label:\n minutes >= 1440\n ? `${minutes / 1440} ${minutes === 1440 ? \"day\" : \"days\"}`\n : minutes < 60\n ? `${minutes} minutes`\n : `${minutes / 60} ${minutes === 60 ? \"hour\" : \"hours\"}`,\n limits: { ttlMs: minutes * 60000 },\n })),\n describe: (limits) => `${limits.ttlMs / 60000} minutes`,\n },\n];\n\nconst LogLimitSelect = observer(function LogLimitSelect({\n setting,\n preferences,\n}: {\n setting: LimitSetting;\n preferences: LogsPreferencesStore;\n}) {\n const selected = setting.presets.findIndex((preset) =>\n Object.entries(preset.limits).every(([key, value]) => preferences.limits[key as keyof PowerLogsLimits] === value),\n );\n const options = setting.presets.map((preset, index) => ({ value: String(index), label: preset.label }));\n if (selected === -1) options.push({ value: \"custom\", label: `Custom: ${setting.describe(preferences.limits)}` });\n const id = `freelens-power-logs-${setting.key}`;\n return (\n <div\n className=\"power-settings-row\"\n style={{ display: \"flex\", alignItems: \"center\", justifyContent: \"space-between\", gap: 20 }}\n >\n <div>\n <label id={`${id}-label`} htmlFor={id}>\n {setting.label}\n </label>\n <div className=\"power-settings-hint\">{setting.hint}</div>\n </div>\n <div style={{ width: 260, maxWidth: \"100%\", flexShrink: 0 }}>\n <Renderer.Component.Select\n id={id}\n aria-labelledby={`${id}-label`}\n options={options}\n value={selected === -1 ? \"custom\" : String(selected)}\n isSearchable={false}\n isClearable={false}\n onChange={(option) => {\n if (!option || option.value === \"custom\") return;\n const preset = setting.presets[Number(option.value)];\n if (!preset) return;\n preferences.limits = { ...preferences.limits, ...preset.limits };\n applyPowerLogsLimits(preferences.limits);\n }}\n />\n </div>\n </div>\n );\n});\n\nexport const LogsPreferences = observer(() => {\n const preferences = LogsPreferencesStore.getInstanceOrCreate<LogsPreferencesStore>();\n return (\n <div style={{ display: \"grid\", gap: 20 }}>\n <div>\n <Renderer.Component.Switch\n checked={preferences.enabled}\n onChange={(value) => {\n preferences.enabled = value;\n }}\n >\n Use Power Logs\n </Renderer.Component.Switch>\n <div className=\"power-settings-hint\">\n Colored workload logs and temporary SQLite captures for SQL analysis. Native logs return when disabled.\n Temporary captures follow the retention settings below and are deleted when Power Logs stops. Pinned snapshots\n remain until manually deleted.\n </div>\n </div>\n <div className=\"power-settings-hint\">\n Changes apply to new requests, captures and SQL queries. Existing captures retain their capacity and expiry.\n </div>\n {settings.map((setting) => (\n <LogLimitSelect key={setting.key} setting={setting} preferences={preferences} />\n ))}\n <div style={{ display: \"flex\", justifyContent: \"flex-end\" }}>\n <Renderer.Component.Button\n onClick={() => {\n preferences.limits = { ...POWER_LOGS_DEFAULT_LIMITS };\n applyPowerLogsLimits(preferences.limits);\n }}\n >\n <Renderer.Component.Icon material=\"restore\" size={16} /> Reset log limits\n </Renderer.Component.Button>\n </div>\n </div>\n );\n});\n"],"mappings":"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"}
@@ -4,6 +4,7 @@ const require_monitoring_history = require("../src/common/monitoring-history.js"
4
4
  const require_monitoring_preferences_store = require("../src/common/store/monitoring-preferences-store.js");
5
5
  const require__global_external_react = require("../_virtual/_global-external_react.js");
6
6
  const require_jsx_runtime = require("../_virtual/_global-external_react/jsx-runtime.js");
7
+ const require_native_tooltip = require("../native-tooltip.js");
7
8
  const require_monitoring_history$1 = require("../monitoring-history.js");
8
9
  //#region src/renderer/preferences/monitoring-preferences.tsx
9
10
  var MonitoringPreferences = require__global_external_mobx_react.observer(() => {
@@ -72,10 +73,12 @@ var MonitoringPreferences = require__global_external_mobx_react.observer(() => {
72
73
  preferences.historyEnabled = value;
73
74
  },
74
75
  children: "Keep local history"
75
- }), /* @__PURE__ */ require_jsx_runtime.jsx("div", {
76
- className: "power-settings-hint",
76
+ }), /* @__PURE__ */ require_jsx_runtime.jsx(require_native_tooltip.NativeTooltip, {
77
77
  title: "SQLite storage. Collects while the cluster view is active. Resolution: 30 seconds for 2 hours, 5 minutes for 24 hours, 30 minutes for 7 days. Disabling preserves saved history.",
78
- children: "Up to 7 days, limited to 100 MiB."
78
+ children: /* @__PURE__ */ require_jsx_runtime.jsx("div", {
79
+ className: "power-settings-hint",
80
+ children: "Up to 7 days, limited to 100 MiB."
81
+ })
79
82
  })] }),
80
83
  /* @__PURE__ */ require_jsx_runtime.jsxs("div", {
81
84
  style: {
@@ -134,6 +137,7 @@ var MonitoringPreferences = require__global_external_mobx_react.observer(() => {
134
137
  })
135
138
  ]
136
139
  }), /* @__PURE__ */ require_jsx_runtime.jsxs(require_extensions.Renderer.Component.Button, {
140
+ tooltip: "Delete locally collected metric history without changing other settings",
137
141
  style: {
138
142
  flexShrink: 0,
139
143
  display: "inline-flex",
@@ -149,7 +153,6 @@ var MonitoringPreferences = require__global_external_mobx_react.observer(() => {
149
153
  background: "var(--contentColor)",
150
154
  color: "var(--textColorSecondary)"
151
155
  },
152
- title: "Delete locally collected metric history without changing other settings",
153
156
  onClick: () => {
154
157
  require_monitoring_history$1.monitoringHistory.clear().then(refresh).catch(() => setStatus((previous) => ({
155
158
  available: previous?.available ?? false,
@@ -1 +1 @@
1
- {"version":3,"file":"monitoring-preferences.js","names":[],"sources":["../../../src/renderer/preferences/monitoring-preferences.tsx"],"sourcesContent":["import { Renderer } from \"@freelensapp/extensions\";\nimport { observer } from \"mobx-react\";\nimport { useEffect, useState } from \"react\";\nimport { HISTORY_MAX_BYTES, type HistoryStatus } from \"../../common/monitoring-history\";\nimport { MonitoringPreferencesStore } from \"../../common/store/monitoring-preferences-store\";\nimport { monitoringHistory } from \"../monitoring-history\";\n\nexport const MonitoringPreferences = observer(() => {\n const preferences = MonitoringPreferencesStore.getInstanceOrCreate<MonitoringPreferencesStore>();\n const [status, setStatus] = useState<HistoryStatus>();\n const refresh = () => {\n void monitoringHistory\n .status()\n .then(setStatus)\n .catch(() =>\n setStatus({\n available: false,\n enabled: preferences.historyEnabled,\n bytes: 0,\n samples: 0,\n error: \"History service unavailable\",\n }),\n );\n };\n useEffect(refresh, [preferences.historyEnabled]);\n return (\n <div style={{ display: \"flex\", flexDirection: \"column\", gap: 20 }}>\n <div>\n <Renderer.Component.Switch\n checked={preferences.diagnosticsVisible}\n onChange={(value) => {\n preferences.diagnosticsVisible = value;\n }}\n >\n Show Diagnostics in sidebar\n </Renderer.Component.Switch>\n <div className=\"power-settings-hint\">Resource consumers, application events and Pending diagnostics.</div>\n </div>\n <div>\n <Renderer.Component.Switch\n checked={preferences.relationshipsVisible}\n onChange={(value) => {\n preferences.relationshipsVisible = value;\n }}\n >\n Show Relationships in sidebar\n </Renderer.Component.Switch>\n <div className=\"power-settings-hint\">\n Focused resource connections from API evidence, with links to related objects.\n </div>\n </div>\n <div>\n <Renderer.Component.Switch\n checked={preferences.resourceSearchEnabled}\n onChange={(value) => {\n preferences.resourceSearchEnabled = value;\n }}\n >\n Enable resource search (Shift–Shift)\n </Renderer.Component.Switch>\n <div className=\"power-settings-hint\">\n Search resources with Shift–Shift. Turning this off stops keyboard search and background indexing.\n </div>\n </div>\n <div>\n <Renderer.Component.Switch\n checked={preferences.enabled}\n onChange={(value) => {\n preferences.enabled = value;\n }}\n >\n Metrics-server monitoring\n </Renderer.Component.Switch>\n <div className=\"power-settings-hint\">\n CPU/RAM charts for clusters, nodes and pods. Keeps 30 minutes of live samples.\n </div>\n </div>\n <div>\n <Renderer.Component.Switch\n checked={preferences.historyEnabled}\n onChange={(value) => {\n preferences.historyEnabled = value;\n }}\n >\n Keep local history\n </Renderer.Component.Switch>\n <div\n className=\"power-settings-hint\"\n title=\"SQLite storage. Collects while the cluster view is active. Resolution: 30 seconds for 2 hours, 5 minutes for 24 hours, 30 minutes for 7 days. Disabling preserves saved history.\"\n >\n Up to 7 days, limited to 100 MiB.\n </div>\n </div>\n <div style={{ display: \"flex\", alignItems: \"center\", justifyContent: \"space-between\", gap: 12 }}>\n <div style={{ flex: 1, minWidth: 0 }} role=\"status\">\n <div style={{ display: \"flex\", justifyContent: \"space-between\", alignItems: \"baseline\", gap: 12 }}>\n <span>Local storage</span>\n <span style={{ fontVariantNumeric: \"tabular-nums\", color: \"var(--textColorSecondary)\" }}>\n {status?.available\n ? `${(status.bytes / 1024 / 1024).toFixed(2)} / ${HISTORY_MAX_BYTES / 1024 / 1024} MiB`\n : \"— / 100 MiB\"}\n </span>\n </div>\n {status?.available && (\n <div\n role=\"progressbar\"\n aria-label=\"Local history storage\"\n aria-valuemin={0}\n aria-valuemax={HISTORY_MAX_BYTES}\n aria-valuenow={status.bytes}\n aria-valuetext={`${(status.bytes / 1024 / 1024).toFixed(2)} of 100 MiB`}\n style={{ height: 4, marginTop: 8, borderRadius: 2, overflow: \"hidden\", background: \"var(--borderColor)\" }}\n >\n <div\n style={{\n height: \"100%\",\n width: `${Math.min(100, Math.max(0, (status.bytes / HISTORY_MAX_BYTES) * 100))}%`,\n background: \"var(--primary)\",\n transition: \"width 180ms ease\",\n }}\n />\n </div>\n )}\n <div className=\"power-settings-hint\" style={{ marginTop: 6 }}>\n {status?.error ??\n (status?.available\n ? `${status.samples.toLocaleString()} metric buckets · 7-day retention`\n : \"Checking history storage…\")}\n </div>\n </div>\n <Renderer.Component.Button\n style={{\n flexShrink: 0,\n display: \"inline-flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n gap: 6,\n height: 30,\n padding: \"0 10px\",\n fontSize: 12,\n lineHeight: \"16px\",\n border: \"1px solid var(--borderFaintColor)\",\n borderRadius: 6,\n background: \"var(--contentColor)\",\n color: \"var(--textColorSecondary)\",\n }}\n title=\"Delete locally collected metric history without changing other settings\"\n onClick={() => {\n void monitoringHistory\n .clear()\n .then(refresh)\n .catch(() =>\n setStatus((previous) => ({\n available: previous?.available ?? false,\n enabled: preferences.historyEnabled,\n bytes: previous?.bytes ?? 0,\n samples: previous?.samples ?? 0,\n error: \"Unable to clear local history. Try again.\",\n })),\n );\n }}\n >\n <Renderer.Component.Icon material=\"delete_outline\" size={14} />\n <span>Clear</span>\n </Renderer.Component.Button>\n </div>\n </div>\n );\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"monitoring-preferences.js","names":[],"sources":["../../../src/renderer/preferences/monitoring-preferences.tsx"],"sourcesContent":["import { Renderer } from \"@freelensapp/extensions\";\nimport { observer } from \"mobx-react\";\nimport { useEffect, useState } from \"react\";\nimport { HISTORY_MAX_BYTES, type HistoryStatus } from \"../../common/monitoring-history\";\nimport { MonitoringPreferencesStore } from \"../../common/store/monitoring-preferences-store\";\nimport { monitoringHistory } from \"../monitoring-history\";\nimport { NativeTooltip } from \"../native-tooltip\";\n\nexport const MonitoringPreferences = observer(() => {\n const preferences = MonitoringPreferencesStore.getInstanceOrCreate<MonitoringPreferencesStore>();\n const [status, setStatus] = useState<HistoryStatus>();\n const refresh = () => {\n void monitoringHistory\n .status()\n .then(setStatus)\n .catch(() =>\n setStatus({\n available: false,\n enabled: preferences.historyEnabled,\n bytes: 0,\n samples: 0,\n error: \"History service unavailable\",\n }),\n );\n };\n useEffect(refresh, [preferences.historyEnabled]);\n return (\n <div style={{ display: \"flex\", flexDirection: \"column\", gap: 20 }}>\n <div>\n <Renderer.Component.Switch\n checked={preferences.diagnosticsVisible}\n onChange={(value) => {\n preferences.diagnosticsVisible = value;\n }}\n >\n Show Diagnostics in sidebar\n </Renderer.Component.Switch>\n <div className=\"power-settings-hint\">Resource consumers, application events and Pending diagnostics.</div>\n </div>\n <div>\n <Renderer.Component.Switch\n checked={preferences.relationshipsVisible}\n onChange={(value) => {\n preferences.relationshipsVisible = value;\n }}\n >\n Show Relationships in sidebar\n </Renderer.Component.Switch>\n <div className=\"power-settings-hint\">\n Focused resource connections from API evidence, with links to related objects.\n </div>\n </div>\n <div>\n <Renderer.Component.Switch\n checked={preferences.resourceSearchEnabled}\n onChange={(value) => {\n preferences.resourceSearchEnabled = value;\n }}\n >\n Enable resource search (Shift–Shift)\n </Renderer.Component.Switch>\n <div className=\"power-settings-hint\">\n Search resources with Shift–Shift. Turning this off stops keyboard search and background indexing.\n </div>\n </div>\n <div>\n <Renderer.Component.Switch\n checked={preferences.enabled}\n onChange={(value) => {\n preferences.enabled = value;\n }}\n >\n Metrics-server monitoring\n </Renderer.Component.Switch>\n <div className=\"power-settings-hint\">\n CPU/RAM charts for clusters, nodes and pods. Keeps 30 minutes of live samples.\n </div>\n </div>\n <div>\n <Renderer.Component.Switch\n checked={preferences.historyEnabled}\n onChange={(value) => {\n preferences.historyEnabled = value;\n }}\n >\n Keep local history\n </Renderer.Component.Switch>\n <NativeTooltip title=\"SQLite storage. Collects while the cluster view is active. Resolution: 30 seconds for 2 hours, 5 minutes for 24 hours, 30 minutes for 7 days. Disabling preserves saved history.\">\n <div className=\"power-settings-hint\">Up to 7 days, limited to 100 MiB.</div>\n </NativeTooltip>\n </div>\n <div style={{ display: \"flex\", alignItems: \"center\", justifyContent: \"space-between\", gap: 12 }}>\n <div style={{ flex: 1, minWidth: 0 }} role=\"status\">\n <div style={{ display: \"flex\", justifyContent: \"space-between\", alignItems: \"baseline\", gap: 12 }}>\n <span>Local storage</span>\n <span style={{ fontVariantNumeric: \"tabular-nums\", color: \"var(--textColorSecondary)\" }}>\n {status?.available\n ? `${(status.bytes / 1024 / 1024).toFixed(2)} / ${HISTORY_MAX_BYTES / 1024 / 1024} MiB`\n : \"— / 100 MiB\"}\n </span>\n </div>\n {status?.available && (\n <div\n role=\"progressbar\"\n aria-label=\"Local history storage\"\n aria-valuemin={0}\n aria-valuemax={HISTORY_MAX_BYTES}\n aria-valuenow={status.bytes}\n aria-valuetext={`${(status.bytes / 1024 / 1024).toFixed(2)} of 100 MiB`}\n style={{ height: 4, marginTop: 8, borderRadius: 2, overflow: \"hidden\", background: \"var(--borderColor)\" }}\n >\n <div\n style={{\n height: \"100%\",\n width: `${Math.min(100, Math.max(0, (status.bytes / HISTORY_MAX_BYTES) * 100))}%`,\n background: \"var(--primary)\",\n transition: \"width 180ms ease\",\n }}\n />\n </div>\n )}\n <div className=\"power-settings-hint\" style={{ marginTop: 6 }}>\n {status?.error ??\n (status?.available\n ? `${status.samples.toLocaleString()} metric buckets · 7-day retention`\n : \"Checking history storage…\")}\n </div>\n </div>\n <Renderer.Component.Button\n tooltip=\"Delete locally collected metric history without changing other settings\"\n style={{\n flexShrink: 0,\n display: \"inline-flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n gap: 6,\n height: 30,\n padding: \"0 10px\",\n fontSize: 12,\n lineHeight: \"16px\",\n border: \"1px solid var(--borderFaintColor)\",\n borderRadius: 6,\n background: \"var(--contentColor)\",\n color: \"var(--textColorSecondary)\",\n }}\n onClick={() => {\n void monitoringHistory\n .clear()\n .then(refresh)\n .catch(() =>\n setStatus((previous) => ({\n available: previous?.available ?? false,\n enabled: preferences.historyEnabled,\n bytes: previous?.bytes ?? 0,\n samples: previous?.samples ?? 0,\n error: \"Unable to clear local history. Try again.\",\n })),\n );\n }}\n >\n <Renderer.Component.Icon material=\"delete_outline\" size={14} />\n <span>Clear</span>\n </Renderer.Component.Button>\n </div>\n </div>\n );\n});\n"],"mappings":"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"}
@@ -124,9 +124,9 @@ var PowerPreferences = () => /* @__PURE__ */ require_jsx_runtime.jsxs("div", {
124
124
  className: "power-preferences-section-links",
125
125
  "aria-label": "Settings sections",
126
126
  children: sectionLinks.map(({ id, title, icon }) => /* @__PURE__ */ require_jsx_runtime.jsxs(require_extensions.Renderer.Component.Button, {
127
+ tooltip: `Jump to ${title} settings`,
127
128
  className: "power-settings-section-link",
128
129
  "aria-label": title,
129
- title: `Jump to ${title} settings`,
130
130
  onClick: (event) => {
131
131
  event.preventDefault();
132
132
  require_section_navigation.focusPreferencesSection(id);
@@ -173,13 +173,13 @@ var PowerPreferences = () => /* @__PURE__ */ require_jsx_runtime.jsxs("div", {
173
173
  marginTop: 20
174
174
  },
175
175
  children: /* @__PURE__ */ require_jsx_runtime.jsxs(require_extensions.Renderer.Component.Button, {
176
+ tooltip: "Create matching icons for your saved clusters",
176
177
  style: {
177
178
  display: "inline-flex",
178
179
  alignItems: "center",
179
180
  gap: 6
180
181
  },
181
182
  onClick: () => require_extensions.Renderer.Navigation.navigate(`/extension/${require_extension_info.EXTENSION_ID}/cluster-icons`),
182
- title: "Create matching icons for your saved clusters",
183
183
  children: [/* @__PURE__ */ require_jsx_runtime.jsx(require_extensions.Renderer.Component.Icon, {
184
184
  material: "palette",
185
185
  size: 16
@@ -1 +1 @@
1
- {"version":3,"file":"preferences.js","names":[],"sources":["../../../src/renderer/preferences/preferences.tsx"],"sourcesContent":["import { Renderer } from \"@freelensapp/extensions\";\nimport { EXTENSION_ID } from \"../../common/extension-info\";\nimport { AiPreferences } from \"./ai-preferences\";\nimport { AppearancePreferences } from \"./appearance-preferences\";\nimport { DashboardPreferences } from \"./dashboard-preferences\";\nimport { LogsPreferences } from \"./logs-preferences\";\nimport { MonitoringPreferences } from \"./monitoring-preferences\";\nimport { NodeShellPreferences } from \"./node-shell-preferences\";\nimport { PowerPreferencesToggle } from \"./power-preferences\";\nimport { ReadOnlyPreferences } from \"./read-only-preferences\";\nimport { focusPreferencesSection } from \"./section-navigation\";\nimport { SettingsExport } from \"./settings-export\";\n\nconst styles = `\n .power-preferences-heading { display: flex; align-items: center; justify-content: space-between; gap: 16px; }\n .power-preferences-header-actions { display: inline-flex; margin-left: auto; flex-shrink: 0; }\n #freelens-power-settings > .SubTitle,\n #freelens-power-settings > .hint,\n #freelens-power-settings + hr { display: none; }\n .freelens-power-preferences { display: grid; gap: 24px; max-width: 760px; container: power-preferences / inline-size; }\n .freelens-power-preferences .power-preferences-section-links {\n display:flex; align-items:center; width:100%; gap:8px; overflow-x:auto;\n }\n :root .freelens-power-preferences .power-preferences-section-links button.power-settings-section-link {\n display: inline-flex; align-items: center; justify-content: center; gap: 6px;\n flex:1 0 auto; width:auto; min-width:max-content; min-height:32px; padding:4px 2px;\n border: 0; border-radius: 4px; background: transparent; box-shadow: none;\n color: var(--textColorSecondary); text-transform: none; white-space: nowrap; cursor: pointer;\n }\n :root .freelens-power-preferences .power-preferences-section-links button.power-settings-section-link:hover {\n color: var(--primary); background: transparent; box-shadow: none;\n }\n :root .freelens-power-preferences .power-preferences-section-links button.power-settings-section-link::before {\n content: none;\n }\n :root .freelens-power-preferences .power-preferences-section-links button.power-settings-section-link:focus-visible {\n color: var(--primary); background: transparent; box-shadow: none;\n outline: 2px solid var(--primary); outline-offset: 2px;\n }\n @container power-preferences (max-width:660px) { .power-preferences-section-links { font-size:12px; } }\n .freelens-power-preferences section[id] { scroll-margin-top: 16px; }\n .freelens-power-preferences section {\n padding: 24px; border: 1px solid var(--borderFaintColor);\n border-radius: 12px; background: var(--contentColor);\n }\n .freelens-power-preferences button, .freelens-power-preferences .Button { transition: color 160ms ease, background-color 160ms ease, border-color 160ms ease; }\n :root .freelens-power-preferences button.power-settings-icon-action,\n :root .power-preferences-header-actions button.power-settings-icon-action {\n display: inline-flex; align-items: center; justify-content: center;\n width: 32px; height: 32px; min-width: 32px; padding: 0; flex-shrink: 0;\n border: 0; border-radius: 6px; background: transparent; color: var(--textColorSecondary); cursor: pointer;\n transition: color 160ms ease, background-color 160ms ease;\n }\n :root .freelens-power-preferences button.power-settings-icon-action:not(:disabled):hover,\n :root .power-preferences-header-actions button.power-settings-icon-action:not(:disabled):hover {\n color: var(--primary); background: color-mix(in srgb, var(--primary) 10%, transparent);\n }\n :root .freelens-power-preferences button.power-settings-icon-action:focus-visible,\n :root .power-preferences-header-actions button.power-settings-icon-action:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }\n :root .freelens-power-preferences button.power-settings-icon-action:disabled,\n :root .power-preferences-header-actions button.power-settings-icon-action:disabled { opacity: 0.4; cursor: default; }\n .freelens-power-preferences h3 {\n display: flex; align-items: center; gap: 10px; margin: 0 0 24px; font-size: 16px; font-weight: 600; color: var(--textColorAccent);\n }\n .freelens-power-preferences label[data-testid=\"switch\"] {\n display: flex; width: 100%; align-items: center; justify-content: space-between;\n }\n .freelens-power-preferences .power-settings-hint {\n margin-top: 6px; font-size: 12px; line-height: 1.5; color: var(--textColorSecondary);\n }\n @media (max-width: 760px) {\n .freelens-power-preferences section { padding: 18px; }\n .freelens-power-preferences .power-settings-row { flex-wrap: wrap; }\n }\n`;\n\nconst sectionLinks = [\n { id: \"safety\", title: \"Safety\", icon: \"lock_outline\" },\n { id: \"appearance\", title: \"Appearance\", icon: \"palette\" },\n { id: \"monitoring\", title: \"Monitoring\", icon: \"show_chart\" },\n { id: \"logs\", title: \"Logs\", icon: \"subject\" },\n { id: \"shell\", title: \"Shell\", icon: \"vpn_key\" },\n { id: \"ai\", title: \"AI\", icon: \"chat_bubble_outline\" },\n { id: \"dashboard\", title: \"Dashboard\", icon: \"dashboard\" },\n];\n\nexport const PowerPreferences = () => (\n <div className=\"freelens-power-preferences\">\n <style>{styles}</style>\n <SettingsExport />\n <section aria-label=\"Freelens Power\">\n <PowerPreferencesToggle />\n </section>\n <nav className=\"power-preferences-section-links\" aria-label=\"Settings sections\">\n {sectionLinks.map(({ id, title, icon }) => (\n <Renderer.Component.Button\n key={id}\n className=\"power-settings-section-link\"\n aria-label={title}\n title={`Jump to ${title} settings`}\n onClick={(event) => {\n event.preventDefault();\n focusPreferencesSection(id);\n }}\n >\n <Renderer.Component.Icon material={icon} size={16} /> {title}\n </Renderer.Component.Button>\n ))}\n </nav>\n <section id=\"freelens-power-safety-section\" tabIndex={-1} aria-labelledby=\"freelens-power-safety-title\">\n <h3 id=\"freelens-power-safety-title\">\n <Renderer.Component.Icon material=\"lock_outline\" size={20} /> Read-only mode\n </h3>\n <ReadOnlyPreferences />\n </section>\n <section id=\"freelens-power-appearance-section\" tabIndex={-1} aria-labelledby=\"freelens-power-appearance-title\">\n <h3 id=\"freelens-power-appearance-title\">\n <Renderer.Component.Icon material=\"palette\" size={20} /> Appearance\n </h3>\n <AppearancePreferences />\n <div style={{ display: \"flex\", justifyContent: \"flex-end\", marginTop: 20 }}>\n <Renderer.Component.Button\n style={{ display: \"inline-flex\", alignItems: \"center\", gap: 6 }}\n onClick={() => Renderer.Navigation.navigate(`/extension/${EXTENSION_ID}/cluster-icons`)}\n title=\"Create matching icons for your saved clusters\"\n >\n <Renderer.Component.Icon material=\"palette\" size={16} /> Cluster icons\n </Renderer.Component.Button>\n </div>\n </section>\n <section id=\"freelens-power-monitoring-section\" tabIndex={-1} aria-labelledby=\"freelens-power-monitoring-title\">\n <h3 id=\"freelens-power-monitoring-title\">\n <Renderer.Component.Icon material=\"show_chart\" size={20} /> Monitoring\n </h3>\n <MonitoringPreferences />\n </section>\n <section id=\"freelens-power-logs-section\" tabIndex={-1} aria-labelledby=\"freelens-power-logs-title\">\n <h3 id=\"freelens-power-logs-title\">\n <Renderer.Component.Icon material=\"subject\" size={20} /> Power Logs\n </h3>\n <LogsPreferences />\n </section>\n <section id=\"freelens-power-shell-section\" tabIndex={-1} aria-labelledby=\"freelens-power-shell-title\">\n <h3 id=\"freelens-power-shell-title\">\n <Renderer.Component.Icon material=\"vpn_key\" size={20} /> Secure Node Shell\n </h3>\n <NodeShellPreferences />\n </section>\n <section id=\"freelens-power-ai-section\" tabIndex={-1} aria-labelledby=\"freelens-power-ai-title\">\n <h3 id=\"freelens-power-ai-title\">\n <Renderer.Component.Icon material=\"chat_bubble_outline\" size={20} /> AI assistant\n </h3>\n <AiPreferences />\n </section>\n <section id=\"freelens-power-dashboard-section\" tabIndex={-1} aria-labelledby=\"freelens-power-dashboard-title\">\n <h3 id=\"freelens-power-dashboard-title\">\n <Renderer.Component.Icon material=\"dashboard\" size={20} /> Dashboard\n </h3>\n <DashboardPreferences />\n </section>\n </div>\n);\n"],"mappings":"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"}
1
+ {"version":3,"file":"preferences.js","names":[],"sources":["../../../src/renderer/preferences/preferences.tsx"],"sourcesContent":["import { Renderer } from \"@freelensapp/extensions\";\nimport { EXTENSION_ID } from \"../../common/extension-info\";\nimport { AiPreferences } from \"./ai-preferences\";\nimport { AppearancePreferences } from \"./appearance-preferences\";\nimport { DashboardPreferences } from \"./dashboard-preferences\";\nimport { LogsPreferences } from \"./logs-preferences\";\nimport { MonitoringPreferences } from \"./monitoring-preferences\";\nimport { NodeShellPreferences } from \"./node-shell-preferences\";\nimport { PowerPreferencesToggle } from \"./power-preferences\";\nimport { ReadOnlyPreferences } from \"./read-only-preferences\";\nimport { focusPreferencesSection } from \"./section-navigation\";\nimport { SettingsExport } from \"./settings-export\";\n\nconst styles = `\n .power-preferences-heading { display: flex; align-items: center; justify-content: space-between; gap: 16px; }\n .power-preferences-header-actions { display: inline-flex; margin-left: auto; flex-shrink: 0; }\n #freelens-power-settings > .SubTitle,\n #freelens-power-settings > .hint,\n #freelens-power-settings + hr { display: none; }\n .freelens-power-preferences { display: grid; gap: 24px; max-width: 760px; container: power-preferences / inline-size; }\n .freelens-power-preferences .power-preferences-section-links {\n display:flex; align-items:center; width:100%; gap:8px; overflow-x:auto;\n }\n :root .freelens-power-preferences .power-preferences-section-links button.power-settings-section-link {\n display: inline-flex; align-items: center; justify-content: center; gap: 6px;\n flex:1 0 auto; width:auto; min-width:max-content; min-height:32px; padding:4px 2px;\n border: 0; border-radius: 4px; background: transparent; box-shadow: none;\n color: var(--textColorSecondary); text-transform: none; white-space: nowrap; cursor: pointer;\n }\n :root .freelens-power-preferences .power-preferences-section-links button.power-settings-section-link:hover {\n color: var(--primary); background: transparent; box-shadow: none;\n }\n :root .freelens-power-preferences .power-preferences-section-links button.power-settings-section-link::before {\n content: none;\n }\n :root .freelens-power-preferences .power-preferences-section-links button.power-settings-section-link:focus-visible {\n color: var(--primary); background: transparent; box-shadow: none;\n outline: 2px solid var(--primary); outline-offset: 2px;\n }\n @container power-preferences (max-width:660px) { .power-preferences-section-links { font-size:12px; } }\n .freelens-power-preferences section[id] { scroll-margin-top: 16px; }\n .freelens-power-preferences section {\n padding: 24px; border: 1px solid var(--borderFaintColor);\n border-radius: 12px; background: var(--contentColor);\n }\n .freelens-power-preferences button, .freelens-power-preferences .Button { transition: color 160ms ease, background-color 160ms ease, border-color 160ms ease; }\n :root .freelens-power-preferences button.power-settings-icon-action,\n :root .power-preferences-header-actions button.power-settings-icon-action {\n display: inline-flex; align-items: center; justify-content: center;\n width: 32px; height: 32px; min-width: 32px; padding: 0; flex-shrink: 0;\n border: 0; border-radius: 6px; background: transparent; color: var(--textColorSecondary); cursor: pointer;\n transition: color 160ms ease, background-color 160ms ease;\n }\n :root .freelens-power-preferences button.power-settings-icon-action:not(:disabled):hover,\n :root .power-preferences-header-actions button.power-settings-icon-action:not(:disabled):hover {\n color: var(--primary); background: color-mix(in srgb, var(--primary) 10%, transparent);\n }\n :root .freelens-power-preferences button.power-settings-icon-action:focus-visible,\n :root .power-preferences-header-actions button.power-settings-icon-action:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }\n :root .freelens-power-preferences button.power-settings-icon-action:disabled,\n :root .power-preferences-header-actions button.power-settings-icon-action:disabled { opacity: 0.4; cursor: default; }\n .freelens-power-preferences h3 {\n display: flex; align-items: center; gap: 10px; margin: 0 0 24px; font-size: 16px; font-weight: 600; color: var(--textColorAccent);\n }\n .freelens-power-preferences label[data-testid=\"switch\"] {\n display: flex; width: 100%; align-items: center; justify-content: space-between;\n }\n .freelens-power-preferences .power-settings-hint {\n margin-top: 6px; font-size: 12px; line-height: 1.5; color: var(--textColorSecondary);\n }\n @media (max-width: 760px) {\n .freelens-power-preferences section { padding: 18px; }\n .freelens-power-preferences .power-settings-row { flex-wrap: wrap; }\n }\n`;\n\nconst sectionLinks = [\n { id: \"safety\", title: \"Safety\", icon: \"lock_outline\" },\n { id: \"appearance\", title: \"Appearance\", icon: \"palette\" },\n { id: \"monitoring\", title: \"Monitoring\", icon: \"show_chart\" },\n { id: \"logs\", title: \"Logs\", icon: \"subject\" },\n { id: \"shell\", title: \"Shell\", icon: \"vpn_key\" },\n { id: \"ai\", title: \"AI\", icon: \"chat_bubble_outline\" },\n { id: \"dashboard\", title: \"Dashboard\", icon: \"dashboard\" },\n];\n\nexport const PowerPreferences = () => (\n <div className=\"freelens-power-preferences\">\n <style>{styles}</style>\n <SettingsExport />\n <section aria-label=\"Freelens Power\">\n <PowerPreferencesToggle />\n </section>\n <nav className=\"power-preferences-section-links\" aria-label=\"Settings sections\">\n {sectionLinks.map(({ id, title, icon }) => (\n <Renderer.Component.Button\n tooltip={`Jump to ${title} settings`}\n key={id}\n className=\"power-settings-section-link\"\n aria-label={title}\n onClick={(event) => {\n event.preventDefault();\n focusPreferencesSection(id);\n }}\n >\n <Renderer.Component.Icon material={icon} size={16} /> {title}\n </Renderer.Component.Button>\n ))}\n </nav>\n <section id=\"freelens-power-safety-section\" tabIndex={-1} aria-labelledby=\"freelens-power-safety-title\">\n <h3 id=\"freelens-power-safety-title\">\n <Renderer.Component.Icon material=\"lock_outline\" size={20} /> Read-only mode\n </h3>\n <ReadOnlyPreferences />\n </section>\n <section id=\"freelens-power-appearance-section\" tabIndex={-1} aria-labelledby=\"freelens-power-appearance-title\">\n <h3 id=\"freelens-power-appearance-title\">\n <Renderer.Component.Icon material=\"palette\" size={20} /> Appearance\n </h3>\n <AppearancePreferences />\n <div style={{ display: \"flex\", justifyContent: \"flex-end\", marginTop: 20 }}>\n <Renderer.Component.Button\n tooltip=\"Create matching icons for your saved clusters\"\n style={{ display: \"inline-flex\", alignItems: \"center\", gap: 6 }}\n onClick={() => Renderer.Navigation.navigate(`/extension/${EXTENSION_ID}/cluster-icons`)}\n >\n <Renderer.Component.Icon material=\"palette\" size={16} /> Cluster icons\n </Renderer.Component.Button>\n </div>\n </section>\n <section id=\"freelens-power-monitoring-section\" tabIndex={-1} aria-labelledby=\"freelens-power-monitoring-title\">\n <h3 id=\"freelens-power-monitoring-title\">\n <Renderer.Component.Icon material=\"show_chart\" size={20} /> Monitoring\n </h3>\n <MonitoringPreferences />\n </section>\n <section id=\"freelens-power-logs-section\" tabIndex={-1} aria-labelledby=\"freelens-power-logs-title\">\n <h3 id=\"freelens-power-logs-title\">\n <Renderer.Component.Icon material=\"subject\" size={20} /> Power Logs\n </h3>\n <LogsPreferences />\n </section>\n <section id=\"freelens-power-shell-section\" tabIndex={-1} aria-labelledby=\"freelens-power-shell-title\">\n <h3 id=\"freelens-power-shell-title\">\n <Renderer.Component.Icon material=\"vpn_key\" size={20} /> Secure Node Shell\n </h3>\n <NodeShellPreferences />\n </section>\n <section id=\"freelens-power-ai-section\" tabIndex={-1} aria-labelledby=\"freelens-power-ai-title\">\n <h3 id=\"freelens-power-ai-title\">\n <Renderer.Component.Icon material=\"chat_bubble_outline\" size={20} /> AI assistant\n </h3>\n <AiPreferences />\n </section>\n <section id=\"freelens-power-dashboard-section\" tabIndex={-1} aria-labelledby=\"freelens-power-dashboard-title\">\n <h3 id=\"freelens-power-dashboard-title\">\n <Renderer.Component.Icon material=\"dashboard\" size={20} /> Dashboard\n </h3>\n <DashboardPreferences />\n </section>\n </div>\n);\n"],"mappings":"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"}
@@ -1,19 +1,20 @@
1
1
  const require_extensions = require("../_virtual/_global-external_@freelensapp/extensions.js");
2
2
  const require_jsx_runtime = require("../_virtual/_global-external_react/jsx-runtime.js");
3
+ const require_native_tooltip = require("../native-tooltip.js");
3
4
  //#region src/renderer/preferences/settings-icon-action.tsx
4
5
  function SettingsIconAction({ material, label, disabled = false, onClick }) {
5
- return /* @__PURE__ */ require_jsx_runtime.jsx("button", {
6
- type: "button",
7
- className: "power-settings-icon-action",
8
- "aria-label": label,
6
+ return /* @__PURE__ */ require_jsx_runtime.jsx(require_native_tooltip.NativeTooltip, {
9
7
  title: label,
10
- disabled,
11
- onClick,
12
- children: /* @__PURE__ */ require_jsx_runtime.jsx(require_extensions.Renderer.Component.Icon, {
13
- material,
14
- size: 18,
15
- tooltip: label,
16
- tooltipOverrideDisabled: true
8
+ children: /* @__PURE__ */ require_jsx_runtime.jsx("button", {
9
+ type: "button",
10
+ className: "power-settings-icon-action",
11
+ "aria-label": label,
12
+ disabled,
13
+ onClick,
14
+ children: /* @__PURE__ */ require_jsx_runtime.jsx(require_extensions.Renderer.Component.Icon, {
15
+ material,
16
+ size: 18
17
+ })
17
18
  })
18
19
  });
19
20
  }
@@ -1 +1 @@
1
- {"version":3,"file":"settings-icon-action.js","names":[],"sources":["../../../src/renderer/preferences/settings-icon-action.tsx"],"sourcesContent":["import { Renderer } from \"@freelensapp/extensions\";\n\nexport function SettingsIconAction({\n material,\n label,\n disabled = false,\n onClick,\n}: {\n material: string;\n label: string;\n disabled?: boolean;\n onClick: () => void;\n}) {\n return (\n <button\n type=\"button\"\n className=\"power-settings-icon-action\"\n aria-label={label}\n title={label}\n disabled={disabled}\n onClick={onClick}\n >\n <Renderer.Component.Icon material={material} size={18} tooltip={label} tooltipOverrideDisabled />\n </button>\n );\n}\n"],"mappings":";;;AAEA,SAAgB,mBAAmB,EACjC,UACA,OACA,WAAW,OACX,WAMC;CACD,OACE,oCAAA,IAAC,UAAD;EACE,MAAK;EACL,WAAU;EACV,cAAY;EACZ,OAAO;EACG;EACD;YAET,oCAAA,IAAC,mBAAA,SAAS,UAAU,MAApB;GAAmC;GAAU,MAAM;GAAI,SAAS;GAAO,yBAAA;EAAyB,CAAA;CAC1F,CAAA;AAEZ"}
1
+ {"version":3,"file":"settings-icon-action.js","names":[],"sources":["../../../src/renderer/preferences/settings-icon-action.tsx"],"sourcesContent":["import { Renderer } from \"@freelensapp/extensions\";\nimport { NativeTooltip } from \"../native-tooltip\";\n\nexport function SettingsIconAction({\n material,\n label,\n disabled = false,\n onClick,\n}: {\n material: string;\n label: string;\n disabled?: boolean;\n onClick: () => void;\n}) {\n return (\n <NativeTooltip title={label}>\n <button\n type=\"button\"\n className=\"power-settings-icon-action\"\n aria-label={label}\n disabled={disabled}\n onClick={onClick}\n >\n <Renderer.Component.Icon material={material} size={18} />\n </button>\n </NativeTooltip>\n );\n}\n"],"mappings":";;;;AAGA,SAAgB,mBAAmB,EACjC,UACA,OACA,WAAW,OACX,WAMC;CACD,OACE,oCAAA,IAAC,uBAAA,eAAD;EAAe,OAAO;YACpB,oCAAA,IAAC,UAAD;GACE,MAAK;GACL,WAAU;GACV,cAAY;GACF;GACD;aAET,oCAAA,IAAC,mBAAA,SAAS,UAAU,MAApB;IAAmC;IAAU,MAAM;GAAK,CAAA;EAClD,CAAA;CACK,CAAA;AAEnB"}
@@ -0,0 +1,53 @@
1
+ //#region src/renderer/relationship-map-finding.ts
2
+ function relationshipMapFinding(clusterId, namespace, service, graph, hideUpstreams) {
3
+ const text = (value) => value.slice(0, 300);
4
+ const visible = graph.nodes.filter((node) => !hideUpstreams || node.role !== "upstream");
5
+ const nodes = visible.slice(0, 60);
6
+ const ids = new Set(nodes.map((node) => node.id));
7
+ const edges = graph.edges.filter((edge) => ids.has(edge.from) && ids.has(edge.to));
8
+ const snapshot = {
9
+ namespace,
10
+ service,
11
+ summary: text(graph.diagnostics.summary),
12
+ nodes: nodes.map(({ id, kind, name, role, detail, tone, inferred }) => ({
13
+ id: text(id),
14
+ kind,
15
+ name: text(name),
16
+ role,
17
+ detail: text(detail),
18
+ tone,
19
+ ...inferred ? { inferred } : {}
20
+ })),
21
+ edges: edges.slice(0, 100).map(({ from, to, label }) => ({
22
+ from: text(from),
23
+ to: text(to),
24
+ label: text(label)
25
+ })),
26
+ gaps: graph.gaps.slice(0, 20).map(text),
27
+ omitted: graph.omitted + visible.length - nodes.length + Math.max(0, edges.length - 100),
28
+ upstreamsHidden: hideUpstreams,
29
+ scope: "Visible map snapshot from Kubernetes API evidence; does not prove network reachability"
30
+ };
31
+ let summary = JSON.stringify(snapshot);
32
+ while (summary.length > 8e3 && (snapshot.edges.length || snapshot.nodes.length)) {
33
+ if (snapshot.edges.length) snapshot.edges.pop();
34
+ else snapshot.nodes.pop();
35
+ snapshot.omitted++;
36
+ summary = JSON.stringify(snapshot);
37
+ }
38
+ return {
39
+ clusterId,
40
+ source: "relationships",
41
+ title: `Relationships · ${service}`,
42
+ resource: {
43
+ kind: "Service",
44
+ name: service,
45
+ namespace
46
+ },
47
+ summary
48
+ };
49
+ }
50
+ //#endregion
51
+ exports.relationshipMapFinding = relationshipMapFinding;
52
+
53
+ //# sourceMappingURL=relationship-map-finding.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relationship-map-finding.js","names":[],"sources":["../../src/renderer/relationship-map-finding.ts"],"sourcesContent":["import type { buildResourceRelationships } from \"../common/resource-relationships\";\nimport type { DiagnosticFinding } from \"./ai-diagnostic-handoff\";\n\ntype RelationshipGraph = ReturnType<typeof buildResourceRelationships>;\n\nexport function relationshipMapFinding(\n clusterId: string,\n namespace: string,\n service: string,\n graph: RelationshipGraph,\n hideUpstreams: boolean,\n): DiagnosticFinding {\n const text = (value: string) => value.slice(0, 300);\n const visible = graph.nodes.filter((node) => !hideUpstreams || node.role !== \"upstream\");\n const nodes = visible.slice(0, 60);\n const ids = new Set(nodes.map((node) => node.id));\n const edges = graph.edges.filter((edge) => ids.has(edge.from) && ids.has(edge.to));\n const snapshot = {\n namespace,\n service,\n summary: text(graph.diagnostics.summary),\n nodes: nodes.map(({ id, kind, name, role, detail, tone, inferred }) => ({\n id: text(id),\n kind,\n name: text(name),\n role,\n detail: text(detail),\n tone,\n ...(inferred ? { inferred } : {}),\n })),\n edges: edges.slice(0, 100).map(({ from, to, label }) => ({ from: text(from), to: text(to), label: text(label) })),\n gaps: graph.gaps.slice(0, 20).map(text),\n omitted: graph.omitted + visible.length - nodes.length + Math.max(0, edges.length - 100),\n upstreamsHidden: hideUpstreams,\n scope: \"Visible map snapshot from Kubernetes API evidence; does not prove network reachability\",\n };\n let summary = JSON.stringify(snapshot);\n while (summary.length > 8000 && (snapshot.edges.length || snapshot.nodes.length)) {\n if (snapshot.edges.length) snapshot.edges.pop();\n else snapshot.nodes.pop();\n snapshot.omitted++;\n summary = JSON.stringify(snapshot);\n }\n return {\n clusterId,\n source: \"relationships\",\n title: `Relationships · ${service}`,\n resource: { kind: \"Service\", name: service, namespace },\n summary,\n };\n}\n"],"mappings":";AAKA,SAAgB,uBACd,WACA,WACA,SACA,OACA,eACmB;CACnB,MAAM,QAAQ,UAAkB,MAAM,MAAM,GAAG,GAAG;CAClD,MAAM,UAAU,MAAM,MAAM,QAAQ,SAAS,CAAC,iBAAiB,KAAK,SAAS,UAAU;CACvF,MAAM,QAAQ,QAAQ,MAAM,GAAG,EAAE;CACjC,MAAM,MAAM,IAAI,IAAI,MAAM,KAAK,SAAS,KAAK,EAAE,CAAC;CAChD,MAAM,QAAQ,MAAM,MAAM,QAAQ,SAAS,IAAI,IAAI,KAAK,IAAI,KAAK,IAAI,IAAI,KAAK,EAAE,CAAC;CACjF,MAAM,WAAW;EACf;EACA;EACA,SAAS,KAAK,MAAM,YAAY,OAAO;EACvC,OAAO,MAAM,KAAK,EAAE,IAAI,MAAM,MAAM,MAAM,QAAQ,MAAM,gBAAgB;GACtE,IAAI,KAAK,EAAE;GACX;GACA,MAAM,KAAK,IAAI;GACf;GACA,QAAQ,KAAK,MAAM;GACnB;GACA,GAAI,WAAW,EAAE,SAAS,IAAI,CAAC;EACjC,EAAE;EACF,OAAO,MAAM,MAAM,GAAG,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,IAAI,aAAa;GAAE,MAAM,KAAK,IAAI;GAAG,IAAI,KAAK,EAAE;GAAG,OAAO,KAAK,KAAK;EAAE,EAAE;EAChH,MAAM,MAAM,KAAK,MAAM,GAAG,EAAE,CAAC,CAAC,IAAI,IAAI;EACtC,SAAS,MAAM,UAAU,QAAQ,SAAS,MAAM,SAAS,KAAK,IAAI,GAAG,MAAM,SAAS,GAAG;EACvF,iBAAiB;EACjB,OAAO;CACT;CACA,IAAI,UAAU,KAAK,UAAU,QAAQ;CACrC,OAAO,QAAQ,SAAS,QAAS,SAAS,MAAM,UAAU,SAAS,MAAM,SAAS;EAChF,IAAI,SAAS,MAAM,QAAQ,SAAS,MAAM,IAAI;OACzC,SAAS,MAAM,IAAI;EACxB,SAAS;EACT,UAAU,KAAK,UAAU,QAAQ;CACnC;CACA,OAAO;EACL;EACA,QAAQ;EACR,OAAO,mBAAmB;EAC1B,UAAU;GAAE,MAAM;GAAW,MAAM;GAAS;EAAU;EACtD;CACF;AACF"}
@@ -1,5 +1,11 @@
1
1
  //#region src/renderer/resource-relationships.css.ts
2
2
  var resourceRelationshipsStyles = `
3
+ .power-relationships .graph-omitted-notice { display:flex; align-items:center; gap:8px; }
4
+ .graph-omitted-notice > span { flex:1; }
5
+ .graph-omitted-warning { color:var(--colorWarning); flex-shrink:0; }
6
+ .power-relationships .graph-show-all { display:inline-flex; padding:4px; border:0; background:transparent; color:inherit; }
7
+ .power-relationships .graph-show-all:hover, .power-relationships .graph-show-all:focus-visible { color:var(--primary); }
8
+
3
9
  .power-relationships{height:100%;overflow:auto;box-sizing:border-box;min-width:0;padding:24px;max-width:1550px;margin:auto;color:var(--textColorPrimary)}.power-relationships h2{margin:0}.power-relationships .page-heading{display:flex;justify-content:space-between;align-items:center;gap:16px;flex-wrap:wrap;margin-bottom:8px}.power-relationships .intro{color:var(--textColorSecondary);max-width:900px;line-height:1.6}.power-relationships .controls{display:flex;gap:24px;align-items:end;flex-wrap:wrap;margin:24px 0}.power-relationships .control{min-width:200px;flex:1;max-width:340px}.power-relationships .control>span{display:block;font-size:12px;margin-bottom:8px;color:var(--textColorSecondary)}.power-relationships button{min-height:32px;cursor:pointer}.power-relationships .refresh{background:transparent;border:1px solid var(--borderColor);border-radius:5px;padding:5px 10px;color:var(--textColorPrimary);display:flex;align-items:center;gap:8px}.power-relationships .notice{padding:14px 16px;background:var(--contentColor);border:1px solid var(--borderColor);border-radius:7px;margin:16px 0;line-height:1.6}.power-relationships .warning{color:var(--colorWarning)}.power-relationships .healthy{color:var(--colorOk)}.power-relationships .neutral{color:var(--textColorSecondary)}.power-relationships .graph-scroll{min-width:0;max-width:100%;overflow:auto;margin-top:24px}.power-relationships .graph{min-width:1000px;display:grid;grid-template-columns:repeat(4,minmax(180px,1fr));column-gap:64px;row-gap:16px;position:relative;padding:6px 2px 56px}.power-relationships .graph.upstream-gutter{padding-left:42px}.power-relationships .gateway-evidence{font-size:11px}.power-relationships .gateway-evidence summary{min-height:24px}.power-relationships .graph.hide-upstreams{min-width:740px;grid-template-columns:repeat(3,minmax(180px,1fr))}.power-relationships .graph-option{display:inline-flex;align-items:center;justify-content:center;gap:8px;flex-shrink:0;min-height:32px;padding:5px 10px;border:1px solid var(--borderColor);border-radius:5px;background:transparent;color:var(--textColorPrimary);font:inherit;cursor:pointer;transition:background-color .15s,border-color .15s}.power-relationships .graph-option[aria-pressed="true"]{background:color-mix(in srgb,var(--primary) 14%,var(--contentColor));border-color:var(--primary);color:var(--primary)}.power-relationships .graph-option:hover,.power-relationships .refresh:hover{background:color-mix(in srgb,var(--primary) 10%,var(--contentColor))}.power-relationships .graph-option:focus-visible{outline:2px solid var(--primary);outline-offset:2px}.power-relationships .column{position:relative;min-width:0;display:grid;grid-row:1/-1;grid-template-rows:subgrid}.power-relationships .column>h3{font-size:13px;margin:0;color:var(--textColorSecondary);font-weight:500}.power-relationships .card{background:var(--contentColor);border:1px solid var(--borderColor);border-radius:8px;padding:14px;margin:0;position:relative;z-index:1;overflow-wrap:anywhere}.power-relationships .card-kind{display:flex;align-items:center;gap:7px;font-size:11px;color:var(--textColorSecondary);margin-bottom:6px}.power-relationships .resource-name{font-size:14px;font-weight:600;color:var(--textColorPrimary);text-align:left;background:transparent;border:0;padding:0;max-width:100%}.power-relationships .resource-name:hover{color:var(--primary)}.power-relationships .card p{font-size:12px;line-height:1.5;margin:6px 0 0}.power-relationships .relation-label{font-size:10px;text-transform:uppercase;letter-spacing:.04em;color:var(--textColorSecondary);margin-bottom:6px}.power-relationships .resource-connections{position:absolute;inset:0;overflow:visible;pointer-events:none;color:var(--textColorSecondary)}.power-relationships .connection{fill:none;stroke:currentColor;stroke-width:1.5;stroke-linecap:butt;stroke-linejoin:miter;opacity:.55;transition:opacity .15s,stroke .15s,stroke-width .15s}.power-relationships .connection.highlighted{opacity:1;stroke:var(--primary);stroke-width:2.5}.power-relationships .connection.dimmed{opacity:.12}.power-relationships .scope{max-width:68ch;margin-top:8px;color:var(--textColorSecondary);font-size:12px;line-height:1.6}.power-relationships .scope>span{display:block;margin-top:3px}.power-relationships details{margin-top:16px}.power-relationships summary{cursor:pointer;min-height:32px}.power-relationships .edge-list{columns:2;line-height:1.7;font-size:12px;list-style:none;padding:0}.power-relationships .empty{padding:28px;border:1px dashed var(--borderColor);border-radius:8px;color:var(--textColorSecondary);text-align:center}.power-relationships .relationship-summary{padding:16px;display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:12px 24px}.power-relationships .ports{margin-left:auto;justify-content:flex-end;display:flex;gap:12px;flex-wrap:wrap;font-size:12px}.power-relationships .ports span{padding:4px 8px;border-radius:4px;background:var(--contentColor);border:1px solid var(--borderColor)}@media(max-width:900px){.power-relationships{padding:16px}.power-relationships .controls{gap:16px}.power-relationships .edge-list{columns:1}}`;
4
10
  //#endregion
5
11
  exports.resourceRelationshipsStyles = resourceRelationshipsStyles;