@64mb/freelens-power 2.1.0 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. package/README.md +4 -4
  2. package/out/main/common/power-logs.js.map +1 -1
  3. package/out/main/common/resource-search.js.map +1 -1
  4. package/out/main/power-logs-child.js +3 -3
  5. package/out/main/power-logs-child.js.map +1 -1
  6. package/out/main/power-logs-database.js +165 -7
  7. package/out/main/power-logs-database.js.map +1 -1
  8. package/out/main/power-logs-ipc.js +12 -3
  9. package/out/main/power-logs-ipc.js.map +1 -1
  10. package/out/main/power-logs-worker.js +29 -7
  11. package/out/main/power-logs-worker.js.map +1 -1
  12. package/out/main/resource-search-database.js +3 -2
  13. package/out/main/resource-search-database.js.map +1 -1
  14. package/out/main/resource-search.js +2 -1
  15. package/out/main/resource-search.js.map +1 -1
  16. package/out/renderer/_virtual/_global-external_react.js +2 -1
  17. package/out/renderer/ai-context-mutations.js +14 -0
  18. package/out/renderer/ai-context-mutations.js.map +1 -0
  19. package/out/renderer/ai-copy-answer.js +18 -15
  20. package/out/renderer/ai-copy-answer.js.map +1 -1
  21. package/out/renderer/ai-diagnostic-handoff.js +2 -2
  22. package/out/renderer/ai-diagnostic-handoff.js.map +1 -1
  23. package/out/renderer/ai-extras.js +41 -38
  24. package/out/renderer/ai-extras.js.map +1 -1
  25. package/out/renderer/ai-message.js +50 -39
  26. package/out/renderer/ai-message.js.map +1 -1
  27. package/out/renderer/ai-provider-icon.js +39 -32
  28. package/out/renderer/ai-provider-icon.js.map +1 -1
  29. package/out/renderer/ai-resize.js +40 -37
  30. package/out/renderer/ai-resize.js.map +1 -1
  31. package/out/renderer/ai-shortcuts.js +20 -17
  32. package/out/renderer/ai-shortcuts.js.map +1 -1
  33. package/out/renderer/ai-terminal-context.js +42 -48
  34. package/out/renderer/ai-terminal-context.js.map +1 -1
  35. package/out/renderer/ai.js +137 -111
  36. package/out/renderer/ai.js.map +1 -1
  37. package/out/renderer/cluster-icon-colors.js +10 -7
  38. package/out/renderer/cluster-icon-colors.js.map +1 -1
  39. package/out/renderer/cluster-icons.js +47 -40
  40. package/out/renderer/cluster-icons.js.map +1 -1
  41. package/out/renderer/details/service-diagnostics-details.js +25 -23
  42. package/out/renderer/details/service-diagnostics-details.js.map +1 -1
  43. package/out/renderer/diagnostic-explain-button.js +7 -4
  44. package/out/renderer/diagnostic-explain-button.js.map +1 -1
  45. package/out/renderer/diagnostics-screen-finding.js +51 -0
  46. package/out/renderer/diagnostics-screen-finding.js.map +1 -0
  47. package/out/renderer/diagnostics.css.js +1 -1
  48. package/out/renderer/diagnostics.css.js.map +1 -1
  49. package/out/renderer/diagnostics.js +146 -107
  50. package/out/renderer/diagnostics.js.map +1 -1
  51. package/out/renderer/incident-copy-button.js +24 -21
  52. package/out/renderer/incident-copy-button.js.map +1 -1
  53. package/out/renderer/index.js +2 -0
  54. package/out/renderer/index.js.map +1 -1
  55. package/out/renderer/monitoring.js +19 -22
  56. package/out/renderer/monitoring.js.map +1 -1
  57. package/out/renderer/native-tooltip.js +22 -0
  58. package/out/renderer/native-tooltip.js.map +1 -0
  59. package/out/renderer/pod-details-enhancements.js +106 -0
  60. package/out/renderer/pod-details-enhancements.js.map +1 -0
  61. package/out/renderer/power-log-json-cell.js +44 -38
  62. package/out/renderer/power-log-json-cell.js.map +1 -1
  63. package/out/renderer/power-log-json.js +17 -10
  64. package/out/renderer/power-log-json.js.map +1 -1
  65. package/out/renderer/power-log-sql-editor.js +31 -2
  66. package/out/renderer/power-log-sql-editor.js.map +1 -1
  67. package/out/renderer/power-logs-client.js +5 -0
  68. package/out/renderer/power-logs-client.js.map +1 -1
  69. package/out/renderer/power-logs-entrypoints.js +10 -36
  70. package/out/renderer/power-logs-entrypoints.js.map +1 -1
  71. package/out/renderer/power-logs.css.js +9 -2
  72. package/out/renderer/power-logs.css.js.map +1 -1
  73. package/out/renderer/power-logs.js +376 -214
  74. package/out/renderer/power-logs.js.map +1 -1
  75. package/out/renderer/preferences/dashboard-preferences.js +42 -35
  76. package/out/renderer/preferences/dashboard-preferences.js.map +1 -1
  77. package/out/renderer/preferences/logs-preferences.js +1 -1
  78. package/out/renderer/preferences/logs-preferences.js.map +1 -1
  79. package/out/renderer/preferences/monitoring-preferences.js +7 -4
  80. package/out/renderer/preferences/monitoring-preferences.js.map +1 -1
  81. package/out/renderer/preferences/preferences.js +2 -2
  82. package/out/renderer/preferences/preferences.js.map +1 -1
  83. package/out/renderer/preferences/settings-icon-action.js +12 -11
  84. package/out/renderer/preferences/settings-icon-action.js.map +1 -1
  85. package/out/renderer/relationship-map-finding.js +53 -0
  86. package/out/renderer/relationship-map-finding.js.map +1 -0
  87. package/out/renderer/resource-relationships.css.js +6 -0
  88. package/out/renderer/resource-relationships.css.js.map +1 -1
  89. package/out/renderer/resource-relationships.js +94 -47
  90. package/out/renderer/resource-relationships.js.map +1 -1
  91. package/out/renderer/resource-search-client.js.map +1 -1
  92. package/out/renderer/resource-search.js +88 -35
  93. package/out/renderer/resource-search.js.map +1 -1
  94. package/out/renderer/src/common/gateway-relationships.js +8 -7
  95. package/out/renderer/src/common/gateway-relationships.js.map +1 -1
  96. package/out/renderer/src/common/power-log-json-filter-sql.js +12 -0
  97. package/out/renderer/src/common/power-log-json-filter-sql.js.map +1 -1
  98. package/out/renderer/src/common/power-log-json-preset.js +2 -2
  99. package/out/renderer/src/common/power-log-json-preset.js.map +1 -1
  100. package/out/renderer/src/common/power-logs.js.map +1 -1
  101. package/out/renderer/src/common/resource-relationships.js +10 -8
  102. package/out/renderer/src/common/resource-relationships.js.map +1 -1
  103. package/out/renderer/src/common/resource-search.js.map +1 -1
  104. package/out/renderer/welcome.js +16 -1
  105. package/out/renderer/welcome.js.map +1 -1
  106. package/package.json +1 -1
