@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/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;