@camstack/ui-library 1.2.298 → 1.2.299
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/dist/composites/addon-global-settings-form.d.ts +1 -1
- package/dist/composites/index.d.ts +2 -0
- package/dist/composites/record-entries/entry-json-schema-form.d.ts +11 -0
- package/dist/composites/record-entries/index.d.ts +4 -0
- package/dist/composites/record-entries/record-entries-hub.d.ts +9 -0
- package/dist/composites/record-entries/record-entries-panel.d.ts +6 -0
- package/dist/composites/record-entries/record-entry-secrets.d.ts +9 -0
- package/dist/composites/storage-records/index.d.ts +2 -0
- package/dist/composites/storage-records/storage-records-hub.d.ts +4 -0
- package/dist/composites/storage-records/storage-records-panel.d.ts +6 -0
- package/dist/index.cjs +796 -19
- package/dist/index.js +785 -21
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -14135,7 +14135,7 @@ function ConfigNotificationTargetMultiSelectFieldView({ field, value, onChange,
|
|
|
14135
14135
|
const kindsQuery = useNotificationOutputListTargetKinds({});
|
|
14136
14136
|
const targets = (0, react$1.useMemo)(() => toTargetOptions(targetsQuery.data), [targetsQuery.data]);
|
|
14137
14137
|
const kindIconUrls = (0, react$1.useMemo)(() => buildKindIconMap(kindsQuery.data), [kindsQuery.data]);
|
|
14138
|
-
const selected = Array.isArray(value) ? value.filter((v) => typeof v === "string") : typeof value === "string" && value.length > 0 ? [value] : [];
|
|
14138
|
+
const selected = Array.isArray(value) ? value.filter((v) => typeof v === "string") : typeof value === "string" && value.length > 0 ? value.includes(",") ? value.split(",").map((id) => id.trim()).filter((id) => id.length > 0) : [value] : [];
|
|
14139
14139
|
const pending = targetsQuery.isPending || kindsQuery.isPending;
|
|
14140
14140
|
const error = targetsQuery.isError ? targetsQuery.error : kindsQuery.isError ? kindsQuery.error : null;
|
|
14141
14141
|
if (pending) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FieldShell, {
|
|
@@ -19498,11 +19498,11 @@ function useDeviceSnapshotImage(deviceId, options = {}) {
|
|
|
19498
19498
|
//#region src/composites/cap-settings/camera-grid-layout.ts
|
|
19499
19499
|
/** Smallest rectangle the editor will produce — ffmpeg refuses a zero-area crop. */
|
|
19500
19500
|
var MIN_EXTENT = .02;
|
|
19501
|
-
function isRecord(value) {
|
|
19501
|
+
function isRecord$2(value) {
|
|
19502
19502
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
19503
19503
|
}
|
|
19504
19504
|
function readRect(value) {
|
|
19505
|
-
if (!isRecord(value)) return null;
|
|
19505
|
+
if (!isRecord$2(value)) return null;
|
|
19506
19506
|
const { x, y, width, height } = value;
|
|
19507
19507
|
if (typeof x !== "number" || typeof y !== "number" || typeof width !== "number" || typeof height !== "number") return null;
|
|
19508
19508
|
if (x < 0 || y < 0 || width <= 0 || height <= 0) return null;
|
|
@@ -19515,7 +19515,7 @@ function readRect(value) {
|
|
|
19515
19515
|
};
|
|
19516
19516
|
}
|
|
19517
19517
|
function readCell(value) {
|
|
19518
|
-
if (!isRecord(value)) return null;
|
|
19518
|
+
if (!isRecord$2(value)) return null;
|
|
19519
19519
|
const deviceId = value["deviceId"];
|
|
19520
19520
|
if (typeof deviceId !== "number" || !Number.isInteger(deviceId)) return null;
|
|
19521
19521
|
const source = readRect(value["source"]);
|
|
@@ -19528,7 +19528,7 @@ function readCell(value) {
|
|
|
19528
19528
|
};
|
|
19529
19529
|
}
|
|
19530
19530
|
function readProfileOffer(value) {
|
|
19531
|
-
if (!isRecord(value)) return null;
|
|
19531
|
+
if (!isRecord$2(value)) return null;
|
|
19532
19532
|
const profile = value["profile"];
|
|
19533
19533
|
const offered = value["offered"];
|
|
19534
19534
|
const missing = value["missingSources"];
|
|
@@ -19557,7 +19557,7 @@ function readProfileOffer(value) {
|
|
|
19557
19557
|
*/
|
|
19558
19558
|
function parseGridView(raw) {
|
|
19559
19559
|
if (raw === null) return null;
|
|
19560
|
-
if (!isRecord(raw)) return "unreadable";
|
|
19560
|
+
if (!isRecord$2(raw)) return "unreadable";
|
|
19561
19561
|
const { instanceId, deviceId, name, fps, cells, profiles } = raw;
|
|
19562
19562
|
if (typeof instanceId !== "string" || typeof deviceId !== "number" || typeof name !== "string" || typeof fps !== "number" || !Array.isArray(cells) || !Array.isArray(profiles)) return "unreadable";
|
|
19563
19563
|
const parsed = [];
|
|
@@ -25714,7 +25714,7 @@ function mergeAvailabilitySpans(ranges) {
|
|
|
25714
25714
|
* significant digits (binary prefixes, matching recording sizes elsewhere).
|
|
25715
25715
|
* KB and up render one decimal under 100, none above; bytes never get a decimal.
|
|
25716
25716
|
*/
|
|
25717
|
-
function formatBytes(bytes) {
|
|
25717
|
+
function formatBytes$1(bytes) {
|
|
25718
25718
|
if (!Number.isFinite(bytes) || bytes < 0) return "—";
|
|
25719
25719
|
if (bytes < 1024) return `${Math.round(bytes)} B`;
|
|
25720
25720
|
const units = [
|
|
@@ -26247,7 +26247,7 @@ function RecordingPanel({ deviceId }) {
|
|
|
26247
26247
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(WidgetMetricCard, {
|
|
26248
26248
|
label: t("uiLibrary.recordingPanel.storage", "Storage"),
|
|
26249
26249
|
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(HardDrive, { className: "h-3.5 w-3.5" }),
|
|
26250
|
-
children: status ? formatBytes(status.storageBytes) : "—"
|
|
26250
|
+
children: status ? formatBytes$1(status.storageBytes) : "—"
|
|
26251
26251
|
}),
|
|
26252
26252
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(WidgetMetricCard, {
|
|
26253
26253
|
label: t("uiLibrary.recordingPanel.recorded24h", "Recorded (24h)"),
|
|
@@ -29608,17 +29608,7 @@ function applyValuesToSchema(schema, nextValues) {
|
|
|
29608
29608
|
};
|
|
29609
29609
|
}
|
|
29610
29610
|
function stripValues(schema) {
|
|
29611
|
-
return
|
|
29612
|
-
...schema,
|
|
29613
|
-
sections: schema.sections.map((s) => ({
|
|
29614
|
-
...s,
|
|
29615
|
-
fields: s.fields.map((f) => {
|
|
29616
|
-
if (!isValueBearingField(f)) return f;
|
|
29617
|
-
const { value: _drop, ...rest } = f;
|
|
29618
|
-
return rest;
|
|
29619
|
-
})
|
|
29620
|
-
}))
|
|
29621
|
-
};
|
|
29611
|
+
return (0, _camstack_types.dehydrateSchema)(schema);
|
|
29622
29612
|
}
|
|
29623
29613
|
function AddonGlobalSettingsForm({ trpc, addonId, nodeId, title, disabled, onAfterChange, refreshToken, sectionIds, bare = false, collapsible, defaultOpen, mode, onOverrideChange }) {
|
|
29624
29614
|
const t = useUiText();
|
|
@@ -58683,6 +58673,780 @@ function EntryIcon({ url }) {
|
|
|
58683
58673
|
});
|
|
58684
58674
|
}
|
|
58685
58675
|
//#endregion
|
|
58676
|
+
//#region src/composites/record-entries/record-entry-secrets.ts
|
|
58677
|
+
/** Whether a record entry field still holds the redaction token from a read. */
|
|
58678
|
+
function isRedactedSecret(value) {
|
|
58679
|
+
return value === _camstack_types.REDACTED_SECRET;
|
|
58680
|
+
}
|
|
58681
|
+
/** Text shown in a password box for a redacted stored secret (empty — placeholder carries the hint). */
|
|
58682
|
+
function secretDisplayValue(value) {
|
|
58683
|
+
if (isRedactedSecret(value)) return "";
|
|
58684
|
+
return typeof value === "string" ? value : "";
|
|
58685
|
+
}
|
|
58686
|
+
/** Merge an edited password box back into the body sent to `putEntry`. */
|
|
58687
|
+
function mergeSecretForSubmit(draft, original) {
|
|
58688
|
+
if (!isRedactedSecret(original)) return draft;
|
|
58689
|
+
if (draft.length === 0) return _camstack_types.REDACTED_SECRET;
|
|
58690
|
+
return draft;
|
|
58691
|
+
}
|
|
58692
|
+
/** Is this JSON-schema leaf (or path) a credential field? */
|
|
58693
|
+
function isSecretField(path, secretPaths, schemaNode) {
|
|
58694
|
+
if (schemaNode["secret"] === true) return true;
|
|
58695
|
+
return secretPaths.includes(path);
|
|
58696
|
+
}
|
|
58697
|
+
//#endregion
|
|
58698
|
+
//#region src/composites/record-entries/entry-json-schema-form.tsx
|
|
58699
|
+
function isRecord$1(value) {
|
|
58700
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
58701
|
+
}
|
|
58702
|
+
function labelFor(key, node) {
|
|
58703
|
+
const desc = node["description"];
|
|
58704
|
+
if (typeof desc === "string" && desc.length > 0) return desc;
|
|
58705
|
+
return key.replace(/([A-Z])/g, " $1").replace(/^./, (c) => c.toUpperCase());
|
|
58706
|
+
}
|
|
58707
|
+
function readString(value) {
|
|
58708
|
+
return typeof value === "string" ? value : "";
|
|
58709
|
+
}
|
|
58710
|
+
function readNumber(value) {
|
|
58711
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
58712
|
+
}
|
|
58713
|
+
function readBool(value) {
|
|
58714
|
+
return value === true;
|
|
58715
|
+
}
|
|
58716
|
+
function objectFromJson(text) {
|
|
58717
|
+
try {
|
|
58718
|
+
const parsed = JSON.parse(text);
|
|
58719
|
+
return isRecord$1(parsed) ? parsed : null;
|
|
58720
|
+
} catch {
|
|
58721
|
+
return null;
|
|
58722
|
+
}
|
|
58723
|
+
}
|
|
58724
|
+
function RecordEntrySecretField({ label, required, value, disabled, onPatch }) {
|
|
58725
|
+
const [shown, setShown] = (0, react$1.useState)(false);
|
|
58726
|
+
const stored = isRedactedSecret(value);
|
|
58727
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FormField$1, {
|
|
58728
|
+
label,
|
|
58729
|
+
required,
|
|
58730
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PasswordInput, {
|
|
58731
|
+
value: secretDisplayValue(value),
|
|
58732
|
+
onValueChange: (text) => onPatch(mergeSecretForSubmit(text, value)),
|
|
58733
|
+
shown,
|
|
58734
|
+
onToggleShown: () => setShown((s) => !s),
|
|
58735
|
+
disabled,
|
|
58736
|
+
placeholder: stored ? SECRET_MASK_PLACEHOLDER : `Enter ${label.toLowerCase()}`
|
|
58737
|
+
})
|
|
58738
|
+
});
|
|
58739
|
+
}
|
|
58740
|
+
function SchemaField(props) {
|
|
58741
|
+
const { path, name, node, value, secretPaths, required, disabled, onPatch } = props;
|
|
58742
|
+
const label = labelFor(name, node);
|
|
58743
|
+
if (isSecretField(path, secretPaths, node)) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RecordEntrySecretField, {
|
|
58744
|
+
label,
|
|
58745
|
+
required,
|
|
58746
|
+
value,
|
|
58747
|
+
disabled,
|
|
58748
|
+
onPatch: (next) => onPatch(path, next)
|
|
58749
|
+
});
|
|
58750
|
+
const enumValues = node["enum"];
|
|
58751
|
+
if (Array.isArray(enumValues) && enumValues.every((v) => typeof v === "string")) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FormField$1, {
|
|
58752
|
+
label,
|
|
58753
|
+
required,
|
|
58754
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Select, {
|
|
58755
|
+
value: readString(value),
|
|
58756
|
+
onChange: (e) => onPatch(path, e.target.value),
|
|
58757
|
+
disabled,
|
|
58758
|
+
options: enumValues.map((opt) => ({
|
|
58759
|
+
value: opt,
|
|
58760
|
+
label: opt
|
|
58761
|
+
}))
|
|
58762
|
+
})
|
|
58763
|
+
});
|
|
58764
|
+
const type = node["type"];
|
|
58765
|
+
if (type === "boolean") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FormField$1, {
|
|
58766
|
+
label,
|
|
58767
|
+
required,
|
|
58768
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Switch, {
|
|
58769
|
+
checked: readBool(value),
|
|
58770
|
+
onCheckedChange: (v) => onPatch(path, v),
|
|
58771
|
+
disabled
|
|
58772
|
+
})
|
|
58773
|
+
});
|
|
58774
|
+
if (type === "integer" || type === "number") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FormField$1, {
|
|
58775
|
+
label,
|
|
58776
|
+
required,
|
|
58777
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Input, {
|
|
58778
|
+
type: "number",
|
|
58779
|
+
value: readNumber(value) ?? "",
|
|
58780
|
+
onChange: (e) => {
|
|
58781
|
+
const raw = e.target.value;
|
|
58782
|
+
onPatch(path, raw === "" ? void 0 : Number(raw));
|
|
58783
|
+
},
|
|
58784
|
+
disabled
|
|
58785
|
+
})
|
|
58786
|
+
});
|
|
58787
|
+
if (type === "object") {
|
|
58788
|
+
const properties = node["properties"];
|
|
58789
|
+
if (isRecord$1(properties)) {
|
|
58790
|
+
const childValue = isRecord$1(value) ? value : {};
|
|
58791
|
+
const childRequired = Array.isArray(node["required"]) ? node["required"].filter((k) => typeof k === "string") : [];
|
|
58792
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("fieldset", {
|
|
58793
|
+
className: "space-y-3 rounded-lg border border-border-subtle p-3",
|
|
58794
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("legend", {
|
|
58795
|
+
className: "px-1 text-xs font-medium text-foreground-muted",
|
|
58796
|
+
children: label
|
|
58797
|
+
}), Object.entries(properties).map(([key, childNode]) => isRecord$1(childNode) ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SchemaField, {
|
|
58798
|
+
path: `${path}.${key}`,
|
|
58799
|
+
name: key,
|
|
58800
|
+
node: childNode,
|
|
58801
|
+
value: childValue[key],
|
|
58802
|
+
secretPaths,
|
|
58803
|
+
required: childRequired.includes(key),
|
|
58804
|
+
disabled,
|
|
58805
|
+
onPatch
|
|
58806
|
+
}, key) : null)]
|
|
58807
|
+
});
|
|
58808
|
+
}
|
|
58809
|
+
const jsonText = isRecord$1(value) ? JSON.stringify(value, null, 2) : "{}";
|
|
58810
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FormField$1, {
|
|
58811
|
+
label,
|
|
58812
|
+
required,
|
|
58813
|
+
description: "JSON object",
|
|
58814
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
|
|
58815
|
+
className: cn("min-h-[8rem] w-full resize-y rounded-md border border-border bg-surface px-2.5 py-2 font-mono text-xs text-foreground", "placeholder:text-foreground-subtle focus:outline-none focus:ring-1 focus:ring-inset focus:ring-primary", "disabled:cursor-not-allowed disabled:opacity-50"),
|
|
58816
|
+
rows: 6,
|
|
58817
|
+
defaultValue: jsonText,
|
|
58818
|
+
disabled,
|
|
58819
|
+
onBlur: (e) => {
|
|
58820
|
+
const parsed = objectFromJson(e.target.value);
|
|
58821
|
+
if (parsed !== null) onPatch(path, parsed);
|
|
58822
|
+
}
|
|
58823
|
+
})
|
|
58824
|
+
});
|
|
58825
|
+
}
|
|
58826
|
+
if (type === "string" || type === void 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FormField$1, {
|
|
58827
|
+
label,
|
|
58828
|
+
required,
|
|
58829
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Input, {
|
|
58830
|
+
value: readString(value),
|
|
58831
|
+
onChange: (e) => onPatch(path, e.target.value),
|
|
58832
|
+
disabled
|
|
58833
|
+
})
|
|
58834
|
+
});
|
|
58835
|
+
return null;
|
|
58836
|
+
}
|
|
58837
|
+
function setAtPath(root, path, next) {
|
|
58838
|
+
const parts = path.split(".");
|
|
58839
|
+
if (parts.length === 1) return {
|
|
58840
|
+
...root,
|
|
58841
|
+
[parts[0]]: next
|
|
58842
|
+
};
|
|
58843
|
+
const [head, ...rest] = parts;
|
|
58844
|
+
const key = head;
|
|
58845
|
+
const child = isRecord$1(root[key]) ? root[key] : {};
|
|
58846
|
+
return {
|
|
58847
|
+
...root,
|
|
58848
|
+
[key]: setAtPath(child, rest.join("."), next)
|
|
58849
|
+
};
|
|
58850
|
+
}
|
|
58851
|
+
/** Renders an entry body from the engine's JSON Schema descriptor. */
|
|
58852
|
+
function EntryJsonSchemaForm({ schema, secretPaths, value, onChange, disabled }) {
|
|
58853
|
+
const properties = schema["properties"];
|
|
58854
|
+
if (!isRecord$1(properties)) return null;
|
|
58855
|
+
const required = Array.isArray(schema["required"]) ? schema["required"].filter((k) => typeof k === "string") : [];
|
|
58856
|
+
const onPatch = (path, next) => {
|
|
58857
|
+
onChange(setAtPath(value, path, next));
|
|
58858
|
+
};
|
|
58859
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
58860
|
+
className: "space-y-3",
|
|
58861
|
+
children: Object.entries(properties).map(([key, node]) => isRecord$1(node) ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SchemaField, {
|
|
58862
|
+
path: key,
|
|
58863
|
+
name: key,
|
|
58864
|
+
node,
|
|
58865
|
+
value: value[key],
|
|
58866
|
+
secretPaths,
|
|
58867
|
+
required: required.includes(key),
|
|
58868
|
+
disabled,
|
|
58869
|
+
onPatch
|
|
58870
|
+
}, key) : null)
|
|
58871
|
+
});
|
|
58872
|
+
}
|
|
58873
|
+
//#endregion
|
|
58874
|
+
//#region src/composites/record-entries/record-entries-panel.tsx
|
|
58875
|
+
function isRecord(value) {
|
|
58876
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
58877
|
+
}
|
|
58878
|
+
function defaultBody(schema) {
|
|
58879
|
+
const properties = schema["properties"];
|
|
58880
|
+
if (!isRecord(properties)) return {};
|
|
58881
|
+
const out = {};
|
|
58882
|
+
for (const [key, node] of Object.entries(properties)) {
|
|
58883
|
+
if (!isRecord(node)) continue;
|
|
58884
|
+
if (node["default"] !== void 0) {
|
|
58885
|
+
out[key] = node["default"];
|
|
58886
|
+
continue;
|
|
58887
|
+
}
|
|
58888
|
+
if (node["type"] === "boolean") out[key] = false;
|
|
58889
|
+
else if (node["type"] === "object") out[key] = {};
|
|
58890
|
+
}
|
|
58891
|
+
return out;
|
|
58892
|
+
}
|
|
58893
|
+
function RecordEntriesPanel({ kind }) {
|
|
58894
|
+
const t = useUiText();
|
|
58895
|
+
const queryClient = (0, _tanstack_react_query.useQueryClient)();
|
|
58896
|
+
const confirm = useConfirm();
|
|
58897
|
+
const formUrl = useItemFormUrl({
|
|
58898
|
+
newKey: "entryNew",
|
|
58899
|
+
editKey: "entryEdit"
|
|
58900
|
+
});
|
|
58901
|
+
const listQuery = useRecordEntriesListEntries({
|
|
58902
|
+
owner: kind.owner,
|
|
58903
|
+
kind: kind.kind
|
|
58904
|
+
}, { staleTime: 15e3 });
|
|
58905
|
+
const putMutation = useRecordEntriesPutEntry({ onSuccess: async () => {
|
|
58906
|
+
await queryClient.invalidateQueries({ queryKey: [["recordEntries"]] });
|
|
58907
|
+
formUrl.close();
|
|
58908
|
+
} });
|
|
58909
|
+
const deleteMutation = useRecordEntriesDeleteEntry({ onSuccess: async () => {
|
|
58910
|
+
await queryClient.invalidateQueries({ queryKey: [["recordEntries"]] });
|
|
58911
|
+
} });
|
|
58912
|
+
const entries = listQuery.data?.entries ?? [];
|
|
58913
|
+
const editing = (0, react$1.useMemo)(() => {
|
|
58914
|
+
const st = formUrl.state;
|
|
58915
|
+
if (st.mode !== "edit") return null;
|
|
58916
|
+
return entries.find((e) => e.id === st.id) ?? null;
|
|
58917
|
+
}, [entries, formUrl.state]);
|
|
58918
|
+
const [draft, setDraft] = (0, react$1.useState)({});
|
|
58919
|
+
const [saveError, setSaveError] = (0, react$1.useState)(null);
|
|
58920
|
+
const openNew = (0, react$1.useCallback)(() => {
|
|
58921
|
+
setDraft(defaultBody(kind.fields));
|
|
58922
|
+
setSaveError(null);
|
|
58923
|
+
formUrl.openNew();
|
|
58924
|
+
}, [formUrl, kind.fields]);
|
|
58925
|
+
const openEdit = (0, react$1.useCallback)((entry) => {
|
|
58926
|
+
setDraft({ ...entry.data });
|
|
58927
|
+
setSaveError(null);
|
|
58928
|
+
formUrl.openEdit(entry.id);
|
|
58929
|
+
}, [formUrl]);
|
|
58930
|
+
const onDelete = (0, react$1.useCallback)(async (entry) => {
|
|
58931
|
+
if (!await confirm({
|
|
58932
|
+
title: t("uiLibrary.recordEntries.deleteTitle", "Delete entry"),
|
|
58933
|
+
message: t("uiLibrary.recordEntries.deleteDescription", "Remove \"{{name}}\" permanently?", { name: entry.name }),
|
|
58934
|
+
confirmLabel: t("uiLibrary.recordEntries.deleteConfirm", "Delete"),
|
|
58935
|
+
variant: "danger"
|
|
58936
|
+
})) return;
|
|
58937
|
+
await deleteMutation.mutateAsync({
|
|
58938
|
+
owner: kind.owner,
|
|
58939
|
+
kind: kind.kind,
|
|
58940
|
+
id: entry.id
|
|
58941
|
+
});
|
|
58942
|
+
}, [
|
|
58943
|
+
confirm,
|
|
58944
|
+
deleteMutation,
|
|
58945
|
+
kind.kind,
|
|
58946
|
+
kind.owner,
|
|
58947
|
+
t
|
|
58948
|
+
]);
|
|
58949
|
+
const columns = (0, react$1.useMemo)(() => {
|
|
58950
|
+
return [
|
|
58951
|
+
{
|
|
58952
|
+
key: "name",
|
|
58953
|
+
header: t("uiLibrary.recordEntries.colName", "Name"),
|
|
58954
|
+
render: (row) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
58955
|
+
type: "button",
|
|
58956
|
+
variant: "ghost",
|
|
58957
|
+
size: "sm",
|
|
58958
|
+
className: "h-auto max-w-full justify-start px-0 py-0 font-medium hover:underline",
|
|
58959
|
+
onClick: () => openEdit(row),
|
|
58960
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
58961
|
+
className: "truncate",
|
|
58962
|
+
children: row.name
|
|
58963
|
+
})
|
|
58964
|
+
})
|
|
58965
|
+
},
|
|
58966
|
+
{
|
|
58967
|
+
key: "updated",
|
|
58968
|
+
header: t("uiLibrary.recordEntries.colUpdated", "Updated"),
|
|
58969
|
+
nowrap: true,
|
|
58970
|
+
render: (row) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
58971
|
+
className: "text-[11px] text-foreground-subtle",
|
|
58972
|
+
children: new Date(row.updatedAt).toLocaleString()
|
|
58973
|
+
})
|
|
58974
|
+
},
|
|
58975
|
+
{
|
|
58976
|
+
key: "actions",
|
|
58977
|
+
header: "",
|
|
58978
|
+
align: "right",
|
|
58979
|
+
nowrap: true,
|
|
58980
|
+
render: (row) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
58981
|
+
className: "flex justify-end gap-1",
|
|
58982
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
58983
|
+
size: "sm",
|
|
58984
|
+
variant: "ghost",
|
|
58985
|
+
type: "button",
|
|
58986
|
+
onClick: () => openEdit(row),
|
|
58987
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Pencil, { className: "h-3.5 w-3.5" })
|
|
58988
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
58989
|
+
size: "sm",
|
|
58990
|
+
variant: "ghost",
|
|
58991
|
+
type: "button",
|
|
58992
|
+
onClick: () => void onDelete(row),
|
|
58993
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Trash2, { className: "h-3.5 w-3.5 text-danger" })
|
|
58994
|
+
})]
|
|
58995
|
+
})
|
|
58996
|
+
}
|
|
58997
|
+
];
|
|
58998
|
+
}, [
|
|
58999
|
+
onDelete,
|
|
59000
|
+
openEdit,
|
|
59001
|
+
t
|
|
59002
|
+
]);
|
|
59003
|
+
const dialogOpen = formUrl.state.mode !== "closed";
|
|
59004
|
+
const dialogTitle = formUrl.state.mode === "new" ? t("uiLibrary.recordEntries.addTitle", "Add entry") : t("uiLibrary.recordEntries.editTitle", "Edit entry");
|
|
59005
|
+
const onSave = async () => {
|
|
59006
|
+
setSaveError(null);
|
|
59007
|
+
try {
|
|
59008
|
+
if (formUrl.state.mode === "new") await putMutation.mutateAsync({
|
|
59009
|
+
owner: kind.owner,
|
|
59010
|
+
kind: kind.kind,
|
|
59011
|
+
data: draft
|
|
59012
|
+
});
|
|
59013
|
+
else if (formUrl.state.mode === "edit" && editing !== null) await putMutation.mutateAsync({
|
|
59014
|
+
owner: kind.owner,
|
|
59015
|
+
kind: kind.kind,
|
|
59016
|
+
id: editing.id,
|
|
59017
|
+
data: draft,
|
|
59018
|
+
ifRev: editing.rev
|
|
59019
|
+
});
|
|
59020
|
+
else {
|
|
59021
|
+
setSaveError(t("uiLibrary.recordEntries.saveUnavailable", "Nothing to save"));
|
|
59022
|
+
return;
|
|
59023
|
+
}
|
|
59024
|
+
} catch (err) {
|
|
59025
|
+
setSaveError(err instanceof Error ? err.message : t("uiLibrary.recordEntries.saveFailed", "Save failed"));
|
|
59026
|
+
}
|
|
59027
|
+
};
|
|
59028
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
59029
|
+
className: "space-y-3",
|
|
59030
|
+
children: [
|
|
59031
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
59032
|
+
className: "flex justify-end",
|
|
59033
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Button, {
|
|
59034
|
+
type: "button",
|
|
59035
|
+
size: "sm",
|
|
59036
|
+
onClick: openNew,
|
|
59037
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Plus, { className: "mr-1 h-3.5 w-3.5" }), t("uiLibrary.recordEntries.add", "Add")]
|
|
59038
|
+
})
|
|
59039
|
+
}),
|
|
59040
|
+
listQuery.isError && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ErrorBox, { message: listQuery.error instanceof Error ? listQuery.error.message : t("uiLibrary.recordEntries.loadFailed", "Could not load entries") }),
|
|
59041
|
+
listQuery.isPending ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
59042
|
+
className: "flex justify-center py-8 text-foreground-subtle",
|
|
59043
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LoaderCircle, { className: "h-5 w-5 animate-spin" })
|
|
59044
|
+
}) : entries.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EmptyState, {
|
|
59045
|
+
title: t("uiLibrary.recordEntries.emptyTitle", "No entries yet"),
|
|
59046
|
+
description: t("uiLibrary.recordEntries.emptyDescription", "Add the first row for this kind.")
|
|
59047
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DataTable, {
|
|
59048
|
+
columns,
|
|
59049
|
+
rows: entries,
|
|
59050
|
+
rowKey: (r) => r.id,
|
|
59051
|
+
maxBodyHeight: TABLE_SCROLL_MAX_H,
|
|
59052
|
+
emptyMessage: t("uiLibrary.recordEntries.emptyTitle", "No entries yet")
|
|
59053
|
+
}),
|
|
59054
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ItemFormDialog, {
|
|
59055
|
+
open: dialogOpen,
|
|
59056
|
+
onClose: formUrl.close,
|
|
59057
|
+
title: dialogTitle,
|
|
59058
|
+
error: saveError,
|
|
59059
|
+
footer: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
59060
|
+
type: "button",
|
|
59061
|
+
size: "sm",
|
|
59062
|
+
disabled: putMutation.isPending,
|
|
59063
|
+
onClick: () => void onSave(),
|
|
59064
|
+
children: putMutation.isPending ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LoaderCircle, { className: "h-3.5 w-3.5 animate-spin" }) : t("uiLibrary.recordEntries.save", "Save")
|
|
59065
|
+
}),
|
|
59066
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EntryJsonSchemaForm, {
|
|
59067
|
+
schema: kind.fields,
|
|
59068
|
+
secretPaths: kind.secretPaths,
|
|
59069
|
+
value: draft,
|
|
59070
|
+
onChange: setDraft,
|
|
59071
|
+
disabled: putMutation.isPending
|
|
59072
|
+
})
|
|
59073
|
+
})
|
|
59074
|
+
]
|
|
59075
|
+
});
|
|
59076
|
+
}
|
|
59077
|
+
//#endregion
|
|
59078
|
+
//#region src/composites/record-entries/record-entries-hub.tsx
|
|
59079
|
+
var RECORD_ENTRY_OWNER_PARAM = "entryOwner";
|
|
59080
|
+
var RECORD_ENTRY_KIND_PARAM = "entryKind";
|
|
59081
|
+
function kindKey$1(k) {
|
|
59082
|
+
return `${k.owner}/${k.kind}`;
|
|
59083
|
+
}
|
|
59084
|
+
function RecordEntriesHub({ filter }) {
|
|
59085
|
+
const t = useUiText();
|
|
59086
|
+
const kindsQuery = useRecordEntriesListEntryKinds({}, { staleTime: 3e4 });
|
|
59087
|
+
const [ownerParam, setOwner] = useUrlQueryParam(RECORD_ENTRY_OWNER_PARAM);
|
|
59088
|
+
const [kindParam, setKind] = useUrlQueryParam(RECORD_ENTRY_KIND_PARAM);
|
|
59089
|
+
const kinds = (0, react$1.useMemo)(() => {
|
|
59090
|
+
return (kindsQuery.data?.kinds ?? []).filter((k) => {
|
|
59091
|
+
if (filter?.owner !== void 0 && k.owner !== filter.owner) return false;
|
|
59092
|
+
if (filter?.kind !== void 0 && k.kind !== filter.kind) return false;
|
|
59093
|
+
return true;
|
|
59094
|
+
});
|
|
59095
|
+
}, [
|
|
59096
|
+
filter?.kind,
|
|
59097
|
+
filter?.owner,
|
|
59098
|
+
kindsQuery.data?.kinds
|
|
59099
|
+
]);
|
|
59100
|
+
const active = (0, react$1.useMemo)(() => {
|
|
59101
|
+
if (kinds.length === 0) return null;
|
|
59102
|
+
return kinds.find((k) => k.owner === ownerParam && k.kind === kindParam) ?? kinds[0] ?? null;
|
|
59103
|
+
}, [
|
|
59104
|
+
kindParam,
|
|
59105
|
+
kinds,
|
|
59106
|
+
ownerParam
|
|
59107
|
+
]);
|
|
59108
|
+
const selectKind = (k) => {
|
|
59109
|
+
setOwner(k.owner);
|
|
59110
|
+
setKind(k.kind);
|
|
59111
|
+
};
|
|
59112
|
+
if (kindsQuery.isError) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ErrorBox, { message: kindsQuery.error instanceof Error ? kindsQuery.error.message : t("uiLibrary.recordEntries.kindsFailed", "Could not load entry kinds") });
|
|
59113
|
+
if (kindsQuery.isPending) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
59114
|
+
className: "flex justify-center py-10 text-foreground-subtle",
|
|
59115
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LoaderCircle, { className: "h-5 w-5 animate-spin" })
|
|
59116
|
+
});
|
|
59117
|
+
if (kinds.length === 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EmptyState, {
|
|
59118
|
+
title: t("uiLibrary.recordEntries.noKindsTitle", "No entry kinds"),
|
|
59119
|
+
description: t("uiLibrary.recordEntries.noKindsDescription", "No addon has declared an entry record kind yet.")
|
|
59120
|
+
});
|
|
59121
|
+
const activeKey = active === null ? "" : kindKey$1(active);
|
|
59122
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
59123
|
+
className: "space-y-4",
|
|
59124
|
+
children: [kinds.length > 1 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Tabs, {
|
|
59125
|
+
appearance: "pills",
|
|
59126
|
+
value: activeKey,
|
|
59127
|
+
onValueChange: (key) => {
|
|
59128
|
+
const found = kinds.find((k) => kindKey$1(k) === key);
|
|
59129
|
+
if (found !== void 0) selectKind(found);
|
|
59130
|
+
},
|
|
59131
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TabsList, {
|
|
59132
|
+
className: "flex flex-wrap gap-1",
|
|
59133
|
+
children: kinds.map((k) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(TabsTrigger, {
|
|
59134
|
+
value: kindKey$1(k),
|
|
59135
|
+
children: [k.title, k.rows > 0 ? ` (${k.rows})` : ""]
|
|
59136
|
+
}, kindKey$1(k)))
|
|
59137
|
+
})
|
|
59138
|
+
}), active !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [kinds.length === 1 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
|
|
59139
|
+
className: "mb-2 text-sm font-semibold text-foreground",
|
|
59140
|
+
children: active.title
|
|
59141
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RecordEntriesPanel, { kind: active })] })]
|
|
59142
|
+
});
|
|
59143
|
+
}
|
|
59144
|
+
//#endregion
|
|
59145
|
+
//#region src/composites/storage-records/storage-records-panel.tsx
|
|
59146
|
+
function StorageRecordsPanel({ kind }) {
|
|
59147
|
+
const t = useUiText();
|
|
59148
|
+
const [inspect, setInspect] = (0, react$1.useState)(null);
|
|
59149
|
+
const recordsQuery = trpc.storageAdmin.readRecords.useQuery({
|
|
59150
|
+
owner: kind.owner,
|
|
59151
|
+
kind: kind.kind,
|
|
59152
|
+
limit: 100,
|
|
59153
|
+
desc: true
|
|
59154
|
+
}, { staleTime: 15e3 });
|
|
59155
|
+
const records = recordsQuery.data?.records ?? [];
|
|
59156
|
+
const columns = (0, react$1.useMemo)(() => {
|
|
59157
|
+
return [
|
|
59158
|
+
{
|
|
59159
|
+
key: "id",
|
|
59160
|
+
header: t("uiLibrary.storageRecords.colId", "Id"),
|
|
59161
|
+
render: (row) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
59162
|
+
type: "button",
|
|
59163
|
+
variant: "ghost",
|
|
59164
|
+
size: "sm",
|
|
59165
|
+
className: "h-auto max-w-full justify-start px-0 py-0 font-mono text-xs hover:underline",
|
|
59166
|
+
onClick: () => setInspect(row),
|
|
59167
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
59168
|
+
className: "truncate",
|
|
59169
|
+
children: row.id
|
|
59170
|
+
})
|
|
59171
|
+
})
|
|
59172
|
+
},
|
|
59173
|
+
{
|
|
59174
|
+
key: "deviceId",
|
|
59175
|
+
header: t("uiLibrary.storageRecords.colDevice", "Device"),
|
|
59176
|
+
nowrap: true,
|
|
59177
|
+
render: (row) => row.deviceId === null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
59178
|
+
className: "text-foreground-subtle",
|
|
59179
|
+
children: "—"
|
|
59180
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
59181
|
+
className: "font-mono text-xs",
|
|
59182
|
+
children: row.deviceId
|
|
59183
|
+
})
|
|
59184
|
+
},
|
|
59185
|
+
{
|
|
59186
|
+
key: "at",
|
|
59187
|
+
header: t("uiLibrary.storageRecords.colAt", "At"),
|
|
59188
|
+
nowrap: true,
|
|
59189
|
+
render: (row) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
59190
|
+
className: "text-[11px] text-foreground-subtle",
|
|
59191
|
+
children: row.at === null ? "—" : new Date(row.at).toLocaleString()
|
|
59192
|
+
})
|
|
59193
|
+
},
|
|
59194
|
+
{
|
|
59195
|
+
key: "updatedAt",
|
|
59196
|
+
header: t("uiLibrary.storageRecords.colUpdated", "Updated"),
|
|
59197
|
+
nowrap: true,
|
|
59198
|
+
render: (row) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
59199
|
+
className: "text-[11px] text-foreground-subtle",
|
|
59200
|
+
children: new Date(row.updatedAt).toLocaleString()
|
|
59201
|
+
})
|
|
59202
|
+
}
|
|
59203
|
+
];
|
|
59204
|
+
}, [t]);
|
|
59205
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
59206
|
+
className: "space-y-3",
|
|
59207
|
+
children: [
|
|
59208
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
59209
|
+
className: "flex flex-wrap items-center gap-2",
|
|
59210
|
+
children: [
|
|
59211
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
|
|
59212
|
+
className: "text-sm font-semibold text-foreground",
|
|
59213
|
+
children: `${kind.owner}/${kind.kind}`
|
|
59214
|
+
}),
|
|
59215
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Badge, {
|
|
59216
|
+
variant: "neutral",
|
|
59217
|
+
style: "outline",
|
|
59218
|
+
children: kind.database
|
|
59219
|
+
}),
|
|
59220
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Badge, {
|
|
59221
|
+
variant: "neutral",
|
|
59222
|
+
style: "outline",
|
|
59223
|
+
children: kind.class
|
|
59224
|
+
}),
|
|
59225
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Badge, {
|
|
59226
|
+
variant: kind.state === "declared" ? "default" : "neutral",
|
|
59227
|
+
children: kind.state
|
|
59228
|
+
}),
|
|
59229
|
+
kind.entry ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Badge, {
|
|
59230
|
+
variant: "info",
|
|
59231
|
+
children: t("uiLibrary.storageRecords.entryKind", "Entry")
|
|
59232
|
+
}) : null
|
|
59233
|
+
]
|
|
59234
|
+
}),
|
|
59235
|
+
recordsQuery.isError ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ErrorBox, { message: recordsQuery.error instanceof Error ? recordsQuery.error.message : t("uiLibrary.storageRecords.loadFailed", "Could not load records") }) : recordsQuery.isPending ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
59236
|
+
className: "flex justify-center py-8 text-foreground-subtle",
|
|
59237
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LoaderCircle, { className: "h-5 w-5 animate-spin" })
|
|
59238
|
+
}) : records.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EmptyState, {
|
|
59239
|
+
title: t("uiLibrary.storageRecords.emptyTitle", "No rows"),
|
|
59240
|
+
description: t("uiLibrary.storageRecords.emptyDescription", "This kind has no stored records yet.")
|
|
59241
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DataTable, {
|
|
59242
|
+
columns,
|
|
59243
|
+
rows: records,
|
|
59244
|
+
rowKey: (r) => r.id,
|
|
59245
|
+
maxBodyHeight: TABLE_SCROLL_MAX_H,
|
|
59246
|
+
emptyMessage: t("uiLibrary.storageRecords.emptyTitle", "No rows")
|
|
59247
|
+
}),
|
|
59248
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Dialog, {
|
|
59249
|
+
open: inspect !== null,
|
|
59250
|
+
onOpenChange: (open) => !open && setInspect(null),
|
|
59251
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(DialogContent, {
|
|
59252
|
+
width: "lg",
|
|
59253
|
+
placement: "sheet-on-mobile",
|
|
59254
|
+
scroll: "body",
|
|
59255
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(DialogHeader, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(DialogTitle, { children: t("uiLibrary.storageRecords.inspectTitle", "Record") }), inspect !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DialogDescription, {
|
|
59256
|
+
className: "font-mono",
|
|
59257
|
+
children: inspect.id
|
|
59258
|
+
}) : null] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DialogBody, { children: inspect !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CodeBlock, {
|
|
59259
|
+
maxHeight: 480,
|
|
59260
|
+
children: JSON.stringify(inspect, null, 2)
|
|
59261
|
+
}) : null })]
|
|
59262
|
+
})
|
|
59263
|
+
})
|
|
59264
|
+
]
|
|
59265
|
+
});
|
|
59266
|
+
}
|
|
59267
|
+
//#endregion
|
|
59268
|
+
//#region src/composites/storage-records/storage-records-hub.tsx
|
|
59269
|
+
var STORAGE_RECORDS_OWNER_PARAM = "recordsOwner";
|
|
59270
|
+
var STORAGE_RECORDS_KIND_PARAM = "recordsKind";
|
|
59271
|
+
function kindKey(k) {
|
|
59272
|
+
return `${k.owner}/${k.kind}`;
|
|
59273
|
+
}
|
|
59274
|
+
function formatBytes(n) {
|
|
59275
|
+
if (n === null) return "—";
|
|
59276
|
+
if (n < 1024) return `${n} B`;
|
|
59277
|
+
if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)} KiB`;
|
|
59278
|
+
return `${(n / (1024 * 1024)).toFixed(1)} MiB`;
|
|
59279
|
+
}
|
|
59280
|
+
function StorageRecordsHub() {
|
|
59281
|
+
const t = useUiText();
|
|
59282
|
+
const kindsQuery = trpc.storageAdmin.listKinds.useQuery({}, { staleTime: 3e4 });
|
|
59283
|
+
const [ownerParam, setOwner] = useUrlQueryParam(STORAGE_RECORDS_OWNER_PARAM);
|
|
59284
|
+
const [kindParam, setKind] = useUrlQueryParam(STORAGE_RECORDS_KIND_PARAM);
|
|
59285
|
+
const kinds = kindsQuery.data?.kinds ?? [];
|
|
59286
|
+
const filter = useDataTableFilter(kinds, {
|
|
59287
|
+
searchText: (row) => [
|
|
59288
|
+
row.owner,
|
|
59289
|
+
row.kind,
|
|
59290
|
+
row.class,
|
|
59291
|
+
row.database,
|
|
59292
|
+
row.state
|
|
59293
|
+
],
|
|
59294
|
+
facetGroups: [{
|
|
59295
|
+
id: "owner",
|
|
59296
|
+
value: (row) => row.owner
|
|
59297
|
+
}, {
|
|
59298
|
+
id: "database",
|
|
59299
|
+
value: (row) => row.database
|
|
59300
|
+
}]
|
|
59301
|
+
});
|
|
59302
|
+
const active = (0, react$1.useMemo)(() => {
|
|
59303
|
+
if (kinds.length === 0) return null;
|
|
59304
|
+
return kinds.find((k) => k.owner === ownerParam && k.kind === kindParam) ?? null;
|
|
59305
|
+
}, [
|
|
59306
|
+
kindParam,
|
|
59307
|
+
kinds,
|
|
59308
|
+
ownerParam
|
|
59309
|
+
]);
|
|
59310
|
+
const selectKind = (0, react$1.useCallback)((k) => {
|
|
59311
|
+
setOwner(k.owner);
|
|
59312
|
+
setKind(k.kind);
|
|
59313
|
+
}, [setKind, setOwner]);
|
|
59314
|
+
const columns = (0, react$1.useMemo)(() => {
|
|
59315
|
+
return [
|
|
59316
|
+
{
|
|
59317
|
+
key: "kind",
|
|
59318
|
+
header: t("uiLibrary.storageRecords.colKind", "Kind"),
|
|
59319
|
+
render: (row) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
59320
|
+
className: "font-mono text-xs",
|
|
59321
|
+
children: [
|
|
59322
|
+
row.owner,
|
|
59323
|
+
"/",
|
|
59324
|
+
row.kind
|
|
59325
|
+
]
|
|
59326
|
+
}),
|
|
59327
|
+
sortValue: (row) => kindKey(row)
|
|
59328
|
+
},
|
|
59329
|
+
{
|
|
59330
|
+
key: "database",
|
|
59331
|
+
header: t("uiLibrary.storageRecords.colDatabase", "DB"),
|
|
59332
|
+
nowrap: true,
|
|
59333
|
+
render: (row) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Badge, {
|
|
59334
|
+
variant: "neutral",
|
|
59335
|
+
style: "outline",
|
|
59336
|
+
children: row.database
|
|
59337
|
+
}),
|
|
59338
|
+
sortValue: (row) => row.database
|
|
59339
|
+
},
|
|
59340
|
+
{
|
|
59341
|
+
key: "class",
|
|
59342
|
+
header: t("uiLibrary.storageRecords.colClass", "Class"),
|
|
59343
|
+
nowrap: true,
|
|
59344
|
+
render: (row) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
59345
|
+
className: "text-xs text-foreground-muted",
|
|
59346
|
+
children: row.class
|
|
59347
|
+
}),
|
|
59348
|
+
sortValue: (row) => row.class
|
|
59349
|
+
},
|
|
59350
|
+
{
|
|
59351
|
+
key: "state",
|
|
59352
|
+
header: t("uiLibrary.storageRecords.colState", "State"),
|
|
59353
|
+
nowrap: true,
|
|
59354
|
+
render: (row) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Badge, {
|
|
59355
|
+
variant: row.state === "declared" ? "default" : "neutral",
|
|
59356
|
+
children: row.state
|
|
59357
|
+
}),
|
|
59358
|
+
sortValue: (row) => row.state
|
|
59359
|
+
},
|
|
59360
|
+
{
|
|
59361
|
+
key: "rows",
|
|
59362
|
+
header: t("uiLibrary.storageRecords.colRows", "Rows"),
|
|
59363
|
+
align: "right",
|
|
59364
|
+
nowrap: true,
|
|
59365
|
+
render: (row) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
59366
|
+
className: "font-mono text-xs tabular-nums",
|
|
59367
|
+
children: row.rows === null ? "—" : row.rows
|
|
59368
|
+
}),
|
|
59369
|
+
sortValue: (row) => row.rows ?? -1
|
|
59370
|
+
},
|
|
59371
|
+
{
|
|
59372
|
+
key: "bytes",
|
|
59373
|
+
header: t("uiLibrary.storageRecords.colSize", "Est. size"),
|
|
59374
|
+
align: "right",
|
|
59375
|
+
nowrap: true,
|
|
59376
|
+
render: (row) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
59377
|
+
className: "text-xs text-foreground-subtle",
|
|
59378
|
+
children: formatBytes(row.bytesEstimate)
|
|
59379
|
+
}),
|
|
59380
|
+
sortValue: (row) => row.bytesEstimate ?? -1
|
|
59381
|
+
},
|
|
59382
|
+
{
|
|
59383
|
+
key: "inspect",
|
|
59384
|
+
header: "",
|
|
59385
|
+
align: "right",
|
|
59386
|
+
nowrap: true,
|
|
59387
|
+
render: (row) => {
|
|
59388
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
59389
|
+
type: "button",
|
|
59390
|
+
size: "sm",
|
|
59391
|
+
variant: active !== null && kindKey(active) === kindKey(row) ? "primary" : "outline",
|
|
59392
|
+
onClick: () => selectKind(row),
|
|
59393
|
+
children: t("uiLibrary.storageRecords.viewRows", "View rows")
|
|
59394
|
+
});
|
|
59395
|
+
},
|
|
59396
|
+
notSortableReason: t("uiLibrary.storageRecords.actionColumn", "Actions")
|
|
59397
|
+
}
|
|
59398
|
+
];
|
|
59399
|
+
}, [
|
|
59400
|
+
active,
|
|
59401
|
+
selectKind,
|
|
59402
|
+
t
|
|
59403
|
+
]);
|
|
59404
|
+
if (kindsQuery.isError) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ErrorBox, { message: kindsQuery.error instanceof Error ? kindsQuery.error.message : t("uiLibrary.storageRecords.kindsFailed", "Could not load record kinds") });
|
|
59405
|
+
if (kindsQuery.isPending) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
59406
|
+
className: "flex justify-center py-10 text-foreground-subtle",
|
|
59407
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LoaderCircle, { className: "h-5 w-5 animate-spin" })
|
|
59408
|
+
});
|
|
59409
|
+
if (kinds.length === 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EmptyState, {
|
|
59410
|
+
title: t("uiLibrary.storageRecords.noKindsTitle", "No record kinds"),
|
|
59411
|
+
description: t("uiLibrary.storageRecords.noKindsDescription", "No addon has declared a record kind on this hub yet.")
|
|
59412
|
+
});
|
|
59413
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
59414
|
+
className: "space-y-4",
|
|
59415
|
+
children: [
|
|
59416
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(DataTableFilterBar, {
|
|
59417
|
+
state: filter.state,
|
|
59418
|
+
facets: filter.facets,
|
|
59419
|
+
groups: filter.groups.map((g) => ({
|
|
59420
|
+
...g,
|
|
59421
|
+
label: g.id === "owner" ? t("uiLibrary.storageRecords.facetOwner", "Owner") : t("uiLibrary.storageRecords.facetDatabase", "Database")
|
|
59422
|
+
})),
|
|
59423
|
+
labels: {
|
|
59424
|
+
searchPlaceholder: t("uiLibrary.storageRecords.search", "Search kinds…"),
|
|
59425
|
+
searchLabel: t("uiLibrary.storageRecords.searchLabel", "Search record kinds"),
|
|
59426
|
+
facetsLabel: t("uiLibrary.storageRecords.facetsLabel", "Filter record kinds"),
|
|
59427
|
+
clearLabel: t("uiLibrary.storageRecords.clearFilters", "Clear filters")
|
|
59428
|
+
},
|
|
59429
|
+
onSearch: filter.setSearch,
|
|
59430
|
+
onToggleFacet: filter.toggleFacet,
|
|
59431
|
+
onToggleGroupFacet: filter.toggleGroupFacet,
|
|
59432
|
+
onClear: filter.clear
|
|
59433
|
+
}),
|
|
59434
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(DataTable, {
|
|
59435
|
+
columns,
|
|
59436
|
+
rows: filter.rows,
|
|
59437
|
+
rowKey: (k) => kindKey(k),
|
|
59438
|
+
maxBodyHeight: TABLE_SCROLL_MAX_H,
|
|
59439
|
+
defaultSort: {
|
|
59440
|
+
columnKey: "kind",
|
|
59441
|
+
dir: "asc"
|
|
59442
|
+
},
|
|
59443
|
+
emptyMessage: t("uiLibrary.storageRecords.noMatch", "No kinds match the filter")
|
|
59444
|
+
}),
|
|
59445
|
+
active !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(StorageRecordsPanel, { kind: active }) : null
|
|
59446
|
+
]
|
|
59447
|
+
});
|
|
59448
|
+
}
|
|
59449
|
+
//#endregion
|
|
58686
59450
|
//#region src/composites/response-log.tsx
|
|
58687
59451
|
/**
|
|
58688
59452
|
* Expandable log box showing the raw JSON response from a pipeline run.
|
|
@@ -63152,6 +63916,7 @@ exports.EllipsisVertical = EllipsisVertical;
|
|
|
63152
63916
|
exports.EmptyState = EmptyState;
|
|
63153
63917
|
exports.EndpointResultsCard = EndpointResultsCard;
|
|
63154
63918
|
exports.EndpointTestCard = EndpointTestCard;
|
|
63919
|
+
exports.EntryJsonSchemaForm = EntryJsonSchemaForm;
|
|
63155
63920
|
exports.ErrorBox = ErrorBox;
|
|
63156
63921
|
exports.EventKindGlyph = EventKindGlyph;
|
|
63157
63922
|
exports.EventStream = EventStream;
|
|
@@ -63339,6 +64104,8 @@ exports.QrCode = QrCode;
|
|
|
63339
64104
|
exports.QrCode$1 = QrCode$1;
|
|
63340
64105
|
exports.RECONNECT_POLICY = RECONNECT_POLICY;
|
|
63341
64106
|
exports.RECORDED_PLAYBACK_MODES = RECORDED_PLAYBACK_MODES;
|
|
64107
|
+
exports.RECORD_ENTRY_KIND_PARAM = RECORD_ENTRY_KIND_PARAM;
|
|
64108
|
+
exports.RECORD_ENTRY_OWNER_PARAM = RECORD_ENTRY_OWNER_PARAM;
|
|
63342
64109
|
exports.RIGHT = RIGHT;
|
|
63343
64110
|
exports.ROI_AREA_WARN_FRACTION = ROI_AREA_WARN_FRACTION;
|
|
63344
64111
|
exports.ROLE_DESCRIPTOR = ROLE_DESCRIPTOR;
|
|
@@ -63347,6 +64114,8 @@ exports.Radar = Radar;
|
|
|
63347
64114
|
exports.RadialGauge = RadialGauge;
|
|
63348
64115
|
exports.Radio = Radio;
|
|
63349
64116
|
exports.RadioTower = RadioTower;
|
|
64117
|
+
exports.RecordEntriesHub = RecordEntriesHub;
|
|
64118
|
+
exports.RecordEntriesPanel = RecordEntriesPanel;
|
|
63350
64119
|
exports.RecordedPlaybackProvider = RecordedPlaybackProvider;
|
|
63351
64120
|
exports.RecordingPanel = RecordingPanel;
|
|
63352
64121
|
exports.RefreshCw = RefreshCw;
|
|
@@ -63379,6 +64148,8 @@ exports.SPLIT_PANEL_SIDE = SPLIT_PANEL_SIDE;
|
|
|
63379
64148
|
exports.STACK_GAP = STACK_GAP;
|
|
63380
64149
|
exports.STATE_COLOR = STATE_COLOR;
|
|
63381
64150
|
exports.STEP_DOCK_WIDTH_PX = STEP_DOCK_WIDTH_PX;
|
|
64151
|
+
exports.STORAGE_RECORDS_KIND_PARAM = STORAGE_RECORDS_KIND_PARAM;
|
|
64152
|
+
exports.STORAGE_RECORDS_OWNER_PARAM = STORAGE_RECORDS_OWNER_PARAM;
|
|
63382
64153
|
exports.Sailboat = Sailboat;
|
|
63383
64154
|
exports.Save = Save;
|
|
63384
64155
|
exports.Scan = Scan;
|
|
@@ -63437,6 +64208,8 @@ exports.StepInspectorPanel = StepInspectorPanel;
|
|
|
63437
64208
|
exports.StepModelRow = StepModelRow;
|
|
63438
64209
|
exports.StepTimings = StepTimings;
|
|
63439
64210
|
exports.Stepper = Stepper;
|
|
64211
|
+
exports.StorageRecordsHub = StorageRecordsHub;
|
|
64212
|
+
exports.StorageRecordsPanel = StorageRecordsPanel;
|
|
63440
64213
|
exports.StreamBrokerSelector = StreamBrokerSelector;
|
|
63441
64214
|
exports.StreamDebugOverlay = StreamDebugOverlay;
|
|
63442
64215
|
exports.StreamPanel = StreamPanel;
|
|
@@ -63629,6 +64402,8 @@ exports.isDataTableFilterActive = isDataTableFilterActive;
|
|
|
63629
64402
|
exports.isFieldVisible = isFieldVisible;
|
|
63630
64403
|
exports.isGroupExpanded = isGroupExpanded;
|
|
63631
64404
|
exports.isKeychainFieldValue = isKeychainFieldValue;
|
|
64405
|
+
exports.isRedactedSecret = isRedactedSecret;
|
|
64406
|
+
exports.isSecretField = isSecretField;
|
|
63632
64407
|
exports.isValueField = isValueField;
|
|
63633
64408
|
exports.lawnMowerActivityMeta = lawnMowerActivityMeta;
|
|
63634
64409
|
exports.lightColors = require_theme_to_root_css.lightColors;
|
|
@@ -63637,6 +64412,7 @@ exports.loadRemoteBundle = loadRemoteBundle;
|
|
|
63637
64412
|
exports.lucideExportName = lucideExportName;
|
|
63638
64413
|
exports.makeScrubBridge = makeScrubBridge;
|
|
63639
64414
|
exports.mapRootDetectorPlacements = mapRootDetectorPlacements;
|
|
64415
|
+
exports.mergeSecretForSubmit = mergeSecretForSubmit;
|
|
63640
64416
|
exports.metadataEntries = metadataEntries;
|
|
63641
64417
|
exports.metadataString = metadataString;
|
|
63642
64418
|
exports.mirror = mirror;
|
|
@@ -63709,6 +64485,7 @@ exports.routerBasename = routerBasename;
|
|
|
63709
64485
|
exports.sameLocationSuggestions = sameLocationSuggestions;
|
|
63710
64486
|
exports.scrubReducer = scrubReducer;
|
|
63711
64487
|
exports.searchSteps = searchSteps;
|
|
64488
|
+
exports.secretDisplayValue = secretDisplayValue;
|
|
63712
64489
|
exports.secretSubmitValue = secretSubmitValue;
|
|
63713
64490
|
exports.selectPickerGroup = selectPickerGroup;
|
|
63714
64491
|
exports.selectedDeviceOptions = selectedDeviceOptions;
|