@64mb/freelens-power 1.6.0 → 2.0.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 +1 -1
- package/out/main/common/resource-search-kind-priority.js +23 -0
- package/out/main/common/resource-search-kind-priority.js.map +1 -0
- package/out/main/power-logs-query.js +1 -0
- package/out/main/power-logs-query.js.map +1 -1
- package/out/main/resource-search-database.js +7 -2
- package/out/main/resource-search-database.js.map +1 -1
- package/out/main/resource-search-worker.js +6 -2
- package/out/main/resource-search-worker.js.map +1 -1
- package/out/renderer/_virtual/_global-external_react.js +2 -1
- package/out/renderer/power-log-json-cell.js +74 -0
- package/out/renderer/power-log-json-cell.js.map +1 -0
- package/out/renderer/power-log-json-fields.js +144 -0
- package/out/renderer/power-log-json-fields.js.map +1 -0
- package/out/renderer/power-log-json.js +139 -20
- package/out/renderer/power-log-json.js.map +1 -1
- package/out/renderer/power-log-message-tokens.js +60 -0
- package/out/renderer/power-log-message-tokens.js.map +1 -0
- package/out/renderer/power-log-message.js +26 -0
- package/out/renderer/power-log-message.js.map +1 -0
- package/out/renderer/power-logs-sql-row.js +2 -2
- package/out/renderer/power-logs-sql-row.js.map +1 -1
- package/out/renderer/power-logs.css.js +36 -6
- package/out/renderer/power-logs.css.js.map +1 -1
- package/out/renderer/power-logs.js +249 -28
- package/out/renderer/power-logs.js.map +1 -1
- package/out/renderer/preferences/logs-preferences.js +159 -38
- package/out/renderer/preferences/logs-preferences.js.map +1 -1
- package/out/renderer/resource-search-model.js +2 -1
- package/out/renderer/resource-search-model.js.map +1 -1
- package/out/renderer/resource-search-sync.js +1 -1
- package/out/renderer/resource-search-sync.js.map +1 -1
- package/out/renderer/resource-search.js +84 -81
- package/out/renderer/resource-search.js.map +1 -1
- package/out/renderer/src/common/power-log-field-filters.js +92 -0
- package/out/renderer/src/common/power-log-field-filters.js.map +1 -0
- package/out/renderer/src/common/power-log-json-filter-sql.js +106 -0
- package/out/renderer/src/common/power-log-json-filter-sql.js.map +1 -0
- package/out/renderer/src/common/power-log-json-preset.js +36 -0
- package/out/renderer/src/common/power-log-json-preset.js.map +1 -0
- package/out/renderer/src/common/power-log-level.js +171 -0
- package/out/renderer/src/common/power-log-level.js.map +1 -0
- package/out/renderer/src/common/power-log-parser.js +7 -29
- package/out/renderer/src/common/power-log-parser.js.map +1 -1
- package/out/renderer/src/common/resource-search-kind-priority.js +28 -0
- package/out/renderer/src/common/resource-search-kind-priority.js.map +1 -0
- package/package.json +1 -1
|
@@ -8,8 +8,14 @@ const require_jsx_runtime = require("./_virtual/_global-external_react/jsx-runti
|
|
|
8
8
|
const require_ai_diagnostic_handoff = require("./ai-diagnostic-handoff.js");
|
|
9
9
|
const require_date_time = require("./src/common/date-time.js");
|
|
10
10
|
const require_diagnostic_explain_button = require("./diagnostic-explain-button.js");
|
|
11
|
+
const require_power_log_field_filters = require("./src/common/power-log-field-filters.js");
|
|
12
|
+
const require_power_log_json_filter_sql = require("./src/common/power-log-json-filter-sql.js");
|
|
13
|
+
const require_power_log_json_preset = require("./src/common/power-log-json-preset.js");
|
|
11
14
|
const require_power_logs_ai = require("./src/common/power-logs-ai.js");
|
|
15
|
+
const require_power_log_json_fields = require("./power-log-json-fields.js");
|
|
12
16
|
const require_power_log_json = require("./power-log-json.js");
|
|
17
|
+
const require_power_log_message = require("./power-log-message.js");
|
|
18
|
+
const require_power_log_json_cell = require("./power-log-json-cell.js");
|
|
13
19
|
const require_power_logs_css = require("./power-logs.css.js");
|
|
14
20
|
const require_power_logs_client = require("./power-logs-client.js");
|
|
15
21
|
const require_power_logs_collector = require("./power-logs-collector.js");
|
|
@@ -17,6 +23,7 @@ const require_power_logs_entrypoints = require("./power-logs-entrypoints.js");
|
|
|
17
23
|
const require_power_logs_sql_row = require("./power-logs-sql-row.js");
|
|
18
24
|
const require_resource_search_client = require("./resource-search-client.js");
|
|
19
25
|
const require_power_logs_transport = require("./power-logs-transport.js");
|
|
26
|
+
let electron = require("electron");
|
|
20
27
|
let node_crypto = require("node:crypto");
|
|
21
28
|
//#region src/renderer/power-logs.tsx
|
|
22
29
|
var Icon = (props) => /* @__PURE__ */ require_jsx_runtime.jsx("span", {
|
|
@@ -38,7 +45,7 @@ var examples = [
|
|
|
38
45
|
["Recent", "SELECT message, level, container, pod, timestamp FROM logs ORDER BY timestamp DESC NULLS LAST LIMIT 200"],
|
|
39
46
|
["Errors", "SELECT pod, container, count(*) AS errors FROM logs WHERE level IN ('error','fatal') GROUP BY pod, container ORDER BY errors DESC"],
|
|
40
47
|
["Timeline", "SELECT strftime('%Y-%m-%d %H:%M', timestamp / 1000, 'unixepoch') AS minute, level, count(*) AS lines FROM logs GROUP BY minute, level ORDER BY minute"],
|
|
41
|
-
["JSON", "SELECT
|
|
48
|
+
["JSON", "SELECT fieldsJson FROM logs WHERE fieldsJson IS NOT NULL LIMIT 100"]
|
|
42
49
|
];
|
|
43
50
|
var sqlColumnWidth = (column) => column === "message" || column === "fieldsJson" ? 360 : column === "level" ? 90 : 200;
|
|
44
51
|
function initialTarget() {
|
|
@@ -154,7 +161,7 @@ var SourcePicker = require__global_external_mobx_react.observer(() => {
|
|
|
154
161
|
]
|
|
155
162
|
});
|
|
156
163
|
});
|
|
157
|
-
function LogRows({ records, selected, onSelect, follow, setFollow, compact }) {
|
|
164
|
+
function LogRows({ records, loading, selected, onSelect, follow, setFollow, compact }) {
|
|
158
165
|
const viewport = require__global_external_react.useRef(null);
|
|
159
166
|
const [top, setTop] = require__global_external_react.useState(0);
|
|
160
167
|
const [height, setHeight] = require__global_external_react.useState(400);
|
|
@@ -175,7 +182,7 @@ function LogRows({ records, selected, onSelect, follow, setFollow, compact }) {
|
|
|
175
182
|
follow,
|
|
176
183
|
compact
|
|
177
184
|
]);
|
|
178
|
-
const rowHeight = compact ?
|
|
185
|
+
const rowHeight = compact ? 20 : 34;
|
|
179
186
|
const start = Math.max(0, Math.floor(top / rowHeight) - 5);
|
|
180
187
|
const visible = records.slice(start, start + Math.ceil(height / rowHeight) + 10);
|
|
181
188
|
return /* @__PURE__ */ require_jsx_runtime.jsx("div", {
|
|
@@ -184,6 +191,7 @@ function LogRows({ records, selected, onSelect, follow, setFollow, compact }) {
|
|
|
184
191
|
className: "power-logs-stream",
|
|
185
192
|
ref: viewport,
|
|
186
193
|
"aria-label": "Log lines",
|
|
194
|
+
"aria-busy": loading,
|
|
187
195
|
onScroll: (event) => {
|
|
188
196
|
const el = event.currentTarget;
|
|
189
197
|
setTop(el.scrollTop);
|
|
@@ -191,7 +199,7 @@ function LogRows({ records, selected, onSelect, follow, setFollow, compact }) {
|
|
|
191
199
|
},
|
|
192
200
|
children: records.length === 0 ? /* @__PURE__ */ require_jsx_runtime.jsx("div", {
|
|
193
201
|
className: "power-logs-empty",
|
|
194
|
-
children: "No matching log lines"
|
|
202
|
+
children: loading ? "Loading logs…" : "No matching log lines"
|
|
195
203
|
}) : /* @__PURE__ */ require_jsx_runtime.jsx("div", {
|
|
196
204
|
style: {
|
|
197
205
|
height: records.length * rowHeight,
|
|
@@ -226,22 +234,21 @@ function LogRows({ records, selected, onSelect, follow, setFollow, compact }) {
|
|
|
226
234
|
record.pod
|
|
227
235
|
]
|
|
228
236
|
}),
|
|
229
|
-
/* @__PURE__ */ require_jsx_runtime.jsx(
|
|
237
|
+
/* @__PURE__ */ require_jsx_runtime.jsx(require_power_log_message.LogMessage, { text: record.message })
|
|
230
238
|
]
|
|
231
239
|
}, record.key))
|
|
232
240
|
})
|
|
233
241
|
})
|
|
234
242
|
});
|
|
235
243
|
}
|
|
236
|
-
function LogDetails({ record, jsonColumn, onClose }) {
|
|
244
|
+
function LogDetails({ record, jsonColumn, onClose, onFilter }) {
|
|
237
245
|
const structuredFields = require__global_external_react.useMemo(() => {
|
|
238
246
|
if (!record?.fieldsJson) return "";
|
|
239
|
-
|
|
240
|
-
return JSON.stringify(JSON.parse(record.fieldsJson), null, 2);
|
|
241
|
-
} catch {
|
|
242
|
-
return record.fieldsJson;
|
|
243
|
-
}
|
|
247
|
+
return require_power_log_json_fields.formatJsonLiteral(record.fieldsJson);
|
|
244
248
|
}, [record?.fieldsJson]);
|
|
249
|
+
const fieldsEnabled = require__global_external_react.useMemo(() => !require_power_log_json_fields.jsonHasDuplicateKeys(record.fieldsJson ?? ""), [record.fieldsJson]);
|
|
250
|
+
const [copyFeedback, setCopyFeedback] = require__global_external_react.useState("");
|
|
251
|
+
require__global_external_react.useEffect(() => setCopyFeedback(""), [structuredFields]);
|
|
245
252
|
return /* @__PURE__ */ require_jsx_runtime.jsxs("aside", {
|
|
246
253
|
className: "power-logs-detail",
|
|
247
254
|
"aria-label": "Log line details",
|
|
@@ -260,11 +267,70 @@ function LogDetails({ record, jsonColumn, onClose }) {
|
|
|
260
267
|
className: "power-logs-muted",
|
|
261
268
|
children: [record.pod && sourceKey(record), record.level].filter(Boolean).join(" · ")
|
|
262
269
|
}),
|
|
263
|
-
record.message && /* @__PURE__ */ require_jsx_runtime.jsx("pre", { children: record.message }),
|
|
264
|
-
record.fieldsJson && /* @__PURE__ */ require_jsx_runtime.jsxs(require_jsx_runtime.Fragment, { children: [/* @__PURE__ */ require_jsx_runtime.
|
|
270
|
+
record.message && /* @__PURE__ */ require_jsx_runtime.jsx("pre", { children: /* @__PURE__ */ require_jsx_runtime.jsx(require_power_log_message.LogMessage, { text: record.message }) }),
|
|
271
|
+
record.fieldsJson && /* @__PURE__ */ require_jsx_runtime.jsxs(require_jsx_runtime.Fragment, { children: [/* @__PURE__ */ require_jsx_runtime.jsxs("div", {
|
|
272
|
+
className: "power-logs-structured-heading",
|
|
273
|
+
children: [
|
|
274
|
+
/* @__PURE__ */ require_jsx_runtime.jsx("strong", { children: jsonColumn ? `Structured fields · ${jsonColumn}` : "Structured fields" }),
|
|
275
|
+
/* @__PURE__ */ require_jsx_runtime.jsx("button", {
|
|
276
|
+
type: "button",
|
|
277
|
+
className: "power-logs-detail-copy",
|
|
278
|
+
"aria-label": "Copy structured JSON",
|
|
279
|
+
title: copyFeedback || "Copy structured JSON",
|
|
280
|
+
onClick: () => {
|
|
281
|
+
try {
|
|
282
|
+
electron.clipboard.writeText(structuredFields);
|
|
283
|
+
setCopyFeedback("Copied");
|
|
284
|
+
} catch {
|
|
285
|
+
setCopyFeedback("Unable to copy JSON");
|
|
286
|
+
}
|
|
287
|
+
},
|
|
288
|
+
children: /* @__PURE__ */ require_jsx_runtime.jsx(Icon, {
|
|
289
|
+
material: copyFeedback === "Copied" ? "check" : "content_copy",
|
|
290
|
+
size: 16
|
|
291
|
+
})
|
|
292
|
+
}),
|
|
293
|
+
/* @__PURE__ */ require_jsx_runtime.jsx("span", {
|
|
294
|
+
className: "power-logs-muted",
|
|
295
|
+
"aria-live": "polite",
|
|
296
|
+
children: copyFeedback
|
|
297
|
+
})
|
|
298
|
+
]
|
|
299
|
+
}), /* @__PURE__ */ require_jsx_runtime.jsx(require_power_log_json.LogJson, {
|
|
300
|
+
text: structuredFields,
|
|
301
|
+
fieldsEnabled,
|
|
302
|
+
Icon,
|
|
303
|
+
onFilter
|
|
304
|
+
})] })
|
|
265
305
|
]
|
|
266
306
|
});
|
|
267
307
|
}
|
|
308
|
+
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);
|
|
309
|
+
var fieldFilterLabel = (filter) => `${filter.path.reduce((path, part) => `${path}[${typeof part === "number" ? part : JSON.stringify(part)}]`, "$")} ${filter.operator === "eq" ? "=" : "!="} ${JSON.stringify(filter.value)}`;
|
|
310
|
+
function FieldFilters({ filters, sql = false, disabled = false, onRemove }) {
|
|
311
|
+
if (!filters.length) return null;
|
|
312
|
+
return /* @__PURE__ */ require_jsx_runtime.jsxs("div", {
|
|
313
|
+
className: "power-logs-field-filters",
|
|
314
|
+
"aria-label": sql ? "SQL JSON filters" : "Live JSON filters",
|
|
315
|
+
children: [/* @__PURE__ */ require_jsx_runtime.jsxs("span", {
|
|
316
|
+
className: "power-logs-muted",
|
|
317
|
+
children: [sql ? "Result filters" : "JSON filters", " · AND"]
|
|
318
|
+
}), filters.map((filter, index) => {
|
|
319
|
+
const label = `${filter.column ? `${filter.column} ` : ""}${fieldFilterLabel(filter)}`;
|
|
320
|
+
return /* @__PURE__ */ require_jsx_runtime.jsxs("button", {
|
|
321
|
+
type: "button",
|
|
322
|
+
disabled,
|
|
323
|
+
title: label,
|
|
324
|
+
"aria-label": `Remove JSON filter ${label}`,
|
|
325
|
+
onClick: () => onRemove(index),
|
|
326
|
+
children: [/* @__PURE__ */ require_jsx_runtime.jsx("span", { children: label }), /* @__PURE__ */ require_jsx_runtime.jsx(Icon, {
|
|
327
|
+
material: "close",
|
|
328
|
+
size: 14
|
|
329
|
+
})]
|
|
330
|
+
}, index);
|
|
331
|
+
})]
|
|
332
|
+
});
|
|
333
|
+
}
|
|
268
334
|
function Workspace({ clusterId, contextId }) {
|
|
269
335
|
const client = require__global_external_react.useMemo(() => require_power_logs_client.createPowerLogsClient({
|
|
270
336
|
clusterId,
|
|
@@ -280,6 +346,10 @@ function Workspace({ clusterId, contextId }) {
|
|
|
280
346
|
const [text, setText] = require__global_external_react.useState("");
|
|
281
347
|
const [level, setLevel] = require__global_external_react.useState("");
|
|
282
348
|
const [source, setSource] = require__global_external_react.useState(initialSource);
|
|
349
|
+
const [fieldFilters, setFieldFilters] = require__global_external_react.useState([]);
|
|
350
|
+
const matchFields = require__global_external_react.useMemo(() => require_power_log_field_filters.compileJsonFilters(fieldFilters), [fieldFilters]);
|
|
351
|
+
const parsedFields = require__global_external_react.useRef(/* @__PURE__ */ new WeakMap());
|
|
352
|
+
const [sqlFieldFilters, setSqlFieldFilters] = require__global_external_react.useState();
|
|
283
353
|
const preferences = require_logs_preferences_store.LogsPreferencesStore.getInstanceOrCreate();
|
|
284
354
|
const limits = require_power_logs_limits.normalizePowerLogsLimits(preferences.limits);
|
|
285
355
|
require__global_external_react.useEffect(() => {
|
|
@@ -291,18 +361,32 @@ function Workspace({ clusterId, contextId }) {
|
|
|
291
361
|
const [liveCoverage, setLiveCoverage] = require__global_external_react.useState();
|
|
292
362
|
const [live, setLive] = require__global_external_react.useState(false);
|
|
293
363
|
const [follow, setFollow] = require__global_external_react.useState(true);
|
|
294
|
-
const [busy, setBusy] = require__global_external_react.useState(
|
|
364
|
+
const [busy, setBusy] = require__global_external_react.useState(() => Boolean(initialTarget()));
|
|
295
365
|
const [captures, setCaptures] = require__global_external_react.useState([]);
|
|
296
|
-
const [captureId,
|
|
366
|
+
const [captureId, updateCaptureId] = require__global_external_react.useState("");
|
|
297
367
|
const captureSelection = require__global_external_react.useRef(captureId);
|
|
298
368
|
captureSelection.current = captureId;
|
|
369
|
+
const setCaptureId = (id) => {
|
|
370
|
+
captureSelection.current = id;
|
|
371
|
+
updateCaptureId(id);
|
|
372
|
+
};
|
|
299
373
|
const deleting = require__global_external_react.useRef(/* @__PURE__ */ new Set());
|
|
300
374
|
const [deletingCount, setDeletingCount] = require__global_external_react.useState(0);
|
|
301
375
|
const [capturing, setCapturing] = require__global_external_react.useState();
|
|
302
376
|
const [capturePending, setCapturePending] = require__global_external_react.useState(false);
|
|
303
377
|
const [captureMinutes, setCaptureMinutes] = require__global_external_react.useState(15);
|
|
304
378
|
const [previous, setPrevious] = require__global_external_react.useState(false);
|
|
305
|
-
const [sql,
|
|
379
|
+
const [sql, updateSql] = require__global_external_react.useState(examples[0][1]);
|
|
380
|
+
const sqlDraft = require__global_external_react.useRef(sql);
|
|
381
|
+
sqlDraft.current = sql;
|
|
382
|
+
const setSql = (query) => {
|
|
383
|
+
sqlDraft.current = query;
|
|
384
|
+
updateSql(query);
|
|
385
|
+
};
|
|
386
|
+
const captureKeys = require__global_external_react.useRef(/* @__PURE__ */ new Map());
|
|
387
|
+
require__global_external_react.useEffect(() => {
|
|
388
|
+
setSqlFieldFilters((current) => current && (current.rendered !== sql || current.captureId !== captureId) ? void 0 : current);
|
|
389
|
+
}, [sql, captureId]);
|
|
306
390
|
const [result, setResult] = require__global_external_react.useState();
|
|
307
391
|
const [resultEvidence, setResultEvidence] = require__global_external_react.useState();
|
|
308
392
|
const [resultPage, setResultPage] = require__global_external_react.useState(0);
|
|
@@ -447,6 +531,7 @@ function Workspace({ clusterId, contextId }) {
|
|
|
447
531
|
};
|
|
448
532
|
require__global_external_react.useEffect(() => {
|
|
449
533
|
setText("");
|
|
534
|
+
setFieldFilters([]);
|
|
450
535
|
setSources([]);
|
|
451
536
|
setTab("live");
|
|
452
537
|
readHistory();
|
|
@@ -581,7 +666,7 @@ function Workspace({ clusterId, contextId }) {
|
|
|
581
666
|
setCaptures((items) => [saved, ...items.filter((item) => item.id !== saved.id)]);
|
|
582
667
|
setTab("captures");
|
|
583
668
|
setSql(examples[0][1]);
|
|
584
|
-
|
|
669
|
+
applyPreset("Recent", saved, true);
|
|
585
670
|
}
|
|
586
671
|
} catch {
|
|
587
672
|
if (alive.current) setError("The temporary capture could not be finalized");
|
|
@@ -623,11 +708,115 @@ function Workspace({ clusterId, contextId }) {
|
|
|
623
708
|
}
|
|
624
709
|
}
|
|
625
710
|
};
|
|
626
|
-
const
|
|
711
|
+
const applyPreset = async (title, selectedCapture, execute = false) => {
|
|
712
|
+
const captured = selectedCapture ?? captures.find((item) => item.id === captureId);
|
|
713
|
+
if (queryRef.current || !selectedCapture && captureController.current || !captured || captured.state === "collecting" || deleting.current.has(captured.id)) return;
|
|
714
|
+
const draft = execute ? examples[0][1] : sqlDraft.current;
|
|
715
|
+
const id = (0, node_crypto.randomUUID)();
|
|
716
|
+
queryRef.current = id;
|
|
717
|
+
setQueryId(id);
|
|
718
|
+
setError("");
|
|
719
|
+
let prepared;
|
|
720
|
+
try {
|
|
721
|
+
let keys = captureKeys.current.get(captured.id);
|
|
722
|
+
if (!keys) {
|
|
723
|
+
const schema = await client.query(captured.id, id, require_power_log_json_preset.JSON_KEY_DISCOVERY_SQL);
|
|
724
|
+
if (schema.error) throw new Error(schema.error);
|
|
725
|
+
const keyColumn = schema.columns.indexOf("key");
|
|
726
|
+
keys = schema.truncated ? ["\0"] : keyColumn < 0 ? [] : schema.rows.map((row) => row[keyColumn]).filter((key) => typeof key === "string");
|
|
727
|
+
captureKeys.current.set(captured.id, keys);
|
|
728
|
+
if (captureKeys.current.size > 10) captureKeys.current.delete(captureKeys.current.keys().next().value);
|
|
729
|
+
}
|
|
730
|
+
if (!alive.current || queryRef.current !== id || captureSelection.current !== captured.id) return;
|
|
731
|
+
if (sqlDraft.current !== draft) {
|
|
732
|
+
setError("SQL draft changed while detecting JSON fields. Select the preset again to replace it.");
|
|
733
|
+
return;
|
|
734
|
+
}
|
|
735
|
+
prepared = require_power_log_json_preset.buildJsonProjectionSql(keys, { recent: title === "Recent" });
|
|
736
|
+
setSql(prepared);
|
|
737
|
+
setSelectedSqlRow(void 0);
|
|
738
|
+
} catch {
|
|
739
|
+
if (alive.current) setError("Could not detect JSON fields for this snapshot. Try the preset again.");
|
|
740
|
+
} finally {
|
|
741
|
+
if (queryRef.current === id) {
|
|
742
|
+
queryRef.current = "";
|
|
743
|
+
if (alive.current) setQueryId("");
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
if (prepared && execute && alive.current) runQuery(captured, prepared);
|
|
747
|
+
};
|
|
748
|
+
const addLiveFilter = (filter) => {
|
|
749
|
+
if (!require_power_log_field_filters.jsonValuesEqual(filter.value, filter.value)) {
|
|
750
|
+
setError("This JSON value is too large or unsupported for filtering");
|
|
751
|
+
return;
|
|
752
|
+
}
|
|
753
|
+
if (fieldFilters.some((current) => sameFieldFilter(current, filter))) return;
|
|
754
|
+
if (fieldFilters.length >= 32) {
|
|
755
|
+
setError("Up to 32 JSON filters can be combined");
|
|
756
|
+
return;
|
|
757
|
+
}
|
|
758
|
+
setFieldFilters([...fieldFilters, filter]);
|
|
759
|
+
};
|
|
760
|
+
const activeSqlFilters = sqlFieldFilters?.rendered === sql && sqlFieldFilters.captureId === captureId ? sqlFieldFilters : void 0;
|
|
761
|
+
const sqlFilteringDisabled = Boolean(queryId || capturePending || deleting.current.has(captureId) || !captures.some((capture) => capture.id === captureId && capture.state !== "collecting"));
|
|
762
|
+
const applySqlFilters = (filters) => {
|
|
763
|
+
if (queryRef.current || captureController.current || sqlFilteringDisabled) return;
|
|
764
|
+
if (!resultEvidence || resultEvidence.sql !== sql) {
|
|
765
|
+
setError("Run the edited SQL query before filtering its results");
|
|
766
|
+
return;
|
|
767
|
+
}
|
|
768
|
+
try {
|
|
769
|
+
const base = activeSqlFilters?.base ?? sql;
|
|
770
|
+
const query = require_power_log_json_filter_sql.buildJsonFilterSql(base, filters);
|
|
771
|
+
setSqlFieldFilters({
|
|
772
|
+
base,
|
|
773
|
+
rendered: query,
|
|
774
|
+
captureId,
|
|
775
|
+
filters
|
|
776
|
+
});
|
|
777
|
+
setSql(query);
|
|
778
|
+
runQuery(void 0, query);
|
|
779
|
+
} catch {
|
|
780
|
+
setError("This JSON filter cannot be added to the query. Check the field path and value size.");
|
|
781
|
+
}
|
|
782
|
+
};
|
|
783
|
+
const addSqlFilter = (column, filter) => {
|
|
784
|
+
const columnNames = result?.columns.map((name) => name.replace(/[A-Z]/g, (letter) => letter.toLowerCase())) ?? [];
|
|
785
|
+
if (!result?.columns.includes(column) || new Set(columnNames).size !== columnNames.length) {
|
|
786
|
+
setError("JSON filters require unique result column names, ignoring case");
|
|
787
|
+
return;
|
|
788
|
+
}
|
|
789
|
+
const filters = activeSqlFilters?.filters ?? [];
|
|
790
|
+
if (filters.some((current) => current.column === column && sameFieldFilter(current, filter))) return;
|
|
791
|
+
if (filters.length >= 32) {
|
|
792
|
+
setError("Up to 32 JSON filters can be combined");
|
|
793
|
+
return;
|
|
794
|
+
}
|
|
795
|
+
applySqlFilters([...filters, {
|
|
796
|
+
...filter,
|
|
797
|
+
column
|
|
798
|
+
}]);
|
|
799
|
+
};
|
|
800
|
+
const matchesRecordFields = (record) => {
|
|
801
|
+
if (!fieldFilters.length) return true;
|
|
802
|
+
if (!parsedFields.current.has(record)) {
|
|
803
|
+
let fields;
|
|
804
|
+
try {
|
|
805
|
+
fields = JSON.parse(record.fieldsJson ?? "null");
|
|
806
|
+
} catch {
|
|
807
|
+
fields = void 0;
|
|
808
|
+
}
|
|
809
|
+
parsedFields.current.set(record, fields);
|
|
810
|
+
}
|
|
811
|
+
return matchFields(parsedFields.current.get(record));
|
|
812
|
+
};
|
|
813
|
+
const filtered = require__global_external_react.useMemo(() => records.filter((record) => (!text || record.message.toLocaleLowerCase().includes(text.toLocaleLowerCase())) && (!level || record.level === level) && (!source || (source.startsWith("container:") ? record.container === source.slice(10) : sourceKey(record) === source)) && matchesRecordFields(record)), [
|
|
627
814
|
records,
|
|
628
815
|
text,
|
|
629
816
|
level,
|
|
630
|
-
source
|
|
817
|
+
source,
|
|
818
|
+
fieldFilters,
|
|
819
|
+
matchFields
|
|
631
820
|
]);
|
|
632
821
|
const chosenCapture = captures.find((item) => item.id === captureId);
|
|
633
822
|
const collectionNotes = tab === "live" ? [.../* @__PURE__ */ new Set([...notes, ...live ? liveCoverage?.notes ?? [] : []])] : [];
|
|
@@ -764,7 +953,7 @@ function Workspace({ clusterId, contextId }) {
|
|
|
764
953
|
if (!captureId && latest && !capturePending) {
|
|
765
954
|
setCaptureId(latest.id);
|
|
766
955
|
setSql(examples[0][1]);
|
|
767
|
-
|
|
956
|
+
applyPreset("Recent", latest, true);
|
|
768
957
|
}
|
|
769
958
|
refreshCaptures();
|
|
770
959
|
},
|
|
@@ -1004,6 +1193,10 @@ function Workspace({ clusterId, contextId }) {
|
|
|
1004
1193
|
})
|
|
1005
1194
|
]
|
|
1006
1195
|
}),
|
|
1196
|
+
/* @__PURE__ */ require_jsx_runtime.jsx(FieldFilters, {
|
|
1197
|
+
filters: fieldFilters,
|
|
1198
|
+
onRemove: (index) => setFieldFilters(fieldFilters.filter((_, item) => item !== index))
|
|
1199
|
+
}),
|
|
1007
1200
|
/* @__PURE__ */ require_jsx_runtime.jsxs("div", {
|
|
1008
1201
|
className: "power-logs-muted power-logs-status",
|
|
1009
1202
|
role: "status",
|
|
@@ -1024,6 +1217,7 @@ function Workspace({ clusterId, contextId }) {
|
|
|
1024
1217
|
className: "power-logs-workspace",
|
|
1025
1218
|
children: [/* @__PURE__ */ require_jsx_runtime.jsx(LogRows, {
|
|
1026
1219
|
records: filtered,
|
|
1220
|
+
loading: busy,
|
|
1027
1221
|
selected: selected?.key,
|
|
1028
1222
|
onSelect: setSelected,
|
|
1029
1223
|
follow,
|
|
@@ -1031,7 +1225,8 @@ function Workspace({ clusterId, contextId }) {
|
|
|
1031
1225
|
compact
|
|
1032
1226
|
}), selected && /* @__PURE__ */ require_jsx_runtime.jsx(LogDetails, {
|
|
1033
1227
|
record: selected,
|
|
1034
|
-
onClose: () => setSelected(void 0)
|
|
1228
|
+
onClose: () => setSelected(void 0),
|
|
1229
|
+
onFilter: addLiveFilter
|
|
1035
1230
|
})]
|
|
1036
1231
|
})
|
|
1037
1232
|
] }) : /* @__PURE__ */ require_jsx_runtime.jsxs(require_jsx_runtime.Fragment, { children: [
|
|
@@ -1100,7 +1295,7 @@ function Workspace({ clusterId, contextId }) {
|
|
|
1100
1295
|
const snapshot = captures.find((item) => item.id === value);
|
|
1101
1296
|
if (snapshot) {
|
|
1102
1297
|
setSql(examples[0][1]);
|
|
1103
|
-
|
|
1298
|
+
applyPreset("Recent", snapshot, true);
|
|
1104
1299
|
}
|
|
1105
1300
|
},
|
|
1106
1301
|
options: [{
|
|
@@ -1160,7 +1355,8 @@ function Workspace({ clusterId, contextId }) {
|
|
|
1160
1355
|
}),
|
|
1161
1356
|
examples.map(([title, query]) => /* @__PURE__ */ require_jsx_runtime.jsxs("button", {
|
|
1162
1357
|
type: "button",
|
|
1163
|
-
|
|
1358
|
+
disabled: !!queryId || capturePending,
|
|
1359
|
+
onClick: () => title === "JSON" || title === "Recent" ? void applyPreset(title) : setSql(query),
|
|
1164
1360
|
children: [
|
|
1165
1361
|
/* @__PURE__ */ require_jsx_runtime.jsx(Icon, {
|
|
1166
1362
|
material: title === "Recent" ? "history" : title === "Errors" ? "error_outline" : title === "Timeline" ? "timeline" : "data_object",
|
|
@@ -1173,13 +1369,36 @@ function Workspace({ clusterId, contextId }) {
|
|
|
1173
1369
|
}, title))
|
|
1174
1370
|
]
|
|
1175
1371
|
}),
|
|
1372
|
+
/* @__PURE__ */ require_jsx_runtime.jsx(FieldFilters, {
|
|
1373
|
+
sql: true,
|
|
1374
|
+
filters: activeSqlFilters?.filters ?? [],
|
|
1375
|
+
disabled: sqlFilteringDisabled,
|
|
1376
|
+
onRemove: (index) => applySqlFilters((activeSqlFilters?.filters ?? []).filter((_, item) => item !== index))
|
|
1377
|
+
}),
|
|
1176
1378
|
/* @__PURE__ */ require_jsx_runtime.jsx("textarea", {
|
|
1177
1379
|
rows: 2,
|
|
1178
1380
|
id: "power-logs-sql",
|
|
1179
1381
|
value: sql,
|
|
1180
1382
|
maxLength: 65536,
|
|
1181
1383
|
onChange: (event) => setSql(event.target.value),
|
|
1182
|
-
spellCheck: false
|
|
1384
|
+
spellCheck: false,
|
|
1385
|
+
onClick: (event) => {
|
|
1386
|
+
event.stopPropagation();
|
|
1387
|
+
if (event.detail >= 3) {
|
|
1388
|
+
event.preventDefault();
|
|
1389
|
+
window.getSelection()?.removeAllRanges();
|
|
1390
|
+
event.currentTarget.select();
|
|
1391
|
+
}
|
|
1392
|
+
},
|
|
1393
|
+
onMouseDown: (event) => {
|
|
1394
|
+
event.stopPropagation();
|
|
1395
|
+
if (event.detail >= 3) {
|
|
1396
|
+
event.preventDefault();
|
|
1397
|
+
window.getSelection()?.removeAllRanges();
|
|
1398
|
+
event.currentTarget.focus();
|
|
1399
|
+
event.currentTarget.select();
|
|
1400
|
+
}
|
|
1401
|
+
}
|
|
1183
1402
|
}),
|
|
1184
1403
|
result ? /* @__PURE__ */ require_jsx_runtime.jsxs(require_jsx_runtime.Fragment, { children: [
|
|
1185
1404
|
/* @__PURE__ */ require_jsx_runtime.jsx("div", {
|
|
@@ -1227,10 +1446,11 @@ function Workspace({ clusterId, contextId }) {
|
|
|
1227
1446
|
children: row.map((cell, j) => /* @__PURE__ */ require_jsx_runtime.jsx("td", {
|
|
1228
1447
|
"data-column": result.columns[j],
|
|
1229
1448
|
"data-level": result.columns[j] === "level" ? String(cell) : void 0,
|
|
1230
|
-
children: /* @__PURE__ */ require_jsx_runtime.jsx(
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1449
|
+
children: /* @__PURE__ */ require_jsx_runtime.jsx(require_power_log_json_cell.LogJsonCell, {
|
|
1450
|
+
value: cell === null ? null : String(cell),
|
|
1451
|
+
message: result.columns[j] === "message",
|
|
1452
|
+
Icon,
|
|
1453
|
+
onFilter: sqlFilteringDisabled ? void 0 : (filter) => addSqlFilter(result.columns[j], filter)
|
|
1234
1454
|
})
|
|
1235
1455
|
}, j))
|
|
1236
1456
|
}, i)) })
|
|
@@ -1242,6 +1462,7 @@ function Workspace({ clusterId, contextId }) {
|
|
|
1242
1462
|
}), selectedSqlRow && /* @__PURE__ */ require_jsx_runtime.jsx(LogDetails, {
|
|
1243
1463
|
record: selectedSqlRow.record,
|
|
1244
1464
|
jsonColumn: selectedSqlRow.jsonColumn,
|
|
1465
|
+
onFilter: !sqlFilteringDisabled && selectedSqlRow.jsonColumn ? (filter) => addSqlFilter(selectedSqlRow.jsonColumn, filter) : void 0,
|
|
1245
1466
|
onClose: () => setSelectedSqlRow(void 0)
|
|
1246
1467
|
})]
|
|
1247
1468
|
}),
|