@64mb/freelens-power 1.0.1 → 1.0.2

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 (54) hide show
  1. package/README.md +4 -4
  2. package/THIRD_PARTY_LICENSES +41 -0
  3. package/out/main/ai.js +9 -6
  4. package/out/main/ai.js.map +1 -1
  5. package/out/main/common/ai-extras.js +17 -0
  6. package/out/main/common/ai-extras.js.map +1 -1
  7. package/out/main/common/dashboard-readiness.js +88 -0
  8. package/out/main/common/dashboard-readiness.js.map +1 -0
  9. package/out/main/common/dashboard-selector.js +9 -1
  10. package/out/main/common/dashboard-selector.js.map +1 -1
  11. package/out/main/common/dashboard-views.js +2 -0
  12. package/out/main/common/dashboard-views.js.map +1 -1
  13. package/out/main/dashboard-network.js +104 -0
  14. package/out/main/dashboard-network.js.map +1 -0
  15. package/out/main/dashboard-views.js +98 -21
  16. package/out/main/dashboard-views.js.map +1 -1
  17. package/out/renderer/ai-extras.js +41 -12
  18. package/out/renderer/ai-extras.js.map +1 -1
  19. package/out/renderer/ai-message.js +1 -0
  20. package/out/renderer/ai-message.js.map +1 -1
  21. package/out/renderer/ai-provider-icon.js +44 -0
  22. package/out/renderer/ai-provider-icon.js.map +1 -0
  23. package/out/renderer/ai-shortcuts.js +1 -1
  24. package/out/renderer/ai-shortcuts.js.map +1 -1
  25. package/out/renderer/ai.js +53 -10
  26. package/out/renderer/ai.js.map +1 -1
  27. package/out/renderer/appearance.js +2 -1
  28. package/out/renderer/appearance.js.map +1 -1
  29. package/out/renderer/assets/claude.js +6 -0
  30. package/out/renderer/assets/claude.js.map +1 -0
  31. package/out/renderer/dashboard.js +39 -4
  32. package/out/renderer/dashboard.js.map +1 -1
  33. package/out/renderer/index.js +2 -0
  34. package/out/renderer/index.js.map +1 -1
  35. package/out/renderer/menus/secure-node-shell-menu.js +1 -1
  36. package/out/renderer/menus/secure-node-shell-menu.js.map +1 -1
  37. package/out/renderer/monitoring.js +671 -91
  38. package/out/renderer/monitoring.js.map +1 -1
  39. package/out/renderer/pod-monitoring.js +214 -0
  40. package/out/renderer/pod-monitoring.js.map +1 -0
  41. package/out/renderer/preferences/ai-preferences.js +2 -2
  42. package/out/renderer/preferences/ai-preferences.js.map +1 -1
  43. package/out/renderer/preferences/dashboard-preferences.js +1 -8
  44. package/out/renderer/preferences/dashboard-preferences.js.map +1 -1
  45. package/out/renderer/preferences/preferences.js +1 -1
  46. package/out/renderer/preferences/preferences.js.map +1 -1
  47. package/out/renderer/preferences/settings-icon-action.js +3 -1
  48. package/out/renderer/preferences/settings-icon-action.js.map +1 -1
  49. package/out/renderer/src/common/ai-extras.js +17 -0
  50. package/out/renderer/src/common/ai-extras.js.map +1 -1
  51. package/out/renderer/src/common/dashboard-selector.js.map +1 -1
  52. package/out/renderer/src/common/dashboard-views.js +2 -0
  53. package/out/renderer/src/common/dashboard-views.js.map +1 -1
  54. package/package.json +1 -1
