@camstack/ui-library 1.2.297 → 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/index.cjs CHANGED
@@ -12001,6 +12001,14 @@ var usePtzAutotrackGetSettings = trpc.ptzAutotrack.getSettings.useQuery;
12001
12001
  var usePtzAutotrackSetSettings = trpc.ptzAutotrack.setSettings.useMutation;
12002
12002
  /** Generated alias around `trpc.reboot.reboot.useMutation`. */
12003
12003
  var useRebootReboot = trpc.reboot.reboot.useMutation;
12004
+ /** Generated alias around `trpc.recordEntries.listEntryKinds.useQuery`. */
12005
+ var useRecordEntriesListEntryKinds = trpc.recordEntries.listEntryKinds.useQuery;
12006
+ /** Generated alias around `trpc.recordEntries.listEntries.useQuery`. */
12007
+ var useRecordEntriesListEntries = trpc.recordEntries.listEntries.useQuery;
12008
+ /** Generated alias around `trpc.recordEntries.putEntry.useMutation`. */
12009
+ var useRecordEntriesPutEntry = trpc.recordEntries.putEntry.useMutation;
12010
+ /** Generated alias around `trpc.recordEntries.deleteEntry.useMutation`. */
12011
+ var useRecordEntriesDeleteEntry = trpc.recordEntries.deleteEntry.useMutation;
12004
12012
  /** Generated alias around `trpc.recording.listSources.useQuery`. */
12005
12013
  var useRecordingListSources = trpc.recording.listSources.useQuery;
12006
12014
  /** Generated alias around `trpc.recording.getAvailability.useQuery`. */