@@ -5,6 +5,7 @@ const require_power_logs_limits = require("./src/common/power-logs-limits.js");
5
5
  const require_logs_preferences_store = require("./src/common/store/logs-preferences-store.js");
6
6
  const require__global_external_react = require("./_virtual/_global-external_react.js");
7
7
  const require_jsx_runtime = require("./_virtual/_global-external_react/jsx-runtime.js");
8
+ const require_native_tooltip = require("./native-tooltip.js");
8
9
  const require_ai_diagnostic_handoff = require("./ai-diagnostic-handoff.js");
9
10
  const require_date_time = require("./src/common/date-time.js");
10
11
  const require_diagnostic_explain_button = require("./diagnostic-explain-button.js");
@@ -45,9 +46,9 @@ var levels = [
45
46
  "unknown"
46
47
  ];
47
48
  var examples = [
48
- ["Recent", "SELECT message, level, container, pod, timestamp FROM logs ORDER BY timestamp DESC NULLS LAST LIMIT 200"],
49
- ["Errors", "SELECT pod, container, count(*) AS errors FROM logs WHERE level IN ('error','fatal') GROUP BY pod, container ORDER BY errors DESC"],
50
- ["Timeline", "SELECT strftime('%Y-%m-%d %H:%M', timestamp / 1000, 'unixepoch') AS minute, UPPER(level) AS level, count(*) AS lines FROM logs GROUP BY minute, level ORDER BY minute"],
49
+ ["Recent", "SELECT timestamp, level, message, container, pod FROM logs ORDER BY timestamp DESC NULLS LAST LIMIT 200"],
50
+ ["Errors", "SELECT message, count(*) AS occurrences FROM logs WHERE level IN ('error','fatal') GROUP BY message ORDER BY occurrences DESC LIMIT 200"],
51
+ ["Timeline", "SELECT (timestamp / 60000) * 60000 AS minute, UPPER(level) AS level, count(*) AS lines FROM logs GROUP BY minute, level ORDER BY minute"],
51
52
  ["JSON", "SELECT fieldsJson FROM logs WHERE fieldsJson IS NOT NULL LIMIT 100"]
52
53
  ];
53
54
  var sqlColumnWidth = (column) => column === "message" || column === "fieldsJson" ? 360 : column === "level" ? 90 : 200;