@@ -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: \"s\" as const, label: \"S · Small\" },\n { value: \"m\" as const, label: \"M · Medium\" },\n { value: \"l\" as const, label: \"L · 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 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 aria-describedby={`${id}-selector-hint`}\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 <div id={`${id}-selector-hint`} className=\"power-settings-hint\" style={{ marginTop: 0 }}>\n Leave empty to show the whole website.\n </div>\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 id={`${id}-autorefresh`} label=\"Autorefresh\">\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 primary label=\"Add card\" onClick={() => setEditing(\"new\")} />\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 { SettingsIconAction } from \"./settings-icon-action\";\nimport { SettingsField, SettingsModal } from \"./settings-modal\";\n\nconst { Input, Select, Button, Icon, Checkbox } = Renderer.Component;\nconst sizeOptions = [\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];\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 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 id={`${id}-autorefresh`} label=\"Autorefresh\">\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 primary label=\"Add card\" onClick={() => setEditing(\"new\")} />\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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"}
@@ -94,7 +94,7 @@ var PowerPreferences = () => /* @__PURE__ */ require_jsx_runtime.jsxs("div", {
94
94
  children: [/* @__PURE__ */ require_jsx_runtime.jsxs("h3", {
95
95
  id: "freelens-power-shell-title",
96
96
  children: [/* @__PURE__ */ require_jsx_runtime.jsx(require_extensions.Renderer.Component.Icon, {
97
- material: "terminal",
97
+ material: "vpn_key",
98
98
  size: 20
99
99
  }), " Secure Node Shell"]
100
100
  }), /* @__PURE__ */ require_jsx_runtime.jsx(require_node_shell_preferences.NodeShellPreferences, {})]
@@ -1 +1 @@
1
- {"version":3,"file":"preferences.js","names":[],"sources":["../../../src/renderer/preferences/preferences.tsx"],"sourcesContent":["import { Renderer } from \"@freelensapp/extensions\";\nimport { AiPreferences } from \"./ai-preferences\";\nimport { AppearancePreferences } from \"./appearance-preferences\";\nimport { DashboardPreferences } from \"./dashboard-preferences\";\nimport { MonitoringPreferences } from \"./monitoring-preferences\";\nimport { NodeShellPreferences } from \"./node-shell-preferences\";\nimport { PowerPreferencesToggle } from \"./power-preferences\";\nimport { ReadOnlyPreferences } from \"./read-only-preferences\";\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; }\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\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 <section 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 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 </section>\n <section 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 aria-labelledby=\"freelens-power-shell-title\">\n <h3 id=\"freelens-power-shell-title\">\n <Renderer.Component.Icon material=\"terminal\" size={20} /> Secure Node Shell\n </h3>\n <NodeShellPreferences />\n </section>\n <section 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 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":";;;;;;;;;;;AAUA,IAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0Cf,IAAa,yBACX,oCAAA,KAAC,OAAD;CAAK,WAAU;WAAf;EACE,oCAAA,IAAC,SAAD,EAAA,UAAQ,OAAc,CAAA;EACtB,oCAAA,IAAC,wBAAA,gBAAD,CAAiB,CAAA;EACjB,oCAAA,IAAC,WAAD;GAAS,cAAW;aAClB,oCAAA,IAAC,0BAAA,wBAAD,CAAyB,CAAA;EAClB,CAAA;EACT,oCAAA,KAAC,WAAD;GAAS,mBAAgB;aAAzB,CACE,oCAAA,KAAC,MAAD;IAAI,IAAG;cAAP,CACE,oCAAA,IAAC,mBAAA,SAAS,UAAU,MAApB;KAAyB,UAAS;KAAe,MAAM;IAAK,CAAA,GAAC,iBAC3D;OACJ,oCAAA,IAAC,8BAAA,qBAAD,CAAsB,CAAA,CACf;;EACT,oCAAA,KAAC,WAAD;GAAS,mBAAgB;aAAzB,CACE,oCAAA,KAAC,MAAD;IAAI,IAAG;cAAP,CACE,oCAAA,IAAC,mBAAA,SAAS,UAAU,MAApB;KAAyB,UAAS;KAAU,MAAM;IAAK,CAAA,GAAC,aACtD;OACJ,oCAAA,IAAC,+BAAA,uBAAD,CAAwB,CAAA,CACjB;;EACT,oCAAA,KAAC,WAAD;GAAS,mBAAgB;aAAzB,CACE,oCAAA,KAAC,MAAD;IAAI,IAAG;cAAP,CACE,oCAAA,IAAC,mBAAA,SAAS,UAAU,MAApB;KAAyB,UAAS;KAAa,MAAM;IAAK,CAAA,GAAC,aACzD;OACJ,oCAAA,IAAC,+BAAA,uBAAD,CAAwB,CAAA,CACjB;;EACT,oCAAA,KAAC,WAAD;GAAS,mBAAgB;aAAzB,CACE,oCAAA,KAAC,MAAD;IAAI,IAAG;cAAP,CACE,oCAAA,IAAC,mBAAA,SAAS,UAAU,MAApB;KAAyB,UAAS;KAAW,MAAM;IAAK,CAAA,GAAC,oBACvD;OACJ,oCAAA,IAAC,+BAAA,sBAAD,CAAuB,CAAA,CAChB;;EACT,oCAAA,KAAC,WAAD;GAAS,mBAAgB;aAAzB,CACE,oCAAA,KAAC,MAAD;IAAI,IAAG;cAAP,CACE,oCAAA,IAAC,mBAAA,SAAS,UAAU,MAApB;KAAyB,UAAS;KAAsB,MAAM;IAAK,CAAA,GAAC,eAClE;OACJ,oCAAA,IAAC,uBAAA,eAAD,CAAgB,CAAA,CACT;;EACT,oCAAA,KAAC,WAAD;GAAS,mBAAgB;aAAzB,CACE,oCAAA,KAAC,MAAD;IAAI,IAAG;cAAP,CACE,oCAAA,IAAC,mBAAA,SAAS,UAAU,MAApB;KAAyB,UAAS;KAAY,MAAM;IAAK,CAAA,GAAC,YACxD;OACJ,oCAAA,IAAC,8BAAA,sBAAD,CAAuB,CAAA,CAChB;;CACN"}
1
+ {"version":3,"file":"preferences.js","names":[],"sources":["../../../src/renderer/preferences/preferences.tsx"],"sourcesContent":["import { Renderer } from \"@freelensapp/extensions\";\nimport { AiPreferences } from \"./ai-preferences\";\nimport { AppearancePreferences } from \"./appearance-preferences\";\nimport { DashboardPreferences } from \"./dashboard-preferences\";\nimport { MonitoringPreferences } from \"./monitoring-preferences\";\nimport { NodeShellPreferences } from \"./node-shell-preferences\";\nimport { PowerPreferencesToggle } from \"./power-preferences\";\nimport { ReadOnlyPreferences } from \"./read-only-preferences\";\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; }\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\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 <section 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 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 </section>\n <section 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 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 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 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":";;;;;;;;;;;AAUA,IAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0Cf,IAAa,yBACX,oCAAA,KAAC,OAAD;CAAK,WAAU;WAAf;EACE,oCAAA,IAAC,SAAD,EAAA,UAAQ,OAAc,CAAA;EACtB,oCAAA,IAAC,wBAAA,gBAAD,CAAiB,CAAA;EACjB,oCAAA,IAAC,WAAD;GAAS,cAAW;aAClB,oCAAA,IAAC,0BAAA,wBAAD,CAAyB,CAAA;EAClB,CAAA;EACT,oCAAA,KAAC,WAAD;GAAS,mBAAgB;aAAzB,CACE,oCAAA,KAAC,MAAD;IAAI,IAAG;cAAP,CACE,oCAAA,IAAC,mBAAA,SAAS,UAAU,MAApB;KAAyB,UAAS;KAAe,MAAM;IAAK,CAAA,GAAC,iBAC3D;OACJ,oCAAA,IAAC,8BAAA,qBAAD,CAAsB,CAAA,CACf;;EACT,oCAAA,KAAC,WAAD;GAAS,mBAAgB;aAAzB,CACE,oCAAA,KAAC,MAAD;IAAI,IAAG;cAAP,CACE,oCAAA,IAAC,mBAAA,SAAS,UAAU,MAApB;KAAyB,UAAS;KAAU,MAAM;IAAK,CAAA,GAAC,aACtD;OACJ,oCAAA,IAAC,+BAAA,uBAAD,CAAwB,CAAA,CACjB;;EACT,oCAAA,KAAC,WAAD;GAAS,mBAAgB;aAAzB,CACE,oCAAA,KAAC,MAAD;IAAI,IAAG;cAAP,CACE,oCAAA,IAAC,mBAAA,SAAS,UAAU,MAApB;KAAyB,UAAS;KAAa,MAAM;IAAK,CAAA,GAAC,aACzD;OACJ,oCAAA,IAAC,+BAAA,uBAAD,CAAwB,CAAA,CACjB;;EACT,oCAAA,KAAC,WAAD;GAAS,mBAAgB;aAAzB,CACE,oCAAA,KAAC,MAAD;IAAI,IAAG;cAAP,CACE,oCAAA,IAAC,mBAAA,SAAS,UAAU,MAApB;KAAyB,UAAS;KAAU,MAAM;IAAK,CAAA,GAAC,oBACtD;OACJ,oCAAA,IAAC,+BAAA,sBAAD,CAAuB,CAAA,CAChB;;EACT,oCAAA,KAAC,WAAD;GAAS,mBAAgB;aAAzB,CACE,oCAAA,KAAC,MAAD;IAAI,IAAG;cAAP,CACE,oCAAA,IAAC,mBAAA,SAAS,UAAU,MAApB;KAAyB,UAAS;KAAsB,MAAM;IAAK,CAAA,GAAC,eAClE;OACJ,oCAAA,IAAC,uBAAA,eAAD,CAAgB,CAAA,CACT;;EACT,oCAAA,KAAC,WAAD;GAAS,mBAAgB;aAAzB,CACE,oCAAA,KAAC,MAAD;IAAI,IAAG;cAAP,CACE,oCAAA,IAAC,mBAAA,SAAS,UAAU,MAApB;KAAyB,UAAS;KAAY,MAAM;IAAK,CAAA,GAAC,YACxD;OACJ,oCAAA,IAAC,8BAAA,sBAAD,CAAuB,CAAA,CAChB;;CACN"}
@@ -11,7 +11,9 @@ function SettingsIconAction({ material, label, disabled = false, onClick }) {
11
11
  onClick,
12
12
  children: /* @__PURE__ */ require_jsx_runtime.jsx(require_extensions.Renderer.Component.Icon, {
13
13
  material,
14
- size: 18
14
+ size: 18,
15
+ tooltip: label,
16
+ tooltipOverrideDisabled: true
15
17
  })
16
18
  });
17
19
  }
@@ -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} />\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;EAAK,CAAA;CAClD,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\";\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"}
@@ -24,6 +24,22 @@ function normalizeAiReferences(value) {
24
24
  }