@@ -14127,7 +14135,7 @@ function ConfigNotificationTargetMultiSelectFieldView({ field, value, onChange,
14127
14135
  const kindsQuery = useNotificationOutputListTargetKinds({});
14128
14136
  const targets = (0, react$1.useMemo)(() => toTargetOptions(targetsQuery.data), [targetsQuery.data]);
14129
14137
  const kindIconUrls = (0, react$1.useMemo)(() => buildKindIconMap(kindsQuery.data), [kindsQuery.data]);
14130
- 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] : [];
14131
14139
  const pending = targetsQuery.isPending || kindsQuery.isPending;
14132
14140
  const error = targetsQuery.isError ? targetsQuery.error : kindsQuery.isError ? kindsQuery.error : null;
14133
14141
  if (pending) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FieldShell, {
@@ -19490,11 +19498,11 @@ function useDeviceSnapshotImage(deviceId, options = {}) {
19490
19498
  //#region src/composites/cap-settings/camera-grid-layout.ts
19491
19499
  /** Smallest rectangle the editor will produce — ffmpeg refuses a zero-area crop. */
19492
19500
  var MIN_EXTENT = .02;
19493
- function isRecord(value) {
19501
+ function isRecord$2(value) {
19494
19502
  return value !== null && typeof value === "object" && !Array.isArray(value);
19495
19503
  }
19496
19504
  function readRect(value) {
19497
- if (!isRecord(value)) return null;
19505
+ if (!isRecord$2(value)) return null;
19498
19506
  const { x, y, width, height } = value;
19499
19507
  if (typeof x !== "number" || typeof y !== "number" || typeof width !== "number" || typeof height !== "number") return null;
19500
19508
  if (x < 0 || y < 0 || width <= 0 || height <= 0) return null;
@@ -19507,7 +19515,7 @@ function readRect(value) {
19507
19515
  };
19508
19516
  }
19509
19517
  function readCell(value) {
19510
- if (!isRecord(value)) return null;
19518
+ if (!isRecord$2(value)) return null;
19511
19519
  const deviceId = value["deviceId"];
19512
19520
  if (typeof deviceId !== "number" || !Number.isInteger(deviceId)) return null;
19513
19521
  const source = readRect(value["source"]);
@@ -19520,7 +19528,7 @@ function readCell(value) {
19520
19528
  };
19521
19529
  }
19522
19530
  function readProfileOffer(value) {
19523
- if (!isRecord(value)) return null;
19531
+ if (!isRecord$2(value)) return null;
19524
19532
  const profile = value["profile"];
19525
19533
  const offered = value["offered"];
19526
19534
  const missing = value["missingSources"];
@@ -19549,7 +19557,7 @@ function readProfileOffer(value) {
19549
19557
  */
19550
19558
  function parseGridView(raw) {
19551
19559
  if (raw === null) return null;
19552
- if (!isRecord(raw)) return "unreadable";
19560
+ if (!isRecord$2(raw)) return "unreadable";
19553
19561
  const { instanceId, deviceId, name, fps, cells, profiles } = raw;
19554
19562
  if (typeof instanceId !== "string" || typeof deviceId !== "number" || typeof name !== "string" || typeof fps !== "number" || !Array.isArray(cells) || !Array.isArray(profiles)) return "unreadable";
19555
19563
  const parsed = [];
@@ -25706,7 +25714,7 @@ function mergeAvailabilitySpans(ranges) {
25706
25714
  * significant digits (binary prefixes, matching recording sizes elsewhere).
25707
25715
  * KB and up render one decimal under 100, none above; bytes never get a decimal.
25708
25716
  */
25709
- function formatBytes(bytes) {
25717
+ function formatBytes$1(bytes) {
25710
25718
  if (!Number.isFinite(bytes) || bytes < 0) return "—";
25711
25719
  if (bytes < 1024) return `${Math.round(bytes)} B`;
25712
25720
  const units = [
@@ -26239,7 +26247,7 @@ function RecordingPanel({ deviceId }) {
26239
26247
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(WidgetMetricCard, {
26240
26248
  label: t("uiLibrary.recordingPanel.storage", "Storage"),
26241
26249
  icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(HardDrive, { className: "h-3.5 w-3.5" }),
26242
- children: status ? formatBytes(status.storageBytes) : "—"
26250
+ children: status ? formatBytes$1(status.storageBytes) : "—"
26243
26251
  }),
26244
26252
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(WidgetMetricCard, {
26245
26253
  label: t("uiLibrary.recordingPanel.recorded24h", "Recorded (24h)"),
@@ -29600,17 +29608,7 @@ function applyValuesToSchema(schema, nextValues) {
29600
29608
  };
29601
29609
  }
29602
29610
  function stripValues(schema) {
29603
- return {
29604
- ...schema,
29605
- sections: schema.sections.map((s) => ({
29606
- ...s,
29607
- fields: s.fields.map((f) => {
29608
- if (!isValueBearingField(f)) return f;
29609
- const { value: _drop, ...rest } = f;
29610
- return rest;
29611
- })
29612
- }))
29613
- };
29611
+ return (0, _camstack_types.dehydrateSchema)(schema);
29614
29612
  }
29615
29613
  function AddonGlobalSettingsForm({ trpc, addonId, nodeId, title, disabled, onAfterChange, refreshToken, sectionIds, bare = false, collapsible, defaultOpen, mode, onOverrideChange }) {
29616
29614
  const t = useUiText();
@@ -58675,6 +58673,780 @@ function EntryIcon({ url }) {
58675
58673
  });
58676
58674
  }
58677
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
58678
59450
  //#region src/composites/response-log.tsx
58679
59451
  /**
58680
59452
  * Expandable log box showing the raw JSON response from a pipeline run.
@@ -63144,6 +63916,7 @@ exports.EllipsisVertical = EllipsisVertical;
63144
63916
  exports.EmptyState = EmptyState;
63145
63917
  exports.EndpointResultsCard = EndpointResultsCard;
63146
63918
  exports.EndpointTestCard = EndpointTestCard;
63919
+ exports.EntryJsonSchemaForm = EntryJsonSchemaForm;
63147
63920
  exports.ErrorBox = ErrorBox;
63148
63921
  exports.EventKindGlyph = EventKindGlyph;
63149
63922
  exports.EventStream = EventStream;
@@ -63331,6 +64104,8 @@ exports.QrCode = QrCode;
63331
64104
  exports.QrCode$1 = QrCode$1;
63332
64105
  exports.RECONNECT_POLICY = RECONNECT_POLICY;
63333
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;
63334
64109
  exports.RIGHT = RIGHT;
63335
64110
  exports.ROI_AREA_WARN_FRACTION = ROI_AREA_WARN_FRACTION;
63336
64111
  exports.ROLE_DESCRIPTOR = ROLE_DESCRIPTOR;
@@ -63339,6 +64114,8 @@ exports.Radar = Radar;
63339
64114
  exports.RadialGauge = RadialGauge;
63340
64115
  exports.Radio = Radio;
63341
64116
  exports.RadioTower = RadioTower;
64117
+ exports.RecordEntriesHub = RecordEntriesHub;
64118
+ exports.RecordEntriesPanel = RecordEntriesPanel;
63342
64119
  exports.RecordedPlaybackProvider = RecordedPlaybackProvider;
63343
64120
  exports.RecordingPanel = RecordingPanel;
63344
64121
  exports.RefreshCw = RefreshCw;
@@ -63371,6 +64148,8 @@ exports.SPLIT_PANEL_SIDE = SPLIT_PANEL_SIDE;
63371
64148
  exports.STACK_GAP = STACK_GAP;
63372
64149
  exports.STATE_COLOR = STATE_COLOR;
63373
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;
63374
64153
  exports.Sailboat = Sailboat;
63375
64154
  exports.Save = Save;
63376
64155
  exports.Scan = Scan;
@@ -63429,6 +64208,8 @@ exports.StepInspectorPanel = StepInspectorPanel;
63429
64208
  exports.StepModelRow = StepModelRow;
63430
64209
  exports.StepTimings = StepTimings;
63431
64210
  exports.Stepper = Stepper;
64211
+ exports.StorageRecordsHub = StorageRecordsHub;
64212
+ exports.StorageRecordsPanel = StorageRecordsPanel;
63432
64213
  exports.StreamBrokerSelector = StreamBrokerSelector;
63433
64214
  exports.StreamDebugOverlay = StreamDebugOverlay;
63434
64215
  exports.StreamPanel = StreamPanel;
@@ -63621,6 +64402,8 @@ exports.isDataTableFilterActive = isDataTableFilterActive;
63621
64402
  exports.isFieldVisible = isFieldVisible;
63622
64403
  exports.isGroupExpanded = isGroupExpanded;
63623
64404
  exports.isKeychainFieldValue = isKeychainFieldValue;
64405
+ exports.isRedactedSecret = isRedactedSecret;
64406
+ exports.isSecretField = isSecretField;
63624
64407
  exports.isValueField = isValueField;
63625
64408
  exports.lawnMowerActivityMeta = lawnMowerActivityMeta;
63626
64409
  exports.lightColors = require_theme_to_root_css.lightColors;
@@ -63629,6 +64412,7 @@ exports.loadRemoteBundle = loadRemoteBundle;
63629
64412
  exports.lucideExportName = lucideExportName;
63630
64413
  exports.makeScrubBridge = makeScrubBridge;
63631
64414
  exports.mapRootDetectorPlacements = mapRootDetectorPlacements;
64415
+ exports.mergeSecretForSubmit = mergeSecretForSubmit;
63632
64416
  exports.metadataEntries = metadataEntries;
63633
64417
  exports.metadataString = metadataString;
63634
64418
  exports.mirror = mirror;
@@ -63701,6 +64485,7 @@ exports.routerBasename = routerBasename;
63701
64485
  exports.sameLocationSuggestions = sameLocationSuggestions;
63702
64486
  exports.scrubReducer = scrubReducer;
63703
64487
  exports.searchSteps = searchSteps;
64488
+ exports.secretDisplayValue = secretDisplayValue;
63704
64489
  exports.secretSubmitValue = secretSubmitValue;
63705
64490
  exports.selectPickerGroup = selectPickerGroup;
63706
64491
  exports.selectedDeviceOptions = selectedDeviceOptions;
@@ -64692,6 +65477,10 @@ exports.usePtzSetHomePreset = usePtzSetHomePreset;
64692
65477
  exports.usePtzSetHomeReturn = usePtzSetHomeReturn;
64693
65478
  exports.usePtzStop = usePtzStop;
64694
65479
  exports.useRebootReboot = useRebootReboot;
65480
+ exports.useRecordEntriesDeleteEntry = useRecordEntriesDeleteEntry;
65481
+ exports.useRecordEntriesListEntries = useRecordEntriesListEntries;
65482
+ exports.useRecordEntriesListEntryKinds = useRecordEntriesListEntryKinds;
65483
+ exports.useRecordEntriesPutEntry = useRecordEntriesPutEntry;
64695
65484
  exports.useRecordedPlayback = useRecordedPlayback;
64696
65485
  exports.useRecordingArchiveApplyDeviceSettingsPatch = useRecordingArchiveApplyDeviceSettingsPatch;
64697
65486
  exports.useRecordingArchiveCancelRelocateJob = useRecordingArchiveCancelRelocateJob;