@@ -224,9 +225,9 @@ function LogRows({ records, loading, selected, onSelect, follow, setFollow, comp
224
225
  },
225
226
  onClick: () => onSelect(record),
226
227
  children: [
227
- /* @__PURE__ */ require_jsx_runtime.jsx("span", {
228
+ /* @__PURE__ */ require_jsx_runtime.jsx(require_native_tooltip.NativeTooltip, {
228
229
  title: record.timestamp !== null ? require_date_time.formatDateTime(record.timestamp) : "Timestamp unavailable",
229
- children: record.timestamp !== null ? require_date_time.formatDateTime(record.timestamp).slice(-8) : "—"
230
+ children: /* @__PURE__ */ require_jsx_runtime.jsx("span", { children: record.timestamp !== null ? require_date_time.formatDateTime(record.timestamp).slice(-8) : "—" })
230
231
  }),
231
232
  /* @__PURE__ */ require_jsx_runtime.jsx("span", {
232
233
  className: "power-log-level",
@@ -263,41 +264,49 @@ function LogDetails({ record, jsonColumn, onClose, onFilter }) {
263
264
  className: "power-logs-detail",
264
265
  "aria-label": "Log line details",
265
266
  children: [
266
- /* @__PURE__ */ require_jsx_runtime.jsxs("header", { children: [/* @__PURE__ */ require_jsx_runtime.jsx("strong", { children: "Line details" }), /* @__PURE__ */ require_jsx_runtime.jsx("button", {
267
- className: "power-logs-detail-close",
268
- "aria-label": "Close line details",
267
+ /* @__PURE__ */ require_jsx_runtime.jsxs("header", { children: [/* @__PURE__ */ require_jsx_runtime.jsx("strong", { children: "Line details" }), /* @__PURE__ */ require_jsx_runtime.jsx(require_native_tooltip.NativeTooltip, {
269
268
  title: "Close line details",
270
- onClick: onClose,
271
- children: /* @__PURE__ */ require_jsx_runtime.jsx(Icon, {
272
- material: "close",
273
- size: 16
269
+ children: /* @__PURE__ */ require_jsx_runtime.jsx("button", {
270
+ className: "power-logs-detail-close",
271
+ "aria-label": "Close line details",
272
+ onClick: onClose,
273
+ children: /* @__PURE__ */ require_jsx_runtime.jsx(Icon, {
274
+ material: "close",
275
+ size: 16
276
+ })
274
277
  })
275
278
  })] }),
276
- /* @__PURE__ */ require_jsx_runtime.jsx("p", {
279
+ /* @__PURE__ */ require_jsx_runtime.jsxs("p", {
277
280
  className: "power-logs-muted",
278
- children: [record.pod && sourceKey(record), record.level.toUpperCase()].filter(Boolean).join(" · ")
281
+ children: [record.pod && /* @__PURE__ */ require_jsx_runtime.jsxs(require_jsx_runtime.Fragment, { children: [sourceKey(record), " · "] }), /* @__PURE__ */ require_jsx_runtime.jsx("span", {
282
+ className: "power-logs-level-label",
283
+ "data-level": record.level,
284
+ children: record.level.toUpperCase()
285
+ })]
279
286
  }),
280
287
  record.message && /* @__PURE__ */ require_jsx_runtime.jsx("pre", { children: /* @__PURE__ */ require_jsx_runtime.jsx(require_power_log_message.LogMessage, { text: record.message }) }),
281
288
  record.fieldsJson && /* @__PURE__ */ require_jsx_runtime.jsxs(require_jsx_runtime.Fragment, { children: [/* @__PURE__ */ require_jsx_runtime.jsxs("div", {
282
289
  className: "power-logs-structured-heading",
283
290
  children: [
284
291
  /* @__PURE__ */ require_jsx_runtime.jsx("strong", { children: jsonColumn ? `Structured fields · ${jsonColumn}` : "Structured fields" }),
285
- /* @__PURE__ */ require_jsx_runtime.jsx("button", {
286
- type: "button",
287
- className: "power-logs-detail-copy",
288
- "aria-label": "Copy structured JSON",
292
+ /* @__PURE__ */ require_jsx_runtime.jsx(require_native_tooltip.NativeTooltip, {
289
293
  title: copyFeedback || "Copy structured JSON",
290
- onClick: () => {
291
- try {
292
- electron.clipboard.writeText(structuredFields);
293
- setCopyFeedback("Copied");
294
- } catch {
295
- setCopyFeedback("Unable to copy JSON");
296
- }
297
- },
298
- children: /* @__PURE__ */ require_jsx_runtime.jsx(Icon, {
299
- material: copyFeedback === "Copied" ? "check" : "content_copy",
300
- size: 16
294
+ children: /* @__PURE__ */ require_jsx_runtime.jsx("button", {
295
+ type: "button",
296
+ className: "power-logs-detail-copy",
297
+ "aria-label": "Copy structured JSON",
298
+ onClick: () => {
299
+ try {
300
+ electron.clipboard.writeText(structuredFields);
301
+ setCopyFeedback("Copied");
302
+ } catch {
303
+ setCopyFeedback("Unable to copy JSON");
304
+ }
305
+ },
306
+ children: /* @__PURE__ */ require_jsx_runtime.jsx(Icon, {
307
+ material: copyFeedback === "Copied" ? "check" : "content_copy",
308
+ size: 16
309
+ })
301
310
  })
302
311
  }),
303
312
  /* @__PURE__ */ require_jsx_runtime.jsx("span", {
@@ -315,7 +324,7 @@ function LogDetails({ record, jsonColumn, onClose, onFilter }) {
315
324
  ]
316
325
  });
317
326
  }
318
- var sameFieldFilter = (a, b) => a.operator === b.operator && a.path.length === b.path.length && a.path.every((part, index) => part === b.path[index]) && require_power_log_field_filters.jsonValuesEqual(a.value, b.value);
327
+ var sameFieldValue = (a, b) => a.path.length === b.path.length && a.path.every((part, index) => part === b.path[index]) && require_power_log_field_filters.jsonValuesEqual(a.value, b.value);
319
328
  var fieldFilterLabel = (filter) => `${filter.path.reduce((path, part) => `${path}[${typeof part === "number" ? part : JSON.stringify(part)}]`, "$")} ${filter.operator === "eq" ? "=" : "!="} ${JSON.stringify(filter.value)}`;
320
329
  function FieldFilters({ filters, sql = false, disabled = false, onRemove }) {
321
330
  if (!filters.length) return null;
@@ -327,16 +336,18 @@ function FieldFilters({ filters, sql = false, disabled = false, onRemove }) {
327
336
  children: [sql ? "Result filters" : "JSON filters", " · AND"]
328
337
  }), filters.map((filter, index) => {
329
338
  const label = `${filter.column ? `${filter.column} ` : ""}${fieldFilterLabel(filter)}`;
330
- return /* @__PURE__ */ require_jsx_runtime.jsxs("button", {
331
- type: "button",
332
- disabled,
339
+ return /* @__PURE__ */ require_jsx_runtime.jsx(require_native_tooltip.NativeTooltip, {
333
340
  title: label,
334
- "aria-label": `Remove JSON filter ${label}`,
335
- onClick: () => onRemove(index),
336
- children: [/* @__PURE__ */ require_jsx_runtime.jsx("span", { children: label }), /* @__PURE__ */ require_jsx_runtime.jsx(Icon, {
337
- material: "close",
338
- size: 14
339
- })]
341
+ children: /* @__PURE__ */ require_jsx_runtime.jsxs("button", {
342
+ type: "button",
343
+ disabled,
344
+ "aria-label": `Remove JSON filter ${label}`,
345
+ onClick: () => onRemove(index),
346
+ children: [/* @__PURE__ */ require_jsx_runtime.jsx("span", { children: label }), /* @__PURE__ */ require_jsx_runtime.jsx(Icon, {
347
+ material: "close",
348
+ size: 14
349
+ })]
350
+ })
340
351
  }, index);
341
352
  })]
342
353
  });
@@ -361,6 +372,7 @@ function Workspace({ clusterId, contextId }) {
361
372
  const [text, setText] = require__global_external_react.useState("");
362
373
  const [level, setLevel] = require__global_external_react.useState("");
363
374
  const [source, setSource] = require__global_external_react.useState(initialSource);
375
+ const [savedPoolFull, setSavedPoolFull] = require__global_external_react.useState(false);
364
376
  const [fieldFilters, setFieldFilters] = require__global_external_react.useState([]);
365
377
  const matchFields = require__global_external_react.useMemo(() => require_power_log_field_filters.compileJsonFilters(fieldFilters), [fieldFilters]);
366
378
  const parsedFields = require__global_external_react.useRef(/* @__PURE__ */ new WeakMap());
@@ -396,6 +408,7 @@ function Workspace({ clusterId, contextId }) {
396
408
  const [capturePending, setCapturePending] = require__global_external_react.useState(false);
397
409
  const [captureMinutes, setCaptureMinutes] = require__global_external_react.useState(15);
398
410
  const [previous, setPrevious] = require__global_external_react.useState(false);
411
+ const [sqlFitVersion, setSqlFitVersion] = require__global_external_react.useState(0);
399
412
  const [sql, updateSql] = require__global_external_react.useState(examples[0][1]);
400
413
  const sqlDraft = require__global_external_react.useRef(sql);
401
414
  sqlDraft.current = sql;
@@ -750,6 +763,7 @@ function Workspace({ clusterId, contextId }) {
750
763
  if (title === "Recent") {
751
764
  const query = examples[0][1];
752
765
  setSql(query);
766
+ setSqlFitVersion((version) => version + 1);
753
767
  setSelectedSqlRow(void 0);
754
768
  if (execute && captured) runQuery(captured, query);
755
769
  return;
@@ -778,6 +792,7 @@ function Workspace({ clusterId, contextId }) {
778
792
  }
779
793
  prepared = require_power_log_json_preset.buildJsonProjectionSql(keys);
780
794
  setSql(prepared);
795
+ setSqlFitVersion((version) => version + 1);
781
796
  setSelectedSqlRow(void 0);
782
797
  } catch {
783
798
  if (alive.current) setSqlError("Could not detect JSON fields for this snapshot. Try the preset again.");
@@ -794,7 +809,11 @@ function Workspace({ clusterId, contextId }) {
794
809
  setError("This JSON value is too large or unsupported for filtering");
795
810
  return;
796
811
  }
797
- if (fieldFilters.some((current) => sameFieldFilter(current, filter))) return;
812
+ const existing = fieldFilters.findIndex((current) => sameFieldValue(current, filter));
813
+ if (existing >= 0) {
814
+ if (fieldFilters[existing].operator !== filter.operator) setFieldFilters(fieldFilters.map((current, index) => index === existing ? filter : current));
815
+ return;
816
+ }
798
817
  if (fieldFilters.length >= 32) {
799
818
  setError("Up to 32 JSON filters can be combined");
800
819
  return;
@@ -831,7 +850,14 @@ function Workspace({ clusterId, contextId }) {
831
850
  return;
832
851
  }
833
852
  const filters = activeSqlFilters?.filters ?? [];
834
- if (filters.some((current) => current.column === column && sameFieldFilter(current, filter))) return;
853
+ const existing = filters.findIndex((current) => current.column === column && sameFieldValue(current, filter));
854
+ if (existing >= 0) {
855
+ if (filters[existing].operator !== filter.operator) applySqlFilters(filters.map((current, index) => index === existing ? {
856
+ ...filter,
857
+ column
858
+ } : current));
859
+ return;
860
+ }
835
861
  if (filters.length >= 32) {
836
862
  setSqlError("Up to 32 JSON filters can be combined");
837
863
  return;
@@ -948,6 +974,82 @@ function Workspace({ clusterId, contextId }) {
948
974
  if (alive.current) setDeletingCount(deleting.current.size);
949
975
  }
950
976
  };
977
+ const confirmDeleteCapture = (id) => {
978
+ const capture = captures.find((capture) => capture.id === id);
979
+ if (!capture) return;
980
+ require_extensions.Renderer.Component.ConfirmDialog.open({
981
+ message: /* @__PURE__ */ require_jsx_runtime.jsxs(require_jsx_runtime.Fragment, { children: [
982
+ "Delete snapshot ",
983
+ /* @__PURE__ */ require_jsx_runtime.jsx("strong", { children: capture.target.name }),
984
+ "? This cannot be undone."
985
+ ] }),
986
+ labelOk: "Delete snapshot",
987
+ ok: () => deleteCapture(id)
988
+ });
989
+ };
990
+ const confirmPersistentCapture = (capture) => {
991
+ const persistent = !capture.persistent;
992
+ require_extensions.Renderer.Component.ConfirmDialog.open({
993
+ message: persistent ? /* @__PURE__ */ require_jsx_runtime.jsxs(require_jsx_runtime.Fragment, { children: [
994
+ "Keep snapshot ",
995
+ /* @__PURE__ */ require_jsx_runtime.jsx("strong", { children: capture.target.name }),
996
+ " until you delete it? It will survive restarts and will not expire automatically."
997
+ ] }) : /* @__PURE__ */ require_jsx_runtime.jsxs(require_jsx_runtime.Fragment, { children: [
998
+ "Allow snapshot ",
999
+ /* @__PURE__ */ require_jsx_runtime.jsx("strong", { children: capture.target.name }),
1000
+ " to expire? Its retention period will start again now."
1001
+ ] }),
1002
+ labelOk: persistent ? "Keep snapshot" : "Allow expiration",
1003
+ ok: async () => {
1004
+ if (!alive.current || deleting.current.has(capture.id) || queryRef.current || captureController.current) return;
1005
+ deleting.current.add(capture.id);
1006
+ setDeletingCount(deleting.current.size);
1007
+ try {
1008
+ await drafts.flush();
1009
+ await client.setPersistent(capture.id, persistent);
1010
+ await refreshCaptures();
1011
+ } catch (error) {
1012
+ if (alive.current) {
1013
+ const full = error instanceof Error && error.message.includes("Saved snapshot limit reached");
1014
+ setSavedPoolFull(full);
1015
+ setError(full ? "Saved snapshot limit reached. Delete a saved snapshot or clear saved snapshots from all clusters." : "Could not update snapshot retention");
1016
+ }
1017
+ } finally {
1018
+ deleting.current.delete(capture.id);
1019
+ if (alive.current) setDeletingCount(deleting.current.size);
1020
+ }
1021
+ }
1022
+ });
1023
+ };
1024
+ const clearSavedSnapshots = () => require_extensions.Renderer.Component.ConfirmDialog.open({
1025
+ message: "Delete all saved snapshots from all clusters? Temporary snapshots will be kept. This cannot be undone.",
1026
+ labelOk: "Clear saved snapshots",
1027
+ ok: async () => {
1028
+ if (queryRef.current || captureController.current || deleting.current.size) return;
1029
+ deleting.current.add("clear-saved");
1030
+ setDeletingCount(deleting.current.size);
1031
+ try {
1032
+ await drafts.flush();
1033
+ await client.clearPersistent();
1034
+ const removed = captures.filter((capture) => capture.persistent);
1035
+ for (const capture of removed) drafts.forget(capture.id);
1036
+ if (removed.some((capture) => capture.id === captureSelection.current)) {
1037
+ setCaptureId("");
1038
+ setResult(void 0);
1039
+ setResultEvidence(void 0);
1040
+ setSelectedSqlRow(void 0);
1041
+ }
1042
+ setSavedPoolFull(false);
1043
+ setError("");
1044
+ await refreshCaptures();
1045
+ } catch {
1046
+ if (alive.current) setError("Could not clear saved snapshots");
1047
+ } finally {
1048
+ deleting.current.delete("clear-saved");
1049
+ if (alive.current) setDeletingCount(deleting.current.size);
1050
+ }
1051
+ }
1052
+ });
951
1053
  const native = () => {
952
1054
  const first = sources[0];
953
1055
  const pod = require_extensions.Renderer.K8sApi.podsStore.getItems().find((item) => target?.kind === "Pod" ? item.metadata.uid === target.uid : item.metadata.uid === first?.podUid);
@@ -1023,12 +1125,12 @@ function Workspace({ clusterId, contextId }) {
1023
1125
  /* @__PURE__ */ require_jsx_runtime.jsxs("details", {
1024
1126
  ref: captureOptions,
1025
1127
  className: "power-logs-options",
1026
- children: [/* @__PURE__ */ require_jsx_runtime.jsxs("summary", {
1128
+ children: [/* @__PURE__ */ require_jsx_runtime.jsx(require_native_tooltip.NativeTooltip, {
1027
1129
  title: `Capture window: ${captureMinutes} minutes`,
1028
- children: [/* @__PURE__ */ require_jsx_runtime.jsx(Icon, {
1130
+ children: /* @__PURE__ */ require_jsx_runtime.jsxs("summary", { children: [/* @__PURE__ */ require_jsx_runtime.jsx(Icon, {
1029
1131
  material: "tune",
1030
1132
  size: 16
1031
- }), " Options"]
1133
+ }), " Options"] })
1032
1134
  }), /* @__PURE__ */ require_jsx_runtime.jsxs("div", { children: [
1033
1135
  " ",
1034
1136
  /* @__PURE__ */ require_jsx_runtime.jsxs("label", { children: ["Capture window", /* @__PURE__ */ require_jsx_runtime.jsx(LogSelect, {
@@ -1114,39 +1216,46 @@ function Workspace({ clusterId, contextId }) {
1114
1216
  size: 16
1115
1217
  }), " Refresh"]
1116
1218
  }),
1117
- target?.kind === "Pod" && /* @__PURE__ */ require_jsx_runtime.jsx("button", {
1118
- type: "button",
1119
- "aria-label": "Native logs",
1219
+ target?.kind === "Pod" && /* @__PURE__ */ require_jsx_runtime.jsx(require_native_tooltip.NativeTooltip, {
1120
1220
  title: "Native logs",
1121
- onClick: native,
1122
- children: /* @__PURE__ */ require_jsx_runtime.jsx(require_extensions.Renderer.Component.Icon, {
1123
- material: "open_in_new",
1124
- size: 16,
1125
- tooltip: "Native logs",
1126
- tooltipOverrideDisabled: true
1221
+ children: /* @__PURE__ */ require_jsx_runtime.jsx("button", {
1222
+ type: "button",
1223
+ "aria-label": "Native logs",
1224
+ onClick: native,
1225
+ children: /* @__PURE__ */ require_jsx_runtime.jsx(require_extensions.Renderer.Component.Icon, {
1226
+ material: "open_in_new",
1227
+ size: 16
1228
+ })
1127
1229
  })
1128
1230
  })
1129
1231
  ]
1130
1232
  })
1131
1233
  ] }),
1132
- target ? /* @__PURE__ */ require_jsx_runtime.jsxs("div", {
1133
- className: "power-logs-target power-logs-muted",
1234
+ target ? /* @__PURE__ */ require_jsx_runtime.jsx(require_native_tooltip.NativeTooltip, {
1134
1235
  title: `${target.kind} / ${target.name} · ${target.namespace} · UID ${target.uid}`,
1135
- children: [
1136
- /* @__PURE__ */ require_jsx_runtime.jsxs("strong", { children: [
1137
- target.kind,
1138
- " / ",
1139
- target.name
1140
- ] }),
1141
- " ",
1142
- "· ",
1143
- target.namespace
1144
- ]
1236
+ children: /* @__PURE__ */ require_jsx_runtime.jsxs("div", {
1237
+ className: "power-logs-target power-logs-muted",
1238
+ children: [
1239
+ /* @__PURE__ */ require_jsx_runtime.jsxs("strong", { children: [
1240
+ target.kind,
1241
+ " / ",
1242
+ target.name
1243
+ ] }),
1244
+ " ",
1245
+ "· ",
1246
+ target.namespace
1247
+ ]
1248
+ })
1145
1249
  }) : /* @__PURE__ */ require_jsx_runtime.jsx(SourcePicker, {}),
1146
- error && /* @__PURE__ */ require_jsx_runtime.jsx("div", {
1250
+ error && /* @__PURE__ */ require_jsx_runtime.jsxs("div", {
1147
1251
  role: "alert",
1148
1252
  className: "power-logs-notice power-logs-error",
1149
- children: error
1253
+ children: [error, savedPoolFull && /* @__PURE__ */ require_jsx_runtime.jsx("button", {
1254
+ type: "button",
1255
+ disabled: deletingCount > 0 || !!queryId || capturePending,
1256
+ onClick: clearSavedSnapshots,
1257
+ children: "Clear saved snapshots"
1258
+ })]
1150
1259
  }),
1151
1260
  tab === "live" ? /* @__PURE__ */ require_jsx_runtime.jsxs(require_jsx_runtime.Fragment, { children: [
1152
1261
  /* @__PURE__ */ require_jsx_runtime.jsxs("div", {
@@ -1174,32 +1283,34 @@ function Workspace({ clusterId, contextId }) {
1174
1283
  /* @__PURE__ */ require_jsx_runtime.jsx(LogSelect, {
1175
1284
  label: "Container source",
1176
1285
  renderOption: (option, context) => {
1177
- if (context !== "menu") return /* @__PURE__ */ require_jsx_runtime.jsx("span", {
1286
+ if (context !== "menu") return /* @__PURE__ */ require_jsx_runtime.jsx(require_native_tooltip.NativeTooltip, {
1178
1287
  title: option.label,
1179
- children: option.label
1288
+ children: /* @__PURE__ */ require_jsx_runtime.jsx("span", { children: option.label })
1180
1289
  });
1181
1290
  const item = sources.find((item) => sourceKey(item) === option.value);
1182
- return /* @__PURE__ */ require_jsx_runtime.jsxs("span", {
1183
- className: "power-logs-source-option",
1291
+ return /* @__PURE__ */ require_jsx_runtime.jsx(require_native_tooltip.NativeTooltip, {
1184
1292
  title: option.label,
1185
- children: [
1186
- /* @__PURE__ */ require_jsx_runtime.jsx(Icon, {
1187
- material: item ? "view_in_ar" : "layers",
1188
- size: 16
1189
- }),
1190
- /* @__PURE__ */ require_jsx_runtime.jsxs("span", {
1191
- className: "power-logs-option-text",
1192
- children: [/* @__PURE__ */ require_jsx_runtime.jsx("strong", { children: item ? item.pod : option.value ? "All pods" : option.label }), /* @__PURE__ */ require_jsx_runtime.jsxs("small", { children: [option.value ? `Container · ${item?.container ?? option.value.slice(10)}` : "Every pod and container", item?.previous ? " · Previous" : ""] })]
1193
- }),
1194
- /* @__PURE__ */ require_jsx_runtime.jsx("span", {
1195
- className: "power-logs-source-check",
1196
- "aria-hidden": "true",
1197
- children: source === option.value && /* @__PURE__ */ require_jsx_runtime.jsx(Icon, {
1198
- material: "check",
1293
+ children: /* @__PURE__ */ require_jsx_runtime.jsxs("span", {
1294
+ className: "power-logs-source-option",
1295
+ children: [
1296
+ /* @__PURE__ */ require_jsx_runtime.jsx(Icon, {
1297
+ material: item ? "view_in_ar" : "layers",
1199
1298
  size: 16
1299
+ }),
1300
+ /* @__PURE__ */ require_jsx_runtime.jsxs("span", {
1301
+ className: "power-logs-option-text",
1302
+ children: [/* @__PURE__ */ require_jsx_runtime.jsx("strong", { children: item ? item.pod : option.value ? "All pods" : option.label }), /* @__PURE__ */ require_jsx_runtime.jsxs("small", { children: [option.value ? `Container · ${item?.container ?? option.value.slice(10)}` : "Every pod and container", item?.previous ? " · Previous" : ""] })]
1303
+ }),
1304
+ /* @__PURE__ */ require_jsx_runtime.jsx("span", {
1305
+ className: "power-logs-source-check",
1306
+ "aria-hidden": "true",
1307
+ children: source === option.value && /* @__PURE__ */ require_jsx_runtime.jsx(Icon, {
1308
+ material: "check",
1309
+ size: 16
1310
+ })
1200
1311
  })
1201
- })
1202
- ]
1312
+ ]
1313
+ })
1203
1314
  });
1204
1315
  },
1205
1316
  value: source,
@@ -1256,21 +1367,23 @@ function Workspace({ clusterId, contextId }) {
1256
1367
  filters: fieldFilters,
1257
1368
  onRemove: (index) => setFieldFilters(fieldFilters.filter((_, item) => item !== index))
1258
1369
  }),
1259
- /* @__PURE__ */ require_jsx_runtime.jsxs("div", {
1260
- className: "power-logs-muted power-logs-status",
1261
- role: "status",
1370
+ /* @__PURE__ */ require_jsx_runtime.jsx(require_native_tooltip.NativeTooltip, {
1262
1371
  title: `${status} · Viewer retains up to ${limits.liveRows.toLocaleString()} lines / ${limits.liveBytes / 1048576} MiB`,
1263
- children: [
1264
- /* @__PURE__ */ require_jsx_runtime.jsxs("span", { children: [filtered.length.toLocaleString(), " matching lines"] }),
1265
- " · ",
1266
- status,
1267
- liveCoverage && live ? ` · ${liveCoverage.active}/${liveCoverage.total} active sources` : "",
1268
- " · Viewer retains up to ",
1269
- limits.liveRows.toLocaleString(),
1270
- " lines / ",
1271
- limits.liveBytes / 1048576,
1272
- " MiB"
1273
- ]
1372
+ children: /* @__PURE__ */ require_jsx_runtime.jsxs("div", {
1373
+ className: "power-logs-muted power-logs-status",
1374
+ role: "status",
1375
+ children: [
1376
+ /* @__PURE__ */ require_jsx_runtime.jsxs("span", { children: [filtered.length.toLocaleString(), " matching lines"] }),
1377
+ " · ",
1378
+ status,
1379
+ liveCoverage && live ? ` · ${liveCoverage.active}/${liveCoverage.total} active sources` : "",
1380
+ " · Viewer retains up to ",
1381
+ limits.liveRows.toLocaleString(),
1382
+ " lines / ",
1383
+ limits.liveBytes / 1048576,
1384
+ " MiB"
1385
+ ]
1386
+ })
1274
1387
  }),
1275
1388
  /* @__PURE__ */ require_jsx_runtime.jsxs("div", {
1276
1389
  className: "power-logs-workspace",
@@ -1304,7 +1417,7 @@ function Workspace({ clusterId, contextId }) {
1304
1417
  if (button && !button.disabled) {
1305
1418
  event.preventDefault();
1306
1419
  event.stopPropagation();
1307
- deleteCapture(button.dataset.captureDelete);
1420
+ confirmDeleteCapture(button.dataset.captureDelete);
1308
1421
  }
1309
1422
  },
1310
1423
  renderOption: (option, context) => {
@@ -1312,41 +1425,71 @@ function Workspace({ clusterId, contextId }) {
1312
1425
  if (context !== "menu" || !item) return option.label;
1313
1426
  return /* @__PURE__ */ require_jsx_runtime.jsxs("span", {
1314
1427
  className: "power-logs-snapshot-option",
1315
- title: option.label,
1316
- children: [/* @__PURE__ */ require_jsx_runtime.jsxs("span", {
1317
- className: "power-logs-option-text",
1318
- children: [/* @__PURE__ */ require_jsx_runtime.jsx("strong", { children: item.target.name }), /* @__PURE__ */ require_jsx_runtime.jsxs("small", { children: [
1319
- require_date_time.formatDateTime(item.createdAt),
1320
- " · ",
1321
- item.rows.toLocaleString(),
1322
- " lines ·",
1323
- " ",
1324
- item.state[0].toUpperCase(),
1325
- item.state.slice(1)
1326
- ] })]
1327
- }), /* @__PURE__ */ require_jsx_runtime.jsx("button", {
1328
- type: "button",
1329
- "aria-label": `Delete snapshot ${item.target.name}`,
1330
- title: "Delete snapshot (Alt+Delete)",
1331
- "data-capture-delete": item.id,
1332
- onKeyDown: (event) => event.stopPropagation(),
1333
- disabled: !!queryId || capturePending || deletingCount > 0 || item.state === "collecting",
1334
- onMouseDown: (event) => {
1335
- event.preventDefault();
1336
- event.stopPropagation();
1337
- },
1338
- onClick: (event) => {
1339
- event.preventDefault();
1340
- event.stopPropagation();
1341
- deleteCapture(item.id);
1342
- },
1343
- children: /* @__PURE__ */ require_jsx_runtime.jsx(require_extensions.Renderer.Component.Icon, {
1344
- material: "delete_outline",
1345
- size: 16,
1346
- tooltip: "Delete snapshot",
1347
- tooltipOverrideDisabled: true
1428
+ children: [
1429
+ /* @__PURE__ */ require_jsx_runtime.jsx(require_native_tooltip.NativeTooltip, {
1430
+ title: option.label,
1431
+ children: /* @__PURE__ */ require_jsx_runtime.jsxs("span", {
1432
+ className: "power-logs-option-text",
1433
+ children: [/* @__PURE__ */ require_jsx_runtime.jsx("strong", { children: item.target.name }), /* @__PURE__ */ require_jsx_runtime.jsxs("small", { children: [
1434
+ require_date_time.formatDateTime(item.createdAt),
1435
+ " · ",
1436
+ item.rows.toLocaleString(),
1437
+ " lines ·",
1438
+ " ",
1439
+ item.state[0].toUpperCase(),
1440
+ item.state.slice(1),
1441
+ item.persistent ? " · Persistent" : ""
1442
+ ] })]
1443
+ })
1444
+ }),
1445
+ /* @__PURE__ */ require_jsx_runtime.jsx(require_native_tooltip.NativeTooltip, {
1446
+ title: item.persistent ? "Allow snapshot to expire" : "Keep snapshot",
1447
+ children: /* @__PURE__ */ require_jsx_runtime.jsx("button", {
1448
+ type: "button",
1449
+ "aria-label": `${item.persistent ? "Allow expiration for" : "Keep"} snapshot ${item.target.name}`,
1450
+ "aria-pressed": Boolean(item.persistent),
1451
+ "data-capture-persistent": item.id,
1452
+ onKeyDown: (event) => event.stopPropagation(),
1453
+ disabled: !!queryId || capturePending || deletingCount > 0 || item.state === "collecting",
1454
+ onMouseDown: (event) => {
1455
+ event.preventDefault();
1456
+ event.stopPropagation();
1457
+ },
1458
+ onClick: (event) => {
1459
+ event.preventDefault();
1460
+ event.stopPropagation();
1461
+ confirmPersistentCapture(item);
1462
+ },
1463
+ children: /* @__PURE__ */ require_jsx_runtime.jsx(require_extensions.Renderer.Component.Icon, {
1464
+ material: "push_pin",
1465
+ size: 16
1466
+ })
1467
+ })
1468
+ }),
1469
+ /* @__PURE__ */ require_jsx_runtime.jsx(require_native_tooltip.NativeTooltip, {
1470
+ title: "Delete snapshot (Alt+Delete)",
1471
+ children: /* @__PURE__ */ require_jsx_runtime.jsx("button", {
1472
+ type: "button",
1473
+ "aria-label": `Delete snapshot ${item.target.name}`,
1474
+ "data-capture-delete": item.id,
1475
+ onKeyDown: (event) => event.stopPropagation(),
1476
+ disabled: !!queryId || capturePending || deletingCount > 0 || item.state === "collecting",
1477
+ onMouseDown: (event) => {
1478
+ event.preventDefault();
1479
+ event.stopPropagation();
1480
+ },
1481
+ onClick: (event) => {
1482
+ event.preventDefault();
1483
+ event.stopPropagation();
1484
+ confirmDeleteCapture(item.id);
1485
+ },
1486
+ children: /* @__PURE__ */ require_jsx_runtime.jsx(require_extensions.Renderer.Component.Icon, {
1487
+ material: "delete_outline",
1488
+ size: 16
1489
+ })
1490
+ })
1348
1491
  })
1349
- })]
1492
+ ]
1350
1493
  });
1351
1494
  },
1352
1495
  value: captureId,
@@ -1363,39 +1506,35 @@ function Workspace({ clusterId, contextId }) {
1363
1506
  label: "Choose a snapshot"
1364
1507
  }, ...captures.map((item) => ({
1365
1508
  value: item.id,
1366
- label: `${item.target.name} · ${require_date_time.formatDateTime(item.createdAt)} · ${item.rows.toLocaleString()} lines · ${item.state[0].toUpperCase()}${item.state.slice(1)}`
1509
+ label: `${item.target.name} · ${require_date_time.formatDateTime(item.createdAt)} · ${item.rows.toLocaleString()} lines · ${item.state[0].toUpperCase()}${item.state.slice(1)}${item.persistent ? " · Persistent" : ""}`
1367
1510
  }))]
1368
1511
  }),
1369
- /* @__PURE__ */ require_jsx_runtime.jsxs("button", {
1370
- type: "button",
1371
- disabled: !captureId || !!queryId || deleting.current.has(captureId),
1512
+ /* @__PURE__ */ require_jsx_runtime.jsx(require_native_tooltip.NativeTooltip, {
1372
1513
  title: "Export JSON Lines (NDJSON)",
1373
- onClick: () => {
1374
- client.export(captureId).catch(() => setError("Could not export capture"));
1375
- },
1376
- children: [/* @__PURE__ */ require_jsx_runtime.jsx(Icon, {
1377
- material: "download",
1378
- size: 16
1379
- }), " Export JSON"]
1514
+ children: /* @__PURE__ */ require_jsx_runtime.jsxs("button", {
1515
+ type: "button",
1516
+ disabled: !captureId || !!queryId || deleting.current.has(captureId),
1517
+ onClick: () => {
1518
+ client.export(captureId).catch(() => setError("Could not export capture"));
1519
+ },
1520
+ children: [/* @__PURE__ */ require_jsx_runtime.jsx(Icon, {
1521
+ material: "download",
1522
+ size: 16
1523
+ }), " Export JSON"]
1524
+ })
1380
1525
  })
1381
1526
  ]
1382
1527
  }),
1383
- !!chosenCapture?.notes.length && /* @__PURE__ */ require_jsx_runtime.jsxs("details", {
1384
- className: "power-logs-snapshot-notes power-logs-muted",
1385
- children: [/* @__PURE__ */ require_jsx_runtime.jsxs("summary", { children: [
1386
- "Snapshot notes (",
1387
- chosenCapture.notes.length,
1388
- ")"
1389
- ] }), chosenCapture.notes.map((note) => /* @__PURE__ */ require_jsx_runtime.jsx("div", { children: note }, note))]
1390
- }),
1391
1528
  /* @__PURE__ */ require_jsx_runtime.jsxs("div", {
1392
1529
  className: "power-logs-toolbar power-logs-sql-tools",
1393
1530
  children: [
1394
- /* @__PURE__ */ require_jsx_runtime.jsx("label", {
1395
- htmlFor: "power-logs-sql",
1396
- className: "power-logs-control-label",
1531
+ /* @__PURE__ */ require_jsx_runtime.jsx(require_native_tooltip.NativeTooltip, {
1397
1532
  title: `Read-only SELECT · ${limits.queryMs / 1e3} s · ${limits.resultRows.toLocaleString()} rows · Schema: logs(timestamp INTEGER in milliseconds, pod, podUid, container, level, message, fieldsJson, previous INTEGER 0 or 1)`,
1398
- children: "SQL query"
1533
+ children: /* @__PURE__ */ require_jsx_runtime.jsx("label", {
1534
+ htmlFor: "power-logs-sql",
1535
+ className: "power-logs-control-label",
1536
+ children: "SQL query"
1537
+ })
1399
1538
  }),
1400
1539
  /* @__PURE__ */ require_jsx_runtime.jsxs("button", {
1401
1540
  type: "button",
@@ -1419,7 +1558,13 @@ function Workspace({ clusterId, contextId }) {
1419
1558
  examples.map(([title, query]) => /* @__PURE__ */ require_jsx_runtime.jsxs("button", {
1420
1559
  type: "button",
1421
1560
  disabled: !!queryId || capturePending,
1422
- onClick: () => title === "JSON" || title === "Recent" ? void applyPreset(title) : setSql(query),
1561
+ onClick: () => {
1562
+ if (title === "JSON" || title === "Recent") applyPreset(title);
1563
+ else {
1564
+ setSql(query);
1565
+ setSqlFitVersion((version) => version + 1);
1566
+ }
1567
+ },
1423
1568
  children: [
1424
1569
  /* @__PURE__ */ require_jsx_runtime.jsx(Icon, {
1425
1570
  material: title === "Recent" ? "history" : title === "Errors" ? "error_outline" : title === "Timeline" ? "timeline" : "data_object",
@@ -1441,7 +1586,8 @@ function Workspace({ clusterId, contextId }) {
1441
1586
  /* @__PURE__ */ require_jsx_runtime.jsx(require_power_log_sql_editor.SqlEditor, {
1442
1587
  id: "power-logs-sql",
1443
1588
  value: sql,
1444
- onChange: setSql
1589
+ onChange: setSql,
1590
+ fitVersion: sqlFitVersion
1445
1591
  }),
1446
1592
  sqlError && /* @__PURE__ */ require_jsx_runtime.jsx("div", {
1447
1593
  role: "alert",
@@ -1498,8 +1644,7 @@ function Workspace({ clusterId, contextId }) {
1498
1644
  value: cell === null ? null : String(cell),
1499
1645
  column: result.columns[j],
1500
1646
  rawValue: cell,
1501
- Icon,
1502
- onFilter: sqlFilteringDisabled ? void 0 : (filter) => addSqlFilter(result.columns[j], filter)
1647
+ Icon
1503
1648
  })
1504
1649
  }, j))
1505
1650
  }, i)) })
@@ -1519,18 +1664,20 @@ function Workspace({ clusterId, contextId }) {
1519
1664
  className: "power-logs-toolbar power-logs-pagination",
1520
1665
  "aria-label": "SQL result pages",
1521
1666
  children: [
1522
- /* @__PURE__ */ require_jsx_runtime.jsx("button", {
1523
- type: "button",
1524
- "aria-label": "Previous page",
1667
+ /* @__PURE__ */ require_jsx_runtime.jsx(require_native_tooltip.NativeTooltip, {
1525
1668
  title: "Previous page",
1526
- disabled: resultPage === 0,
1527
- onClick: () => {
1528
- setResultPage(resultPage - 1);
1529
- setSelectedSqlRow(void 0);
1530
- },
1531
- children: /* @__PURE__ */ require_jsx_runtime.jsx(Icon, {
1532
- material: "chevron_left",
1533
- size: 16
1669
+ children: /* @__PURE__ */ require_jsx_runtime.jsx("button", {
1670
+ type: "button",
1671
+ "aria-label": "Previous page",
1672
+ disabled: resultPage === 0,
1673
+ onClick: () => {
1674
+ setResultPage(resultPage - 1);
1675
+ setSelectedSqlRow(void 0);
1676
+ },
1677
+ children: /* @__PURE__ */ require_jsx_runtime.jsx(Icon, {
1678
+ material: "chevron_left",
1679
+ size: 16
1680
+ })
1534
1681
  })
1535
1682
  }),
1536
1683
  /* @__PURE__ */ require_jsx_runtime.jsxs("span", {
@@ -1542,18 +1689,20 @@ function Workspace({ clusterId, contextId }) {
1542
1689
  Math.max(1, Math.ceil(result.rows.length / 50))
1543
1690
  ]
1544
1691
  }),
1545
- /* @__PURE__ */ require_jsx_runtime.jsx("button", {
1546
- type: "button",
1547
- "aria-label": "Next page",
1692
+ /* @__PURE__ */ require_jsx_runtime.jsx(require_native_tooltip.NativeTooltip, {
1548
1693
  title: "Next page",
1549
- disabled: (resultPage + 1) * 50 >= result.rows.length,
1550
- onClick: () => {
1551
- setResultPage(resultPage + 1);
1552
- setSelectedSqlRow(void 0);
1553
- },
1554
- children: /* @__PURE__ */ require_jsx_runtime.jsx(Icon, {
1555
- material: "chevron_right",
1556
- size: 16
1694
+ children: /* @__PURE__ */ require_jsx_runtime.jsx("button", {
1695
+ type: "button",
1696
+ "aria-label": "Next page",
1697
+ disabled: (resultPage + 1) * 50 >= result.rows.length,
1698
+ onClick: () => {
1699
+ setResultPage(resultPage + 1);
1700
+ setSelectedSqlRow(void 0);
1701
+ },
1702
+ children: /* @__PURE__ */ require_jsx_runtime.jsx(Icon, {
1703
+ material: "chevron_right",
1704
+ size: 16
1705
+ })
1557
1706
  })
1558
1707
  })
1559
1708
  ]
@@ -1565,35 +1714,48 @@ function Workspace({ clusterId, contextId }) {
1565
1714
  ] }),
1566
1715
  /* @__PURE__ */ require_jsx_runtime.jsxs("div", {
1567
1716
  className: "power-logs-muted power-logs-footer",
1568
- children: [/* @__PURE__ */ require_jsx_runtime.jsxs("span", {
1569
- className: "power-logs-caption",
1570
- title: `Gentle collection: ${limits.requestsPerSecond} requests/s, ${limits.bytesPerSecond / 1048576} MiB/s. Captures: ${limits.captureSourceLines.toLocaleString()} lines / ${limits.captureSourceBytes / 1048576} MiB per source, ${limits.captureBytes / 1048576} MiB total. Up to ${limits.captures} snapshots retained for ${limits.ttlMs / 6e4} minutes.`,
1571
- children: [
1572
- "Gentle collection · ",
1573
- limits.requestsPerSecond,
1574
- " requests/s · ",
1575
- limits.bytesPerSecond / 1048576,
1576
- " MiB/s · Captures limited to ",
1577
- limits.captureSourceLines.toLocaleString(),
1578
- " lines / ",
1579
- limits.captureSourceBytes / 1048576,
1580
- " MiB per source and ",
1581
- limits.captureBytes / 1048576,
1582
- " MiB total · Up to ",
1583
- limits.captures,
1584
- " temporary snapshots, retained for ",
1585
- limits.ttlMs / 6e4,
1586
- " min"
1587
- ]
1588
- }), collectionNotes.length > 0 && /* @__PURE__ */ require_jsx_runtime.jsxs("span", {
1589
- role: "note",
1590
- className: "power-logs-notice power-logs-collection-note",
1591
- title: collectionNotes.join("\n"),
1592
- children: [/* @__PURE__ */ require_jsx_runtime.jsx(Icon, {
1593
- material: "warning_amber",
1594
- size: 14
1595
- }), /* @__PURE__ */ require_jsx_runtime.jsx("span", { children: collectionNotes.join(" · ") })]
1596
- })]
1717
+ children: [
1718
+ /* @__PURE__ */ require_jsx_runtime.jsx(require_native_tooltip.NativeTooltip, {
1719
+ title: `Gentle collection: ${limits.requestsPerSecond} requests/s, ${limits.bytesPerSecond / 1048576} MiB/s. Captures: ${limits.captureSourceLines.toLocaleString()} lines / ${limits.captureSourceBytes / 1048576} MiB per source, ${limits.captureBytes / 1048576} MiB total. Up to ${limits.captures} snapshots retained for ${limits.ttlMs / 6e4} minutes.`,
1720
+ children: /* @__PURE__ */ require_jsx_runtime.jsxs("span", {
1721
+ className: "power-logs-caption",
1722
+ children: [
1723
+ "Collection · ",
1724
+ limits.requestsPerSecond,
1725
+ " req/s · ",
1726
+ limits.bytesPerSecond / 1048576,
1727
+ " MiB/s ·",
1728
+ " ",
1729
+ limits.captureBytes / 1048576,
1730
+ " MiB/snapshot · Retention ",
1731
+ limits.ttlMs / 6e4,
1732
+ " min"
1733
+ ]
1734
+ })
1735
+ }),
1736
+ tab === "live" && collectionNotes.length > 0 && /* @__PURE__ */ require_jsx_runtime.jsx(require_native_tooltip.NativeTooltip, {
1737
+ title: collectionNotes.join("\n"),
1738
+ children: /* @__PURE__ */ require_jsx_runtime.jsxs("span", {
1739
+ role: "note",
1740
+ className: "power-logs-notice power-logs-collection-note",
1741
+ children: [/* @__PURE__ */ require_jsx_runtime.jsx(Icon, {
1742
+ material: "warning_amber",
1743
+ size: 14
1744
+ }), /* @__PURE__ */ require_jsx_runtime.jsx("span", { children: collectionNotes.join(" · ") })]
1745
+ })
1746
+ }),
1747
+ tab === "captures" && chosenCapture && (chosenCapture.state === "partial" || chosenCapture.notes.length > 0) && /* @__PURE__ */ require_jsx_runtime.jsx(require_native_tooltip.NativeTooltip, {
1748
+ title: chosenCapture.notes.join("\n") || "Collection stopped or a source was unavailable; this snapshot may be incomplete",
1749
+ children: /* @__PURE__ */ require_jsx_runtime.jsxs("span", {
1750
+ role: "note",
1751
+ className: "power-logs-notice power-logs-collection-note",
1752
+ children: [/* @__PURE__ */ require_jsx_runtime.jsx(Icon, {
1753
+ material: "warning_amber",
1754
+ size: 14
1755
+ }), /* @__PURE__ */ require_jsx_runtime.jsx("span", { children: "Incomplete snapshot" })]
1756
+ })
1757
+ })
1758
+ ]
1597
1759
  })
1598
1760
  ]
1599
1761
  });