25
25
  return references;
26
26
  }
27
+ function referencedAiResources(text, value) {
28
+ const candidates = normalizeAiReferences(value);
29
+ const tokens = new Set((text.match(/[A-Za-z0-9][A-Za-z0-9.-]*/g) ?? []).map((token) => token.replace(/\.+$/, "")));
30
+ const qualifiedTokens = new Set((text.match(/[A-Za-z0-9][A-Za-z0-9./-]*/g) ?? []).map((token) => token.replace(/\.+$/, "")));
31
+ return candidates.filter((reference) => {
32
+ if (!tokens.has(reference.name)) return false;
33
+ const matches = candidates.filter((item) => item.name === reference.name);
34
+ if (matches.length === 1) {
35
+ const qualifiedMentions = [...qualifiedTokens].filter((token) => token.endsWith(`/${reference.name}`));
36
+ return !qualifiedMentions.length || qualifiedMentions.some((token) => token === `${reference.namespace}/${reference.name}` || token === `${reference.kind}/${reference.name}`);
37
+ }
38
+ const qualified = reference.namespace ? `${reference.namespace}/${reference.name}` : "";
39
+ if (!qualified || !qualifiedTokens.has(qualified)) return false;
40
+ return matches.filter((item) => item.namespace === reference.namespace).length === 1;
41
+ }).slice(0, 5);
42
+ }
27
43
  function attachedAiContext(context) {
28
44
  const result = {};
29
45
  if (typeof context.clusterId === "string" && context.clusterId.length <= 256) result.clusterId = context.clusterId;
@@ -46,6 +62,7 @@ function attachedAiContext(context) {
46
62
  exports.AI_CANCEL_CHANNEL = AI_CANCEL_CHANNEL;
47
63
  exports.attachedAiContext = attachedAiContext;
48
64
  exports.normalizeAiReferences = normalizeAiReferences;
65
+ exports.referencedAiResources = referencedAiResources;
49
66
  exports.validAiResourceReference = validAiResourceReference;
50
67
 
51
68
  //# sourceMappingURL=ai-extras.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ai-extras.js","names":[],"sources":["../../../../src/common/ai-extras.ts"],"sourcesContent":["import type { AiChatRequest } from \"./ai\";\n\nexport const AI_CANCEL_CHANNEL = \"freelens-power:ai-cancel\";\n\nexport interface AiResourceReference {\n apiVersion: string;\n kind: string;\n name: string;\n namespace?: string;\n}\n\nconst identifier = /^[a-z0-9][a-z0-9.-]{0,252}$/;\n\nexport function validAiResourceReference(value: unknown): value is AiResourceReference {\n if (!value || typeof value !== \"object\") return false;\n const item = value as AiResourceReference;\n return (\n typeof item.apiVersion === \"string\" &&\n /^(?:[a-z0-9][a-z0-9.-]{0,200}\\/)?v[0-9]+(?:(?:alpha|beta)[0-9]+)?$/.test(item.apiVersion) &&\n typeof item.kind === \"string\" &&\n /^[A-Z][A-Za-z0-9]{0,100}$/.test(item.kind) &&\n typeof item.name === \"string\" &&\n identifier.test(item.name) &&\n (item.namespace === undefined || (typeof item.namespace === \"string\" && identifier.test(item.namespace)))\n );\n}\n\nexport function normalizeAiReferences(value: unknown): AiResourceReference[] {\n if (!Array.isArray(value)) return [];\n const references: AiResourceReference[] = [];\n const seen = new Set<string>();\n for (const item of value.slice(0, 200)) {\n if (!validAiResourceReference(item)) continue;\n const reference: AiResourceReference = {\n apiVersion: item.apiVersion,\n kind: item.kind,\n name: item.name,\n ...(item.namespace ? { namespace: item.namespace } : {}),\n };\n const key = JSON.stringify(reference);\n if (!seen.has(key)) references.push(reference);\n seen.add(key);\n }\n return references;\n}\n\nexport function attachedAiContext(context: AiChatRequest[\"context\"]): AiChatRequest[\"context\"] {\n const result: AiChatRequest[\"context\"] = {};\n if (typeof context.clusterId === \"string\" && context.clusterId.length <= 256) result.clusterId = context.clusterId;\n if (typeof context.screen === \"string\" && context.screen.startsWith(\"/\") && !/[?#]/.test(context.screen))\n result.screen = context.screen.slice(0, 2048);\n if (context.resource && typeof context.resource === \"object\") {\n const resource: NonNullable<AiChatRequest[\"context\"][\"resource\"]> = {};\n for (const key of [\"kind\", \"namespace\", \"name\"] as const) {\n const value = context.resource[key];\n if (typeof value === \"string\" && /^[A-Za-z0-9][A-Za-z0-9._-]{0,252}$/.test(value)) resource[key] = value;\n }\n if (Object.keys(resource).length) result.resource = resource;\n }\n return result;\n}\n"],"mappings":";AAEA,IAAa,oBAAoB;AASjC,IAAM,aAAa;AAEnB,SAAgB,yBAAyB,OAA8C;CACrF,IAAI,CAAC,SAAS,OAAO,UAAU,UAAU,OAAO;CAChD,MAAM,OAAO;CACb,OACE,OAAO,KAAK,eAAe,YAC3B,qEAAqE,KAAK,KAAK,UAAU,KACzF,OAAO,KAAK,SAAS,YACrB,4BAA4B,KAAK,KAAK,IAAI,KAC1C,OAAO,KAAK,SAAS,YACrB,WAAW,KAAK,KAAK,IAAI,MACxB,KAAK,cAAc,KAAA,KAAc,OAAO,KAAK,cAAc,YAAY,WAAW,KAAK,KAAK,SAAS;AAE1G;AAEA,SAAgB,sBAAsB,OAAuC;CAC3E,IAAI,CAAC,MAAM,QAAQ,KAAK,GAAG,OAAO,CAAC;CACnC,MAAM,aAAoC,CAAC;CAC3C,MAAM,uBAAO,IAAI,IAAY;CAC7B,KAAK,MAAM,QAAQ,MAAM,MAAM,GAAG,GAAG,GAAG;EACtC,IAAI,CAAC,yBAAyB,IAAI,GAAG;EACrC,MAAM,YAAiC;GACrC,YAAY,KAAK;GACjB,MAAM,KAAK;GACX,MAAM,KAAK;GACX,GAAI,KAAK,YAAY,EAAE,WAAW,KAAK,UAAU,IAAI,CAAC;EACxD;EACA,MAAM,MAAM,KAAK,UAAU,SAAS;EACpC,IAAI,CAAC,KAAK,IAAI,GAAG,GAAG,WAAW,KAAK,SAAS;EAC7C,KAAK,IAAI,GAAG;CACd;CACA,OAAO;AACT;AAEA,SAAgB,kBAAkB,SAA6D;CAC7F,MAAM,SAAmC,CAAC;CAC1C,IAAI,OAAO,QAAQ,cAAc,YAAY,QAAQ,UAAU,UAAU,KAAK,OAAO,YAAY,QAAQ;CACzG,IAAI,OAAO,QAAQ,WAAW,YAAY,QAAQ,OAAO,WAAW,GAAG,KAAK,CAAC,OAAO,KAAK,QAAQ,MAAM,GACrG,OAAO,SAAS,QAAQ,OAAO,MAAM,GAAG,IAAI;CAC9C,IAAI,QAAQ,YAAY,OAAO,QAAQ,aAAa,UAAU;EAC5D,MAAM,WAA8D,CAAC;EACrE,KAAK,MAAM,OAAO;GAAC;GAAQ;GAAa;EAAM,GAAY;GACxD,MAAM,QAAQ,QAAQ,SAAS;GAC/B,IAAI,OAAO,UAAU,YAAY,qCAAqC,KAAK,KAAK,GAAG,SAAS,OAAO;EACrG;EACA,IAAI,OAAO,KAAK,QAAQ,CAAC,CAAC,QAAQ,OAAO,WAAW;CACtD;CACA,OAAO;AACT"}
1
+ {"version":3,"file":"ai-extras.js","names":[],"sources":["../../../../src/common/ai-extras.ts"],"sourcesContent":["import type { AiChatRequest } from \"./ai\";\n\nexport const AI_CANCEL_CHANNEL = \"freelens-power:ai-cancel\";\n\nexport interface AiResourceReference {\n apiVersion: string;\n kind: string;\n name: string;\n namespace?: string;\n}\n\nconst identifier = /^[a-z0-9][a-z0-9.-]{0,252}$/;\n\nexport function validAiResourceReference(value: unknown): value is AiResourceReference {\n if (!value || typeof value !== \"object\") return false;\n const item = value as AiResourceReference;\n return (\n typeof item.apiVersion === \"string\" &&\n /^(?:[a-z0-9][a-z0-9.-]{0,200}\\/)?v[0-9]+(?:(?:alpha|beta)[0-9]+)?$/.test(item.apiVersion) &&\n typeof item.kind === \"string\" &&\n /^[A-Z][A-Za-z0-9]{0,100}$/.test(item.kind) &&\n typeof item.name === \"string\" &&\n identifier.test(item.name) &&\n (item.namespace === undefined || (typeof item.namespace === \"string\" && identifier.test(item.namespace)))\n );\n}\n\nexport function normalizeAiReferences(value: unknown): AiResourceReference[] {\n if (!Array.isArray(value)) return [];\n const references: AiResourceReference[] = [];\n const seen = new Set<string>();\n for (const item of value.slice(0, 200)) {\n if (!validAiResourceReference(item)) continue;\n const reference: AiResourceReference = {\n apiVersion: item.apiVersion,\n kind: item.kind,\n name: item.name,\n ...(item.namespace ? { namespace: item.namespace } : {}),\n };\n const key = JSON.stringify(reference);\n if (!seen.has(key)) references.push(reference);\n seen.add(key);\n }\n return references;\n}\n\nexport function referencedAiResources(text: string, value: unknown): AiResourceReference[] {\n const candidates = normalizeAiReferences(value);\n const tokens = new Set((text.match(/[A-Za-z0-9][A-Za-z0-9.-]*/g) ?? []).map((token) => token.replace(/\\.+$/, \"\")));\n const qualifiedTokens = new Set(\n (text.match(/[A-Za-z0-9][A-Za-z0-9./-]*/g) ?? []).map((token) => token.replace(/\\.+$/, \"\")),\n );\n return candidates\n .filter((reference) => {\n if (!tokens.has(reference.name)) return false;\n const matches = candidates.filter((item) => item.name === reference.name);\n if (matches.length === 1) {\n const qualifiedMentions = [...qualifiedTokens].filter((token) => token.endsWith(`/${reference.name}`));\n return (\n !qualifiedMentions.length ||\n qualifiedMentions.some(\n (token) =>\n token === `${reference.namespace}/${reference.name}` || token === `${reference.kind}/${reference.name}`,\n )\n );\n }\n // ambiguous names require an explicit namespace/name pair in the answer\n const qualified = reference.namespace ? `${reference.namespace}/${reference.name}` : \"\";\n if (!qualified || !qualifiedTokens.has(qualified)) return false;\n return matches.filter((item) => item.namespace === reference.namespace).length === 1;\n })\n .slice(0, 5);\n}\n\nexport function attachedAiContext(context: AiChatRequest[\"context\"]): AiChatRequest[\"context\"] {\n const result: AiChatRequest[\"context\"] = {};\n if (typeof context.clusterId === \"string\" && context.clusterId.length <= 256) result.clusterId = context.clusterId;\n if (typeof context.screen === \"string\" && context.screen.startsWith(\"/\") && !/[?#]/.test(context.screen))\n result.screen = context.screen.slice(0, 2048);\n if (context.resource && typeof context.resource === \"object\") {\n const resource: NonNullable<AiChatRequest[\"context\"][\"resource\"]> = {};\n for (const key of [\"kind\", \"namespace\", \"name\"] as const) {\n const value = context.resource[key];\n if (typeof value === \"string\" && /^[A-Za-z0-9][A-Za-z0-9._-]{0,252}$/.test(value)) resource[key] = value;\n }\n if (Object.keys(resource).length) result.resource = resource;\n }\n return result;\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"dashboard-selector.js","names":[],"sources":["../../../../src/common/dashboard-selector.ts"],"sourcesContent":["export const dashboardSelectorLimit = 512;\n\nexport function normalizeDashboardSelector(value: unknown): string | undefined {\n if (typeof value !== \"string\") return undefined;\n const selector = value.trim();\n return selector && selector.length <= dashboardSelectorLimit && !/[\\u0000-\\u001f\\u007f]/.test(selector)\n ? selector\n : undefined;\n}\n\n// this function runs only inside the isolated website world\nexport function dashboardSelectorAdapter(selector: string): void {\n const state = globalThis as typeof globalThis & { powerSelectorCleanup?: () => void };\n state.powerSelectorCleanup?.();\n if (!selector) return;\n const hidden = \"data-power-selector-hidden\";\n const path = \"data-power-selector-path\";\n let marked: Element[] = [];\n let timer: ReturnType<typeof setTimeout> | undefined;\n const style = document.createElement(\"style\");\n style.textContent = `[${hidden}] { display: none !important; } [${path}] { display: block !important; position: static !important; width: auto !important; height: auto !important; min-height: 0 !important; max-height: none !important; overflow: visible !important; margin: 0 !important; padding: 0 !important; transform: none !important; }`;\n const notice = document.createElement(\"div\");\n notice.textContent =\n \"Selected element unavailable. Showing the whole page. Clear CSS selector in card settings to reset.\";\n notice.style.cssText =\n \"position:fixed;top:0;left:0;right:0;z-index:2147483647;padding:8px;background:#292929;color:white;font:12px sans-serif\";\n const observer = new MutationObserver(() => {\n if (!timer) timer = setTimeout(update, 200);\n });\n function restore() {\n for (const element of marked) {\n element.removeAttribute(hidden);\n element.removeAttribute(path);\n }\n marked = [];\n style.remove();\n notice.remove();\n }\n function update() {\n timer = undefined;\n observer.disconnect();\n restore();\n let target: Element | null = null;\n try {\n target = document.querySelector(selector);\n } catch {}\n const branches: Element[] = [];\n const ancestors: Element[] = [];\n if (target && target !== document.documentElement && target !== document.body) {\n let child: Element = target;\n while (child.parentElement && ancestors.length < 128 && branches.length < 2000) {\n const parent = child.parentElement;\n ancestors.push(parent);\n for (const sibling of parent.children) {\n if (sibling !== child) branches.push(sibling);\n if (branches.length >= 2000) break;\n }\n child = parent;\n }\n if (ancestors.length >= 128 || branches.length >= 2000) target = null;\n }\n if (target) {\n for (const element of branches) element.setAttribute(hidden, \"\");\n for (const element of ancestors) element.setAttribute(path, \"\");\n marked = [...branches, ...ancestors];\n document.documentElement.append(style);\n } else {\n document.documentElement.append(notice);\n }\n observer.observe(document.documentElement, { subtree: true, childList: true, attributes: true });\n }\n state.powerSelectorCleanup = () => {\n observer.disconnect();\n clearTimeout(timer);\n restore();\n delete state.powerSelectorCleanup;\n };\n update();\n}\n\nexport function dashboardSelectorScript(selector?: string): string {\n return `(${dashboardSelectorAdapter.toString()})(${JSON.stringify(normalizeDashboardSelector(selector) ?? \"\")})`;\n}\n"],"mappings":"AAEA,SAAgB,2BAA2B,OAAoC;CAC7E,IAAI,OAAO,UAAU,UAAU,OAAO,KAAA;CACtC,MAAM,WAAW,MAAM,KAAK;CAC5B,OAAO,YAAY,SAAS,UAAA,OAAoC,CAAC,wBAAwB,KAAK,QAAQ,IAClG,WACA,KAAA;AACN"}
1
+ {"version":3,"file":"dashboard-selector.js","names":[],"sources":["../../../../src/common/dashboard-selector.ts"],"sourcesContent":["export const dashboardSelectorLimit = 512;\n\nexport function normalizeDashboardSelector(value: unknown): string | undefined {\n if (typeof value !== \"string\") return undefined;\n const selector = value.trim();\n return selector && selector.length <= dashboardSelectorLimit && !/[\\u0000-\\u001f\\u007f]/.test(selector)\n ? selector\n : undefined;\n}\n\n// this function runs only inside the isolated website world\nexport function dashboardSelectorAdapter(selector: string): void {\n const state = globalThis as typeof globalThis & { powerSelectorCleanup?: () => void };\n state.powerSelectorCleanup?.();\n if (!selector) return;\n const hidden = \"data-power-selector-hidden\";\n const path = \"data-power-selector-path\";\n const inset = \"data-power-selector-inset\";\n let insetRoot: HTMLElement | undefined;\n let marked: Element[] = [];\n let timer: ReturnType<typeof setTimeout> | undefined;\n const style = document.createElement(\"style\");\n style.textContent = `[${hidden}] { display: none !important; } [${path}] { display: block !important; position: static !important; width: auto !important; height: auto !important; min-height: 0 !important; max-height: none !important; overflow: visible !important; margin: 0 !important; padding: 0 !important; transform: none !important; } body[${inset}] { padding: 12px !important; box-sizing: border-box !important; }`;\n const notice = document.createElement(\"div\");\n notice.textContent =\n \"Selected element unavailable. Showing the whole page. Clear CSS selector in card settings to reset.\";\n notice.style.cssText =\n \"position:fixed;top:0;left:0;right:0;z-index:2147483647;padding:8px;background:#292929;color:white;font:12px sans-serif\";\n const observer = new MutationObserver(() => {\n if (!timer) timer = setTimeout(update, 200);\n });\n function restore() {\n for (const element of marked) {\n element.removeAttribute(hidden);\n element.removeAttribute(path);\n }\n marked = [];\n insetRoot?.removeAttribute(inset);\n insetRoot = undefined;\n style.remove();\n notice.remove();\n }\n function update() {\n timer = undefined;\n observer.disconnect();\n restore();\n let target: Element | null = null;\n try {\n target = document.querySelector(selector);\n } catch {}\n const branches: Element[] = [];\n const ancestors: Element[] = [];\n if (target && target !== document.documentElement && target !== document.body) {\n let child: Element = target;\n while (child.parentElement && ancestors.length < 128 && branches.length < 2000) {\n const parent = child.parentElement;\n ancestors.push(parent);\n for (const sibling of parent.children) {\n if (sibling !== child) branches.push(sibling);\n if (branches.length >= 2000) break;\n }\n child = parent;\n }\n if (ancestors.length >= 128 || branches.length >= 2000) target = null;\n }\n if (target) {\n for (const element of branches) element.setAttribute(hidden, \"\");\n for (const element of ancestors) element.setAttribute(path, \"\");\n marked = [...branches, ...ancestors];\n if (document.body) {\n insetRoot = document.body;\n insetRoot.setAttribute(inset, \"\");\n }\n document.documentElement.append(style);\n } else {\n document.documentElement.append(notice);\n }\n observer.observe(document.documentElement, { subtree: true, childList: true, attributes: true });\n }\n state.powerSelectorCleanup = () => {\n observer.disconnect();\n clearTimeout(timer);\n restore();\n delete state.powerSelectorCleanup;\n };\n update();\n}\n\nexport function dashboardSelectorScript(selector?: string): string {\n return `(${dashboardSelectorAdapter.toString()})(${JSON.stringify(normalizeDashboardSelector(selector) ?? \"\")})`;\n}\n"],"mappings":"AAEA,SAAgB,2BAA2B,OAAoC;CAC7E,IAAI,OAAO,UAAU,UAAU,OAAO,KAAA;CACtC,MAAM,WAAW,MAAM,KAAK;CAC5B,OAAO,YAAY,SAAS,UAAA,OAAoC,CAAC,wBAAwB,KAAK,QAAQ,IAClG,WACA,KAAA;AACN"}
@@ -2,12 +2,14 @@
2
2
  var DASHBOARD_VIEWS_SYNC = "freelens-power:dashboard-views:sync";
3
3
  var DASHBOARD_VIEWS_RELOAD = "freelens-power:dashboard-views:reload";
4
4
  var DASHBOARD_VIEWS_CLEAR = "freelens-power:dashboard-views:clear";
5
+ var DASHBOARD_VIEWS_LOADING = "freelens-power:dashboard-views:loading";
5
6
  var DASHBOARD_SITE_ICONS = "freelens-power:dashboard-site-icons";
6
7
  var DASHBOARD_VIEWS_PIN = "freelens-power:dashboard-views:pin";
7
8
  var DASHBOARD_VIEWS_PINNED = "freelens-power:dashboard-views:pinned";
8
9
  //#endregion
9
10
  exports.DASHBOARD_SITE_ICONS = DASHBOARD_SITE_ICONS;
10
11
  exports.DASHBOARD_VIEWS_CLEAR = DASHBOARD_VIEWS_CLEAR;
12
+ exports.DASHBOARD_VIEWS_LOADING = DASHBOARD_VIEWS_LOADING;
11
13
  exports.DASHBOARD_VIEWS_PIN = DASHBOARD_VIEWS_PIN;
12
14
  exports.DASHBOARD_VIEWS_PINNED = DASHBOARD_VIEWS_PINNED;
13
15
  exports.DASHBOARD_VIEWS_RELOAD = DASHBOARD_VIEWS_RELOAD;
@@ -1 +1 @@
1
- {"version":3,"file":"dashboard-views.js","names":[],"sources":["../../../../src/common/dashboard-views.ts"],"sourcesContent":["export const DASHBOARD_VIEWS_SYNC = \"freelens-power:dashboard-views:sync\";\nexport const DASHBOARD_VIEWS_RELOAD = \"freelens-power:dashboard-views:reload\";\nexport const DASHBOARD_VIEWS_CLEAR = \"freelens-power:dashboard-views:clear\";\n\nexport interface DashboardViewBounds {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\nexport interface DashboardViewPlacement {\n id: string;\n bounds: DashboardViewBounds;\n clip: DashboardViewBounds;\n}\n\nexport const DASHBOARD_SITE_ICONS = \"freelens-power:dashboard-site-icons\";\n\nexport interface DashboardSiteIcon {\n id: string;\n pageUrl: string;\n dataUrl: string;\n}\n\nexport const DASHBOARD_VIEWS_PIN = \"freelens-power:dashboard-views:pin\";\nexport const DASHBOARD_VIEWS_PINNED = \"freelens-power:dashboard-views:pinned\";\n"],"mappings":";AAAA,IAAa,uBAAuB;AACpC,IAAa,yBAAyB;AACtC,IAAa,wBAAwB;AAerC,IAAa,uBAAuB;AAQpC,IAAa,sBAAsB;AACnC,IAAa,yBAAyB"}
1
+ {"version":3,"file":"dashboard-views.js","names":[],"sources":["../../../../src/common/dashboard-views.ts"],"sourcesContent":["export const DASHBOARD_VIEWS_SYNC = \"freelens-power:dashboard-views:sync\";\nexport const DASHBOARD_VIEWS_RELOAD = \"freelens-power:dashboard-views:reload\";\nexport const DASHBOARD_VIEWS_CLEAR = \"freelens-power:dashboard-views:clear\";\nexport const DASHBOARD_VIEWS_LOADING = \"freelens-power:dashboard-views:loading\";\n\nexport interface DashboardViewLoading {\n id: string;\n url: string;\n loading: boolean;\n failed: boolean;\n}\n\nexport interface DashboardViewBounds {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\nexport interface DashboardViewPlacement {\n id: string;\n bounds: DashboardViewBounds;\n clip: DashboardViewBounds;\n}\n\nexport const DASHBOARD_SITE_ICONS = \"freelens-power:dashboard-site-icons\";\n\nexport interface DashboardSiteIcon {\n id: string;\n pageUrl: string;\n dataUrl: string;\n}\n\nexport const DASHBOARD_VIEWS_PIN = \"freelens-power:dashboard-views:pin\";\nexport const DASHBOARD_VIEWS_PINNED = \"freelens-power:dashboard-views:pinned\";\n"],"mappings":";AAAA,IAAa,uBAAuB;AACpC,IAAa,yBAAyB;AACtC,IAAa,wBAAwB;AACrC,IAAa,0BAA0B;AAsBvC,IAAa,uBAAuB;AAQpC,IAAa,sBAAsB;AACnC,IAAa,yBAAyB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@64mb/freelens-power",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "Power tools for Freelens Kubernetes IDE",
5
5
  "main": "out/main/index.js",
6
6
  "renderer": "out/renderer/index.js",