@64mb/freelens-power 1.3.0 → 1.5.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.
- package/README.md +4 -4
- package/out/main/common/resource-search.js +61 -0
- package/out/main/common/resource-search.js.map +1 -0
- package/out/main/common/store/monitoring-preferences-store.js +10 -0
- package/out/main/common/store/monitoring-preferences-store.js.map +1 -1
- package/out/main/index.js +2 -0
- package/out/main/index.js.map +1 -1
- package/out/main/resource-search-database.js +209 -0
- package/out/main/resource-search-database.js.map +1 -0
- package/out/main/resource-search-worker.js +56 -0
- package/out/main/resource-search-worker.js.map +1 -0
- package/out/main/resource-search.js +155 -0
- package/out/main/resource-search.js.map +1 -0
- package/out/renderer/appearance.js +1 -1
- package/out/renderer/appearance.js.map +1 -1
- package/out/renderer/details/resource-health-details.js +8 -4
- package/out/renderer/details/resource-health-details.js.map +1 -1
- package/out/renderer/diagnostics-state.js +7 -5
- package/out/renderer/diagnostics-state.js.map +1 -1
- package/out/renderer/diagnostics.css.js +2 -2
- package/out/renderer/diagnostics.css.js.map +1 -1
- package/out/renderer/diagnostics.js +127 -51
- package/out/renderer/diagnostics.js.map +1 -1
- package/out/renderer/gateway-relationships-client.js +107 -0
- package/out/renderer/gateway-relationships-client.js.map +1 -0
- package/out/renderer/index.js +2 -2
- package/out/renderer/index.js.map +1 -1
- package/out/renderer/monitoring.js +15 -0
- package/out/renderer/monitoring.js.map +1 -1
- package/out/renderer/preferences/monitoring-preferences.js +11 -1
- package/out/renderer/preferences/monitoring-preferences.js.map +1 -1
- package/out/renderer/preferences/preferences.js +16 -6
- package/out/renderer/preferences/preferences.js.map +1 -1
- package/out/renderer/resource-relationships.css.js +1 -1
- package/out/renderer/resource-relationships.css.js.map +1 -1
- package/out/renderer/resource-relationships.js +71 -18
- package/out/renderer/resource-relationships.js.map +1 -1
- package/out/renderer/resource-search-client.js +116 -0
- package/out/renderer/resource-search-client.js.map +1 -0
- package/out/renderer/resource-search-discovery.js +79 -0
- package/out/renderer/resource-search-discovery.js.map +1 -0
- package/out/renderer/resource-search-model.js +2 -1
- package/out/renderer/resource-search-model.js.map +1 -1
- package/out/renderer/resource-search-routing.js +78 -0
- package/out/renderer/resource-search-routing.js.map +1 -0
- package/out/renderer/resource-search-sync.js +199 -0
- package/out/renderer/resource-search-sync.js.map +1 -0
- package/out/renderer/resource-search.js +279 -54
- package/out/renderer/resource-search.js.map +1 -1
- package/out/renderer/src/common/gateway-relationships.js +122 -0
- package/out/renderer/src/common/gateway-relationships.js.map +1 -0
- package/out/renderer/src/common/resource-relationships.js +8 -0
- package/out/renderer/src/common/resource-relationships.js.map +1 -1
- package/out/renderer/src/common/resource-search.js +6 -0
- package/out/renderer/src/common/resource-search.js.map +1 -0
- package/out/renderer/src/common/store/monitoring-preferences-store.js +10 -0
- package/out/renderer/src/common/store/monitoring-preferences-store.js.map +1 -1
- package/package.json +6 -2
|
@@ -16,7 +16,7 @@ var styles = `
|
|
|
16
16
|
#freelens-power-settings > .SubTitle,
|
|
17
17
|
#freelens-power-settings > .hint,
|
|
18
18
|
#freelens-power-settings + hr { display: none; }
|
|
19
|
-
.freelens-power-preferences { display: grid; gap: 24px; max-width: 760px; }
|
|
19
|
+
.freelens-power-preferences { display: grid; gap: 24px; max-width: 760px; container: power-preferences / inline-size; }
|
|
20
20
|
.freelens-power-preferences .power-preferences-section-links {
|
|
21
21
|
display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); width: 100%; gap: 8px;
|
|
22
22
|
}
|
|
@@ -29,14 +29,17 @@ var styles = `
|
|
|
29
29
|
:root .freelens-power-preferences .power-preferences-section-links button.power-settings-section-link:hover {
|
|
30
30
|
color: var(--primary); background: transparent; box-shadow: none;
|
|
31
31
|
}
|
|
32
|
+
:root .freelens-power-preferences .power-preferences-section-links button.power-settings-section-link::before {
|
|
33
|
+
content: none;
|
|
34
|
+
}
|
|
32
35
|
:root .freelens-power-preferences .power-preferences-section-links button.power-settings-section-link:focus-visible {
|
|
33
36
|
color: var(--primary); background: transparent; box-shadow: none;
|
|
34
37
|
outline: 2px solid var(--primary); outline-offset: 2px;
|
|
35
38
|
}
|
|
36
|
-
@
|
|
39
|
+
@container power-preferences (max-width: 660px) {
|
|
37
40
|
.freelens-power-preferences .power-preferences-section-links { grid-template-columns: repeat(3, minmax(0, 1fr)); }
|
|
38
41
|
}
|
|
39
|
-
@
|
|
42
|
+
@container power-preferences (max-width: 360px) {
|
|
40
43
|
.freelens-power-preferences .power-preferences-section-links { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
|
41
44
|
}
|
|
42
45
|
.freelens-power-preferences section[id] { scroll-margin-top: 16px; }
|
|
@@ -121,10 +124,17 @@ var PowerPreferences = () => /* @__PURE__ */ require_jsx_runtime.jsxs("div", {
|
|
|
121
124
|
children: sectionLinks.map(({ id, title, icon }) => /* @__PURE__ */ require_jsx_runtime.jsxs(require_extensions.Renderer.Component.Button, {
|
|
122
125
|
className: "power-settings-section-link",
|
|
123
126
|
title: `Jump to ${title} settings`,
|
|
124
|
-
onClick: () => {
|
|
127
|
+
onClick: (event) => {
|
|
128
|
+
event.preventDefault();
|
|
125
129
|
const section = document.getElementById(`freelens-power-${id}-section`);
|
|
126
|
-
|
|
127
|
-
|
|
130
|
+
requestAnimationFrame(() => {
|
|
131
|
+
if (!section?.isConnected) return;
|
|
132
|
+
section.focus({ preventScroll: true });
|
|
133
|
+
section.scrollIntoView({
|
|
134
|
+
block: "start",
|
|
135
|
+
behavior: "instant"
|
|
136
|
+
});
|
|
137
|
+
});
|
|
128
138
|
},
|
|
129
139
|
children: [
|
|
130
140
|
/* @__PURE__ */ require_jsx_runtime.jsx(require_extensions.Renderer.Component.Icon, {
|
|
@@ -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 { 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 .power-preferences-section-links {\n display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); width: 100%; gap: 8px;\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 width: 100%; min-width: 0; 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:focus-visible {\n color: var(--primary); background: transparent; box-shadow: none;\n outline: 2px solid var(--primary); outline-offset: 2px;\n }\n @media (max-width: 600px) {\n .freelens-power-preferences .power-preferences-section-links { grid-template-columns: repeat(3, minmax(0, 1fr)); }\n }\n @media (max-width: 360px) {\n .freelens-power-preferences .power-preferences-section-links { grid-template-columns: repeat(2, minmax(0, 1fr)); }\n }\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: \"shell\", title: \"Node 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 title={`Jump to ${title} settings`}\n onClick={() => {\n const section = document.getElementById(`freelens-power-${id}-section`);\n section?.focus({ preventScroll: true });\n section?.scrollIntoView({ block: \"start\" });\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-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 { 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; container: power-preferences / inline-size; }\n .freelens-power-preferences .power-preferences-section-links {\n display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); width: 100%; gap: 8px;\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 width: 100%; min-width: 0; 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) {\n .freelens-power-preferences .power-preferences-section-links { grid-template-columns: repeat(3, minmax(0, 1fr)); }\n }\n @container power-preferences (max-width: 360px) {\n .freelens-power-preferences .power-preferences-section-links { grid-template-columns: repeat(2, minmax(0, 1fr)); }\n }\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: \"shell\", title: \"Node 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 title={`Jump to ${title} settings`}\n onClick={(event) => {\n event.preventDefault();\n const section = document.getElementById(`freelens-power-${id}-section`);\n requestAnimationFrame(() => {\n if (!section?.isConnected) return;\n section.focus({ preventScroll: true });\n section.scrollIntoView({ block: \"start\", behavior: \"instant\" });\n });\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-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,6 +1,6 @@
|
|
|
1
1
|
//#region src/renderer/resource-relationships.css.ts
|
|
2
2
|
var resourceRelationshipsStyles = `
|
|
3
|
-
.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.hide-upstreams{min-width:740px;grid-template-columns:repeat(3,minmax(180px,1fr))}.power-relationships .graph-option{display:flex;align-items:center;gap:8px;
|
|
3
|
+
.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
4
|
//#endregion
|
|
5
5
|
exports.resourceRelationshipsStyles = resourceRelationshipsStyles;
|
|
6
6
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resource-relationships.css.js","names":[],"sources":["../../src/renderer/resource-relationships.css.ts"],"sourcesContent":["export const resourceRelationshipsStyles = `\n.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.hide-upstreams{min-width:740px;grid-template-columns:repeat(3,minmax(180px,1fr))}.power-relationships .graph-option{display:flex;align-items:center;gap:8px;
|
|
1
|
+
{"version":3,"file":"resource-relationships.css.js","names":[],"sources":["../../src/renderer/resource-relationships.css.ts"],"sourcesContent":["export const resourceRelationshipsStyles = `\n.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}}`;\n"],"mappings":";AAAA,IAAa,8BAA8B"}
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
const require_extensions = require("./_virtual/_global-external_@freelensapp/extensions.js");
|
|
2
2
|
const require__global_external_mobx_react = require("./_virtual/_global-external_mobx-react.js");
|
|
3
|
+
const require_monitoring_preferences_store = require("./src/common/store/monitoring-preferences-store.js");
|
|
3
4
|
const require__global_external_react = require("./_virtual/_global-external_react.js");
|
|
4
5
|
const require_jsx_runtime = require("./_virtual/_global-external_react/jsx-runtime.js");
|
|
5
6
|
const require_resource_relationships = require("./src/common/resource-relationships.js");
|
|
7
|
+
const require_gateway_relationships_client = require("./gateway-relationships-client.js");
|
|
6
8
|
const require_resource_relationships_css = require("./resource-relationships.css.js");
|
|
9
|
+
const require_resource_search_client = require("./resource-search-client.js");
|
|
10
|
+
const require_resource_search_routing = require("./resource-search-routing.js");
|
|
7
11
|
//#region src/renderer/resource-relationships.tsx
|
|
8
12
|
var { Icon, Select } = require_extensions.Renderer.Component;
|
|
9
13
|
var LIMIT = 100;
|
|
@@ -85,15 +89,18 @@ async function loadRelationshipInventory(namespace, service, signal) {
|
|
|
85
89
|
list("Ingress", () => require_extensions.Renderer.K8sApi.ingressApi.list(options, query)),
|
|
86
90
|
...ownerApis.map((api) => list("Controller", () => api.list(options, query)))
|
|
87
91
|
]);
|
|
92
|
+
const clusterId = require_extensions.Renderer.Catalog.activeCluster.get()?.metadata.uid;
|
|
93
|
+
const gateway = clusterId ? await require_gateway_relationships_client.loadGatewayInventory(require_resource_search_client.createResourceSearchTransport(clusterId, signal), signal, { focusedNamespace: namespace }) : void 0;
|
|
88
94
|
return {
|
|
89
95
|
pods,
|
|
90
96
|
slices,
|
|
91
97
|
ingresses,
|
|
92
98
|
owners: owners.flatMap((items) => items ?? []),
|
|
93
|
-
gaps
|
|
99
|
+
gaps,
|
|
100
|
+
gateway
|
|
94
101
|
};
|
|
95
102
|
}
|
|
96
|
-
function ResourceCard({ node, incoming, onOpen, onHighlight }) {
|
|
103
|
+
function ResourceCard({ node, incoming, incomingEvidence, onOpen, onHighlight }) {
|
|
97
104
|
return /* @__PURE__ */ require_jsx_runtime.jsxs("article", {
|
|
98
105
|
className: "card",
|
|
99
106
|
"data-node-id": node.id,
|
|
@@ -138,6 +145,10 @@ function ResourceCard({ node, incoming, onOpen, onHighlight }) {
|
|
|
138
145
|
" ",
|
|
139
146
|
node.detail
|
|
140
147
|
]
|
|
148
|
+
}),
|
|
149
|
+
!!(node.evidence?.length || incomingEvidence?.length) && /* @__PURE__ */ require_jsx_runtime.jsxs("details", {
|
|
150
|
+
className: "gateway-evidence",
|
|
151
|
+
children: [/* @__PURE__ */ require_jsx_runtime.jsx("summary", { children: "API evidence" }), [...node.evidence ?? [], ...incomingEvidence ?? []].map((evidence) => /* @__PURE__ */ require_jsx_runtime.jsx("p", { children: evidence }, evidence))]
|
|
141
152
|
})
|
|
142
153
|
]
|
|
143
154
|
});
|
|
@@ -159,6 +170,8 @@ function roundedConnector(points) {
|
|
|
159
170
|
return `${path} L ${last[0]} ${last[1]}`;
|
|
160
171
|
}
|
|
161
172
|
function RelationshipGraph({ graph, onOpen, ingressAvailable, hideUpstreams = false }) {
|
|
173
|
+
const upstreamIds = new Set(graph.nodes.filter((node) => node.role === "upstream").map((node) => node.id));
|
|
174
|
+
const upstreamGutter = !hideUpstreams && graph.edges.some((edge) => upstreamIds.has(edge.from) && upstreamIds.has(edge.to));
|
|
162
175
|
const visibleRoles = roles.filter((role) => !hideUpstreams || role.id !== "upstream");
|
|
163
176
|
const element = require__global_external_react.useRef(null);
|
|
164
177
|
const [paths, setPaths] = require__global_external_react.useState([]);
|
|
@@ -220,7 +233,7 @@ function RelationshipGraph({ graph, onOpen, ingressAvailable, hideUpstreams = fa
|
|
|
220
233
|
className: "graph-scroll",
|
|
221
234
|
children: /* @__PURE__ */ require_jsx_runtime.jsxs("div", {
|
|
222
235
|
ref: element,
|
|
223
|
-
className: `graph${hideUpstreams ? " hide-upstreams" : ""}`,
|
|
236
|
+
className: `graph${hideUpstreams ? " hide-upstreams" : ""}${upstreamGutter ? " upstream-gutter" : ""}`,
|
|
224
237
|
style: { gridTemplateRows: `auto repeat(${Math.max(1, ...visibleRoles.map((role) => graph.nodes.filter((node) => node.role === role.id).length))}, auto)` },
|
|
225
238
|
"aria-label": "Service resource relationship graph",
|
|
226
239
|
children: [/* @__PURE__ */ require_jsx_runtime.jsxs("svg", {
|
|
@@ -262,12 +275,13 @@ function RelationshipGraph({ graph, onOpen, ingressAvailable, hideUpstreams = fa
|
|
|
262
275
|
graph.nodes.filter((node) => node.role === role.id).map((node) => /* @__PURE__ */ require_jsx_runtime.jsx(ResourceCard, {
|
|
263
276
|
node,
|
|
264
277
|
incoming: [...new Set(graph.edges.filter((edge) => edge.to === node.id).map((edge) => edge.label))],
|
|
278
|
+
incomingEvidence: graph.edges.filter((edge) => edge.to === node.id && edge.evidence).map((edge) => edge.evidence),
|
|
265
279
|
onOpen,
|
|
266
280
|
onHighlight: setHighlight
|
|
267
281
|
}, node.id)),
|
|
268
282
|
!graph.nodes.some((node) => node.role === role.id) && /* @__PURE__ */ require_jsx_runtime.jsx("div", {
|
|
269
283
|
className: "card neutral",
|
|
270
|
-
children: role.id === "upstream" ? ingressAvailable ? "No matching
|
|
284
|
+
children: role.id === "upstream" ? ingressAvailable ? "No matching upstream references observed" : "Ingress evidence unavailable" : "No relationships observed in available evidence"
|
|
271
285
|
})
|
|
272
286
|
]
|
|
273
287
|
}, role.id))]
|
|
@@ -295,7 +309,16 @@ function EnabledResourceRelationshipsPage() {
|
|
|
295
309
|
const [services, setServices] = require__global_external_react.useState([]);
|
|
296
310
|
const [serviceName, setServiceName] = require__global_external_react.useState("");
|
|
297
311
|
const [focusedPod, setFocusedPod] = require__global_external_react.useState("");
|
|
298
|
-
const
|
|
312
|
+
const preferences = require_monitoring_preferences_store.MonitoringPreferencesStore.getInstanceOrCreate();
|
|
313
|
+
const [hideUpstreams, setHideUpstreams] = require__global_external_react.useState(() => preferences.hiddenUpstreamClusters.includes(clusterId.current ?? ""));
|
|
314
|
+
const toggleUpstreams = () => {
|
|
315
|
+
const id = clusterId.current;
|
|
316
|
+
if (!id || require_extensions.Renderer.Catalog.activeCluster.get()?.metadata.uid !== id) return;
|
|
317
|
+
const hidden = !hideUpstreams;
|
|
318
|
+
const otherClusters = preferences.hiddenUpstreamClusters.filter((cluster) => cluster !== id);
|
|
319
|
+
preferences.hiddenUpstreamClusters = hidden ? [...otherClusters, id].slice(-100) : otherClusters;
|
|
320
|
+
setHideUpstreams(hidden);
|
|
321
|
+
};
|
|
299
322
|
const [inventory, setInventory] = require__global_external_react.useState();
|
|
300
323
|
const [refresh, setRefresh] = require__global_external_react.useState(0);
|
|
301
324
|
const [scopeRefresh, setScopeRefresh] = require__global_external_react.useState(0);
|
|
@@ -377,7 +400,31 @@ function EnabledResourceRelationshipsPage() {
|
|
|
377
400
|
const currentCluster = () => mounted.current && require_extensions.Renderer.Catalog.activeCluster.get()?.metadata.uid === clusterId.current;
|
|
378
401
|
setOpenError("");
|
|
379
402
|
Promise.resolve().then(() => {
|
|
380
|
-
if (currentCluster()) return
|
|
403
|
+
if (!currentCluster()) return;
|
|
404
|
+
const gatewayPath = path.match(/^\/apis\/(gateway\.networking\.k8s\.io)\/([^/]+)\/(?:namespaces\/([^/]+)\/)?([^/]+)\/([^/]+)$/);
|
|
405
|
+
if (gatewayPath) {
|
|
406
|
+
const [, group, version, namespace, resource, name] = gatewayPath;
|
|
407
|
+
const kind = {
|
|
408
|
+
gateways: "Gateway",
|
|
409
|
+
gatewayclasses: "GatewayClass",
|
|
410
|
+
httproutes: "HTTPRoute",
|
|
411
|
+
grpcroutes: "GRPCRoute",
|
|
412
|
+
tcproutes: "TCPRoute",
|
|
413
|
+
tlsroutes: "TLSRoute",
|
|
414
|
+
udproutes: "UDPRoute"
|
|
415
|
+
}[resource];
|
|
416
|
+
return require_resource_search_routing.openSearchResource({
|
|
417
|
+
path,
|
|
418
|
+
group,
|
|
419
|
+
version,
|
|
420
|
+
namespace,
|
|
421
|
+
resource,
|
|
422
|
+
name,
|
|
423
|
+
kind,
|
|
424
|
+
labels: {}
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
return require_extensions.Renderer.Navigation.showDetails(path);
|
|
381
428
|
}).catch(() => {
|
|
382
429
|
if (currentCluster()) setOpenError("Resource details could not be opened; the object may be unavailable");
|
|
383
430
|
});
|
|
@@ -386,20 +433,13 @@ function EnabledResourceRelationshipsPage() {
|
|
|
386
433
|
className: "power-relationships",
|
|
387
434
|
children: [
|
|
388
435
|
/* @__PURE__ */ require_jsx_runtime.jsx("style", { children: require_resource_relationships_css.resourceRelationshipsStyles }),
|
|
389
|
-
/* @__PURE__ */ require_jsx_runtime.
|
|
436
|
+
/* @__PURE__ */ require_jsx_runtime.jsx("div", {
|
|
390
437
|
className: "page-heading",
|
|
391
|
-
children:
|
|
392
|
-
className: "graph-option",
|
|
393
|
-
children: [/* @__PURE__ */ require_jsx_runtime.jsx("input", {
|
|
394
|
-
type: "checkbox",
|
|
395
|
-
checked: hideUpstreams,
|
|
396
|
-
onChange: (event) => setHideUpstreams(event.target.checked)
|
|
397
|
-
}), "Hide Upstream"]
|
|
398
|
-
})]
|
|
438
|
+
children: /* @__PURE__ */ require_jsx_runtime.jsx("h2", { children: "Resource relationships" })
|
|
399
439
|
}),
|
|
400
440
|
/* @__PURE__ */ require_jsx_runtime.jsx("p", {
|
|
401
441
|
className: "intro",
|
|
402
|
-
children: "Follow one Service from upstream Ingress references to selected pods, published EndpointSlices and controller ownership. Connections show Kubernetes API evidence; they do not prove network reachability."
|
|
442
|
+
children: "Follow one Service from upstream Ingress and Gateway API references to selected pods, published EndpointSlices and controller ownership. Connections show Kubernetes API evidence; they do not prove network reachability."
|
|
403
443
|
}),
|
|
404
444
|
/* @__PURE__ */ require_jsx_runtime.jsxs("div", {
|
|
405
445
|
className: "controls",
|
|
@@ -446,6 +486,18 @@ function EnabledResourceRelationshipsPage() {
|
|
|
446
486
|
isDisabled: !graph?.podOptions.length
|
|
447
487
|
})]
|
|
448
488
|
}),
|
|
489
|
+
/* @__PURE__ */ require_jsx_runtime.jsxs("button", {
|
|
490
|
+
type: "button",
|
|
491
|
+
className: "graph-option",
|
|
492
|
+
"aria-pressed": hideUpstreams,
|
|
493
|
+
onClick: toggleUpstreams,
|
|
494
|
+
title: hideUpstreams ? "Show upstream references" : "Hide upstream references",
|
|
495
|
+
disabled: !clusterId.current,
|
|
496
|
+
children: [/* @__PURE__ */ require_jsx_runtime.jsx(Icon, {
|
|
497
|
+
material: hideUpstreams ? "visibility_off" : "visibility",
|
|
498
|
+
size: 16
|
|
499
|
+
}), "Hide Upstream"]
|
|
500
|
+
}),
|
|
449
501
|
/* @__PURE__ */ require_jsx_runtime.jsxs("button", {
|
|
450
502
|
type: "button",
|
|
451
503
|
className: "refresh",
|
|
@@ -532,13 +584,14 @@ function EnabledResourceRelationshipsPage() {
|
|
|
532
584
|
edge.label,
|
|
533
585
|
" →",
|
|
534
586
|
" ",
|
|
535
|
-
graph.nodes.find((node) => node.id === edge.to)?.name
|
|
587
|
+
graph.nodes.find((node) => node.id === edge.to)?.name,
|
|
588
|
+
edge.evidence && /* @__PURE__ */ require_jsx_runtime.jsx("div", { children: edge.evidence })
|
|
536
589
|
] }, `${edge.from}/${edge.to}/${edge.label}`))
|
|
537
590
|
})] }),
|
|
538
591
|
/* @__PURE__ */ require_jsx_runtime.jsxs("p", {
|
|
539
592
|
className: "scope",
|
|
540
593
|
children: [
|
|
541
|
-
/* @__PURE__ */ require_jsx_runtime.jsx("span", { children: "Snapshot from
|
|
594
|
+
/* @__PURE__ */ require_jsx_runtime.jsx("span", { children: "Snapshot from read-only API requests; Gateway discovery and references include other namespaces." }),
|
|
542
595
|
/* @__PURE__ */ require_jsx_runtime.jsx("span", { children: "Owner and node references can point to objects that were not queried." }),
|
|
543
596
|
/* @__PURE__ */ require_jsx_runtime.jsx("span", { children: "Endpoint counts can include separate address families." }),
|
|
544
597
|
/* @__PURE__ */ require_jsx_runtime.jsx("span", { children: "No Secret or ConfigMap data is read." })
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resource-relationships.js","names":[],"sources":["../../src/renderer/resource-relationships.tsx"],"sourcesContent":["import { Renderer } from \"@freelensapp/extensions\";\nimport { observer } from \"mobx-react\";\nimport { useEffect, useLayoutEffect, useRef, useState } from \"react\";\nimport {\n buildResourceRelationships,\n type RelationshipInventory,\n type RelationshipNode,\n type RelationshipObject,\n} from \"../common/resource-relationships\";\nimport { resourceRelationshipsStyles } from \"./resource-relationships.css\";\n\nconst { Icon, Select } = Renderer.Component;\nconst LIMIT = 100;\ntype Service = Renderer.K8sApi.Service;\ninterface InventoryState {\n namespace: string;\n service: string;\n data: RelationshipInventory;\n}\nconst roles = [\n { id: \"upstream\", name: \"Upstream references\", relation: \"references backend\" },\n { id: \"service\", name: \"Focused Service\", relation: \"API configuration\" },\n { id: \"backend\", name: \"Selected & published backends\", relation: \"selector matches / published in\" },\n { id: \"placement\", name: \"Ownership & placement\", relation: \"owned by / assigned to\" },\n] as const;\nconst icons: Record<string, string> = {\n Ingress: \"login\",\n Service: \"share\",\n Pod: \"view_in_ar\",\n EndpointSlice: \"hub\",\n Node: \"dns\",\n ReplicaSet: \"layers\",\n Deployment: \"layers\",\n StatefulSet: \"layers\",\n DaemonSet: \"layers\",\n Job: \"work\",\n CronJob: \"schedule\",\n};\nexport async function loadRelationshipInventory(\n namespace: string,\n service: Service,\n signal: AbortSignal,\n): Promise<RelationshipInventory> {\n const gaps: string[] = [];\n const list = async <T,>(name: string, request: () => Promise<T[] | null>) => {\n try {\n const items = await request();\n if (!items) {\n gaps.push(`${name} inventory unavailable`);\n return undefined;\n }\n if (items.length > LIMIT)\n gaps.push(`${name} inventory capped at ${LIMIT} objects; additional relationships may be omitted`);\n return items.slice(0, LIMIT);\n } catch {\n if (!signal.aborted) gaps.push(`${name} inventory unavailable; access or API availability may be restricted`);\n return undefined;\n }\n };\n const options = { namespace, reqInit: { signal } };\n const query = { limit: LIMIT + 1 };\n const selector = Object.entries(service.spec.selector ?? {})\n .map(([key, value]) => `${key}=${value}`)\n .join(\",\");\n const external = service.spec.type === \"ExternalName\";\n const ownerApis = external\n ? []\n : [\n Renderer.K8sApi.replicaSetApi,\n Renderer.K8sApi.deploymentApi,\n Renderer.K8sApi.statefulSetApi,\n Renderer.K8sApi.daemonSetApi,\n Renderer.K8sApi.jobApi,\n Renderer.K8sApi.cronJobApi,\n ];\n const [pods, slices, ingresses, ...owners] = await Promise.all([\n selector && !external\n ? list(\"Pod\", () => Renderer.K8sApi.podsApi.list(options, { ...query, labelSelector: selector }))\n : Promise.resolve([]),\n service.spec.type === \"ExternalName\"\n ? Promise.resolve([])\n : list(\"EndpointSlice\", () =>\n Renderer.K8sApi.endpointSliceApi.list(options, {\n ...query,\n labelSelector: `kubernetes.io/service-name=${service.getName()}`,\n }),\n ),\n list(\"Ingress\", () => Renderer.K8sApi.ingressApi.list(options, query)),\n ...ownerApis.map((api) => list<RelationshipObject>(\"Controller\", () => api.list(options, query))),\n ]);\n return { pods, slices, ingresses, owners: owners.flatMap((items) => items ?? []), gaps };\n}\nfunction ResourceCard({\n node,\n incoming,\n onOpen,\n onHighlight,\n}: {\n onHighlight: (id?: string) => void;\n node: RelationshipNode;\n incoming: string[];\n onOpen: (path: string) => void;\n}) {\n return (\n <article\n className=\"card\"\n data-node-id={node.id}\n onMouseEnter={() => onHighlight(node.id)}\n onMouseLeave={() => onHighlight()}\n onFocus={() => onHighlight(node.id)}\n onBlur={() => onHighlight()}\n >\n <div className=\"relation-label\">{incoming.join(\" · \") || \"Focus\"}</div>\n <div className=\"card-kind\">\n <Icon material={icons[node.kind] ?? \"account_tree\"} size={16} />\n {node.kind}\n {node.inferred && \" · reference\"}\n </div>\n {node.selfLink ? (\n <button\n type=\"button\"\n className=\"resource-name\"\n onClick={(event) => {\n event.preventDefault();\n event.stopPropagation();\n onOpen(node.selfLink as string);\n }}\n title={`Open ${node.kind} ${node.name}`}\n >\n {node.name}\n </button>\n ) : (\n <strong>{node.name}</strong>\n )}\n <p className={node.tone}>\n <Icon\n material={node.tone === \"warning\" ? \"warning\" : node.tone === \"healthy\" ? \"check_circle\" : \"info\"}\n size={14}\n />{\" \"}\n {node.detail}\n </p>\n </article>\n );\n}\nfunction roundedConnector(points: [number, number][]) {\n let path = `M ${points[0][0]} ${points[0][1]}`;\n for (let index = 1; index < points.length - 1; index++) {\n const [x, y] = points[index];\n const [px, py] = points[index - 1];\n const [nx, ny] = points[index + 1];\n const before = Math.hypot(x - px, y - py);\n const after = Math.hypot(nx - x, ny - y);\n if (!before || !after) continue;\n const radius = Math.min(6, before / 2, after / 2);\n path += ` L ${x + ((px - x) * radius) / before} ${y + ((py - y) * radius) / before}`;\n path += ` Q ${x} ${y} ${x + ((nx - x) * radius) / after} ${y + ((ny - y) * radius) / after}`;\n }\n const last = points[points.length - 1];\n return `${path} L ${last[0]} ${last[1]}`;\n}\nexport function RelationshipGraph({\n graph,\n onOpen,\n ingressAvailable,\n hideUpstreams = false,\n}: {\n graph: ReturnType<typeof buildResourceRelationships>;\n onOpen: (path: string) => void;\n ingressAvailable: boolean;\n hideUpstreams?: boolean;\n}) {\n const visibleRoles = roles.filter((role) => !hideUpstreams || role.id !== \"upstream\");\n const element = useRef<HTMLDivElement>(null);\n const [paths, setPaths] = useState<{ from: string; to: string; label: string; path: string }[]>([]);\n const [highlight, setHighlight] = useState<string>();\n useLayoutEffect(() => {\n const container = element.current;\n if (!container) return;\n const measure = () => {\n const origin = container.getBoundingClientRect();\n const cards = new Map(\n Array.from(container.querySelectorAll<HTMLElement>(\"[data-node-id]\")).map((card) => [\n card.dataset.nodeId,\n card.getBoundingClientRect(),\n ]),\n );\n setPaths(\n graph.edges.flatMap((edge, index) => {\n const from = cards.get(edge.from);\n const to = cards.get(edge.to);\n if (!from || !to) return [];\n const sy = from.top + from.height / 2 - origin.top;\n const ty = to.top + to.height / 2 - origin.top;\n const sameColumn = Math.abs(from.left - to.left) < 2;\n const sx = (sameColumn ? from.left : from.right) - origin.left;\n const tx = to.left - origin.left;\n const laneOffset = ((index % 3) - 1) * 8;\n const gutter = sameColumn ? sx - 28 + laneOffset : (sx + tx) / 2 + laneOffset;\n const crossesColumn = Array.from(cards.values()).some(\n (card) => card.left > from.left + 2 && card.right < to.left - 2,\n );\n let path =\n !sameColumn && sy === ty\n ? `M ${sx} ${sy} H ${tx}`\n : roundedConnector([\n [sx, sy],\n [gutter, sy],\n [gutter, ty],\n [tx, ty],\n ]);\n if (crossesColumn) {\n const bottom =\n Math.max(...Array.from(cards.values(), (card) => card.bottom)) - origin.top + 24 + (index % 3) * 8;\n const sourceGutter = sx + 32 + laneOffset;\n const targetGutter = tx - 32 + laneOffset;\n path = roundedConnector([\n [sx, sy],\n [sourceGutter, sy],\n [sourceGutter, bottom],\n [targetGutter, bottom],\n [targetGutter, ty],\n [tx, ty],\n ]);\n }\n return [{ ...edge, path }];\n }),\n );\n };\n measure();\n const observer = typeof ResizeObserver === \"undefined\" ? undefined : new ResizeObserver(measure);\n observer?.observe(container);\n for (const card of container.querySelectorAll(\"[data-node-id]\")) observer?.observe(card);\n window.addEventListener(\"resize\", measure);\n return () => {\n observer?.disconnect();\n window.removeEventListener(\"resize\", measure);\n };\n }, [graph, hideUpstreams]);\n return (\n <div className=\"graph-scroll\">\n <div\n ref={element}\n className={`graph${hideUpstreams ? \" hide-upstreams\" : \"\"}`}\n style={{\n gridTemplateRows: `auto repeat(${Math.max(1, ...visibleRoles.map((role) => graph.nodes.filter((node) => node.role === role.id).length))}, auto)`,\n }}\n aria-label=\"Service resource relationship graph\"\n >\n <svg className=\"resource-connections\" width=\"100%\" height=\"100%\" aria-hidden=\"true\">\n <defs>\n <marker id=\"relationship-arrow\" markerWidth=\"5\" markerHeight=\"5\" refX=\"4\" refY=\"2.5\" orient=\"auto\">\n <path d=\"M0 0L5 2.5L0 5\" fill=\"currentColor\" />\n </marker>\n </defs>\n {paths.map((edge) => (\n <path\n key={`${edge.from}/${edge.to}/${edge.label}`}\n data-edge-from={edge.from}\n data-edge-to={edge.to}\n className={\n highlight\n ? edge.from === highlight || edge.to === highlight\n ? \"connection highlighted\"\n : \"connection dimmed\"\n : \"connection\"\n }\n d={edge.path}\n markerEnd=\"url(#relationship-arrow)\"\n >\n <title>\n {graph.nodes.find((node) => node.id === edge.from)?.name} → {edge.label} →{\" \"}\n {graph.nodes.find((node) => node.id === edge.to)?.name}\n </title>\n </path>\n ))}\n </svg>\n {visibleRoles.map((role) => (\n <section className=\"column\" key={role.id} aria-label={role.name}>\n <h3>{role.name}</h3>\n {graph.nodes\n .filter((node) => node.role === role.id)\n .map((node) => (\n <ResourceCard\n key={node.id}\n node={node}\n incoming={[...new Set(graph.edges.filter((edge) => edge.to === node.id).map((edge) => edge.label))]}\n onOpen={onOpen}\n onHighlight={setHighlight}\n />\n ))}\n {!graph.nodes.some((node) => node.role === role.id) && (\n <div className=\"card neutral\">\n {role.id === \"upstream\"\n ? ingressAvailable\n ? \"No matching Ingress references observed\"\n : \"Ingress evidence unavailable\"\n : \"No relationships observed in available evidence\"}\n </div>\n )}\n </section>\n ))}\n </div>\n </div>\n );\n}\nexport const ResourceRelationshipsPage = observer(({ enabled = true }: { enabled?: boolean }) => {\n if (!enabled)\n return (\n <div className=\"power-relationships\">\n <p>Resource relationships are disabled in Power settings</p>\n </div>\n );\n return <EnabledResourceRelationshipsPage key={Renderer.Catalog.activeCluster.get()?.metadata.uid ?? \"cluster\"} />;\n});\nfunction EnabledResourceRelationshipsPage() {\n const mounted = useRef(true);\n const clusterId = useRef(Renderer.Catalog.activeCluster.get()?.metadata.uid);\n useEffect(() => {\n mounted.current = true;\n return () => {\n mounted.current = false;\n };\n }, []);\n const [namespaces, setNamespaces] = useState<string[]>([]);\n const [namespace, setNamespace] = useState(\"\");\n const [services, setServices] = useState<Service[]>([]);\n const [serviceName, setServiceName] = useState(\"\");\n const [focusedPod, setFocusedPod] = useState(\"\");\n const [hideUpstreams, setHideUpstreams] = useState(false);\n const [inventory, setInventory] = useState<InventoryState>();\n const [refresh, setRefresh] = useState(0);\n const [scopeRefresh, setScopeRefresh] = useState(0);\n const [namespaceMessage, setNamespaceMessage] = useState(\"\");\n const [scopeLoading, setScopeLoading] = useState(true);\n const [loading, setLoading] = useState(false);\n const [scopeMessage, setScopeMessage] = useState(\"\");\n const [openError, setOpenError] = useState(\"\");\n useEffect(() => {\n const controller = new AbortController();\n setScopeLoading(true);\n setNamespaceMessage(\"\");\n void Renderer.K8sApi.namespacesApi\n .list({ reqInit: { signal: controller.signal } }, { limit: LIMIT + 1 })\n .then((items) => {\n if (controller.signal.aborted) return;\n const names = (items ?? [])\n .slice(0, LIMIT)\n .map((item) => item.getName())\n .sort();\n setNamespaces(names);\n setNamespace((current) => (names.includes(current) ? current : (names[0] ?? \"\")));\n if ((items?.length ?? 0) > LIMIT) setNamespaceMessage(`Namespace selector is capped at ${LIMIT} entries`);\n else if (!names.length) setScopeMessage(\"No visible namespaces returned by the API\");\n })\n .catch(() => {\n if (!controller.signal.aborted)\n setScopeMessage(\"Namespace inventory unavailable; check access to namespace listing\");\n })\n .finally(() => {\n if (!controller.signal.aborted) setScopeLoading(false);\n });\n return () => controller.abort();\n }, [scopeRefresh]);\n useEffect(() => {\n if (!namespace) return;\n const controller = new AbortController();\n setLoading(false);\n setServices([]);\n setServiceName(\"\");\n setInventory(undefined);\n setScopeLoading(true);\n setScopeMessage(\"\");\n void Renderer.K8sApi.serviceApi\n .list({ namespace, reqInit: { signal: controller.signal } }, { limit: LIMIT + 1 })\n .then((items) => {\n if (controller.signal.aborted) return;\n const visible = (items ?? []).slice(0, LIMIT).sort((a, b) => a.getName().localeCompare(b.getName()));\n setServices(visible);\n setServiceName(visible[0]?.getName() ?? \"\");\n if ((items?.length ?? 0) > LIMIT)\n setScopeMessage(`Service selector is capped at ${LIMIT} entries; additional Services are not shown`);\n else if (!visible.length) setScopeMessage(\"No visible Services in this namespace\");\n })\n .catch(() => {\n if (!controller.signal.aborted) setScopeMessage(\"Service inventory unavailable; check namespace access\");\n })\n .finally(() => {\n if (!controller.signal.aborted) setScopeLoading(false);\n });\n return () => controller.abort();\n }, [namespace, scopeRefresh]);\n const service = services.find((item) => item.getName() === serviceName);\n useEffect(() => {\n if (!service || !namespace || service.metadata.namespace !== namespace) return;\n const controller = new AbortController();\n setLoading(true);\n setInventory(undefined);\n setFocusedPod(\"\");\n setOpenError(\"\");\n void loadRelationshipInventory(namespace, service, controller.signal)\n .then((data) => {\n if (!controller.signal.aborted) setInventory({ namespace, service: service.getName(), data });\n })\n .finally(() => {\n if (!controller.signal.aborted) setLoading(false);\n });\n return () => controller.abort();\n }, [namespace, service, refresh]);\n const current = inventory?.namespace === namespace && inventory.service === serviceName ? inventory : undefined;\n const graph =\n current && service ? buildResourceRelationships(service, current.data, focusedPod || undefined) : undefined;\n const openResource = (path: string) => {\n const currentCluster = () =>\n mounted.current && Renderer.Catalog.activeCluster.get()?.metadata.uid === clusterId.current;\n setOpenError(\"\");\n void Promise.resolve()\n .then(() => {\n if (currentCluster()) return Renderer.Navigation.showDetails(path);\n })\n .catch(() => {\n if (currentCluster()) setOpenError(\"Resource details could not be opened; the object may be unavailable\");\n });\n };\n return (\n <div className=\"power-relationships\">\n <style>{resourceRelationshipsStyles}</style>\n <div className=\"page-heading\">\n <h2>Resource relationships</h2>\n <label className=\"graph-option\">\n <input type=\"checkbox\" checked={hideUpstreams} onChange={(event) => setHideUpstreams(event.target.checked)} />\n Hide Upstream\n </label>\n </div>\n <p className=\"intro\">\n Follow one Service from upstream Ingress references to selected pods, published EndpointSlices and controller\n ownership. Connections show Kubernetes API evidence; they do not prove network reachability.\n </p>\n <div className=\"controls\">\n <label className=\"control\">\n <span>Namespace</span>\n <Select\n aria-label=\"Relationship namespace\"\n value={namespace}\n options={namespaces.map((name) => ({ value: name, label: name }))}\n onChange={(option) => setNamespace(option?.value ?? \"\")}\n isDisabled={!namespaces.length}\n />\n </label>\n <label className=\"control\">\n <span>Service</span>\n <Select\n aria-label=\"Relationship Service\"\n value={serviceName}\n options={services.map((item) => ({ value: item.getName(), label: item.getName() }))}\n onChange={(option) => setServiceName(option?.value ?? \"\")}\n isDisabled={!services.length || scopeLoading}\n />\n </label>\n <label className=\"control\">\n <span>Pod focus</span>\n <Select\n aria-label=\"Relationship pod focus\"\n value={focusedPod}\n options={[\n { value: \"\", label: \"All selected pods (up to 8)\" },\n ...(graph?.podOptions ?? []).map((name) => ({ value: name, label: name })),\n ]}\n onChange={(option) => setFocusedPod(option?.value ?? \"\")}\n isDisabled={!graph?.podOptions.length}\n />\n </label>\n <button\n type=\"button\"\n className=\"refresh\"\n onClick={() => (service ? setRefresh((value) => value + 1) : setScopeRefresh((value) => value + 1))}\n disabled={loading || scopeLoading}\n title=\"Refresh scoped API evidence\"\n >\n <Icon material=\"refresh\" size={18} />\n Refresh\n </button>\n </div>\n {namespaceMessage && (\n <div className=\"notice\" role=\"status\">\n {namespaceMessage}\n </div>\n )}\n {scopeMessage && (\n <div className=\"notice\" role=\"status\">\n {scopeMessage}\n </div>\n )}\n {openError && (\n <div className=\"notice warning\" role=\"alert\">\n {openError}\n </div>\n )}\n {(scopeLoading || loading) && (\n <div className=\"empty\" role=\"status\">\n Loading scoped relationship evidence…\n </div>\n )}\n {!scopeLoading && !loading && !service && (\n <div className=\"empty\">Select a namespace with a visible Service to inspect relationships</div>\n )}\n {graph && !loading && (\n <>\n <div className=\"notice relationship-summary\">\n <strong>{graph.diagnostics.summary}</strong>\n <div className=\"ports\">\n {graph.diagnostics.ports.map((port) => (\n <span key={port.name}>\n {port.name} · {port.protocol} → {port.target} · published:{\" \"}\n {port.endpointPorts.join(\", \") || \"unknown\"}\n {port.unresolved ? ` · ${port.unresolved} unresolved named targets` : \"\"}\n </span>\n ))}\n </div>\n </div>\n {graph.gaps.length > 0 && (\n <details open className=\"notice\">\n <summary>Partial coverage ({graph.gaps.length})</summary>\n <ul>\n {graph.gaps.map((gap) => (\n <li key={gap}>{gap}</li>\n ))}\n </ul>\n </details>\n )}\n <RelationshipGraph\n graph={graph}\n onOpen={openResource}\n ingressAvailable={current?.data.ingresses !== undefined}\n hideUpstreams={hideUpstreams}\n />\n {graph.omitted > 0 && (\n <div className=\"notice\">\n {graph.omitted} additional visible resources omitted to keep the graph readable. Focus a pod to inspect\n its ownership and placement.\n </div>\n )}\n <details>\n <summary>Accessible connection list ({graph.edges.length})</summary>\n <ul className=\"edge-list\">\n {graph.edges.map((edge) => (\n <li key={`${edge.from}/${edge.to}/${edge.label}`}>\n {graph.nodes.find((node) => node.id === edge.from)?.name} → {edge.label} →{\" \"}\n {graph.nodes.find((node) => node.id === edge.to)?.name}\n </li>\n ))}\n </ul>\n </details>\n <p className=\"scope\">\n <span>Snapshot from namespace-scoped read-only API requests.</span>\n <span>Owner and node references can point to objects that were not queried.</span>\n <span>Endpoint counts can include separate address families.</span>\n <span>No Secret or ConfigMap data is read.</span>\n </p>\n </>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"resource-relationships.js","names":[],"sources":["../../src/renderer/resource-relationships.tsx"],"sourcesContent":["import { Renderer } from \"@freelensapp/extensions\";\nimport { observer } from \"mobx-react\";\nimport { useEffect, useLayoutEffect, useRef, useState } from \"react\";\nimport {\n buildResourceRelationships,\n type RelationshipInventory,\n type RelationshipNode,\n type RelationshipObject,\n} from \"../common/resource-relationships\";\nimport { MonitoringPreferencesStore } from \"../common/store/monitoring-preferences-store\";\nimport { loadGatewayInventory } from \"./gateway-relationships-client\";\nimport { resourceRelationshipsStyles } from \"./resource-relationships.css\";\nimport { createResourceSearchTransport } from \"./resource-search-client\";\nimport { openSearchResource } from \"./resource-search-routing\";\n\nconst { Icon, Select } = Renderer.Component;\nconst LIMIT = 100;\ntype Service = Renderer.K8sApi.Service;\ninterface InventoryState {\n namespace: string;\n service: string;\n data: RelationshipInventory;\n}\nconst roles = [\n { id: \"upstream\", name: \"Upstream references\", relation: \"references backend\" },\n { id: \"service\", name: \"Focused Service\", relation: \"API configuration\" },\n { id: \"backend\", name: \"Selected & published backends\", relation: \"selector matches / published in\" },\n { id: \"placement\", name: \"Ownership & placement\", relation: \"owned by / assigned to\" },\n] as const;\nconst icons: Record<string, string> = {\n Ingress: \"login\",\n Service: \"share\",\n Pod: \"view_in_ar\",\n EndpointSlice: \"hub\",\n Node: \"dns\",\n ReplicaSet: \"layers\",\n Deployment: \"layers\",\n StatefulSet: \"layers\",\n DaemonSet: \"layers\",\n Job: \"work\",\n CronJob: \"schedule\",\n};\nexport async function loadRelationshipInventory(\n namespace: string,\n service: Service,\n signal: AbortSignal,\n): Promise<RelationshipInventory> {\n const gaps: string[] = [];\n const list = async <T,>(name: string, request: () => Promise<T[] | null>) => {\n try {\n const items = await request();\n if (!items) {\n gaps.push(`${name} inventory unavailable`);\n return undefined;\n }\n if (items.length > LIMIT)\n gaps.push(`${name} inventory capped at ${LIMIT} objects; additional relationships may be omitted`);\n return items.slice(0, LIMIT);\n } catch {\n if (!signal.aborted) gaps.push(`${name} inventory unavailable; access or API availability may be restricted`);\n return undefined;\n }\n };\n const options = { namespace, reqInit: { signal } };\n const query = { limit: LIMIT + 1 };\n const selector = Object.entries(service.spec.selector ?? {})\n .map(([key, value]) => `${key}=${value}`)\n .join(\",\");\n const external = service.spec.type === \"ExternalName\";\n const ownerApis = external\n ? []\n : [\n Renderer.K8sApi.replicaSetApi,\n Renderer.K8sApi.deploymentApi,\n Renderer.K8sApi.statefulSetApi,\n Renderer.K8sApi.daemonSetApi,\n Renderer.K8sApi.jobApi,\n Renderer.K8sApi.cronJobApi,\n ];\n const [pods, slices, ingresses, ...owners] = await Promise.all([\n selector && !external\n ? list(\"Pod\", () => Renderer.K8sApi.podsApi.list(options, { ...query, labelSelector: selector }))\n : Promise.resolve([]),\n service.spec.type === \"ExternalName\"\n ? Promise.resolve([])\n : list(\"EndpointSlice\", () =>\n Renderer.K8sApi.endpointSliceApi.list(options, {\n ...query,\n labelSelector: `kubernetes.io/service-name=${service.getName()}`,\n }),\n ),\n list(\"Ingress\", () => Renderer.K8sApi.ingressApi.list(options, query)),\n ...ownerApis.map((api) => list<RelationshipObject>(\"Controller\", () => api.list(options, query))),\n ]);\n const clusterId = Renderer.Catalog.activeCluster.get()?.metadata.uid;\n const gateway = clusterId\n ? await loadGatewayInventory(createResourceSearchTransport(clusterId, signal), signal, {\n focusedNamespace: namespace,\n })\n : undefined;\n return { pods, slices, ingresses, owners: owners.flatMap((items) => items ?? []), gaps, gateway };\n}\nfunction ResourceCard({\n node,\n incoming,\n incomingEvidence,\n onOpen,\n onHighlight,\n}: {\n onHighlight: (id?: string) => void;\n node: RelationshipNode;\n incoming: string[];\n incomingEvidence?: string[];\n onOpen: (path: string) => void;\n}) {\n return (\n <article\n className=\"card\"\n data-node-id={node.id}\n onMouseEnter={() => onHighlight(node.id)}\n onMouseLeave={() => onHighlight()}\n onFocus={() => onHighlight(node.id)}\n onBlur={() => onHighlight()}\n >\n <div className=\"relation-label\">{incoming.join(\" · \") || \"Focus\"}</div>\n <div className=\"card-kind\">\n <Icon material={icons[node.kind] ?? \"account_tree\"} size={16} />\n {node.kind}\n {node.inferred && \" · reference\"}\n </div>\n {node.selfLink ? (\n <button\n type=\"button\"\n className=\"resource-name\"\n onClick={(event) => {\n event.preventDefault();\n event.stopPropagation();\n onOpen(node.selfLink as string);\n }}\n title={`Open ${node.kind} ${node.name}`}\n >\n {node.name}\n </button>\n ) : (\n <strong>{node.name}</strong>\n )}\n <p className={node.tone}>\n <Icon\n material={node.tone === \"warning\" ? \"warning\" : node.tone === \"healthy\" ? \"check_circle\" : \"info\"}\n size={14}\n />{\" \"}\n {node.detail}\n </p>\n {!!(node.evidence?.length || incomingEvidence?.length) && (\n <details className=\"gateway-evidence\">\n <summary>API evidence</summary>\n {[...(node.evidence ?? []), ...(incomingEvidence ?? [])].map((evidence) => (\n <p key={evidence}>{evidence}</p>\n ))}\n </details>\n )}\n </article>\n );\n}\nfunction roundedConnector(points: [number, number][]) {\n let path = `M ${points[0][0]} ${points[0][1]}`;\n for (let index = 1; index < points.length - 1; index++) {\n const [x, y] = points[index];\n const [px, py] = points[index - 1];\n const [nx, ny] = points[index + 1];\n const before = Math.hypot(x - px, y - py);\n const after = Math.hypot(nx - x, ny - y);\n if (!before || !after) continue;\n const radius = Math.min(6, before / 2, after / 2);\n path += ` L ${x + ((px - x) * radius) / before} ${y + ((py - y) * radius) / before}`;\n path += ` Q ${x} ${y} ${x + ((nx - x) * radius) / after} ${y + ((ny - y) * radius) / after}`;\n }\n const last = points[points.length - 1];\n return `${path} L ${last[0]} ${last[1]}`;\n}\nexport function RelationshipGraph({\n graph,\n onOpen,\n ingressAvailable,\n hideUpstreams = false,\n}: {\n graph: ReturnType<typeof buildResourceRelationships>;\n onOpen: (path: string) => void;\n ingressAvailable: boolean;\n hideUpstreams?: boolean;\n}) {\n const upstreamIds = new Set(graph.nodes.filter((node) => node.role === \"upstream\").map((node) => node.id));\n const upstreamGutter =\n !hideUpstreams && graph.edges.some((edge) => upstreamIds.has(edge.from) && upstreamIds.has(edge.to));\n const visibleRoles = roles.filter((role) => !hideUpstreams || role.id !== \"upstream\");\n const element = useRef<HTMLDivElement>(null);\n const [paths, setPaths] = useState<{ from: string; to: string; label: string; path: string }[]>([]);\n const [highlight, setHighlight] = useState<string>();\n useLayoutEffect(() => {\n const container = element.current;\n if (!container) return;\n const measure = () => {\n const origin = container.getBoundingClientRect();\n const cards = new Map(\n Array.from(container.querySelectorAll<HTMLElement>(\"[data-node-id]\")).map((card) => [\n card.dataset.nodeId,\n card.getBoundingClientRect(),\n ]),\n );\n setPaths(\n graph.edges.flatMap((edge, index) => {\n const from = cards.get(edge.from);\n const to = cards.get(edge.to);\n if (!from || !to) return [];\n const sy = from.top + from.height / 2 - origin.top;\n const ty = to.top + to.height / 2 - origin.top;\n const sameColumn = Math.abs(from.left - to.left) < 2;\n const sx = (sameColumn ? from.left : from.right) - origin.left;\n const tx = to.left - origin.left;\n const laneOffset = ((index % 3) - 1) * 8;\n const gutter = sameColumn ? sx - 28 + laneOffset : (sx + tx) / 2 + laneOffset;\n const crossesColumn = Array.from(cards.values()).some(\n (card) => card.left > from.left + 2 && card.right < to.left - 2,\n );\n let path =\n !sameColumn && sy === ty\n ? `M ${sx} ${sy} H ${tx}`\n : roundedConnector([\n [sx, sy],\n [gutter, sy],\n [gutter, ty],\n [tx, ty],\n ]);\n if (crossesColumn) {\n const bottom =\n Math.max(...Array.from(cards.values(), (card) => card.bottom)) - origin.top + 24 + (index % 3) * 8;\n const sourceGutter = sx + 32 + laneOffset;\n const targetGutter = tx - 32 + laneOffset;\n path = roundedConnector([\n [sx, sy],\n [sourceGutter, sy],\n [sourceGutter, bottom],\n [targetGutter, bottom],\n [targetGutter, ty],\n [tx, ty],\n ]);\n }\n return [{ ...edge, path }];\n }),\n );\n };\n measure();\n const observer = typeof ResizeObserver === \"undefined\" ? undefined : new ResizeObserver(measure);\n observer?.observe(container);\n for (const card of container.querySelectorAll(\"[data-node-id]\")) observer?.observe(card);\n window.addEventListener(\"resize\", measure);\n return () => {\n observer?.disconnect();\n window.removeEventListener(\"resize\", measure);\n };\n }, [graph, hideUpstreams]);\n return (\n <div className=\"graph-scroll\">\n <div\n ref={element}\n className={`graph${hideUpstreams ? \" hide-upstreams\" : \"\"}${upstreamGutter ? \" upstream-gutter\" : \"\"}`}\n style={{\n gridTemplateRows: `auto repeat(${Math.max(1, ...visibleRoles.map((role) => graph.nodes.filter((node) => node.role === role.id).length))}, auto)`,\n }}\n aria-label=\"Service resource relationship graph\"\n >\n <svg className=\"resource-connections\" width=\"100%\" height=\"100%\" aria-hidden=\"true\">\n <defs>\n <marker id=\"relationship-arrow\" markerWidth=\"5\" markerHeight=\"5\" refX=\"4\" refY=\"2.5\" orient=\"auto\">\n <path d=\"M0 0L5 2.5L0 5\" fill=\"currentColor\" />\n </marker>\n </defs>\n {paths.map((edge) => (\n <path\n key={`${edge.from}/${edge.to}/${edge.label}`}\n data-edge-from={edge.from}\n data-edge-to={edge.to}\n className={\n highlight\n ? edge.from === highlight || edge.to === highlight\n ? \"connection highlighted\"\n : \"connection dimmed\"\n : \"connection\"\n }\n d={edge.path}\n markerEnd=\"url(#relationship-arrow)\"\n >\n <title>\n {graph.nodes.find((node) => node.id === edge.from)?.name} → {edge.label} →{\" \"}\n {graph.nodes.find((node) => node.id === edge.to)?.name}\n </title>\n </path>\n ))}\n </svg>\n {visibleRoles.map((role) => (\n <section className=\"column\" key={role.id} aria-label={role.name}>\n <h3>{role.name}</h3>\n {graph.nodes\n .filter((node) => node.role === role.id)\n .map((node) => (\n <ResourceCard\n key={node.id}\n node={node}\n incoming={[...new Set(graph.edges.filter((edge) => edge.to === node.id).map((edge) => edge.label))]}\n incomingEvidence={graph.edges\n .filter((edge) => edge.to === node.id && edge.evidence)\n .map((edge) => edge.evidence as string)}\n onOpen={onOpen}\n onHighlight={setHighlight}\n />\n ))}\n {!graph.nodes.some((node) => node.role === role.id) && (\n <div className=\"card neutral\">\n {role.id === \"upstream\"\n ? ingressAvailable\n ? \"No matching upstream references observed\"\n : \"Ingress evidence unavailable\"\n : \"No relationships observed in available evidence\"}\n </div>\n )}\n </section>\n ))}\n </div>\n </div>\n );\n}\nexport const ResourceRelationshipsPage = observer(({ enabled = true }: { enabled?: boolean }) => {\n if (!enabled)\n return (\n <div className=\"power-relationships\">\n <p>Resource relationships are disabled in Power settings</p>\n </div>\n );\n return <EnabledResourceRelationshipsPage key={Renderer.Catalog.activeCluster.get()?.metadata.uid ?? \"cluster\"} />;\n});\nfunction EnabledResourceRelationshipsPage() {\n const mounted = useRef(true);\n const clusterId = useRef(Renderer.Catalog.activeCluster.get()?.metadata.uid);\n useEffect(() => {\n mounted.current = true;\n return () => {\n mounted.current = false;\n };\n }, []);\n const [namespaces, setNamespaces] = useState<string[]>([]);\n const [namespace, setNamespace] = useState(\"\");\n const [services, setServices] = useState<Service[]>([]);\n const [serviceName, setServiceName] = useState(\"\");\n const [focusedPod, setFocusedPod] = useState(\"\");\n const preferences = MonitoringPreferencesStore.getInstanceOrCreate<MonitoringPreferencesStore>();\n const [hideUpstreams, setHideUpstreams] = useState(() =>\n preferences.hiddenUpstreamClusters.includes(clusterId.current ?? \"\"),\n );\n const toggleUpstreams = () => {\n const id = clusterId.current;\n if (!id || Renderer.Catalog.activeCluster.get()?.metadata.uid !== id) return;\n const hidden = !hideUpstreams;\n const otherClusters = preferences.hiddenUpstreamClusters.filter((cluster) => cluster !== id);\n preferences.hiddenUpstreamClusters = hidden ? [...otherClusters, id].slice(-100) : otherClusters;\n setHideUpstreams(hidden);\n };\n const [inventory, setInventory] = useState<InventoryState>();\n const [refresh, setRefresh] = useState(0);\n const [scopeRefresh, setScopeRefresh] = useState(0);\n const [namespaceMessage, setNamespaceMessage] = useState(\"\");\n const [scopeLoading, setScopeLoading] = useState(true);\n const [loading, setLoading] = useState(false);\n const [scopeMessage, setScopeMessage] = useState(\"\");\n const [openError, setOpenError] = useState(\"\");\n useEffect(() => {\n const controller = new AbortController();\n setScopeLoading(true);\n setNamespaceMessage(\"\");\n void Renderer.K8sApi.namespacesApi\n .list({ reqInit: { signal: controller.signal } }, { limit: LIMIT + 1 })\n .then((items) => {\n if (controller.signal.aborted) return;\n const names = (items ?? [])\n .slice(0, LIMIT)\n .map((item) => item.getName())\n .sort();\n setNamespaces(names);\n setNamespace((current) => (names.includes(current) ? current : (names[0] ?? \"\")));\n if ((items?.length ?? 0) > LIMIT) setNamespaceMessage(`Namespace selector is capped at ${LIMIT} entries`);\n else if (!names.length) setScopeMessage(\"No visible namespaces returned by the API\");\n })\n .catch(() => {\n if (!controller.signal.aborted)\n setScopeMessage(\"Namespace inventory unavailable; check access to namespace listing\");\n })\n .finally(() => {\n if (!controller.signal.aborted) setScopeLoading(false);\n });\n return () => controller.abort();\n }, [scopeRefresh]);\n useEffect(() => {\n if (!namespace) return;\n const controller = new AbortController();\n setLoading(false);\n setServices([]);\n setServiceName(\"\");\n setInventory(undefined);\n setScopeLoading(true);\n setScopeMessage(\"\");\n void Renderer.K8sApi.serviceApi\n .list({ namespace, reqInit: { signal: controller.signal } }, { limit: LIMIT + 1 })\n .then((items) => {\n if (controller.signal.aborted) return;\n const visible = (items ?? []).slice(0, LIMIT).sort((a, b) => a.getName().localeCompare(b.getName()));\n setServices(visible);\n setServiceName(visible[0]?.getName() ?? \"\");\n if ((items?.length ?? 0) > LIMIT)\n setScopeMessage(`Service selector is capped at ${LIMIT} entries; additional Services are not shown`);\n else if (!visible.length) setScopeMessage(\"No visible Services in this namespace\");\n })\n .catch(() => {\n if (!controller.signal.aborted) setScopeMessage(\"Service inventory unavailable; check namespace access\");\n })\n .finally(() => {\n if (!controller.signal.aborted) setScopeLoading(false);\n });\n return () => controller.abort();\n }, [namespace, scopeRefresh]);\n const service = services.find((item) => item.getName() === serviceName);\n useEffect(() => {\n if (!service || !namespace || service.metadata.namespace !== namespace) return;\n const controller = new AbortController();\n setLoading(true);\n setInventory(undefined);\n setFocusedPod(\"\");\n setOpenError(\"\");\n void loadRelationshipInventory(namespace, service, controller.signal)\n .then((data) => {\n if (!controller.signal.aborted) setInventory({ namespace, service: service.getName(), data });\n })\n .finally(() => {\n if (!controller.signal.aborted) setLoading(false);\n });\n return () => controller.abort();\n }, [namespace, service, refresh]);\n const current = inventory?.namespace === namespace && inventory.service === serviceName ? inventory : undefined;\n const graph =\n current && service ? buildResourceRelationships(service, current.data, focusedPod || undefined) : undefined;\n const openResource = (path: string) => {\n const currentCluster = () =>\n mounted.current && Renderer.Catalog.activeCluster.get()?.metadata.uid === clusterId.current;\n setOpenError(\"\");\n void Promise.resolve()\n .then(() => {\n if (!currentCluster()) return;\n const gatewayPath = path.match(\n /^\\/apis\\/(gateway\\.networking\\.k8s\\.io)\\/([^/]+)\\/(?:namespaces\\/([^/]+)\\/)?([^/]+)\\/([^/]+)$/,\n );\n if (gatewayPath) {\n const [, group, version, namespace, resource, name] = gatewayPath;\n const kind = (\n {\n gateways: \"Gateway\",\n gatewayclasses: \"GatewayClass\",\n httproutes: \"HTTPRoute\",\n grpcroutes: \"GRPCRoute\",\n tcproutes: \"TCPRoute\",\n tlsroutes: \"TLSRoute\",\n udproutes: \"UDPRoute\",\n } as Record<string, string>\n )[resource];\n return openSearchResource({ path, group, version, namespace, resource, name, kind, labels: {} });\n }\n return Renderer.Navigation.showDetails(path);\n })\n .catch(() => {\n if (currentCluster()) setOpenError(\"Resource details could not be opened; the object may be unavailable\");\n });\n };\n return (\n <div className=\"power-relationships\">\n <style>{resourceRelationshipsStyles}</style>\n <div className=\"page-heading\">\n <h2>Resource relationships</h2>\n </div>\n <p className=\"intro\">\n Follow one Service from upstream Ingress and Gateway API references to selected pods, published EndpointSlices\n and controller ownership. Connections show Kubernetes API evidence; they do not prove network reachability.\n </p>\n <div className=\"controls\">\n <label className=\"control\">\n <span>Namespace</span>\n <Select\n aria-label=\"Relationship namespace\"\n value={namespace}\n options={namespaces.map((name) => ({ value: name, label: name }))}\n onChange={(option) => setNamespace(option?.value ?? \"\")}\n isDisabled={!namespaces.length}\n />\n </label>\n <label className=\"control\">\n <span>Service</span>\n <Select\n aria-label=\"Relationship Service\"\n value={serviceName}\n options={services.map((item) => ({ value: item.getName(), label: item.getName() }))}\n onChange={(option) => setServiceName(option?.value ?? \"\")}\n isDisabled={!services.length || scopeLoading}\n />\n </label>\n <label className=\"control\">\n <span>Pod focus</span>\n <Select\n aria-label=\"Relationship pod focus\"\n value={focusedPod}\n options={[\n { value: \"\", label: \"All selected pods (up to 8)\" },\n ...(graph?.podOptions ?? []).map((name) => ({ value: name, label: name })),\n ]}\n onChange={(option) => setFocusedPod(option?.value ?? \"\")}\n isDisabled={!graph?.podOptions.length}\n />\n </label>\n <button\n type=\"button\"\n className=\"graph-option\"\n aria-pressed={hideUpstreams}\n onClick={toggleUpstreams}\n title={hideUpstreams ? \"Show upstream references\" : \"Hide upstream references\"}\n disabled={!clusterId.current}\n >\n <Icon material={hideUpstreams ? \"visibility_off\" : \"visibility\"} size={16} />\n Hide Upstream\n </button>\n <button\n type=\"button\"\n className=\"refresh\"\n onClick={() => (service ? setRefresh((value) => value + 1) : setScopeRefresh((value) => value + 1))}\n disabled={loading || scopeLoading}\n title=\"Refresh scoped API evidence\"\n >\n <Icon material=\"refresh\" size={18} />\n Refresh\n </button>\n </div>\n {namespaceMessage && (\n <div className=\"notice\" role=\"status\">\n {namespaceMessage}\n </div>\n )}\n {scopeMessage && (\n <div className=\"notice\" role=\"status\">\n {scopeMessage}\n </div>\n )}\n {openError && (\n <div className=\"notice warning\" role=\"alert\">\n {openError}\n </div>\n )}\n {(scopeLoading || loading) && (\n <div className=\"empty\" role=\"status\">\n Loading scoped relationship evidence…\n </div>\n )}\n {!scopeLoading && !loading && !service && (\n <div className=\"empty\">Select a namespace with a visible Service to inspect relationships</div>\n )}\n {graph && !loading && (\n <>\n <div className=\"notice relationship-summary\">\n <strong>{graph.diagnostics.summary}</strong>\n <div className=\"ports\">\n {graph.diagnostics.ports.map((port) => (\n <span key={port.name}>\n {port.name} · {port.protocol} → {port.target} · published:{\" \"}\n {port.endpointPorts.join(\", \") || \"unknown\"}\n {port.unresolved ? ` · ${port.unresolved} unresolved named targets` : \"\"}\n </span>\n ))}\n </div>\n </div>\n {graph.gaps.length > 0 && (\n <details open className=\"notice\">\n <summary>Partial coverage ({graph.gaps.length})</summary>\n <ul>\n {graph.gaps.map((gap) => (\n <li key={gap}>{gap}</li>\n ))}\n </ul>\n </details>\n )}\n <RelationshipGraph\n graph={graph}\n onOpen={openResource}\n ingressAvailable={current?.data.ingresses !== undefined}\n hideUpstreams={hideUpstreams}\n />\n {graph.omitted > 0 && (\n <div className=\"notice\">\n {graph.omitted} additional visible resources omitted to keep the graph readable. Focus a pod to inspect\n its ownership and placement.\n </div>\n )}\n <details>\n <summary>Accessible connection list ({graph.edges.length})</summary>\n <ul className=\"edge-list\">\n {graph.edges.map((edge) => (\n <li key={`${edge.from}/${edge.to}/${edge.label}`}>\n {graph.nodes.find((node) => node.id === edge.from)?.name} → {edge.label} →{\" \"}\n {graph.nodes.find((node) => node.id === edge.to)?.name}\n {edge.evidence && <div>{edge.evidence}</div>}\n </li>\n ))}\n </ul>\n </details>\n <p className=\"scope\">\n <span>\n Snapshot from read-only API requests; Gateway discovery and references include other namespaces.\n </span>\n <span>Owner and node references can point to objects that were not queried.</span>\n <span>Endpoint counts can include separate address families.</span>\n <span>No Secret or ConfigMap data is read.</span>\n </p>\n </>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|