@camstack/ui-library 1.2.243 → 1.2.245
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/agent-step-editor.d.ts +41 -16
- package/dist/composites/device-step-matrix.d.ts +2 -25
- package/dist/composites/index.d.ts +8 -11
- package/dist/composites/model-bound-slider.d.ts +8 -1
- package/dist/composites/pipeline-builder.d.ts +1 -28
- package/dist/composites/pipeline-matrix-shared.d.ts +1 -1
- package/dist/composites/pipeline-step.d.ts +4 -44
- package/dist/composites/step-inspector/accelerator-tabs.d.ts +12 -0
- package/dist/composites/step-inspector/gate-control.d.ts +20 -0
- package/dist/composites/step-inspector/index.d.ts +11 -0
- package/dist/composites/step-inspector/layered-settings-form.d.ts +38 -0
- package/dist/composites/step-inspector/segmented-choice.d.ts +11 -0
- package/dist/composites/step-inspector/setting-values.d.ts +19 -0
- package/dist/composites/step-inspector/step-chips.d.ts +11 -0
- package/dist/composites/step-inspector/step-inspector-layout.d.ts +23 -0
- package/dist/composites/step-inspector/step-inspector-panel.d.ts +26 -0
- package/dist/composites/step-inspector/step-list.d.ts +39 -0
- package/dist/composites/step-inspector/step-model-list.d.ts +9 -0
- package/dist/composites/step-inspector/step-model-row.d.ts +27 -0
- package/dist/composites/{step-tree-master.d.ts → step-tree.d.ts} +0 -12
- package/dist/generated/system-hooks.d.ts +2 -0
- package/dist/index.cjs +1339 -1016
- package/dist/index.js +1316 -1016
- package/package.json +1 -1
- package/dist/composites/pipeline-tree-matrix.d.ts +0 -18
- package/dist/composites/slide-over-panel.d.ts +0 -35
package/dist/index.cjs
CHANGED
|
@@ -8048,6 +8048,8 @@ var usePipelineOrchestratorSetCameraStepToggle = trpc.pipelineOrchestrator.setCa
|
|
|
8048
8048
|
var usePipelineOrchestratorGetCameraStepOverrides = trpc.pipelineOrchestrator.getCameraStepOverrides.useQuery;
|
|
8049
8049
|
/** Generated alias around `trpc.pipelineOrchestrator.setCameraStepOverride.useMutation`. */
|
|
8050
8050
|
var usePipelineOrchestratorSetCameraStepOverride = trpc.pipelineOrchestrator.setCameraStepOverride.useMutation;
|
|
8051
|
+
/** Generated alias around `trpc.pipelineOrchestrator.setCameraStepSettings.useMutation`. */
|
|
8052
|
+
var usePipelineOrchestratorSetCameraStepSettings = trpc.pipelineOrchestrator.setCameraStepSettings.useMutation;
|
|
8051
8053
|
/** Generated alias around `trpc.pipelineOrchestrator.setCameraPipelineForAgent.useMutation`. */
|
|
8052
8054
|
var usePipelineOrchestratorSetCameraPipelineForAgent = trpc.pipelineOrchestrator.setCameraPipelineForAgent.useMutation;
|
|
8053
8055
|
/** Generated alias around `trpc.pipelineOrchestrator.resolvePipeline.useQuery`. */
|
|
@@ -28744,32 +28746,6 @@ function AddonGlobalSettingsForm({ trpc, addonId, nodeId, title, disabled, onAft
|
|
|
28744
28746
|
});
|
|
28745
28747
|
}
|
|
28746
28748
|
//#endregion
|
|
28747
|
-
//#region src/primitives/collapsible-card.tsx
|
|
28748
|
-
function CollapsibleCard({ expanded, onExpandedChange, header, children, dimmed = false, hideChevron = false, className }) {
|
|
28749
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
28750
|
-
className: cn("rounded-lg border border-border bg-surface overflow-hidden", dimmed && "opacity-[0.45]", className),
|
|
28751
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
28752
|
-
role: "button",
|
|
28753
|
-
tabIndex: 0,
|
|
28754
|
-
className: "flex items-center gap-2.5 px-3 py-2.5 cursor-pointer select-none",
|
|
28755
|
-
onClick: () => onExpandedChange(!expanded),
|
|
28756
|
-
onKeyDown: (e) => {
|
|
28757
|
-
if (e.key === "Enter" || e.key === " ") {
|
|
28758
|
-
e.preventDefault();
|
|
28759
|
-
onExpandedChange(!expanded);
|
|
28760
|
-
}
|
|
28761
|
-
},
|
|
28762
|
-
children: [!hideChevron && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
28763
|
-
className: "text-foreground-subtle shrink-0",
|
|
28764
|
-
children: expanded ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChevronDown, { className: "h-4 w-4" }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChevronRight, { className: "h-4 w-4" })
|
|
28765
|
-
}), header]
|
|
28766
|
-
}), expanded && children && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
28767
|
-
className: "border-t border-border px-3 py-3",
|
|
28768
|
-
children
|
|
28769
|
-
})]
|
|
28770
|
-
});
|
|
28771
|
-
}
|
|
28772
|
-
//#endregion
|
|
28773
28749
|
//#region src/composites/grouped-model-selector.tsx
|
|
28774
28750
|
/**
|
|
28775
28751
|
* GroupedModelSelector — the shared Family → Tier → Variant model picker.
|
|
@@ -29050,6 +29026,257 @@ function ModelPicker({ models, value, onChange, disabled, defaultModelId }) {
|
|
|
29050
29026
|
});
|
|
29051
29027
|
}
|
|
29052
29028
|
//#endregion
|
|
29029
|
+
//#region src/composites/resolve-step-default-model.ts
|
|
29030
|
+
function resolveStepDefaultModel(catalog, format) {
|
|
29031
|
+
const hasFormatBuild = (modelId) => catalog.models.find((m) => m.id === modelId)?.formats[format] !== void 0;
|
|
29032
|
+
const declared = catalog.defaultModelIdByFormat?.[format];
|
|
29033
|
+
if (declared !== void 0 && hasFormatBuild(declared)) return declared;
|
|
29034
|
+
if (hasFormatBuild(catalog.defaultModelId)) return catalog.defaultModelId;
|
|
29035
|
+
const available = catalog.models.filter((m) => m.formats[format] !== void 0 && m.legacy !== true);
|
|
29036
|
+
if (available.length === 0) return catalog.defaultModelId;
|
|
29037
|
+
return [...available].toSorted((a, b) => (a.formats[format]?.sizeMB ?? Infinity) - (b.formats[format]?.sizeMB ?? Infinity))[0].id;
|
|
29038
|
+
}
|
|
29039
|
+
/**
|
|
29040
|
+
* The model a matrix CELL shows as this step's effective default on `device`.
|
|
29041
|
+
*
|
|
29042
|
+
* The device's ELECTED model (`device.defaultModelId`, the per-device
|
|
29043
|
+
* object-detection election) applies ONLY when this step's catalog actually
|
|
29044
|
+
* contains it — `slot === 'detector'` alone is too wide, because
|
|
29045
|
+
* package-detection shares the detector slot with the root step. Bit live
|
|
29046
|
+
* 2026-08-08: rfdetr-package became the package step's default and every
|
|
29047
|
+
* matrix cell still showed the device's yolo as the "selected" model, because
|
|
29048
|
+
* the election was applied slot-wide. Membership is the principled gate: an
|
|
29049
|
+
* elected model this step cannot run is never displayed for it.
|
|
29050
|
+
*/
|
|
29051
|
+
function resolveEffectiveDefaultModel(catalog, device) {
|
|
29052
|
+
const format = device?.format;
|
|
29053
|
+
if (format === void 0) return void 0;
|
|
29054
|
+
const elected = device?.defaultModelId;
|
|
29055
|
+
return catalog.slot === "detector" && elected !== void 0 && catalog.models.some((m) => m.id === elected) ? elected : resolveStepDefaultModel(catalog, format);
|
|
29056
|
+
}
|
|
29057
|
+
/**
|
|
29058
|
+
* The models a step may run on an engine `format` — the ONE derivation of the
|
|
29059
|
+
* option list. An unknown format yields NOTHING rather than everything: a
|
|
29060
|
+
* picker that offered a model with no build for the device would write a pin
|
|
29061
|
+
* the runner cannot honour.
|
|
29062
|
+
*/
|
|
29063
|
+
function stepModelOptions(models, format) {
|
|
29064
|
+
if (format === void 0) return [];
|
|
29065
|
+
return models.filter((m) => m.formats[format] !== void 0);
|
|
29066
|
+
}
|
|
29067
|
+
/** Can this step run on `format` at all? (`false` ⇒ the caller renders "⚠ skip"/"—".) */
|
|
29068
|
+
function stepHasModelForFormat(models, format) {
|
|
29069
|
+
return stepModelOptions(models, format).length > 0;
|
|
29070
|
+
}
|
|
29071
|
+
/**
|
|
29072
|
+
* The model a step ACTUALLY runs for a (device, camera) — the whole effective
|
|
29073
|
+
* chain in one place: per-camera override → per-(node,device) base → the
|
|
29074
|
+
* resolved default (`resolveEffectiveDefaultModel`).
|
|
29075
|
+
*
|
|
29076
|
+
* Every surface calls this: the matrix cell, and the drawer's picker seed. They
|
|
29077
|
+
* are the same number, and the only way to keep them the same number is to have
|
|
29078
|
+
* one function produce it. A surface that owns fewer layers omits them (the node
|
|
29079
|
+
* matrix passes no `override`) — it does NOT get its own resolver.
|
|
29080
|
+
*/
|
|
29081
|
+
function resolveEffectiveStepModel(input) {
|
|
29082
|
+
return input.override ?? input.base ?? resolveEffectiveDefaultModel(input.catalog, input.device);
|
|
29083
|
+
}
|
|
29084
|
+
//#endregion
|
|
29085
|
+
//#region src/composites/root-model-source.tsx
|
|
29086
|
+
/**
|
|
29087
|
+
* "Use the root model" — the step editor's control for a step the camera's
|
|
29088
|
+
* ROOT detection model can supply (D730).
|
|
29089
|
+
*
|
|
29090
|
+
* The flag (`useRootModel`, in the step's own settings) is an operator INTENT
|
|
29091
|
+
* kept beside the step's model: checking it never changes the model, and a
|
|
29092
|
+
* root that cannot supply the step leaves the step running its own model while
|
|
29093
|
+
* the flag waits, inactive, for a root that can. Whether it is in force is
|
|
29094
|
+
* `resolveRootSupply` — the same function the runner decides with.
|
|
29095
|
+
*/
|
|
29096
|
+
/** The editor's view of the flag for one step, or `null` for a step no root can supply. */
|
|
29097
|
+
function rootSourceState(stepId, settings, rootModel) {
|
|
29098
|
+
if (!(0, _camstack_types.isRootSuppliableStepId)(stepId)) return null;
|
|
29099
|
+
return (0, _camstack_types.resolveRootSupply)(stepId, settings, rootModel?.supplies);
|
|
29100
|
+
}
|
|
29101
|
+
/** The settings bag with the flag set — every other key untouched. */
|
|
29102
|
+
function withUseRootModel(settings, value) {
|
|
29103
|
+
return {
|
|
29104
|
+
...settings,
|
|
29105
|
+
[_camstack_types.USE_ROOT_MODEL_SETTING_KEY]: value
|
|
29106
|
+
};
|
|
29107
|
+
}
|
|
29108
|
+
/** What the operator must know about a supply, beyond "it is on". */
|
|
29109
|
+
function supplyNotes(supply) {
|
|
29110
|
+
if (supply.kind === "label") {
|
|
29111
|
+
const notes = supply.uncovered.length > 0 ? [`Not produced by this model: ${supply.uncovered.join(", ")}.`] : [];
|
|
29112
|
+
if (supply.stepId === "package-detection") return [...notes, "The root model's own package boxes become the package result at this step's threshold; this step's zone-crop view is not used, so small parcels the full-frame model misses stay missed."];
|
|
29113
|
+
return [...notes, "This step's class list decides which of the root's labels become the fine class; a switched-off class stays at its macro."];
|
|
29114
|
+
}
|
|
29115
|
+
if (supply.kind === "mask") return ["Masks come from the root model: each detection carries the root's own instance mask, so this step's model does not run. A root mask follows the model's mask grid (a quarter of its input), coarser than this step's own per-crop mask."];
|
|
29116
|
+
if (supply.stepId === "face-detection") return ["Face boxes come from the root model. Each is re-found by this step's face detector in a square around it before recognition, so only a face it finds is recognised; a box with no face in it is dropped."];
|
|
29117
|
+
return ["Plate boxes come from the root model and the plate reader reads them. The crop margin around a root plate box has not been measured for this model yet."];
|
|
29118
|
+
}
|
|
29119
|
+
/** The reason an intended supply is not in force, in the operator's words. */
|
|
29120
|
+
function inactiveText(state, rootModel) {
|
|
29121
|
+
switch (state.inactiveReason) {
|
|
29122
|
+
case "root-input-too-small": return `the current root model (${rootModel.name}) sees the frame too small to find faces reliably (it needs an input of 640 px or more).`;
|
|
29123
|
+
case "root-does-not-declare":
|
|
29124
|
+
case void 0: return `the current root model (${rootModel.name}) cannot supply this.`;
|
|
29125
|
+
}
|
|
29126
|
+
}
|
|
29127
|
+
function RootModelSourceControl({ stepId, settings, rootModel, disabled, onChange }) {
|
|
29128
|
+
if (rootModel === void 0) return null;
|
|
29129
|
+
const state = rootSourceState(stepId, settings, rootModel);
|
|
29130
|
+
if (state === null) return null;
|
|
29131
|
+
const inactiveNote = state.inactive ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
29132
|
+
className: "rounded bg-muted/40 px-3 py-2 text-[11px] text-foreground-subtle",
|
|
29133
|
+
"data-testid": "root-model-inactive",
|
|
29134
|
+
children: [
|
|
29135
|
+
"Use the root model: inactive — ",
|
|
29136
|
+
inactiveText(state, rootModel),
|
|
29137
|
+
" The step runs its own model."
|
|
29138
|
+
]
|
|
29139
|
+
}) : null;
|
|
29140
|
+
if (state.supply === void 0) return inactiveNote;
|
|
29141
|
+
const checked = state.intent;
|
|
29142
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
29143
|
+
className: "space-y-1",
|
|
29144
|
+
"data-testid": "root-model-source",
|
|
29145
|
+
children: [
|
|
29146
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
29147
|
+
className: "flex items-center gap-2 text-xs text-foreground",
|
|
29148
|
+
children: [
|
|
29149
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
29150
|
+
type: "checkbox",
|
|
29151
|
+
checked,
|
|
29152
|
+
disabled,
|
|
29153
|
+
onChange: (e) => onChange(e.target.checked)
|
|
29154
|
+
}),
|
|
29155
|
+
"Use the root model (",
|
|
29156
|
+
rootModel.name,
|
|
29157
|
+
")"
|
|
29158
|
+
]
|
|
29159
|
+
}),
|
|
29160
|
+
inactiveNote,
|
|
29161
|
+
state.effective && supplyNotes(state.supply).map((note) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
29162
|
+
className: "text-[10px] leading-snug text-foreground-subtle",
|
|
29163
|
+
children: note
|
|
29164
|
+
}, note))
|
|
29165
|
+
]
|
|
29166
|
+
});
|
|
29167
|
+
}
|
|
29168
|
+
//#endregion
|
|
29169
|
+
//#region src/lib/responsive.ts
|
|
29170
|
+
/**
|
|
29171
|
+
* Responsive design tokens — three-tier system.
|
|
29172
|
+
*
|
|
29173
|
+
* The admin-ui targets three width tiers; every component should pick
|
|
29174
|
+
* the right token from this file instead of hand-coding breakpoints.
|
|
29175
|
+
* Adopting the tokens uniformly is what makes the app feel consistent
|
|
29176
|
+
* across operator devices (mobile / tablet / desktop) and what unlocks
|
|
29177
|
+
* targeted tuning (e.g. shrink every label by 1px in one place).
|
|
29178
|
+
*
|
|
29179
|
+
* Tier definitions (Tailwind breakpoints):
|
|
29180
|
+
*
|
|
29181
|
+
* • **L1 — Compact** (`< 640px`, default = mobile portrait)
|
|
29182
|
+
* Single column, tight padding, smallest text, icon-only buttons
|
|
29183
|
+
* where labels can be inferred. The operator can still see every
|
|
29184
|
+
* stat / action — no horizontal scroll, no clipped text. The user
|
|
29185
|
+
* directive: "molta informazione in poco spazio quando la width è
|
|
29186
|
+
* bassa." [a lot of information in little space when the width is low.]
|
|
29187
|
+
*
|
|
29188
|
+
* • **L2 — Standard** (`sm` — `640–1023px`, tablet + small laptop)
|
|
29189
|
+
* 2-column grids, side panels become visible, button labels return.
|
|
29190
|
+
* Targets ~768px–1024px viewports — the most common operator sizes.
|
|
29191
|
+
*
|
|
29192
|
+
* • **L3 — Spacious** (`lg+` — `≥ 1024px`, desktop)
|
|
29193
|
+
* 4-column grids, generous padding, full-width header text,
|
|
29194
|
+
* side-by-side composite layouts. The operator has elbow room.
|
|
29195
|
+
*
|
|
29196
|
+
* Conventions:
|
|
29197
|
+
* - **Always start from L1** — the bare class is always the compact
|
|
29198
|
+
* variant, then `sm:` adds room at 640px, `lg:` at 1024px. No
|
|
29199
|
+
* desktop-first breakpoints; no max-width queries.
|
|
29200
|
+
* - **Token strings are static** — kept as `as const` so callers can
|
|
29201
|
+
* compose them via `cn()` / template literals without running a
|
|
29202
|
+
* class generator at runtime.
|
|
29203
|
+
* - **Pair the token with a comment** — the comment in the file
|
|
29204
|
+
* names every breakpoint it crosses, so a reader can predict the
|
|
29205
|
+
* layout without going to Tailwind docs.
|
|
29206
|
+
*/
|
|
29207
|
+
/** Container padding for a card-style section (header + body). */
|
|
29208
|
+
var SECTION_CARD = "rounded-lg border border-border bg-surface overflow-hidden";
|
|
29209
|
+
/** Header strip inside a card (between border-b lines). */
|
|
29210
|
+
var SECTION_HEADER = "border-b border-border px-3 sm:px-4 py-1.5 sm:py-2";
|
|
29211
|
+
/** Body padding for a card-style section. */
|
|
29212
|
+
var SECTION_BODY = "p-2 sm:p-3 lg:p-4";
|
|
29213
|
+
/** Gap between cards in a vertical stack. */
|
|
29214
|
+
var STACK_GAP = "space-y-3 sm:space-y-4";
|
|
29215
|
+
/** Gap between cards in a grid (4 cells / row at lg). */
|
|
29216
|
+
var GRID_GAP = "gap-2 sm:gap-3";
|
|
29217
|
+
/** Row padding inside a divided list (e.g. InfoRow). */
|
|
29218
|
+
var LIST_ROW = "px-3 sm:px-4 py-1.5 sm:py-2";
|
|
29219
|
+
/** 1-up at L1, 2-up at L2, 4-up at L3 — quick-stat row. */
|
|
29220
|
+
var GRID_QUICK_STATS = "grid grid-cols-2 sm:grid-cols-2 lg:grid-cols-4";
|
|
29221
|
+
/** 1-up at L1, 2-up at L2+ — paired panels (motion + detection rules). */
|
|
29222
|
+
var GRID_PAIRED = "grid grid-cols-1 lg:grid-cols-2";
|
|
29223
|
+
/** Side-by-side layout that stacks below md (canvas + side panel). */
|
|
29224
|
+
var SPLIT_PANEL_OUTER = "flex flex-col-reverse md:flex-row";
|
|
29225
|
+
/** Sidebar narrow lane in a SPLIT_PANEL_OUTER layout. */
|
|
29226
|
+
var SPLIT_PANEL_SIDE = "w-full md:w-44 lg:w-52 md:flex-shrink-0 border-b md:border-b-0 md:border-l border-border";
|
|
29227
|
+
/**
|
|
29228
|
+
* The tier boundary at which a settings label/value row stops stacking.
|
|
29229
|
+
*
|
|
29230
|
+
* Below it (L1 — compact) the row is ONE column: label on its own line, value
|
|
29231
|
+
* on the next at full width. Above it the row is label-left / value-right as
|
|
29232
|
+
* before. The two-column form needs `SETTING_ROW_LABEL`'s lane plus a readable
|
|
29233
|
+
* value beside it; a phone has neither, and the failure mode is not "cramped"
|
|
29234
|
+
* but "the value is the part that gets cut" — the one thing the operator
|
|
29235
|
+
* opened the page to read.
|
|
29236
|
+
*/
|
|
29237
|
+
var SETTING_ROW_STACK_BREAKPOINT = "sm";
|
|
29238
|
+
/** Outer row: single column at L1, label/value columns from `sm` up. */
|
|
29239
|
+
var SETTING_ROW = "flex min-w-0 flex-col gap-0.5 py-1.5 sm:flex-row sm:items-center";
|
|
29240
|
+
/** Label lane. Full width (and free to wrap) at L1; a fixed lane from `sm` up. */
|
|
29241
|
+
var SETTING_ROW_LABEL = "min-w-0 text-[11px] leading-tight text-foreground-subtle sm:w-32 sm:shrink-0 sm:pr-2";
|
|
29242
|
+
/**
|
|
29243
|
+
* Value lane — the value text plus its trailing affordances (copy / reveal).
|
|
29244
|
+
* `w-full` at L1 so the value owns the whole row once the label is above it;
|
|
29245
|
+
* `sm:flex-1` makes it share the row again from `sm` up.
|
|
29246
|
+
*/
|
|
29247
|
+
var SETTING_ROW_VALUE = "flex w-full min-w-0 items-center gap-1 sm:flex-1";
|
|
29248
|
+
/**
|
|
29249
|
+
* The value text itself. `break-all` lets an opaque token (a key, a URL) wrap
|
|
29250
|
+
* at L1 instead of being cut mid-word; `sm:truncate` restores the single-line
|
|
29251
|
+
* desktop form, where the row is wide enough for truncation to be a choice
|
|
29252
|
+
* rather than data loss.
|
|
29253
|
+
*/
|
|
29254
|
+
var SETTING_ROW_VALUE_TEXT = "min-w-0 break-all text-xs text-foreground sm:truncate";
|
|
29255
|
+
/** Section header label (uppercase tracking-wider). */
|
|
29256
|
+
var TEXT_SECTION_LABEL = "text-[10px] sm:text-[11px] font-semibold text-foreground uppercase tracking-wider";
|
|
29257
|
+
/** Field label inside a row. */
|
|
29258
|
+
var TEXT_FIELD_LABEL = "text-[11px] sm:text-xs text-foreground";
|
|
29259
|
+
/** Sub-label / hint text. */
|
|
29260
|
+
var TEXT_HINT = "text-[10px] text-foreground-subtle";
|
|
29261
|
+
/** Primary value (a metric, badge, …). */
|
|
29262
|
+
var TEXT_VALUE = "text-[11px] sm:text-xs font-medium text-foreground";
|
|
29263
|
+
/** Big metric value (StatCard). */
|
|
29264
|
+
var TEXT_METRIC = "text-base sm:text-lg font-semibold leading-tight text-foreground";
|
|
29265
|
+
/** Default compact button. */
|
|
29266
|
+
var BTN_COMPACT = "inline-flex items-center justify-center gap-1 rounded border border-border bg-surface px-1.5 py-0.5 sm:px-2 sm:py-1 text-[10px] sm:text-[11px] font-medium text-foreground hover:bg-surface-hover transition-colors disabled:opacity-40";
|
|
29267
|
+
/** Primary compact button. */
|
|
29268
|
+
var BTN_COMPACT_PRIMARY = "inline-flex items-center justify-center gap-1 rounded border border-primary/40 bg-primary/15 px-1.5 py-0.5 sm:px-2 sm:py-1 text-[10px] sm:text-[11px] font-medium text-primary hover:bg-primary/25 transition-colors disabled:opacity-40";
|
|
29269
|
+
/** Danger compact button. */
|
|
29270
|
+
var BTN_COMPACT_DANGER = "inline-flex items-center justify-center gap-1 rounded border border-danger/40 bg-danger/10 px-1.5 py-0.5 sm:px-2 sm:py-1 text-[10px] sm:text-[11px] font-medium text-danger hover:bg-danger/20 transition-colors disabled:opacity-40";
|
|
29271
|
+
/** Warning compact button (e.g. cancel-drawing). */
|
|
29272
|
+
var BTN_COMPACT_WARNING = "inline-flex items-center justify-center gap-1 rounded border border-warning/40 bg-warning/10 px-1.5 py-0.5 sm:px-2 sm:py-1 text-[10px] sm:text-[11px] font-medium text-warning hover:bg-warning/20 transition-colors disabled:opacity-40";
|
|
29273
|
+
/** Compact text/select/number input. */
|
|
29274
|
+
var INPUT_COMPACT = "w-full rounded border border-border bg-background px-1.5 py-0.5 sm:px-2 sm:py-1 text-[11px] sm:text-xs text-foreground focus:border-primary focus:ring-1 focus:ring-primary/30 outline-none";
|
|
29275
|
+
/** Chip-style toggle (zone / class selectors in ZoneRulesEditor). */
|
|
29276
|
+
var CHIP_BASE = "inline-flex items-center gap-1 rounded-full border px-1.5 py-0.5 text-[10px] font-medium transition-colors";
|
|
29277
|
+
var CHIP_ACTIVE = "border-primary/50 bg-primary/15 text-primary";
|
|
29278
|
+
var CHIP_INACTIVE = "border-border bg-surface text-foreground-subtle hover:bg-surface-hover";
|
|
29279
|
+
//#endregion
|
|
29053
29280
|
//#region src/composites/model-bound-slider.tsx
|
|
29054
29281
|
var SOURCE_LABEL = {
|
|
29055
29282
|
override: "Override for this model",
|
|
@@ -29059,7 +29286,7 @@ var SOURCE_LABEL = {
|
|
|
29059
29286
|
function formatNumber(value, scale) {
|
|
29060
29287
|
return (scale !== void 0 ? value / scale : value).toFixed(2).replace(/\.?0+$/, "");
|
|
29061
29288
|
}
|
|
29062
|
-
function ModelBoundSlider({ field, modelId, settings, disabled, onChangeSettings }) {
|
|
29289
|
+
function ModelBoundSlider({ field, modelId, settings, disabled, onChangeSettings, hideSourceRow = false }) {
|
|
29063
29290
|
const modelDefault = field.modelApplicability?.defaultByModel?.[modelId];
|
|
29064
29291
|
const state = (0, _camstack_types.resolveModelBoundSetting)(settings, field.key, modelId.length > 0 ? modelId : void 0, modelDefault, field.default);
|
|
29065
29292
|
const fallback = typeof field.default === "number" ? field.default : field.min ?? 0;
|
|
@@ -29099,7 +29326,7 @@ function ModelBoundSlider({ field, modelId, settings, disabled, onChangeSettings
|
|
|
29099
29326
|
onChange: (e) => handleChange(Number(e.target.value)),
|
|
29100
29327
|
className: "w-full accent-primary h-1.5"
|
|
29101
29328
|
}),
|
|
29102
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
29329
|
+
!hideSourceRow && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
29103
29330
|
className: "mt-1 flex items-center justify-between gap-2 text-[10px]",
|
|
29104
29331
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
29105
29332
|
"data-testid": "model-bound-source",
|
|
@@ -29150,6 +29377,32 @@ function ResetModelDefaultsButton({ fields, modelId, settings, disabled, onReset
|
|
|
29150
29377
|
});
|
|
29151
29378
|
}
|
|
29152
29379
|
//#endregion
|
|
29380
|
+
//#region src/primitives/collapsible-card.tsx
|
|
29381
|
+
function CollapsibleCard({ expanded, onExpandedChange, header, children, dimmed = false, hideChevron = false, className }) {
|
|
29382
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
29383
|
+
className: cn("rounded-lg border border-border bg-surface overflow-hidden", dimmed && "opacity-[0.45]", className),
|
|
29384
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
29385
|
+
role: "button",
|
|
29386
|
+
tabIndex: 0,
|
|
29387
|
+
className: "flex items-center gap-2.5 px-3 py-2.5 cursor-pointer select-none",
|
|
29388
|
+
onClick: () => onExpandedChange(!expanded),
|
|
29389
|
+
onKeyDown: (e) => {
|
|
29390
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
29391
|
+
e.preventDefault();
|
|
29392
|
+
onExpandedChange(!expanded);
|
|
29393
|
+
}
|
|
29394
|
+
},
|
|
29395
|
+
children: [!hideChevron && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
29396
|
+
className: "text-foreground-subtle shrink-0",
|
|
29397
|
+
children: expanded ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChevronDown, { className: "h-4 w-4" }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChevronRight, { className: "h-4 w-4" })
|
|
29398
|
+
}), header]
|
|
29399
|
+
}), expanded && children && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
29400
|
+
className: "border-t border-border px-3 py-3",
|
|
29401
|
+
children
|
|
29402
|
+
})]
|
|
29403
|
+
});
|
|
29404
|
+
}
|
|
29405
|
+
//#endregion
|
|
29153
29406
|
//#region src/composites/pipeline-step.tsx
|
|
29154
29407
|
/**
|
|
29155
29408
|
* PipelineStep — single step card in the pipeline builder.
|
|
@@ -29161,124 +29414,77 @@ function ResetModelDefaultsButton({ fields, modelId, settings, disabled, onReset
|
|
|
29161
29414
|
function modelsForStep(schema) {
|
|
29162
29415
|
return schema?.models ?? [];
|
|
29163
29416
|
}
|
|
29164
|
-
function PipelineStep({ step, schema, allSchemas: _allSchemas, depth: _depth = 0, onChange, onDelete: _onDelete, readOnly = false
|
|
29417
|
+
function PipelineStep({ step, schema, allSchemas: _allSchemas, depth: _depth = 0, onChange, onDelete: _onDelete, readOnly = false }) {
|
|
29165
29418
|
const [expanded, setExpanded] = (0, react$1.useState)(false);
|
|
29166
29419
|
const models = modelsForStep(schema);
|
|
29167
|
-
|
|
29168
|
-
if (models.length > 0 && !isAutoSentinel && !models.some((m) => m.id === step.modelId) && !readOnly) {
|
|
29420
|
+
if (models.length > 0 && !models.some((m) => m.id === step.modelId) && !readOnly) {
|
|
29169
29421
|
const fallback = (schema?.defaultModelId ? models.find((m) => m.id === schema.defaultModelId) : null) ?? models[0];
|
|
29170
29422
|
if (fallback && fallback.id !== step.modelId) queueMicrotask(() => onChange({
|
|
29171
29423
|
...step,
|
|
29172
29424
|
modelId: fallback.id
|
|
29173
29425
|
}));
|
|
29174
29426
|
}
|
|
29175
|
-
const header = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
29176
|
-
|
|
29177
|
-
|
|
29178
|
-
|
|
29179
|
-
|
|
29180
|
-
|
|
29181
|
-
|
|
29182
|
-
|
|
29183
|
-
|
|
29184
|
-
|
|
29185
|
-
|
|
29186
|
-
|
|
29187
|
-
|
|
29188
|
-
|
|
29189
|
-
|
|
29190
|
-
|
|
29191
|
-
|
|
29192
|
-
|
|
29193
|
-
|
|
29194
|
-
|
|
29195
|
-
|
|
29196
|
-
|
|
29197
|
-
|
|
29198
|
-
|
|
29199
|
-
|
|
29200
|
-
|
|
29201
|
-
|
|
29202
|
-
|
|
29203
|
-
|
|
29204
|
-
|
|
29205
|
-
|
|
29206
|
-
|
|
29207
|
-
|
|
29208
|
-
|
|
29209
|
-
|
|
29210
|
-
|
|
29211
|
-
|
|
29212
|
-
|
|
29213
|
-
|
|
29214
|
-
|
|
29215
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: cn("inline-block h-4 w-4 rounded-full bg-white shadow transition-transform", step.enabled ? "translate-x-6" : "translate-x-1") })
|
|
29216
|
-
}),
|
|
29217
|
-
!readOnly && toggleMode === "threeState" && onOverrideChange && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
29218
|
-
className: "flex items-center gap-0.5 rounded-md border border-border p-0.5",
|
|
29219
|
-
onClick: (e) => e.stopPropagation(),
|
|
29220
|
-
children: [
|
|
29221
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ThreeStateButton, {
|
|
29222
|
-
label: "Inherit",
|
|
29223
|
-
active: overrideState === null,
|
|
29224
|
-
variant: "inherit",
|
|
29225
|
-
subtext: inheritedEnabled === void 0 ? void 0 : inheritedEnabled ? "on" : "off",
|
|
29226
|
-
onClick: () => onOverrideChange(null)
|
|
29227
|
-
}),
|
|
29228
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ThreeStateButton, {
|
|
29229
|
-
label: "On",
|
|
29230
|
-
active: overrideState === true,
|
|
29231
|
-
variant: "on",
|
|
29232
|
-
onClick: () => onOverrideChange(true)
|
|
29233
|
-
}),
|
|
29234
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ThreeStateButton, {
|
|
29235
|
-
label: "Off",
|
|
29236
|
-
active: overrideState === false,
|
|
29237
|
-
variant: "off",
|
|
29238
|
-
onClick: () => onOverrideChange(false)
|
|
29239
|
-
})
|
|
29240
|
-
]
|
|
29241
|
-
})
|
|
29242
|
-
] });
|
|
29427
|
+
const header = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
29428
|
+
className: "flex-1 min-w-0",
|
|
29429
|
+
children: [
|
|
29430
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
29431
|
+
className: "text-[10px] uppercase tracking-wider font-medium text-foreground-subtle/60 block leading-none",
|
|
29432
|
+
children: step.slot
|
|
29433
|
+
}),
|
|
29434
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
29435
|
+
className: "text-sm font-semibold text-foreground truncate block leading-tight",
|
|
29436
|
+
children: step.addonName
|
|
29437
|
+
}),
|
|
29438
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
29439
|
+
className: "flex items-center gap-1 mt-0.5 flex-wrap",
|
|
29440
|
+
children: [
|
|
29441
|
+
step.inputClasses.map((c) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
29442
|
+
className: "text-[9px] uppercase font-semibold tracking-wide px-1.5 py-0.5 rounded bg-blue-500/12 text-blue-400",
|
|
29443
|
+
children: c
|
|
29444
|
+
}, c)),
|
|
29445
|
+
step.inputClasses.length > 0 && step.outputClasses.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
29446
|
+
className: "text-foreground-subtle/40 text-[10px]",
|
|
29447
|
+
children: "→"
|
|
29448
|
+
}),
|
|
29449
|
+
step.outputClasses.map((c) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
29450
|
+
className: "text-[9px] uppercase font-semibold tracking-wide px-1.5 py-0.5 rounded bg-green-500/12 text-green-400",
|
|
29451
|
+
children: c
|
|
29452
|
+
}, c))
|
|
29453
|
+
]
|
|
29454
|
+
})
|
|
29455
|
+
]
|
|
29456
|
+
}), !readOnly && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
29457
|
+
onClick: (e) => {
|
|
29458
|
+
e.stopPropagation();
|
|
29459
|
+
onChange({
|
|
29460
|
+
...step,
|
|
29461
|
+
enabled: !step.enabled
|
|
29462
|
+
});
|
|
29463
|
+
},
|
|
29464
|
+
className: cn("relative inline-flex h-6 w-11 shrink-0 items-center rounded-full transition-colors", step.enabled ? "bg-success" : "bg-foreground-subtle/30"),
|
|
29465
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: cn("inline-block h-4 w-4 rounded-full bg-white shadow transition-transform", step.enabled ? "translate-x-6" : "translate-x-1") })
|
|
29466
|
+
})] });
|
|
29243
29467
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CollapsibleCard, {
|
|
29244
29468
|
expanded,
|
|
29245
29469
|
onExpandedChange: setExpanded,
|
|
29246
29470
|
dimmed: !step.enabled,
|
|
29247
29471
|
header,
|
|
29248
|
-
children:
|
|
29249
|
-
className: "text-[11px] text-foreground-subtle",
|
|
29250
|
-
children: "Model and detection settings are managed per agent — open the Pipeline page for this camera's agent to edit them."
|
|
29251
|
-
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
29472
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
29252
29473
|
className: "space-y-3",
|
|
29253
29474
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
29254
29475
|
className: "space-y-2",
|
|
29255
|
-
children: [
|
|
29256
|
-
|
|
29257
|
-
|
|
29258
|
-
|
|
29259
|
-
|
|
29260
|
-
|
|
29261
|
-
|
|
29262
|
-
|
|
29263
|
-
|
|
29264
|
-
|
|
29265
|
-
disabled: readOnly,
|
|
29266
|
-
onChange: (e) => onChange({
|
|
29267
|
-
...step,
|
|
29268
|
-
modelId: e.target.checked ? "" : schema?.defaultModelId ?? models[0]?.id ?? ""
|
|
29269
|
-
})
|
|
29270
|
-
}), "Auto (node default)"]
|
|
29271
|
-
}),
|
|
29272
|
-
!isAutoSentinel && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ModelPicker, {
|
|
29273
|
-
models,
|
|
29274
|
-
value: step.modelId,
|
|
29275
|
-
disabled: readOnly,
|
|
29276
|
-
onChange: (id) => onChange({
|
|
29277
|
-
...step,
|
|
29278
|
-
modelId: id
|
|
29279
|
-
})
|
|
29476
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
|
|
29477
|
+
className: "block text-[10px] font-medium text-foreground-subtle uppercase tracking-wide",
|
|
29478
|
+
children: "Model"
|
|
29479
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ModelPicker, {
|
|
29480
|
+
models,
|
|
29481
|
+
value: step.modelId,
|
|
29482
|
+
disabled: readOnly,
|
|
29483
|
+
onChange: (id) => onChange({
|
|
29484
|
+
...step,
|
|
29485
|
+
modelId: id
|
|
29280
29486
|
})
|
|
29281
|
-
]
|
|
29487
|
+
})]
|
|
29282
29488
|
}), schema?.configSchema?.map((field) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ConfigSchemaField, {
|
|
29283
29489
|
field,
|
|
29284
29490
|
allFields: schema.configSchema ?? [],
|
|
@@ -29345,7 +29551,7 @@ function resolveSettingValue(key, step, allFields) {
|
|
|
29345
29551
|
const sibling = allFields.find((f) => "key" in f && f.key === key);
|
|
29346
29552
|
return sibling && "default" in sibling ? sibling.default : void 0;
|
|
29347
29553
|
}
|
|
29348
|
-
function ConfigSchemaField({ field, allFields, step, disabled, onChange }) {
|
|
29554
|
+
function ConfigSchemaField({ field, allFields, step, disabled, onChange, hideModelBoundSourceRow }) {
|
|
29349
29555
|
const applicability = "modelApplicability" in field ? field.modelApplicability : void 0;
|
|
29350
29556
|
const inapplicableReason = applicability?.inapplicable?.[step.modelId];
|
|
29351
29557
|
const control = /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ConfigSchemaFieldControl, {
|
|
@@ -29354,7 +29560,8 @@ function ConfigSchemaField({ field, allFields, step, disabled, onChange }) {
|
|
|
29354
29560
|
step,
|
|
29355
29561
|
disabled: disabled || inapplicableReason !== void 0,
|
|
29356
29562
|
modelScopedOptions: applicability?.optionsByModel?.[step.modelId],
|
|
29357
|
-
onChange
|
|
29563
|
+
onChange,
|
|
29564
|
+
hideModelBoundSourceRow: hideModelBoundSourceRow === true
|
|
29358
29565
|
});
|
|
29359
29566
|
if (inapplicableReason === void 0) return control;
|
|
29360
29567
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -29365,7 +29572,7 @@ function ConfigSchemaField({ field, allFields, step, disabled, onChange }) {
|
|
|
29365
29572
|
})]
|
|
29366
29573
|
});
|
|
29367
29574
|
}
|
|
29368
|
-
function ConfigSchemaFieldControl({ field, allFields, step, disabled, modelScopedOptions, onChange }) {
|
|
29575
|
+
function ConfigSchemaFieldControl({ field, allFields, step, disabled, modelScopedOptions, onChange, hideModelBoundSourceRow }) {
|
|
29369
29576
|
const showWhen = field.type !== "separator" && field.type !== "info" ? field.showWhen : void 0;
|
|
29370
29577
|
if (showWhen) {
|
|
29371
29578
|
const { field: condField, equals, notEquals, in: inList, notIn } = showWhen;
|
|
@@ -29415,7 +29622,8 @@ function ConfigSchemaFieldControl({ field, allFields, step, disabled, modelScope
|
|
|
29415
29622
|
onChangeSettings: (settings) => onChange({
|
|
29416
29623
|
...step,
|
|
29417
29624
|
settings
|
|
29418
|
-
})
|
|
29625
|
+
}),
|
|
29626
|
+
hideSourceRow: hideModelBoundSourceRow
|
|
29419
29627
|
});
|
|
29420
29628
|
if (field.type === "slider" || field.type === "number") {
|
|
29421
29629
|
const raw = step.settings?.[field.key];
|
|
@@ -29501,204 +29709,247 @@ function ConfigSchemaFieldControl({ field, allFields, step, disabled, modelScope
|
|
|
29501
29709
|
});
|
|
29502
29710
|
return null;
|
|
29503
29711
|
}
|
|
29504
|
-
function ThreeStateButton({ label, active, variant, subtext, onClick }) {
|
|
29505
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
29506
|
-
type: "button",
|
|
29507
|
-
onClick,
|
|
29508
|
-
className: cn("px-2 py-1 text-[10px] font-medium rounded transition-colors", active ? variant === "on" ? "bg-green-500/20 text-green-400" : variant === "off" ? "bg-red-500/20 text-red-400" : "bg-primary/20 text-primary" : "text-foreground-subtle hover:bg-surface-hover"),
|
|
29509
|
-
children: [label, subtext && active && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
29510
|
-
className: "ml-1 opacity-60",
|
|
29511
|
-
children: [
|
|
29512
|
-
"(",
|
|
29513
|
-
subtext,
|
|
29514
|
-
")"
|
|
29515
|
-
]
|
|
29516
|
-
})]
|
|
29517
|
-
});
|
|
29518
|
-
}
|
|
29519
29712
|
//#endregion
|
|
29520
|
-
//#region src/composites/
|
|
29521
|
-
function
|
|
29522
|
-
|
|
29523
|
-
const declared = catalog.defaultModelIdByFormat?.[format];
|
|
29524
|
-
if (declared !== void 0 && hasFormatBuild(declared)) return declared;
|
|
29525
|
-
if (hasFormatBuild(catalog.defaultModelId)) return catalog.defaultModelId;
|
|
29526
|
-
const available = catalog.models.filter((m) => m.formats[format] !== void 0 && m.legacy !== true);
|
|
29527
|
-
if (available.length === 0) return catalog.defaultModelId;
|
|
29528
|
-
return [...available].toSorted((a, b) => (a.formats[format]?.sizeMB ?? Infinity) - (b.formats[format]?.sizeMB ?? Infinity))[0].id;
|
|
29713
|
+
//#region src/composites/step-inspector/setting-values.ts
|
|
29714
|
+
function isValueField(field) {
|
|
29715
|
+
return field.type !== "separator" && field.type !== "info" && field.type !== "group";
|
|
29529
29716
|
}
|
|
29530
|
-
/**
|
|
29531
|
-
|
|
29532
|
-
|
|
29533
|
-
* The device's ELECTED model (`device.defaultModelId`, the per-device
|
|
29534
|
-
* object-detection election) applies ONLY when this step's catalog actually
|
|
29535
|
-
* contains it — `slot === 'detector'` alone is too wide, because
|
|
29536
|
-
* package-detection shares the detector slot with the root step. Bit live
|
|
29537
|
-
* 2026-08-08: rfdetr-package became the package step's default and every
|
|
29538
|
-
* matrix cell still showed the device's yolo as the "selected" model, because
|
|
29539
|
-
* the election was applied slot-wide. Membership is the principled gate: an
|
|
29540
|
-
* elected model this step cannot run is never displayed for it.
|
|
29541
|
-
*/
|
|
29542
|
-
function resolveEffectiveDefaultModel(catalog, device) {
|
|
29543
|
-
const format = device?.format;
|
|
29544
|
-
if (format === void 0) return void 0;
|
|
29545
|
-
const elected = device?.defaultModelId;
|
|
29546
|
-
return catalog.slot === "detector" && elected !== void 0 && catalog.models.some((m) => m.id === elected) ? elected : resolveStepDefaultModel(catalog, format);
|
|
29717
|
+
/** True for a D738 field whose value is stored with the model it was made for. */
|
|
29718
|
+
function bindsToModel(field) {
|
|
29719
|
+
return (field.type === "slider" || field.type === "number") && field.bindsToModel === true;
|
|
29547
29720
|
}
|
|
29548
29721
|
/**
|
|
29549
|
-
*
|
|
29550
|
-
*
|
|
29551
|
-
*
|
|
29552
|
-
* the runner cannot honour.
|
|
29722
|
+
* What runs when no layer stores the field: the running model's default for a
|
|
29723
|
+
* model-bound field that the model declares one for (D738), else the field's
|
|
29724
|
+
* own default. `fromModel` says which.
|
|
29553
29725
|
*/
|
|
29554
|
-
function
|
|
29555
|
-
|
|
29556
|
-
|
|
29726
|
+
function defaultOfField(field, modelId) {
|
|
29727
|
+
const byModel = "modelApplicability" in field ? field.modelApplicability?.defaultByModel?.[modelId] : void 0;
|
|
29728
|
+
if (byModel !== void 0) return {
|
|
29729
|
+
value: byModel,
|
|
29730
|
+
fromModel: true
|
|
29731
|
+
};
|
|
29732
|
+
return {
|
|
29733
|
+
value: "default" in field ? field.default : void 0,
|
|
29734
|
+
fromModel: false
|
|
29735
|
+
};
|
|
29557
29736
|
}
|
|
29558
|
-
|
|
29559
|
-
|
|
29560
|
-
return stepModelOptions(models, format).length > 0;
|
|
29737
|
+
function trimNumber(n) {
|
|
29738
|
+
return n.toFixed(2).replace(/\.?0+$/, "");
|
|
29561
29739
|
}
|
|
29562
|
-
/**
|
|
29563
|
-
|
|
29564
|
-
|
|
29565
|
-
|
|
29566
|
-
|
|
29567
|
-
|
|
29568
|
-
|
|
29569
|
-
|
|
29570
|
-
|
|
29571
|
-
|
|
29572
|
-
|
|
29573
|
-
|
|
29740
|
+
/** One stored value as the operator reads it (`0.65`, `on`, `Person, Vehicle`, `—`). */
|
|
29741
|
+
function formatSettingValue(field, value) {
|
|
29742
|
+
if (value === void 0 || value === null) return "—";
|
|
29743
|
+
if (typeof value === "boolean") return value ? "on" : "off";
|
|
29744
|
+
if (typeof value === "number") {
|
|
29745
|
+
const scale = field.type === "slider" ? field.displayScale : void 0;
|
|
29746
|
+
const unit = "unit" in field && typeof field.unit === "string" ? ` ${field.unit}` : "";
|
|
29747
|
+
return `${trimNumber(scale !== void 0 ? value / scale : value)}${unit}`;
|
|
29748
|
+
}
|
|
29749
|
+
const options = "options" in field && Array.isArray(field.options) ? field.options : [];
|
|
29750
|
+
const labelOf = (v) => {
|
|
29751
|
+
const hit = options.find((o) => o.value === v);
|
|
29752
|
+
return hit ? hit.label : String(v);
|
|
29753
|
+
};
|
|
29754
|
+
if (Array.isArray(value)) return value.length === 0 ? "none" : value.map(labelOf).join(", ");
|
|
29755
|
+
if (typeof value === "string") return labelOf(value);
|
|
29756
|
+
return JSON.stringify(value);
|
|
29574
29757
|
}
|
|
29575
29758
|
//#endregion
|
|
29576
|
-
//#region src/composites/
|
|
29577
|
-
|
|
29578
|
-
|
|
29579
|
-
|
|
29580
|
-
|
|
29581
|
-
|
|
29582
|
-
|
|
29583
|
-
|
|
29584
|
-
|
|
29585
|
-
|
|
29586
|
-
*/
|
|
29587
|
-
/** The editor's view of the flag for one step, or `null` for a step no root can supply. */
|
|
29588
|
-
function rootSourceState(stepId, settings, rootModel) {
|
|
29589
|
-
if (!(0, _camstack_types.isRootSuppliableStepId)(stepId)) return null;
|
|
29590
|
-
return (0, _camstack_types.resolveRootSupply)(stepId, settings, rootModel?.supplies);
|
|
29759
|
+
//#region src/composites/step-inspector/layered-settings-form.tsx
|
|
29760
|
+
var SOURCE_TONE$1 = {
|
|
29761
|
+
accelerator: "border-amber-500/40 bg-amber-500/10 text-amber-500",
|
|
29762
|
+
camera: "border-primary/40 bg-primary/10 text-primary",
|
|
29763
|
+
node: "border-border bg-muted/40 text-foreground",
|
|
29764
|
+
default: "border-border/60 text-foreground-subtle"
|
|
29765
|
+
};
|
|
29766
|
+
/** DOM id of a field's box — the target of a search hit. */
|
|
29767
|
+
function stepFieldDomId(key) {
|
|
29768
|
+
return `step-field-${key}`;
|
|
29591
29769
|
}
|
|
29592
|
-
|
|
29593
|
-
function withUseRootModel(settings, value) {
|
|
29770
|
+
function displayStep(addon, modelId, settings) {
|
|
29594
29771
|
return {
|
|
29595
|
-
|
|
29596
|
-
|
|
29772
|
+
addonId: addon.id,
|
|
29773
|
+
addonName: addon.name,
|
|
29774
|
+
slot: addon.slot,
|
|
29775
|
+
inputClasses: [...addon.inputClasses],
|
|
29776
|
+
outputClasses: [...addon.outputClasses],
|
|
29777
|
+
enabled: true,
|
|
29778
|
+
modelId,
|
|
29779
|
+
children: [],
|
|
29780
|
+
settings: { ...settings }
|
|
29597
29781
|
};
|
|
29598
29782
|
}
|
|
29599
|
-
|
|
29600
|
-
|
|
29601
|
-
|
|
29602
|
-
|
|
29603
|
-
|
|
29604
|
-
|
|
29605
|
-
|
|
29606
|
-
|
|
29607
|
-
|
|
29608
|
-
|
|
29609
|
-
|
|
29610
|
-
|
|
29611
|
-
|
|
29612
|
-
|
|
29613
|
-
|
|
29614
|
-
|
|
29615
|
-
|
|
29616
|
-
|
|
29617
|
-
}
|
|
29618
|
-
|
|
29619
|
-
|
|
29620
|
-
const
|
|
29621
|
-
|
|
29622
|
-
const
|
|
29623
|
-
|
|
29624
|
-
|
|
29783
|
+
var LAYER_IDS = [
|
|
29784
|
+
"accelerator",
|
|
29785
|
+
"camera",
|
|
29786
|
+
"node"
|
|
29787
|
+
];
|
|
29788
|
+
/** "Camera · node 0.65 · model default 0.78 · [Reset to node]" under one field. */
|
|
29789
|
+
function SettingProvenance({ field, layers, target, labels, boundKeys, modelId, pinned, disabled, onReset, action }) {
|
|
29790
|
+
const effective = (0, _camstack_types.effectiveStepSettings)(layers);
|
|
29791
|
+
const fallback = defaultOfField(field, modelId);
|
|
29792
|
+
const defaultLabel = fallback.fromModel ? "model default" : "default";
|
|
29793
|
+
const stored = (0, _camstack_types.stepSettingSource)(layers, field.key, boundKeys);
|
|
29794
|
+
const bound = bindsToModel(field);
|
|
29795
|
+
const state = bound ? (0, _camstack_types.resolveModelBoundSetting)(effective, field.key, modelId, fallback.value, fallback.value) : null;
|
|
29796
|
+
const source = state === null || state.source === "override" ? stored : "default";
|
|
29797
|
+
const sourceText = source === "default" ? defaultLabel : labels[source] ?? source;
|
|
29798
|
+
const levels = LAYER_IDS.filter((id) => id !== source && labels[id] !== void 0).filter((id) => layers[id]?.[field.key] !== void 0).map((id) => {
|
|
29799
|
+
const binding = bound ? layers[id]?.[(0, _camstack_types.modelBindingKey)(field.key)] : void 0;
|
|
29800
|
+
const forOther = typeof binding === "string" && binding !== modelId ? ` (for ${binding})` : "";
|
|
29801
|
+
return `${labels[id]} ${formatSettingValue(field, layers[id]?.[field.key])}${forOther}`;
|
|
29802
|
+
});
|
|
29803
|
+
const withDefault = source === "default" ? levels : [...levels, `${defaultLabel} ${formatSettingValue(field, fallback.value)}`];
|
|
29804
|
+
const targetStores = (0, _camstack_types.stepSettingSource)({ [target]: layers[target] }, field.key, boundKeys) !== "default";
|
|
29805
|
+
const below = LAYER_IDS.slice(LAYER_IDS.indexOf(target) + 1).find((id) => labels[id] !== void 0 && layers[id]?.[field.key] !== void 0);
|
|
29806
|
+
const resetTo = below !== void 0 ? labels[below] ?? below : defaultLabel;
|
|
29807
|
+
const belowSource = stored === "default" ? "default" : (0, _camstack_types.stepSettingSource)({
|
|
29808
|
+
...layers,
|
|
29809
|
+
[stored]: void 0
|
|
29810
|
+
}, field.key, boundKeys);
|
|
29811
|
+
const pinnedAt = belowSource === "default" ? defaultLabel : labels[belowSource] ?? belowSource;
|
|
29812
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
29813
|
+
className: "mt-1 flex flex-wrap items-center gap-x-2 gap-y-1 text-[10px]",
|
|
29625
29814
|
children: [
|
|
29626
|
-
|
|
29627
|
-
|
|
29628
|
-
|
|
29815
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
29816
|
+
"data-testid": "setting-source",
|
|
29817
|
+
className: cn("rounded border px-1.5 py-px font-medium", SOURCE_TONE$1[source]),
|
|
29818
|
+
children: sourceText
|
|
29819
|
+
}),
|
|
29820
|
+
withDefault.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
29821
|
+
"data-testid": "setting-levels",
|
|
29822
|
+
className: "text-foreground-subtle",
|
|
29823
|
+
children: withDefault.join(" · ")
|
|
29824
|
+
}),
|
|
29825
|
+
pinned && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
29826
|
+
className: "rounded border border-amber-500/40 px-1.5 py-px text-amber-500",
|
|
29827
|
+
title: "Stored by an older editor as a copy of the value below. It changes nothing today, but it stops later changes below from reaching this camera.",
|
|
29828
|
+
children: [
|
|
29829
|
+
"pinned at the ",
|
|
29830
|
+
pinnedAt.toLowerCase(),
|
|
29831
|
+
" value"
|
|
29832
|
+
]
|
|
29833
|
+
}),
|
|
29834
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
29835
|
+
className: "ml-auto flex items-center gap-2",
|
|
29836
|
+
children: [action, targetStores && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
29837
|
+
type: "button",
|
|
29838
|
+
disabled,
|
|
29839
|
+
onClick: onReset,
|
|
29840
|
+
className: "rounded px-1 text-foreground-subtle hover:bg-muted hover:text-foreground disabled:opacity-50",
|
|
29841
|
+
children: ["Reset to ", resetTo.toLowerCase()]
|
|
29842
|
+
})]
|
|
29843
|
+
})
|
|
29629
29844
|
]
|
|
29630
|
-
})
|
|
29631
|
-
|
|
29632
|
-
|
|
29845
|
+
});
|
|
29846
|
+
}
|
|
29847
|
+
function LayeredSettingsForm({ addon, fields, layers, target, labels, modelId, onChangeLayer, rootModel, pinnedKeys = [], fieldActions, headerActions, highlightKey = null, disabled = false }) {
|
|
29848
|
+
const boundKeys = (0, _camstack_types.collectModelBoundKeys)(fields);
|
|
29849
|
+
const effective = (0, _camstack_types.effectiveStepSettings)(layers);
|
|
29850
|
+
const targetLayer = layers[target];
|
|
29851
|
+
const step = displayStep(addon, modelId, effective);
|
|
29852
|
+
const rootState = rootSourceState(addon.id, effective, rootModel);
|
|
29633
29853
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
29634
|
-
className: "space-y-
|
|
29635
|
-
"data-testid": "root-model-source",
|
|
29854
|
+
className: "space-y-2 text-xs",
|
|
29636
29855
|
children: [
|
|
29637
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("
|
|
29638
|
-
className: "flex items-center gap-2
|
|
29856
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
29857
|
+
className: "flex flex-wrap items-center gap-2",
|
|
29639
29858
|
children: [
|
|
29640
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("
|
|
29641
|
-
|
|
29642
|
-
|
|
29643
|
-
disabled,
|
|
29644
|
-
onChange: (e) => onChange(e.target.checked)
|
|
29859
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
|
|
29860
|
+
className: TEXT_SECTION_LABEL,
|
|
29861
|
+
children: "Settings"
|
|
29645
29862
|
}),
|
|
29646
|
-
|
|
29647
|
-
|
|
29648
|
-
|
|
29863
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
29864
|
+
className: TEXT_HINT,
|
|
29865
|
+
children: ["editing: ", labels[target] ?? target]
|
|
29866
|
+
}),
|
|
29867
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
29868
|
+
className: "ml-auto flex flex-wrap items-center gap-3",
|
|
29869
|
+
children: [headerActions, /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ResetModelDefaultsButton, {
|
|
29870
|
+
fields,
|
|
29871
|
+
modelId,
|
|
29872
|
+
settings: targetLayer,
|
|
29873
|
+
disabled,
|
|
29874
|
+
onReset: (next) => onChangeLayer(next)
|
|
29875
|
+
})]
|
|
29876
|
+
})
|
|
29649
29877
|
]
|
|
29650
29878
|
}),
|
|
29651
|
-
|
|
29652
|
-
|
|
29653
|
-
|
|
29654
|
-
|
|
29655
|
-
|
|
29879
|
+
rootState !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RootModelSourceControl, {
|
|
29880
|
+
stepId: addon.id,
|
|
29881
|
+
settings: effective,
|
|
29882
|
+
rootModel,
|
|
29883
|
+
disabled,
|
|
29884
|
+
onChange: (v) => onChangeLayer((0, _camstack_types.withFieldFrom)(targetLayer, _camstack_types.USE_ROOT_MODEL_SETTING_KEY, withUseRootModel(effective, v), []))
|
|
29885
|
+
}),
|
|
29886
|
+
fields.map((field) => {
|
|
29887
|
+
if (!isValueField(field)) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ConfigSchemaField, {
|
|
29888
|
+
field,
|
|
29889
|
+
allFields: fields,
|
|
29890
|
+
step,
|
|
29891
|
+
disabled,
|
|
29892
|
+
onChange: () => {}
|
|
29893
|
+
}, field.key);
|
|
29894
|
+
const highlighted = highlightKey === field.key;
|
|
29895
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
29896
|
+
id: stepFieldDomId(field.key),
|
|
29897
|
+
"data-field-key": field.key,
|
|
29898
|
+
className: cn("rounded-md border border-transparent px-2 py-1 -mx-2", highlighted && "border-primary/50 bg-primary/5"),
|
|
29899
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ConfigSchemaField, {
|
|
29900
|
+
field,
|
|
29901
|
+
allFields: fields,
|
|
29902
|
+
step,
|
|
29903
|
+
disabled,
|
|
29904
|
+
hideModelBoundSourceRow: true,
|
|
29905
|
+
onChange: (next) => onChangeLayer((0, _camstack_types.withFieldFrom)(targetLayer, field.key, next.settings ?? {}, boundKeys))
|
|
29906
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SettingProvenance, {
|
|
29907
|
+
field,
|
|
29908
|
+
layers,
|
|
29909
|
+
target,
|
|
29910
|
+
labels,
|
|
29911
|
+
boundKeys,
|
|
29912
|
+
modelId,
|
|
29913
|
+
pinned: pinnedKeys.includes(field.key),
|
|
29914
|
+
disabled,
|
|
29915
|
+
onReset: () => onChangeLayer((0, _camstack_types.withoutField)(targetLayer, field.key, boundKeys)),
|
|
29916
|
+
action: fieldActions?.(field.key, (0, _camstack_types.stepSettingSource)(layers, field.key, boundKeys))
|
|
29917
|
+
})]
|
|
29918
|
+
}, field.key);
|
|
29919
|
+
})
|
|
29656
29920
|
]
|
|
29657
29921
|
});
|
|
29658
29922
|
}
|
|
29659
29923
|
//#endregion
|
|
29660
29924
|
//#region src/composites/agent-step-editor.tsx
|
|
29661
29925
|
/**
|
|
29662
|
-
*
|
|
29663
|
-
*
|
|
29664
|
-
*
|
|
29926
|
+
* A step's node-local fields: the catalog schema minus the knobs the CLUSTER
|
|
29927
|
+
* owns (`clusterStepSettingFieldsFor`). Those still exist on the schema so the
|
|
29928
|
+
* runner can hydrate `child.settings`, but writing them per node or per camera
|
|
29665
29929
|
* would be a second store the overlay silently ignores.
|
|
29666
29930
|
*/
|
|
29667
|
-
function
|
|
29931
|
+
function stepLocalFields(addon) {
|
|
29668
29932
|
const clusterKeys = new Set((0, _camstack_types.clusterStepSettingFieldsFor)(addon.id).map((field) => field.key));
|
|
29669
29933
|
return (addon.configSchema ?? []).filter((field) => !clusterKeys.has(field.key));
|
|
29670
29934
|
}
|
|
29671
|
-
function ClusterSettingsHint({ addonId }) {
|
|
29672
|
-
if ((0, _camstack_types.clusterStepSettingFieldsFor)(addonId).length === 0) return null;
|
|
29673
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
29674
|
-
className: "text-[10px] leading-snug text-foreground-subtle",
|
|
29675
|
-
children: "Admission knobs for this step live in Pipeline → Cluster → Settings → Enrichment models. They apply to every camera — a per-device copy would fill the shared index from two policies."
|
|
29676
|
-
});
|
|
29677
|
-
}
|
|
29678
29935
|
/**
|
|
29679
|
-
* The model
|
|
29936
|
+
* The model a step's settings are read and written for — what a model-bound
|
|
29680
29937
|
* field (D738) binds to. While the ROOT supplies the step's fine label (D741),
|
|
29681
29938
|
* that is the root model: the step's threshold then gates the root's label, on
|
|
29682
29939
|
* the root's score scale. Otherwise the step's own model: its pin, else the
|
|
29683
29940
|
* model the row really runs (`effectiveModelId` — the device's hardware-aware
|
|
29684
29941
|
* default when unpinned), else the step's flat catalog default.
|
|
29685
29942
|
*/
|
|
29686
|
-
function settingsModelIdFor(addon,
|
|
29687
|
-
if (rootModel !== void 0 && rootSourceState(addon.id,
|
|
29688
|
-
return
|
|
29943
|
+
function settingsModelIdFor(addon, modelId, settings, rootModel) {
|
|
29944
|
+
if (rootModel !== void 0 && rootSourceState(addon.id, settings, rootModel)?.effective) return rootModel.modelId;
|
|
29945
|
+
return modelId ?? addon.defaultModelId;
|
|
29689
29946
|
}
|
|
29690
|
-
function
|
|
29691
|
-
return
|
|
29692
|
-
|
|
29693
|
-
|
|
29694
|
-
|
|
29695
|
-
|
|
29696
|
-
outputClasses: [...addon.outputClasses],
|
|
29697
|
-
enabled: cfg.enabled,
|
|
29698
|
-
modelId,
|
|
29699
|
-
children: [],
|
|
29700
|
-
settings: { ...cfg.settings }
|
|
29701
|
-
};
|
|
29947
|
+
function ClusterSettingsHint({ addonId }) {
|
|
29948
|
+
if ((0, _camstack_types.clusterStepSettingFieldsFor)(addonId).length === 0) return null;
|
|
29949
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
29950
|
+
className: "text-[10px] leading-snug text-foreground-subtle",
|
|
29951
|
+
children: "Admission knobs for this step live in Pipeline → Cluster → Settings → Enrichment models. They apply to every camera — a per-device copy would fill the shared index from two policies."
|
|
29952
|
+
});
|
|
29702
29953
|
}
|
|
29703
29954
|
/**
|
|
29704
29955
|
* Shown in place of the model picker while the root model supplies the step:
|
|
@@ -29719,233 +29970,57 @@ function RootSuppliedModelNote({ rootModel, stepModelId }) {
|
|
|
29719
29970
|
]
|
|
29720
29971
|
});
|
|
29721
29972
|
}
|
|
29722
|
-
|
|
29723
|
-
|
|
29724
|
-
|
|
29725
|
-
|
|
29726
|
-
|
|
29727
|
-
|
|
29728
|
-
|
|
29729
|
-
}
|
|
29730
|
-
|
|
29973
|
+
/**
|
|
29974
|
+
* AgentStepEditor — one step on ONE accelerator: its model and its settings,
|
|
29975
|
+
* as a single node-level layer. Model Studio's "settings for this installed
|
|
29976
|
+
* model" dialog uses it. The pipeline pages use the step inspector, which lays
|
|
29977
|
+
* the same parts out across accelerators and layers (D754/D756); the settings
|
|
29978
|
+
* form here is that inspector's `LayeredSettingsForm` with one layer.
|
|
29979
|
+
*/
|
|
29980
|
+
function AgentStepEditor({ addon, agentDefault, onChangeAgentConfig, engineFormat, effectiveModelId, rootModel }) {
|
|
29981
|
+
const modelsForFormat = (0, react$1.useMemo)(() => stepModelOptions(addon.models, engineFormat), [addon.models, engineFormat]);
|
|
29731
29982
|
const update = (patch) => {
|
|
29732
29983
|
onChangeAgentConfig?.({
|
|
29733
29984
|
...agentDefault,
|
|
29734
29985
|
...patch
|
|
29735
29986
|
});
|
|
29736
29987
|
};
|
|
29737
|
-
const
|
|
29988
|
+
const fields = stepLocalFields(addon);
|
|
29738
29989
|
const formatDefault = addon.defaultModelIdByFormat?.[engineFormat] ?? addon.defaultModelId;
|
|
29739
29990
|
const rootSupplied = rootSourceState(addon.id, agentDefault.settings, rootModel)?.effective === true;
|
|
29991
|
+
const runningModel = agentDefault.modelId ?? effectiveModelId;
|
|
29740
29992
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
29741
29993
|
className: "space-y-4 text-xs",
|
|
29742
29994
|
children: [
|
|
29743
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(RootModelSourceControl, {
|
|
29744
|
-
stepId: addon.id,
|
|
29745
|
-
settings: agentDefault.settings,
|
|
29746
|
-
rootModel,
|
|
29747
|
-
onChange: (v) => update({ settings: withUseRootModel(agentDefault.settings, v) })
|
|
29748
|
-
}),
|
|
29749
29995
|
rootSupplied && rootModel !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RootSuppliedModelNote, {
|
|
29750
29996
|
rootModel,
|
|
29751
|
-
stepModelId:
|
|
29997
|
+
stepModelId: runningModel
|
|
29752
29998
|
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
29753
29999
|
className: "text-[10px] uppercase tracking-widest text-foreground-subtle mb-1",
|
|
29754
30000
|
children: "Model"
|
|
29755
30001
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ModelPicker, {
|
|
29756
30002
|
models: modelsForFormat,
|
|
29757
|
-
value:
|
|
30003
|
+
value: runningModel ?? "",
|
|
29758
30004
|
defaultModelId: formatDefault,
|
|
29759
30005
|
onChange: (modelId) => update({ modelId })
|
|
29760
30006
|
})] }),
|
|
29761
|
-
|
|
29762
|
-
className: "pt-2 border-t border-border/50
|
|
29763
|
-
children:
|
|
29764
|
-
|
|
29765
|
-
|
|
29766
|
-
|
|
29767
|
-
|
|
29768
|
-
|
|
29769
|
-
|
|
29770
|
-
|
|
29771
|
-
|
|
29772
|
-
|
|
29773
|
-
})]
|
|
29774
|
-
}), localSchema.map((field) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ConfigSchemaField, {
|
|
29775
|
-
field,
|
|
29776
|
-
allFields: localSchema,
|
|
29777
|
-
step: buildDisplayStep(addon, agentDefault, settingsModelIdFor(addon, agentDefault, effectiveModelId, rootModel)),
|
|
29778
|
-
disabled: false,
|
|
29779
|
-
onChange: (next) => update({ settings: { ...next.settings } })
|
|
29780
|
-
}, field.key))]
|
|
30007
|
+
(fields.length > 0 || rootSourceState(addon.id, agentDefault.settings, rootModel)) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
30008
|
+
className: "pt-2 border-t border-border/50",
|
|
30009
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LayeredSettingsForm, {
|
|
30010
|
+
addon,
|
|
30011
|
+
fields,
|
|
30012
|
+
layers: { node: agentDefault.settings },
|
|
30013
|
+
target: "node",
|
|
30014
|
+
labels: { node: "This node" },
|
|
30015
|
+
modelId: settingsModelIdFor(addon, runningModel, agentDefault.settings, rootModel),
|
|
30016
|
+
...rootModel !== void 0 ? { rootModel } : {},
|
|
30017
|
+
onChangeLayer: (settings) => update({ settings })
|
|
30018
|
+
})
|
|
29781
30019
|
}),
|
|
29782
30020
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ClusterSettingsHint, { addonId: addon.id })
|
|
29783
30021
|
]
|
|
29784
30022
|
});
|
|
29785
30023
|
}
|
|
29786
|
-
function DeviceModeEditor({ addon, agentDefault, agentNodeId, currentPatch, modelsForFormat, engineFormat, effectiveModelId, rootModel, onChangePatch }) {
|
|
29787
|
-
const effective = computeEffective("device", agentDefault, currentPatch);
|
|
29788
|
-
const inheritedModelId = agentDefault.modelId ?? effectiveModelId;
|
|
29789
|
-
const formatDefault = addon.defaultModelIdByFormat?.[engineFormat] ?? addon.defaultModelId;
|
|
29790
|
-
const commitPatch = (next) => {
|
|
29791
|
-
const hasAnyField = next.modelId !== void 0 || next.settings !== void 0;
|
|
29792
|
-
onChangePatch?.(hasAnyField ? next : null);
|
|
29793
|
-
};
|
|
29794
|
-
const setModel = (modelId) => {
|
|
29795
|
-
const { modelId: _prev, ...rest } = currentPatch ?? {};
|
|
29796
|
-
commitPatch(modelId === void 0 ? rest : {
|
|
29797
|
-
...rest,
|
|
29798
|
-
modelId
|
|
29799
|
-
});
|
|
29800
|
-
};
|
|
29801
|
-
const setSettings = (settings) => {
|
|
29802
|
-
const { settings: _prev, ...rest } = currentPatch ?? {};
|
|
29803
|
-
commitPatch(settings === void 0 ? rest : {
|
|
29804
|
-
...rest,
|
|
29805
|
-
settings
|
|
29806
|
-
});
|
|
29807
|
-
};
|
|
29808
|
-
const modelOverridden = currentPatch?.modelId !== void 0;
|
|
29809
|
-
const localSchema = nodeLocalConfigSchema(addon);
|
|
29810
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
29811
|
-
className: "space-y-4 text-xs",
|
|
29812
|
-
children: [
|
|
29813
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
29814
|
-
className: "rounded bg-muted/40 px-3 py-2 text-[11px] text-foreground-subtle",
|
|
29815
|
-
children: [
|
|
29816
|
-
"Provisioning for ",
|
|
29817
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
29818
|
-
className: "font-semibold text-foreground",
|
|
29819
|
-
children: agentNodeId
|
|
29820
|
-
}),
|
|
29821
|
-
" — model + settings only. Whether this camera runs the step is set by its per-camera gate above."
|
|
29822
|
-
]
|
|
29823
|
-
}),
|
|
29824
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(RootModelSourceControl, {
|
|
29825
|
-
stepId: addon.id,
|
|
29826
|
-
settings: effective.settings,
|
|
29827
|
-
rootModel,
|
|
29828
|
-
onChange: (v) => setSettings(withUseRootModel(effective.settings, v))
|
|
29829
|
-
}),
|
|
29830
|
-
rootSourceState(addon.id, effective.settings, rootModel)?.effective === true && rootModel !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RootSuppliedModelNote, {
|
|
29831
|
-
rootModel,
|
|
29832
|
-
stepModelId: effective.modelId ?? inheritedModelId
|
|
29833
|
-
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [
|
|
29834
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
29835
|
-
className: "flex items-center justify-between mb-1",
|
|
29836
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
29837
|
-
className: "text-[10px] uppercase tracking-widest text-foreground-subtle",
|
|
29838
|
-
children: "Model"
|
|
29839
|
-
}), modelOverridden ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
29840
|
-
type: "button",
|
|
29841
|
-
className: "text-[10px] text-foreground-subtle hover:text-foreground",
|
|
29842
|
-
onClick: () => setModel(void 0),
|
|
29843
|
-
children: "Clear"
|
|
29844
|
-
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
29845
|
-
type: "button",
|
|
29846
|
-
className: "text-[10px] text-primary hover:underline",
|
|
29847
|
-
onClick: () => setModel(inheritedModelId),
|
|
29848
|
-
children: "Override"
|
|
29849
|
-
})]
|
|
29850
|
-
}),
|
|
29851
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ModelPicker, {
|
|
29852
|
-
models: modelsForFormat,
|
|
29853
|
-
disabled: !modelOverridden,
|
|
29854
|
-
value: (modelOverridden ? currentPatch?.modelId ?? inheritedModelId : inheritedModelId) ?? "",
|
|
29855
|
-
defaultModelId: formatDefault,
|
|
29856
|
-
onChange: (modelId) => setModel(modelId)
|
|
29857
|
-
}),
|
|
29858
|
-
!modelOverridden && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
29859
|
-
className: "text-[10px] text-foreground-subtle mt-1",
|
|
29860
|
-
children: ["inherits from ", agentNodeId]
|
|
29861
|
-
})
|
|
29862
|
-
] }),
|
|
29863
|
-
localSchema.length > 0 && (() => {
|
|
29864
|
-
const settingsOverridden = currentPatch?.settings !== void 0;
|
|
29865
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
29866
|
-
className: "pt-2 border-t border-border/50 space-y-3",
|
|
29867
|
-
children: [
|
|
29868
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
29869
|
-
className: "flex items-center justify-between",
|
|
29870
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
29871
|
-
className: "text-[10px] uppercase tracking-widest text-foreground-subtle",
|
|
29872
|
-
children: "Settings"
|
|
29873
|
-
}), settingsOverridden ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
29874
|
-
className: "flex items-center gap-3",
|
|
29875
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ResetModelDefaultsButton, {
|
|
29876
|
-
fields: localSchema,
|
|
29877
|
-
modelId: settingsModelIdFor(addon, effective, inheritedModelId, rootModel),
|
|
29878
|
-
settings: currentPatch?.settings,
|
|
29879
|
-
onReset: (settings) => setSettings(settings)
|
|
29880
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
29881
|
-
type: "button",
|
|
29882
|
-
className: "text-[10px] text-foreground-subtle hover:text-foreground",
|
|
29883
|
-
onClick: () => setSettings(void 0),
|
|
29884
|
-
children: "Clear"
|
|
29885
|
-
})]
|
|
29886
|
-
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
29887
|
-
type: "button",
|
|
29888
|
-
className: "text-[10px] text-primary hover:underline",
|
|
29889
|
-
onClick: () => setSettings({ ...agentDefault.settings }),
|
|
29890
|
-
children: "Override"
|
|
29891
|
-
})]
|
|
29892
|
-
}),
|
|
29893
|
-
localSchema.map((field) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ConfigSchemaField, {
|
|
29894
|
-
field,
|
|
29895
|
-
allFields: localSchema,
|
|
29896
|
-
step: buildDisplayStep(addon, effective, settingsModelIdFor(addon, effective, inheritedModelId, rootModel)),
|
|
29897
|
-
disabled: !settingsOverridden,
|
|
29898
|
-
onChange: (next) => setSettings({ ...next.settings })
|
|
29899
|
-
}, field.key)),
|
|
29900
|
-
!settingsOverridden && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
29901
|
-
className: "text-[10px] text-foreground-subtle",
|
|
29902
|
-
children: ["inherits from ", agentNodeId]
|
|
29903
|
-
})
|
|
29904
|
-
]
|
|
29905
|
-
});
|
|
29906
|
-
})(),
|
|
29907
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ClusterSettingsHint, { addonId: addon.id }),
|
|
29908
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
29909
|
-
className: "rounded bg-muted/40 px-3 py-2 text-[11px] text-foreground-subtle",
|
|
29910
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
29911
|
-
className: "font-semibold text-foreground mb-0.5",
|
|
29912
|
-
children: "Effective provisioning preview"
|
|
29913
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
29914
|
-
className: "font-mono truncate",
|
|
29915
|
-
children: [
|
|
29916
|
-
addon.id,
|
|
29917
|
-
" · model: ",
|
|
29918
|
-
effective.modelId ?? inheritedModelId ?? "Auto"
|
|
29919
|
-
]
|
|
29920
|
-
})]
|
|
29921
|
-
})
|
|
29922
|
-
]
|
|
29923
|
-
});
|
|
29924
|
-
}
|
|
29925
|
-
function AgentStepEditor(props) {
|
|
29926
|
-
const { mode, addon, agentDefault, agentNodeId, currentPatch, onChangeAgentConfig, onChangePatch, engineFormat, effectiveModelId, rootModel } = props;
|
|
29927
|
-
const modelsForFormat = (0, react$1.useMemo)(() => stepModelOptions(addon.models, engineFormat), [addon.models, engineFormat]);
|
|
29928
|
-
if (mode === "agent") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AgentModeEditor, {
|
|
29929
|
-
addon,
|
|
29930
|
-
agentDefault,
|
|
29931
|
-
modelsForFormat,
|
|
29932
|
-
engineFormat,
|
|
29933
|
-
effectiveModelId,
|
|
29934
|
-
...rootModel !== void 0 ? { rootModel } : {},
|
|
29935
|
-
onChangeAgentConfig
|
|
29936
|
-
});
|
|
29937
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DeviceModeEditor, {
|
|
29938
|
-
addon,
|
|
29939
|
-
agentDefault,
|
|
29940
|
-
agentNodeId,
|
|
29941
|
-
currentPatch,
|
|
29942
|
-
modelsForFormat,
|
|
29943
|
-
engineFormat,
|
|
29944
|
-
effectiveModelId,
|
|
29945
|
-
...rootModel !== void 0 ? { rootModel } : {},
|
|
29946
|
-
onChangePatch
|
|
29947
|
-
});
|
|
29948
|
-
}
|
|
29949
30024
|
//#endregion
|
|
29950
30025
|
//#region src/primitives/icon-button.tsx
|
|
29951
30026
|
var iconButtonVariants = cva("inline-flex items-center justify-center rounded-md font-medium transition-colors cursor-pointer disabled:opacity-50 disabled:pointer-events-none", {
|
|
@@ -33860,117 +33935,6 @@ async function waitForIceGathering(pc) {
|
|
|
33860
33935
|
});
|
|
33861
33936
|
}
|
|
33862
33937
|
//#endregion
|
|
33863
|
-
//#region src/lib/responsive.ts
|
|
33864
|
-
/**
|
|
33865
|
-
* Responsive design tokens — three-tier system.
|
|
33866
|
-
*
|
|
33867
|
-
* The admin-ui targets three width tiers; every component should pick
|
|
33868
|
-
* the right token from this file instead of hand-coding breakpoints.
|
|
33869
|
-
* Adopting the tokens uniformly is what makes the app feel consistent
|
|
33870
|
-
* across operator devices (mobile / tablet / desktop) and what unlocks
|
|
33871
|
-
* targeted tuning (e.g. shrink every label by 1px in one place).
|
|
33872
|
-
*
|
|
33873
|
-
* Tier definitions (Tailwind breakpoints):
|
|
33874
|
-
*
|
|
33875
|
-
* • **L1 — Compact** (`< 640px`, default = mobile portrait)
|
|
33876
|
-
* Single column, tight padding, smallest text, icon-only buttons
|
|
33877
|
-
* where labels can be inferred. The operator can still see every
|
|
33878
|
-
* stat / action — no horizontal scroll, no clipped text. The user
|
|
33879
|
-
* directive: "molta informazione in poco spazio quando la width è
|
|
33880
|
-
* bassa." [a lot of information in little space when the width is low.]
|
|
33881
|
-
*
|
|
33882
|
-
* • **L2 — Standard** (`sm` — `640–1023px`, tablet + small laptop)
|
|
33883
|
-
* 2-column grids, side panels become visible, button labels return.
|
|
33884
|
-
* Targets ~768px–1024px viewports — the most common operator sizes.
|
|
33885
|
-
*
|
|
33886
|
-
* • **L3 — Spacious** (`lg+` — `≥ 1024px`, desktop)
|
|
33887
|
-
* 4-column grids, generous padding, full-width header text,
|
|
33888
|
-
* side-by-side composite layouts. The operator has elbow room.
|
|
33889
|
-
*
|
|
33890
|
-
* Conventions:
|
|
33891
|
-
* - **Always start from L1** — the bare class is always the compact
|
|
33892
|
-
* variant, then `sm:` adds room at 640px, `lg:` at 1024px. No
|
|
33893
|
-
* desktop-first breakpoints; no max-width queries.
|
|
33894
|
-
* - **Token strings are static** — kept as `as const` so callers can
|
|
33895
|
-
* compose them via `cn()` / template literals without running a
|
|
33896
|
-
* class generator at runtime.
|
|
33897
|
-
* - **Pair the token with a comment** — the comment in the file
|
|
33898
|
-
* names every breakpoint it crosses, so a reader can predict the
|
|
33899
|
-
* layout without going to Tailwind docs.
|
|
33900
|
-
*/
|
|
33901
|
-
/** Container padding for a card-style section (header + body). */
|
|
33902
|
-
var SECTION_CARD = "rounded-lg border border-border bg-surface overflow-hidden";
|
|
33903
|
-
/** Header strip inside a card (between border-b lines). */
|
|
33904
|
-
var SECTION_HEADER = "border-b border-border px-3 sm:px-4 py-1.5 sm:py-2";
|
|
33905
|
-
/** Body padding for a card-style section. */
|
|
33906
|
-
var SECTION_BODY = "p-2 sm:p-3 lg:p-4";
|
|
33907
|
-
/** Gap between cards in a vertical stack. */
|
|
33908
|
-
var STACK_GAP = "space-y-3 sm:space-y-4";
|
|
33909
|
-
/** Gap between cards in a grid (4 cells / row at lg). */
|
|
33910
|
-
var GRID_GAP = "gap-2 sm:gap-3";
|
|
33911
|
-
/** Row padding inside a divided list (e.g. InfoRow). */
|
|
33912
|
-
var LIST_ROW = "px-3 sm:px-4 py-1.5 sm:py-2";
|
|
33913
|
-
/** 1-up at L1, 2-up at L2, 4-up at L3 — quick-stat row. */
|
|
33914
|
-
var GRID_QUICK_STATS = "grid grid-cols-2 sm:grid-cols-2 lg:grid-cols-4";
|
|
33915
|
-
/** 1-up at L1, 2-up at L2+ — paired panels (motion + detection rules). */
|
|
33916
|
-
var GRID_PAIRED = "grid grid-cols-1 lg:grid-cols-2";
|
|
33917
|
-
/** Side-by-side layout that stacks below md (canvas + side panel). */
|
|
33918
|
-
var SPLIT_PANEL_OUTER = "flex flex-col-reverse md:flex-row";
|
|
33919
|
-
/** Sidebar narrow lane in a SPLIT_PANEL_OUTER layout. */
|
|
33920
|
-
var SPLIT_PANEL_SIDE = "w-full md:w-44 lg:w-52 md:flex-shrink-0 border-b md:border-b-0 md:border-l border-border";
|
|
33921
|
-
/**
|
|
33922
|
-
* The tier boundary at which a settings label/value row stops stacking.
|
|
33923
|
-
*
|
|
33924
|
-
* Below it (L1 — compact) the row is ONE column: label on its own line, value
|
|
33925
|
-
* on the next at full width. Above it the row is label-left / value-right as
|
|
33926
|
-
* before. The two-column form needs `SETTING_ROW_LABEL`'s lane plus a readable
|
|
33927
|
-
* value beside it; a phone has neither, and the failure mode is not "cramped"
|
|
33928
|
-
* but "the value is the part that gets cut" — the one thing the operator
|
|
33929
|
-
* opened the page to read.
|
|
33930
|
-
*/
|
|
33931
|
-
var SETTING_ROW_STACK_BREAKPOINT = "sm";
|
|
33932
|
-
/** Outer row: single column at L1, label/value columns from `sm` up. */
|
|
33933
|
-
var SETTING_ROW = "flex min-w-0 flex-col gap-0.5 py-1.5 sm:flex-row sm:items-center";
|
|
33934
|
-
/** Label lane. Full width (and free to wrap) at L1; a fixed lane from `sm` up. */
|
|
33935
|
-
var SETTING_ROW_LABEL = "min-w-0 text-[11px] leading-tight text-foreground-subtle sm:w-32 sm:shrink-0 sm:pr-2";
|
|
33936
|
-
/**
|
|
33937
|
-
* Value lane — the value text plus its trailing affordances (copy / reveal).
|
|
33938
|
-
* `w-full` at L1 so the value owns the whole row once the label is above it;
|
|
33939
|
-
* `sm:flex-1` makes it share the row again from `sm` up.
|
|
33940
|
-
*/
|
|
33941
|
-
var SETTING_ROW_VALUE = "flex w-full min-w-0 items-center gap-1 sm:flex-1";
|
|
33942
|
-
/**
|
|
33943
|
-
* The value text itself. `break-all` lets an opaque token (a key, a URL) wrap
|
|
33944
|
-
* at L1 instead of being cut mid-word; `sm:truncate` restores the single-line
|
|
33945
|
-
* desktop form, where the row is wide enough for truncation to be a choice
|
|
33946
|
-
* rather than data loss.
|
|
33947
|
-
*/
|
|
33948
|
-
var SETTING_ROW_VALUE_TEXT = "min-w-0 break-all text-xs text-foreground sm:truncate";
|
|
33949
|
-
/** Section header label (uppercase tracking-wider). */
|
|
33950
|
-
var TEXT_SECTION_LABEL = "text-[10px] sm:text-[11px] font-semibold text-foreground uppercase tracking-wider";
|
|
33951
|
-
/** Field label inside a row. */
|
|
33952
|
-
var TEXT_FIELD_LABEL = "text-[11px] sm:text-xs text-foreground";
|
|
33953
|
-
/** Sub-label / hint text. */
|
|
33954
|
-
var TEXT_HINT = "text-[10px] text-foreground-subtle";
|
|
33955
|
-
/** Primary value (a metric, badge, …). */
|
|
33956
|
-
var TEXT_VALUE = "text-[11px] sm:text-xs font-medium text-foreground";
|
|
33957
|
-
/** Big metric value (StatCard). */
|
|
33958
|
-
var TEXT_METRIC = "text-base sm:text-lg font-semibold leading-tight text-foreground";
|
|
33959
|
-
/** Default compact button. */
|
|
33960
|
-
var BTN_COMPACT = "inline-flex items-center justify-center gap-1 rounded border border-border bg-surface px-1.5 py-0.5 sm:px-2 sm:py-1 text-[10px] sm:text-[11px] font-medium text-foreground hover:bg-surface-hover transition-colors disabled:opacity-40";
|
|
33961
|
-
/** Primary compact button. */
|
|
33962
|
-
var BTN_COMPACT_PRIMARY = "inline-flex items-center justify-center gap-1 rounded border border-primary/40 bg-primary/15 px-1.5 py-0.5 sm:px-2 sm:py-1 text-[10px] sm:text-[11px] font-medium text-primary hover:bg-primary/25 transition-colors disabled:opacity-40";
|
|
33963
|
-
/** Danger compact button. */
|
|
33964
|
-
var BTN_COMPACT_DANGER = "inline-flex items-center justify-center gap-1 rounded border border-danger/40 bg-danger/10 px-1.5 py-0.5 sm:px-2 sm:py-1 text-[10px] sm:text-[11px] font-medium text-danger hover:bg-danger/20 transition-colors disabled:opacity-40";
|
|
33965
|
-
/** Warning compact button (e.g. cancel-drawing). */
|
|
33966
|
-
var BTN_COMPACT_WARNING = "inline-flex items-center justify-center gap-1 rounded border border-warning/40 bg-warning/10 px-1.5 py-0.5 sm:px-2 sm:py-1 text-[10px] sm:text-[11px] font-medium text-warning hover:bg-warning/20 transition-colors disabled:opacity-40";
|
|
33967
|
-
/** Compact text/select/number input. */
|
|
33968
|
-
var INPUT_COMPACT = "w-full rounded border border-border bg-background px-1.5 py-0.5 sm:px-2 sm:py-1 text-[11px] sm:text-xs text-foreground focus:border-primary focus:ring-1 focus:ring-primary/30 outline-none";
|
|
33969
|
-
/** Chip-style toggle (zone / class selectors in ZoneRulesEditor). */
|
|
33970
|
-
var CHIP_BASE = "inline-flex items-center gap-1 rounded-full border px-1.5 py-0.5 text-[10px] font-medium transition-colors";
|
|
33971
|
-
var CHIP_ACTIVE = "border-primary/50 bg-primary/15 text-primary";
|
|
33972
|
-
var CHIP_INACTIVE = "border-border bg-surface text-foreground-subtle hover:bg-surface-hover";
|
|
33973
|
-
//#endregion
|
|
33974
33938
|
//#region src/composites/data-table-layout.ts
|
|
33975
33939
|
/**
|
|
33976
33940
|
* At this many columns and above, `auto` switches a narrow viewport to cards.
|
|
@@ -55563,16 +55527,16 @@ function cellButtonClass(state, isSelected, extra) {
|
|
|
55563
55527
|
//#endregion
|
|
55564
55528
|
//#region src/composites/device-step-matrix.tsx
|
|
55565
55529
|
/**
|
|
55566
|
-
* DeviceStepMatrix — the
|
|
55567
|
-
*
|
|
55530
|
+
* DeviceStepMatrix — the READ-ONLY "Compare" view of the step inspector
|
|
55531
|
+
* (D756): one hierarchical steps × accelerators matrix showing what every
|
|
55532
|
+
* accelerator runs for every step, side by side.
|
|
55568
55533
|
*
|
|
55569
|
-
* Column 1 (STICKY): the indented step tree
|
|
55570
|
-
*
|
|
55571
|
-
*
|
|
55572
|
-
*
|
|
55573
|
-
*
|
|
55574
|
-
*
|
|
55575
|
-
* but the node has no compatible model, or "—" when N/A.
|
|
55534
|
+
* Column 1 (STICKY): the indented step tree (slot + name + class-flow chips).
|
|
55535
|
+
* Columns 2..N (one per accelerator): the model chip, "⚠ skip" when the step
|
|
55536
|
+
* runs on the camera but the accelerator has no compatible model, or "—".
|
|
55537
|
+
* A click selects that (step, accelerator) in the inspector — the matrix
|
|
55538
|
+
* itself edits nothing (it used to host a slide-over editor that scrolled
|
|
55539
|
+
* away with the page).
|
|
55576
55540
|
*
|
|
55577
55541
|
* Responsive, container-measured (never a global media query, so it also works
|
|
55578
55542
|
* embedded):
|
|
@@ -55583,77 +55547,20 @@ function cellButtonClass(state, isSelected, extra) {
|
|
|
55583
55547
|
* single-node view: a node selector picks ONE node and the matrix renders
|
|
55584
55548
|
* `step-tree × that-one-node`.
|
|
55585
55549
|
*/
|
|
55586
|
-
/**
|
|
55587
|
-
var STEP_COL_REM
|
|
55588
|
-
var STEP_COL_PX = STEP_COL_REM
|
|
55550
|
+
/** The sticky step column. */
|
|
55551
|
+
var STEP_COL_REM = 18;
|
|
55552
|
+
var STEP_COL_PX = STEP_COL_REM * 16;
|
|
55589
55553
|
/**
|
|
55590
|
-
* Narrow (mobile) step-column width. On a phone the wide
|
|
55591
|
-
*
|
|
55592
|
-
*
|
|
55593
|
-
* (both fully readable) rather than cramming every column into the viewport.
|
|
55554
|
+
* Narrow (mobile) step-column width. On a phone the wide column would occlude
|
|
55555
|
+
* nearly the whole viewport, so the single-node layout pins a slimmer sticky
|
|
55556
|
+
* step column and lets the device columns scroll horizontally beside it.
|
|
55594
55557
|
*/
|
|
55595
55558
|
var STEP_COL_SINGLE_REM = 11;
|
|
55596
|
-
function
|
|
55597
|
-
|
|
55598
|
-
|
|
55599
|
-
}
|
|
55600
|
-
/**
|
|
55601
|
-
* Tri-state segmented control. `Default` inherits the catalog value (shown in
|
|
55602
|
-
* the caption); `On`/`Off` pin an explicit per-camera override. Touch-friendly
|
|
55603
|
-
* 28px segments.
|
|
55604
|
-
*/
|
|
55605
|
-
function GateControl({ gate, busy, onSet }) {
|
|
55606
|
-
const active = activeChoice(gate);
|
|
55607
|
-
const seg = (choice, label, value, activeClass) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
55608
|
-
type: "button",
|
|
55609
|
-
"aria-pressed": active === choice,
|
|
55610
|
-
disabled: busy,
|
|
55611
|
-
onClick: () => onSet(value),
|
|
55612
|
-
className: cn("flex-1 px-2 py-1 text-[11px] font-medium leading-none transition-colors", "min-h-[26px]", active === choice ? activeClass : "text-foreground-subtle hover:bg-muted/60", busy && "opacity-50 cursor-not-allowed"),
|
|
55613
|
-
children: label
|
|
55614
|
-
});
|
|
55615
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
55616
|
-
className: "flex flex-col gap-1",
|
|
55617
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
55618
|
-
className: "inline-flex w-fit max-w-full self-start overflow-hidden rounded-md border border-border",
|
|
55619
|
-
children: [
|
|
55620
|
-
seg("default", "Auto", null, "bg-primary/15 text-primary"),
|
|
55621
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: "w-px self-stretch bg-border" }),
|
|
55622
|
-
seg("on", "On", true, "bg-emerald-500 text-white"),
|
|
55623
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: "w-px self-stretch bg-border" }),
|
|
55624
|
-
seg("off", "Off", false, "bg-foreground-subtle/70 text-white")
|
|
55625
|
-
]
|
|
55626
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
55627
|
-
className: "text-[10px] leading-none text-foreground-subtle",
|
|
55628
|
-
children: active === "default" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
55629
|
-
"= default (",
|
|
55630
|
-
gate.defaultOn ? "on" : "off",
|
|
55631
|
-
")"
|
|
55632
|
-
] }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: ["overridden · default ", gate.defaultOn ? "on" : "off"] })
|
|
55633
|
-
})]
|
|
55634
|
-
});
|
|
55635
|
-
}
|
|
55636
|
-
function ZoneBadge() {
|
|
55637
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
55638
|
-
className: "flex flex-col gap-1",
|
|
55639
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
55640
|
-
className: "inline-flex w-fit items-center gap-1 rounded-md border border-violet-500/40 bg-violet-500/10 px-2 py-1 text-[11px] font-medium text-violet-400",
|
|
55641
|
-
children: "Zones"
|
|
55642
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
55643
|
-
className: "text-[10px] leading-none text-foreground-subtle",
|
|
55644
|
-
children: "driven by package zones"
|
|
55645
|
-
})]
|
|
55646
|
-
});
|
|
55647
|
-
}
|
|
55648
|
-
function StepGateCell({ node, depth, gate, busy, onSet, hideGate }) {
|
|
55649
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
55650
|
-
className: "sticky left-0 z-10 flex flex-col gap-2 border-b border-border bg-surface px-3 py-2.5 text-xs min-w-0",
|
|
55559
|
+
function StepCell({ node, depth }) {
|
|
55560
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
55561
|
+
className: "sticky left-0 z-10 flex flex-col gap-2 border-b border-border bg-surface px-3 py-2 text-xs min-w-0",
|
|
55651
55562
|
style: { paddingLeft: `${12 + depth * 14}px` },
|
|
55652
|
-
children:
|
|
55653
|
-
gate,
|
|
55654
|
-
busy,
|
|
55655
|
-
onSet
|
|
55656
|
-
})]
|
|
55563
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(StepLabel, { node })
|
|
55657
55564
|
});
|
|
55658
55565
|
}
|
|
55659
55566
|
/**
|
|
@@ -55692,18 +55599,18 @@ function NodeSelectorBar({ nodes, selected, onSelect }) {
|
|
|
55692
55599
|
]
|
|
55693
55600
|
});
|
|
55694
55601
|
}
|
|
55695
|
-
function MatrixGrid
|
|
55602
|
+
function MatrixGrid({ tree, agents, getCellState, onCellClick, selectedCell, single }) {
|
|
55696
55603
|
const rows = (0, react$1.useMemo)(() => flattenTree(tree), [tree]);
|
|
55697
55604
|
const groups = (0, react$1.useMemo)(() => groupAgentColumns(agents), [agents]);
|
|
55698
55605
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
55699
55606
|
className: "overflow-auto rounded border border-border",
|
|
55700
55607
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
55701
55608
|
className: "grid w-max",
|
|
55702
|
-
style: { gridTemplateColumns: `${single ? STEP_COL_SINGLE_REM : STEP_COL_REM
|
|
55609
|
+
style: { gridTemplateColumns: `${single ? STEP_COL_SINGLE_REM : STEP_COL_REM}rem repeat(${agents.length}, 13rem)` },
|
|
55703
55610
|
children: [
|
|
55704
55611
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
55705
55612
|
className: "sticky left-0 top-0 z-20 border-b border-border bg-muted/60 px-3 py-2 text-[10px] uppercase tracking-widest text-foreground-subtle",
|
|
55706
|
-
children:
|
|
55613
|
+
children: "Step"
|
|
55707
55614
|
}),
|
|
55708
55615
|
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", {
|
|
55709
55616
|
className: "sticky top-0 z-10 min-w-0 border-b border-l border-border bg-muted/60 px-3 py-2",
|
|
@@ -55719,26 +55626,18 @@ function MatrixGrid$1({ tree, agents, gateFor, getCellState, onCellClick, select
|
|
|
55719
55626
|
node,
|
|
55720
55627
|
depth,
|
|
55721
55628
|
agents,
|
|
55722
|
-
gate: gateFor(node.addonId),
|
|
55723
55629
|
getCellState,
|
|
55724
55630
|
onCellClick,
|
|
55725
|
-
selectedCell
|
|
55726
|
-
onSetGate,
|
|
55727
|
-
gateBusy,
|
|
55728
|
-
hideGate
|
|
55631
|
+
selectedCell
|
|
55729
55632
|
}, node.addonId))
|
|
55730
55633
|
]
|
|
55731
55634
|
})
|
|
55732
55635
|
});
|
|
55733
55636
|
}
|
|
55734
|
-
function MatrixRow({ node, depth, agents,
|
|
55735
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
55637
|
+
function MatrixRow({ node, depth, agents, getCellState, onCellClick, selectedCell }) {
|
|
55638
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(StepCell, {
|
|
55736
55639
|
node,
|
|
55737
|
-
depth
|
|
55738
|
-
gate,
|
|
55739
|
-
busy: gateBusy,
|
|
55740
|
-
onSet: (next) => onSetGate(node.addonId, next),
|
|
55741
|
-
hideGate
|
|
55640
|
+
depth
|
|
55742
55641
|
}), agents.map((a) => {
|
|
55743
55642
|
const state = getCellState(node.addonId, a);
|
|
55744
55643
|
const isSelected = selectedCell !== null && selectedCell.addonId === node.addonId && agentColumnKey(selectedCell) === agentColumnKey(a);
|
|
@@ -55752,7 +55651,7 @@ function MatrixRow({ node, depth, agents, gate, getCellState, onCellClick, selec
|
|
|
55752
55651
|
}, agentColumnKey(a));
|
|
55753
55652
|
})] });
|
|
55754
55653
|
}
|
|
55755
|
-
function DeviceStepMatrix({ tree, agents,
|
|
55654
|
+
function DeviceStepMatrix({ tree, agents, getCellState, onCellClick, selectedCell, fallbackNodeId, onFallbackNodeChange }) {
|
|
55756
55655
|
const containerRef = (0, react$1.useRef)(null);
|
|
55757
55656
|
const [width, setWidth] = (0, react$1.useState)(0);
|
|
55758
55657
|
(0, react$1.useLayoutEffect)(() => {
|
|
@@ -55778,17 +55677,13 @@ function DeviceStepMatrix({ tree, agents, gateFor, getCellState, onCellClick, se
|
|
|
55778
55677
|
nodes,
|
|
55779
55678
|
selected: selectedNode.agentNodeId,
|
|
55780
55679
|
onSelect: onFallbackNodeChange
|
|
55781
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MatrixGrid
|
|
55680
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MatrixGrid, {
|
|
55782
55681
|
tree,
|
|
55783
55682
|
agents: shownAgents,
|
|
55784
|
-
gateFor,
|
|
55785
55683
|
getCellState,
|
|
55786
55684
|
onCellClick,
|
|
55787
55685
|
selectedCell,
|
|
55788
|
-
|
|
55789
|
-
gateBusy,
|
|
55790
|
-
single: single && selectedNode !== null,
|
|
55791
|
-
hideGate
|
|
55686
|
+
single: single && selectedNode !== null
|
|
55792
55687
|
})]
|
|
55793
55688
|
});
|
|
55794
55689
|
}
|
|
@@ -56818,17 +56713,7 @@ function PlaceholderStep({ addon, onClick }) {
|
|
|
56818
56713
|
})
|
|
56819
56714
|
});
|
|
56820
56715
|
}
|
|
56821
|
-
function PipelineBuilder({ schema, steps, onChange, templates, selectedTemplateId, onSelectTemplate, onSaveTemplate, onUpdateTemplate, onDeleteTemplate, readOnly = false, excludeAddons = [], hideTemplates = false, showOnlyEnabled = false, showSlotLabels = false
|
|
56822
|
-
const stepExtraProps = (addonId) => ({
|
|
56823
|
-
toggleMode,
|
|
56824
|
-
hideModelAndSettings,
|
|
56825
|
-
allowAutoModel,
|
|
56826
|
-
...toggleMode === "threeState" ? {
|
|
56827
|
-
overrideState: overrides[addonId] !== void 0 ? overrides[addonId] : null,
|
|
56828
|
-
onOverrideChange: onOverrideChange ? (next) => onOverrideChange(addonId, next) : void 0,
|
|
56829
|
-
inheritedEnabled: inheritedEnabledByAddon[addonId]
|
|
56830
|
-
} : {}
|
|
56831
|
-
});
|
|
56716
|
+
function PipelineBuilder({ schema, steps, onChange, templates, selectedTemplateId, onSelectTemplate, onSaveTemplate, onUpdateTemplate, onDeleteTemplate, readOnly = false, excludeAddons = [], hideTemplates = false, showOnlyEnabled = false, showSlotLabels = false }) {
|
|
56832
56717
|
const excluded = (0, react$1.useMemo)(() => new Set(excludeAddons), [excludeAddons]);
|
|
56833
56718
|
const schemaMap = (0, react$1.useMemo)(() => buildSchemaMap(schema), [schema]);
|
|
56834
56719
|
const [warnings, setWarnings] = (0, react$1.useState)([]);
|
|
@@ -56935,8 +56820,7 @@ function PipelineBuilder({ schema, steps, onChange, templates, selectedTemplateI
|
|
|
56935
56820
|
allSchemas: schemaMap,
|
|
56936
56821
|
onChange: handleStepChange,
|
|
56937
56822
|
onDelete: readOnly ? void 0 : (id) => onChange(steps.filter((s) => s.addonId !== id)),
|
|
56938
|
-
readOnly
|
|
56939
|
-
...stepExtraProps(step.addonId)
|
|
56823
|
+
readOnly
|
|
56940
56824
|
}), (step.children.length > 0 || childPlaceholders.length > 0) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
56941
56825
|
className: "ml-4 pl-3 border-l border-border/60 space-y-1.5",
|
|
56942
56826
|
children: [
|
|
@@ -56965,8 +56849,7 @@ function PipelineBuilder({ schema, steps, onChange, templates, selectedTemplateI
|
|
|
56965
56849
|
children: step.children.filter((c) => c.addonId !== id)
|
|
56966
56850
|
});
|
|
56967
56851
|
},
|
|
56968
|
-
readOnly
|
|
56969
|
-
...stepExtraProps(child.addonId)
|
|
56852
|
+
readOnly
|
|
56970
56853
|
}), (child.children.length > 0 || childChildPlaceholders.length > 0) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
56971
56854
|
className: "ml-4 pl-3 border-l border-border/40 space-y-1.5",
|
|
56972
56855
|
children: [
|
|
@@ -56997,8 +56880,7 @@ function PipelineBuilder({ schema, steps, onChange, templates, selectedTemplateI
|
|
|
56997
56880
|
} : c)
|
|
56998
56881
|
});
|
|
56999
56882
|
},
|
|
57000
|
-
readOnly
|
|
57001
|
-
...stepExtraProps(grandchild.addonId)
|
|
56883
|
+
readOnly
|
|
57002
56884
|
}, grandchild.addonId)),
|
|
57003
56885
|
!readOnly && childChildPlaceholders.map((addon) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PlaceholderStep, {
|
|
57004
56886
|
addon,
|
|
@@ -57158,179 +57040,6 @@ function PipelineRuntimeSelector({ options, value, onChange }) {
|
|
|
57158
57040
|
});
|
|
57159
57041
|
}
|
|
57160
57042
|
//#endregion
|
|
57161
|
-
//#region src/composites/pipeline-tree-matrix.tsx
|
|
57162
|
-
var STEP_COL_REM = 18;
|
|
57163
|
-
function QuickToggle({ enabled, onChange, disabled }) {
|
|
57164
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
57165
|
-
type: "button",
|
|
57166
|
-
role: "switch",
|
|
57167
|
-
"aria-checked": enabled,
|
|
57168
|
-
disabled,
|
|
57169
|
-
onClick: (e) => {
|
|
57170
|
-
e.stopPropagation();
|
|
57171
|
-
onChange(!enabled);
|
|
57172
|
-
},
|
|
57173
|
-
className: cn("relative inline-flex h-3.5 w-7 shrink-0 items-center rounded-full transition-colors", enabled ? "bg-emerald-500" : "bg-foreground-subtle/30", disabled ? "opacity-50 cursor-not-allowed" : "cursor-pointer"),
|
|
57174
|
-
title: enabled ? "Click to disable" : "Click to enable",
|
|
57175
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: cn("inline-block h-3 w-3 rounded-full bg-white shadow transition-transform", enabled ? "translate-x-3.5" : "translate-x-0.5") })
|
|
57176
|
-
});
|
|
57177
|
-
}
|
|
57178
|
-
function GridRow({ node, depth, agents, getCellState, onCellClick, selectedCell, toggleProps }) {
|
|
57179
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
57180
|
-
className: "sticky left-0 z-10 bg-surface px-3 py-2 border-b border-border text-xs flex items-start gap-2 min-w-0",
|
|
57181
|
-
style: { paddingLeft: `${12 + depth * 14}px` },
|
|
57182
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(StepLabel, { node }), toggleProps && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
57183
|
-
className: "pl-2 pt-0.5 shrink-0",
|
|
57184
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(QuickToggle, {
|
|
57185
|
-
enabled: toggleProps.enabled,
|
|
57186
|
-
onChange: toggleProps.onChange,
|
|
57187
|
-
disabled: toggleProps.disabled
|
|
57188
|
-
})
|
|
57189
|
-
})]
|
|
57190
|
-
}), agents.map((a) => {
|
|
57191
|
-
const state = getCellState(node.addonId, a);
|
|
57192
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
57193
|
-
type: "button",
|
|
57194
|
-
onClick: () => onCellClick(node.addonId, a),
|
|
57195
|
-
className: cellButtonClass(state, selectedCell !== null && selectedCell.addonId === node.addonId && agentColumnKey(selectedCell) === agentColumnKey(a), "min-w-0 overflow-hidden px-3 py-1.5 border-b border-l border-border"),
|
|
57196
|
-
children: renderCellContent(state)
|
|
57197
|
-
}, agentColumnKey(a));
|
|
57198
|
-
})] });
|
|
57199
|
-
}
|
|
57200
|
-
/**
|
|
57201
|
-
* Wide layout: horizontally self-scrolling matrix. The scroll lives INSIDE
|
|
57202
|
-
* this `overflow-auto` box (sticky first column + sticky header row) so the
|
|
57203
|
-
* page body never scrolls sideways. Column tracks are fixed px widths so the
|
|
57204
|
-
* grid is static regardless of content.
|
|
57205
|
-
*/
|
|
57206
|
-
function MatrixGrid({ rows, agents, getCellState, onCellClick, selectedCell, onToggleEnabled }) {
|
|
57207
|
-
const gridTemplate = `${STEP_COL_REM}rem repeat(${agents.length}, 13rem)`;
|
|
57208
|
-
const showToggle = onToggleEnabled !== void 0 && agents.length === 1;
|
|
57209
|
-
const onlyAgent = agents[0];
|
|
57210
|
-
const groups = groupAgentColumns(agents);
|
|
57211
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
57212
|
-
className: "overflow-auto border border-border rounded",
|
|
57213
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
57214
|
-
className: "grid w-max",
|
|
57215
|
-
style: { gridTemplateColumns: gridTemplate },
|
|
57216
|
-
children: [
|
|
57217
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
57218
|
-
className: "sticky top-0 left-0 z-20 bg-muted/60 px-3 py-2 text-[10px] uppercase tracking-widest text-foreground-subtle border-b border-border",
|
|
57219
|
-
children: "Step"
|
|
57220
|
-
}),
|
|
57221
|
-
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", {
|
|
57222
|
-
className: "sticky top-0 z-10 min-w-0 bg-muted/60 px-3 py-2 border-b border-l border-border",
|
|
57223
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
57224
|
-
className: "text-xs font-semibold text-foreground truncate",
|
|
57225
|
-
children: col.agentNodeId
|
|
57226
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
57227
|
-
className: "text-[10px] text-foreground-subtle truncate",
|
|
57228
|
-
children: col.engineLabel
|
|
57229
|
-
})]
|
|
57230
|
-
}, agentColumnKey(col)))),
|
|
57231
|
-
rows.map(({ node, depth }) => {
|
|
57232
|
-
const cellState = showToggle && onlyAgent !== void 0 ? getCellState(node.addonId, onlyAgent) : null;
|
|
57233
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(GridRow, {
|
|
57234
|
-
node,
|
|
57235
|
-
depth,
|
|
57236
|
-
agents,
|
|
57237
|
-
getCellState,
|
|
57238
|
-
onCellClick,
|
|
57239
|
-
selectedCell,
|
|
57240
|
-
toggleProps: showToggle && cellState !== null ? {
|
|
57241
|
-
enabled: cellState.kind === "enabled",
|
|
57242
|
-
onChange: (next) => onToggleEnabled?.(node.addonId, next),
|
|
57243
|
-
disabled: cellState.kind === "na"
|
|
57244
|
-
} : void 0
|
|
57245
|
-
}, node.addonId);
|
|
57246
|
-
})
|
|
57247
|
-
]
|
|
57248
|
-
})
|
|
57249
|
-
});
|
|
57250
|
-
}
|
|
57251
|
-
/**
|
|
57252
|
-
* Narrow layout: one card per agent column, each listing every step stacked
|
|
57253
|
-
* vertically. Feature-parity with the matrix — same `onCellClick`, same
|
|
57254
|
-
* `renderCellContent`, same single-agent `onToggleEnabled`.
|
|
57255
|
-
*/
|
|
57256
|
-
function StackedCards({ rows, agents, getCellState, onCellClick, selectedCell, onToggleEnabled }) {
|
|
57257
|
-
const showToggle = onToggleEnabled !== void 0 && agents.length === 1;
|
|
57258
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
57259
|
-
className: "space-y-3",
|
|
57260
|
-
children: agents.map((a) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
57261
|
-
className: "border border-border rounded overflow-hidden",
|
|
57262
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
57263
|
-
className: "bg-muted/60 px-3 py-2 border-b border-border",
|
|
57264
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
57265
|
-
className: "text-xs font-semibold text-foreground truncate",
|
|
57266
|
-
children: a.deviceLabel ? `${a.agentNodeId} · ${a.deviceLabel}` : a.agentNodeId
|
|
57267
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
57268
|
-
className: "text-[10px] text-foreground-subtle truncate",
|
|
57269
|
-
children: a.engineLabel
|
|
57270
|
-
})]
|
|
57271
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", { children: rows.map(({ node, depth }) => {
|
|
57272
|
-
const state = getCellState(node.addonId, a);
|
|
57273
|
-
const isSelected = selectedCell !== null && selectedCell.addonId === node.addonId && agentColumnKey(selectedCell) === agentColumnKey(a);
|
|
57274
|
-
const toggleProps = showToggle && state !== null ? {
|
|
57275
|
-
enabled: state.kind === "enabled",
|
|
57276
|
-
onChange: (next) => onToggleEnabled?.(node.addonId, next),
|
|
57277
|
-
disabled: state.kind === "na"
|
|
57278
|
-
} : void 0;
|
|
57279
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", {
|
|
57280
|
-
className: "border-b border-border last:border-b-0",
|
|
57281
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
57282
|
-
className: "flex items-center gap-2",
|
|
57283
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
57284
|
-
type: "button",
|
|
57285
|
-
onClick: () => onCellClick(node.addonId, a),
|
|
57286
|
-
className: cellButtonClass(state, isSelected, "flex flex-1 min-w-0 items-start justify-between gap-3 px-3 py-2"),
|
|
57287
|
-
style: { paddingLeft: `${12 + depth * 14}px` },
|
|
57288
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(StepLabel, { node }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
57289
|
-
className: "shrink-0 max-w-[45%] pt-0.5",
|
|
57290
|
-
children: renderCellContent(state)
|
|
57291
|
-
})]
|
|
57292
|
-
}), toggleProps && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
57293
|
-
className: "pr-3 shrink-0",
|
|
57294
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(QuickToggle, {
|
|
57295
|
-
enabled: toggleProps.enabled,
|
|
57296
|
-
onChange: toggleProps.onChange,
|
|
57297
|
-
disabled: toggleProps.disabled
|
|
57298
|
-
})
|
|
57299
|
-
})]
|
|
57300
|
-
})
|
|
57301
|
-
}, node.addonId);
|
|
57302
|
-
}) })]
|
|
57303
|
-
}, agentColumnKey(a)))
|
|
57304
|
-
});
|
|
57305
|
-
}
|
|
57306
|
-
function PipelineTreeMatrix({ tree, agents, getCellState, onCellClick, selectedCell, onToggleEnabled }) {
|
|
57307
|
-
const rows = (0, react$1.useMemo)(() => flattenTree(tree), [tree]);
|
|
57308
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
57309
|
-
className: "@container/matrix w-full",
|
|
57310
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
57311
|
-
className: "@2xl/matrix:hidden",
|
|
57312
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(StackedCards, {
|
|
57313
|
-
rows,
|
|
57314
|
-
agents,
|
|
57315
|
-
getCellState,
|
|
57316
|
-
onCellClick,
|
|
57317
|
-
selectedCell,
|
|
57318
|
-
onToggleEnabled
|
|
57319
|
-
})
|
|
57320
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
57321
|
-
className: "hidden @2xl/matrix:block",
|
|
57322
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MatrixGrid, {
|
|
57323
|
-
rows,
|
|
57324
|
-
agents,
|
|
57325
|
-
getCellState,
|
|
57326
|
-
onCellClick,
|
|
57327
|
-
selectedCell,
|
|
57328
|
-
onToggleEnabled
|
|
57329
|
-
})
|
|
57330
|
-
})]
|
|
57331
|
-
});
|
|
57332
|
-
}
|
|
57333
|
-
//#endregion
|
|
57334
57043
|
//#region src/composites/provider-badge.tsx
|
|
57335
57044
|
var providerConfig = {
|
|
57336
57045
|
onvif: {
|
|
@@ -57774,89 +57483,6 @@ function validateSelector(selector) {
|
|
|
57774
57483
|
}
|
|
57775
57484
|
}
|
|
57776
57485
|
//#endregion
|
|
57777
|
-
//#region src/composites/slide-over-panel.tsx
|
|
57778
|
-
/**
|
|
57779
|
-
* SlideOverPanel — a detail surface anchored to context on desktop and to the
|
|
57780
|
-
* viewport on mobile.
|
|
57781
|
-
*
|
|
57782
|
-
* - **Desktop (`md+`):** an in-container, NON-modal slide-over pinned to the
|
|
57783
|
-
* right edge of the nearest positioned ancestor. The host reserves space with
|
|
57784
|
-
* a matching `md:pr-*` so the panel sits beside its content (e.g. the
|
|
57785
|
-
* multi-node pipeline matrix), not over it.
|
|
57786
|
-
* - **Mobile (`< md`):** a MODAL bottom sheet pinned to the viewport
|
|
57787
|
-
* (`position: fixed`). It never derives its size from the surrounding
|
|
57788
|
-
* container, so it can't stretch across a horizontally-laid-out node matrix
|
|
57789
|
-
* and overflow the page — the previous behaviour when it was a fixed-width
|
|
57790
|
-
* `absolute` panel anchored to the wide matrix wrapper.
|
|
57791
|
-
*
|
|
57792
|
-
* The whole desktop⇄mobile transform is pure Tailwind responsive classes on one
|
|
57793
|
-
* element — no layout-shift on hydration, no portal. JS is used only to lock
|
|
57794
|
-
* body scroll behind the mobile sheet and to wire Escape-to-close.
|
|
57795
|
-
*/
|
|
57796
|
-
function SlideOverPanel({ open, onClose, title, subtitle, footer, children, widthClass = "md:w-[360px]" }) {
|
|
57797
|
-
const isMobile = useIsMobile();
|
|
57798
|
-
(0, react$1.useEffect)(() => {
|
|
57799
|
-
if (!open) return;
|
|
57800
|
-
const onEsc = (e) => {
|
|
57801
|
-
if (e.key === "Escape") onClose();
|
|
57802
|
-
};
|
|
57803
|
-
window.addEventListener("keydown", onEsc);
|
|
57804
|
-
return () => window.removeEventListener("keydown", onEsc);
|
|
57805
|
-
}, [open, onClose]);
|
|
57806
|
-
(0, react$1.useEffect)(() => {
|
|
57807
|
-
if (!open || !isMobile) return;
|
|
57808
|
-
const previous = document.body.style.overflow;
|
|
57809
|
-
document.body.style.overflow = "hidden";
|
|
57810
|
-
return () => {
|
|
57811
|
-
document.body.style.overflow = previous;
|
|
57812
|
-
};
|
|
57813
|
-
}, [open, isMobile]);
|
|
57814
|
-
if (!open) return null;
|
|
57815
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
57816
|
-
className: "fixed inset-0 z-40 bg-black/50 md:hidden",
|
|
57817
|
-
onClick: onClose,
|
|
57818
|
-
"aria-hidden": "true"
|
|
57819
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("aside", {
|
|
57820
|
-
className: cn("fixed inset-x-0 bottom-0 z-50 flex flex-col", "max-h-[85dvh] rounded-t-2xl border-t border-border", "bg-surface shadow-2xl pb-[env(safe-area-inset-bottom)]", "md:absolute md:inset-x-auto md:top-0 md:right-0 md:bottom-0 md:z-20", "md:max-h-none md:rounded-none md:border-t-0 md:border-l md:pb-0", widthClass),
|
|
57821
|
-
role: "dialog",
|
|
57822
|
-
"aria-modal": isMobile ? "true" : "false",
|
|
57823
|
-
children: [
|
|
57824
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
57825
|
-
className: "flex shrink-0 justify-center pt-2 pb-1 md:hidden",
|
|
57826
|
-
"aria-hidden": "true",
|
|
57827
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: "h-1 w-9 rounded-full bg-foreground-subtle/30" })
|
|
57828
|
-
}),
|
|
57829
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", {
|
|
57830
|
-
className: "flex shrink-0 items-start justify-between gap-2 px-4 py-3 border-b border-border",
|
|
57831
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
57832
|
-
className: "min-w-0",
|
|
57833
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
57834
|
-
className: "text-sm font-semibold text-foreground truncate",
|
|
57835
|
-
children: title
|
|
57836
|
-
}), subtitle !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
57837
|
-
className: "text-[11px] text-foreground-subtle mt-0.5 truncate",
|
|
57838
|
-
children: subtitle
|
|
57839
|
-
})]
|
|
57840
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
57841
|
-
type: "button",
|
|
57842
|
-
onClick: onClose,
|
|
57843
|
-
className: "p-1 rounded hover:bg-muted text-foreground-subtle hover:text-foreground",
|
|
57844
|
-
"aria-label": "Close panel",
|
|
57845
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(X, { className: "w-4 h-4" })
|
|
57846
|
-
})]
|
|
57847
|
-
}),
|
|
57848
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
57849
|
-
className: "flex-1 min-h-0 overflow-y-auto overscroll-contain px-4 py-3",
|
|
57850
|
-
children
|
|
57851
|
-
}),
|
|
57852
|
-
footer !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("footer", {
|
|
57853
|
-
className: "flex shrink-0 items-center gap-2 justify-end px-4 py-3 border-t border-border",
|
|
57854
|
-
children: footer
|
|
57855
|
-
})
|
|
57856
|
-
]
|
|
57857
|
-
})] });
|
|
57858
|
-
}
|
|
57859
|
-
//#endregion
|
|
57860
57486
|
//#region src/composites/snapshot-button.tsx
|
|
57861
57487
|
/**
|
|
57862
57488
|
* SnapshotButton — operator-facing manual snapshot trigger.
|
|
@@ -58042,51 +57668,725 @@ function StepTimings({ timings, totalMs, className }) {
|
|
|
58042
57668
|
});
|
|
58043
57669
|
}
|
|
58044
57670
|
//#endregion
|
|
58045
|
-
//#region src/composites/step-
|
|
58046
|
-
|
|
58047
|
-
|
|
58048
|
-
|
|
58049
|
-
|
|
58050
|
-
|
|
58051
|
-
|
|
58052
|
-
|
|
58053
|
-
|
|
58054
|
-
|
|
58055
|
-
|
|
57671
|
+
//#region src/composites/step-inspector/accelerator-tabs.tsx
|
|
57672
|
+
function AcceleratorTabs({ items, selectedId, onSelect }) {
|
|
57673
|
+
const onKeyDown = (e, index) => {
|
|
57674
|
+
const delta = e.key === "ArrowRight" ? 1 : e.key === "ArrowLeft" ? -1 : 0;
|
|
57675
|
+
if (delta === 0) return;
|
|
57676
|
+
e.preventDefault();
|
|
57677
|
+
const next = items[(index + delta + items.length) % items.length];
|
|
57678
|
+
if (next !== void 0) onSelect(next.id);
|
|
57679
|
+
};
|
|
57680
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
57681
|
+
role: "tablist",
|
|
57682
|
+
"aria-label": "Accelerator",
|
|
57683
|
+
className: "-mx-1 flex min-w-0 flex-nowrap gap-1 overflow-x-auto px-1 pb-0.5",
|
|
57684
|
+
children: items.map((item, index) => {
|
|
57685
|
+
const selected = item.id === selectedId;
|
|
57686
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
57687
|
+
type: "button",
|
|
57688
|
+
role: "tab",
|
|
57689
|
+
"aria-selected": selected,
|
|
57690
|
+
"aria-label": item.marked ? `${item.label} (camera override)` : item.label,
|
|
57691
|
+
tabIndex: selected ? 0 : -1,
|
|
57692
|
+
onClick: () => onSelect(item.id),
|
|
57693
|
+
onKeyDown: (e) => onKeyDown(e, index),
|
|
57694
|
+
className: cn("inline-flex h-9 shrink-0 items-center gap-1 whitespace-nowrap rounded-md border px-2.5 text-[11px] font-medium transition-colors md:h-7", selected ? "border-primary/50 bg-primary/15 text-primary" : "border-border text-foreground-subtle hover:bg-surface-hover hover:text-foreground"),
|
|
57695
|
+
children: [item.label, item.marked && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
57696
|
+
className: "h-1.5 w-1.5 rounded-full bg-amber-500",
|
|
57697
|
+
"aria-hidden": true
|
|
57698
|
+
})]
|
|
57699
|
+
}, item.id);
|
|
57700
|
+
})
|
|
57701
|
+
});
|
|
57702
|
+
}
|
|
57703
|
+
//#endregion
|
|
57704
|
+
//#region src/composites/step-inspector/gate-control.tsx
|
|
57705
|
+
/**
|
|
57706
|
+
* GateControl — whether ONE camera runs a step: Auto (the catalog default) /
|
|
57707
|
+
* On / Off. A per-camera, node-independent switch, written at once (it is not
|
|
57708
|
+
* part of the inspector's draft). `package-detection` is driven by package
|
|
57709
|
+
* zones and shows a badge instead.
|
|
57710
|
+
*
|
|
57711
|
+
* Segments are 36 px tall on a phone and 32 px from `md` up — the matrix this
|
|
57712
|
+
* replaced drew 26 px ones.
|
|
57713
|
+
*/
|
|
57714
|
+
function activeChoice(gate) {
|
|
57715
|
+
if (!gate.explicit) return "auto";
|
|
57716
|
+
return gate.effectiveOn ? "on" : "off";
|
|
57717
|
+
}
|
|
57718
|
+
function GateControl({ gate, busy = false, onSet }) {
|
|
57719
|
+
if (gate.kind === "zone-driven") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
57720
|
+
className: "inline-flex items-center rounded-md border border-violet-500/40 bg-violet-500/10 px-2 py-1 text-[11px] font-medium text-violet-400",
|
|
57721
|
+
title: "Runs where this camera has package zones — set on the Zones tab",
|
|
57722
|
+
children: "Zones"
|
|
57723
|
+
});
|
|
57724
|
+
const active = activeChoice(gate);
|
|
57725
|
+
const segment = (choice, label, value, on) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
58056
57726
|
type: "button",
|
|
58057
|
-
|
|
58058
|
-
|
|
58059
|
-
|
|
58060
|
-
|
|
58061
|
-
|
|
58062
|
-
|
|
58063
|
-
|
|
58064
|
-
|
|
58065
|
-
|
|
58066
|
-
|
|
58067
|
-
|
|
58068
|
-
|
|
57727
|
+
role: "radio",
|
|
57728
|
+
"aria-checked": active === choice,
|
|
57729
|
+
disabled: busy,
|
|
57730
|
+
onClick: () => onSet(value),
|
|
57731
|
+
className: cn("h-9 min-w-12 px-3 text-xs font-medium transition-colors md:h-8", active === choice ? on : "text-foreground-subtle hover:bg-muted/60", busy && "cursor-not-allowed opacity-50"),
|
|
57732
|
+
children: label
|
|
57733
|
+
});
|
|
57734
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
57735
|
+
className: "flex items-center gap-2",
|
|
57736
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
57737
|
+
role: "radiogroup",
|
|
57738
|
+
"aria-label": "Runs on this camera",
|
|
57739
|
+
title: `Catalog default: ${gate.defaultOn ? "on" : "off"}`,
|
|
57740
|
+
className: "inline-flex overflow-hidden rounded-md border border-border",
|
|
57741
|
+
children: [
|
|
57742
|
+
segment("auto", "Auto", null, "bg-primary/15 text-primary"),
|
|
57743
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
57744
|
+
className: "w-px self-stretch bg-border",
|
|
57745
|
+
"aria-hidden": true
|
|
57746
|
+
}),
|
|
57747
|
+
segment("on", "On", true, "bg-emerald-500 text-white"),
|
|
57748
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
57749
|
+
className: "w-px self-stretch bg-border",
|
|
57750
|
+
"aria-hidden": true
|
|
57751
|
+
}),
|
|
57752
|
+
segment("off", "Off", false, "bg-foreground-subtle/70 text-white")
|
|
57753
|
+
]
|
|
57754
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
57755
|
+
className: "hidden text-[10px] text-foreground-subtle @3xl/inspector:inline",
|
|
57756
|
+
children: ["default: ", gate.defaultOn ? "on" : "off"]
|
|
58069
57757
|
})]
|
|
58070
|
-
})
|
|
58071
|
-
|
|
58072
|
-
|
|
58073
|
-
|
|
58074
|
-
|
|
58075
|
-
|
|
58076
|
-
|
|
57758
|
+
});
|
|
57759
|
+
}
|
|
57760
|
+
/** The gate as a short list-row badge. */
|
|
57761
|
+
function GateBadge({ gate }) {
|
|
57762
|
+
if (gate.kind === "zone-driven") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
57763
|
+
className: "shrink-0 text-[9px] font-semibold uppercase text-violet-400",
|
|
57764
|
+
children: "zones"
|
|
57765
|
+
});
|
|
57766
|
+
const on = gate.effectiveOn;
|
|
57767
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
57768
|
+
className: cn("shrink-0 rounded px-1.5 py-px text-[9px] font-semibold uppercase", on ? "bg-emerald-500/15 text-emerald-500" : "bg-muted text-foreground-subtle", gate.explicit && "ring-1 ring-inset ring-current"),
|
|
57769
|
+
title: gate.explicit ? "Set for this camera" : "Catalog default",
|
|
57770
|
+
children: on ? "on" : "off"
|
|
57771
|
+
});
|
|
57772
|
+
}
|
|
57773
|
+
//#endregion
|
|
57774
|
+
//#region src/composites/step-inspector/segmented-choice.tsx
|
|
57775
|
+
/**
|
|
57776
|
+
* SegmentedChoice — a small, labelled single-choice group (a radiogroup of
|
|
57777
|
+
* buttons): which layer the inspector's settings edit ("All accelerators" /
|
|
57778
|
+
* "Only hub · NPU"). 36 px tall on a phone, 28 px from `md` up.
|
|
57779
|
+
*/
|
|
57780
|
+
function SegmentedChoice({ label, options, value, onChange }) {
|
|
57781
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
57782
|
+
role: "radiogroup",
|
|
57783
|
+
"aria-label": label,
|
|
57784
|
+
className: "flex flex-wrap items-center gap-1",
|
|
57785
|
+
children: options.map((option) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
57786
|
+
type: "button",
|
|
57787
|
+
role: "radio",
|
|
57788
|
+
"aria-checked": value === option.value,
|
|
57789
|
+
onClick: () => onChange(option.value),
|
|
57790
|
+
className: cn("h-9 rounded-md border px-2.5 text-[11px] font-medium transition-colors md:h-7", value === option.value ? "border-primary/50 bg-primary/15 text-primary" : "border-border text-foreground-subtle hover:bg-surface-hover hover:text-foreground"),
|
|
57791
|
+
children: option.label
|
|
57792
|
+
}, option.value))
|
|
57793
|
+
});
|
|
57794
|
+
}
|
|
57795
|
+
//#endregion
|
|
57796
|
+
//#region src/composites/step-inspector/step-chips.tsx
|
|
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
|
|
57858
|
+
/**
|
|
57859
|
+
* StepInspectorLayout — the master–detail frame of the step inspector.
|
|
57860
|
+
*
|
|
57861
|
+
* Desktop: the step list and the inspector side by side, each scrolling on its
|
|
57862
|
+
* own, in a block whose height FILLS the page's scroll container below it. So
|
|
57863
|
+
* neither pane depends on the page scroll position: the inspector's header and
|
|
57864
|
+
* save bar are always on screen, and the selected step stays visible in the
|
|
57865
|
+
* list. (The slide-over this replaced was absolutely positioned inside the
|
|
57866
|
+
* matrix block — its title and its Save button scrolled away with the page.)
|
|
57867
|
+
* In a narrow container (the camera page beside its live view, a tablet) the
|
|
57868
|
+
* two panes stack: the list on top, a third of the height.
|
|
57869
|
+
*
|
|
57870
|
+
* Phone: the list flows with the page; the inspector opens as a full-screen
|
|
57871
|
+
* sheet with "‹ Steps" to go back.
|
|
57872
|
+
*/
|
|
57873
|
+
/** The tallest the inspector block can be without making its scroll container scroll. */
|
|
57874
|
+
function fillHeightPx(input) {
|
|
57875
|
+
const room = input.scrollerHeight - input.paddingBottom - input.offsetInScroller;
|
|
57876
|
+
return Math.max(input.minPx, Math.floor(room));
|
|
57877
|
+
}
|
|
57878
|
+
function scrollParentOf(el) {
|
|
57879
|
+
for (let p = el.parentElement; p !== null; p = p.parentElement) {
|
|
57880
|
+
const { overflowY } = getComputedStyle(p);
|
|
57881
|
+
if (overflowY === "auto" || overflowY === "scroll") return p;
|
|
57882
|
+
}
|
|
57883
|
+
return null;
|
|
57884
|
+
}
|
|
57885
|
+
/** Height of the block so that it ends at the bottom of its scroll container. */
|
|
57886
|
+
function useFillHeight(enabled, minPx) {
|
|
57887
|
+
const ref = (0, react$1.useRef)(null);
|
|
57888
|
+
const [height, setHeight] = (0, react$1.useState)(null);
|
|
57889
|
+
(0, react$1.useLayoutEffect)(() => {
|
|
57890
|
+
const el = ref.current;
|
|
57891
|
+
if (!enabled || el === null) return;
|
|
57892
|
+
const scroller = scrollParentOf(el);
|
|
57893
|
+
const measure = () => {
|
|
57894
|
+
const box = scroller ?? document.documentElement;
|
|
57895
|
+
const style = getComputedStyle(box);
|
|
57896
|
+
const top = scroller ? scroller.getBoundingClientRect().top : 0;
|
|
57897
|
+
const scrollTop = scroller ? scroller.scrollTop : window.scrollY;
|
|
57898
|
+
setHeight(fillHeightPx({
|
|
57899
|
+
scrollerHeight: scroller ? scroller.clientHeight : window.innerHeight,
|
|
57900
|
+
paddingBottom: Number.parseFloat(style.paddingBottom) || 0,
|
|
57901
|
+
offsetInScroller: el.getBoundingClientRect().top - top + scrollTop,
|
|
57902
|
+
minPx
|
|
57903
|
+
}));
|
|
57904
|
+
};
|
|
57905
|
+
measure();
|
|
57906
|
+
const RO = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(measure);
|
|
57907
|
+
if (scroller) RO?.observe(scroller);
|
|
57908
|
+
if (el.parentElement) RO?.observe(el.parentElement);
|
|
57909
|
+
window.addEventListener("resize", measure);
|
|
57910
|
+
return () => {
|
|
57911
|
+
RO?.disconnect();
|
|
57912
|
+
window.removeEventListener("resize", measure);
|
|
57913
|
+
};
|
|
57914
|
+
}, [enabled, minPx]);
|
|
57915
|
+
return {
|
|
57916
|
+
ref,
|
|
57917
|
+
height
|
|
57918
|
+
};
|
|
58077
57919
|
}
|
|
58078
|
-
function
|
|
57920
|
+
function StepInspectorLayout({ list, detail, mobileDetailOpen, onMobileClose, minHeightPx = 420, className }) {
|
|
57921
|
+
const isMobile = useIsMobile();
|
|
57922
|
+
const { ref, height } = useFillHeight(!isMobile, minHeightPx);
|
|
57923
|
+
if (isMobile) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
57924
|
+
className: cn("space-y-3", className),
|
|
57925
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
57926
|
+
className: SECTION_CARD,
|
|
57927
|
+
children: list
|
|
57928
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Dialog, {
|
|
57929
|
+
open: mobileDetailOpen,
|
|
57930
|
+
onOpenChange: (open) => !open && onMobileClose(),
|
|
57931
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DialogContent, {
|
|
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
|
+
});
|
|
58079
57939
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
58080
|
-
|
|
58081
|
-
|
|
58082
|
-
|
|
58083
|
-
|
|
58084
|
-
|
|
58085
|
-
|
|
58086
|
-
|
|
58087
|
-
|
|
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
|
+
})]
|
|
57952
|
+
})
|
|
57953
|
+
});
|
|
57954
|
+
}
|
|
57955
|
+
/** "‹ Steps" — the phone sheet's way back to the list. */
|
|
57956
|
+
function BackToStepsButton({ onClick }) {
|
|
57957
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
57958
|
+
type: "button",
|
|
57959
|
+
onClick,
|
|
57960
|
+
className: "inline-flex h-9 items-center gap-0.5 rounded-md border border-border px-2 text-xs text-foreground hover:bg-surface-hover",
|
|
57961
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChevronLeft, {
|
|
57962
|
+
className: "h-3.5 w-3.5",
|
|
57963
|
+
"aria-hidden": true
|
|
57964
|
+
}), "Steps"]
|
|
58088
57965
|
});
|
|
58089
57966
|
}
|
|
57967
|
+
//#endregion
|
|
57968
|
+
//#region src/composites/step-inspector/step-inspector-panel.tsx
|
|
57969
|
+
/**
|
|
57970
|
+
* StepInspectorPanel — the detail pane of the step inspector: a pinned header
|
|
57971
|
+
* (the step, its gate, the accelerator tabs), ONE scrolling body, and a pinned
|
|
57972
|
+
* save bar. Nothing in it depends on the page's scroll position — the slide-over
|
|
57973
|
+
* it replaced was anchored to the matrix block and scrolled away with it.
|
|
57974
|
+
*/
|
|
57975
|
+
function SaveBar({ dirtyCount, saving, status, error, onSave, onDiscard }) {
|
|
57976
|
+
const dirty = dirtyCount > 0;
|
|
57977
|
+
const message = saving ? "Saving…" : dirty ? `${dirtyCount} unsaved change${dirtyCount === 1 ? "" : "s"}` : status === "saved" ? "Saved" : status === "error" ? error ?? "Save failed" : "No unsaved changes";
|
|
57978
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("footer", {
|
|
57979
|
+
className: "flex shrink-0 items-center gap-2 border-t border-border bg-surface px-4 py-2 pb-[max(0.5rem,env(safe-area-inset-bottom))] md:pb-2",
|
|
57980
|
+
children: [
|
|
57981
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
57982
|
+
role: "status",
|
|
57983
|
+
className: cn("min-w-0 flex-1 truncate text-[11px]", status === "error" && !dirty ? "text-danger" : dirty ? "text-amber-500" : "text-foreground-subtle"),
|
|
57984
|
+
children: message
|
|
57985
|
+
}),
|
|
57986
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
57987
|
+
variant: "outline",
|
|
57988
|
+
size: "md",
|
|
57989
|
+
disabled: !dirty || saving,
|
|
57990
|
+
onClick: onDiscard,
|
|
57991
|
+
children: "Discard"
|
|
57992
|
+
}),
|
|
57993
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
57994
|
+
variant: "primary",
|
|
57995
|
+
size: "md",
|
|
57996
|
+
disabled: !dirty || saving,
|
|
57997
|
+
onClick: onSave,
|
|
57998
|
+
children: "Save"
|
|
57999
|
+
})
|
|
58000
|
+
]
|
|
58001
|
+
});
|
|
58002
|
+
}
|
|
58003
|
+
var StepInspectorPanel = (0, react$1.forwardRef)(function StepInspectorPanel({ title, subtitle, headerActions, headerExtra, leading, saveBar, onEscape, children, className }, headingRef) {
|
|
58004
|
+
const headingId = (0, react$1.useId)();
|
|
58005
|
+
const onKeyDown = (e) => {
|
|
58006
|
+
if (e.key !== "Escape" || onEscape === void 0) return;
|
|
58007
|
+
e.stopPropagation();
|
|
58008
|
+
onEscape();
|
|
58009
|
+
};
|
|
58010
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
58011
|
+
"aria-labelledby": headingId,
|
|
58012
|
+
onKeyDown,
|
|
58013
|
+
className: cn("flex min-h-0 flex-1 flex-col overflow-hidden bg-surface", className),
|
|
58014
|
+
children: [
|
|
58015
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", {
|
|
58016
|
+
className: "shrink-0 space-y-2 border-b border-border px-4 py-2.5",
|
|
58017
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
58018
|
+
className: "flex flex-wrap items-start gap-x-3 gap-y-2",
|
|
58019
|
+
children: [
|
|
58020
|
+
leading,
|
|
58021
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
58022
|
+
className: "min-w-[9rem] flex-1",
|
|
58023
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
|
|
58024
|
+
id: headingId,
|
|
58025
|
+
ref: headingRef,
|
|
58026
|
+
tabIndex: -1,
|
|
58027
|
+
className: "truncate text-sm font-semibold text-foreground outline-none focus-visible:ring-2 focus-visible:ring-primary rounded",
|
|
58028
|
+
children: title
|
|
58029
|
+
}), subtitle !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
58030
|
+
className: "mt-0.5 text-[11px] text-foreground-subtle",
|
|
58031
|
+
children: subtitle
|
|
58032
|
+
})]
|
|
58033
|
+
}),
|
|
58034
|
+
headerActions
|
|
58035
|
+
]
|
|
58036
|
+
}), headerExtra]
|
|
58037
|
+
}),
|
|
58038
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
58039
|
+
"data-inspector-body": true,
|
|
58040
|
+
className: "min-h-0 flex-1 overflow-y-auto overscroll-contain px-4 py-3",
|
|
58041
|
+
children
|
|
58042
|
+
}),
|
|
58043
|
+
saveBar !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SaveBar, { ...saveBar })
|
|
58044
|
+
]
|
|
58045
|
+
});
|
|
58046
|
+
});
|
|
58047
|
+
//#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
|
+
//#region src/composites/step-inspector/step-model-row.tsx
|
|
58235
|
+
var SOURCE_TONE = {
|
|
58236
|
+
camera: "border-primary/40 bg-primary/10 text-primary",
|
|
58237
|
+
node: "border-border bg-muted/40 text-foreground",
|
|
58238
|
+
default: "border-border/60 text-foreground-subtle",
|
|
58239
|
+
cluster: "border-primary/40 bg-primary/5 text-primary"
|
|
58240
|
+
};
|
|
58241
|
+
function StepModelRow({ label, format, modelId, source, sourceLabel, models, defaultModelId, expanded, onToggle, onChangeModel, onReset, resetLabel = "Reset", note, extra, changed = false, disabled = false }) {
|
|
58242
|
+
const pickable = models.length > 0 && note === void 0;
|
|
58243
|
+
const canExpand = pickable || extra !== void 0;
|
|
58244
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
58245
|
+
className: cn("rounded-md border border-border", expanded && "bg-muted/10"),
|
|
58246
|
+
children: [
|
|
58247
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
58248
|
+
className: cn(LIST_ROW, "space-y-1"),
|
|
58249
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
58250
|
+
className: "flex flex-wrap items-center gap-x-2 gap-y-1 text-xs",
|
|
58251
|
+
children: [
|
|
58252
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
58253
|
+
className: "font-medium text-foreground",
|
|
58254
|
+
children: label
|
|
58255
|
+
}),
|
|
58256
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
58257
|
+
className: "text-[10px] text-foreground-subtle",
|
|
58258
|
+
children: format
|
|
58259
|
+
}),
|
|
58260
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
58261
|
+
className: cn("ml-auto rounded border px-1.5 py-px text-[10px] font-medium", SOURCE_TONE[source]),
|
|
58262
|
+
children: sourceLabel
|
|
58263
|
+
})
|
|
58264
|
+
]
|
|
58265
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
58266
|
+
className: "flex items-center gap-2",
|
|
58267
|
+
children: [
|
|
58268
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
58269
|
+
className: "min-w-0 flex-1 truncate font-mono text-xs text-foreground",
|
|
58270
|
+
children: [modelId ?? "—", changed && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
58271
|
+
className: "ml-1 text-amber-500",
|
|
58272
|
+
children: "•"
|
|
58273
|
+
})]
|
|
58274
|
+
}),
|
|
58275
|
+
onReset !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
58276
|
+
type: "button",
|
|
58277
|
+
className: "inline-flex items-center justify-center gap-1 rounded border border-border bg-surface px-1.5 py-0.5 sm:px-2 sm:py-1 text-[10px] sm:text-[11px] font-medium text-foreground hover:bg-surface-hover transition-colors disabled:opacity-40",
|
|
58278
|
+
disabled,
|
|
58279
|
+
onClick: onReset,
|
|
58280
|
+
children: resetLabel
|
|
58281
|
+
}),
|
|
58282
|
+
canExpand && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
58283
|
+
type: "button",
|
|
58284
|
+
className: cn("inline-flex items-center justify-center gap-1 rounded border border-border bg-surface px-1.5 py-0.5 sm:px-2 sm:py-1 text-[10px] sm:text-[11px] font-medium text-foreground hover:bg-surface-hover transition-colors disabled:opacity-40", "min-h-9 md:min-h-0"),
|
|
58285
|
+
"aria-expanded": expanded,
|
|
58286
|
+
"aria-label": `Change model for ${label}`,
|
|
58287
|
+
disabled,
|
|
58288
|
+
onClick: onToggle,
|
|
58289
|
+
children: expanded ? "Done" : pickable ? "Change" : "Route"
|
|
58290
|
+
})
|
|
58291
|
+
]
|
|
58292
|
+
})]
|
|
58293
|
+
}),
|
|
58294
|
+
note !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
58295
|
+
className: "border-t border-border/60 px-3 py-1.5 text-[10px] leading-snug text-foreground-subtle",
|
|
58296
|
+
children: note
|
|
58297
|
+
}),
|
|
58298
|
+
expanded && canExpand && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
58299
|
+
className: "space-y-3 border-t border-border/60 px-3 py-3",
|
|
58300
|
+
children: [pickable && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ModelPicker, {
|
|
58301
|
+
models,
|
|
58302
|
+
value: modelId ?? "",
|
|
58303
|
+
defaultModelId,
|
|
58304
|
+
disabled,
|
|
58305
|
+
onChange: onChangeModel
|
|
58306
|
+
}), extra]
|
|
58307
|
+
})
|
|
58308
|
+
]
|
|
58309
|
+
});
|
|
58310
|
+
}
|
|
58311
|
+
//#endregion
|
|
58312
|
+
//#region src/composites/step-inspector/step-model-list.tsx
|
|
58313
|
+
/**
|
|
58314
|
+
* StepModelList — the model section of the step inspector.
|
|
58315
|
+
*
|
|
58316
|
+
* While nothing is pinned, edited or worth a note, the accelerators are
|
|
58317
|
+
* summarised by model — one line per distinct model, naming the accelerators
|
|
58318
|
+
* that run it ("yolov9m-320-int8 · hub iGPU, hub NPU, little-unraid iGPU") —
|
|
58319
|
+
* with "Per accelerator" to open one `StepModelRow` each. Four near-identical
|
|
58320
|
+
* rows pushed the settings, the thing most edits are about, below the fold.
|
|
58321
|
+
* A pin, a pending change or a note (no build here, root-supplied) shows every
|
|
58322
|
+
* row, so nothing that differs from the default is ever folded away.
|
|
58323
|
+
*/
|
|
58324
|
+
/** True when the rows can be summarised: nothing pinned here, edited, or noted. */
|
|
58325
|
+
function modelRowsAreFoldable(rows) {
|
|
58326
|
+
return rows.length >= 2 && rows.every((r) => r.note === void 0 && r.onReset === void 0 && r.changed !== true && !r.expanded);
|
|
58327
|
+
}
|
|
58328
|
+
function groupByModel(rows) {
|
|
58329
|
+
const groups = [];
|
|
58330
|
+
for (const row of rows) {
|
|
58331
|
+
const modelId = row.modelId ?? "—";
|
|
58332
|
+
const index = groups.findIndex((g) => g.modelId === modelId && g.sourceLabel === row.sourceLabel);
|
|
58333
|
+
const existing = groups[index];
|
|
58334
|
+
if (existing !== void 0) groups[index] = {
|
|
58335
|
+
...existing,
|
|
58336
|
+
labels: [...existing.labels, row.label]
|
|
58337
|
+
};
|
|
58338
|
+
else groups.push({
|
|
58339
|
+
modelId,
|
|
58340
|
+
labels: [row.label],
|
|
58341
|
+
sourceLabel: row.sourceLabel
|
|
58342
|
+
});
|
|
58343
|
+
}
|
|
58344
|
+
return groups;
|
|
58345
|
+
}
|
|
58346
|
+
function StepModelList({ rows }) {
|
|
58347
|
+
const [open, setOpen] = (0, react$1.useState)(false);
|
|
58348
|
+
if (!open && modelRowsAreFoldable(rows)) {
|
|
58349
|
+
const groups = groupByModel(rows);
|
|
58350
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
58351
|
+
className: cn("rounded-md border border-border", LIST_ROW),
|
|
58352
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
|
|
58353
|
+
className: "space-y-1",
|
|
58354
|
+
children: groups.map((g) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
|
|
58355
|
+
className: "flex flex-wrap items-baseline gap-x-2 text-xs",
|
|
58356
|
+
children: [
|
|
58357
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
58358
|
+
className: "font-mono text-foreground",
|
|
58359
|
+
children: g.modelId
|
|
58360
|
+
}),
|
|
58361
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
58362
|
+
className: "min-w-0 flex-1 text-[11px] text-foreground-subtle",
|
|
58363
|
+
children: g.labels.length === rows.length ? `all ${rows.length} accelerators` : g.labels.join(", ")
|
|
58364
|
+
}),
|
|
58365
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
58366
|
+
className: "rounded border border-border px-1.5 py-px text-[10px] font-medium text-foreground-subtle",
|
|
58367
|
+
children: g.sourceLabel
|
|
58368
|
+
})
|
|
58369
|
+
]
|
|
58370
|
+
}, `${g.modelId}|${g.sourceLabel}`))
|
|
58371
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
58372
|
+
className: "mt-1.5 flex justify-end",
|
|
58373
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
58374
|
+
type: "button",
|
|
58375
|
+
className: cn(BTN_COMPACT, "min-h-9 md:min-h-0"),
|
|
58376
|
+
"aria-expanded": false,
|
|
58377
|
+
onClick: () => setOpen(true),
|
|
58378
|
+
children: "Per accelerator"
|
|
58379
|
+
})
|
|
58380
|
+
})]
|
|
58381
|
+
});
|
|
58382
|
+
}
|
|
58383
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
58384
|
+
className: "space-y-2",
|
|
58385
|
+
children: rows.map(({ id, ...row }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(StepModelRow, { ...row }, id))
|
|
58386
|
+
});
|
|
58387
|
+
}
|
|
58388
|
+
//#endregion
|
|
58389
|
+
//#region src/composites/step-tree.ts
|
|
58090
58390
|
/**
|
|
58091
58391
|
* Helper: build a StepTreeNode[] from a `PipelineSchema` by chaining on
|
|
58092
58392
|
* `inputClasses` ⇔ `outputClasses` compatibility. Mirrors the orchestrator
|
|
@@ -61031,6 +61331,7 @@ var SceneMonitorEditor = (0, react$1.lazy)(() => Promise.resolve().then(() => re
|
|
|
61031
61331
|
/** Lazy-wrapped `PrivacyMaskSettings` — code-split off the main bundle. */
|
|
61032
61332
|
var PrivacyMaskSettings = (0, react$1.lazy)(() => Promise.resolve().then(() => require("./PrivacyMaskSettings-BqjXsXZR.cjs")).then((m) => ({ default: m.PrivacyMaskSettings })));
|
|
61033
61333
|
//#endregion
|
|
61334
|
+
exports.AcceleratorTabs = AcceleratorTabs;
|
|
61034
61335
|
exports.AddonGlobalSettingsForm = AddonGlobalSettingsForm;
|
|
61035
61336
|
exports.AdminLinkQuickAction = AdminLinkQuickAction;
|
|
61036
61337
|
exports.AgentStepEditor = AgentStepEditor;
|
|
@@ -61048,6 +61349,7 @@ exports.BTN_COMPACT = BTN_COMPACT;
|
|
|
61048
61349
|
exports.BTN_COMPACT_DANGER = BTN_COMPACT_DANGER;
|
|
61049
61350
|
exports.BTN_COMPACT_PRIMARY = BTN_COMPACT_PRIMARY;
|
|
61050
61351
|
exports.BTN_COMPACT_WARNING = BTN_COMPACT_WARNING;
|
|
61352
|
+
exports.BackToStepsButton = BackToStepsButton;
|
|
61051
61353
|
exports.Badge = Badge;
|
|
61052
61354
|
exports.BatteryBadge = BatteryBadge;
|
|
61053
61355
|
exports.BottomSheet = BottomSheet;
|
|
@@ -61169,6 +61471,8 @@ exports.FormField = FormField$1;
|
|
|
61169
61471
|
exports.GRID_GAP = GRID_GAP;
|
|
61170
61472
|
exports.GRID_PAIRED = GRID_PAIRED;
|
|
61171
61473
|
exports.GRID_QUICK_STATS = GRID_QUICK_STATS;
|
|
61474
|
+
exports.GateBadge = GateBadge;
|
|
61475
|
+
exports.GateControl = GateControl;
|
|
61172
61476
|
exports.Grid2x2 = Grid2x2;
|
|
61173
61477
|
exports.GripTrack = GripTrack;
|
|
61174
61478
|
exports.GroupedModelSelector = GroupedModelSelector;
|
|
@@ -61196,6 +61500,7 @@ exports.LIST_ROW = LIST_ROW;
|
|
|
61196
61500
|
exports.Label = Label;
|
|
61197
61501
|
exports.LawnMowerHeroCard = LawnMowerHeroCard;
|
|
61198
61502
|
exports.LawnMowerInlineControl = LawnMowerInlineControl;
|
|
61503
|
+
exports.LayeredSettingsForm = LayeredSettingsForm;
|
|
61199
61504
|
exports.LightHeroCard = LightHeroCard;
|
|
61200
61505
|
exports.LightInlineControl = LightInlineControl;
|
|
61201
61506
|
exports.LockHeroCard = LockHeroCard;
|
|
@@ -61243,7 +61548,6 @@ exports.PhaseIcon = PhaseIcon;
|
|
|
61243
61548
|
exports.PipelineBuilder = PipelineBuilder;
|
|
61244
61549
|
exports.PipelineRuntimeSelector = PipelineRuntimeSelector;
|
|
61245
61550
|
exports.PipelineStep = PipelineStep;
|
|
61246
|
-
exports.PipelineTreeMatrix = PipelineTreeMatrix;
|
|
61247
61551
|
exports.PlaceholderChipField = PlaceholderChipField;
|
|
61248
61552
|
exports.PlayerOverlaysProvider = PlayerOverlaysProvider;
|
|
61249
61553
|
exports.Popover = Popover;
|
|
@@ -61266,6 +61570,8 @@ exports.RecordingPanel = RecordingPanel;
|
|
|
61266
61570
|
exports.ResponseLog = ResponseLog;
|
|
61267
61571
|
exports.RoleDisplayDefaultsFromServer = RoleDisplayDefaultsFromServer;
|
|
61268
61572
|
exports.RoleDisplayDefaultsProvider = RoleDisplayDefaultsProvider;
|
|
61573
|
+
exports.RootModelSourceControl = RootModelSourceControl;
|
|
61574
|
+
exports.RootSuppliedModelNote = RootSuppliedModelNote;
|
|
61269
61575
|
exports.RotateCcw = RotateCcw;
|
|
61270
61576
|
exports.RunReport = RunReport;
|
|
61271
61577
|
exports.SCENE_CAPTURE_VARIANTS = SCENE_CAPTURE_VARIANTS;
|
|
@@ -61289,6 +61595,7 @@ exports.ScriptHeroCard = ScriptHeroCard;
|
|
|
61289
61595
|
exports.ScriptInlineControl = ScriptInlineControl;
|
|
61290
61596
|
exports.ScrollArea = ScrollArea;
|
|
61291
61597
|
exports.SectionCard = SectionCard;
|
|
61598
|
+
exports.SegmentedChoice = SegmentedChoice;
|
|
61292
61599
|
exports.Select = Select;
|
|
61293
61600
|
exports.SelectedChip = SelectedChip;
|
|
61294
61601
|
exports.SemanticBadge = SemanticBadge;
|
|
@@ -61300,7 +61607,6 @@ exports.SettingRow = SettingRow;
|
|
|
61300
61607
|
exports.Sidebar = Sidebar;
|
|
61301
61608
|
exports.SidebarItem = SidebarItem;
|
|
61302
61609
|
exports.Skeleton = Skeleton;
|
|
61303
|
-
exports.SlideOverPanel = SlideOverPanel;
|
|
61304
61610
|
exports.SlideToggle = SlideToggle;
|
|
61305
61611
|
exports.SnapshotButton = SnapshotButton;
|
|
61306
61612
|
exports.SortHeaderButton = SortHeaderButton;
|
|
@@ -61308,8 +61614,13 @@ exports.Square = Square;
|
|
|
61308
61614
|
exports.StatCard = StatCard;
|
|
61309
61615
|
exports.StateValuesStream = StateValuesStream;
|
|
61310
61616
|
exports.StatusBadge = StatusBadge;
|
|
61617
|
+
exports.StepChips = StepChips;
|
|
61618
|
+
exports.StepInspectorLayout = StepInspectorLayout;
|
|
61619
|
+
exports.StepInspectorPanel = StepInspectorPanel;
|
|
61620
|
+
exports.StepList = StepList;
|
|
61621
|
+
exports.StepModelList = StepModelList;
|
|
61622
|
+
exports.StepModelRow = StepModelRow;
|
|
61311
61623
|
exports.StepTimings = StepTimings;
|
|
61312
|
-
exports.StepTreeMaster = StepTreeMaster;
|
|
61313
61624
|
exports.Stepper = Stepper;
|
|
61314
61625
|
exports.StreamBrokerSelector = StreamBrokerSelector;
|
|
61315
61626
|
exports.StreamDebugOverlay = StreamDebugOverlay;
|
|
@@ -61363,6 +61674,7 @@ exports.applyPickerFilters = applyPickerFilters;
|
|
|
61363
61674
|
exports.ariaSortForColumn = ariaSortForColumn;
|
|
61364
61675
|
exports.badgeFor = badgeFor;
|
|
61365
61676
|
exports.badgeFor$1 = badgeFor;
|
|
61677
|
+
exports.bindsToModel = bindsToModel;
|
|
61366
61678
|
exports.buildPeerConnectionConfig = buildPeerConnectionConfig;
|
|
61367
61679
|
exports.buildStepTreeFromSchema = buildStepTreeFromSchema;
|
|
61368
61680
|
exports.catalogHasDraft = catalogHasDraft;
|
|
@@ -61387,6 +61699,7 @@ exports.createTheme = require_theme_index.createTheme$1;
|
|
|
61387
61699
|
exports.cursorFractionFor = cursorFractionFor;
|
|
61388
61700
|
exports.darkColors = require_theme_index.darkColors$1;
|
|
61389
61701
|
exports.dataTableFacets = dataTableFacets;
|
|
61702
|
+
exports.defaultOfField = defaultOfField;
|
|
61390
61703
|
exports.defaultTheme = require_theme_index.defaultTheme$1;
|
|
61391
61704
|
exports.deriveDeviceKind = deriveDeviceKind;
|
|
61392
61705
|
exports.deriveWebrtcDebugStats = deriveWebrtcDebugStats;
|
|
@@ -61406,6 +61719,7 @@ exports.emptyDevicesWidens = emptyDevicesWidens;
|
|
|
61406
61719
|
exports.emptySessionRun = emptySessionRun;
|
|
61407
61720
|
exports.ensureMfHostInit = ensureMfHostInit;
|
|
61408
61721
|
exports.eventKindLabel = eventKindLabel;
|
|
61722
|
+
exports.fillHeightPx = fillHeightPx;
|
|
61409
61723
|
exports.filterDataTableRows = filterDataTableRows;
|
|
61410
61724
|
exports.filterDeviceOptions = filterDeviceOptions;
|
|
61411
61725
|
exports.filterOptionSelectOptions = filterOptions;
|
|
@@ -61418,6 +61732,7 @@ exports.fleetViewOf = fleetViewOf;
|
|
|
61418
61732
|
exports.formatControlDateTime = formatControlDateTime;
|
|
61419
61733
|
exports.formatLastSeen = formatLastSeen;
|
|
61420
61734
|
exports.formatNumeric = formatNumeric;
|
|
61735
|
+
exports.formatSettingValue = formatSettingValue;
|
|
61421
61736
|
exports.freezeVerdict = freezeVerdict;
|
|
61422
61737
|
exports.fuzzyMatch = fuzzyMatch;
|
|
61423
61738
|
exports.getClassColor = getClassColor;
|
|
@@ -61441,6 +61756,7 @@ exports.isAbsentProvider$1 = isAbsentProvider;
|
|
|
61441
61756
|
exports.isDataTableFilterActive = isDataTableFilterActive;
|
|
61442
61757
|
exports.isFieldVisible = isFieldVisible;
|
|
61443
61758
|
exports.isGroupExpanded = isGroupExpanded;
|
|
61759
|
+
exports.isValueField = isValueField;
|
|
61444
61760
|
exports.lawnMowerActivityMeta = lawnMowerActivityMeta;
|
|
61445
61761
|
exports.lightColors = require_theme_index.lightColors$1;
|
|
61446
61762
|
exports.loadRemoteBundle = loadRemoteBundle;
|
|
@@ -61448,6 +61764,7 @@ exports.makeScrubBridge = makeScrubBridge;
|
|
|
61448
61764
|
exports.metadataEntries = metadataEntries;
|
|
61449
61765
|
exports.metadataString = metadataString;
|
|
61450
61766
|
exports.mirror = mirror;
|
|
61767
|
+
exports.modelRowsAreFoldable = modelRowsAreFoldable;
|
|
61451
61768
|
exports.mountAddonPage = mountAddonPage;
|
|
61452
61769
|
exports.mountPath = mountPath;
|
|
61453
61770
|
exports.nextReconnectAction = nextReconnectAction;
|
|
@@ -61505,9 +61822,11 @@ exports.rootSourceState = rootSourceState;
|
|
|
61505
61822
|
exports.routerBasename = routerBasename;
|
|
61506
61823
|
exports.sameLocationSuggestions = sameLocationSuggestions;
|
|
61507
61824
|
exports.scrubReducer = scrubReducer;
|
|
61825
|
+
exports.searchSteps = searchSteps;
|
|
61508
61826
|
exports.selectPickerGroup = selectPickerGroup;
|
|
61509
61827
|
exports.selectedDeviceOptions = selectedDeviceOptions;
|
|
61510
61828
|
exports.serializeRecordedCommand = serializeRecordedCommand;
|
|
61829
|
+
exports.settingsModelIdFor = settingsModelIdFor;
|
|
61511
61830
|
exports.shouldCommit = shouldCommit;
|
|
61512
61831
|
exports.shouldEmit = shouldEmit;
|
|
61513
61832
|
exports.shouldShowAddNewFooter = shouldShowAddNewFooter;
|
|
@@ -61519,7 +61838,9 @@ exports.sortRowsByColumn = sortRowsByColumn;
|
|
|
61519
61838
|
exports.statusIcons = statusIcons;
|
|
61520
61839
|
exports.statusLine = statusLine;
|
|
61521
61840
|
exports.statusLine$1 = statusLine;
|
|
61841
|
+
exports.stepFieldDomId = stepFieldDomId;
|
|
61522
61842
|
exports.stepHasModelForFormat = stepHasModelForFormat;
|
|
61843
|
+
exports.stepLocalFields = stepLocalFields;
|
|
61523
61844
|
exports.stepModelOptions = stepModelOptions;
|
|
61524
61845
|
exports.stripParentNamePrefix = stripParentNamePrefix;
|
|
61525
61846
|
exports.summarizeHubCandidates = summarizeHubCandidates;
|
|
@@ -62349,6 +62670,7 @@ exports.usePipelineOrchestratorSetAgentReachableHost = usePipelineOrchestratorSe
|
|
|
62349
62670
|
exports.usePipelineOrchestratorSetCameraPipelineForAgent = usePipelineOrchestratorSetCameraPipelineForAgent;
|
|
62350
62671
|
exports.usePipelineOrchestratorSetCameraSensors = usePipelineOrchestratorSetCameraSensors;
|
|
62351
62672
|
exports.usePipelineOrchestratorSetCameraStepOverride = usePipelineOrchestratorSetCameraStepOverride;
|
|
62673
|
+
exports.usePipelineOrchestratorSetCameraStepSettings = usePipelineOrchestratorSetCameraStepSettings;
|
|
62352
62674
|
exports.usePipelineOrchestratorSetCameraStepToggle = usePipelineOrchestratorSetCameraStepToggle;
|
|
62353
62675
|
exports.usePipelineOrchestratorSetCameraSwitch = usePipelineOrchestratorSetCameraSwitch;
|
|
62354
62676
|
exports.usePipelineOrchestratorSetCapabilityBinding = usePipelineOrchestratorSetCapabilityBinding;
|
|
@@ -62734,4 +63056,5 @@ exports.waterHeaterTint = waterHeaterTint;
|
|
|
62734
63056
|
exports.weatherConditionMeta = weatherConditionMeta;
|
|
62735
63057
|
exports.weatherTint = weatherTint;
|
|
62736
63058
|
exports.withResolvedParentDetail = withResolvedParentDetail;
|
|
63059
|
+
exports.withUseRootModel = withUseRootModel;
|
|
62737
63060
|
exports.writeStoredGroupBy = writeStoredGroupBy;
|