@camstack/ui-library 1.2.301 → 1.2.303
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/data-records/data-records-hub.d.ts +9 -0
- package/dist/composites/data-records/data-records-model.d.ts +26 -0
- package/dist/composites/data-records/index.d.ts +2 -0
- package/dist/composites/data-table-filter-bar.d.ts +6 -0
- package/dist/composites/data-table.d.ts +11 -2
- package/dist/composites/device-controls/dishwasher-control.d.ts +14 -2
- package/dist/composites/index.d.ts +1 -0
- package/dist/composites/record-entries/index.d.ts +0 -1
- package/dist/composites/record-entries/record-entries-panel.d.ts +15 -3
- package/dist/composites/storage-records/index.d.ts +0 -1
- package/dist/generated/system-hooks.d.ts +6 -0
- package/dist/index.cjs +530 -369
- package/dist/index.js +519 -364
- package/package.json +1 -1
- package/dist/composites/record-entries/record-entries-hub.d.ts +0 -9
- package/dist/composites/storage-records/storage-records-hub.d.ts +0 -4
package/dist/index.cjs
CHANGED
|
@@ -11016,6 +11016,8 @@ var useDeviceStatusGetStatus = trpc.deviceStatus.getStatus.useQuery;
|
|
|
11016
11016
|
var useDishwasherStart = trpc.dishwasher.start.useMutation;
|
|
11017
11017
|
/** Generated alias around `trpc.dishwasher.pause.useMutation`. */
|
|
11018
11018
|
var useDishwasherPause = trpc.dishwasher.pause.useMutation;
|
|
11019
|
+
/** Generated alias around `trpc.dishwasher.resume.useMutation`. */
|
|
11020
|
+
var useDishwasherResume = trpc.dishwasher.resume.useMutation;
|
|
11019
11021
|
/** Generated alias around `trpc.dishwasher.stop.useMutation`. */
|
|
11020
11022
|
var useDishwasherStop = trpc.dishwasher.stop.useMutation;
|
|
11021
11023
|
/** Generated alias around `trpc.dishwasher.setProgram.useMutation`. */
|
|
@@ -11036,6 +11038,8 @@ var useDishwasherSetVarioSpeedPlus = trpc.dishwasher.setVarioSpeedPlus.useMutati
|
|
|
11036
11038
|
var useDishwasherSetChildLock = trpc.dishwasher.setChildLock.useMutation;
|
|
11037
11039
|
/** Generated alias around `trpc.dishwasher.setOption.useMutation`. */
|
|
11038
11040
|
var useDishwasherSetOption = trpc.dishwasher.setOption.useMutation;
|
|
11041
|
+
/** Generated alias around `trpc.dishwasher.getOptions.useQuery`. */
|
|
11042
|
+
var useDishwasherGetOptions = trpc.dishwasher.getOptions.useQuery;
|
|
11039
11043
|
/** Generated alias around `trpc.dishwasher.getStatus.useQuery`. */
|
|
11040
11044
|
var useDishwasherGetStatus = trpc.dishwasher.getStatus.useQuery;
|
|
11041
11045
|
/** Generated alias around `trpc.doorbell.getStatus.useQuery`. */
|
|
@@ -12362,6 +12366,8 @@ var useStorageMigrationStatus = trpc.storageMigration.status.useQuery;
|
|
|
12362
12366
|
var useStorageMigrationCancel = trpc.storageMigration.cancel.useMutation;
|
|
12363
12367
|
/** Generated alias around `trpc.storageMigration.movers.useQuery`. */
|
|
12364
12368
|
var useStorageMigrationMovers = trpc.storageMigration.movers.useQuery;
|
|
12369
|
+
/** Generated alias around `trpc.storageMigration.moverClearance.useQuery`. */
|
|
12370
|
+
var useStorageMigrationMoverClearance = trpc.storageMigration.moverClearance.useQuery;
|
|
12365
12371
|
/** Generated alias around `trpc.storageMigration.residue.useQuery`. */
|
|
12366
12372
|
var useStorageMigrationResidue = trpc.storageMigration.residue.useQuery;
|
|
12367
12373
|
/** Generated alias around `trpc.storageMigration.drain.useMutation`. */
|
|
@@ -28588,7 +28594,7 @@ var STATUS_DOT_STYLES = {
|
|
|
28588
28594
|
idle: "bg-foreground-subtle/40",
|
|
28589
28595
|
unknown: "bg-foreground-subtle/40"
|
|
28590
28596
|
};
|
|
28591
|
-
function formatDuration(ms) {
|
|
28597
|
+
function formatDuration$1(ms) {
|
|
28592
28598
|
if (!Number.isFinite(ms) || ms < 0) return "—";
|
|
28593
28599
|
if (ms < 1e3) return `${ms}ms`;
|
|
28594
28600
|
const totalSec = Math.round(ms / 1e3);
|
|
@@ -28616,7 +28622,7 @@ function ObjectArrayCell({ kind, value }) {
|
|
|
28616
28622
|
});
|
|
28617
28623
|
if (kind === "duration" && typeof value === "number") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
28618
28624
|
className: "font-mono text-[11px]",
|
|
28619
|
-
children: formatDuration(value)
|
|
28625
|
+
children: formatDuration$1(value)
|
|
28620
28626
|
});
|
|
28621
28627
|
if (kind === "timestamp" && typeof value === "number") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
28622
28628
|
className: "font-mono text-[11px]",
|
|
@@ -35116,7 +35122,7 @@ var ALIGN_CLASS = {
|
|
|
35116
35122
|
right: "text-right",
|
|
35117
35123
|
center: "text-center"
|
|
35118
35124
|
};
|
|
35119
|
-
function DataTable({ columns, rows, rowKey, onRowClick, minWidthPx = 480, emptyMessage, className, bordered = true, rowClassName, maxBodyHeight, fill = false, defaultSort, sort: sortProp, onSortChange, pageSize, page: pageProp, onPageChange, paginationLabels = DEFAULT_PAGINATION_LABELS, selection }) {
|
|
35125
|
+
function DataTable({ columns, rows, rowKey, onRowClick, minWidthPx = 480, emptyMessage, className, bordered = true, rowClassName, maxBodyHeight, fill = false, defaultSort, sort: sortProp, onSortChange, pageSize, page: pageProp, onPageChange, paginationLabels = DEFAULT_PAGINATION_LABELS, selection, renderExpanded, isExpanded }) {
|
|
35120
35126
|
const [innerSort, setInnerSort] = (0, react$1.useState)(defaultSort ?? null);
|
|
35121
35127
|
const [innerPage, setInnerPage] = (0, react$1.useState)(0);
|
|
35122
35128
|
const sort = sortProp !== void 0 ? sortProp : innerSort;
|
|
@@ -35193,7 +35199,8 @@ function DataTable({ columns, rows, rowKey, onRowClick, minWidthPx = 480, emptyM
|
|
|
35193
35199
|
const key = rowKey ? rowKey(row, rowIndex) : rowIndex;
|
|
35194
35200
|
const extra = rowClassName?.(row, rowIndex) ?? "";
|
|
35195
35201
|
const interactive = onRowClick !== void 0;
|
|
35196
|
-
|
|
35202
|
+
const detail = renderExpanded !== void 0 && isExpanded?.(row) === true ? renderExpanded(row, rowIndex) : null;
|
|
35203
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react$1.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("tr", {
|
|
35197
35204
|
onClick: interactive ? () => onRowClick(row, rowIndex) : void 0,
|
|
35198
35205
|
className: [interactive ? "cursor-pointer hover:bg-primary/5" : "hover:bg-primary/5", extra].filter(Boolean).join(" "),
|
|
35199
35206
|
children: shownColumns.map((col) => {
|
|
@@ -35209,7 +35216,15 @@ function DataTable({ columns, rows, rowKey, onRowClick, minWidthPx = 480, emptyM
|
|
|
35209
35216
|
children: col.render(row, rowIndex)
|
|
35210
35217
|
}, col.key);
|
|
35211
35218
|
})
|
|
35212
|
-
},
|
|
35219
|
+
}), detail !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("tr", {
|
|
35220
|
+
"data-expanded-row": "",
|
|
35221
|
+
className: "bg-surface",
|
|
35222
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
|
|
35223
|
+
colSpan: shownColumns.length,
|
|
35224
|
+
className: "border-b border-border px-3 py-2",
|
|
35225
|
+
children: detail
|
|
35226
|
+
})
|
|
35227
|
+
})] }, key);
|
|
35213
35228
|
}) })]
|
|
35214
35229
|
})
|
|
35215
35230
|
});
|
|
@@ -37773,6 +37788,88 @@ function filterDataTableRows(rows, state, config) {
|
|
|
37773
37788
|
});
|
|
37774
37789
|
}
|
|
37775
37790
|
//#endregion
|
|
37791
|
+
//#region src/composites/device-list/multi-select.tsx
|
|
37792
|
+
/**
|
|
37793
|
+
* Compact multi-select dropdown — a single chip-sized trigger ("Label · N")
|
|
37794
|
+
* that opens a checklist. Self-contained (outside-click / Escape dismiss), so
|
|
37795
|
+
* it stays compressed regardless of how many options exist or how little
|
|
37796
|
+
* horizontal room the container has. Shared by the device list's generic-mode
|
|
37797
|
+
* type filter and any other multi-select needs.
|
|
37798
|
+
*/
|
|
37799
|
+
function MultiSelectDropdown({ label, options, selected, onChange }) {
|
|
37800
|
+
const t = useUiText();
|
|
37801
|
+
const [open, setOpen] = (0, react$1.useState)(false);
|
|
37802
|
+
const rootRef = (0, react$1.useRef)(null);
|
|
37803
|
+
(0, react$1.useEffect)(() => {
|
|
37804
|
+
if (!open) return;
|
|
37805
|
+
const onOutside = (e) => {
|
|
37806
|
+
const target = e.target instanceof Node ? e.target : null;
|
|
37807
|
+
if (target && rootRef.current && !rootRef.current.contains(target)) setOpen(false);
|
|
37808
|
+
};
|
|
37809
|
+
const onKey = (e) => {
|
|
37810
|
+
if (e.key === "Escape") setOpen(false);
|
|
37811
|
+
};
|
|
37812
|
+
document.addEventListener("mousedown", onOutside);
|
|
37813
|
+
document.addEventListener("touchstart", onOutside);
|
|
37814
|
+
document.addEventListener("keydown", onKey);
|
|
37815
|
+
return () => {
|
|
37816
|
+
document.removeEventListener("mousedown", onOutside);
|
|
37817
|
+
document.removeEventListener("touchstart", onOutside);
|
|
37818
|
+
document.removeEventListener("keydown", onKey);
|
|
37819
|
+
};
|
|
37820
|
+
}, [open]);
|
|
37821
|
+
const selectedSet = new Set(selected);
|
|
37822
|
+
const count = selected.length;
|
|
37823
|
+
const toggle = (id) => {
|
|
37824
|
+
const next = new Set(selectedSet);
|
|
37825
|
+
if (next.has(id)) next.delete(id);
|
|
37826
|
+
else next.add(id);
|
|
37827
|
+
onChange(options.filter((o) => next.has(o.id)).map((o) => o.id));
|
|
37828
|
+
};
|
|
37829
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
37830
|
+
ref: rootRef,
|
|
37831
|
+
className: "relative",
|
|
37832
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
37833
|
+
type: "button",
|
|
37834
|
+
onClick: () => setOpen((v) => !v),
|
|
37835
|
+
"aria-haspopup": "listbox",
|
|
37836
|
+
"aria-expanded": open,
|
|
37837
|
+
className: `inline-flex items-center gap-1.5 h-7 px-2.5 rounded-full border text-[10.5px] font-medium transition-colors ${count > 0 ? "border-primary/40 bg-primary/15 text-primary" : "border-border bg-surface text-foreground-subtle hover:text-foreground hover:bg-surface-hover"}`,
|
|
37838
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [label, count > 0 ? ` · ${String(count)}` : ""] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChevronDown, { className: `h-3 w-3 transition-transform ${open ? "rotate-180" : ""}` })]
|
|
37839
|
+
}), open && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
37840
|
+
role: "listbox",
|
|
37841
|
+
className: "absolute left-0 top-full mt-1 z-30 min-w-[180px] max-h-72 overflow-y-auto rounded-lg border border-border bg-surface shadow-xl py-1",
|
|
37842
|
+
children: [count > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
37843
|
+
type: "button",
|
|
37844
|
+
onClick: () => onChange([]),
|
|
37845
|
+
className: "flex w-full items-center px-3 py-1.5 text-left text-[10.5px] text-foreground-subtle hover:bg-surface-hover hover:text-foreground",
|
|
37846
|
+
children: t("uiLibrary.multiSelect.clear", "Clear selection")
|
|
37847
|
+
}), options.map((o) => {
|
|
37848
|
+
const active = selectedSet.has(o.id);
|
|
37849
|
+
const Icon = o.icon;
|
|
37850
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
37851
|
+
type: "button",
|
|
37852
|
+
role: "option",
|
|
37853
|
+
"aria-selected": active,
|
|
37854
|
+
onClick: () => toggle(o.id),
|
|
37855
|
+
className: "flex w-full items-center gap-2 px-3 py-1.5 text-left text-[10.5px] text-foreground hover:bg-surface-hover",
|
|
37856
|
+
children: [
|
|
37857
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
37858
|
+
className: `flex h-3.5 w-3.5 items-center justify-center rounded border shrink-0 ${active ? "border-primary bg-primary" : "border-border"}`,
|
|
37859
|
+
children: active && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Check, { className: "h-2.5 w-2.5 text-primary-foreground" })
|
|
37860
|
+
}),
|
|
37861
|
+
Icon && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, { className: "h-3.5 w-3.5 shrink-0 text-foreground-subtle" }),
|
|
37862
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
37863
|
+
className: "truncate",
|
|
37864
|
+
children: o.label
|
|
37865
|
+
})
|
|
37866
|
+
]
|
|
37867
|
+
}, o.id);
|
|
37868
|
+
})]
|
|
37869
|
+
})]
|
|
37870
|
+
});
|
|
37871
|
+
}
|
|
37872
|
+
//#endregion
|
|
37776
37873
|
//#region src/composites/data-table-filter-bar.tsx
|
|
37777
37874
|
/**
|
|
37778
37875
|
* The controls of one table's filter: a search box and the facet chips.
|
|
@@ -37825,7 +37922,18 @@ function DataTableFilterBar({ state, facets, labels, onSearch, onToggleFacet, on
|
|
|
37825
37922
|
}, facet.value);
|
|
37826
37923
|
})
|
|
37827
37924
|
}),
|
|
37828
|
-
groups.filter((group) => group.facets.length > 1).map((group) => /* @__PURE__ */ (0, react_jsx_runtime.
|
|
37925
|
+
groups.filter((group) => group.facets.length > 1).map((group) => group.display === "menu" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MultiSelectDropdown, {
|
|
37926
|
+
label: group.label,
|
|
37927
|
+
options: group.facets.map((facet) => ({
|
|
37928
|
+
id: facet.value,
|
|
37929
|
+
label: `${group.facetLabel ? group.facetLabel(facet.value) : facet.value} (${String(facet.count)})`
|
|
37930
|
+
})),
|
|
37931
|
+
selected: group.selected,
|
|
37932
|
+
onChange: (next) => {
|
|
37933
|
+
const chosen = new Set(next);
|
|
37934
|
+
for (const facet of group.facets) if (chosen.has(facet.value) !== group.selected.includes(facet.value)) onToggleGroupFacet?.(group.id, facet.value);
|
|
37935
|
+
}
|
|
37936
|
+
}, group.id) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
37829
37937
|
role: "group",
|
|
37830
37938
|
"aria-label": group.label,
|
|
37831
37939
|
className: "flex flex-wrap items-center gap-1",
|
|
@@ -48689,47 +48797,95 @@ function PetFeederHeroCard({ trpc, deviceId, features, optimistic }) {
|
|
|
48689
48797
|
*
|
|
48690
48798
|
* Reads the `dishwasher` cap status slice and renders inline + hero surfaces
|
|
48691
48799
|
* mirroring vacuum-control / pet-feeder patterns.
|
|
48800
|
+
*
|
|
48801
|
+
* UNKNOWN IS NOT OFF. The slice carries `null` for everything the appliance has not
|
|
48802
|
+
* reported, and this view renders that as "—" / a disabled control, never as an unchecked
|
|
48803
|
+
* box or a zero. It also does not echo a command before the appliance confirms it: the
|
|
48804
|
+
* slice moves when the appliance says so.
|
|
48692
48805
|
*/
|
|
48693
|
-
|
|
48694
|
-
|
|
48695
|
-
|
|
48696
|
-
|
|
48806
|
+
/** What the operation state is called to a person, and how it is toned. */
|
|
48807
|
+
function dishwasherOperationMeta(operationState, t = defaultUiText) {
|
|
48808
|
+
switch (operationState) {
|
|
48809
|
+
case "Run": return {
|
|
48810
|
+
label: t("uiLibrary.dishwasher.op.run", "Running"),
|
|
48697
48811
|
tone: "text-primary"
|
|
48698
48812
|
};
|
|
48699
|
-
case "
|
|
48700
|
-
label: t("uiLibrary.dishwasher.
|
|
48813
|
+
case "Pause": return {
|
|
48814
|
+
label: t("uiLibrary.dishwasher.op.pause", "Paused"),
|
|
48701
48815
|
tone: "text-warning"
|
|
48702
48816
|
};
|
|
48703
|
-
case "
|
|
48704
|
-
label: t("uiLibrary.dishwasher.finished", "Finished"),
|
|
48817
|
+
case "Finished": return {
|
|
48818
|
+
label: t("uiLibrary.dishwasher.op.finished", "Finished"),
|
|
48705
48819
|
tone: "text-success"
|
|
48706
48820
|
};
|
|
48707
|
-
case "
|
|
48708
|
-
label: t("uiLibrary.dishwasher.error", "Error"),
|
|
48709
|
-
tone: "text-
|
|
48821
|
+
case "Error": return {
|
|
48822
|
+
label: t("uiLibrary.dishwasher.op.error", "Error"),
|
|
48823
|
+
tone: "text-danger"
|
|
48710
48824
|
};
|
|
48711
|
-
case "
|
|
48712
|
-
label: t("uiLibrary.dishwasher.
|
|
48713
|
-
tone: "text-
|
|
48825
|
+
case "Aborting": return {
|
|
48826
|
+
label: t("uiLibrary.dishwasher.op.aborting", "Stopping"),
|
|
48827
|
+
tone: "text-warning"
|
|
48714
48828
|
};
|
|
48715
|
-
case "
|
|
48716
|
-
label: t("uiLibrary.dishwasher.
|
|
48829
|
+
case "ActionRequired": return {
|
|
48830
|
+
label: t("uiLibrary.dishwasher.op.actionRequired", "Action required"),
|
|
48831
|
+
tone: "text-warning"
|
|
48832
|
+
};
|
|
48833
|
+
case "DelayedStart": return {
|
|
48834
|
+
label: t("uiLibrary.dishwasher.op.delayedStart", "Delayed start"),
|
|
48835
|
+
tone: "text-primary"
|
|
48836
|
+
};
|
|
48837
|
+
case "Ready": return {
|
|
48838
|
+
label: t("uiLibrary.dishwasher.op.ready", "Ready"),
|
|
48839
|
+
tone: "text-foreground"
|
|
48840
|
+
};
|
|
48841
|
+
case "Inactive": return {
|
|
48842
|
+
label: t("uiLibrary.dishwasher.op.inactive", "Inactive"),
|
|
48717
48843
|
tone: "text-foreground-subtle"
|
|
48718
48844
|
};
|
|
48719
|
-
case
|
|
48845
|
+
case null: return {
|
|
48720
48846
|
label: t("uiLibrary.dishwasher.unknown", "Unknown"),
|
|
48721
48847
|
tone: "text-foreground-subtle"
|
|
48722
48848
|
};
|
|
48723
48849
|
}
|
|
48724
48850
|
}
|
|
48851
|
+
/** The headline for the whole slice: the appliance's state, or why there is none. */
|
|
48852
|
+
function dishwasherHeadline(status, t = defaultUiText) {
|
|
48853
|
+
switch (status.availability) {
|
|
48854
|
+
case "offline": return {
|
|
48855
|
+
label: t("uiLibrary.dishwasher.offline", "Offline"),
|
|
48856
|
+
tone: "text-foreground-subtle"
|
|
48857
|
+
};
|
|
48858
|
+
case "description-missing": return {
|
|
48859
|
+
label: t("uiLibrary.dishwasher.descriptionMissing", "Waiting for the appliance profile"),
|
|
48860
|
+
tone: "text-warning"
|
|
48861
|
+
};
|
|
48862
|
+
case "available": return dishwasherOperationMeta(status.operationState, t);
|
|
48863
|
+
}
|
|
48864
|
+
}
|
|
48725
48865
|
function consumableTone(level) {
|
|
48726
48866
|
switch (level) {
|
|
48727
48867
|
case "ok": return "text-success";
|
|
48728
48868
|
case "low": return "text-warning";
|
|
48729
|
-
case "empty": return "text-
|
|
48869
|
+
case "empty": return "text-danger";
|
|
48730
48870
|
case null: return "text-foreground-subtle";
|
|
48731
48871
|
}
|
|
48732
48872
|
}
|
|
48873
|
+
/** Last segment of a feature key, spaced out: `Dishcare.Dishwasher.Program.Eco50` -> `Eco50`. */
|
|
48874
|
+
function featureLabel(key) {
|
|
48875
|
+
return (key.split(".").pop() ?? key).replace(/([a-z0-9])([A-Z])/g, "$1 $2");
|
|
48876
|
+
}
|
|
48877
|
+
/** Whole seconds as a short duration: `1 h 24 min`, `42 min`, `30 s`. */
|
|
48878
|
+
function formatDuration(seconds, t = defaultUiText) {
|
|
48879
|
+
if (seconds < 60) return t("uiLibrary.dishwasher.durationSeconds", "{{n}} s", { n: seconds });
|
|
48880
|
+
const minutes = Math.round(seconds / 60);
|
|
48881
|
+
if (minutes < 60) return t("uiLibrary.dishwasher.durationMinutes", "{{n}} min", { n: minutes });
|
|
48882
|
+
const hours = Math.floor(minutes / 60);
|
|
48883
|
+
const rest = minutes % 60;
|
|
48884
|
+
return rest === 0 ? t("uiLibrary.dishwasher.durationHours", "{{n}} h", { n: hours }) : t("uiLibrary.dishwasher.durationHoursMinutes", "{{h}} h {{m}} min", {
|
|
48885
|
+
h: hours,
|
|
48886
|
+
m: rest
|
|
48887
|
+
});
|
|
48888
|
+
}
|
|
48733
48889
|
function useDishwasher(trpc, deviceId) {
|
|
48734
48890
|
return useDeviceCapability({
|
|
48735
48891
|
trpc,
|
|
@@ -48763,13 +48919,11 @@ function ConsumableBadge({ label, level }) {
|
|
|
48763
48919
|
]
|
|
48764
48920
|
});
|
|
48765
48921
|
}
|
|
48766
|
-
function DishwasherGraphic({
|
|
48767
|
-
const running = state === "running";
|
|
48922
|
+
function DishwasherGraphic({ running, progressPercent }) {
|
|
48768
48923
|
const pct = progressPercent != null ? Math.max(0, Math.min(100, progressPercent)) : running ? 40 : 0;
|
|
48769
48924
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
48770
48925
|
"aria-hidden": "true",
|
|
48771
48926
|
className: "relative w-28 h-36 rounded border-2 border-border bg-gradient-to-b from-surface-hover to-surface overflow-hidden flex-shrink-0",
|
|
48772
|
-
style: { boxShadow: "inset 0 0 0 2px rgba(255,255,255,.06)" },
|
|
48773
48927
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
48774
48928
|
className: cn("absolute inset-x-0 bottom-0 bg-primary/25 transition-[height] duration-500", running && "animate-pulse"),
|
|
48775
48929
|
style: { height: `${pct}%` }
|
|
@@ -48779,20 +48933,21 @@ function DishwasherGraphic({ state, progressPercent }) {
|
|
|
48779
48933
|
})]
|
|
48780
48934
|
});
|
|
48781
48935
|
}
|
|
48782
|
-
function DishwasherPanel({ trpc, deviceId, layout
|
|
48936
|
+
function DishwasherPanel({ trpc, deviceId, layout }) {
|
|
48783
48937
|
const t = useUiText();
|
|
48784
48938
|
const { cap, slice, available } = useDishwasher(trpc, deviceId);
|
|
48785
|
-
const { display, applyOptimistic } = useOptimisticSlice(slice, { enabled: optimistic ?? true });
|
|
48786
48939
|
if (cap === void 0) return null;
|
|
48787
|
-
if (
|
|
48788
|
-
const
|
|
48940
|
+
if (slice === void 0) return null;
|
|
48941
|
+
const display = slice;
|
|
48942
|
+
const link = display.availability === "available";
|
|
48943
|
+
const busy = !available || !link;
|
|
48789
48944
|
const optionTogglesLocked = display.childLock === true;
|
|
48790
|
-
const meta =
|
|
48791
|
-
const running = display.
|
|
48792
|
-
const paused = display.
|
|
48793
|
-
const
|
|
48945
|
+
const meta = dishwasherHeadline(display, t);
|
|
48946
|
+
const running = display.operationState === "Run";
|
|
48947
|
+
const paused = display.operationState === "Pause";
|
|
48948
|
+
const startable = display.remoteStartAllowed === true && display.selectedProgram !== null;
|
|
48949
|
+
const press = (fn) => {
|
|
48794
48950
|
if (busy) return;
|
|
48795
|
-
applyOptimistic(patch);
|
|
48796
48951
|
fn();
|
|
48797
48952
|
};
|
|
48798
48953
|
if (layout === "compact") {
|
|
@@ -48801,7 +48956,7 @@ function DishwasherPanel({ trpc, deviceId, layout, optimistic }) {
|
|
|
48801
48956
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
48802
48957
|
className: "inline-flex items-center gap-1.5 max-w-full",
|
|
48803
48958
|
children: [
|
|
48804
|
-
display.doorOpen && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
48959
|
+
display.doorOpen === true && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
48805
48960
|
className: "inline-flex text-warning shrink-0",
|
|
48806
48961
|
title: t("uiLibrary.dishwasher.doorOpen", "Door open"),
|
|
48807
48962
|
"aria-label": t("uiLibrary.dishwasher.doorOpen", "Door open"),
|
|
@@ -48814,15 +48969,11 @@ function DishwasherPanel({ trpc, deviceId, layout, optimistic }) {
|
|
|
48814
48969
|
display.program != null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
48815
48970
|
className: "text-xs text-foreground-subtle truncate max-w-[7rem]",
|
|
48816
48971
|
title: display.program,
|
|
48817
|
-
children: display.program
|
|
48972
|
+
children: featureLabel(display.program)
|
|
48818
48973
|
}),
|
|
48819
|
-
display.
|
|
48974
|
+
display.remainingSeconds != null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
48820
48975
|
className: "inline-flex items-center gap-0.5 text-xs text-foreground-subtle tabular-nums shrink-0",
|
|
48821
|
-
children: [
|
|
48822
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Timer, { className: "h-3 w-3" }),
|
|
48823
|
-
display.remainingMinutes,
|
|
48824
|
-
"m"
|
|
48825
|
-
]
|
|
48976
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Timer, { className: "h-3 w-3" }), formatDuration(display.remainingSeconds, t)]
|
|
48826
48977
|
}),
|
|
48827
48978
|
saltWarn && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
48828
48979
|
className: cn("text-[10px] font-medium shrink-0", consumableTone(display.saltLevel)),
|
|
@@ -48834,19 +48985,16 @@ function DishwasherPanel({ trpc, deviceId, layout, optimistic }) {
|
|
|
48834
48985
|
}),
|
|
48835
48986
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(DishwasherIconButton, {
|
|
48836
48987
|
label: t("uiLibrary.dishwasher.start", "Start"),
|
|
48837
|
-
busy: busy || !
|
|
48988
|
+
busy: busy || !startable,
|
|
48838
48989
|
active: running,
|
|
48839
|
-
onClick: () => press(() => cap.start({}),
|
|
48840
|
-
state: "running",
|
|
48841
|
-
remoteStartAllowed: false
|
|
48842
|
-
}),
|
|
48990
|
+
onClick: () => press(() => cap.start({})),
|
|
48843
48991
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Play, { className: "h-3 w-3" })
|
|
48844
48992
|
}),
|
|
48845
48993
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(DishwasherIconButton, {
|
|
48846
|
-
label: t("uiLibrary.dishwasher.pause", "Pause"),
|
|
48847
|
-
busy: busy || !running,
|
|
48994
|
+
label: paused ? t("uiLibrary.dishwasher.resume", "Resume") : t("uiLibrary.dishwasher.pause", "Pause"),
|
|
48995
|
+
busy: busy || !(running || paused),
|
|
48848
48996
|
active: paused,
|
|
48849
|
-
onClick: () => press(() => cap.
|
|
48997
|
+
onClick: () => press(() => paused ? cap.resume({}) : cap.pause({})),
|
|
48850
48998
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Pause, { className: "h-3 w-3" })
|
|
48851
48999
|
})
|
|
48852
49000
|
]
|
|
@@ -48859,7 +49007,7 @@ function DishwasherPanel({ trpc, deviceId, layout, optimistic }) {
|
|
|
48859
49007
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
48860
49008
|
className: "flex items-start gap-4",
|
|
48861
49009
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(DishwasherGraphic, {
|
|
48862
|
-
|
|
49010
|
+
running,
|
|
48863
49011
|
progressPercent: display.progressPercent
|
|
48864
49012
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
48865
49013
|
className: "flex min-w-0 flex-1 flex-col gap-2",
|
|
@@ -48869,14 +49017,23 @@ function DishwasherPanel({ trpc, deviceId, layout, optimistic }) {
|
|
|
48869
49017
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
48870
49018
|
className: cn("text-3xl font-semibold", meta.tone),
|
|
48871
49019
|
children: meta.label
|
|
48872
|
-
}),
|
|
49020
|
+
}), display.powerOn === false && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
48873
49021
|
className: "text-xs font-medium text-foreground-subtle",
|
|
48874
49022
|
children: t("uiLibrary.dishwasher.powerOff", "Power off")
|
|
48875
49023
|
})]
|
|
48876
49024
|
}),
|
|
48877
49025
|
display.program != null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
48878
49026
|
className: "text-sm text-foreground-subtle",
|
|
48879
|
-
|
|
49027
|
+
title: display.program,
|
|
49028
|
+
children: featureLabel(display.program)
|
|
49029
|
+
}),
|
|
49030
|
+
display.remainingSeconds != null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
49031
|
+
className: "inline-flex items-center gap-1 text-sm text-foreground-subtle tabular-nums",
|
|
49032
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Timer, { className: "h-3.5 w-3.5" }), t("uiLibrary.dishwasher.remaining", "{{time}} left", { time: formatDuration(display.remainingSeconds, t) })]
|
|
49033
|
+
}),
|
|
49034
|
+
display.delayedStartSeconds != null && display.delayedStartSeconds > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
49035
|
+
className: "text-xs text-foreground-subtle tabular-nums",
|
|
49036
|
+
children: t("uiLibrary.dishwasher.startsIn", "Starts in {{time}}", { time: formatDuration(display.delayedStartSeconds, t) })
|
|
48880
49037
|
}),
|
|
48881
49038
|
display.progressPercent != null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
48882
49039
|
className: "flex items-center gap-2",
|
|
@@ -48902,53 +49059,52 @@ function DishwasherPanel({ trpc, deviceId, layout, optimistic }) {
|
|
|
48902
49059
|
label: t("uiLibrary.dishwasher.rinseAid", "Rinse aid"),
|
|
48903
49060
|
level: display.rinseAidLevel
|
|
48904
49061
|
}),
|
|
48905
|
-
display.doorOpen && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
49062
|
+
display.doorOpen === true && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
48906
49063
|
className: "inline-flex items-center gap-1 text-xs text-warning",
|
|
48907
49064
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(DoorOpen, { className: "h-3.5 w-3.5" }), t("uiLibrary.dishwasher.doorOpen", "Door open")]
|
|
48908
|
-
})
|
|
49065
|
+
}),
|
|
49066
|
+
display.activeEvents.map((event) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
49067
|
+
className: "text-xs text-warning",
|
|
49068
|
+
title: event,
|
|
49069
|
+
children: featureLabel(event)
|
|
49070
|
+
}, event))
|
|
48909
49071
|
]
|
|
48910
49072
|
}),
|
|
48911
|
-
display.
|
|
48912
|
-
className: "inline-flex items-center gap-1 text-xs text-
|
|
48913
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(TriangleAlert, { className: "h-3.5 w-3.5" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: display.errorLabel
|
|
49073
|
+
display.operationState === "Error" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
49074
|
+
className: "inline-flex items-center gap-1 text-xs text-danger",
|
|
49075
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(TriangleAlert, { className: "h-3.5 w-3.5" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: display.errorLabel != null ? featureLabel(display.errorLabel) : display.errorCode != null ? t("uiLibrary.dishwasher.errorCode", "Error {{code}}", { code: display.errorCode }) : t("uiLibrary.dishwasher.op.error", "Error") })]
|
|
48914
49076
|
}),
|
|
48915
49077
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
48916
49078
|
className: "flex flex-wrap items-center gap-2",
|
|
48917
49079
|
children: [
|
|
48918
49080
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(DishwasherIconButton, {
|
|
48919
49081
|
label: t("uiLibrary.dishwasher.start", "Start"),
|
|
48920
|
-
busy: busy || !
|
|
49082
|
+
busy: busy || !startable,
|
|
48921
49083
|
active: running,
|
|
48922
|
-
onClick: () => press(() => cap.start({}),
|
|
48923
|
-
state: "running",
|
|
48924
|
-
remoteStartAllowed: false
|
|
48925
|
-
}),
|
|
49084
|
+
onClick: () => press(() => cap.start({})),
|
|
48926
49085
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Play, { className: "h-4 w-4" })
|
|
48927
49086
|
}),
|
|
48928
49087
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(DishwasherIconButton, {
|
|
48929
|
-
label: t("uiLibrary.dishwasher.pause", "Pause"),
|
|
48930
|
-
busy: busy || !running,
|
|
49088
|
+
label: paused ? t("uiLibrary.dishwasher.resume", "Resume") : t("uiLibrary.dishwasher.pause", "Pause"),
|
|
49089
|
+
busy: busy || !(running || paused),
|
|
48931
49090
|
active: paused,
|
|
48932
|
-
onClick: () => press(() => cap.
|
|
49091
|
+
onClick: () => press(() => paused ? cap.resume({}) : cap.pause({})),
|
|
48933
49092
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Pause, { className: "h-4 w-4" })
|
|
48934
49093
|
}),
|
|
48935
49094
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(DishwasherIconButton, {
|
|
48936
49095
|
label: t("uiLibrary.dishwasher.stop", "Stop"),
|
|
48937
|
-
busy,
|
|
49096
|
+
busy: busy || !(running || paused),
|
|
48938
49097
|
active: false,
|
|
48939
|
-
onClick: () => press(() => cap.stop({}),
|
|
48940
|
-
state: "idle",
|
|
48941
|
-
remainingMinutes: null
|
|
48942
|
-
}),
|
|
49098
|
+
onClick: () => press(() => cap.stop({})),
|
|
48943
49099
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Square, { className: "h-3.5 w-3.5" })
|
|
48944
49100
|
}),
|
|
48945
49101
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(DishwasherIconButton, {
|
|
48946
49102
|
label: t("uiLibrary.dishwasher.power", "Power"),
|
|
48947
|
-
busy,
|
|
48948
|
-
active: display.powerOn,
|
|
49103
|
+
busy: busy || display.powerOn === null,
|
|
49104
|
+
active: display.powerOn === true,
|
|
48949
49105
|
onClick: () => {
|
|
48950
|
-
const next =
|
|
48951
|
-
press(() => cap.setPower({ on: next })
|
|
49106
|
+
const next = display.powerOn !== true;
|
|
49107
|
+
press(() => cap.setPower({ on: next }));
|
|
48952
49108
|
},
|
|
48953
49109
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Power, { className: "h-4 w-4" })
|
|
48954
49110
|
})
|
|
@@ -48964,24 +49120,23 @@ function DishwasherPanel({ trpc, deviceId, layout, optimistic }) {
|
|
|
48964
49120
|
children: t("uiLibrary.dishwasher.program", "Program")
|
|
48965
49121
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
|
|
48966
49122
|
"aria-label": t("uiLibrary.dishwasher.program", "Program"),
|
|
48967
|
-
value: display.
|
|
49123
|
+
value: display.selectedProgram ?? "",
|
|
48968
49124
|
disabled: busy,
|
|
48969
49125
|
onChange: (e) => {
|
|
48970
49126
|
const program = e.target.value;
|
|
48971
49127
|
if (!program) return;
|
|
48972
|
-
applyOptimistic({ program });
|
|
48973
49128
|
cap.setProgram({ program });
|
|
48974
49129
|
},
|
|
48975
49130
|
onClick: (e) => {
|
|
48976
49131
|
e.stopPropagation();
|
|
48977
49132
|
},
|
|
48978
49133
|
className: "flex-1 rounded border border-border bg-surface px-2 py-1 text-foreground disabled:opacity-50",
|
|
48979
|
-
children: [display.
|
|
49134
|
+
children: [display.selectedProgram == null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
48980
49135
|
value: "",
|
|
48981
49136
|
children: "—"
|
|
48982
49137
|
}), programs.map((p) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
48983
49138
|
value: p,
|
|
48984
|
-
children: p
|
|
49139
|
+
children: featureLabel(p)
|
|
48985
49140
|
}, p))]
|
|
48986
49141
|
})]
|
|
48987
49142
|
}),
|
|
@@ -48991,77 +49146,80 @@ function DishwasherPanel({ trpc, deviceId, layout, optimistic }) {
|
|
|
48991
49146
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ToggleRow, {
|
|
48992
49147
|
label: t("uiLibrary.dishwasher.halfLoad", "Half load"),
|
|
48993
49148
|
checked: display.halfLoad,
|
|
49149
|
+
shown: link,
|
|
48994
49150
|
busy: busy || optionTogglesLocked,
|
|
48995
|
-
onChange: (on) => {
|
|
48996
|
-
applyOptimistic({ halfLoad: on });
|
|
48997
|
-
cap.setHalfLoad({ on });
|
|
48998
|
-
}
|
|
49151
|
+
onChange: (on) => void cap.setHalfLoad({ on })
|
|
48999
49152
|
}),
|
|
49000
49153
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ToggleRow, {
|
|
49001
49154
|
label: t("uiLibrary.dishwasher.hygienePlus", "Hygiene plus"),
|
|
49002
49155
|
checked: display.hygienePlus,
|
|
49156
|
+
shown: link,
|
|
49003
49157
|
busy: busy || optionTogglesLocked,
|
|
49004
|
-
onChange: (on) => {
|
|
49005
|
-
applyOptimistic({ hygienePlus: on });
|
|
49006
|
-
cap.setHygienePlus({ on });
|
|
49007
|
-
}
|
|
49158
|
+
onChange: (on) => void cap.setHygienePlus({ on })
|
|
49008
49159
|
}),
|
|
49009
49160
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ToggleRow, {
|
|
49010
49161
|
label: t("uiLibrary.dishwasher.extraDry", "Extra dry"),
|
|
49011
49162
|
checked: display.extraDry,
|
|
49163
|
+
shown: link,
|
|
49012
49164
|
busy: busy || optionTogglesLocked,
|
|
49013
|
-
onChange: (on) => {
|
|
49014
|
-
applyOptimistic({ extraDry: on });
|
|
49015
|
-
cap.setExtraDry({ on });
|
|
49016
|
-
}
|
|
49165
|
+
onChange: (on) => void cap.setExtraDry({ on })
|
|
49017
49166
|
}),
|
|
49018
49167
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ToggleRow, {
|
|
49019
49168
|
label: t("uiLibrary.dishwasher.intensiveZone", "Intensive zone"),
|
|
49020
49169
|
checked: display.intensiveZone,
|
|
49170
|
+
shown: link,
|
|
49021
49171
|
busy: busy || optionTogglesLocked,
|
|
49022
|
-
onChange: (on) => {
|
|
49023
|
-
applyOptimistic({ intensiveZone: on });
|
|
49024
|
-
cap.setIntensiveZone({ on });
|
|
49025
|
-
}
|
|
49172
|
+
onChange: (on) => void cap.setIntensiveZone({ on })
|
|
49026
49173
|
}),
|
|
49027
49174
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ToggleRow, {
|
|
49028
49175
|
label: t("uiLibrary.dishwasher.varioSpeedPlus", "VarioSpeed+"),
|
|
49029
49176
|
checked: display.varioSpeedPlus,
|
|
49177
|
+
shown: link,
|
|
49030
49178
|
busy: busy || optionTogglesLocked,
|
|
49031
|
-
onChange: (on) => {
|
|
49032
|
-
applyOptimistic({ varioSpeedPlus: on });
|
|
49033
|
-
cap.setVarioSpeedPlus({ on });
|
|
49034
|
-
}
|
|
49179
|
+
onChange: (on) => void cap.setVarioSpeedPlus({ on })
|
|
49035
49180
|
}),
|
|
49036
49181
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ToggleRow, {
|
|
49037
49182
|
label: t("uiLibrary.dishwasher.childLock", "Child lock"),
|
|
49038
49183
|
checked: display.childLock,
|
|
49184
|
+
shown: link,
|
|
49039
49185
|
busy,
|
|
49040
|
-
onChange: (on) => {
|
|
49041
|
-
applyOptimistic({ childLock: on });
|
|
49042
|
-
cap.setChildLock({ on });
|
|
49043
|
-
}
|
|
49186
|
+
onChange: (on) => void cap.setChildLock({ on })
|
|
49044
49187
|
})
|
|
49045
49188
|
]
|
|
49046
49189
|
})
|
|
49047
49190
|
]
|
|
49048
49191
|
});
|
|
49049
49192
|
}
|
|
49050
|
-
|
|
49193
|
+
/**
|
|
49194
|
+
* One boolean setting. `checked === null` is "the appliance has not said": on a reachable
|
|
49195
|
+
* appliance that means it does not offer the setting (hidden); on an unreachable one the
|
|
49196
|
+
* setting is shown but disabled and marked unknown — never as an unchecked box.
|
|
49197
|
+
*/
|
|
49198
|
+
function ToggleRow({ label, checked, shown, busy, onChange }) {
|
|
49199
|
+
const t = useUiText();
|
|
49200
|
+
if (checked === null && shown) return null;
|
|
49051
49201
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
49052
49202
|
className: "inline-flex items-center gap-2 cursor-pointer",
|
|
49053
|
-
children: [
|
|
49054
|
-
|
|
49055
|
-
|
|
49056
|
-
|
|
49057
|
-
|
|
49058
|
-
|
|
49059
|
-
|
|
49060
|
-
|
|
49061
|
-
|
|
49062
|
-
|
|
49063
|
-
|
|
49064
|
-
|
|
49203
|
+
children: [
|
|
49204
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
49205
|
+
type: "checkbox",
|
|
49206
|
+
checked: checked === true,
|
|
49207
|
+
"aria-checked": checked === null ? "mixed" : checked,
|
|
49208
|
+
disabled: busy || checked === null,
|
|
49209
|
+
onChange: (e) => {
|
|
49210
|
+
onChange(e.target.checked);
|
|
49211
|
+
},
|
|
49212
|
+
onClick: (e) => {
|
|
49213
|
+
e.stopPropagation();
|
|
49214
|
+
},
|
|
49215
|
+
className: "rounded border-border"
|
|
49216
|
+
}),
|
|
49217
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: label }),
|
|
49218
|
+
checked === null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
49219
|
+
className: "text-foreground-subtle",
|
|
49220
|
+
children: t("uiLibrary.dishwasher.unknownValue", "—")
|
|
49221
|
+
})
|
|
49222
|
+
]
|
|
49065
49223
|
});
|
|
49066
49224
|
}
|
|
49067
49225
|
function DishwasherInlineControl(props) {
|
|
@@ -54693,88 +54851,6 @@ function PageSizeSelect({ value, options, onChange, ariaLabel }) {
|
|
|
54693
54851
|
});
|
|
54694
54852
|
}
|
|
54695
54853
|
//#endregion
|
|
54696
|
-
//#region src/composites/device-list/multi-select.tsx
|
|
54697
|
-
/**
|
|
54698
|
-
* Compact multi-select dropdown — a single chip-sized trigger ("Label · N")
|
|
54699
|
-
* that opens a checklist. Self-contained (outside-click / Escape dismiss), so
|
|
54700
|
-
* it stays compressed regardless of how many options exist or how little
|
|
54701
|
-
* horizontal room the container has. Shared by the device list's generic-mode
|
|
54702
|
-
* type filter and any other multi-select needs.
|
|
54703
|
-
*/
|
|
54704
|
-
function MultiSelectDropdown({ label, options, selected, onChange }) {
|
|
54705
|
-
const t = useUiText();
|
|
54706
|
-
const [open, setOpen] = (0, react$1.useState)(false);
|
|
54707
|
-
const rootRef = (0, react$1.useRef)(null);
|
|
54708
|
-
(0, react$1.useEffect)(() => {
|
|
54709
|
-
if (!open) return;
|
|
54710
|
-
const onOutside = (e) => {
|
|
54711
|
-
const target = e.target instanceof Node ? e.target : null;
|
|
54712
|
-
if (target && rootRef.current && !rootRef.current.contains(target)) setOpen(false);
|
|
54713
|
-
};
|
|
54714
|
-
const onKey = (e) => {
|
|
54715
|
-
if (e.key === "Escape") setOpen(false);
|
|
54716
|
-
};
|
|
54717
|
-
document.addEventListener("mousedown", onOutside);
|
|
54718
|
-
document.addEventListener("touchstart", onOutside);
|
|
54719
|
-
document.addEventListener("keydown", onKey);
|
|
54720
|
-
return () => {
|
|
54721
|
-
document.removeEventListener("mousedown", onOutside);
|
|
54722
|
-
document.removeEventListener("touchstart", onOutside);
|
|
54723
|
-
document.removeEventListener("keydown", onKey);
|
|
54724
|
-
};
|
|
54725
|
-
}, [open]);
|
|
54726
|
-
const selectedSet = new Set(selected);
|
|
54727
|
-
const count = selected.length;
|
|
54728
|
-
const toggle = (id) => {
|
|
54729
|
-
const next = new Set(selectedSet);
|
|
54730
|
-
if (next.has(id)) next.delete(id);
|
|
54731
|
-
else next.add(id);
|
|
54732
|
-
onChange(options.filter((o) => next.has(o.id)).map((o) => o.id));
|
|
54733
|
-
};
|
|
54734
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
54735
|
-
ref: rootRef,
|
|
54736
|
-
className: "relative",
|
|
54737
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
54738
|
-
type: "button",
|
|
54739
|
-
onClick: () => setOpen((v) => !v),
|
|
54740
|
-
"aria-haspopup": "listbox",
|
|
54741
|
-
"aria-expanded": open,
|
|
54742
|
-
className: `inline-flex items-center gap-1.5 h-7 px-2.5 rounded-full border text-[10.5px] font-medium transition-colors ${count > 0 ? "border-primary/40 bg-primary/15 text-primary" : "border-border bg-surface text-foreground-subtle hover:text-foreground hover:bg-surface-hover"}`,
|
|
54743
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [label, count > 0 ? ` · ${String(count)}` : ""] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChevronDown, { className: `h-3 w-3 transition-transform ${open ? "rotate-180" : ""}` })]
|
|
54744
|
-
}), open && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
54745
|
-
role: "listbox",
|
|
54746
|
-
className: "absolute left-0 top-full mt-1 z-30 min-w-[180px] max-h-72 overflow-y-auto rounded-lg border border-border bg-surface shadow-xl py-1",
|
|
54747
|
-
children: [count > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
54748
|
-
type: "button",
|
|
54749
|
-
onClick: () => onChange([]),
|
|
54750
|
-
className: "flex w-full items-center px-3 py-1.5 text-left text-[10.5px] text-foreground-subtle hover:bg-surface-hover hover:text-foreground",
|
|
54751
|
-
children: t("uiLibrary.multiSelect.clear", "Clear selection")
|
|
54752
|
-
}), options.map((o) => {
|
|
54753
|
-
const active = selectedSet.has(o.id);
|
|
54754
|
-
const Icon = o.icon;
|
|
54755
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
54756
|
-
type: "button",
|
|
54757
|
-
role: "option",
|
|
54758
|
-
"aria-selected": active,
|
|
54759
|
-
onClick: () => toggle(o.id),
|
|
54760
|
-
className: "flex w-full items-center gap-2 px-3 py-1.5 text-left text-[10.5px] text-foreground hover:bg-surface-hover",
|
|
54761
|
-
children: [
|
|
54762
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
54763
|
-
className: `flex h-3.5 w-3.5 items-center justify-center rounded border shrink-0 ${active ? "border-primary bg-primary" : "border-border"}`,
|
|
54764
|
-
children: active && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Check, { className: "h-2.5 w-2.5 text-primary-foreground" })
|
|
54765
|
-
}),
|
|
54766
|
-
Icon && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, { className: "h-3.5 w-3.5 shrink-0 text-foreground-subtle" }),
|
|
54767
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
54768
|
-
className: "truncate",
|
|
54769
|
-
children: o.label
|
|
54770
|
-
})
|
|
54771
|
-
]
|
|
54772
|
-
}, o.id);
|
|
54773
|
-
})]
|
|
54774
|
-
})]
|
|
54775
|
-
});
|
|
54776
|
-
}
|
|
54777
|
-
//#endregion
|
|
54778
54854
|
//#region src/composites/device-list/type-filter.tsx
|
|
54779
54855
|
/**
|
|
54780
54856
|
* Shared, multi-select type filter that adapts to its OWN available width
|
|
@@ -59467,19 +59543,35 @@ function objectFromJson(text) {
|
|
|
59467
59543
|
return null;
|
|
59468
59544
|
}
|
|
59469
59545
|
}
|
|
59470
|
-
|
|
59471
|
-
|
|
59472
|
-
|
|
59546
|
+
/**
|
|
59547
|
+
* What the secret control is hydrated with. A read hands a stored secret as a
|
|
59548
|
+
* VIEW (`{ $secret: <row ref>, set: true }`) the control reveals by ref through
|
|
59549
|
+
* the host's audited reveal; the legacy redaction token is "set, no ref" (it
|
|
59550
|
+
* can be replaced but not revealed); anything else is "nothing stored".
|
|
59551
|
+
*/
|
|
59552
|
+
function hydratedSecret(value) {
|
|
59553
|
+
if ((0, _camstack_types.isSecretFieldView)(value) || (0, _camstack_types.isSecretClear)(value)) return value;
|
|
59554
|
+
if (isRedactedSecret(value)) return {
|
|
59555
|
+
$secret: null,
|
|
59556
|
+
v: 1,
|
|
59557
|
+
set: true
|
|
59558
|
+
};
|
|
59559
|
+
return null;
|
|
59560
|
+
}
|
|
59561
|
+
function RecordEntrySecretField({ name, label, required, value, disabled, onPatch }) {
|
|
59473
59562
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FormField$1, {
|
|
59474
59563
|
label,
|
|
59475
59564
|
required,
|
|
59476
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
59477
|
-
|
|
59478
|
-
|
|
59479
|
-
|
|
59480
|
-
|
|
59481
|
-
|
|
59482
|
-
|
|
59565
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SecretFieldControl, {
|
|
59566
|
+
field: {
|
|
59567
|
+
type: "password",
|
|
59568
|
+
key: name,
|
|
59569
|
+
label,
|
|
59570
|
+
required
|
|
59571
|
+
},
|
|
59572
|
+
value: hydratedSecret(value),
|
|
59573
|
+
onChange: onPatch,
|
|
59574
|
+
disabled
|
|
59483
59575
|
})
|
|
59484
59576
|
});
|
|
59485
59577
|
}
|
|
@@ -59487,6 +59579,7 @@ function SchemaField(props) {
|
|
|
59487
59579
|
const { path, name, node, value, secretPaths, required, disabled, onPatch } = props;
|
|
59488
59580
|
const label = labelFor(name, node);
|
|
59489
59581
|
if (isSecretField(path, secretPaths, node)) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RecordEntrySecretField, {
|
|
59582
|
+
name,
|
|
59490
59583
|
label,
|
|
59491
59584
|
required,
|
|
59492
59585
|
value,
|
|
@@ -59636,7 +59729,7 @@ function defaultBody(schema) {
|
|
|
59636
59729
|
}
|
|
59637
59730
|
return out;
|
|
59638
59731
|
}
|
|
59639
|
-
function RecordEntriesPanel({ kind }) {
|
|
59732
|
+
function RecordEntriesPanel({ kind, rowActions, extraColumns = [], showUpdated = true, minWidthPx }) {
|
|
59640
59733
|
const t = useUiText();
|
|
59641
59734
|
const queryClient = (0, _tanstack_react_query.useQueryClient)();
|
|
59642
59735
|
const confirm = useConfirm();
|
|
@@ -59709,41 +59802,51 @@ function RecordEntriesPanel({ kind }) {
|
|
|
59709
59802
|
})
|
|
59710
59803
|
})
|
|
59711
59804
|
},
|
|
59712
|
-
{
|
|
59805
|
+
...showUpdated ? [{
|
|
59713
59806
|
key: "updated",
|
|
59714
59807
|
header: t("uiLibrary.recordEntries.colUpdated", "Updated"),
|
|
59715
59808
|
nowrap: true,
|
|
59716
59809
|
render: (row) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
59717
59810
|
className: "text-[11px] text-foreground-subtle",
|
|
59718
|
-
|
|
59811
|
+
title: new Date(row.updatedAt).toLocaleString(),
|
|
59812
|
+
children: new Date(row.updatedAt).toLocaleDateString()
|
|
59719
59813
|
})
|
|
59720
|
-
},
|
|
59814
|
+
}] : [],
|
|
59815
|
+
...extraColumns,
|
|
59721
59816
|
{
|
|
59722
59817
|
key: "actions",
|
|
59723
59818
|
header: "",
|
|
59724
59819
|
align: "right",
|
|
59725
59820
|
nowrap: true,
|
|
59821
|
+
width: "w-px",
|
|
59726
59822
|
render: (row) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
59727
59823
|
className: "flex justify-end gap-1",
|
|
59728
|
-
children: [
|
|
59729
|
-
|
|
59730
|
-
|
|
59731
|
-
|
|
59732
|
-
|
|
59733
|
-
|
|
59734
|
-
|
|
59735
|
-
|
|
59736
|
-
|
|
59737
|
-
|
|
59738
|
-
|
|
59739
|
-
|
|
59740
|
-
|
|
59824
|
+
children: [
|
|
59825
|
+
rowActions?.(row),
|
|
59826
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
59827
|
+
size: "sm",
|
|
59828
|
+
variant: "ghost",
|
|
59829
|
+
type: "button",
|
|
59830
|
+
onClick: () => openEdit(row),
|
|
59831
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Pencil, { className: "h-3.5 w-3.5" })
|
|
59832
|
+
}),
|
|
59833
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
59834
|
+
size: "sm",
|
|
59835
|
+
variant: "ghost",
|
|
59836
|
+
type: "button",
|
|
59837
|
+
onClick: () => void onDelete(row),
|
|
59838
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Trash2, { className: "h-3.5 w-3.5 text-danger" })
|
|
59839
|
+
})
|
|
59840
|
+
]
|
|
59741
59841
|
})
|
|
59742
59842
|
}
|
|
59743
59843
|
];
|
|
59744
59844
|
}, [
|
|
59845
|
+
extraColumns,
|
|
59745
59846
|
onDelete,
|
|
59746
59847
|
openEdit,
|
|
59848
|
+
rowActions,
|
|
59849
|
+
showUpdated,
|
|
59747
59850
|
t
|
|
59748
59851
|
]);
|
|
59749
59852
|
const dialogOpen = formUrl.state.mode !== "closed";
|
|
@@ -59791,6 +59894,7 @@ function RecordEntriesPanel({ kind }) {
|
|
|
59791
59894
|
title: t("uiLibrary.recordEntries.emptyTitle", "No entries yet"),
|
|
59792
59895
|
description: t("uiLibrary.recordEntries.emptyDescription", "Add the first row for this kind.")
|
|
59793
59896
|
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DataTable, {
|
|
59897
|
+
...minWidthPx !== void 0 ? { minWidthPx } : {},
|
|
59794
59898
|
columns,
|
|
59795
59899
|
rows: entries,
|
|
59796
59900
|
rowKey: (r) => r.id,
|
|
@@ -59821,73 +59925,6 @@ function RecordEntriesPanel({ kind }) {
|
|
|
59821
59925
|
});
|
|
59822
59926
|
}
|
|
59823
59927
|
//#endregion
|
|
59824
|
-
//#region src/composites/record-entries/record-entries-hub.tsx
|
|
59825
|
-
var RECORD_ENTRY_OWNER_PARAM = "entryOwner";
|
|
59826
|
-
var RECORD_ENTRY_KIND_PARAM = "entryKind";
|
|
59827
|
-
function kindKey$1(k) {
|
|
59828
|
-
return `${k.owner}/${k.kind}`;
|
|
59829
|
-
}
|
|
59830
|
-
function RecordEntriesHub({ filter }) {
|
|
59831
|
-
const t = useUiText();
|
|
59832
|
-
const kindsQuery = useRecordEntriesListEntryKinds({}, { staleTime: 3e4 });
|
|
59833
|
-
const [ownerParam, setOwner] = useUrlQueryParam(RECORD_ENTRY_OWNER_PARAM);
|
|
59834
|
-
const [kindParam, setKind] = useUrlQueryParam(RECORD_ENTRY_KIND_PARAM);
|
|
59835
|
-
const kinds = (0, react$1.useMemo)(() => {
|
|
59836
|
-
return (kindsQuery.data?.kinds ?? []).filter((k) => {
|
|
59837
|
-
if (filter?.owner !== void 0 && k.owner !== filter.owner) return false;
|
|
59838
|
-
if (filter?.kind !== void 0 && k.kind !== filter.kind) return false;
|
|
59839
|
-
return true;
|
|
59840
|
-
});
|
|
59841
|
-
}, [
|
|
59842
|
-
filter?.kind,
|
|
59843
|
-
filter?.owner,
|
|
59844
|
-
kindsQuery.data?.kinds
|
|
59845
|
-
]);
|
|
59846
|
-
const active = (0, react$1.useMemo)(() => {
|
|
59847
|
-
if (kinds.length === 0) return null;
|
|
59848
|
-
return kinds.find((k) => k.owner === ownerParam && k.kind === kindParam) ?? kinds[0] ?? null;
|
|
59849
|
-
}, [
|
|
59850
|
-
kindParam,
|
|
59851
|
-
kinds,
|
|
59852
|
-
ownerParam
|
|
59853
|
-
]);
|
|
59854
|
-
const selectKind = (k) => {
|
|
59855
|
-
setOwner(k.owner);
|
|
59856
|
-
setKind(k.kind);
|
|
59857
|
-
};
|
|
59858
|
-
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") });
|
|
59859
|
-
if (kindsQuery.isPending) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
59860
|
-
className: "flex justify-center py-10 text-foreground-subtle",
|
|
59861
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LoaderCircle, { className: "h-5 w-5 animate-spin" })
|
|
59862
|
-
});
|
|
59863
|
-
if (kinds.length === 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EmptyState, {
|
|
59864
|
-
title: t("uiLibrary.recordEntries.noKindsTitle", "No entry kinds"),
|
|
59865
|
-
description: t("uiLibrary.recordEntries.noKindsDescription", "No addon has declared an entry record kind yet.")
|
|
59866
|
-
});
|
|
59867
|
-
const activeKey = active === null ? "" : kindKey$1(active);
|
|
59868
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
59869
|
-
className: "space-y-4",
|
|
59870
|
-
children: [kinds.length > 1 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Tabs, {
|
|
59871
|
-
appearance: "pills",
|
|
59872
|
-
value: activeKey,
|
|
59873
|
-
onValueChange: (key) => {
|
|
59874
|
-
const found = kinds.find((k) => kindKey$1(k) === key);
|
|
59875
|
-
if (found !== void 0) selectKind(found);
|
|
59876
|
-
},
|
|
59877
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TabsList, {
|
|
59878
|
-
className: "flex flex-wrap gap-1",
|
|
59879
|
-
children: kinds.map((k) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(TabsTrigger, {
|
|
59880
|
-
value: kindKey$1(k),
|
|
59881
|
-
children: [k.title, k.rows > 0 ? ` (${k.rows})` : ""]
|
|
59882
|
-
}, kindKey$1(k)))
|
|
59883
|
-
})
|
|
59884
|
-
}), active !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [kinds.length === 1 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
|
|
59885
|
-
className: "mb-2 text-sm font-semibold text-foreground",
|
|
59886
|
-
children: active.title
|
|
59887
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RecordEntriesPanel, { kind: active })] })]
|
|
59888
|
-
});
|
|
59889
|
-
}
|
|
59890
|
-
//#endregion
|
|
59891
59928
|
//#region src/composites/storage-records/storage-records-panel.tsx
|
|
59892
59929
|
function StorageRecordsPanel({ kind }) {
|
|
59893
59930
|
const t = useUiText();
|
|
@@ -60011,47 +60048,143 @@ function StorageRecordsPanel({ kind }) {
|
|
|
60011
60048
|
});
|
|
60012
60049
|
}
|
|
60013
60050
|
//#endregion
|
|
60014
|
-
//#region src/composites/
|
|
60015
|
-
|
|
60016
|
-
|
|
60017
|
-
function kindKey(k) {
|
|
60018
|
-
return `${k.owner}/${k.kind}`;
|
|
60051
|
+
//#region src/composites/data-records/data-records-model.ts
|
|
60052
|
+
function dataRecordKey(kind) {
|
|
60053
|
+
return `${kind.owner}/${kind.kind}`;
|
|
60019
60054
|
}
|
|
60055
|
+
function dataRecordType(kind) {
|
|
60056
|
+
return kind.entry ? "entry" : "record";
|
|
60057
|
+
}
|
|
60058
|
+
/** `unknown` is a kind whose count was not asked for or could not be read — never "empty". */
|
|
60059
|
+
function dataRecordContents(kind) {
|
|
60060
|
+
if (kind.rows === null) return "unknown";
|
|
60061
|
+
return kind.rows > 0 ? "has-rows" : "empty";
|
|
60062
|
+
}
|
|
60063
|
+
/**
|
|
60064
|
+
* Join the declared kinds with the entry catalog. A pending/failed catalog
|
|
60065
|
+
* (`undefined`) leaves titles `null`; it never changes which kinds are listed.
|
|
60066
|
+
*/
|
|
60067
|
+
function buildDataRecordRows(kinds, entryKinds) {
|
|
60068
|
+
const titles = /* @__PURE__ */ new Map();
|
|
60069
|
+
for (const entry of entryKinds ?? []) titles.set(dataRecordKey(entry), entry.title);
|
|
60070
|
+
return kinds.map((kind) => ({
|
|
60071
|
+
kind,
|
|
60072
|
+
entryTitle: kind.entry ? titles.get(dataRecordKey(kind)) ?? null : null
|
|
60073
|
+
}));
|
|
60074
|
+
}
|
|
60075
|
+
var DATA_RECORD_FACET_GROUPS = [
|
|
60076
|
+
{
|
|
60077
|
+
id: "kind",
|
|
60078
|
+
value: (row) => dataRecordKey(row.kind)
|
|
60079
|
+
},
|
|
60080
|
+
{
|
|
60081
|
+
id: "owner",
|
|
60082
|
+
value: (row) => row.kind.owner
|
|
60083
|
+
},
|
|
60084
|
+
{
|
|
60085
|
+
id: "type",
|
|
60086
|
+
value: (row) => dataRecordType(row.kind)
|
|
60087
|
+
},
|
|
60088
|
+
{
|
|
60089
|
+
id: "database",
|
|
60090
|
+
value: (row) => row.kind.database
|
|
60091
|
+
},
|
|
60092
|
+
{
|
|
60093
|
+
id: "class",
|
|
60094
|
+
value: (row) => row.kind.class
|
|
60095
|
+
},
|
|
60096
|
+
{
|
|
60097
|
+
id: "state",
|
|
60098
|
+
value: (row) => row.kind.state
|
|
60099
|
+
},
|
|
60100
|
+
{
|
|
60101
|
+
id: "contents",
|
|
60102
|
+
value: (row) => dataRecordContents(row.kind)
|
|
60103
|
+
}
|
|
60104
|
+
];
|
|
60105
|
+
function dataRecordSearchText(row) {
|
|
60106
|
+
const { kind } = row;
|
|
60107
|
+
return [
|
|
60108
|
+
kind.owner,
|
|
60109
|
+
kind.kind,
|
|
60110
|
+
kind.class,
|
|
60111
|
+
kind.database,
|
|
60112
|
+
kind.state,
|
|
60113
|
+
row.entryTitle ?? ""
|
|
60114
|
+
];
|
|
60115
|
+
}
|
|
60116
|
+
//#endregion
|
|
60117
|
+
//#region src/composites/data-records/data-records-hub.tsx
|
|
60118
|
+
var DATA_RECORDS_OWNER_PARAM = "recordsOwner";
|
|
60119
|
+
var DATA_RECORDS_KIND_PARAM = "recordsKind";
|
|
60020
60120
|
function formatBytes(n) {
|
|
60021
60121
|
if (n === null) return "—";
|
|
60022
60122
|
if (n < 1024) return `${n} B`;
|
|
60023
60123
|
if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)} KiB`;
|
|
60024
60124
|
return `${(n / (1024 * 1024)).toFixed(1)} MiB`;
|
|
60025
60125
|
}
|
|
60026
|
-
function
|
|
60126
|
+
function groupLabel(id, t) {
|
|
60127
|
+
switch (id) {
|
|
60128
|
+
case "kind": return t("uiLibrary.dataRecords.facetKind", "Kind");
|
|
60129
|
+
case "owner": return t("uiLibrary.dataRecords.facetOwner", "Owner");
|
|
60130
|
+
case "type": return t("uiLibrary.dataRecords.facetType", "Type");
|
|
60131
|
+
case "database": return t("uiLibrary.dataRecords.facetDatabase", "Database");
|
|
60132
|
+
case "class": return t("uiLibrary.dataRecords.facetClass", "Class");
|
|
60133
|
+
case "state": return t("uiLibrary.dataRecords.facetState", "State");
|
|
60134
|
+
default: return t("uiLibrary.dataRecords.facetContents", "Contents");
|
|
60135
|
+
}
|
|
60136
|
+
}
|
|
60137
|
+
function facetCaption(groupId, value, t) {
|
|
60138
|
+
if (groupId === "type") return value === "entry" ? t("uiLibrary.dataRecords.typeEntry", "Entries (editable)") : t("uiLibrary.dataRecords.typeRecord", "Records (read-only)");
|
|
60139
|
+
if (groupId === "contents") {
|
|
60140
|
+
if (value === "has-rows") return t("uiLibrary.dataRecords.contentsHasRows", "Has rows");
|
|
60141
|
+
if (value === "empty") return t("uiLibrary.dataRecords.contentsEmpty", "Empty");
|
|
60142
|
+
return t("uiLibrary.dataRecords.contentsUnknown", "Count unknown");
|
|
60143
|
+
}
|
|
60144
|
+
return value;
|
|
60145
|
+
}
|
|
60146
|
+
/** Entry kinds open the editable list; every other kind opens the read-only preview. */
|
|
60147
|
+
function KindDetail({ kind, entryKinds, entryKindsPending, entryKindsError }) {
|
|
60148
|
+
const t = useUiText();
|
|
60149
|
+
if (!kind.entry) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(StorageRecordsPanel, { kind });
|
|
60150
|
+
if (entryKindsPending) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
60151
|
+
className: "flex justify-center py-8 text-foreground-subtle",
|
|
60152
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LoaderCircle, { className: "h-5 w-5 animate-spin" })
|
|
60153
|
+
});
|
|
60154
|
+
if (entryKindsError !== null) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ErrorBox, { message: entryKindsError });
|
|
60155
|
+
const info = entryKinds?.find((e) => dataRecordKey(e) === dataRecordKey(kind));
|
|
60156
|
+
if (info === void 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ErrorBox, { message: t("uiLibrary.dataRecords.entryKindMissing", "This entry kind is not served by the entries service.") });
|
|
60157
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
60158
|
+
className: "space-y-2",
|
|
60159
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
|
|
60160
|
+
className: "text-sm font-semibold text-foreground",
|
|
60161
|
+
children: info.title
|
|
60162
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RecordEntriesPanel, { kind: info })]
|
|
60163
|
+
});
|
|
60164
|
+
}
|
|
60165
|
+
/**
|
|
60166
|
+
* System → Data → Records: every declared record kind in ONE table with
|
|
60167
|
+
* compact filters; an entry kind opens its editable list, any other kind its
|
|
60168
|
+
* read-only row preview. Selection is in `?recordsOwner=&recordsKind=`.
|
|
60169
|
+
*/
|
|
60170
|
+
function DataRecordsHub() {
|
|
60027
60171
|
const t = useUiText();
|
|
60028
60172
|
const kindsQuery = trpc.storageAdmin.listKinds.useQuery({}, { staleTime: 3e4 });
|
|
60029
|
-
const
|
|
60030
|
-
const [
|
|
60031
|
-
const
|
|
60032
|
-
const
|
|
60033
|
-
|
|
60034
|
-
|
|
60035
|
-
|
|
60036
|
-
|
|
60037
|
-
row.database,
|
|
60038
|
-
row.state
|
|
60039
|
-
],
|
|
60040
|
-
facetGroups: [{
|
|
60041
|
-
id: "owner",
|
|
60042
|
-
value: (row) => row.owner
|
|
60043
|
-
}, {
|
|
60044
|
-
id: "database",
|
|
60045
|
-
value: (row) => row.database
|
|
60046
|
-
}]
|
|
60173
|
+
const entryKindsQuery = useRecordEntriesListEntryKinds({}, { staleTime: 3e4 });
|
|
60174
|
+
const [ownerParam, setOwner] = useUrlQueryParam(DATA_RECORDS_OWNER_PARAM);
|
|
60175
|
+
const [kindParam, setKind] = useUrlQueryParam(DATA_RECORDS_KIND_PARAM);
|
|
60176
|
+
const entryKinds = entryKindsQuery.data?.kinds;
|
|
60177
|
+
const rows = (0, react$1.useMemo)(() => buildDataRecordRows(kindsQuery.data?.kinds ?? [], entryKinds), [entryKinds, kindsQuery.data?.kinds]);
|
|
60178
|
+
const filter = useDataTableFilter(rows, {
|
|
60179
|
+
searchText: dataRecordSearchText,
|
|
60180
|
+
facetGroups: DATA_RECORD_FACET_GROUPS
|
|
60047
60181
|
});
|
|
60048
60182
|
const active = (0, react$1.useMemo)(() => {
|
|
60049
|
-
|
|
60050
|
-
return kinds.find((k) => k.owner === ownerParam && k.kind === kindParam) ?? null;
|
|
60183
|
+
return rows.find((r) => r.kind.owner === ownerParam && r.kind.kind === kindParam)?.kind ?? null;
|
|
60051
60184
|
}, [
|
|
60052
60185
|
kindParam,
|
|
60053
|
-
|
|
60054
|
-
|
|
60186
|
+
ownerParam,
|
|
60187
|
+
rows
|
|
60055
60188
|
]);
|
|
60056
60189
|
const selectKind = (0, react$1.useCallback)((k) => {
|
|
60057
60190
|
setOwner(k.owner);
|
|
@@ -60061,72 +60194,87 @@ function StorageRecordsHub() {
|
|
|
60061
60194
|
return [
|
|
60062
60195
|
{
|
|
60063
60196
|
key: "kind",
|
|
60064
|
-
header: t("uiLibrary.
|
|
60197
|
+
header: t("uiLibrary.dataRecords.colKind", "Kind"),
|
|
60065
60198
|
render: (row) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
60066
|
-
className: "
|
|
60067
|
-
children: [
|
|
60068
|
-
|
|
60069
|
-
|
|
60070
|
-
|
|
60071
|
-
|
|
60199
|
+
className: "flex flex-col",
|
|
60200
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
60201
|
+
className: "font-mono text-xs",
|
|
60202
|
+
children: dataRecordKey(row.kind)
|
|
60203
|
+
}), row.entryTitle !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
60204
|
+
className: "text-[11px] text-foreground-subtle",
|
|
60205
|
+
children: row.entryTitle
|
|
60206
|
+
}) : null]
|
|
60072
60207
|
}),
|
|
60073
|
-
sortValue: (row) =>
|
|
60208
|
+
sortValue: (row) => dataRecordKey(row.kind)
|
|
60209
|
+
},
|
|
60210
|
+
{
|
|
60211
|
+
key: "type",
|
|
60212
|
+
header: t("uiLibrary.dataRecords.colType", "Type"),
|
|
60213
|
+
nowrap: true,
|
|
60214
|
+
render: (row) => row.kind.entry ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Badge, {
|
|
60215
|
+
variant: "info",
|
|
60216
|
+
children: t("uiLibrary.dataRecords.badgeEntry", "Entry")
|
|
60217
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Badge, {
|
|
60218
|
+
variant: "neutral",
|
|
60219
|
+
children: t("uiLibrary.dataRecords.badgeRecord", "Record")
|
|
60220
|
+
}),
|
|
60221
|
+
sortValue: (row) => row.kind.entry ? "entry" : "record"
|
|
60074
60222
|
},
|
|
60075
60223
|
{
|
|
60076
60224
|
key: "database",
|
|
60077
|
-
header: t("uiLibrary.
|
|
60225
|
+
header: t("uiLibrary.dataRecords.colDatabase", "DB"),
|
|
60078
60226
|
nowrap: true,
|
|
60079
60227
|
render: (row) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Badge, {
|
|
60080
60228
|
variant: "neutral",
|
|
60081
60229
|
style: "outline",
|
|
60082
|
-
children: row.database
|
|
60230
|
+
children: row.kind.database
|
|
60083
60231
|
}),
|
|
60084
|
-
sortValue: (row) => row.database
|
|
60232
|
+
sortValue: (row) => row.kind.database
|
|
60085
60233
|
},
|
|
60086
60234
|
{
|
|
60087
60235
|
key: "class",
|
|
60088
|
-
header: t("uiLibrary.
|
|
60236
|
+
header: t("uiLibrary.dataRecords.colClass", "Class"),
|
|
60089
60237
|
nowrap: true,
|
|
60090
60238
|
render: (row) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
60091
60239
|
className: "text-xs text-foreground-muted",
|
|
60092
|
-
children: row.class
|
|
60240
|
+
children: row.kind.class
|
|
60093
60241
|
}),
|
|
60094
|
-
sortValue: (row) => row.class
|
|
60242
|
+
sortValue: (row) => row.kind.class
|
|
60095
60243
|
},
|
|
60096
60244
|
{
|
|
60097
60245
|
key: "state",
|
|
60098
|
-
header: t("uiLibrary.
|
|
60246
|
+
header: t("uiLibrary.dataRecords.colState", "State"),
|
|
60099
60247
|
nowrap: true,
|
|
60100
60248
|
render: (row) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Badge, {
|
|
60101
|
-
variant: row.state === "declared" ? "default" : "neutral",
|
|
60102
|
-
children: row.state
|
|
60249
|
+
variant: row.kind.state === "declared" ? "default" : "neutral",
|
|
60250
|
+
children: row.kind.state
|
|
60103
60251
|
}),
|
|
60104
|
-
sortValue: (row) => row.state
|
|
60252
|
+
sortValue: (row) => row.kind.state
|
|
60105
60253
|
},
|
|
60106
60254
|
{
|
|
60107
60255
|
key: "rows",
|
|
60108
|
-
header: t("uiLibrary.
|
|
60256
|
+
header: t("uiLibrary.dataRecords.colRows", "Rows"),
|
|
60109
60257
|
align: "right",
|
|
60110
60258
|
nowrap: true,
|
|
60111
60259
|
render: (row) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
60112
60260
|
className: "font-mono text-xs tabular-nums",
|
|
60113
|
-
children: row.rows === null ? "—" : row.rows
|
|
60261
|
+
children: row.kind.rows === null ? "—" : row.kind.rows
|
|
60114
60262
|
}),
|
|
60115
|
-
sortValue: (row) => row.rows ?? -1
|
|
60263
|
+
sortValue: (row) => row.kind.rows ?? -1
|
|
60116
60264
|
},
|
|
60117
60265
|
{
|
|
60118
60266
|
key: "bytes",
|
|
60119
|
-
header: t("uiLibrary.
|
|
60267
|
+
header: t("uiLibrary.dataRecords.colSize", "Est. size"),
|
|
60120
60268
|
align: "right",
|
|
60121
60269
|
nowrap: true,
|
|
60122
60270
|
render: (row) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
60123
60271
|
className: "text-xs text-foreground-subtle",
|
|
60124
|
-
children: formatBytes(row.bytesEstimate)
|
|
60272
|
+
children: formatBytes(row.kind.bytesEstimate)
|
|
60125
60273
|
}),
|
|
60126
|
-
sortValue: (row) => row.bytesEstimate ?? -1
|
|
60274
|
+
sortValue: (row) => row.kind.bytesEstimate ?? -1
|
|
60127
60275
|
},
|
|
60128
60276
|
{
|
|
60129
|
-
key: "
|
|
60277
|
+
key: "open",
|
|
60130
60278
|
header: "",
|
|
60131
60279
|
align: "right",
|
|
60132
60280
|
nowrap: true,
|
|
@@ -60134,12 +60282,12 @@ function StorageRecordsHub() {
|
|
|
60134
60282
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
60135
60283
|
type: "button",
|
|
60136
60284
|
size: "sm",
|
|
60137
|
-
variant: active !== null &&
|
|
60138
|
-
onClick: () => selectKind(row),
|
|
60139
|
-
children: t("uiLibrary.
|
|
60285
|
+
variant: active !== null && dataRecordKey(active) === dataRecordKey(row.kind) ? "primary" : "outline",
|
|
60286
|
+
onClick: () => selectKind(row.kind),
|
|
60287
|
+
children: row.kind.entry ? t("uiLibrary.dataRecords.manage", "Manage") : t("uiLibrary.dataRecords.viewRows", "View rows")
|
|
60140
60288
|
});
|
|
60141
60289
|
},
|
|
60142
|
-
notSortableReason: t("uiLibrary.
|
|
60290
|
+
notSortableReason: t("uiLibrary.dataRecords.actionColumn", "Actions")
|
|
60143
60291
|
}
|
|
60144
60292
|
];
|
|
60145
60293
|
}, [
|
|
@@ -60147,14 +60295,14 @@ function StorageRecordsHub() {
|
|
|
60147
60295
|
selectKind,
|
|
60148
60296
|
t
|
|
60149
60297
|
]);
|
|
60150
|
-
if (kindsQuery.isError) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ErrorBox, { message: kindsQuery.error instanceof Error ? kindsQuery.error.message : t("uiLibrary.
|
|
60298
|
+
if (kindsQuery.isError) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ErrorBox, { message: kindsQuery.error instanceof Error ? kindsQuery.error.message : t("uiLibrary.dataRecords.kindsFailed", "Could not load record kinds") });
|
|
60151
60299
|
if (kindsQuery.isPending) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
60152
60300
|
className: "flex justify-center py-10 text-foreground-subtle",
|
|
60153
60301
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LoaderCircle, { className: "h-5 w-5 animate-spin" })
|
|
60154
60302
|
});
|
|
60155
|
-
if (
|
|
60156
|
-
title: t("uiLibrary.
|
|
60157
|
-
description: t("uiLibrary.
|
|
60303
|
+
if (rows.length === 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EmptyState, {
|
|
60304
|
+
title: t("uiLibrary.dataRecords.noKindsTitle", "No record kinds"),
|
|
60305
|
+
description: t("uiLibrary.dataRecords.noKindsDescription", "No addon has declared a record kind on this hub yet.")
|
|
60158
60306
|
});
|
|
60159
60307
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
60160
60308
|
className: "space-y-4",
|
|
@@ -60164,13 +60312,15 @@ function StorageRecordsHub() {
|
|
|
60164
60312
|
facets: filter.facets,
|
|
60165
60313
|
groups: filter.groups.map((g) => ({
|
|
60166
60314
|
...g,
|
|
60167
|
-
label: g.id
|
|
60315
|
+
label: groupLabel(g.id, t),
|
|
60316
|
+
display: "menu",
|
|
60317
|
+
facetLabel: (value) => facetCaption(g.id, value, t)
|
|
60168
60318
|
})),
|
|
60169
60319
|
labels: {
|
|
60170
|
-
searchPlaceholder: t("uiLibrary.
|
|
60171
|
-
searchLabel: t("uiLibrary.
|
|
60172
|
-
facetsLabel: t("uiLibrary.
|
|
60173
|
-
clearLabel: t("uiLibrary.
|
|
60320
|
+
searchPlaceholder: t("uiLibrary.dataRecords.search", "Search kinds…"),
|
|
60321
|
+
searchLabel: t("uiLibrary.dataRecords.searchLabel", "Search record kinds"),
|
|
60322
|
+
facetsLabel: t("uiLibrary.dataRecords.facetsLabel", "Filter record kinds"),
|
|
60323
|
+
clearLabel: t("uiLibrary.dataRecords.clearFilters", "Clear filters")
|
|
60174
60324
|
},
|
|
60175
60325
|
onSearch: filter.setSearch,
|
|
60176
60326
|
onToggleFacet: filter.toggleFacet,
|
|
@@ -60180,15 +60330,20 @@ function StorageRecordsHub() {
|
|
|
60180
60330
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(DataTable, {
|
|
60181
60331
|
columns,
|
|
60182
60332
|
rows: filter.rows,
|
|
60183
|
-
rowKey: (
|
|
60333
|
+
rowKey: (r) => dataRecordKey(r.kind),
|
|
60184
60334
|
maxBodyHeight: TABLE_SCROLL_MAX_H,
|
|
60185
60335
|
defaultSort: {
|
|
60186
60336
|
columnKey: "kind",
|
|
60187
60337
|
dir: "asc"
|
|
60188
60338
|
},
|
|
60189
|
-
emptyMessage: t("uiLibrary.
|
|
60339
|
+
emptyMessage: t("uiLibrary.dataRecords.noMatch", "No kinds match the filter")
|
|
60190
60340
|
}),
|
|
60191
|
-
active !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
60341
|
+
active !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(KindDetail, {
|
|
60342
|
+
kind: active,
|
|
60343
|
+
entryKinds,
|
|
60344
|
+
entryKindsPending: entryKindsQuery.isPending,
|
|
60345
|
+
entryKindsError: entryKindsQuery.isError ? entryKindsQuery.error instanceof Error ? entryKindsQuery.error.message : t("uiLibrary.dataRecords.entryKindsFailed", "Could not load entry kinds") : null
|
|
60346
|
+
}) : null
|
|
60192
60347
|
]
|
|
60193
60348
|
});
|
|
60194
60349
|
}
|
|
@@ -64597,6 +64752,9 @@ exports.CoverPanel = CoverPanel;
|
|
|
64597
64752
|
exports.Cpu = Cpu;
|
|
64598
64753
|
exports.Crosshair = Crosshair;
|
|
64599
64754
|
exports.CustomFieldRenderersProvider = CustomFieldRenderersProvider;
|
|
64755
|
+
exports.DATA_RECORDS_KIND_PARAM = DATA_RECORDS_KIND_PARAM;
|
|
64756
|
+
exports.DATA_RECORDS_OWNER_PARAM = DATA_RECORDS_OWNER_PARAM;
|
|
64757
|
+
exports.DATA_RECORD_FACET_GROUPS = DATA_RECORD_FACET_GROUPS;
|
|
64600
64758
|
exports.DEFAULT_COLOR = DEFAULT_COLOR;
|
|
64601
64759
|
exports.DEFAULT_PAGINATION_LABELS = DEFAULT_PAGINATION_LABELS;
|
|
64602
64760
|
exports.DEVICE_COLUMNS = DEVICE_COLUMNS;
|
|
@@ -64607,6 +64765,7 @@ exports.DEVICE_PICKER_GROUP_STORAGE_KEY = DEVICE_PICKER_GROUP_STORAGE_KEY;
|
|
|
64607
64765
|
exports.DEVICE_ROLE_META = DEVICE_ROLE_META;
|
|
64608
64766
|
exports.DEVICE_TYPE_CONTROL = DEVICE_TYPE_CONTROL;
|
|
64609
64767
|
exports.DEVICE_TYPE_META = DEVICE_TYPE_META;
|
|
64768
|
+
exports.DataRecordsHub = DataRecordsHub;
|
|
64610
64769
|
exports.DataTable = DataTable;
|
|
64611
64770
|
exports.DataTableFilterBar = DataTableFilterBar;
|
|
64612
64771
|
exports.DataTablePager = DataTablePager;
|
|
@@ -64851,8 +65010,6 @@ exports.QrCode = QrCode;
|
|
|
64851
65010
|
exports.QrCode$1 = QrCode$1;
|
|
64852
65011
|
exports.RECONNECT_POLICY = RECONNECT_POLICY;
|
|
64853
65012
|
exports.RECORDED_PLAYBACK_MODES = RECORDED_PLAYBACK_MODES;
|
|
64854
|
-
exports.RECORD_ENTRY_KIND_PARAM = RECORD_ENTRY_KIND_PARAM;
|
|
64855
|
-
exports.RECORD_ENTRY_OWNER_PARAM = RECORD_ENTRY_OWNER_PARAM;
|
|
64856
65013
|
exports.RIGHT = RIGHT;
|
|
64857
65014
|
exports.ROI_AREA_WARN_FRACTION = ROI_AREA_WARN_FRACTION;
|
|
64858
65015
|
exports.ROLE_DESCRIPTOR = ROLE_DESCRIPTOR;
|
|
@@ -64861,7 +65018,6 @@ exports.Radar = Radar;
|
|
|
64861
65018
|
exports.RadialGauge = RadialGauge;
|
|
64862
65019
|
exports.Radio = Radio;
|
|
64863
65020
|
exports.RadioTower = RadioTower;
|
|
64864
|
-
exports.RecordEntriesHub = RecordEntriesHub;
|
|
64865
65021
|
exports.RecordEntriesPanel = RecordEntriesPanel;
|
|
64866
65022
|
exports.RecordedPlaybackProvider = RecordedPlaybackProvider;
|
|
64867
65023
|
exports.RecordingPanel = RecordingPanel;
|
|
@@ -64895,8 +65051,6 @@ exports.SPLIT_PANEL_SIDE = SPLIT_PANEL_SIDE;
|
|
|
64895
65051
|
exports.STACK_GAP = STACK_GAP;
|
|
64896
65052
|
exports.STATE_COLOR = STATE_COLOR;
|
|
64897
65053
|
exports.STEP_DOCK_WIDTH_PX = STEP_DOCK_WIDTH_PX;
|
|
64898
|
-
exports.STORAGE_RECORDS_KIND_PARAM = STORAGE_RECORDS_KIND_PARAM;
|
|
64899
|
-
exports.STORAGE_RECORDS_OWNER_PARAM = STORAGE_RECORDS_OWNER_PARAM;
|
|
64900
65054
|
exports.Sailboat = Sailboat;
|
|
64901
65055
|
exports.Save = Save;
|
|
64902
65056
|
exports.Scan = Scan;
|
|
@@ -64955,7 +65109,6 @@ exports.StepInspectorPanel = StepInspectorPanel;
|
|
|
64955
65109
|
exports.StepModelRow = StepModelRow;
|
|
64956
65110
|
exports.StepTimings = StepTimings;
|
|
64957
65111
|
exports.Stepper = Stepper;
|
|
64958
|
-
exports.StorageRecordsHub = StorageRecordsHub;
|
|
64959
65112
|
exports.StorageRecordsPanel = StorageRecordsPanel;
|
|
64960
65113
|
exports.StreamBrokerSelector = StreamBrokerSelector;
|
|
64961
65114
|
exports.StreamDebugOverlay = StreamDebugOverlay;
|
|
@@ -65057,6 +65210,7 @@ exports.badgeFor = badgeFor;
|
|
|
65057
65210
|
exports.badgeFor$1 = badgeFor;
|
|
65058
65211
|
exports.bindsToModel = bindsToModel;
|
|
65059
65212
|
exports.buildColorByNodeId = buildColorByNodeId;
|
|
65213
|
+
exports.buildDataRecordRows = buildDataRecordRows;
|
|
65060
65214
|
exports.buildPeerConnectionConfig = buildPeerConnectionConfig;
|
|
65061
65215
|
exports.buildStepTreeFromSchema = buildStepTreeFromSchema;
|
|
65062
65216
|
exports.catalogHasDraft = catalogHasDraft;
|
|
@@ -65084,6 +65238,10 @@ exports.createTheme = require_theme_index.createTheme$1;
|
|
|
65084
65238
|
exports.currentAddonLanguage = currentAddonLanguage;
|
|
65085
65239
|
exports.cursorFractionFor = cursorFractionFor;
|
|
65086
65240
|
exports.darkColors = require_theme_to_root_css.darkColors;
|
|
65241
|
+
exports.dataRecordContents = dataRecordContents;
|
|
65242
|
+
exports.dataRecordKey = dataRecordKey;
|
|
65243
|
+
exports.dataRecordSearchText = dataRecordSearchText;
|
|
65244
|
+
exports.dataRecordType = dataRecordType;
|
|
65087
65245
|
exports.dataTableFacetGroups = dataTableFacetGroups;
|
|
65088
65246
|
exports.dataTableFacets = dataTableFacets;
|
|
65089
65247
|
exports.defaultOfField = defaultOfField;
|
|
@@ -65667,8 +65825,10 @@ exports.useDeviceStateSlice$1 = useDeviceStateSlice;
|
|
|
65667
65825
|
exports.useDeviceStatusGetStatus = useDeviceStatusGetStatus;
|
|
65668
65826
|
exports.useDeviceWebrtc = useDeviceWebrtc;
|
|
65669
65827
|
exports.useDevices = useDevices;
|
|
65828
|
+
exports.useDishwasherGetOptions = useDishwasherGetOptions;
|
|
65670
65829
|
exports.useDishwasherGetStatus = useDishwasherGetStatus;
|
|
65671
65830
|
exports.useDishwasherPause = useDishwasherPause;
|
|
65831
|
+
exports.useDishwasherResume = useDishwasherResume;
|
|
65672
65832
|
exports.useDishwasherSetChildLock = useDishwasherSetChildLock;
|
|
65673
65833
|
exports.useDishwasherSetExtraDry = useDishwasherSetExtraDry;
|
|
65674
65834
|
exports.useDishwasherSetHalfLoad = useDishwasherSetHalfLoad;
|
|
@@ -66363,6 +66523,7 @@ exports.useStorageMigrationCleanupStart = useStorageMigrationCleanupStart;
|
|
|
66363
66523
|
exports.useStorageMigrationCleanupStatus = useStorageMigrationCleanupStatus;
|
|
66364
66524
|
exports.useStorageMigrationDrain = useStorageMigrationDrain;
|
|
66365
66525
|
exports.useStorageMigrationHistory = useStorageMigrationHistory;
|
|
66526
|
+
exports.useStorageMigrationMoverClearance = useStorageMigrationMoverClearance;
|
|
66366
66527
|
exports.useStorageMigrationMovers = useStorageMigrationMovers;
|
|
66367
66528
|
exports.useStorageMigrationPlan = useStorageMigrationPlan;
|
|
66368
66529
|
exports.useStorageMigrationResidue = useStorageMigrationResidue;
|