@camstack/ui-library 1.2.245 → 1.2.246
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/accelerator-label.d.ts +17 -0
- package/dist/composites/agent-step-editor.d.ts +3 -3
- package/dist/composites/device-step-matrix.d.ts +25 -2
- package/dist/composites/index.d.ts +3 -2
- package/dist/composites/pipeline-builder.d.ts +2 -10
- package/dist/composites/pipeline-matrix-shared.d.ts +10 -0
- package/dist/composites/step-inspector/index.d.ts +2 -3
- package/dist/composites/step-inspector/step-detail-dock.d.ts +33 -0
- package/dist/composites/step-inspector/step-search.d.ts +18 -0
- package/dist/generated/system-hooks.d.ts +0 -16
- package/dist/index.cjs +445 -620
- package/dist/index.js +440 -609
- package/package.json +1 -1
- package/dist/composites/step-inspector/step-chips.d.ts +0 -11
- package/dist/composites/step-inspector/step-inspector-layout.d.ts +0 -23
- package/dist/composites/step-inspector/step-list.d.ts +0 -39
- package/dist/lib/validate-template.d.ts +0 -2
package/dist/index.cjs
CHANGED
|
@@ -1707,41 +1707,6 @@ var CookingPot = createLucideIcon("cooking-pot", [
|
|
|
1707
1707
|
* This source code is licensed under the ISC license.
|
|
1708
1708
|
* See the LICENSE file in the root directory of this source tree.
|
|
1709
1709
|
*/
|
|
1710
|
-
var CopyPlus = createLucideIcon("copy-plus", [
|
|
1711
|
-
["line", {
|
|
1712
|
-
x1: "15",
|
|
1713
|
-
x2: "15",
|
|
1714
|
-
y1: "12",
|
|
1715
|
-
y2: "18",
|
|
1716
|
-
key: "1p7wdc"
|
|
1717
|
-
}],
|
|
1718
|
-
["line", {
|
|
1719
|
-
x1: "12",
|
|
1720
|
-
x2: "18",
|
|
1721
|
-
y1: "15",
|
|
1722
|
-
y2: "15",
|
|
1723
|
-
key: "1nscbv"
|
|
1724
|
-
}],
|
|
1725
|
-
["rect", {
|
|
1726
|
-
width: "14",
|
|
1727
|
-
height: "14",
|
|
1728
|
-
x: "8",
|
|
1729
|
-
y: "8",
|
|
1730
|
-
rx: "2",
|
|
1731
|
-
ry: "2",
|
|
1732
|
-
key: "17jyea"
|
|
1733
|
-
}],
|
|
1734
|
-
["path", {
|
|
1735
|
-
d: "M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2",
|
|
1736
|
-
key: "zix9uf"
|
|
1737
|
-
}]
|
|
1738
|
-
]);
|
|
1739
|
-
/**
|
|
1740
|
-
* @license lucide-react v0.576.0 - ISC
|
|
1741
|
-
*
|
|
1742
|
-
* This source code is licensed under the ISC license.
|
|
1743
|
-
* See the LICENSE file in the root directory of this source tree.
|
|
1744
|
-
*/
|
|
1745
1710
|
var Copy = createLucideIcon("copy", [["rect", {
|
|
1746
1711
|
width: "14",
|
|
1747
1712
|
height: "14",
|
|
@@ -7914,14 +7879,6 @@ var usePipelineExecutorGetGlobalPipelineConfig = trpc.pipelineExecutor.getGlobal
|
|
|
7914
7879
|
var usePipelineExecutorGetOrchestratorConfigSchema = trpc.pipelineExecutor.getOrchestratorConfigSchema.useQuery;
|
|
7915
7880
|
/** Generated alias around `trpc.pipelineExecutor.validatePipeline.useQuery`. */
|
|
7916
7881
|
var usePipelineExecutorValidatePipeline = trpc.pipelineExecutor.validatePipeline.useQuery;
|
|
7917
|
-
/** Generated alias around `trpc.pipelineExecutor.listTemplates.useQuery`. */
|
|
7918
|
-
var usePipelineExecutorListTemplates = trpc.pipelineExecutor.listTemplates.useQuery;
|
|
7919
|
-
/** Generated alias around `trpc.pipelineExecutor.saveTemplate.useMutation`. */
|
|
7920
|
-
var usePipelineExecutorSaveTemplate = trpc.pipelineExecutor.saveTemplate.useMutation;
|
|
7921
|
-
/** Generated alias around `trpc.pipelineExecutor.updateTemplate.useMutation`. */
|
|
7922
|
-
var usePipelineExecutorUpdateTemplate = trpc.pipelineExecutor.updateTemplate.useMutation;
|
|
7923
|
-
/** Generated alias around `trpc.pipelineExecutor.deleteTemplate.useMutation`. */
|
|
7924
|
-
var usePipelineExecutorDeleteTemplate = trpc.pipelineExecutor.deleteTemplate.useMutation;
|
|
7925
7882
|
/** Generated alias around `trpc.pipelineExecutor.getCapabilities.useQuery`. */
|
|
7926
7883
|
var usePipelineExecutorGetCapabilities = trpc.pipelineExecutor.getCapabilities.useQuery;
|
|
7927
7884
|
/** Generated alias around `trpc.pipelineExecutor.getAddonModels.useQuery`. */
|
|
@@ -8068,14 +8025,6 @@ var usePipelineOrchestratorSetCameraSensors = trpc.pipelineOrchestrator.setCamer
|
|
|
8068
8025
|
var usePipelineOrchestratorReconcileFromDisk = trpc.pipelineOrchestrator.reconcileFromDisk.useMutation;
|
|
8069
8026
|
/** Generated alias around `trpc.pipelineOrchestrator.getReconcileFromDiskStatus.useQuery`. */
|
|
8070
8027
|
var usePipelineOrchestratorGetReconcileFromDiskStatus = trpc.pipelineOrchestrator.getReconcileFromDiskStatus.useQuery;
|
|
8071
|
-
/** Generated alias around `trpc.pipelineOrchestrator.listTemplates.useQuery`. */
|
|
8072
|
-
var usePipelineOrchestratorListTemplates = trpc.pipelineOrchestrator.listTemplates.useQuery;
|
|
8073
|
-
/** Generated alias around `trpc.pipelineOrchestrator.saveTemplate.useMutation`. */
|
|
8074
|
-
var usePipelineOrchestratorSaveTemplate = trpc.pipelineOrchestrator.saveTemplate.useMutation;
|
|
8075
|
-
/** Generated alias around `trpc.pipelineOrchestrator.updateTemplate.useMutation`. */
|
|
8076
|
-
var usePipelineOrchestratorUpdateTemplate = trpc.pipelineOrchestrator.updateTemplate.useMutation;
|
|
8077
|
-
/** Generated alias around `trpc.pipelineOrchestrator.deleteTemplate.useMutation`. */
|
|
8078
|
-
var usePipelineOrchestratorDeleteTemplate = trpc.pipelineOrchestrator.deleteTemplate.useMutation;
|
|
8079
8028
|
/** Generated alias around `trpc.pipelineOrchestrator.getDeviceSettingsContribution.useQuery`. */
|
|
8080
8029
|
var usePipelineOrchestratorGetDeviceSettingsContribution = trpc.pipelineOrchestrator.getDeviceSettingsContribution.useQuery;
|
|
8081
8030
|
/** Generated alias around `trpc.pipelineOrchestrator.getDeviceLiveContribution.useQuery`. */
|
|
@@ -28746,6 +28695,45 @@ function AddonGlobalSettingsForm({ trpc, addonId, nodeId, title, disabled, onAft
|
|
|
28746
28695
|
});
|
|
28747
28696
|
}
|
|
28748
28697
|
//#endregion
|
|
28698
|
+
//#region src/composites/accelerator-label.ts
|
|
28699
|
+
function names(device) {
|
|
28700
|
+
const backend = device.backend.toLowerCase();
|
|
28701
|
+
const dev = device.device.toLowerCase();
|
|
28702
|
+
if (device.key === "cpu" || dev === "cpu" || backend === "cpu") return {
|
|
28703
|
+
label: "CPU",
|
|
28704
|
+
short: "CPU"
|
|
28705
|
+
};
|
|
28706
|
+
if (dev === "npu") return {
|
|
28707
|
+
label: "Intel NPU",
|
|
28708
|
+
short: "NPU"
|
|
28709
|
+
};
|
|
28710
|
+
if (dev === "gpu" || dev === "igpu") return {
|
|
28711
|
+
label: "Intel iGPU",
|
|
28712
|
+
short: "iGPU"
|
|
28713
|
+
};
|
|
28714
|
+
if (backend === "edgetpu") return {
|
|
28715
|
+
label: "Coral Edge TPU",
|
|
28716
|
+
short: "Coral"
|
|
28717
|
+
};
|
|
28718
|
+
if (backend === "coreml") return {
|
|
28719
|
+
label: "Apple Neural Engine",
|
|
28720
|
+
short: "ANE"
|
|
28721
|
+
};
|
|
28722
|
+
const pretty = `${device.backend} ${device.device}`.trim().replace(/\b\w/g, (c) => c.toUpperCase());
|
|
28723
|
+
return {
|
|
28724
|
+
label: pretty.length > 0 ? pretty : device.key,
|
|
28725
|
+
short: device.backend || device.key
|
|
28726
|
+
};
|
|
28727
|
+
}
|
|
28728
|
+
/** "Intel NPU", "Apple Neural Engine", "Coral Edge TPU", "CPU" — Auto tune's names too. */
|
|
28729
|
+
function acceleratorLabel(device) {
|
|
28730
|
+
return names(device).label;
|
|
28731
|
+
}
|
|
28732
|
+
/** "NPU", "ANE", "Coral", "CPU" — chips and tabs. */
|
|
28733
|
+
function acceleratorShortLabel(device) {
|
|
28734
|
+
return names(device).short;
|
|
28735
|
+
}
|
|
28736
|
+
//#endregion
|
|
28749
28737
|
//#region src/composites/grouped-model-selector.tsx
|
|
28750
28738
|
/**
|
|
28751
28739
|
* GroupedModelSelector — the shared Family → Tier → Variant model picker.
|
|
@@ -29973,9 +29961,9 @@ function RootSuppliedModelNote({ rootModel, stepModelId }) {
|
|
|
29973
29961
|
/**
|
|
29974
29962
|
* AgentStepEditor — one step on ONE accelerator: its model and its settings,
|
|
29975
29963
|
* as a single node-level layer. Model Studio's "settings for this installed
|
|
29976
|
-
* model" dialog uses it. The pipeline pages use the step
|
|
29977
|
-
* the same parts out across accelerators and layers (D754/
|
|
29978
|
-
* form here is that
|
|
29964
|
+
* model" dialog uses it. The pipeline pages use the step matrix's panel, which lays
|
|
29965
|
+
* the same parts out across accelerators and layers (D754/D757); the settings
|
|
29966
|
+
* form here is that panel's `LayeredSettingsForm` with one layer.
|
|
29979
29967
|
*/
|
|
29980
29968
|
function AgentStepEditor({ addon, agentDefault, onChangeAgentConfig, engineFormat, effectiveModelId, rootModel }) {
|
|
29981
29969
|
const modelsForFormat = (0, react$1.useMemo)(() => stepModelOptions(addon.models, engineFormat), [addon.models, engineFormat]);
|
|
@@ -55405,25 +55393,46 @@ function ClassChips({ inputs, outputs }) {
|
|
|
55405
55393
|
* the first column; each device's real format is shown per sub-column instead
|
|
55406
55394
|
* ("Coral Edge TPU · tflite").
|
|
55407
55395
|
*/
|
|
55396
|
+
/** The per-accelerator lines of a column header: name, format, model, off. */
|
|
55397
|
+
function AgentColumnLines({ column }) {
|
|
55398
|
+
const name = column.deviceLabel ?? column.deviceKey;
|
|
55399
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
55400
|
+
(name !== void 0 || column.disabled === true) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
55401
|
+
className: "flex min-w-0 items-center gap-1",
|
|
55402
|
+
children: [name !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
55403
|
+
className: "truncate text-[10px] font-medium text-foreground/90",
|
|
55404
|
+
children: name
|
|
55405
|
+
}), column.disabled === true && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
55406
|
+
className: "shrink-0 rounded bg-muted px-1 text-[8px] font-semibold uppercase text-foreground-subtle",
|
|
55407
|
+
children: "off"
|
|
55408
|
+
})]
|
|
55409
|
+
}),
|
|
55410
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
55411
|
+
className: "truncate text-[9px] text-foreground-subtle",
|
|
55412
|
+
children: column.engineLabel
|
|
55413
|
+
}),
|
|
55414
|
+
column.detail !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
55415
|
+
className: "truncate font-mono text-[9px] text-foreground-subtle",
|
|
55416
|
+
title: column.detail,
|
|
55417
|
+
children: column.detail
|
|
55418
|
+
})
|
|
55419
|
+
] });
|
|
55420
|
+
}
|
|
55408
55421
|
function GroupedAgentHeader({ group }) {
|
|
55422
|
+
const nodeLabel = group.columns[0]?.nodeLabel ?? group.agentNodeId;
|
|
55409
55423
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
55424
|
+
role: "columnheader",
|
|
55410
55425
|
className: "sticky top-0 z-10 min-w-0 border-b border-l border-border bg-muted/60",
|
|
55411
55426
|
style: { gridColumn: `span ${group.columns.length}` },
|
|
55412
55427
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
55413
55428
|
className: "truncate px-3 pt-2 pb-1 text-xs font-semibold text-foreground",
|
|
55414
|
-
children:
|
|
55429
|
+
children: nodeLabel
|
|
55415
55430
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
55416
55431
|
className: "mt-1 flex border-t border-border/50",
|
|
55417
|
-
children: group.columns.map((c, i) => /* @__PURE__ */ (0, react_jsx_runtime.
|
|
55418
|
-
className: cn("min-w-0 flex-1 px-3 py-1", i > 0 && "border-l border-border/50"),
|
|
55419
|
-
title: `${c.deviceLabel ?? c.deviceKey} · ${c.engineLabel}`,
|
|
55420
|
-
children:
|
|
55421
|
-
className: "truncate text-[10px] font-medium text-foreground/90",
|
|
55422
|
-
children: c.deviceLabel ?? c.deviceKey
|
|
55423
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
55424
|
-
className: "truncate text-[9px] text-foreground-subtle",
|
|
55425
|
-
children: c.engineLabel
|
|
55426
|
-
})]
|
|
55432
|
+
children: group.columns.map((c, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
55433
|
+
className: cn("min-w-0 flex-1 px-3 py-1", i > 0 && "border-l border-border/50", c.disabled === true && "opacity-70"),
|
|
55434
|
+
title: `${c.deviceLabel ?? c.deviceKey} · ${c.engineLabel}${c.detail ? ` · ${c.detail}` : ""}`,
|
|
55435
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AgentColumnLines, { column: c })
|
|
55427
55436
|
}, agentColumnKey(c)))
|
|
55428
55437
|
})]
|
|
55429
55438
|
});
|
|
@@ -55527,25 +55536,30 @@ function cellButtonClass(state, isSelected, extra) {
|
|
|
55527
55536
|
//#endregion
|
|
55528
55537
|
//#region src/composites/device-step-matrix.tsx
|
|
55529
55538
|
/**
|
|
55530
|
-
* DeviceStepMatrix — the
|
|
55531
|
-
* (
|
|
55532
|
-
*
|
|
55533
|
-
*
|
|
55534
|
-
*
|
|
55535
|
-
*
|
|
55536
|
-
*
|
|
55537
|
-
*
|
|
55538
|
-
*
|
|
55539
|
-
*
|
|
55540
|
-
*
|
|
55541
|
-
*
|
|
55542
|
-
*
|
|
55543
|
-
*
|
|
55544
|
-
*
|
|
55545
|
-
*
|
|
55546
|
-
*
|
|
55547
|
-
*
|
|
55548
|
-
*
|
|
55539
|
+
* DeviceStepMatrix — the step × accelerator TABLE of a detection pipeline
|
|
55540
|
+
* (D757): the node's Pipeline tab and the camera's Detection pipeline → Steps
|
|
55541
|
+
* are this matrix, and a click on a cell (or a step's header) opens that step's
|
|
55542
|
+
* settings in a docked panel (`StepDetailDock`) that overlays the page instead
|
|
55543
|
+
* of reflowing the matrix.
|
|
55544
|
+
*
|
|
55545
|
+
* Column 1 (STICKY): the indented step tree — slot, name, class-flow chips,
|
|
55546
|
+
* and an optional badge (the camera's gate). The header is a button: it
|
|
55547
|
+
* opens the step on the selected accelerator.
|
|
55548
|
+
* Columns 2..N: one per accelerator, grouped under their node; the header
|
|
55549
|
+
* names the accelerator, its format, the model it elects, and "off" for a
|
|
55550
|
+
* switched-off one. A cell shows the model that runs there, or "⚠ skip",
|
|
55551
|
+
* "→ iGPU", "root", "cluster", "ovr", "—".
|
|
55552
|
+
*
|
|
55553
|
+
* Keyboard: ONE Tab stop (a roving tabindex over the step headers and cells);
|
|
55554
|
+
* arrows move, Home / End go to the row's ends, Enter or Space opens.
|
|
55555
|
+
*
|
|
55556
|
+
* `reserveRightPx`: the width a docked panel covers at the right of the
|
|
55557
|
+
* viewport. The matrix adds a trailing spacer that wide (so any column can
|
|
55558
|
+
* scroll clear of it) and scrolls the selected cell into the uncovered part —
|
|
55559
|
+
* it never shrinks, so nothing reflows when the panel opens.
|
|
55560
|
+
*
|
|
55561
|
+
* Responsive, container-measured: narrower than the step column plus two
|
|
55562
|
+
* columns, the matrix shows ONE node at a time with a node selector.
|
|
55549
55563
|
*/
|
|
55550
55564
|
/** The sticky step column. */
|
|
55551
55565
|
var STEP_COL_REM = 18;
|
|
@@ -55556,11 +55570,41 @@ var STEP_COL_PX = STEP_COL_REM * 16;
|
|
|
55556
55570
|
* step column and lets the device columns scroll horizontally beside it.
|
|
55557
55571
|
*/
|
|
55558
55572
|
var STEP_COL_SINGLE_REM = 11;
|
|
55559
|
-
|
|
55573
|
+
/** Where a key press moves the roving focus in a `rows × cols` grid. */
|
|
55574
|
+
function nextGridPosition(key, pos, rows, cols) {
|
|
55575
|
+
const clamp = (r, c) => ({
|
|
55576
|
+
r: Math.max(0, Math.min(rows - 1, r)),
|
|
55577
|
+
c: Math.max(0, Math.min(cols - 1, c))
|
|
55578
|
+
});
|
|
55579
|
+
switch (key) {
|
|
55580
|
+
case "ArrowRight": return clamp(pos.r, pos.c + 1);
|
|
55581
|
+
case "ArrowLeft": return clamp(pos.r, pos.c - 1);
|
|
55582
|
+
case "ArrowDown": return clamp(pos.r + 1, pos.c);
|
|
55583
|
+
case "ArrowUp": return clamp(pos.r - 1, pos.c);
|
|
55584
|
+
case "Home": return clamp(pos.r, 0);
|
|
55585
|
+
case "End": return clamp(pos.r, cols - 1);
|
|
55586
|
+
case "PageDown": return clamp(rows - 1, pos.c);
|
|
55587
|
+
case "PageUp": return clamp(0, pos.c);
|
|
55588
|
+
default: return null;
|
|
55589
|
+
}
|
|
55590
|
+
}
|
|
55591
|
+
function StepCell({ node, depth, r, tabbable, selected, badge, onClick, sticky }) {
|
|
55560
55592
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
55561
|
-
|
|
55562
|
-
|
|
55563
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.
|
|
55593
|
+
role: "rowheader",
|
|
55594
|
+
className: cn("min-w-0 border-b border-border bg-surface", sticky && "sticky left-0 z-10"),
|
|
55595
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
55596
|
+
type: "button",
|
|
55597
|
+
"data-r": r,
|
|
55598
|
+
"data-c": 0,
|
|
55599
|
+
"data-step": node.addonId,
|
|
55600
|
+
"data-col": "",
|
|
55601
|
+
tabIndex: tabbable ? 0 : -1,
|
|
55602
|
+
"aria-current": selected ? "true" : void 0,
|
|
55603
|
+
onClick: onClick ? (e) => onClick(e.detail === 0) : void 0,
|
|
55604
|
+
className: cn("flex h-full w-full min-w-0 items-start gap-2 px-3 py-2 text-left text-xs outline-none", "hover:bg-muted/40 focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-primary", selected && "bg-primary/10 shadow-[inset_3px_0_0_var(--color-primary)]"),
|
|
55605
|
+
style: { paddingLeft: `${12 + depth * 14}px` },
|
|
55606
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(StepLabel, { node }), badge]
|
|
55607
|
+
})
|
|
55564
55608
|
});
|
|
55565
55609
|
}
|
|
55566
55610
|
/**
|
|
@@ -55590,68 +55634,179 @@ function NodeSelectorBar({ nodes, selected, onSelect }) {
|
|
|
55590
55634
|
role: "tab",
|
|
55591
55635
|
"aria-selected": isSelected,
|
|
55592
55636
|
onClick: () => onSelect(a.agentNodeId),
|
|
55593
|
-
title: `${a.agentNodeId} · ${a.engineLabel}`,
|
|
55637
|
+
title: `${a.columns[0]?.nodeLabel ?? a.agentNodeId} · ${a.engineLabel}`,
|
|
55594
55638
|
className: cn("px-2.5 py-1 transition-colors", isSelected ? "bg-primary/15 text-primary" : "bg-transparent text-foreground-subtle hover:bg-surface-hover hover:text-foreground", idx > 0 && "border-l border-border"),
|
|
55595
|
-
children: a.agentNodeId
|
|
55639
|
+
children: a.columns[0]?.nodeLabel ?? a.agentNodeId
|
|
55596
55640
|
}, a.agentNodeId);
|
|
55597
55641
|
})
|
|
55598
55642
|
})
|
|
55599
55643
|
]
|
|
55600
55644
|
});
|
|
55601
55645
|
}
|
|
55602
|
-
function MatrixGrid({ tree, agents, getCellState, onCellClick, selectedCell, single }) {
|
|
55646
|
+
var MatrixGrid = (0, react$1.forwardRef)(function MatrixGrid({ tree, agents, getCellState, onCellClick, onStepClick, stepBadge, selectedCell, single, reserveRightPx, label }, ref) {
|
|
55603
55647
|
const rows = (0, react$1.useMemo)(() => flattenTree(tree), [tree]);
|
|
55604
55648
|
const groups = (0, react$1.useMemo)(() => groupAgentColumns(agents), [agents]);
|
|
55649
|
+
const boxRef = (0, react$1.useRef)(null);
|
|
55650
|
+
const stepColRem = single ? STEP_COL_SINGLE_REM : STEP_COL_REM;
|
|
55651
|
+
const gridTemplate = `${stepColRem}rem repeat(${agents.length}, 13rem)`;
|
|
55652
|
+
const cols = agents.length + 1;
|
|
55653
|
+
const [stickySteps, setStickySteps] = (0, react$1.useState)(true);
|
|
55654
|
+
(0, react$1.useLayoutEffect)(() => {
|
|
55655
|
+
const box = boxRef.current;
|
|
55656
|
+
if (!box || reserveRightPx <= 0) {
|
|
55657
|
+
setStickySteps(true);
|
|
55658
|
+
return;
|
|
55659
|
+
}
|
|
55660
|
+
const measure = () => {
|
|
55661
|
+
const left = box.getBoundingClientRect().left;
|
|
55662
|
+
setStickySteps(window.innerWidth - reserveRightPx - left >= stepColRem * 16 + 208 + 24);
|
|
55663
|
+
};
|
|
55664
|
+
measure();
|
|
55665
|
+
window.addEventListener("resize", measure);
|
|
55666
|
+
return () => window.removeEventListener("resize", measure);
|
|
55667
|
+
}, [reserveRightPx, stepColRem]);
|
|
55668
|
+
const selectedPos = (0, react$1.useMemo)(() => {
|
|
55669
|
+
if (selectedCell === null) return null;
|
|
55670
|
+
const r = rows.findIndex((row) => row.node.addonId === selectedCell.addonId);
|
|
55671
|
+
if (r < 0) return null;
|
|
55672
|
+
const c = agents.findIndex((a) => agentColumnKey(a) === agentColumnKey(selectedCell));
|
|
55673
|
+
return {
|
|
55674
|
+
r,
|
|
55675
|
+
c: c < 0 ? 0 : c + 1
|
|
55676
|
+
};
|
|
55677
|
+
}, [
|
|
55678
|
+
selectedCell,
|
|
55679
|
+
rows,
|
|
55680
|
+
agents
|
|
55681
|
+
]);
|
|
55682
|
+
const [focusPos, setFocusPos] = (0, react$1.useState)({
|
|
55683
|
+
r: 0,
|
|
55684
|
+
c: 0
|
|
55685
|
+
});
|
|
55686
|
+
(0, react$1.useEffect)(() => {
|
|
55687
|
+
if (selectedPos !== null) setFocusPos(selectedPos);
|
|
55688
|
+
}, [selectedPos]);
|
|
55689
|
+
const tab = focusPos.r < rows.length && focusPos.c < cols ? focusPos : {
|
|
55690
|
+
r: 0,
|
|
55691
|
+
c: 0
|
|
55692
|
+
};
|
|
55693
|
+
const focusAt = (r, c) => {
|
|
55694
|
+
boxRef.current?.querySelector(`[data-r="${r}"][data-c="${c}"]`)?.focus();
|
|
55695
|
+
};
|
|
55696
|
+
(0, react$1.useImperativeHandle)(ref, () => ({ focusCell: (addonId, columnKey) => {
|
|
55697
|
+
const r = rows.findIndex((row) => row.node.addonId === addonId);
|
|
55698
|
+
if (r < 0) return;
|
|
55699
|
+
const index = columnKey === null ? -1 : agents.findIndex((a) => agentColumnKey(a) === columnKey);
|
|
55700
|
+
const c = index < 0 ? 0 : index + 1;
|
|
55701
|
+
setFocusPos({
|
|
55702
|
+
r,
|
|
55703
|
+
c
|
|
55704
|
+
});
|
|
55705
|
+
focusAt(r, c);
|
|
55706
|
+
} }), [rows, agents]);
|
|
55707
|
+
(0, react$1.useLayoutEffect)(() => {
|
|
55708
|
+
if (selectedPos === null) return;
|
|
55709
|
+
const box = boxRef.current;
|
|
55710
|
+
const el = box?.querySelector(`[data-r="${selectedPos.r}"][data-c="${selectedPos.c}"]`);
|
|
55711
|
+
if (!box || !el) return;
|
|
55712
|
+
if (typeof el.scrollIntoView === "function") el.scrollIntoView({
|
|
55713
|
+
block: "nearest",
|
|
55714
|
+
inline: "nearest"
|
|
55715
|
+
});
|
|
55716
|
+
if (reserveRightPx <= 0) return;
|
|
55717
|
+
const limit = window.innerWidth - reserveRightPx - 12;
|
|
55718
|
+
const right = el.getBoundingClientRect().right;
|
|
55719
|
+
if (right > limit) box.scrollLeft += right - limit;
|
|
55720
|
+
}, [
|
|
55721
|
+
selectedPos,
|
|
55722
|
+
reserveRightPx,
|
|
55723
|
+
stickySteps
|
|
55724
|
+
]);
|
|
55725
|
+
const onKeyDown = (e) => {
|
|
55726
|
+
if (!(e.target instanceof HTMLElement) || e.target.dataset.r === void 0) return;
|
|
55727
|
+
const pos = {
|
|
55728
|
+
r: Number(e.target.dataset.r),
|
|
55729
|
+
c: Number(e.target.dataset.c)
|
|
55730
|
+
};
|
|
55731
|
+
const next = nextGridPosition(e.key, pos, rows.length, cols);
|
|
55732
|
+
if (next === null) return;
|
|
55733
|
+
e.preventDefault();
|
|
55734
|
+
setFocusPos(next);
|
|
55735
|
+
focusAt(next.r, next.c);
|
|
55736
|
+
};
|
|
55605
55737
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
55738
|
+
ref: boxRef,
|
|
55606
55739
|
className: "overflow-auto rounded border border-border",
|
|
55607
55740
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
55608
|
-
className: "
|
|
55609
|
-
|
|
55610
|
-
|
|
55611
|
-
|
|
55612
|
-
|
|
55613
|
-
|
|
55614
|
-
}
|
|
55615
|
-
|
|
55616
|
-
|
|
55741
|
+
className: "flex w-max",
|
|
55742
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
55743
|
+
role: "grid",
|
|
55744
|
+
"aria-label": label,
|
|
55745
|
+
"aria-rowcount": rows.length + 1,
|
|
55746
|
+
className: "grid w-max",
|
|
55747
|
+
style: { gridTemplateColumns: gridTemplate },
|
|
55748
|
+
onKeyDown,
|
|
55749
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
55750
|
+
role: "row",
|
|
55751
|
+
className: "contents",
|
|
55617
55752
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
55618
|
-
|
|
55619
|
-
|
|
55620
|
-
|
|
55621
|
-
|
|
55622
|
-
|
|
55753
|
+
role: "columnheader",
|
|
55754
|
+
className: cn("top-0 z-20 border-b border-border bg-muted/60 px-3 py-2 text-[10px] uppercase tracking-widest text-foreground-subtle", stickySteps ? "sticky left-0" : "sticky"),
|
|
55755
|
+
children: "Step"
|
|
55756
|
+
}), groups.map((group) => group.grouped ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(GroupedAgentHeader, { group }, group.agentNodeId) : group.columns.map((col) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
55757
|
+
role: "columnheader",
|
|
55758
|
+
className: cn("sticky top-0 z-10 min-w-0 border-b border-l border-border bg-muted/60 px-3 py-2", col.disabled === true && "opacity-70"),
|
|
55759
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
55760
|
+
className: "truncate text-xs font-semibold text-foreground",
|
|
55761
|
+
children: col.nodeLabel ?? col.agentNodeId
|
|
55762
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AgentColumnLines, { column: col })]
|
|
55763
|
+
}, agentColumnKey(col))))]
|
|
55764
|
+
}), rows.map(({ node, depth }, r) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
55765
|
+
role: "row",
|
|
55766
|
+
className: "contents",
|
|
55767
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(StepCell, {
|
|
55768
|
+
node,
|
|
55769
|
+
depth,
|
|
55770
|
+
r,
|
|
55771
|
+
tabbable: tab.r === r && tab.c === 0,
|
|
55772
|
+
selected: selectedCell?.addonId === node.addonId,
|
|
55773
|
+
badge: stepBadge?.(node.addonId),
|
|
55774
|
+
onClick: onStepClick ? (kb) => onStepClick(node.addonId, kb) : void 0,
|
|
55775
|
+
sticky: stickySteps
|
|
55776
|
+
}), agents.map((a, i) => {
|
|
55777
|
+
const state = getCellState(node.addonId, a);
|
|
55778
|
+
const isSelected = selectedCell !== null && selectedCell.addonId === node.addonId && agentColumnKey(selectedCell) === agentColumnKey(a);
|
|
55779
|
+
const actionable = state.kind === "enabled" || state.kind === "skip";
|
|
55780
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
55781
|
+
role: "gridcell",
|
|
55782
|
+
className: "min-w-0 border-b border-l border-border",
|
|
55783
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
55784
|
+
type: "button",
|
|
55785
|
+
"data-r": r,
|
|
55786
|
+
"data-c": i + 1,
|
|
55787
|
+
"data-step": node.addonId,
|
|
55788
|
+
"data-col": agentColumnKey(a),
|
|
55789
|
+
tabIndex: tab.r === r && tab.c === i + 1 ? 0 : -1,
|
|
55790
|
+
"aria-disabled": !actionable,
|
|
55791
|
+
"aria-selected": isSelected,
|
|
55792
|
+
onClick: (e) => {
|
|
55793
|
+
if (actionable) onCellClick(node.addonId, a, e.detail === 0);
|
|
55794
|
+
},
|
|
55795
|
+
className: cellButtonClass(state, isSelected, cn("h-full w-full min-w-0 overflow-hidden px-3 py-2 outline-none", "focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-primary", !actionable && "cursor-default hover:bg-transparent", a.disabled === true && "opacity-70")),
|
|
55796
|
+
children: renderCellContent(state)
|
|
55797
|
+
})
|
|
55798
|
+
}, agentColumnKey(a));
|
|
55623
55799
|
})]
|
|
55624
|
-
},
|
|
55625
|
-
|
|
55626
|
-
|
|
55627
|
-
|
|
55628
|
-
|
|
55629
|
-
|
|
55630
|
-
onCellClick,
|
|
55631
|
-
selectedCell
|
|
55632
|
-
}, node.addonId))
|
|
55633
|
-
]
|
|
55800
|
+
}, node.addonId))]
|
|
55801
|
+
}), reserveRightPx > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
55802
|
+
"aria-hidden": true,
|
|
55803
|
+
style: { width: reserveRightPx },
|
|
55804
|
+
className: "shrink-0"
|
|
55805
|
+
})]
|
|
55634
55806
|
})
|
|
55635
55807
|
});
|
|
55636
|
-
}
|
|
55637
|
-
function
|
|
55638
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(StepCell, {
|
|
55639
|
-
node,
|
|
55640
|
-
depth
|
|
55641
|
-
}), agents.map((a) => {
|
|
55642
|
-
const state = getCellState(node.addonId, a);
|
|
55643
|
-
const isSelected = selectedCell !== null && selectedCell.addonId === node.addonId && agentColumnKey(selectedCell) === agentColumnKey(a);
|
|
55644
|
-
const actionable = state.kind === "enabled" || state.kind === "skip";
|
|
55645
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
55646
|
-
type: "button",
|
|
55647
|
-
disabled: !actionable,
|
|
55648
|
-
onClick: () => onCellClick(node.addonId, a),
|
|
55649
|
-
className: cellButtonClass(state, isSelected, cn("min-w-0 overflow-hidden border-b border-l border-border px-3 py-2", !actionable && "cursor-default hover:bg-transparent")),
|
|
55650
|
-
children: renderCellContent(state)
|
|
55651
|
-
}, agentColumnKey(a));
|
|
55652
|
-
})] });
|
|
55653
|
-
}
|
|
55654
|
-
function DeviceStepMatrix({ tree, agents, getCellState, onCellClick, selectedCell, fallbackNodeId, onFallbackNodeChange }) {
|
|
55808
|
+
});
|
|
55809
|
+
var DeviceStepMatrix = (0, react$1.forwardRef)(function DeviceStepMatrix({ tree, agents, getCellState, onCellClick, selectedCell, fallbackNodeId, onFallbackNodeChange, onStepClick, stepBadge, reserveRightPx = 0, label = "Detection steps" }, ref) {
|
|
55655
55810
|
const containerRef = (0, react$1.useRef)(null);
|
|
55656
55811
|
const [width, setWidth] = (0, react$1.useState)(0);
|
|
55657
55812
|
(0, react$1.useLayoutEffect)(() => {
|
|
@@ -55669,6 +55824,15 @@ function DeviceStepMatrix({ tree, agents, getCellState, onCellClick, selectedCel
|
|
|
55669
55824
|
if (nodes.length === 0) return null;
|
|
55670
55825
|
return nodes.find((n) => n.agentNodeId === fallbackNodeId) ?? nodes[0] ?? null;
|
|
55671
55826
|
}, [nodes, fallbackNodeId]);
|
|
55827
|
+
const selectedNodeId = selectedCell?.agentNodeId;
|
|
55828
|
+
(0, react$1.useEffect)(() => {
|
|
55829
|
+
if (single && selectedNodeId !== void 0 && selectedNodeId !== fallbackNodeId) onFallbackNodeChange(selectedNodeId);
|
|
55830
|
+
}, [
|
|
55831
|
+
single,
|
|
55832
|
+
selectedNodeId,
|
|
55833
|
+
fallbackNodeId,
|
|
55834
|
+
onFallbackNodeChange
|
|
55835
|
+
]);
|
|
55672
55836
|
const shownAgents = single && selectedNode ? selectedNode.columns : agents;
|
|
55673
55837
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
55674
55838
|
ref: containerRef,
|
|
@@ -55678,15 +55842,20 @@ function DeviceStepMatrix({ tree, agents, getCellState, onCellClick, selectedCel
|
|
|
55678
55842
|
selected: selectedNode.agentNodeId,
|
|
55679
55843
|
onSelect: onFallbackNodeChange
|
|
55680
55844
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MatrixGrid, {
|
|
55845
|
+
ref,
|
|
55681
55846
|
tree,
|
|
55682
55847
|
agents: shownAgents,
|
|
55683
55848
|
getCellState,
|
|
55684
55849
|
onCellClick,
|
|
55850
|
+
onStepClick,
|
|
55851
|
+
stepBadge,
|
|
55685
55852
|
selectedCell,
|
|
55686
|
-
single: single && selectedNode !== null
|
|
55853
|
+
single: single && selectedNode !== null,
|
|
55854
|
+
reserveRightPx,
|
|
55855
|
+
label
|
|
55687
55856
|
})]
|
|
55688
55857
|
});
|
|
55689
|
-
}
|
|
55858
|
+
});
|
|
55690
55859
|
//#endregion
|
|
55691
55860
|
//#region src/composites/discovery-panel.tsx
|
|
55692
55861
|
function DiscoveryPanel({ deviceId, className = "", onOpenChild }) {
|
|
@@ -56625,43 +56794,13 @@ function PhaseIcon({ phase, ...props }) {
|
|
|
56625
56794
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, { ...props });
|
|
56626
56795
|
}
|
|
56627
56796
|
//#endregion
|
|
56628
|
-
//#region src/lib/validate-template.ts
|
|
56629
|
-
function validateTemplate(steps, schema) {
|
|
56630
|
-
const availableAddonIds = new Set(schema.slots.flatMap((s) => s.addons.map((a) => a.id)));
|
|
56631
|
-
const warnings = [];
|
|
56632
|
-
function validateStep(step) {
|
|
56633
|
-
if (!availableAddonIds.has(step.addonId)) {
|
|
56634
|
-
warnings.push(`Addon "${step.addonId}" is no longer available — step removed`);
|
|
56635
|
-
return null;
|
|
56636
|
-
}
|
|
56637
|
-
const addon = schema.slots.flatMap((s) => s.addons).find((a) => a.id === step.addonId);
|
|
56638
|
-
let modelId = step.modelId;
|
|
56639
|
-
if (addon && !addon.models.some((m) => m.id === modelId)) {
|
|
56640
|
-
const fallback = addon.defaultModelId;
|
|
56641
|
-
warnings.push(`Model "${modelId}" not available for ${step.addonId} — using "${fallback}"`);
|
|
56642
|
-
modelId = fallback;
|
|
56643
|
-
}
|
|
56644
|
-
const validChildren = step.children.map((c) => validateStep(c)).filter((c) => c !== null);
|
|
56645
|
-
return {
|
|
56646
|
-
...step,
|
|
56647
|
-
modelId,
|
|
56648
|
-
children: validChildren
|
|
56649
|
-
};
|
|
56650
|
-
}
|
|
56651
|
-
const validSteps = steps.map((s) => validateStep(s)).filter((s) => s !== null);
|
|
56652
|
-
return {
|
|
56653
|
-
valid: warnings.length === 0,
|
|
56654
|
-
steps: validSteps,
|
|
56655
|
-
warnings
|
|
56656
|
-
};
|
|
56657
|
-
}
|
|
56658
|
-
//#endregion
|
|
56659
56797
|
//#region src/composites/pipeline-builder.tsx
|
|
56660
56798
|
/**
|
|
56661
|
-
* PipelineBuilder — orchestrates the pipeline step tree
|
|
56799
|
+
* PipelineBuilder — orchestrates the pipeline step tree.
|
|
56662
56800
|
*
|
|
56663
|
-
* Renders
|
|
56664
|
-
*
|
|
56801
|
+
* Renders the step tree from schema with nested children and placeholder steps
|
|
56802
|
+
* for disabled addons, all driven by API schema. There are no saved pipeline
|
|
56803
|
+
* templates (D759): the tree is the caller's state.
|
|
56665
56804
|
*/
|
|
56666
56805
|
function buildSchemaMap(schema) {
|
|
56667
56806
|
const map = /* @__PURE__ */ new Map();
|
|
@@ -56713,31 +56852,9 @@ function PlaceholderStep({ addon, onClick }) {
|
|
|
56713
56852
|
})
|
|
56714
56853
|
});
|
|
56715
56854
|
}
|
|
56716
|
-
function PipelineBuilder({ schema, steps, onChange,
|
|
56855
|
+
function PipelineBuilder({ schema, steps, onChange, readOnly = false, excludeAddons = [], showOnlyEnabled = false, showSlotLabels = false }) {
|
|
56717
56856
|
const excluded = (0, react$1.useMemo)(() => new Set(excludeAddons), [excludeAddons]);
|
|
56718
56857
|
const schemaMap = (0, react$1.useMemo)(() => buildSchemaMap(schema), [schema]);
|
|
56719
|
-
const [warnings, setWarnings] = (0, react$1.useState)([]);
|
|
56720
|
-
const dirty = selectedTemplateId ? JSON.stringify(steps) !== JSON.stringify(templates.find((t) => t.id === selectedTemplateId)?.steps) : false;
|
|
56721
|
-
function handleSelectTemplate(e) {
|
|
56722
|
-
const id = e.target.value || null;
|
|
56723
|
-
if (id) {
|
|
56724
|
-
const tpl = templates.find((t) => t.id === id);
|
|
56725
|
-
if (tpl) setWarnings([...validateTemplate(tpl.steps, schema).warnings]);
|
|
56726
|
-
} else setWarnings([]);
|
|
56727
|
-
onSelectTemplate(id);
|
|
56728
|
-
}
|
|
56729
|
-
function handleSave() {
|
|
56730
|
-
if (selectedTemplateId) onUpdateTemplate(selectedTemplateId, steps);
|
|
56731
|
-
}
|
|
56732
|
-
function handleSaveAs() {
|
|
56733
|
-
const name = window.prompt("Template name:");
|
|
56734
|
-
if (name?.trim()) onSaveTemplate(name.trim(), steps);
|
|
56735
|
-
}
|
|
56736
|
-
function handleDelete() {
|
|
56737
|
-
if (!selectedTemplateId) return;
|
|
56738
|
-
const tpl = templates.find((t) => t.id === selectedTemplateId);
|
|
56739
|
-
if (tpl && window.confirm(`Delete template "${tpl.name}"?`)) onDeleteTemplate(selectedTemplateId);
|
|
56740
|
-
}
|
|
56741
56858
|
/**
|
|
56742
56859
|
* When a step is updated, auto-enable the entire ancestor chain if a
|
|
56743
56860
|
* child/grandchild was just enabled. This ensures enabling face-recognition
|
|
@@ -56907,104 +57024,42 @@ function PipelineBuilder({ schema, steps, onChange, templates, selectedTemplateI
|
|
|
56907
57024
|
})]
|
|
56908
57025
|
}, step.addonId);
|
|
56909
57026
|
}
|
|
56910
|
-
|
|
56911
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
57027
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
56912
57028
|
className: "space-y-4",
|
|
56913
|
-
children:
|
|
56914
|
-
|
|
56915
|
-
|
|
56916
|
-
|
|
56917
|
-
|
|
56918
|
-
|
|
56919
|
-
|
|
56920
|
-
|
|
56921
|
-
|
|
56922
|
-
|
|
56923
|
-
|
|
56924
|
-
|
|
56925
|
-
|
|
56926
|
-
|
|
56927
|
-
|
|
56928
|
-
|
|
56929
|
-
|
|
56930
|
-
|
|
56931
|
-
|
|
56932
|
-
|
|
56933
|
-
|
|
56934
|
-
|
|
56935
|
-
|
|
56936
|
-
|
|
56937
|
-
|
|
56938
|
-
|
|
56939
|
-
|
|
56940
|
-
|
|
56941
|
-
|
|
56942
|
-
|
|
56943
|
-
|
|
56944
|
-
|
|
56945
|
-
|
|
56946
|
-
|
|
56947
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopyPlus, { className: "h-4 w-4" })
|
|
56948
|
-
}),
|
|
56949
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
56950
|
-
onClick: handleDelete,
|
|
56951
|
-
disabled: !selectedTemplateId || readOnly,
|
|
56952
|
-
title: "Delete",
|
|
56953
|
-
className: cn("p-2 rounded-lg border border-border transition-colors", selectedTemplateId && !readOnly ? "text-foreground-subtle hover:text-danger" : "text-foreground-subtle/30 cursor-not-allowed"),
|
|
56954
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Trash2, { className: "h-4 w-4" })
|
|
56955
|
-
})
|
|
56956
|
-
]
|
|
56957
|
-
})
|
|
56958
|
-
}),
|
|
56959
|
-
warnings.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
56960
|
-
className: "rounded-lg border border-amber-500/30 bg-amber-500/5 p-3 text-xs text-amber-400 space-y-1",
|
|
56961
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
56962
|
-
className: "flex items-center justify-between",
|
|
56963
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
56964
|
-
className: "font-medium",
|
|
56965
|
-
children: "Template loaded with warnings:"
|
|
56966
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
56967
|
-
onClick: () => setWarnings([]),
|
|
56968
|
-
className: "text-amber-400/60 hover:text-amber-400",
|
|
56969
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(X, { className: "h-3.5 w-3.5" })
|
|
56970
|
-
})]
|
|
56971
|
-
}), warnings.map((w, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: ["• ", w] }, i))]
|
|
56972
|
-
}),
|
|
56973
|
-
rootSlots.map((slot) => {
|
|
56974
|
-
const allSlotSteps = steps.filter((s) => s.slot === slot.id && !excluded.has(s.addonId));
|
|
56975
|
-
const slotSteps = showOnlyEnabled ? allSlotSteps.filter((s) => s.enabled) : allSlotSteps;
|
|
56976
|
-
const missingRootAddons = showOnlyEnabled ? [] : slot.addons.filter((a) => !existingIds.has(a.id) && !excluded.has(a.id));
|
|
56977
|
-
const groups = /* @__PURE__ */ new Map();
|
|
56978
|
-
const ungrouped = [];
|
|
56979
|
-
for (const step of slotSteps) if (step.group) {
|
|
56980
|
-
if (!groups.has(step.group)) groups.set(step.group, []);
|
|
56981
|
-
groups.get(step.group).push(step);
|
|
56982
|
-
} else ungrouped.push(step);
|
|
56983
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
56984
|
-
className: "space-y-2",
|
|
56985
|
-
children: [
|
|
56986
|
-
showSlotLabels && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
56987
|
-
className: "text-[10px] font-semibold uppercase tracking-widest text-foreground-subtle/50",
|
|
56988
|
-
children: ["Slot: ", slot.label]
|
|
56989
|
-
}),
|
|
56990
|
-
ungrouped.map((step) => renderStep(step)),
|
|
56991
|
-
[...groups.entries()].map(([groupName, groupSteps]) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
56992
|
-
className: "space-y-2 rounded-lg border border-border/40 p-2",
|
|
56993
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
56994
|
-
className: "text-[10px] font-semibold uppercase tracking-widest text-foreground-subtle/50 px-1",
|
|
56995
|
-
children: groupName
|
|
56996
|
-
}), groupSteps.map((step) => renderStep(step))]
|
|
56997
|
-
}, groupName)),
|
|
56998
|
-
!readOnly && missingRootAddons.map((addon) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PlaceholderStep, {
|
|
56999
|
-
addon,
|
|
57000
|
-
onClick: () => {
|
|
57001
|
-
onChange([...steps, createDefaultStep(addon)]);
|
|
57002
|
-
}
|
|
57003
|
-
}, addon.id))
|
|
57004
|
-
]
|
|
57005
|
-
}, slot.id);
|
|
57006
|
-
})
|
|
57007
|
-
]
|
|
57029
|
+
children: schema.slots.filter((s) => s.parentSlot === null).toSorted((a, b) => a.priority - b.priority).map((slot) => {
|
|
57030
|
+
const allSlotSteps = steps.filter((s) => s.slot === slot.id && !excluded.has(s.addonId));
|
|
57031
|
+
const slotSteps = showOnlyEnabled ? allSlotSteps.filter((s) => s.enabled) : allSlotSteps;
|
|
57032
|
+
const missingRootAddons = showOnlyEnabled ? [] : slot.addons.filter((a) => !existingIds.has(a.id) && !excluded.has(a.id));
|
|
57033
|
+
const groups = /* @__PURE__ */ new Map();
|
|
57034
|
+
const ungrouped = [];
|
|
57035
|
+
for (const step of slotSteps) if (step.group) {
|
|
57036
|
+
if (!groups.has(step.group)) groups.set(step.group, []);
|
|
57037
|
+
groups.get(step.group).push(step);
|
|
57038
|
+
} else ungrouped.push(step);
|
|
57039
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
57040
|
+
className: "space-y-2",
|
|
57041
|
+
children: [
|
|
57042
|
+
showSlotLabels && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
57043
|
+
className: "text-[10px] font-semibold uppercase tracking-widest text-foreground-subtle/50",
|
|
57044
|
+
children: ["Slot: ", slot.label]
|
|
57045
|
+
}),
|
|
57046
|
+
ungrouped.map((step) => renderStep(step)),
|
|
57047
|
+
[...groups.entries()].map(([groupName, groupSteps]) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
57048
|
+
className: "space-y-2 rounded-lg border border-border/40 p-2",
|
|
57049
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
57050
|
+
className: "text-[10px] font-semibold uppercase tracking-widest text-foreground-subtle/50 px-1",
|
|
57051
|
+
children: groupName
|
|
57052
|
+
}), groupSteps.map((step) => renderStep(step))]
|
|
57053
|
+
}, groupName)),
|
|
57054
|
+
!readOnly && missingRootAddons.map((addon) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PlaceholderStep, {
|
|
57055
|
+
addon,
|
|
57056
|
+
onClick: () => {
|
|
57057
|
+
onChange([...steps, createDefaultStep(addon)]);
|
|
57058
|
+
}
|
|
57059
|
+
}, addon.id))
|
|
57060
|
+
]
|
|
57061
|
+
}, slot.id);
|
|
57062
|
+
})
|
|
57008
57063
|
});
|
|
57009
57064
|
}
|
|
57010
57065
|
//#endregion
|
|
@@ -57793,166 +57848,104 @@ function SegmentedChoice({ label, options, value, onChange }) {
|
|
|
57793
57848
|
});
|
|
57794
57849
|
}
|
|
57795
57850
|
//#endregion
|
|
57796
|
-
//#region src/composites/step-inspector/step-
|
|
57797
|
-
function chipText(state) {
|
|
57798
|
-
switch (state.kind) {
|
|
57799
|
-
case "enabled":
|
|
57800
|
-
if (state.suppliedByRoot !== void 0) return "root";
|
|
57801
|
-
return state.jumpTo !== void 0 ? `→ ${state.jumpTo}` : state.modelId;
|
|
57802
|
-
case "skip": return state.jumpTo !== void 0 ? `→ ${state.jumpTo}` : "skip";
|
|
57803
|
-
case "disabled": return "off";
|
|
57804
|
-
case "na": return "—";
|
|
57805
|
-
}
|
|
57806
|
-
}
|
|
57807
|
-
/** What a chip MEANS — the full model id, not its shortened text. */
|
|
57808
|
-
function chipKey(state) {
|
|
57809
|
-
return state.kind === "enabled" ? `${state.modelId}|${chipText(state)}` : chipText(state);
|
|
57810
|
-
}
|
|
57811
|
-
function chipTone(state, selected) {
|
|
57812
|
-
if (selected) return "border-primary/60 text-primary";
|
|
57813
|
-
if (state.kind === "skip" && state.jumpTo === void 0) return "border-amber-500/40 text-amber-500";
|
|
57814
|
-
if (state.kind === "na" || state.kind === "disabled") return "border-border/60 text-foreground-subtle/70";
|
|
57815
|
-
return "border-border text-foreground-subtle";
|
|
57816
|
-
}
|
|
57817
|
-
function StepChips({ chips, selectedId }) {
|
|
57818
|
-
const first = chips[0];
|
|
57819
|
-
if (first !== void 0 && chips.length > 1 && chips.every((c) => chipKey(c.state) === chipKey(first.state) && !(c.state.kind === "enabled" && c.state.overridden === true) && chipTone(c.state, c.id === selectedId) === chipTone(first.state, first.id === selectedId)) && first !== void 0) {
|
|
57820
|
-
const text = chipText(first.state);
|
|
57821
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
57822
|
-
className: "flex flex-wrap gap-1",
|
|
57823
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
57824
|
-
title: `${text} on ${chips.map((c) => c.label).join(", ")}`,
|
|
57825
|
-
className: cn("inline-flex max-w-[12rem] items-center gap-1 truncate rounded border px-1 font-mono text-[9px] leading-4", chipTone(first.state, first.id === selectedId)),
|
|
57826
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
57827
|
-
className: "truncate",
|
|
57828
|
-
children: text
|
|
57829
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
57830
|
-
className: "shrink-0 font-sans text-foreground-subtle/80",
|
|
57831
|
-
children: ["×", chips.length]
|
|
57832
|
-
})]
|
|
57833
|
-
})
|
|
57834
|
-
});
|
|
57835
|
-
}
|
|
57836
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
57837
|
-
className: "flex flex-wrap gap-1",
|
|
57838
|
-
children: chips.map((chip) => {
|
|
57839
|
-
const overridden = chip.state.kind === "enabled" && chip.state.overridden === true;
|
|
57840
|
-
const text = chipText(chip.state);
|
|
57841
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
57842
|
-
title: `${chip.label}: ${chip.state.kind === "enabled" ? chip.state.modelId : text}${overridden ? " (camera override)" : ""}`,
|
|
57843
|
-
className: cn("inline-flex max-w-[9rem] items-center gap-0.5 truncate rounded border px-1 font-mono text-[9px] leading-4", chipTone(chip.state, chip.id === selectedId)),
|
|
57844
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
57845
|
-
className: "truncate",
|
|
57846
|
-
children: text
|
|
57847
|
-
}), overridden && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
57848
|
-
className: "text-amber-500",
|
|
57849
|
-
"aria-hidden": true,
|
|
57850
|
-
children: "•"
|
|
57851
|
-
})]
|
|
57852
|
-
}, chip.id);
|
|
57853
|
-
})
|
|
57854
|
-
});
|
|
57855
|
-
}
|
|
57856
|
-
//#endregion
|
|
57857
|
-
//#region src/composites/step-inspector/step-inspector-layout.tsx
|
|
57851
|
+
//#region src/composites/step-inspector/step-detail-dock.tsx
|
|
57858
57852
|
/**
|
|
57859
|
-
*
|
|
57853
|
+
* StepDetailDock — where a step's settings open from the step matrix
|
|
57854
|
+
* (D757): docked to the page's scroll container, never inside the scrolling
|
|
57855
|
+
* content.
|
|
57860
57856
|
*
|
|
57861
|
-
* Desktop:
|
|
57862
|
-
*
|
|
57863
|
-
*
|
|
57864
|
-
* save bar are always on screen
|
|
57865
|
-
*
|
|
57866
|
-
* matrix
|
|
57867
|
-
*
|
|
57868
|
-
*
|
|
57857
|
+
* Desktop: a side panel `position: fixed` over the RIGHT edge of the nearest
|
|
57858
|
+
* scroll container (its top, bottom and right are measured from that box), so
|
|
57859
|
+
* it stays where it is while the matrix scrolls under it, and its header and
|
|
57860
|
+
* save bar are always on screen. It overlays — it never reserves width, so the
|
|
57861
|
+
* matrix does not reflow (the slide-over before D756 reserved 360 px, the
|
|
57862
|
+
* matrix re-measured into a single-node layout, and the clicked cell slid
|
|
57863
|
+
* under the panel). The matrix uses {@link STEP_DOCK_WIDTH_PX} to scroll the
|
|
57864
|
+
* selected column clear of it.
|
|
57869
57865
|
*
|
|
57870
|
-
* Phone:
|
|
57871
|
-
* sheet with "‹ Steps" to go back.
|
|
57866
|
+
* Phone: a full-screen `Dialog` sheet.
|
|
57872
57867
|
*/
|
|
57873
|
-
/**
|
|
57874
|
-
|
|
57875
|
-
|
|
57876
|
-
|
|
57868
|
+
/** Width of the desktop dock — what the matrix keeps clear of it. */
|
|
57869
|
+
var STEP_DOCK_WIDTH_PX = 432;
|
|
57870
|
+
/** The dock's viewport box, from its scroll container's box. */
|
|
57871
|
+
function dockBox(input) {
|
|
57872
|
+
const right = Math.max(0, input.viewportWidth - input.scroller.right);
|
|
57873
|
+
const width = Math.min(input.widthPx, input.scroller.right);
|
|
57874
|
+
return {
|
|
57875
|
+
top: Math.max(0, input.scroller.top),
|
|
57876
|
+
height: Math.max(0, input.scroller.bottom - Math.max(0, input.scroller.top)),
|
|
57877
|
+
right,
|
|
57878
|
+
width
|
|
57879
|
+
};
|
|
57877
57880
|
}
|
|
57878
57881
|
function scrollParentOf(el) {
|
|
57879
|
-
for (let p = el
|
|
57882
|
+
for (let p = el?.parentElement ?? null; p !== null; p = p.parentElement) {
|
|
57880
57883
|
const { overflowY } = getComputedStyle(p);
|
|
57881
57884
|
if (overflowY === "auto" || overflowY === "scroll") return p;
|
|
57882
57885
|
}
|
|
57883
57886
|
return null;
|
|
57884
57887
|
}
|
|
57885
|
-
|
|
57886
|
-
|
|
57887
|
-
const ref = (0, react$1.useRef)(null);
|
|
57888
|
-
const [height, setHeight] = (0, react$1.useState)(null);
|
|
57888
|
+
function useDockBox(anchor, enabled) {
|
|
57889
|
+
const [box, setBox] = (0, react$1.useState)(null);
|
|
57889
57890
|
(0, react$1.useLayoutEffect)(() => {
|
|
57890
|
-
|
|
57891
|
-
|
|
57892
|
-
const scroller = scrollParentOf(el);
|
|
57891
|
+
if (!enabled) return;
|
|
57892
|
+
const scroller = scrollParentOf(anchor.current);
|
|
57893
57893
|
const measure = () => {
|
|
57894
|
-
|
|
57895
|
-
|
|
57896
|
-
|
|
57897
|
-
|
|
57898
|
-
|
|
57899
|
-
|
|
57900
|
-
|
|
57901
|
-
|
|
57902
|
-
minPx
|
|
57894
|
+
setBox(dockBox({
|
|
57895
|
+
scroller: scroller?.getBoundingClientRect() ?? {
|
|
57896
|
+
top: 0,
|
|
57897
|
+
bottom: window.innerHeight,
|
|
57898
|
+
right: window.innerWidth
|
|
57899
|
+
},
|
|
57900
|
+
viewportWidth: window.innerWidth,
|
|
57901
|
+
widthPx: 432
|
|
57903
57902
|
}));
|
|
57904
57903
|
};
|
|
57905
57904
|
measure();
|
|
57906
57905
|
const RO = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(measure);
|
|
57907
57906
|
if (scroller) RO?.observe(scroller);
|
|
57908
|
-
if (el.parentElement) RO?.observe(el.parentElement);
|
|
57909
57907
|
window.addEventListener("resize", measure);
|
|
57910
57908
|
return () => {
|
|
57911
57909
|
RO?.disconnect();
|
|
57912
57910
|
window.removeEventListener("resize", measure);
|
|
57913
57911
|
};
|
|
57914
|
-
}, [
|
|
57915
|
-
return
|
|
57916
|
-
ref,
|
|
57917
|
-
height
|
|
57918
|
-
};
|
|
57912
|
+
}, [anchor, enabled]);
|
|
57913
|
+
return box;
|
|
57919
57914
|
}
|
|
57920
|
-
function
|
|
57915
|
+
function StepDetailDock({ open, anchor, onClose, label, children }) {
|
|
57921
57916
|
const isMobile = useIsMobile();
|
|
57922
|
-
const
|
|
57923
|
-
if (isMobile) return /* @__PURE__ */ (0, react_jsx_runtime.
|
|
57924
|
-
|
|
57925
|
-
|
|
57926
|
-
|
|
57927
|
-
|
|
57928
|
-
|
|
57929
|
-
|
|
57930
|
-
|
|
57931
|
-
children:
|
|
57932
|
-
placement: "sheet-on-mobile",
|
|
57933
|
-
scroll: "body",
|
|
57934
|
-
className: "h-[100dvh] max-h-none w-full max-w-full rounded-none border-0 p-0 pt-[env(safe-area-inset-top)] pb-[env(safe-area-inset-bottom)]",
|
|
57935
|
-
children: mobileDetailOpen && detail
|
|
57936
|
-
})
|
|
57937
|
-
})]
|
|
57938
|
-
});
|
|
57939
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
57940
|
-
ref,
|
|
57941
|
-
className: cn("@container/inspector", className),
|
|
57942
|
-
style: height !== null ? { height } : void 0,
|
|
57943
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
57944
|
-
className: cn("grid h-full min-h-0 gap-3", "grid-cols-1 grid-rows-[minmax(9rem,32%)_minmax(0,1fr)]", "@xl/inspector:grid-cols-[minmax(14rem,19rem)_minmax(0,1fr)] @xl/inspector:grid-rows-1"),
|
|
57945
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
57946
|
-
className: cn(SECTION_CARD, "flex min-h-0 flex-col"),
|
|
57947
|
-
children: list
|
|
57948
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
57949
|
-
className: cn(SECTION_CARD, "flex min-h-0 flex-col"),
|
|
57950
|
-
children: detail
|
|
57951
|
-
})]
|
|
57917
|
+
const box = useDockBox(anchor, open && !isMobile);
|
|
57918
|
+
if (isMobile) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Dialog, {
|
|
57919
|
+
open,
|
|
57920
|
+
onOpenChange: (next) => !next && onClose(),
|
|
57921
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DialogContent, {
|
|
57922
|
+
placement: "sheet-on-mobile",
|
|
57923
|
+
scroll: "body",
|
|
57924
|
+
"aria-label": label,
|
|
57925
|
+
className: "h-[100dvh] max-h-none w-full max-w-full rounded-none border-0 p-0 pt-[env(safe-area-inset-top)] pb-[env(safe-area-inset-bottom)]",
|
|
57926
|
+
children: open && children
|
|
57952
57927
|
})
|
|
57953
57928
|
});
|
|
57929
|
+
if (!open) return null;
|
|
57930
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("aside", {
|
|
57931
|
+
"aria-label": label,
|
|
57932
|
+
"data-step-dock": true,
|
|
57933
|
+
className: "fixed z-30 flex flex-col border-l border-border bg-surface shadow-2xl",
|
|
57934
|
+
style: box !== null ? {
|
|
57935
|
+
top: box.top,
|
|
57936
|
+
height: box.height,
|
|
57937
|
+
right: box.right,
|
|
57938
|
+
width: box.width
|
|
57939
|
+
} : {
|
|
57940
|
+
top: 0,
|
|
57941
|
+
bottom: 0,
|
|
57942
|
+
right: 0,
|
|
57943
|
+
width: 432
|
|
57944
|
+
},
|
|
57945
|
+
children
|
|
57946
|
+
});
|
|
57954
57947
|
}
|
|
57955
|
-
/** "‹ Steps" — the phone sheet's way back to the
|
|
57948
|
+
/** "‹ Steps" — the phone sheet's way back to the matrix. */
|
|
57956
57949
|
function BackToStepsButton({ onClick }) {
|
|
57957
57950
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
57958
57951
|
type: "button",
|
|
@@ -58045,192 +58038,6 @@ var StepInspectorPanel = (0, react$1.forwardRef)(function StepInspectorPanel({ t
|
|
|
58045
58038
|
});
|
|
58046
58039
|
});
|
|
58047
58040
|
//#endregion
|
|
58048
|
-
//#region src/composites/step-inspector/step-list.tsx
|
|
58049
|
-
/**
|
|
58050
|
-
* StepList — the master pane of the step inspector: every detection step of the
|
|
58051
|
-
* tree, one compact row each, as ONE tab stop.
|
|
58052
|
-
*
|
|
58053
|
-
* Keyboard (a listbox with a roving tabindex): ↑/↓/Home/End move the selection,
|
|
58054
|
-
* Enter or → hands focus to the inspector, `/` jumps to the search box. The
|
|
58055
|
-
* search matches a step's name or any of its field labels, so a question about
|
|
58056
|
-
* a knob ("face size", "person") finds the step that owns it; Enter in the box
|
|
58057
|
-
* selects the first hit and says which field it matched.
|
|
58058
|
-
*/
|
|
58059
|
-
function matches(text, tokens) {
|
|
58060
|
-
const lower = text.toLowerCase();
|
|
58061
|
-
return tokens.every((t) => lower.includes(t));
|
|
58062
|
-
}
|
|
58063
|
-
/** Rows matching `query` (all tokens in the name, or all in one field label). */
|
|
58064
|
-
function searchSteps(rows, query) {
|
|
58065
|
-
const tokens = query.trim().toLowerCase().split(/\s+/).filter(Boolean);
|
|
58066
|
-
if (tokens.length === 0) return rows.map((row) => ({ row }));
|
|
58067
|
-
const hits = [];
|
|
58068
|
-
for (const row of rows) {
|
|
58069
|
-
if (matches(row.name, tokens)) {
|
|
58070
|
-
hits.push({ row });
|
|
58071
|
-
continue;
|
|
58072
|
-
}
|
|
58073
|
-
const field = row.fieldLabels.find((l) => matches(l, tokens));
|
|
58074
|
-
if (field !== void 0) hits.push({
|
|
58075
|
-
row,
|
|
58076
|
-
matchedField: field
|
|
58077
|
-
});
|
|
58078
|
-
}
|
|
58079
|
-
return hits;
|
|
58080
|
-
}
|
|
58081
|
-
var StepList = (0, react$1.forwardRef)(function StepList({ rows, selectedId, onSelect, onActivate, onPick, label, className }, ref) {
|
|
58082
|
-
const [query, setQuery] = (0, react$1.useState)("");
|
|
58083
|
-
const listRef = (0, react$1.useRef)(null);
|
|
58084
|
-
const searchRef = (0, react$1.useRef)(null);
|
|
58085
|
-
const hits = (0, react$1.useMemo)(() => searchSteps(rows, query), [rows, query]);
|
|
58086
|
-
const tabStopId = hits.some((h) => h.row.addonId === selectedId) ? selectedId : hits[0]?.row.addonId ?? null;
|
|
58087
|
-
const pendingFocus = (0, react$1.useRef)(null);
|
|
58088
|
-
const tryFocus = (addonId) => {
|
|
58089
|
-
const el = listRef.current?.querySelector(`[data-step-id="${addonId}"]`);
|
|
58090
|
-
if (!el) return false;
|
|
58091
|
-
el.focus();
|
|
58092
|
-
return true;
|
|
58093
|
-
};
|
|
58094
|
-
const focusRow = (addonId) => {
|
|
58095
|
-
if (addonId === null) return;
|
|
58096
|
-
pendingFocus.current = tryFocus(addonId) ? null : addonId;
|
|
58097
|
-
};
|
|
58098
|
-
(0, react$1.useLayoutEffect)(() => {
|
|
58099
|
-
if (pendingFocus.current !== null && tryFocus(pendingFocus.current)) pendingFocus.current = null;
|
|
58100
|
-
});
|
|
58101
|
-
(0, react$1.useImperativeHandle)(ref, () => ({ focusSelected: () => focusRow(selectedId) }), [selectedId]);
|
|
58102
|
-
const move = (index) => {
|
|
58103
|
-
const target = hits[Math.max(0, Math.min(hits.length - 1, index))];
|
|
58104
|
-
if (target === void 0) return;
|
|
58105
|
-
onSelect(target.row.addonId, target.matchedField);
|
|
58106
|
-
focusRow(target.row.addonId);
|
|
58107
|
-
};
|
|
58108
|
-
const onRowKeyDown = (e, index, hit) => {
|
|
58109
|
-
switch (e.key) {
|
|
58110
|
-
case "ArrowDown":
|
|
58111
|
-
e.preventDefault();
|
|
58112
|
-
move(index + 1);
|
|
58113
|
-
return;
|
|
58114
|
-
case "ArrowUp":
|
|
58115
|
-
e.preventDefault();
|
|
58116
|
-
move(index - 1);
|
|
58117
|
-
return;
|
|
58118
|
-
case "Home":
|
|
58119
|
-
e.preventDefault();
|
|
58120
|
-
move(0);
|
|
58121
|
-
return;
|
|
58122
|
-
case "End":
|
|
58123
|
-
e.preventDefault();
|
|
58124
|
-
move(hits.length - 1);
|
|
58125
|
-
return;
|
|
58126
|
-
case "Enter":
|
|
58127
|
-
case "ArrowRight":
|
|
58128
|
-
e.preventDefault();
|
|
58129
|
-
onActivate(hit.row.addonId);
|
|
58130
|
-
return;
|
|
58131
|
-
case "/":
|
|
58132
|
-
e.preventDefault();
|
|
58133
|
-
searchRef.current?.focus();
|
|
58134
|
-
return;
|
|
58135
|
-
default:
|
|
58136
|
-
}
|
|
58137
|
-
};
|
|
58138
|
-
const onSearchKeyDown = (e) => {
|
|
58139
|
-
if (e.key === "Enter") {
|
|
58140
|
-
e.preventDefault();
|
|
58141
|
-
const first = hits[0];
|
|
58142
|
-
if (first !== void 0) {
|
|
58143
|
-
onSelect(first.row.addonId, first.matchedField);
|
|
58144
|
-
onPick?.(first.row.addonId);
|
|
58145
|
-
focusRow(first.row.addonId);
|
|
58146
|
-
}
|
|
58147
|
-
} else if (e.key === "Escape") {
|
|
58148
|
-
e.preventDefault();
|
|
58149
|
-
setQuery("");
|
|
58150
|
-
focusRow(selectedId);
|
|
58151
|
-
} else if (e.key === "ArrowDown") {
|
|
58152
|
-
e.preventDefault();
|
|
58153
|
-
focusRow(tabStopId);
|
|
58154
|
-
}
|
|
58155
|
-
};
|
|
58156
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
58157
|
-
className: cn("flex min-h-0 flex-col", className),
|
|
58158
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
58159
|
-
className: "relative shrink-0 border-b border-border p-1.5",
|
|
58160
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Search, {
|
|
58161
|
-
className: "pointer-events-none absolute left-3.5 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-foreground-subtle",
|
|
58162
|
-
"aria-hidden": true
|
|
58163
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
58164
|
-
ref: searchRef,
|
|
58165
|
-
type: "search",
|
|
58166
|
-
value: query,
|
|
58167
|
-
onChange: (e) => setQuery(e.target.value),
|
|
58168
|
-
onKeyDown: onSearchKeyDown,
|
|
58169
|
-
placeholder: "Find a step or setting /",
|
|
58170
|
-
"aria-label": "Find a step or setting",
|
|
58171
|
-
className: "h-9 w-full rounded-md border border-border bg-background pl-8 pr-2 text-xs text-foreground outline-none focus:border-primary focus:ring-1 focus:ring-primary/30 md:h-8"
|
|
58172
|
-
})]
|
|
58173
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("ul", {
|
|
58174
|
-
ref: listRef,
|
|
58175
|
-
role: "listbox",
|
|
58176
|
-
"aria-label": label,
|
|
58177
|
-
className: "min-h-0 flex-1 overflow-y-auto py-1",
|
|
58178
|
-
children: [hits.map((hit, index) => {
|
|
58179
|
-
const { row } = hit;
|
|
58180
|
-
const selected = row.addonId === selectedId;
|
|
58181
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
|
|
58182
|
-
role: "option",
|
|
58183
|
-
"aria-selected": selected,
|
|
58184
|
-
tabIndex: row.addonId === tabStopId ? 0 : -1,
|
|
58185
|
-
"data-step-id": row.addonId,
|
|
58186
|
-
onClick: () => {
|
|
58187
|
-
onSelect(row.addonId, hit.matchedField);
|
|
58188
|
-
onPick?.(row.addonId);
|
|
58189
|
-
},
|
|
58190
|
-
onKeyDown: (e) => onRowKeyDown(e, index, hit),
|
|
58191
|
-
className: cn("cursor-pointer border-l-2 py-1 pl-2.5 pr-3 outline-none transition-colors", "focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-primary", selected ? "border-primary bg-primary/10" : "border-transparent hover:bg-muted/40"),
|
|
58192
|
-
children: [
|
|
58193
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
58194
|
-
className: "flex min-w-0 items-baseline gap-2",
|
|
58195
|
-
children: [
|
|
58196
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
58197
|
-
className: "w-[4.5rem] shrink-0 truncate",
|
|
58198
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SlotHeading, { slot: row.slot })
|
|
58199
|
-
}),
|
|
58200
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
58201
|
-
className: cn("min-w-0 flex-1 truncate text-xs font-medium", selected ? "text-foreground" : "text-foreground/90"),
|
|
58202
|
-
style: { paddingLeft: `${row.depth * 12}px` },
|
|
58203
|
-
children: [row.depth > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
58204
|
-
className: "mr-1 text-foreground-subtle/60",
|
|
58205
|
-
"aria-hidden": true,
|
|
58206
|
-
children: "└"
|
|
58207
|
-
}), row.name]
|
|
58208
|
-
}),
|
|
58209
|
-
row.status
|
|
58210
|
-
]
|
|
58211
|
-
}),
|
|
58212
|
-
hit.matchedField !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
58213
|
-
className: "mt-0.5 truncate pl-[5rem] text-[10px] text-primary",
|
|
58214
|
-
children: ["↳ ", hit.matchedField]
|
|
58215
|
-
}),
|
|
58216
|
-
row.detail !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
58217
|
-
className: "mt-0.5 pl-[5rem]",
|
|
58218
|
-
children: row.detail
|
|
58219
|
-
})
|
|
58220
|
-
]
|
|
58221
|
-
}, row.addonId);
|
|
58222
|
-
}), hits.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
|
|
58223
|
-
className: "px-3 py-4 text-center text-[11px] text-foreground-subtle",
|
|
58224
|
-
children: [
|
|
58225
|
-
"No step matches “",
|
|
58226
|
-
query,
|
|
58227
|
-
"”."
|
|
58228
|
-
]
|
|
58229
|
-
})]
|
|
58230
|
-
})]
|
|
58231
|
-
});
|
|
58232
|
-
});
|
|
58233
|
-
//#endregion
|
|
58234
58041
|
//#region src/composites/step-inspector/step-model-row.tsx
|
|
58235
58042
|
var SOURCE_TONE = {
|
|
58236
58043
|
camera: "border-primary/40 bg-primary/10 text-primary",
|
|
@@ -58386,6 +58193,30 @@ function StepModelList({ rows }) {
|
|
|
58386
58193
|
});
|
|
58387
58194
|
}
|
|
58388
58195
|
//#endregion
|
|
58196
|
+
//#region src/composites/step-inspector/step-search.ts
|
|
58197
|
+
function matches(text, tokens) {
|
|
58198
|
+
const lower = text.toLowerCase();
|
|
58199
|
+
return tokens.every((t) => lower.includes(t));
|
|
58200
|
+
}
|
|
58201
|
+
/** Steps matching `query` (all tokens in the name, or all in one field label). Empty query = all. */
|
|
58202
|
+
function searchSteps(rows, query) {
|
|
58203
|
+
const tokens = query.trim().toLowerCase().split(/\s+/).filter(Boolean);
|
|
58204
|
+
if (tokens.length === 0) return rows.map((row) => ({ addonId: row.addonId }));
|
|
58205
|
+
const hits = [];
|
|
58206
|
+
for (const row of rows) {
|
|
58207
|
+
if (matches(row.name, tokens)) {
|
|
58208
|
+
hits.push({ addonId: row.addonId });
|
|
58209
|
+
continue;
|
|
58210
|
+
}
|
|
58211
|
+
const field = row.fieldLabels.find((l) => matches(l, tokens));
|
|
58212
|
+
if (field !== void 0) hits.push({
|
|
58213
|
+
addonId: row.addonId,
|
|
58214
|
+
matchedField: field
|
|
58215
|
+
});
|
|
58216
|
+
}
|
|
58217
|
+
return hits;
|
|
58218
|
+
}
|
|
58219
|
+
//#endregion
|
|
58389
58220
|
//#region src/composites/step-tree.ts
|
|
58390
58221
|
/**
|
|
58391
58222
|
* Helper: build a StepTreeNode[] from a `PipelineSchema` by chaining on
|
|
@@ -61589,6 +61420,7 @@ exports.SPLIT_PANEL_OUTER = SPLIT_PANEL_OUTER;
|
|
|
61589
61420
|
exports.SPLIT_PANEL_SIDE = SPLIT_PANEL_SIDE;
|
|
61590
61421
|
exports.STACK_GAP = STACK_GAP;
|
|
61591
61422
|
exports.STATE_COLOR = STATE_COLOR;
|
|
61423
|
+
exports.STEP_DOCK_WIDTH_PX = STEP_DOCK_WIDTH_PX;
|
|
61592
61424
|
exports.SceneMonitorEditor = SceneMonitorEditor;
|
|
61593
61425
|
exports.ScopePicker = ScopePicker;
|
|
61594
61426
|
exports.ScriptHeroCard = ScriptHeroCard;
|
|
@@ -61614,10 +61446,8 @@ exports.Square = Square;
|
|
|
61614
61446
|
exports.StatCard = StatCard;
|
|
61615
61447
|
exports.StateValuesStream = StateValuesStream;
|
|
61616
61448
|
exports.StatusBadge = StatusBadge;
|
|
61617
|
-
exports.
|
|
61618
|
-
exports.StepInspectorLayout = StepInspectorLayout;
|
|
61449
|
+
exports.StepDetailDock = StepDetailDock;
|
|
61619
61450
|
exports.StepInspectorPanel = StepInspectorPanel;
|
|
61620
|
-
exports.StepList = StepList;
|
|
61621
61451
|
exports.StepModelList = StepModelList;
|
|
61622
61452
|
exports.StepModelRow = StepModelRow;
|
|
61623
61453
|
exports.StepTimings = StepTimings;
|
|
@@ -61667,6 +61497,8 @@ exports.WidgetPanel = WidgetPanel;
|
|
|
61667
61497
|
exports.WidgetRegistryProvider = WidgetRegistryProvider;
|
|
61668
61498
|
exports.WidgetSlot = WidgetSlot;
|
|
61669
61499
|
exports.ZoneEditingProvider = ZoneEditingProvider;
|
|
61500
|
+
exports.acceleratorLabel = acceleratorLabel;
|
|
61501
|
+
exports.acceleratorShortLabel = acceleratorShortLabel;
|
|
61670
61502
|
exports.agentColumnKey = agentColumnKey;
|
|
61671
61503
|
exports.allDeviceTypeFilterOptions = allDeviceTypeFilterOptions;
|
|
61672
61504
|
exports.applyFleetQueryDefaults = applyFleetQueryDefaults;
|
|
@@ -61714,12 +61546,12 @@ exports.deviceTypeLabel = deviceTypeLabel;
|
|
|
61714
61546
|
exports.deviceTypeMeta = deviceTypeMeta;
|
|
61715
61547
|
exports.deviceTypeMetaOf = deviceTypeMetaOf;
|
|
61716
61548
|
exports.devicesToOptions = devicesToOptions;
|
|
61549
|
+
exports.dockBox = dockBox;
|
|
61717
61550
|
exports.draftFromQuery = draftFromQuery;
|
|
61718
61551
|
exports.emptyDevicesWidens = emptyDevicesWidens;
|
|
61719
61552
|
exports.emptySessionRun = emptySessionRun;
|
|
61720
61553
|
exports.ensureMfHostInit = ensureMfHostInit;
|
|
61721
61554
|
exports.eventKindLabel = eventKindLabel;
|
|
61722
|
-
exports.fillHeightPx = fillHeightPx;
|
|
61723
61555
|
exports.filterDataTableRows = filterDataTableRows;
|
|
61724
61556
|
exports.filterDeviceOptions = filterDeviceOptions;
|
|
61725
61557
|
exports.filterOptionSelectOptions = filterOptions;
|
|
@@ -61767,6 +61599,7 @@ exports.mirror = mirror;
|
|
|
61767
61599
|
exports.modelRowsAreFoldable = modelRowsAreFoldable;
|
|
61768
61600
|
exports.mountAddonPage = mountAddonPage;
|
|
61769
61601
|
exports.mountPath = mountPath;
|
|
61602
|
+
exports.nextGridPosition = nextGridPosition;
|
|
61770
61603
|
exports.nextReconnectAction = nextReconnectAction;
|
|
61771
61604
|
exports.nextSort = nextSort;
|
|
61772
61605
|
exports.nextSortDirection = nextSortDirection;
|
|
@@ -62586,7 +62419,6 @@ exports.usePipelineExecutorCacheFrameInPool = usePipelineExecutorCacheFrameInPoo
|
|
|
62586
62419
|
exports.usePipelineExecutorClearDeviceOverrides = usePipelineExecutorClearDeviceOverrides;
|
|
62587
62420
|
exports.usePipelineExecutorClearModelBoundDeviceOverrides = usePipelineExecutorClearModelBoundDeviceOverrides;
|
|
62588
62421
|
exports.usePipelineExecutorDeleteModel = usePipelineExecutorDeleteModel;
|
|
62589
|
-
exports.usePipelineExecutorDeleteTemplate = usePipelineExecutorDeleteTemplate;
|
|
62590
62422
|
exports.usePipelineExecutorDownloadModel = usePipelineExecutorDownloadModel;
|
|
62591
62423
|
exports.usePipelineExecutorGetAddonModels = usePipelineExecutorGetAddonModels;
|
|
62592
62424
|
exports.usePipelineExecutorGetAudioCapabilities = usePipelineExecutorGetAudioCapabilities;
|
|
@@ -62610,22 +62442,18 @@ exports.usePipelineExecutorInferCached = usePipelineExecutorInferCached;
|
|
|
62610
62442
|
exports.usePipelineExecutorKillEngine = usePipelineExecutorKillEngine;
|
|
62611
62443
|
exports.usePipelineExecutorListLoadedEngines = usePipelineExecutorListLoadedEngines;
|
|
62612
62444
|
exports.usePipelineExecutorListReferenceImages = usePipelineExecutorListReferenceImages;
|
|
62613
|
-
exports.usePipelineExecutorListTemplates = usePipelineExecutorListTemplates;
|
|
62614
62445
|
exports.usePipelineExecutorRearmInferenceDevice = usePipelineExecutorRearmInferenceDevice;
|
|
62615
62446
|
exports.usePipelineExecutorRunAudioTest = usePipelineExecutorRunAudioTest;
|
|
62616
62447
|
exports.usePipelineExecutorRunPipeline = usePipelineExecutorRunPipeline;
|
|
62617
62448
|
exports.usePipelineExecutorRunPipelineBatch = usePipelineExecutorRunPipelineBatch;
|
|
62618
|
-
exports.usePipelineExecutorSaveTemplate = usePipelineExecutorSaveTemplate;
|
|
62619
62449
|
exports.usePipelineExecutorSetVideoPipelineSteps = usePipelineExecutorSetVideoPipelineSteps;
|
|
62620
62450
|
exports.usePipelineExecutorSpinEngine = usePipelineExecutorSpinEngine;
|
|
62621
62451
|
exports.usePipelineExecutorUncacheFrame = usePipelineExecutorUncacheFrame;
|
|
62622
|
-
exports.usePipelineExecutorUpdateTemplate = usePipelineExecutorUpdateTemplate;
|
|
62623
62452
|
exports.usePipelineExecutorValidatePipeline = usePipelineExecutorValidatePipeline;
|
|
62624
62453
|
exports.usePipelineOrchestratorApplyAutoTune = usePipelineOrchestratorApplyAutoTune;
|
|
62625
62454
|
exports.usePipelineOrchestratorApplyDeviceSettingsPatch = usePipelineOrchestratorApplyDeviceSettingsPatch;
|
|
62626
62455
|
exports.usePipelineOrchestratorAssignAudio = usePipelineOrchestratorAssignAudio;
|
|
62627
62456
|
exports.usePipelineOrchestratorAssignPipeline = usePipelineOrchestratorAssignPipeline;
|
|
62628
|
-
exports.usePipelineOrchestratorDeleteTemplate = usePipelineOrchestratorDeleteTemplate;
|
|
62629
62457
|
exports.usePipelineOrchestratorGetAgentLoad = usePipelineOrchestratorGetAgentLoad;
|
|
62630
62458
|
exports.usePipelineOrchestratorGetAgentSettings = usePipelineOrchestratorGetAgentSettings;
|
|
62631
62459
|
exports.usePipelineOrchestratorGetAudioAssignment = usePipelineOrchestratorGetAudioAssignment;
|
|
@@ -62651,7 +62479,6 @@ exports.usePipelineOrchestratorGetPipelineDevicePin = usePipelineOrchestratorGet
|
|
|
62651
62479
|
exports.usePipelineOrchestratorGetPlacementStats = usePipelineOrchestratorGetPlacementStats;
|
|
62652
62480
|
exports.usePipelineOrchestratorGetReconcileFromDiskStatus = usePipelineOrchestratorGetReconcileFromDiskStatus;
|
|
62653
62481
|
exports.usePipelineOrchestratorListAgentSettings = usePipelineOrchestratorListAgentSettings;
|
|
62654
|
-
exports.usePipelineOrchestratorListTemplates = usePipelineOrchestratorListTemplates;
|
|
62655
62482
|
exports.usePipelineOrchestratorPauseForStorageMigration = usePipelineOrchestratorPauseForStorageMigration;
|
|
62656
62483
|
exports.usePipelineOrchestratorPlanAutoTune = usePipelineOrchestratorPlanAutoTune;
|
|
62657
62484
|
exports.usePipelineOrchestratorRebalance = usePipelineOrchestratorRebalance;
|
|
@@ -62661,7 +62488,6 @@ exports.usePipelineOrchestratorRequestOccupancyLook = usePipelineOrchestratorReq
|
|
|
62661
62488
|
exports.usePipelineOrchestratorResetNodePipelineDefaults = usePipelineOrchestratorResetNodePipelineDefaults;
|
|
62662
62489
|
exports.usePipelineOrchestratorResolvePipeline = usePipelineOrchestratorResolvePipeline;
|
|
62663
62490
|
exports.usePipelineOrchestratorResumeForStorageMigration = usePipelineOrchestratorResumeForStorageMigration;
|
|
62664
|
-
exports.usePipelineOrchestratorSaveTemplate = usePipelineOrchestratorSaveTemplate;
|
|
62665
62491
|
exports.usePipelineOrchestratorSetAgentCapabilities = usePipelineOrchestratorSetAgentCapabilities;
|
|
62666
62492
|
exports.usePipelineOrchestratorSetAgentDecodeLimits = usePipelineOrchestratorSetAgentDecodeLimits;
|
|
62667
62493
|
exports.usePipelineOrchestratorSetAgentInferenceDevices = usePipelineOrchestratorSetAgentInferenceDevices;
|
|
@@ -62680,7 +62506,6 @@ exports.usePipelineOrchestratorSetShareSource = usePipelineOrchestratorSetShareS
|
|
|
62680
62506
|
exports.usePipelineOrchestratorSuggestShares = usePipelineOrchestratorSuggestShares;
|
|
62681
62507
|
exports.usePipelineOrchestratorUnassignAudio = usePipelineOrchestratorUnassignAudio;
|
|
62682
62508
|
exports.usePipelineOrchestratorUnassignPipeline = usePipelineOrchestratorUnassignPipeline;
|
|
62683
|
-
exports.usePipelineOrchestratorUpdateTemplate = usePipelineOrchestratorUpdateTemplate;
|
|
62684
62509
|
exports.usePipelineRunnerAttachCamera = usePipelineRunnerAttachCamera;
|
|
62685
62510
|
exports.usePipelineRunnerDetachCamera = usePipelineRunnerDetachCamera;
|
|
62686
62511
|
exports.usePipelineRunnerGetAllCameraMetrics = usePipelineRunnerGetAllCameraMetrics;
|