@64mb/freelens-power 1.4.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 +3 -3
- 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 +5 -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/gateway-relationships-client.js +107 -0
- package/out/renderer/gateway-relationships-client.js.map +1 -0
- package/out/renderer/preferences/monitoring-preferences.js +10 -0
- package/out/renderer/preferences/monitoring-preferences.js.map +1 -1
- package/out/renderer/preferences/preferences.js +3 -3
- 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 +46 -8
- 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 +5 -0
- package/out/renderer/src/common/store/monitoring-preferences-store.js.map +1 -1
- package/package.json +6 -2
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
const require_extensions = require("./_virtual/_global-external_@freelensapp/extensions.js");
|
|
2
2
|
const require__global_external_mobx = require("./_virtual/_global-external_mobx.js");
|
|
3
|
+
const require__global_external_mobx_react = require("./_virtual/_global-external_mobx-react.js");
|
|
4
|
+
const require_monitoring_preferences_store = require("./src/common/store/monitoring-preferences-store.js");
|
|
3
5
|
const require__global_external_react = require("./_virtual/_global-external_react.js");
|
|
4
6
|
const require__global_external_react_dom = require("./_virtual/_global-external_react-dom.js");
|
|
5
7
|
const require_jsx_runtime = require("./_virtual/_global-external_react/jsx-runtime.js");
|
|
6
8
|
const require_ai_icon = require("./ai-icon.js");
|
|
7
9
|
const require_ai_diagnostic_handoff = require("./ai-diagnostic-handoff.js");
|
|
8
10
|
const require_diagnostic_explain_button = require("./diagnostic-explain-button.js");
|
|
11
|
+
const require_resource_search_client = require("./resource-search-client.js");
|
|
12
|
+
const require_resource_search_routing = require("./resource-search-routing.js");
|
|
9
13
|
const require_resource_search_fields = require("./resource-search-fields.js");
|
|
10
14
|
const require_resource_search_model = require("./resource-search-model.js");
|
|
15
|
+
const require_resource_search_sync = require("./resource-search-sync.js");
|
|
11
16
|
//#region src/renderer/resource-search.tsx
|
|
12
17
|
var OPEN = "power-resource-search";
|
|
13
18
|
var activeId = () => require_extensions.Renderer.Catalog.activeCluster.get()?.metadata.uid;
|
|
@@ -74,16 +79,16 @@ var inventory = () => [
|
|
|
74
79
|
]
|
|
75
80
|
];
|
|
76
81
|
var icons = new Map(inventory().map(([kind, , icon]) => [kind, icon]));
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
}
|
|
86
|
-
}
|
|
82
|
+
require__global_external_mobx_react.observer(() => {
|
|
83
|
+
if (!require_monitoring_preferences_store.MonitoringPreferencesStore.getInstanceOrCreate().resourceSearchEnabled) return null;
|
|
84
|
+
return /* @__PURE__ */ require_jsx_runtime.jsx("button", {
|
|
85
|
+
type: "button",
|
|
86
|
+
title: "Search resources (double Shift)",
|
|
87
|
+
"aria-label": "Search resources",
|
|
88
|
+
onClick: () => window.dispatchEvent(new Event(OPEN)),
|
|
89
|
+
children: /* @__PURE__ */ require_jsx_runtime.jsx(require_ai_icon.AiIcon, { material: "search" })
|
|
90
|
+
});
|
|
91
|
+
});
|
|
87
92
|
function SearchSnippet({ field, query }) {
|
|
88
93
|
if (!field) return null;
|
|
89
94
|
const token = require_resource_search_model.queryTokens(query).find((token) => field.text.toLocaleLowerCase().includes(token));
|
|
@@ -104,9 +109,13 @@ function SearchSnippet({ field, query }) {
|
|
|
104
109
|
}
|
|
105
110
|
function SearchDialog({ close, clusterId }) {
|
|
106
111
|
const [query, setQuery] = require__global_external_react.useState("");
|
|
112
|
+
const [knownNamespace, setKnownNamespace] = require__global_external_react.useState("");
|
|
113
|
+
const [kindFilter, setKindFilter] = require__global_external_react.useState("");
|
|
114
|
+
const [namespaceFilter, setNamespaceFilter] = require__global_external_react.useState("");
|
|
107
115
|
const [resources, setResources] = require__global_external_react.useState([]);
|
|
108
116
|
const [loading, setLoading] = require__global_external_react.useState(true);
|
|
109
117
|
const [failed, setFailed] = require__global_external_react.useState(0);
|
|
118
|
+
const [cachedCount, setCachedCount] = require__global_external_react.useState();
|
|
110
119
|
const [selectedPath, setSelectedPath] = require__global_external_react.useState();
|
|
111
120
|
const [error, setError] = require__global_external_react.useState("");
|
|
112
121
|
const dialog = require__global_external_react.useRef(null);
|
|
@@ -114,55 +123,73 @@ function SearchDialog({ close, clusterId }) {
|
|
|
114
123
|
const searchIndex = require__global_external_react.useMemo(() => require_resource_search_model.createResourceSearchIndex(resources), [resources]);
|
|
115
124
|
const matches = searchIndex.search(query);
|
|
116
125
|
const selectedResource = matches.find((resource) => resource.path === selectedPath) ?? matches[0];
|
|
117
|
-
const results = matches
|
|
126
|
+
const results = matches;
|
|
118
127
|
if (selectedResource && !results.includes(selectedResource)) results[results.length - 1] = selectedResource;
|
|
119
128
|
const selected = results.findIndex((resource) => resource.path === selectedResource?.path);
|
|
120
129
|
require__global_external_react.useEffect(() => {
|
|
121
130
|
if (selectedPath !== void 0 && selectedPath !== selectedResource?.path) setSelectedPath(void 0);
|
|
122
131
|
}, [selectedPath, selectedResource?.path]);
|
|
132
|
+
const [coverage, setCoverage] = require__global_external_react.useState(currentCoverage);
|
|
133
|
+
const [limit, setLimit] = require__global_external_react.useState(100);
|
|
134
|
+
const [hasMore, setHasMore] = require__global_external_react.useState(false);
|
|
123
135
|
require__global_external_react.useEffect(() => {
|
|
124
136
|
const previous = document.activeElement;
|
|
125
137
|
input.current?.focus();
|
|
126
|
-
const
|
|
127
|
-
|
|
138
|
+
const update = () => setCoverage({ ...currentCoverage });
|
|
139
|
+
window.addEventListener("power-search-coverage", update);
|
|
140
|
+
return () => {
|
|
141
|
+
window.removeEventListener("power-search-coverage", update);
|
|
142
|
+
if (previous?.isConnected) previous.focus();
|
|
143
|
+
};
|
|
144
|
+
}, []);
|
|
145
|
+
require__global_external_react.useEffect(() => {
|
|
128
146
|
let live = true;
|
|
129
|
-
const
|
|
130
|
-
const
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
+
const client = require_resource_search_client.createResourceSearchClient(clusterId, require_resource_search_client.searchContextId());
|
|
148
|
+
const timer = window.setTimeout(() => {
|
|
149
|
+
client.query(query, limit, {
|
|
150
|
+
...kindFilter ? { kind: coverage.kinds?.find((kind) => kind.toLocaleLowerCase() === kindFilter.toLocaleLowerCase()) ?? kindFilter } : {},
|
|
151
|
+
...namespaceFilter ? { namespace: namespaceFilter === "(cluster)" ? "" : namespaceFilter } : {}
|
|
152
|
+
}).then((result) => {
|
|
153
|
+
if (!live || activeId() !== clusterId) return;
|
|
154
|
+
setResources(result.documents);
|
|
155
|
+
setHasMore(result.hasMore);
|
|
156
|
+
setLoading(false);
|
|
157
|
+
setFailed(0);
|
|
158
|
+
client.status?.().then((status) => {
|
|
159
|
+
if (live) setCachedCount(status.count);
|
|
160
|
+
}).catch(() => {});
|
|
161
|
+
}).catch(() => {
|
|
162
|
+
if (live) {
|
|
163
|
+
setFailed(1);
|
|
164
|
+
setLoading(false);
|
|
147
165
|
}
|
|
148
|
-
}
|
|
149
|
-
};
|
|
150
|
-
Promise.all([worker(), worker()]).then(() => {
|
|
151
|
-
if (live) setLoading(false);
|
|
152
|
-
});
|
|
166
|
+
});
|
|
167
|
+
}, 100);
|
|
153
168
|
return () => {
|
|
154
169
|
live = false;
|
|
155
|
-
window.clearTimeout(
|
|
156
|
-
controller.abort();
|
|
157
|
-
if (previous?.isConnected) previous.focus();
|
|
170
|
+
window.clearTimeout(timer);
|
|
158
171
|
};
|
|
159
|
-
}, [
|
|
172
|
+
}, [
|
|
173
|
+
clusterId,
|
|
174
|
+
query,
|
|
175
|
+
limit,
|
|
176
|
+
kindFilter,
|
|
177
|
+
namespaceFilter,
|
|
178
|
+
coverage.scanned,
|
|
179
|
+
coverage.indexing
|
|
180
|
+
]);
|
|
160
181
|
require__global_external_react.useEffect(() => {
|
|
161
182
|
document.getElementById(`power-resource-result-${selected}`)?.scrollIntoView?.({ block: "nearest" });
|
|
162
183
|
}, [selected, selectedResource?.path]);
|
|
184
|
+
const clearCache = () => {
|
|
185
|
+
require_resource_search_client.createResourceSearchClient(clusterId, require_resource_search_client.searchContextId()).clear().then(() => {
|
|
186
|
+
setResources([]);
|
|
187
|
+
restartSearchSync();
|
|
188
|
+
}).catch(() => setError("Could not clear the local search cache. Try again."));
|
|
189
|
+
};
|
|
163
190
|
const open = (resource) => {
|
|
164
191
|
if (activeId() !== clusterId) return;
|
|
165
|
-
Promise.resolve().then(() =>
|
|
192
|
+
Promise.resolve().then(() => require_resource_search_routing.openSearchResource(resource)).then(() => {
|
|
166
193
|
if (activeId() === clusterId) close();
|
|
167
194
|
}).catch(() => setError("Could not open this resource. Try again or refresh the inventory."));
|
|
168
195
|
};
|
|
@@ -186,7 +213,7 @@ function SearchDialog({ close, clusterId }) {
|
|
|
186
213
|
close();
|
|
187
214
|
}
|
|
188
215
|
if (event.key === "Tab") {
|
|
189
|
-
const controls = Array.from(dialog.current?.querySelectorAll("input, button:not(:disabled)") ?? []);
|
|
216
|
+
const controls = Array.from(dialog.current?.querySelectorAll("input, button:not(:disabled), select") ?? []);
|
|
190
217
|
const index = controls.indexOf(document.activeElement);
|
|
191
218
|
if (event.shiftKey && index <= 0) {
|
|
192
219
|
event.preventDefault();
|
|
@@ -211,11 +238,23 @@ function SearchDialog({ close, clusterId }) {
|
|
|
211
238
|
material: "search",
|
|
212
239
|
size: 18
|
|
213
240
|
}), "Search resources"]
|
|
214
|
-
}), /* @__PURE__ */ require_jsx_runtime.
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
241
|
+
}), /* @__PURE__ */ require_jsx_runtime.jsxs("div", {
|
|
242
|
+
style: {
|
|
243
|
+
display: "flex",
|
|
244
|
+
gap: 4
|
|
245
|
+
},
|
|
246
|
+
children: [/* @__PURE__ */ require_jsx_runtime.jsx("button", {
|
|
247
|
+
type: "button",
|
|
248
|
+
"aria-label": "Refresh resource inventory",
|
|
249
|
+
title: "Refresh resource inventory",
|
|
250
|
+
onClick: () => restartSearchSync(),
|
|
251
|
+
children: /* @__PURE__ */ require_jsx_runtime.jsx(require_ai_icon.AiIcon, { material: "refresh" })
|
|
252
|
+
}), /* @__PURE__ */ require_jsx_runtime.jsx("button", {
|
|
253
|
+
type: "button",
|
|
254
|
+
"aria-label": "Close resource search",
|
|
255
|
+
onClick: close,
|
|
256
|
+
children: /* @__PURE__ */ require_jsx_runtime.jsx(require_ai_icon.AiIcon, { material: "close" })
|
|
257
|
+
})]
|
|
219
258
|
})]
|
|
220
259
|
}),
|
|
221
260
|
/* @__PURE__ */ require_jsx_runtime.jsx("input", {
|
|
@@ -240,14 +279,68 @@ function SearchDialog({ close, clusterId }) {
|
|
|
240
279
|
}
|
|
241
280
|
}
|
|
242
281
|
}),
|
|
282
|
+
/* @__PURE__ */ require_jsx_runtime.jsxs("div", {
|
|
283
|
+
className: "power-resource-search-filters",
|
|
284
|
+
style: {
|
|
285
|
+
display: "flex",
|
|
286
|
+
gap: 8,
|
|
287
|
+
flexWrap: "wrap"
|
|
288
|
+
},
|
|
289
|
+
children: [/* @__PURE__ */ require_jsx_runtime.jsx("input", {
|
|
290
|
+
list: "power-search-kinds",
|
|
291
|
+
"aria-label": "Filter by exact resource kind",
|
|
292
|
+
placeholder: "Kind (all types)",
|
|
293
|
+
value: kindFilter,
|
|
294
|
+
maxLength: 253,
|
|
295
|
+
onChange: (event) => {
|
|
296
|
+
setKindFilter(event.target.value);
|
|
297
|
+
setSelectedPath(void 0);
|
|
298
|
+
}
|
|
299
|
+
}), /* @__PURE__ */ require_jsx_runtime.jsx("input", {
|
|
300
|
+
list: "power-search-namespaces",
|
|
301
|
+
"aria-label": "Filter by exact namespace",
|
|
302
|
+
placeholder: "Namespace (all)",
|
|
303
|
+
value: namespaceFilter,
|
|
304
|
+
maxLength: 253,
|
|
305
|
+
onChange: (event) => {
|
|
306
|
+
setNamespaceFilter(event.target.value);
|
|
307
|
+
setSelectedPath(void 0);
|
|
308
|
+
}
|
|
309
|
+
})]
|
|
310
|
+
}),
|
|
311
|
+
/* @__PURE__ */ require_jsx_runtime.jsx("datalist", {
|
|
312
|
+
id: "power-search-kinds",
|
|
313
|
+
children: (coverage.kinds ?? []).map((kind) => /* @__PURE__ */ require_jsx_runtime.jsx("option", { value: kind }, kind))
|
|
314
|
+
}),
|
|
315
|
+
/* @__PURE__ */ require_jsx_runtime.jsxs("datalist", {
|
|
316
|
+
id: "power-search-namespaces",
|
|
317
|
+
children: [/* @__PURE__ */ require_jsx_runtime.jsx("option", {
|
|
318
|
+
value: "(cluster)",
|
|
319
|
+
children: "Cluster scoped"
|
|
320
|
+
}), (coverage.namespaces ?? []).map((namespace) => /* @__PURE__ */ require_jsx_runtime.jsx("option", { value: namespace }, namespace))]
|
|
321
|
+
}),
|
|
243
322
|
/* @__PURE__ */ require_jsx_runtime.jsxs("p", {
|
|
244
323
|
role: "status",
|
|
245
324
|
children: [
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
325
|
+
coverage.indexing ? `Indexing ${coverage.scanned}/${coverage.discovered} types` : coverage.completedAt ? `Updated ${new Date(coverage.completedAt).toLocaleTimeString([], {
|
|
326
|
+
hour: "2-digit",
|
|
327
|
+
minute: "2-digit"
|
|
328
|
+
})}` : "Cached inventory",
|
|
329
|
+
cachedCount !== void 0 && ` · ${cachedCount.toLocaleString()} resources`,
|
|
330
|
+
coverage.denied > 0 && ` · ${coverage.denied} restricted scopes`,
|
|
331
|
+
coverage.unavailable + coverage.unsupported > 0 && ` · ${coverage.unavailable + coverage.unsupported} APIs unavailable`,
|
|
332
|
+
failed > 0 && " · Search cache unavailable"
|
|
249
333
|
]
|
|
250
334
|
}),
|
|
335
|
+
(coverage.message || coverage.denied > 0 || coverage.unavailable + coverage.unsupported > 0) && /* @__PURE__ */ require_jsx_runtime.jsxs("details", { children: [/* @__PURE__ */ require_jsx_runtime.jsx("summary", { children: "Inventory coverage" }), /* @__PURE__ */ require_jsx_runtime.jsx("p", { children: coverage.message ?? "Results include the resources your current permissions and available APIs allow." })] }),
|
|
336
|
+
coverage.storageFull && /* @__PURE__ */ require_jsx_runtime.jsxs("div", {
|
|
337
|
+
role: "alert",
|
|
338
|
+
children: [/* @__PURE__ */ require_jsx_runtime.jsx("p", { children: "Local search storage is full. Cached results are partial; indexing is paused." }), /* @__PURE__ */ require_jsx_runtime.jsx("button", {
|
|
339
|
+
type: "button",
|
|
340
|
+
onClick: clearCache,
|
|
341
|
+
children: "Clear local search cache"
|
|
342
|
+
})]
|
|
343
|
+
}),
|
|
251
344
|
error && /* @__PURE__ */ require_jsx_runtime.jsx("p", {
|
|
252
345
|
role: "alert",
|
|
253
346
|
children: error
|
|
@@ -289,7 +382,7 @@ function SearchDialog({ close, clusterId }) {
|
|
|
289
382
|
require_ai_diagnostic_handoff.explainDiagnosticFinding({
|
|
290
383
|
clusterId,
|
|
291
384
|
title: `${resource.kind}: ${resource.name}`,
|
|
292
|
-
summary: `Resource selected from search.
|
|
385
|
+
summary: `Resource selected from search. API group: ${resource.group || "core"}; version: ${resource.version}; resource: ${resource.resource}; kind: ${resource.kind}; namespace: ${resource.namespace ?? "cluster scoped"}; name: ${resource.name}; UID: ${resource.uid ?? "unknown"}; path: ${resource.path}. No live diagnostic data was collected.`,
|
|
293
386
|
resource: {
|
|
294
387
|
kind: resource.kind,
|
|
295
388
|
name: resource.name,
|
|
@@ -301,7 +394,43 @@ function SearchDialog({ close, clusterId }) {
|
|
|
301
394
|
})]
|
|
302
395
|
}, resource.path)), !results.length && /* @__PURE__ */ require_jsx_runtime.jsx("p", { children: loading ? "Searching…" : "No matching resources in the available inventory" })]
|
|
303
396
|
}),
|
|
304
|
-
|
|
397
|
+
hasMore && /* @__PURE__ */ require_jsx_runtime.jsx("button", {
|
|
398
|
+
type: "button",
|
|
399
|
+
disabled: limit >= 1e3,
|
|
400
|
+
onClick: () => setLimit((value) => Math.min(1e3, value + 100)),
|
|
401
|
+
children: "Show more matches"
|
|
402
|
+
}),
|
|
403
|
+
/* @__PURE__ */ require_jsx_runtime.jsxs("details", { children: [
|
|
404
|
+
/* @__PURE__ */ require_jsx_runtime.jsx("summary", { children: "Search options" }),
|
|
405
|
+
/* @__PURE__ */ require_jsx_runtime.jsxs("div", {
|
|
406
|
+
style: {
|
|
407
|
+
display: "flex",
|
|
408
|
+
gap: 8,
|
|
409
|
+
flexWrap: "wrap"
|
|
410
|
+
},
|
|
411
|
+
children: [/* @__PURE__ */ require_jsx_runtime.jsx("input", {
|
|
412
|
+
"aria-label": "Known namespace for restricted access",
|
|
413
|
+
placeholder: "Known namespace",
|
|
414
|
+
value: knownNamespace,
|
|
415
|
+
maxLength: 63,
|
|
416
|
+
onChange: (event) => setKnownNamespace(event.target.value)
|
|
417
|
+
}), /* @__PURE__ */ require_jsx_runtime.jsx("button", {
|
|
418
|
+
type: "button",
|
|
419
|
+
disabled: !/^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/.test(knownNamespace),
|
|
420
|
+
onClick: () => {
|
|
421
|
+
extraNamespaces.add(knownNamespace);
|
|
422
|
+
restartSearchSync();
|
|
423
|
+
},
|
|
424
|
+
children: "Index namespace"
|
|
425
|
+
})]
|
|
426
|
+
}),
|
|
427
|
+
hasMore && limit >= 1e3 && /* @__PURE__ */ require_jsx_runtime.jsx("p", { children: "Showing up to 1000 candidates. Refine the name, type or namespace to continue." }),
|
|
428
|
+
!coverage.storageFull && /* @__PURE__ */ require_jsx_runtime.jsx("button", {
|
|
429
|
+
type: "button",
|
|
430
|
+
onClick: clearCache,
|
|
431
|
+
children: "Clear local search cache"
|
|
432
|
+
})
|
|
433
|
+
] }),
|
|
305
434
|
/* @__PURE__ */ require_jsx_runtime.jsx("p", {
|
|
306
435
|
className: "power-resource-search-shortcuts",
|
|
307
436
|
children: "↑↓ Navigate · Enter Open · Esc Close"
|
|
@@ -310,10 +439,98 @@ function SearchDialog({ close, clusterId }) {
|
|
|
310
439
|
})
|
|
311
440
|
});
|
|
312
441
|
}
|
|
442
|
+
var currentCoverage = {
|
|
443
|
+
scanned: 0,
|
|
444
|
+
discovered: 0,
|
|
445
|
+
denied: 0,
|
|
446
|
+
unavailable: 0,
|
|
447
|
+
unsupported: 0,
|
|
448
|
+
indexing: true
|
|
449
|
+
};
|
|
450
|
+
var restartSearchSync = () => {};
|
|
451
|
+
var extraNamespaces = /* @__PURE__ */ new Set();
|
|
313
452
|
function startResourceSearch() {
|
|
453
|
+
const preferences = require_monitoring_preferences_store.MonitoringPreferencesStore.getInstanceOrCreate();
|
|
454
|
+
let stop = preferences.resourceSearchEnabled ? startEnabledResourceSearch() : void 0;
|
|
455
|
+
const dispose = require__global_external_mobx.reaction(() => preferences.resourceSearchEnabled, (enabled) => {
|
|
456
|
+
stop?.();
|
|
457
|
+
stop = enabled ? startEnabledResourceSearch() : void 0;
|
|
458
|
+
});
|
|
459
|
+
return () => {
|
|
460
|
+
dispose();
|
|
461
|
+
stop?.();
|
|
462
|
+
stop = void 0;
|
|
463
|
+
};
|
|
464
|
+
}
|
|
465
|
+
function startEnabledResourceSearch() {
|
|
466
|
+
let syncAbort;
|
|
467
|
+
const sync = () => {
|
|
468
|
+
syncAbort?.abort();
|
|
469
|
+
require_resource_search_routing.closeSearchResourceFallback();
|
|
470
|
+
const clusterId = activeId();
|
|
471
|
+
if (!clusterId || window.top === window) return;
|
|
472
|
+
const phase = require_extensions.Renderer.Catalog.activeCluster.get()?.status?.phase;
|
|
473
|
+
if (phase && phase !== "connected") {
|
|
474
|
+
currentCoverage = {
|
|
475
|
+
...currentCoverage,
|
|
476
|
+
indexing: false,
|
|
477
|
+
message: "Cluster disconnected; cached results may be stale"
|
|
478
|
+
};
|
|
479
|
+
window.dispatchEvent(new Event("power-search-coverage"));
|
|
480
|
+
return;
|
|
481
|
+
}
|
|
482
|
+
const controller = new AbortController();
|
|
483
|
+
syncAbort = controller;
|
|
484
|
+
const client = require_resource_search_client.createResourceSearchClient(clusterId, require_resource_search_client.searchContextId());
|
|
485
|
+
const liveStores = new Map(inventory().map(([kind, store]) => [kind, store]));
|
|
486
|
+
const liveObjects = /* @__PURE__ */ new Map();
|
|
487
|
+
const sink = {
|
|
488
|
+
...client,
|
|
489
|
+
append: (scope, scanId, documents) => client.append(scope, scanId, documents.map((item) => {
|
|
490
|
+
const store = liveStores.get(item.kind);
|
|
491
|
+
if (!store) return item;
|
|
492
|
+
let objects = liveObjects.get(item.kind);
|
|
493
|
+
if (!objects) {
|
|
494
|
+
objects = new Map(store.items.map((object) => [object.selfLink, object]));
|
|
495
|
+
liveObjects.set(item.kind, objects);
|
|
496
|
+
}
|
|
497
|
+
const object = objects.get(item.path);
|
|
498
|
+
return object ? {
|
|
499
|
+
...item,
|
|
500
|
+
fields: require_resource_search_fields.projectSearchFields(item.kind, object)
|
|
501
|
+
} : item;
|
|
502
|
+
}))
|
|
503
|
+
};
|
|
504
|
+
let wasIndexing = false;
|
|
505
|
+
require_resource_search_sync.createSearchSynchronizer({
|
|
506
|
+
transport: require_resource_search_client.createResourceSearchTransport(clusterId, controller.signal),
|
|
507
|
+
sink,
|
|
508
|
+
signal: controller.signal,
|
|
509
|
+
namespaces: () => [.../* @__PURE__ */ new Set([...require_extensions.Renderer.Catalog.activeCluster.get()?.spec?.accessibleNamespaces ?? [], ...extraNamespaces])],
|
|
510
|
+
onStatus: (status) => {
|
|
511
|
+
if (!controller.signal.aborted) {
|
|
512
|
+
if (status.indexing && !wasIndexing) liveObjects.clear();
|
|
513
|
+
wasIndexing = status.indexing;
|
|
514
|
+
currentCoverage = status;
|
|
515
|
+
window.dispatchEvent(new Event("power-search-coverage"));
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
}).run().catch(() => {
|
|
519
|
+
if (!controller.signal.aborted) {
|
|
520
|
+
currentCoverage = {
|
|
521
|
+
...currentCoverage,
|
|
522
|
+
indexing: false,
|
|
523
|
+
unavailable: currentCoverage.unavailable + 1
|
|
524
|
+
};
|
|
525
|
+
window.dispatchEvent(new Event("power-search-coverage"));
|
|
526
|
+
}
|
|
527
|
+
});
|
|
528
|
+
};
|
|
529
|
+
restartSearchSync = sync;
|
|
530
|
+
sync();
|
|
314
531
|
const container = document.createElement("div");
|
|
315
532
|
const style = document.createElement("style");
|
|
316
|
-
style.textContent = `.power-resource-search-backdrop{position:fixed;inset:0;z-index:10000;background:#0007;display:flex;align-items:flex-start;justify-content:center;padding:
|
|
533
|
+
style.textContent = `.power-resource-search-backdrop{position:fixed;inset:0;z-index:10000;background:#0007;display:flex;align-items:flex-start;justify-content:center;padding:8vh 20px}.power-resource-search-dialog{width:680px;max-width:100%;max-height:75vh;display:flex;flex-direction:column;padding:20px;gap:12px;background:var(--mainBackground,#222);color:var(--textColorPrimary,#eee);border:1px solid var(--borderColor,#555);border-radius:8px;box-shadow:0 16px 60px #0008}.power-resource-search-heading{display:flex;align-items:center;justify-content:space-between}.power-resource-search-filters input{flex:1;min-width:180px}.power-resource-search-dialog input{padding:12px;font-size:16px;background:var(--inputControlBackground,#333);color:inherit;border:1px solid var(--borderColor,#666);border-radius:4px}.power-resource-search-dialog p{margin:0;font-size:12px;color:var(--textColorSecondary,#bbb)}.power-resource-search-results{overflow:auto;min-height:180px;flex:1}.power-resource-search-row{display:flex;align-items:center;gap:12px;padding:4px;border-radius:4px}.power-resource-search-row{border-left:3px solid transparent}.power-resource-search-row.selected{background:color-mix(in srgb,var(--primary,#668fff) 16%,var(--mainBackground,#222));color:var(--tableSelectedRowColor,var(--textColorPrimary,#eee));border-left-color:var(--primary,#668fff)}.power-resource-search-row.selected .Icon{color:var(--primary,#8daaff)}.power-resource-search-row:hover{background:var(--tableBgcSelected,var(--contentColor,#292d32))}.power-resource-search-dialog button:hover:not(:disabled){background:#ffffff12;border-radius:4px}.power-resource-search-row>button:last-child{border:1px solid var(--borderColor,#555);border-radius:4px}.power-resource-search-shortcuts{padding-top:8px;border-top:1px solid var(--borderColor,#555)}.power-resource-search-dialog button{min-width:32px;min-height:32px;padding:6px;color:inherit;background:transparent;border:0;cursor:pointer}.power-resource-search-dialog button:disabled{opacity:.45;cursor:default}.power-resource-search-open{display:flex;align-items:center;gap:12px;flex:1;text-align:left;min-width:0}.power-resource-search-open span{min-width:0}.power-resource-search-open strong,.power-resource-search-open small{display:block;overflow-wrap:anywhere}.power-resource-search-open small{opacity:.7}.power-resource-search-row>button.power-resource-search-ai{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:34px;height:34px;min-width:34px;padding:0;background:var(--contentColor,#292d32);border:1px solid var(--borderColor,#666)}.power-resource-search-row.selected>button.power-resource-search-ai{background:var(--mainBackground,#202326);border-color:color-mix(in srgb,var(--textColorPrimary,#ddd) 55%,var(--borderColor,#666));box-shadow:0 1px 3px #0002}.power-resource-search-row.selected>button.power-resource-search-ai .Icon{color:var(--textColorAccent,#eee)}.power-resource-search-row>button.power-resource-search-ai:hover:not(:disabled){background:var(--contentColor,#30343a);border-color:var(--primary,#8daaff);color:var(--primary,#8daaff)}.power-resource-search-row>button.power-resource-search-ai:hover:not(:disabled) .Icon{color:inherit}.power-resource-search-dialog button:focus-visible{outline:2px solid var(--primary,#668fff)}`;
|
|
317
534
|
document.head.append(style);
|
|
318
535
|
document.body.append(container);
|
|
319
536
|
let visible = false;
|
|
@@ -347,9 +564,17 @@ function startResourceSearch() {
|
|
|
347
564
|
window.addEventListener("keydown", key);
|
|
348
565
|
window.addEventListener("keyup", key);
|
|
349
566
|
window.addEventListener(OPEN, show);
|
|
350
|
-
const dispose = require__global_external_mobx.reaction(
|
|
567
|
+
const dispose = require__global_external_mobx.reaction(() => `${require_resource_search_client.searchContextId()}/${require_extensions.Renderer.Catalog.activeCluster.get()?.status?.phase}`, () => {
|
|
568
|
+
close();
|
|
569
|
+
extraNamespaces.clear();
|
|
570
|
+
sync();
|
|
571
|
+
});
|
|
351
572
|
return () => {
|
|
352
573
|
close();
|
|
574
|
+
syncAbort?.abort();
|
|
575
|
+
require_resource_search_routing.closeSearchResourceFallback();
|
|
576
|
+
restartSearchSync = () => {};
|
|
577
|
+
extraNamespaces.clear();
|
|
353
578
|
dispose();
|
|
354
579
|
window.removeEventListener("blur", resetShift);
|
|
355
580
|
window.removeEventListener("keydown", key);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resource-search.js","names":[],"sources":["../../src/renderer/resource-search.tsx"],"sourcesContent":["import { Renderer } from \"@freelensapp/extensions\";\nimport { reaction } from \"mobx\";\nimport { useEffect, useMemo, useRef, useState } from \"react\";\nimport ReactDOM from \"react-dom\";\nimport { explainDiagnosticFinding } from \"./ai-diagnostic-handoff\";\nimport { AiIcon } from \"./ai-icon\";\nimport { DiagnosticExplainButton } from \"./diagnostic-explain-button\";\nimport { projectSearchFields } from \"./resource-search-fields\";\nimport {\n createDoubleShift,\n createResourceSearchIndex,\n queryTokens,\n type SearchResource,\n} from \"./resource-search-model\";\n\nconst OPEN = \"power-resource-search\";\nconst activeId = () => Renderer.Catalog.activeCluster.get()?.metadata.uid;\nconst inventory = () =>\n [\n [\"Pod\", Renderer.K8sApi.podsStore, \"view_in_ar\"],\n [\"Node\", Renderer.K8sApi.nodesStore, \"dns\"],\n [\"Deployment\", Renderer.K8sApi.deploymentStore, \"layers\"],\n [\"StatefulSet\", Renderer.K8sApi.statefulSetStore, \"layers\"],\n [\"DaemonSet\", Renderer.K8sApi.daemonSetStore, \"layers\"],\n [\"ReplicaSet\", Renderer.K8sApi.replicaSetStore, \"layers\"],\n [\"Job\", Renderer.K8sApi.jobStore, \"work\"],\n [\"CronJob\", Renderer.K8sApi.cronJobStore, \"schedule\"],\n [\"Service\", Renderer.K8sApi.serviceStore, \"settings_ethernet\"],\n [\"Ingress\", Renderer.K8sApi.ingressStore, \"alt_route\"],\n [\"Namespace\", Renderer.K8sApi.namespaceStore, \"folder\"],\n [\"HorizontalPodAutoscaler\", Renderer.K8sApi.hpaStore, \"swap_vert\"],\n ] as const;\nconst icons = new Map(inventory().map(([kind, , icon]) => [kind as string, icon]));\nfunction project(\n kind: string,\n objects: {\n metadata: { name?: string; namespace?: string; labels?: Partial<Record<string, string>> };\n selfLink: string;\n }[],\n): SearchResource[] {\n return objects.slice(0, 500).flatMap((object) =>\n object.metadata.name\n ? [\n {\n kind,\n name: object.metadata.name,\n namespace: object.metadata.namespace,\n labels: Object.fromEntries(\n Object.entries(object.metadata.labels ?? {}).filter(\n (entry): entry is [string, string] => typeof entry[1] === \"string\",\n ),\n ),\n path: object.selfLink,\n fields: projectSearchFields(kind, object),\n },\n ]\n : [],\n );\n}\n\nexport function ResourceSearchLauncher() {\n return (\n <button\n type=\"button\"\n title=\"Search resources (double Shift)\"\n aria-label=\"Search resources\"\n onClick={() => window.dispatchEvent(new Event(OPEN))}\n >\n <AiIcon material=\"search\" />\n </button>\n );\n}\n\nfunction SearchSnippet({ field, query }: { field?: { label: string; text: string }; query: string }) {\n if (!field) return null;\n const token = queryTokens(query).find((token) => field.text.toLocaleLowerCase().includes(token));\n const offset = token ? field.text.toLocaleLowerCase().indexOf(token) : -1;\n return (\n <small className=\"power-resource-search-snippet\">\n {field.label}:{\" \"}\n {offset < 0 || !token ? (\n field.text\n ) : (\n <>\n {field.text.slice(0, offset)}\n <mark>{field.text.slice(offset, offset + token.length)}</mark>\n {field.text.slice(offset + token.length)}\n </>\n )}\n </small>\n );\n}\n\nfunction SearchDialog({ close, clusterId }: { close: () => void; clusterId: string }) {\n const [query, setQuery] = useState(\"\");\n const [resources, setResources] = useState<SearchResource[]>([]);\n const [loading, setLoading] = useState(true);\n const [failed, setFailed] = useState(0);\n const [selectedPath, setSelectedPath] = useState<string>();\n const [error, setError] = useState(\"\");\n const dialog = useRef<HTMLDivElement>(null);\n const input = useRef<HTMLInputElement>(null);\n const searchIndex = useMemo(() => createResourceSearchIndex(resources), [resources]);\n const matches = searchIndex.search(query);\n const selectedResource = matches.find((resource) => resource.path === selectedPath) ?? matches[0];\n const results = matches.slice(0, 100);\n if (selectedResource && !results.includes(selectedResource)) results[results.length - 1] = selectedResource;\n const selected = results.findIndex((resource) => resource.path === selectedResource?.path);\n useEffect(() => {\n if (selectedPath !== undefined && selectedPath !== selectedResource?.path) setSelectedPath(undefined);\n }, [selectedPath, selectedResource?.path]);\n useEffect(() => {\n const previous = document.activeElement as HTMLElement | null;\n input.current?.focus();\n const controller = new AbortController();\n const timeout = window.setTimeout(() => controller.abort(), 15000);\n let live = true;\n const sources = inventory();\n const parts = sources.map(([kind, store]) => project(kind, store.items));\n setResources(parts.flat());\n let next = 0;\n const worker = async () => {\n while (next < sources.length && live && activeId() === clusterId) {\n const index = next++;\n const [kind, store] = sources[index];\n try {\n const objects = await store.api.list(\n { namespace: \"\", reqInit: { signal: controller.signal } },\n { limit: 500 },\n );\n if (!live || activeId() !== clusterId) return;\n parts[index] = project(kind, objects ?? []);\n setResources(parts.flat());\n } catch {\n if (live && activeId() === clusterId) setFailed((count) => count + 1);\n }\n }\n };\n void Promise.all([worker(), worker()]).then(() => {\n if (live) setLoading(false);\n });\n return () => {\n live = false;\n window.clearTimeout(timeout);\n controller.abort();\n if (previous?.isConnected) previous.focus();\n };\n }, [clusterId]);\n useEffect(() => {\n document.getElementById(`power-resource-result-${selected}`)?.scrollIntoView?.({ block: \"nearest\" });\n }, [selected, selectedResource?.path]);\n const open = (resource: SearchResource) => {\n if (activeId() !== clusterId) return;\n void Promise.resolve()\n .then(() => Renderer.Navigation.showDetails(resource.path))\n .then(() => {\n if (activeId() === clusterId) close();\n })\n .catch(() => setError(\"Could not open this resource. Try again or refresh the inventory.\"));\n };\n return (\n <div\n className=\"power-resource-search-backdrop\"\n data-freelens-power-ai-overlay=\"\"\n onClick={(event) => event.stopPropagation()}\n onMouseDown={(event) => {\n event.stopPropagation();\n if (event.target === event.currentTarget) close();\n }}\n >\n <div\n ref={dialog}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"power-resource-search-title\"\n className=\"power-resource-search-dialog\"\n onKeyDown={(event) => {\n if (event.key === \"Escape\") {\n event.stopPropagation();\n close();\n }\n if (event.key === \"Tab\") {\n const controls = Array.from(\n dialog.current?.querySelectorAll<HTMLElement>(\"input, button:not(:disabled)\") ?? [],\n );\n const index = controls.indexOf(document.activeElement as HTMLElement);\n if (event.shiftKey && index <= 0) {\n event.preventDefault();\n controls.at(-1)?.focus();\n } else if (!event.shiftKey && index === controls.length - 1) {\n event.preventDefault();\n controls[0]?.focus();\n }\n }\n }}\n >\n <div className=\"power-resource-search-heading\">\n <strong id=\"power-resource-search-title\" style={{ display: \"flex\", alignItems: \"center\", gap: 8 }}>\n <AiIcon material=\"search\" size={18} />\n Search resources\n </strong>\n <button type=\"button\" aria-label=\"Close resource search\" onClick={close}>\n <AiIcon material=\"close\" />\n </button>\n </div>\n <input\n ref={input}\n aria-label=\"Resource name, namespace, kind, label or indexed text\"\n aria-controls=\"power-resource-search-results\"\n placeholder=\"Name, namespace, label, image, condition…\"\n maxLength={300}\n value={query}\n onChange={(event) => {\n setQuery(event.target.value);\n setSelectedPath(undefined);\n }}\n onKeyDown={(event) => {\n if (event.key === \"ArrowDown\" || event.key === \"ArrowUp\") {\n event.preventDefault();\n const next = results.length\n ? (selected + (event.key === \"ArrowDown\" ? 1 : -1) + results.length) % results.length\n : 0;\n setSelectedPath(results[next]?.path);\n }\n if (event.key === \"Enter\" && !event.nativeEvent.isComposing && results[selected]) {\n event.preventDefault();\n open(results[selected]);\n }\n }}\n />\n <p role=\"status\">\n {loading ? \"Loading supported kinds; cached results are available. \" : \"Supported kinds loaded. \"}Partial\n inventory: up to 500 objects per kind, subject to permissions. Secrets, ConfigMaps and custom resources are\n excluded. Full-text index covers safe metadata, images, selectors and status only.\n {failed > 0 && ` ${failed} kinds unavailable; cached results retained.`}\n </p>\n {error && <p role=\"alert\">{error}</p>}\n <div\n id=\"power-resource-search-results\"\n role=\"list\"\n aria-label=\"Matching resources\"\n className=\"power-resource-search-results\"\n >\n {results.map((resource, index) => (\n <div\n key={resource.path}\n id={`power-resource-result-${index}`}\n role=\"listitem\"\n className={`power-resource-search-row ${selected === index ? \"selected\" : \"\"}`}\n >\n <button className=\"power-resource-search-open\" type=\"button\" onClick={() => open(resource)}>\n <AiIcon material={icons.get(resource.kind) ?? \"view_in_ar\"} />\n <span>\n <strong>{resource.name}</strong>\n <small>\n {resource.kind} · {resource.namespace ?? \"cluster scoped\"}\n </small>\n {searchIndex.nameParts(resource) && <small>Name parts</small>}\n {searchIndex.similarName(resource) && <small>Similar name</small>}\n <SearchSnippet field={searchIndex.snippet(resource, query)} query={query} />\n </span>\n </button>\n <DiagnosticExplainButton\n className=\"power-resource-search-ai\"\n aria-label={`Ask AI about ${resource.kind} ${resource.name}`}\n title=\"Ask AI about this resource\"\n onClick={() => {\n if (activeId() !== clusterId) return;\n close();\n explainDiagnosticFinding({\n clusterId,\n title: `${resource.kind}: ${resource.name}`,\n summary: `Resource selected from search. Kind: ${resource.kind}; namespace: ${resource.namespace ?? \"cluster scoped\"}; name: ${resource.name}. No live diagnostic data was collected.`,\n resource: { kind: resource.kind, name: resource.name, namespace: resource.namespace },\n });\n }}\n >\n <AiIcon material=\"auto_awesome\" />\n </DiagnosticExplainButton>\n </div>\n ))}\n {!results.length && <p>{loading ? \"Searching…\" : \"No matching resources in the available inventory\"}</p>}\n </div>\n {matches.length > 100 && <p>Showing 100 matches. Refine your search.</p>}\n <p className=\"power-resource-search-shortcuts\">↑↓ Navigate · Enter Open · Esc Close</p>\n </div>\n </div>\n );\n}\n\nexport function startResourceSearch(): () => void {\n const container = document.createElement(\"div\");\n const style = document.createElement(\"style\");\n style.textContent = `.power-resource-search-backdrop{position:fixed;inset:0;z-index:10000;background:#0007;display:flex;align-items:flex-start;justify-content:center;padding:12vh 20px}.power-resource-search-dialog{width:680px;max-width:100%;max-height:75vh;display:flex;flex-direction:column;padding:20px;gap:12px;background:var(--mainBackground,#222);color:var(--textColorPrimary,#eee);border:1px solid var(--borderColor,#555);border-radius:8px;box-shadow:0 16px 60px #0008}.power-resource-search-heading{display:flex;align-items:center;justify-content:space-between}.power-resource-search-dialog input{padding:12px;font-size:16px;background:var(--inputControlBackground,#333);color:inherit;border:1px solid var(--borderColor,#666);border-radius:4px}.power-resource-search-dialog p{margin:0;font-size:12px;color:var(--textColorSecondary,#bbb)}.power-resource-search-results{overflow:auto;min-height:60px}.power-resource-search-row{display:flex;align-items:center;gap:12px;padding:4px;border-radius:4px}.power-resource-search-row{border-left:3px solid transparent}.power-resource-search-row.selected{background:var(--tableSelectedBackground,#394b66);border-left-color:var(--primary,#668fff)}.power-resource-search-row.selected .Icon{color:var(--primary,#8daaff)}.power-resource-search-row:hover{background:var(--tableHoveredBackground,#ffffff0b)}.power-resource-search-dialog button:hover:not(:disabled){background:#ffffff12;border-radius:4px}.power-resource-search-row>button:last-child{border:1px solid var(--borderColor,#555);border-radius:4px}.power-resource-search-shortcuts{padding-top:8px;border-top:1px solid var(--borderColor,#555)}.power-resource-search-dialog button{min-width:32px;min-height:32px;padding:6px;color:inherit;background:transparent;border:0;cursor:pointer}.power-resource-search-dialog button:disabled{opacity:.45;cursor:default}.power-resource-search-open{display:flex;align-items:center;gap:12px;flex:1;text-align:left;min-width:0}.power-resource-search-open span{min-width:0}.power-resource-search-open strong,.power-resource-search-open small{display:block;overflow-wrap:anywhere}.power-resource-search-open small{opacity:.7}.power-resource-search-row>button.power-resource-search-ai{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:34px;height:34px;min-width:34px;padding:0;background:var(--contentColor,#292d32);border:1px solid var(--borderColor,#666)}.power-resource-search-row.selected>button.power-resource-search-ai{background:var(--mainBackground,#202326);border-color:color-mix(in srgb,var(--textColorPrimary,#ddd) 55%,var(--borderColor,#666));box-shadow:0 1px 3px #0002}.power-resource-search-row.selected>button.power-resource-search-ai .Icon{color:var(--textColorAccent,#eee)}.power-resource-search-row>button.power-resource-search-ai:hover:not(:disabled){background:var(--contentColor,#30343a);border-color:var(--primary,#8daaff);color:var(--primary,#8daaff)}.power-resource-search-row>button.power-resource-search-ai:hover:not(:disabled) .Icon{color:inherit}.power-resource-search-dialog button:focus-visible{outline:2px solid var(--primary,#668fff)}`;\n document.head.append(style);\n document.body.append(container);\n let visible = false;\n const close = () => {\n if (visible) {\n visible = false;\n ReactDOM.unmountComponentAtNode(container);\n }\n };\n const show = () => {\n const clusterId = activeId();\n if (\n window.top === window ||\n !clusterId ||\n visible ||\n document.querySelector('[aria-modal=\"true\"], .Dialog.is-opened')\n )\n return;\n visible = true;\n ReactDOM.render(<SearchDialog close={close} clusterId={clusterId} />, container);\n };\n let shift = createDoubleShift();\n const resetShift = () => {\n shift = createDoubleShift();\n };\n const key = (event: KeyboardEvent) => {\n if (event.isComposing || event.key === \"Process\") {\n resetShift();\n return;\n }\n if (shift(event, performance.now())) show();\n };\n window.addEventListener(\"blur\", resetShift);\n window.addEventListener(\"keydown\", key);\n window.addEventListener(\"keyup\", key);\n window.addEventListener(OPEN, show);\n const dispose = reaction(activeId, close);\n return () => {\n close();\n dispose();\n window.removeEventListener(\"blur\", resetShift);\n window.removeEventListener(\"keydown\", key);\n window.removeEventListener(\"keyup\", key);\n window.removeEventListener(OPEN, show);\n container.remove();\n style.remove();\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"resource-search.js","names":[],"sources":["../../src/renderer/resource-search.tsx"],"sourcesContent":["import { Renderer } from \"@freelensapp/extensions\";\nimport { reaction } from \"mobx\";\nimport { observer } from \"mobx-react\";\nimport { useEffect, useMemo, useRef, useState } from \"react\";\nimport ReactDOM from \"react-dom\";\nimport { MonitoringPreferencesStore } from \"../common/store/monitoring-preferences-store\";\nimport { explainDiagnosticFinding } from \"./ai-diagnostic-handoff\";\nimport { AiIcon } from \"./ai-icon\";\nimport { DiagnosticExplainButton } from \"./diagnostic-explain-button\";\nimport { createResourceSearchClient, createResourceSearchTransport, searchContextId } from \"./resource-search-client\";\nimport { projectSearchFields } from \"./resource-search-fields\";\nimport {\n createDoubleShift,\n createResourceSearchIndex,\n queryTokens,\n type SearchResource,\n} from \"./resource-search-model\";\nimport { closeSearchResourceFallback, openSearchResource } from \"./resource-search-routing\";\nimport { createSearchSynchronizer, type SearchCoverage } from \"./resource-search-sync\";\n\nimport type { SearchDocument } from \"../common/resource-search\";\n\nconst OPEN = \"power-resource-search\";\nconst activeId = () => Renderer.Catalog.activeCluster.get()?.metadata.uid;\nconst inventory = () =>\n [\n [\"Pod\", Renderer.K8sApi.podsStore, \"view_in_ar\"],\n [\"Node\", Renderer.K8sApi.nodesStore, \"dns\"],\n [\"Deployment\", Renderer.K8sApi.deploymentStore, \"layers\"],\n [\"StatefulSet\", Renderer.K8sApi.statefulSetStore, \"layers\"],\n [\"DaemonSet\", Renderer.K8sApi.daemonSetStore, \"layers\"],\n [\"ReplicaSet\", Renderer.K8sApi.replicaSetStore, \"layers\"],\n [\"Job\", Renderer.K8sApi.jobStore, \"work\"],\n [\"CronJob\", Renderer.K8sApi.cronJobStore, \"schedule\"],\n [\"Service\", Renderer.K8sApi.serviceStore, \"settings_ethernet\"],\n [\"Ingress\", Renderer.K8sApi.ingressStore, \"alt_route\"],\n [\"Namespace\", Renderer.K8sApi.namespaceStore, \"folder\"],\n [\"HorizontalPodAutoscaler\", Renderer.K8sApi.hpaStore, \"swap_vert\"],\n ] as const;\nconst icons = new Map(inventory().map(([kind, , icon]) => [kind as string, icon]));\n\nexport const ResourceSearchLauncher = observer(() => {\n if (!MonitoringPreferencesStore.getInstanceOrCreate<MonitoringPreferencesStore>().resourceSearchEnabled) return null;\n return (\n <button\n type=\"button\"\n title=\"Search resources (double Shift)\"\n aria-label=\"Search resources\"\n onClick={() => window.dispatchEvent(new Event(OPEN))}\n >\n <AiIcon material=\"search\" />\n </button>\n );\n});\n\nfunction SearchSnippet({ field, query }: { field?: { label: string; text: string }; query: string }) {\n if (!field) return null;\n const token = queryTokens(query).find((token) => field.text.toLocaleLowerCase().includes(token));\n const offset = token ? field.text.toLocaleLowerCase().indexOf(token) : -1;\n return (\n <small className=\"power-resource-search-snippet\">\n {field.label}:{\" \"}\n {offset < 0 || !token ? (\n field.text\n ) : (\n <>\n {field.text.slice(0, offset)}\n <mark>{field.text.slice(offset, offset + token.length)}</mark>\n {field.text.slice(offset + token.length)}\n </>\n )}\n </small>\n );\n}\n\nfunction SearchDialog({ close, clusterId }: { close: () => void; clusterId: string }) {\n const [query, setQuery] = useState(\"\");\n const [knownNamespace, setKnownNamespace] = useState(\"\");\n const [kindFilter, setKindFilter] = useState(\"\");\n const [namespaceFilter, setNamespaceFilter] = useState(\"\");\n const [resources, setResources] = useState<SearchResource[]>([]);\n const [loading, setLoading] = useState(true);\n const [failed, setFailed] = useState(0);\n const [cachedCount, setCachedCount] = useState<number>();\n const [selectedPath, setSelectedPath] = useState<string>();\n const [error, setError] = useState(\"\");\n const dialog = useRef<HTMLDivElement>(null);\n const input = useRef<HTMLInputElement>(null);\n const searchIndex = useMemo(() => createResourceSearchIndex(resources), [resources]);\n const matches = searchIndex.search(query);\n const selectedResource = matches.find((resource) => resource.path === selectedPath) ?? matches[0];\n const results = matches;\n if (selectedResource && !results.includes(selectedResource)) results[results.length - 1] = selectedResource;\n const selected = results.findIndex((resource) => resource.path === selectedResource?.path);\n useEffect(() => {\n if (selectedPath !== undefined && selectedPath !== selectedResource?.path) setSelectedPath(undefined);\n }, [selectedPath, selectedResource?.path]);\n const [coverage, setCoverage] = useState<SearchCoverage>(currentCoverage);\n const [limit, setLimit] = useState(100);\n const [hasMore, setHasMore] = useState(false);\n useEffect(() => {\n const previous = document.activeElement as HTMLElement | null;\n input.current?.focus();\n const update = () => setCoverage({ ...currentCoverage });\n window.addEventListener(\"power-search-coverage\", update);\n return () => {\n window.removeEventListener(\"power-search-coverage\", update);\n if (previous?.isConnected) previous.focus();\n };\n }, []);\n useEffect(() => {\n let live = true;\n const client = createResourceSearchClient(clusterId, searchContextId());\n const timer = window.setTimeout(() => {\n void client\n .query(query, limit, {\n ...(kindFilter\n ? {\n kind:\n coverage.kinds?.find((kind) => kind.toLocaleLowerCase() === kindFilter.toLocaleLowerCase()) ??\n kindFilter,\n }\n : {}),\n ...(namespaceFilter ? { namespace: namespaceFilter === \"(cluster)\" ? \"\" : namespaceFilter } : {}),\n })\n .then((result) => {\n if (!live || activeId() !== clusterId) return;\n setResources(result.documents);\n setHasMore(result.hasMore);\n setLoading(false);\n setFailed(0);\n void client\n .status?.()\n .then((status) => {\n if (live) setCachedCount(status.count);\n })\n .catch(() => {});\n })\n .catch(() => {\n if (live) {\n setFailed(1);\n setLoading(false);\n }\n });\n }, 100);\n return () => {\n live = false;\n window.clearTimeout(timer);\n };\n }, [clusterId, query, limit, kindFilter, namespaceFilter, coverage.scanned, coverage.indexing]);\n useEffect(() => {\n document.getElementById(`power-resource-result-${selected}`)?.scrollIntoView?.({ block: \"nearest\" });\n }, [selected, selectedResource?.path]);\n const clearCache = () => {\n void createResourceSearchClient(clusterId, searchContextId())\n .clear()\n .then(() => {\n setResources([]);\n restartSearchSync();\n })\n .catch(() => setError(\"Could not clear the local search cache. Try again.\"));\n };\n const open = (resource: SearchResource) => {\n if (activeId() !== clusterId) return;\n void Promise.resolve()\n .then(() => openSearchResource(resource as SearchDocument))\n .then(() => {\n if (activeId() === clusterId) close();\n })\n .catch(() => setError(\"Could not open this resource. Try again or refresh the inventory.\"));\n };\n return (\n <div\n className=\"power-resource-search-backdrop\"\n data-freelens-power-ai-overlay=\"\"\n onClick={(event) => event.stopPropagation()}\n onMouseDown={(event) => {\n event.stopPropagation();\n if (event.target === event.currentTarget) close();\n }}\n >\n <div\n ref={dialog}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"power-resource-search-title\"\n className=\"power-resource-search-dialog\"\n onKeyDown={(event) => {\n if (event.key === \"Escape\") {\n event.stopPropagation();\n close();\n }\n if (event.key === \"Tab\") {\n const controls = Array.from(\n dialog.current?.querySelectorAll<HTMLElement>(\"input, button:not(:disabled), select\") ?? [],\n );\n const index = controls.indexOf(document.activeElement as HTMLElement);\n if (event.shiftKey && index <= 0) {\n event.preventDefault();\n controls.at(-1)?.focus();\n } else if (!event.shiftKey && index === controls.length - 1) {\n event.preventDefault();\n controls[0]?.focus();\n }\n }\n }}\n >\n <div className=\"power-resource-search-heading\">\n <strong id=\"power-resource-search-title\" style={{ display: \"flex\", alignItems: \"center\", gap: 8 }}>\n <AiIcon material=\"search\" size={18} />\n Search resources\n </strong>\n <div style={{ display: \"flex\", gap: 4 }}>\n <button\n type=\"button\"\n aria-label=\"Refresh resource inventory\"\n title=\"Refresh resource inventory\"\n onClick={() => restartSearchSync()}\n >\n <AiIcon material=\"refresh\" />\n </button>\n <button type=\"button\" aria-label=\"Close resource search\" onClick={close}>\n <AiIcon material=\"close\" />\n </button>\n </div>\n </div>\n <input\n ref={input}\n aria-label=\"Resource name, namespace, kind, label or indexed text\"\n aria-controls=\"power-resource-search-results\"\n placeholder=\"Name, namespace, label, image, condition…\"\n maxLength={300}\n value={query}\n onChange={(event) => {\n setQuery(event.target.value);\n setSelectedPath(undefined);\n }}\n onKeyDown={(event) => {\n if (event.key === \"ArrowDown\" || event.key === \"ArrowUp\") {\n event.preventDefault();\n const next = results.length\n ? (selected + (event.key === \"ArrowDown\" ? 1 : -1) + results.length) % results.length\n : 0;\n setSelectedPath(results[next]?.path);\n }\n if (event.key === \"Enter\" && !event.nativeEvent.isComposing && results[selected]) {\n event.preventDefault();\n open(results[selected]);\n }\n }}\n />\n <div className=\"power-resource-search-filters\" style={{ display: \"flex\", gap: 8, flexWrap: \"wrap\" }}>\n <input\n list=\"power-search-kinds\"\n aria-label=\"Filter by exact resource kind\"\n placeholder=\"Kind (all types)\"\n value={kindFilter}\n maxLength={253}\n onChange={(event) => {\n setKindFilter(event.target.value);\n setSelectedPath(undefined);\n }}\n />\n <input\n list=\"power-search-namespaces\"\n aria-label=\"Filter by exact namespace\"\n placeholder=\"Namespace (all)\"\n value={namespaceFilter}\n maxLength={253}\n onChange={(event) => {\n setNamespaceFilter(event.target.value);\n setSelectedPath(undefined);\n }}\n />\n </div>\n <datalist id=\"power-search-kinds\">\n {(coverage.kinds ?? []).map((kind) => (\n <option key={kind} value={kind} />\n ))}\n </datalist>\n <datalist id=\"power-search-namespaces\">\n <option value=\"(cluster)\">Cluster scoped</option>\n {(coverage.namespaces ?? []).map((namespace) => (\n <option key={namespace} value={namespace} />\n ))}\n </datalist>\n <p role=\"status\">\n {coverage.indexing\n ? `Indexing ${coverage.scanned}/${coverage.discovered} types`\n : coverage.completedAt\n ? `Updated ${new Date(coverage.completedAt).toLocaleTimeString([], { hour: \"2-digit\", minute: \"2-digit\" })}`\n : \"Cached inventory\"}\n {cachedCount !== undefined && ` · ${cachedCount.toLocaleString()} resources`}\n {coverage.denied > 0 && ` · ${coverage.denied} restricted scopes`}\n {coverage.unavailable + coverage.unsupported > 0 &&\n ` · ${coverage.unavailable + coverage.unsupported} APIs unavailable`}\n {failed > 0 && \" · Search cache unavailable\"}\n </p>\n {(coverage.message || coverage.denied > 0 || coverage.unavailable + coverage.unsupported > 0) && (\n <details>\n <summary>Inventory coverage</summary>\n <p>\n {coverage.message ?? \"Results include the resources your current permissions and available APIs allow.\"}\n </p>\n </details>\n )}\n {coverage.storageFull && (\n <div role=\"alert\">\n <p>Local search storage is full. Cached results are partial; indexing is paused.</p>\n <button type=\"button\" onClick={clearCache}>\n Clear local search cache\n </button>\n </div>\n )}\n {error && <p role=\"alert\">{error}</p>}\n <div\n id=\"power-resource-search-results\"\n role=\"list\"\n aria-label=\"Matching resources\"\n className=\"power-resource-search-results\"\n >\n {results.map((resource, index) => (\n <div\n key={resource.path}\n id={`power-resource-result-${index}`}\n role=\"listitem\"\n className={`power-resource-search-row ${selected === index ? \"selected\" : \"\"}`}\n >\n <button className=\"power-resource-search-open\" type=\"button\" onClick={() => open(resource)}>\n <AiIcon material={icons.get(resource.kind) ?? \"view_in_ar\"} />\n <span>\n <strong>{resource.name}</strong>\n <small>\n {resource.kind} · {resource.namespace ?? \"cluster scoped\"}\n </small>\n {searchIndex.nameParts(resource) && <small>Name parts</small>}\n {searchIndex.similarName(resource) && <small>Similar name</small>}\n <SearchSnippet field={searchIndex.snippet(resource, query)} query={query} />\n </span>\n </button>\n <DiagnosticExplainButton\n className=\"power-resource-search-ai\"\n aria-label={`Ask AI about ${resource.kind} ${resource.name}`}\n title=\"Ask AI about this resource\"\n onClick={() => {\n if (activeId() !== clusterId) return;\n close();\n explainDiagnosticFinding({\n clusterId,\n title: `${resource.kind}: ${resource.name}`,\n summary: `Resource selected from search. API group: ${(resource as SearchDocument).group || \"core\"}; version: ${(resource as SearchDocument).version}; resource: ${(resource as SearchDocument).resource}; kind: ${resource.kind}; namespace: ${resource.namespace ?? \"cluster scoped\"}; name: ${resource.name}; UID: ${(resource as SearchDocument).uid ?? \"unknown\"}; path: ${resource.path}. No live diagnostic data was collected.`,\n resource: { kind: resource.kind, name: resource.name, namespace: resource.namespace },\n });\n }}\n >\n <AiIcon material=\"auto_awesome\" />\n </DiagnosticExplainButton>\n </div>\n ))}\n {!results.length && <p>{loading ? \"Searching…\" : \"No matching resources in the available inventory\"}</p>}\n </div>\n {hasMore && (\n <button\n type=\"button\"\n disabled={limit >= 1000}\n onClick={() => setLimit((value) => Math.min(1000, value + 100))}\n >\n Show more matches\n </button>\n )}\n <details>\n <summary>Search options</summary>\n <div style={{ display: \"flex\", gap: 8, flexWrap: \"wrap\" }}>\n <input\n aria-label=\"Known namespace for restricted access\"\n placeholder=\"Known namespace\"\n value={knownNamespace}\n maxLength={63}\n onChange={(event) => setKnownNamespace(event.target.value)}\n />\n <button\n type=\"button\"\n disabled={!/^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/.test(knownNamespace)}\n onClick={() => {\n extraNamespaces.add(knownNamespace);\n restartSearchSync();\n }}\n >\n Index namespace\n </button>\n </div>\n {hasMore && limit >= 1000 && (\n <p>Showing up to 1000 candidates. Refine the name, type or namespace to continue.</p>\n )}\n {!coverage.storageFull && (\n <button type=\"button\" onClick={clearCache}>\n Clear local search cache\n </button>\n )}\n </details>\n <p className=\"power-resource-search-shortcuts\">↑↓ Navigate · Enter Open · Esc Close</p>\n </div>\n </div>\n );\n}\n\nlet currentCoverage: SearchCoverage = {\n scanned: 0,\n discovered: 0,\n denied: 0,\n unavailable: 0,\n unsupported: 0,\n indexing: true,\n};\nlet restartSearchSync = () => {};\nconst extraNamespaces = new Set<string>();\n\nexport function startResourceSearch(): () => void {\n const preferences = MonitoringPreferencesStore.getInstanceOrCreate<MonitoringPreferencesStore>();\n let stop = preferences.resourceSearchEnabled ? startEnabledResourceSearch() : undefined;\n const dispose = reaction(\n () => preferences.resourceSearchEnabled,\n (enabled) => {\n stop?.();\n stop = enabled ? startEnabledResourceSearch() : undefined;\n },\n );\n return () => {\n dispose();\n stop?.();\n stop = undefined;\n };\n}\n\nfunction startEnabledResourceSearch(): () => void {\n let syncAbort: AbortController | undefined;\n const sync = () => {\n syncAbort?.abort();\n closeSearchResourceFallback();\n const clusterId = activeId();\n if (!clusterId || window.top === window) return;\n const phase = Renderer.Catalog.activeCluster.get()?.status?.phase;\n if (phase && phase !== \"connected\") {\n currentCoverage = {\n ...currentCoverage,\n indexing: false,\n message: \"Cluster disconnected; cached results may be stale\",\n };\n window.dispatchEvent(new Event(\"power-search-coverage\"));\n return;\n }\n const controller = new AbortController();\n syncAbort = controller;\n const client = createResourceSearchClient(clusterId, searchContextId());\n const liveStores = new Map(inventory().map(([kind, store]) => [kind as string, store]));\n const liveObjects = new Map<string, Map<string, unknown>>();\n const sink = {\n ...client,\n append: (scope: string, scanId: string, documents: SearchDocument[]) =>\n client.append(\n scope,\n scanId,\n documents.map((item) => {\n const store = liveStores.get(item.kind);\n if (!store) return item;\n let objects = liveObjects.get(item.kind);\n if (!objects) {\n objects = new Map(store.items.map((object) => [object.selfLink, object] as const));\n liveObjects.set(item.kind, objects);\n }\n const object = objects.get(item.path);\n return object ? { ...item, fields: projectSearchFields(item.kind, object) } : item;\n }),\n ),\n };\n let wasIndexing = false;\n const task = createSearchSynchronizer({\n transport: createResourceSearchTransport(clusterId, controller.signal),\n sink,\n signal: controller.signal,\n namespaces: () => [\n ...new Set([...(Renderer.Catalog.activeCluster.get()?.spec?.accessibleNamespaces ?? []), ...extraNamespaces]),\n ],\n onStatus: (status) => {\n if (!controller.signal.aborted) {\n if (status.indexing && !wasIndexing) liveObjects.clear();\n wasIndexing = status.indexing;\n currentCoverage = status;\n window.dispatchEvent(new Event(\"power-search-coverage\"));\n }\n },\n });\n void task.run().catch(() => {\n if (!controller.signal.aborted) {\n currentCoverage = { ...currentCoverage, indexing: false, unavailable: currentCoverage.unavailable + 1 };\n window.dispatchEvent(new Event(\"power-search-coverage\"));\n }\n });\n };\n restartSearchSync = sync;\n sync();\n const container = document.createElement(\"div\");\n const style = document.createElement(\"style\");\n style.textContent = `.power-resource-search-backdrop{position:fixed;inset:0;z-index:10000;background:#0007;display:flex;align-items:flex-start;justify-content:center;padding:8vh 20px}.power-resource-search-dialog{width:680px;max-width:100%;max-height:75vh;display:flex;flex-direction:column;padding:20px;gap:12px;background:var(--mainBackground,#222);color:var(--textColorPrimary,#eee);border:1px solid var(--borderColor,#555);border-radius:8px;box-shadow:0 16px 60px #0008}.power-resource-search-heading{display:flex;align-items:center;justify-content:space-between}.power-resource-search-filters input{flex:1;min-width:180px}.power-resource-search-dialog input{padding:12px;font-size:16px;background:var(--inputControlBackground,#333);color:inherit;border:1px solid var(--borderColor,#666);border-radius:4px}.power-resource-search-dialog p{margin:0;font-size:12px;color:var(--textColorSecondary,#bbb)}.power-resource-search-results{overflow:auto;min-height:180px;flex:1}.power-resource-search-row{display:flex;align-items:center;gap:12px;padding:4px;border-radius:4px}.power-resource-search-row{border-left:3px solid transparent}.power-resource-search-row.selected{background:color-mix(in srgb,var(--primary,#668fff) 16%,var(--mainBackground,#222));color:var(--tableSelectedRowColor,var(--textColorPrimary,#eee));border-left-color:var(--primary,#668fff)}.power-resource-search-row.selected .Icon{color:var(--primary,#8daaff)}.power-resource-search-row:hover{background:var(--tableBgcSelected,var(--contentColor,#292d32))}.power-resource-search-dialog button:hover:not(:disabled){background:#ffffff12;border-radius:4px}.power-resource-search-row>button:last-child{border:1px solid var(--borderColor,#555);border-radius:4px}.power-resource-search-shortcuts{padding-top:8px;border-top:1px solid var(--borderColor,#555)}.power-resource-search-dialog button{min-width:32px;min-height:32px;padding:6px;color:inherit;background:transparent;border:0;cursor:pointer}.power-resource-search-dialog button:disabled{opacity:.45;cursor:default}.power-resource-search-open{display:flex;align-items:center;gap:12px;flex:1;text-align:left;min-width:0}.power-resource-search-open span{min-width:0}.power-resource-search-open strong,.power-resource-search-open small{display:block;overflow-wrap:anywhere}.power-resource-search-open small{opacity:.7}.power-resource-search-row>button.power-resource-search-ai{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:34px;height:34px;min-width:34px;padding:0;background:var(--contentColor,#292d32);border:1px solid var(--borderColor,#666)}.power-resource-search-row.selected>button.power-resource-search-ai{background:var(--mainBackground,#202326);border-color:color-mix(in srgb,var(--textColorPrimary,#ddd) 55%,var(--borderColor,#666));box-shadow:0 1px 3px #0002}.power-resource-search-row.selected>button.power-resource-search-ai .Icon{color:var(--textColorAccent,#eee)}.power-resource-search-row>button.power-resource-search-ai:hover:not(:disabled){background:var(--contentColor,#30343a);border-color:var(--primary,#8daaff);color:var(--primary,#8daaff)}.power-resource-search-row>button.power-resource-search-ai:hover:not(:disabled) .Icon{color:inherit}.power-resource-search-dialog button:focus-visible{outline:2px solid var(--primary,#668fff)}`;\n document.head.append(style);\n document.body.append(container);\n let visible = false;\n const close = () => {\n if (visible) {\n visible = false;\n ReactDOM.unmountComponentAtNode(container);\n }\n };\n const show = () => {\n const clusterId = activeId();\n if (\n window.top === window ||\n !clusterId ||\n visible ||\n document.querySelector('[aria-modal=\"true\"], .Dialog.is-opened')\n )\n return;\n visible = true;\n ReactDOM.render(<SearchDialog close={close} clusterId={clusterId} />, container);\n };\n let shift = createDoubleShift();\n const resetShift = () => {\n shift = createDoubleShift();\n };\n const key = (event: KeyboardEvent) => {\n if (event.isComposing || event.key === \"Process\") {\n resetShift();\n return;\n }\n if (shift(event, performance.now())) show();\n };\n window.addEventListener(\"blur\", resetShift);\n window.addEventListener(\"keydown\", key);\n window.addEventListener(\"keyup\", key);\n window.addEventListener(OPEN, show);\n const dispose = reaction(\n () => `${searchContextId()}/${Renderer.Catalog.activeCluster.get()?.status?.phase}`,\n () => {\n close();\n extraNamespaces.clear();\n sync();\n },\n );\n return () => {\n close();\n syncAbort?.abort();\n closeSearchResourceFallback();\n restartSearchSync = () => {};\n extraNamespaces.clear();\n dispose();\n window.removeEventListener(\"blur\", resetShift);\n window.removeEventListener(\"keydown\", key);\n window.removeEventListener(\"keyup\", key);\n window.removeEventListener(OPEN, show);\n container.remove();\n style.remove();\n };\n}\n"],"mappings":"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"}
|