@camstack/ui-library 1.1.45 → 1.1.76
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/device-item/status-dot.d.ts +2 -1
- package/dist/composites/device-step-matrix.d.ts +13 -9
- package/dist/composites/index.d.ts +4 -1
- package/dist/composites/model-picker.d.ts +25 -0
- package/dist/composites/pipeline-matrix-shared.d.ts +64 -0
- package/dist/composites/pipeline-tree-matrix.d.ts +5 -8
- package/dist/generated/system-hooks.d.ts +6 -4
- package/dist/index.cjs +409 -286
- package/dist/index.js +404 -285
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -3775,7 +3775,6 @@ function mirror(input) {
|
|
|
3775
3775
|
}
|
|
3776
3776
|
}
|
|
3777
3777
|
const patch = {
|
|
3778
|
-
enabled: srcCfg.enabled,
|
|
3779
3778
|
...chosenModelId ? { modelId: chosenModelId } : {},
|
|
3780
3779
|
settings: dropModelSpecific(srcCfg.settings, targetAddon)
|
|
3781
3780
|
};
|
|
@@ -13874,6 +13873,228 @@ function buildStepTreeFromSchema(schema) {
|
|
|
13874
13873
|
return [...roots, ...audioRoots];
|
|
13875
13874
|
}
|
|
13876
13875
|
//#endregion
|
|
13876
|
+
//#region src/composites/grouped-model-selector.tsx
|
|
13877
|
+
/**
|
|
13878
|
+
* GroupedModelSelector — the shared Family → Tier → Variant model picker.
|
|
13879
|
+
*
|
|
13880
|
+
* The catalog is a FLAT list of models (ids like `yolo26s`, `yolo26s-int8`);
|
|
13881
|
+
* this folds it into a `family → tier → variant` tree (see
|
|
13882
|
+
* `buildModelVariantGroups` in `@camstack/types`) so the operator picks
|
|
13883
|
+
* "YOLO26 → Small → Int8" instead of scanning a flat dropdown of every
|
|
13884
|
+
* size×quantization. The selected value stays the flat model id.
|
|
13885
|
+
*
|
|
13886
|
+
* Parameterised on the minimal `ModelVariantSource` shape so BOTH the config-UI
|
|
13887
|
+
* catalog (`ModelCatalogEntry`) and the pipeline/device steppers
|
|
13888
|
+
* (`PipelineModelOption`) drive the same component. Legacy / ungrouped models
|
|
13889
|
+
* never appear here (the grouping helpers skip them).
|
|
13890
|
+
*/
|
|
13891
|
+
function Chip({ active, onClick, disabled, children, title }) {
|
|
13892
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
13893
|
+
type: "button",
|
|
13894
|
+
onClick,
|
|
13895
|
+
disabled,
|
|
13896
|
+
title,
|
|
13897
|
+
className: cn("rounded-full px-3 py-1 text-[11px] font-medium border transition-colors", active ? "border-primary bg-primary/10 text-primary" : "border-border bg-background text-foreground-subtle hover:text-foreground hover:border-foreground-subtle/40", disabled ? "opacity-50 cursor-not-allowed" : "cursor-pointer"),
|
|
13898
|
+
children
|
|
13899
|
+
});
|
|
13900
|
+
}
|
|
13901
|
+
function GroupedModelSelector({ catalog, value, onChange, disabled }) {
|
|
13902
|
+
const families = (0, _camstack_types.buildModelVariantGroups)(catalog);
|
|
13903
|
+
const current = (0, _camstack_types.describeModelVariant)(catalog, value);
|
|
13904
|
+
const activeFamily = families.find((f) => f.family === current?.family)?.family ?? families[0]?.family ?? "";
|
|
13905
|
+
const family = families.find((f) => f.family === activeFamily) ?? families[0];
|
|
13906
|
+
if (!family) return null;
|
|
13907
|
+
const activeTier = family.tiers.find((t) => t.tier === current?.tier)?.tier ?? family.tiers[0]?.tier ?? "";
|
|
13908
|
+
const tier = family.tiers.find((t) => t.tier === activeTier) ?? family.tiers[0];
|
|
13909
|
+
if (!tier) return null;
|
|
13910
|
+
const resolutions = [...new Set(tier.options.map((o) => o.resolution))].sort((a, b) => (b ?? Infinity) - (a ?? Infinity));
|
|
13911
|
+
const selectedResolution = resolutions.includes(current?.resolution) ? current?.resolution : resolutions[0];
|
|
13912
|
+
const variantOptions = tier.options.filter((o) => o.resolution === selectedResolution);
|
|
13913
|
+
const resLabel = (r) => r === void 0 ? "640 · native" : `${r}`;
|
|
13914
|
+
const selectTier = (tierId) => {
|
|
13915
|
+
const t = family.tiers.find((x) => x.tier === tierId);
|
|
13916
|
+
if (!t) return;
|
|
13917
|
+
onChange((t.options.find((o) => o.precision === (current?.precision ?? "fp32") && o.optimization === (current?.optimization ?? "standard") && o.resolution === current?.resolution) ?? t.options[0]).modelId);
|
|
13918
|
+
};
|
|
13919
|
+
const selectResolution = (resolution) => {
|
|
13920
|
+
const opts = tier.options.filter((o) => o.resolution === resolution);
|
|
13921
|
+
const pick = opts.find((o) => o.precision === (current?.precision ?? "fp32") && o.optimization === (current?.optimization ?? "standard")) ?? opts[0];
|
|
13922
|
+
if (pick) onChange(pick.modelId);
|
|
13923
|
+
};
|
|
13924
|
+
const selectVariant = (opt) => {
|
|
13925
|
+
const id = (0, _camstack_types.resolveVariantModelId)(catalog, {
|
|
13926
|
+
family: family.family,
|
|
13927
|
+
tier: tier.tier,
|
|
13928
|
+
precision: opt.precision,
|
|
13929
|
+
optimization: opt.optimization,
|
|
13930
|
+
resolution: opt.resolution
|
|
13931
|
+
});
|
|
13932
|
+
if (id) onChange(id);
|
|
13933
|
+
};
|
|
13934
|
+
const selectedOption = tier.options.find((o) => o.modelId === value) ?? null;
|
|
13935
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
13936
|
+
className: "space-y-3",
|
|
13937
|
+
children: [
|
|
13938
|
+
families.length > 1 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
13939
|
+
className: "text-[10px] uppercase tracking-wide text-foreground-subtle mb-1.5",
|
|
13940
|
+
children: "Family"
|
|
13941
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
13942
|
+
className: "flex flex-wrap gap-1.5",
|
|
13943
|
+
children: families.map((f) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Chip, {
|
|
13944
|
+
active: f.family === family.family,
|
|
13945
|
+
disabled,
|
|
13946
|
+
onClick: () => onChange(f.tiers[0]?.baseModelId ?? ""),
|
|
13947
|
+
children: f.label
|
|
13948
|
+
}, f.family))
|
|
13949
|
+
})] }),
|
|
13950
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
|
|
13951
|
+
className: "text-[10px] uppercase tracking-wide text-foreground-subtle mb-1.5",
|
|
13952
|
+
children: [family.label, " — size"]
|
|
13953
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
13954
|
+
className: "grid grid-cols-2 gap-1.5 sm:grid-cols-4",
|
|
13955
|
+
children: family.tiers.map((t) => {
|
|
13956
|
+
const active = t.tier === tier.tier;
|
|
13957
|
+
const base = t.options.find((o) => o.modelId === t.baseModelId) ?? t.options[0];
|
|
13958
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
13959
|
+
type: "button",
|
|
13960
|
+
disabled,
|
|
13961
|
+
onClick: () => selectTier(t.tier),
|
|
13962
|
+
className: cn("rounded-lg border px-2 py-2 text-left transition-all", active ? "border-primary bg-primary/5 ring-1 ring-primary/30" : "border-border bg-background hover:border-foreground-subtle/40", disabled ? "opacity-50 cursor-not-allowed" : "cursor-pointer"),
|
|
13963
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
13964
|
+
className: "flex items-center gap-1",
|
|
13965
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
13966
|
+
className: "text-xs font-semibold text-foreground",
|
|
13967
|
+
children: t.label
|
|
13968
|
+
}), active && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Check, { className: "h-3 w-3 text-primary" })]
|
|
13969
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
13970
|
+
className: "text-[10px] text-foreground-subtle",
|
|
13971
|
+
children: [
|
|
13972
|
+
"~",
|
|
13973
|
+
base?.sizeMB ?? 0,
|
|
13974
|
+
" MB"
|
|
13975
|
+
]
|
|
13976
|
+
})]
|
|
13977
|
+
}, t.tier);
|
|
13978
|
+
})
|
|
13979
|
+
})] }),
|
|
13980
|
+
resolutions.length > 1 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
13981
|
+
className: "text-[10px] uppercase tracking-wide text-foreground-subtle mb-1.5",
|
|
13982
|
+
children: "Resolution"
|
|
13983
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
13984
|
+
className: "flex flex-wrap gap-1.5",
|
|
13985
|
+
children: resolutions.map((r) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Chip, {
|
|
13986
|
+
active: r === selectedResolution,
|
|
13987
|
+
disabled,
|
|
13988
|
+
title: r === void 0 ? "native (best accuracy)" : `${r}×${r} (faster)`,
|
|
13989
|
+
onClick: () => selectResolution(r),
|
|
13990
|
+
children: resLabel(r)
|
|
13991
|
+
}, r ?? "native"))
|
|
13992
|
+
})] }),
|
|
13993
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
13994
|
+
className: "text-[10px] uppercase tracking-wide text-foreground-subtle mb-1.5",
|
|
13995
|
+
children: "Variant"
|
|
13996
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
13997
|
+
className: "flex flex-wrap gap-1.5",
|
|
13998
|
+
children: variantOptions.map((opt) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Chip, {
|
|
13999
|
+
active: opt.modelId === value,
|
|
14000
|
+
disabled,
|
|
14001
|
+
title: `${opt.formats.join(", ")} · ~${opt.sizeMB} MB`,
|
|
14002
|
+
onClick: () => selectVariant(opt),
|
|
14003
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
14004
|
+
className: "inline-flex items-center gap-1",
|
|
14005
|
+
children: [opt.optimization === "fast" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Zap, { className: "h-3 w-3" }), opt.label]
|
|
14006
|
+
})
|
|
14007
|
+
}, opt.modelId))
|
|
14008
|
+
})] }),
|
|
14009
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
14010
|
+
className: "flex items-center gap-2 text-[10px] text-foreground-subtle pt-0.5",
|
|
14011
|
+
children: [
|
|
14012
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Cpu, { className: "h-3 w-3" }),
|
|
14013
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
14014
|
+
className: "font-mono",
|
|
14015
|
+
children: value || "—"
|
|
14016
|
+
}),
|
|
14017
|
+
selectedOption && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
|
|
14018
|
+
"· ",
|
|
14019
|
+
selectedOption.formats.join(", "),
|
|
14020
|
+
" · ~",
|
|
14021
|
+
selectedOption.sizeMB,
|
|
14022
|
+
" MB"
|
|
14023
|
+
] })
|
|
14024
|
+
]
|
|
14025
|
+
})
|
|
14026
|
+
]
|
|
14027
|
+
});
|
|
14028
|
+
}
|
|
14029
|
+
//#endregion
|
|
14030
|
+
//#region src/composites/model-picker.tsx
|
|
14031
|
+
/**
|
|
14032
|
+
* Shared model picker — the ONE model-selection control across the app.
|
|
14033
|
+
*
|
|
14034
|
+
* Renders the grouped Family→Tier→Resolution→Variant selector
|
|
14035
|
+
* ({@link GroupedModelSelector}) when the step's models declare variant groups
|
|
14036
|
+
* (yolo26 / yolov9 …), else a flat `<select>` (face / plate / classifier
|
|
14037
|
+
* catalogs and operator-registered custom models). Custom / ungrouped ids stay
|
|
14038
|
+
* selectable via an "Other models" flat select alongside the grouped picker, and
|
|
14039
|
+
* a legacy/removed pin is surfaced with an explicit banner rather than a
|
|
14040
|
+
* silently mis-highlighted chip.
|
|
14041
|
+
*
|
|
14042
|
+
* Used by the pipeline stepper (`PipelineStep`), the agent/device step editor
|
|
14043
|
+
* (`AgentStepEditor`), and the benchmark — so the picker looks identical
|
|
14044
|
+
* everywhere. `value === ''` renders nothing selected (callers that support an
|
|
14045
|
+
* "Auto / node default" mode own that affordance and hide this picker while it
|
|
14046
|
+
* is active).
|
|
14047
|
+
*/
|
|
14048
|
+
function ModelPicker({ models, value, onChange, disabled }) {
|
|
14049
|
+
const hasGroups = (0, react$1.useMemo)(() => (0, _camstack_types.buildModelVariantGroups)(models).length > 0, [models]);
|
|
14050
|
+
const ungrouped = (0, react$1.useMemo)(() => models.filter((m) => m.group === void 0), [models]);
|
|
14051
|
+
const unresolvedBanner = value !== "" && !models.some((m) => m.id === value) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
14052
|
+
className: "rounded border border-amber-500/40 bg-amber-500/10 px-2 py-1.5 text-[10px] text-amber-300",
|
|
14053
|
+
children: [
|
|
14054
|
+
"Current pin (",
|
|
14055
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
14056
|
+
className: "font-mono",
|
|
14057
|
+
children: value
|
|
14058
|
+
}),
|
|
14059
|
+
") is a legacy/removed model — no longer offered below. Pick a replacement to change it; Save persists whatever is selected here."
|
|
14060
|
+
]
|
|
14061
|
+
});
|
|
14062
|
+
const flatSelect = (opts, selectPlaceholder) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
|
|
14063
|
+
disabled,
|
|
14064
|
+
className: "w-full bg-surface border border-border rounded px-2 py-1 text-xs disabled:opacity-50",
|
|
14065
|
+
value: opts.some((m) => m.id === value) ? value : "",
|
|
14066
|
+
onChange: (e) => onChange(e.target.value),
|
|
14067
|
+
children: [selectPlaceholder !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
14068
|
+
value: "",
|
|
14069
|
+
disabled: true,
|
|
14070
|
+
children: selectPlaceholder
|
|
14071
|
+
}), opts.map((m) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
14072
|
+
value: m.id,
|
|
14073
|
+
children: m.name
|
|
14074
|
+
}, m.id))]
|
|
14075
|
+
});
|
|
14076
|
+
if (!hasGroups) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
14077
|
+
className: "space-y-2",
|
|
14078
|
+
children: [unresolvedBanner, flatSelect(models)]
|
|
14079
|
+
});
|
|
14080
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
14081
|
+
className: "space-y-3",
|
|
14082
|
+
children: [
|
|
14083
|
+
unresolvedBanner,
|
|
14084
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(GroupedModelSelector, {
|
|
14085
|
+
catalog: models,
|
|
14086
|
+
value,
|
|
14087
|
+
onChange,
|
|
14088
|
+
disabled
|
|
14089
|
+
}),
|
|
14090
|
+
ungrouped.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
14091
|
+
className: "text-[10px] uppercase tracking-widest text-foreground-subtle mb-1",
|
|
14092
|
+
children: "Other models"
|
|
14093
|
+
}), flatSelect(ungrouped, "— custom / ungrouped model —")] })
|
|
14094
|
+
]
|
|
14095
|
+
});
|
|
14096
|
+
}
|
|
14097
|
+
//#endregion
|
|
13877
14098
|
//#region src/composites/pipeline-step.tsx
|
|
13878
14099
|
/**
|
|
13879
14100
|
* PipelineStep — single step card in the pipeline builder.
|
|
@@ -13883,11 +14104,7 @@ function buildStepTreeFromSchema(schema) {
|
|
|
13883
14104
|
* (Model → Confidence), children recursively.
|
|
13884
14105
|
*/
|
|
13885
14106
|
function modelsForStep(schema) {
|
|
13886
|
-
|
|
13887
|
-
return schema.models.map((m) => ({
|
|
13888
|
-
id: m.id,
|
|
13889
|
-
name: m.name
|
|
13890
|
-
}));
|
|
14107
|
+
return schema?.models ?? [];
|
|
13891
14108
|
}
|
|
13892
14109
|
function PipelineStep({ step, schema, allSchemas: _allSchemas, depth: _depth = 0, onChange, onDelete: _onDelete, readOnly = false, toggleMode = "simple", overrideState = null, onOverrideChange, inheritedEnabled, hideModelAndSettings = false, allowAutoModel = false }) {
|
|
13893
14110
|
const [expanded, setExpanded] = (0, react$1.useState)(false);
|
|
@@ -13978,21 +14195,35 @@ function PipelineStep({ step, schema, allSchemas: _allSchemas, depth: _depth = 0
|
|
|
13978
14195
|
children: "Model and detection settings are managed per agent — open the Pipeline page for this camera's agent to edit them."
|
|
13979
14196
|
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
13980
14197
|
className: "space-y-3",
|
|
13981
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.
|
|
13982
|
-
|
|
13983
|
-
|
|
13984
|
-
|
|
13985
|
-
|
|
13986
|
-
|
|
13987
|
-
|
|
13988
|
-
|
|
13989
|
-
|
|
13990
|
-
|
|
13991
|
-
|
|
13992
|
-
|
|
13993
|
-
|
|
13994
|
-
|
|
13995
|
-
|
|
14198
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
14199
|
+
className: "space-y-2",
|
|
14200
|
+
children: [
|
|
14201
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
|
|
14202
|
+
className: "block text-[10px] font-medium text-foreground-subtle uppercase tracking-wide",
|
|
14203
|
+
children: "Model"
|
|
14204
|
+
}),
|
|
14205
|
+
allowAutoModel && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
14206
|
+
className: "flex items-center gap-2 text-[11px] text-foreground-subtle",
|
|
14207
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
14208
|
+
type: "checkbox",
|
|
14209
|
+
checked: isAutoSentinel,
|
|
14210
|
+
disabled: readOnly,
|
|
14211
|
+
onChange: (e) => onChange({
|
|
14212
|
+
...step,
|
|
14213
|
+
modelId: e.target.checked ? "" : schema?.defaultModelId ?? models[0]?.id ?? ""
|
|
14214
|
+
})
|
|
14215
|
+
}), "Auto (node default)"]
|
|
14216
|
+
}),
|
|
14217
|
+
!isAutoSentinel && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ModelPicker, {
|
|
14218
|
+
models,
|
|
14219
|
+
value: step.modelId,
|
|
14220
|
+
disabled: readOnly,
|
|
14221
|
+
onChange: (id) => onChange({
|
|
14222
|
+
...step,
|
|
14223
|
+
modelId: id
|
|
14224
|
+
})
|
|
14225
|
+
})
|
|
14226
|
+
]
|
|
13996
14227
|
}), schema?.configSchema?.map((field) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ConfigSchemaField, {
|
|
13997
14228
|
field,
|
|
13998
14229
|
allFields: schema.configSchema ?? [],
|
|
@@ -14198,218 +14429,7 @@ function ThreeStateButton({ label, active, variant, subtext, onClick }) {
|
|
|
14198
14429
|
});
|
|
14199
14430
|
}
|
|
14200
14431
|
//#endregion
|
|
14201
|
-
//#region src/composites/grouped-model-selector.tsx
|
|
14202
|
-
/**
|
|
14203
|
-
* GroupedModelSelector — the shared Family → Tier → Variant model picker.
|
|
14204
|
-
*
|
|
14205
|
-
* The catalog is a FLAT list of models (ids like `yolo26s`, `yolo26s-int8`);
|
|
14206
|
-
* this folds it into a `family → tier → variant` tree (see
|
|
14207
|
-
* `buildModelVariantGroups` in `@camstack/types`) so the operator picks
|
|
14208
|
-
* "YOLO26 → Small → Int8" instead of scanning a flat dropdown of every
|
|
14209
|
-
* size×quantization. The selected value stays the flat model id.
|
|
14210
|
-
*
|
|
14211
|
-
* Parameterised on the minimal `ModelVariantSource` shape so BOTH the config-UI
|
|
14212
|
-
* catalog (`ModelCatalogEntry`) and the pipeline/device steppers
|
|
14213
|
-
* (`PipelineModelOption`) drive the same component. Legacy / ungrouped models
|
|
14214
|
-
* never appear here (the grouping helpers skip them).
|
|
14215
|
-
*/
|
|
14216
|
-
function Chip({ active, onClick, disabled, children, title }) {
|
|
14217
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
14218
|
-
type: "button",
|
|
14219
|
-
onClick,
|
|
14220
|
-
disabled,
|
|
14221
|
-
title,
|
|
14222
|
-
className: cn("rounded-full px-3 py-1 text-[11px] font-medium border transition-colors", active ? "border-primary bg-primary/10 text-primary" : "border-border bg-background text-foreground-subtle hover:text-foreground hover:border-foreground-subtle/40", disabled ? "opacity-50 cursor-not-allowed" : "cursor-pointer"),
|
|
14223
|
-
children
|
|
14224
|
-
});
|
|
14225
|
-
}
|
|
14226
|
-
function GroupedModelSelector({ catalog, value, onChange, disabled }) {
|
|
14227
|
-
const families = (0, _camstack_types.buildModelVariantGroups)(catalog);
|
|
14228
|
-
const current = (0, _camstack_types.describeModelVariant)(catalog, value);
|
|
14229
|
-
const activeFamily = families.find((f) => f.family === current?.family)?.family ?? families[0]?.family ?? "";
|
|
14230
|
-
const family = families.find((f) => f.family === activeFamily) ?? families[0];
|
|
14231
|
-
if (!family) return null;
|
|
14232
|
-
const activeTier = family.tiers.find((t) => t.tier === current?.tier)?.tier ?? family.tiers[0]?.tier ?? "";
|
|
14233
|
-
const tier = family.tiers.find((t) => t.tier === activeTier) ?? family.tiers[0];
|
|
14234
|
-
if (!tier) return null;
|
|
14235
|
-
const resolutions = [...new Set(tier.options.map((o) => o.resolution))].sort((a, b) => (b ?? Infinity) - (a ?? Infinity));
|
|
14236
|
-
const selectedResolution = resolutions.includes(current?.resolution) ? current?.resolution : resolutions[0];
|
|
14237
|
-
const variantOptions = tier.options.filter((o) => o.resolution === selectedResolution);
|
|
14238
|
-
const resLabel = (r) => r === void 0 ? "640 · native" : `${r}`;
|
|
14239
|
-
const selectTier = (tierId) => {
|
|
14240
|
-
const t = family.tiers.find((x) => x.tier === tierId);
|
|
14241
|
-
if (!t) return;
|
|
14242
|
-
onChange((t.options.find((o) => o.precision === (current?.precision ?? "fp32") && o.optimization === (current?.optimization ?? "standard") && o.resolution === current?.resolution) ?? t.options[0]).modelId);
|
|
14243
|
-
};
|
|
14244
|
-
const selectResolution = (resolution) => {
|
|
14245
|
-
const opts = tier.options.filter((o) => o.resolution === resolution);
|
|
14246
|
-
const pick = opts.find((o) => o.precision === (current?.precision ?? "fp32") && o.optimization === (current?.optimization ?? "standard")) ?? opts[0];
|
|
14247
|
-
if (pick) onChange(pick.modelId);
|
|
14248
|
-
};
|
|
14249
|
-
const selectVariant = (opt) => {
|
|
14250
|
-
const id = (0, _camstack_types.resolveVariantModelId)(catalog, {
|
|
14251
|
-
family: family.family,
|
|
14252
|
-
tier: tier.tier,
|
|
14253
|
-
precision: opt.precision,
|
|
14254
|
-
optimization: opt.optimization,
|
|
14255
|
-
resolution: opt.resolution
|
|
14256
|
-
});
|
|
14257
|
-
if (id) onChange(id);
|
|
14258
|
-
};
|
|
14259
|
-
const selectedOption = tier.options.find((o) => o.modelId === value) ?? null;
|
|
14260
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
14261
|
-
className: "space-y-3",
|
|
14262
|
-
children: [
|
|
14263
|
-
families.length > 1 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
14264
|
-
className: "text-[10px] uppercase tracking-wide text-foreground-subtle mb-1.5",
|
|
14265
|
-
children: "Family"
|
|
14266
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
14267
|
-
className: "flex flex-wrap gap-1.5",
|
|
14268
|
-
children: families.map((f) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Chip, {
|
|
14269
|
-
active: f.family === family.family,
|
|
14270
|
-
disabled,
|
|
14271
|
-
onClick: () => onChange(f.tiers[0]?.baseModelId ?? ""),
|
|
14272
|
-
children: f.label
|
|
14273
|
-
}, f.family))
|
|
14274
|
-
})] }),
|
|
14275
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
|
|
14276
|
-
className: "text-[10px] uppercase tracking-wide text-foreground-subtle mb-1.5",
|
|
14277
|
-
children: [family.label, " — size"]
|
|
14278
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
14279
|
-
className: "grid grid-cols-2 gap-1.5 sm:grid-cols-4",
|
|
14280
|
-
children: family.tiers.map((t) => {
|
|
14281
|
-
const active = t.tier === tier.tier;
|
|
14282
|
-
const base = t.options.find((o) => o.modelId === t.baseModelId) ?? t.options[0];
|
|
14283
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
14284
|
-
type: "button",
|
|
14285
|
-
disabled,
|
|
14286
|
-
onClick: () => selectTier(t.tier),
|
|
14287
|
-
className: cn("rounded-lg border px-2 py-2 text-left transition-all", active ? "border-primary bg-primary/5 ring-1 ring-primary/30" : "border-border bg-background hover:border-foreground-subtle/40", disabled ? "opacity-50 cursor-not-allowed" : "cursor-pointer"),
|
|
14288
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
14289
|
-
className: "flex items-center gap-1",
|
|
14290
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
14291
|
-
className: "text-xs font-semibold text-foreground",
|
|
14292
|
-
children: t.label
|
|
14293
|
-
}), active && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Check, { className: "h-3 w-3 text-primary" })]
|
|
14294
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
14295
|
-
className: "text-[10px] text-foreground-subtle",
|
|
14296
|
-
children: [
|
|
14297
|
-
"~",
|
|
14298
|
-
base?.sizeMB ?? 0,
|
|
14299
|
-
" MB"
|
|
14300
|
-
]
|
|
14301
|
-
})]
|
|
14302
|
-
}, t.tier);
|
|
14303
|
-
})
|
|
14304
|
-
})] }),
|
|
14305
|
-
resolutions.length > 1 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
14306
|
-
className: "text-[10px] uppercase tracking-wide text-foreground-subtle mb-1.5",
|
|
14307
|
-
children: "Resolution"
|
|
14308
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
14309
|
-
className: "flex flex-wrap gap-1.5",
|
|
14310
|
-
children: resolutions.map((r) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Chip, {
|
|
14311
|
-
active: r === selectedResolution,
|
|
14312
|
-
disabled,
|
|
14313
|
-
title: r === void 0 ? "native (best accuracy)" : `${r}×${r} (faster)`,
|
|
14314
|
-
onClick: () => selectResolution(r),
|
|
14315
|
-
children: resLabel(r)
|
|
14316
|
-
}, r ?? "native"))
|
|
14317
|
-
})] }),
|
|
14318
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
14319
|
-
className: "text-[10px] uppercase tracking-wide text-foreground-subtle mb-1.5",
|
|
14320
|
-
children: "Variant"
|
|
14321
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
14322
|
-
className: "flex flex-wrap gap-1.5",
|
|
14323
|
-
children: variantOptions.map((opt) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Chip, {
|
|
14324
|
-
active: opt.modelId === value,
|
|
14325
|
-
disabled,
|
|
14326
|
-
title: `${opt.formats.join(", ")} · ~${opt.sizeMB} MB`,
|
|
14327
|
-
onClick: () => selectVariant(opt),
|
|
14328
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
14329
|
-
className: "inline-flex items-center gap-1",
|
|
14330
|
-
children: [opt.optimization === "fast" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Zap, { className: "h-3 w-3" }), opt.label]
|
|
14331
|
-
})
|
|
14332
|
-
}, opt.modelId))
|
|
14333
|
-
})] }),
|
|
14334
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
14335
|
-
className: "flex items-center gap-2 text-[10px] text-foreground-subtle pt-0.5",
|
|
14336
|
-
children: [
|
|
14337
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Cpu, { className: "h-3 w-3" }),
|
|
14338
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
14339
|
-
className: "font-mono",
|
|
14340
|
-
children: value || "—"
|
|
14341
|
-
}),
|
|
14342
|
-
selectedOption && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
|
|
14343
|
-
"· ",
|
|
14344
|
-
selectedOption.formats.join(", "),
|
|
14345
|
-
" · ~",
|
|
14346
|
-
selectedOption.sizeMB,
|
|
14347
|
-
" MB"
|
|
14348
|
-
] })
|
|
14349
|
-
]
|
|
14350
|
-
})
|
|
14351
|
-
]
|
|
14352
|
-
});
|
|
14353
|
-
}
|
|
14354
|
-
//#endregion
|
|
14355
14432
|
//#region src/composites/agent-step-editor.tsx
|
|
14356
|
-
/**
|
|
14357
|
-
* Shared model picker for the step editor — renders the grouped
|
|
14358
|
-
* Family→Tier→Variant selector when the step's models declare variant groups
|
|
14359
|
-
* (yolo26 …), else a flat `<select>` (face / plate / classifier catalogs and
|
|
14360
|
-
* custom models). Same component both the agent-default and per-device-override
|
|
14361
|
-
* modes use, so the picker looks identical across the pipeline stepper, the
|
|
14362
|
-
* device stepper and the cluster matrix.
|
|
14363
|
-
*/
|
|
14364
|
-
function ModelPicker({ models, value, onChange, disabled }) {
|
|
14365
|
-
const hasGroups = (0, react$1.useMemo)(() => (0, _camstack_types.buildModelVariantGroups)(models).length > 0, [models]);
|
|
14366
|
-
const ungrouped = (0, react$1.useMemo)(() => models.filter((m) => m.group === void 0), [models]);
|
|
14367
|
-
const unresolvedBanner = value !== "" && !models.some((m) => m.id === value) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
14368
|
-
className: "rounded border border-amber-500/40 bg-amber-500/10 px-2 py-1.5 text-[10px] text-amber-300",
|
|
14369
|
-
children: [
|
|
14370
|
-
"Current pin (",
|
|
14371
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
14372
|
-
className: "font-mono",
|
|
14373
|
-
children: value
|
|
14374
|
-
}),
|
|
14375
|
-
") is a legacy/removed model — no longer offered below. Pick a replacement to change it; Save persists whatever is selected here."
|
|
14376
|
-
]
|
|
14377
|
-
});
|
|
14378
|
-
const flatSelect = (opts, selectPlaceholder) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
|
|
14379
|
-
disabled,
|
|
14380
|
-
className: "w-full bg-surface border border-border rounded px-2 py-1 text-xs disabled:opacity-50",
|
|
14381
|
-
value: opts.some((m) => m.id === value) ? value : "",
|
|
14382
|
-
onChange: (e) => onChange(e.target.value),
|
|
14383
|
-
children: [selectPlaceholder !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
14384
|
-
value: "",
|
|
14385
|
-
disabled: true,
|
|
14386
|
-
children: selectPlaceholder
|
|
14387
|
-
}), opts.map((m) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
14388
|
-
value: m.id,
|
|
14389
|
-
children: m.name
|
|
14390
|
-
}, m.id))]
|
|
14391
|
-
});
|
|
14392
|
-
if (!hasGroups) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
14393
|
-
className: "space-y-2",
|
|
14394
|
-
children: [unresolvedBanner, flatSelect(models)]
|
|
14395
|
-
});
|
|
14396
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
14397
|
-
className: "space-y-3",
|
|
14398
|
-
children: [
|
|
14399
|
-
unresolvedBanner,
|
|
14400
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(GroupedModelSelector, {
|
|
14401
|
-
catalog: models,
|
|
14402
|
-
value,
|
|
14403
|
-
onChange,
|
|
14404
|
-
disabled
|
|
14405
|
-
}),
|
|
14406
|
-
ungrouped.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
14407
|
-
className: "text-[10px] uppercase tracking-widest text-foreground-subtle mb-1",
|
|
14408
|
-
children: "Other models"
|
|
14409
|
-
}), flatSelect(ungrouped, "— custom / ungrouped model —")] })
|
|
14410
|
-
]
|
|
14411
|
-
});
|
|
14412
|
-
}
|
|
14413
14433
|
function buildDisplayStep(addon, cfg) {
|
|
14414
14434
|
return {
|
|
14415
14435
|
addonId: addon.id,
|
|
@@ -14469,14 +14489,14 @@ function DeviceModeEditor({ addon, agentDefault, agentNodeId, currentPatch, mode
|
|
|
14469
14489
|
onChangePatch?.(hasAnyField ? next : null);
|
|
14470
14490
|
};
|
|
14471
14491
|
const setModel = (modelId) => {
|
|
14472
|
-
const {
|
|
14492
|
+
const { modelId: _prev, ...rest } = currentPatch ?? {};
|
|
14473
14493
|
commitPatch(modelId === void 0 ? rest : {
|
|
14474
14494
|
...rest,
|
|
14475
14495
|
modelId
|
|
14476
14496
|
});
|
|
14477
14497
|
};
|
|
14478
14498
|
const setSettings = (settings) => {
|
|
14479
|
-
const {
|
|
14499
|
+
const { settings: _prev, ...rest } = currentPatch ?? {};
|
|
14480
14500
|
commitPatch(settings === void 0 ? rest : {
|
|
14481
14501
|
...rest,
|
|
14482
14502
|
settings
|
|
@@ -14597,6 +14617,42 @@ function AgentStepEditor(props) {
|
|
|
14597
14617
|
onChangePatch
|
|
14598
14618
|
});
|
|
14599
14619
|
}
|
|
14620
|
+
//#endregion
|
|
14621
|
+
//#region src/composites/pipeline-matrix-shared.tsx
|
|
14622
|
+
/**
|
|
14623
|
+
* Stable column identity. Plain per-node columns key by `agentNodeId` (so the
|
|
14624
|
+
* rendered `key` is byte-identical to the pre-C7.4 matrix); device sub-columns
|
|
14625
|
+
* disambiguate with their `deviceKey`. MUST be used everywhere a React `key`,
|
|
14626
|
+
* selection compare, or column identity is derived.
|
|
14627
|
+
*/
|
|
14628
|
+
function agentColumnKey(a) {
|
|
14629
|
+
return a.deviceKey !== void 0 ? `${a.agentNodeId}::${a.deviceKey}` : a.agentNodeId;
|
|
14630
|
+
}
|
|
14631
|
+
/**
|
|
14632
|
+
* Coalesce CONSECUTIVE columns that share an `agentNodeId` into node groups.
|
|
14633
|
+
* Order-preserving: the flat column order is untouched, so body cells still map
|
|
14634
|
+
* 1:1 to `agents`. A run of length 1 is a plain (ungrouped) node header.
|
|
14635
|
+
*/
|
|
14636
|
+
function groupAgentColumns(agents) {
|
|
14637
|
+
const groups = [];
|
|
14638
|
+
for (const col of agents) {
|
|
14639
|
+
const last = groups[groups.length - 1];
|
|
14640
|
+
if (last && last.agentNodeId === col.agentNodeId) {
|
|
14641
|
+
const columns = [...last.columns, col];
|
|
14642
|
+
groups[groups.length - 1] = {
|
|
14643
|
+
...last,
|
|
14644
|
+
columns,
|
|
14645
|
+
grouped: columns.length > 1
|
|
14646
|
+
};
|
|
14647
|
+
} else groups.push({
|
|
14648
|
+
agentNodeId: col.agentNodeId,
|
|
14649
|
+
engineLabel: col.engineLabel,
|
|
14650
|
+
columns: [col],
|
|
14651
|
+
grouped: false
|
|
14652
|
+
});
|
|
14653
|
+
}
|
|
14654
|
+
return groups;
|
|
14655
|
+
}
|
|
14600
14656
|
function flattenTree(nodes) {
|
|
14601
14657
|
const out = [];
|
|
14602
14658
|
const walk = (list, depth) => {
|
|
@@ -14675,6 +14731,41 @@ function ClassChips({ inputs, outputs }) {
|
|
|
14675
14731
|
]
|
|
14676
14732
|
});
|
|
14677
14733
|
}
|
|
14734
|
+
/**
|
|
14735
|
+
* Grouped node header (C7.4): a node super-label spanning its device
|
|
14736
|
+
* sub-columns, with a per-device sub-label row beneath. Rendered ONLY for a
|
|
14737
|
+
* node expanded into 2+ device sub-columns; a single plain column keeps each
|
|
14738
|
+
* matrix's own byte-identical single-header markup. The spanning cell uses
|
|
14739
|
+
* `gridColumn: span N` so it aligns to its N body columns; the inner flex row
|
|
14740
|
+
* gives each device its own equal-width, padded sub-label slot.
|
|
14741
|
+
*/
|
|
14742
|
+
function GroupedAgentHeader({ group }) {
|
|
14743
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
14744
|
+
className: "sticky top-0 z-10 min-w-0 border-b border-l border-border bg-muted/60",
|
|
14745
|
+
style: { gridColumn: `span ${group.columns.length}` },
|
|
14746
|
+
children: [
|
|
14747
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
14748
|
+
className: "truncate px-3 pt-2 text-xs font-semibold text-foreground",
|
|
14749
|
+
children: group.agentNodeId
|
|
14750
|
+
}),
|
|
14751
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
14752
|
+
className: "truncate px-3 text-[10px] text-foreground-subtle",
|
|
14753
|
+
children: group.engineLabel
|
|
14754
|
+
}),
|
|
14755
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
14756
|
+
className: "mt-1 flex border-t border-border/50",
|
|
14757
|
+
children: group.columns.map((c, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
14758
|
+
className: cn("min-w-0 flex-1 px-3 py-1", i > 0 && "border-l border-border/50"),
|
|
14759
|
+
title: c.deviceLabel ?? c.deviceKey,
|
|
14760
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
14761
|
+
className: "truncate text-[10px] font-medium text-foreground/90",
|
|
14762
|
+
children: c.deviceLabel ?? c.deviceKey
|
|
14763
|
+
})
|
|
14764
|
+
}, agentColumnKey(c)))
|
|
14765
|
+
})
|
|
14766
|
+
]
|
|
14767
|
+
});
|
|
14768
|
+
}
|
|
14678
14769
|
/** Step label (slot heading + addon name + class chips), shared by both views. */
|
|
14679
14770
|
function StepLabel({ node }) {
|
|
14680
14771
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -14777,13 +14868,13 @@ function GridRow({ node, depth, agents, getCellState, onCellClick, selectedCell,
|
|
|
14777
14868
|
})
|
|
14778
14869
|
})]
|
|
14779
14870
|
}), agents.map((a) => {
|
|
14780
|
-
const state = getCellState(node.addonId, a
|
|
14871
|
+
const state = getCellState(node.addonId, a);
|
|
14781
14872
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
14782
14873
|
type: "button",
|
|
14783
|
-
onClick: () => onCellClick(node.addonId, a
|
|
14784
|
-
className: cellButtonClass(state, selectedCell
|
|
14874
|
+
onClick: () => onCellClick(node.addonId, a),
|
|
14875
|
+
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"),
|
|
14785
14876
|
children: renderCellContent(state)
|
|
14786
|
-
}, a
|
|
14877
|
+
}, agentColumnKey(a));
|
|
14787
14878
|
})] });
|
|
14788
14879
|
}
|
|
14789
14880
|
/**
|
|
@@ -14795,7 +14886,8 @@ function GridRow({ node, depth, agents, getCellState, onCellClick, selectedCell,
|
|
|
14795
14886
|
function MatrixGrid$1({ rows, agents, getCellState, onCellClick, selectedCell, onToggleEnabled }) {
|
|
14796
14887
|
const gridTemplate = `${STEP_COL_REM$1}rem repeat(${agents.length}, 13rem)`;
|
|
14797
14888
|
const showToggle = onToggleEnabled !== void 0 && agents.length === 1;
|
|
14798
|
-
const onlyAgent = agents[0]
|
|
14889
|
+
const onlyAgent = agents[0];
|
|
14890
|
+
const groups = groupAgentColumns(agents);
|
|
14799
14891
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
14800
14892
|
className: "overflow-auto border border-border rounded",
|
|
14801
14893
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -14806,16 +14898,16 @@ function MatrixGrid$1({ rows, agents, getCellState, onCellClick, selectedCell, o
|
|
|
14806
14898
|
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",
|
|
14807
14899
|
children: "Step"
|
|
14808
14900
|
}),
|
|
14809
|
-
|
|
14901
|
+
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", {
|
|
14810
14902
|
className: "sticky top-0 z-10 min-w-0 bg-muted/60 px-3 py-2 border-b border-l border-border",
|
|
14811
14903
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
14812
14904
|
className: "text-xs font-semibold text-foreground truncate",
|
|
14813
|
-
children:
|
|
14905
|
+
children: col.agentNodeId
|
|
14814
14906
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
14815
14907
|
className: "text-[10px] text-foreground-subtle truncate",
|
|
14816
|
-
children:
|
|
14908
|
+
children: col.engineLabel
|
|
14817
14909
|
})]
|
|
14818
|
-
},
|
|
14910
|
+
}, agentColumnKey(col)))),
|
|
14819
14911
|
rows.map(({ node, depth }) => {
|
|
14820
14912
|
const cellState = showToggle && onlyAgent !== void 0 ? getCellState(node.addonId, onlyAgent) : null;
|
|
14821
14913
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(GridRow, {
|
|
@@ -14851,14 +14943,14 @@ function StackedCards({ rows, agents, getCellState, onCellClick, selectedCell, o
|
|
|
14851
14943
|
className: "bg-muted/60 px-3 py-2 border-b border-border",
|
|
14852
14944
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
14853
14945
|
className: "text-xs font-semibold text-foreground truncate",
|
|
14854
|
-
children: a.agentNodeId
|
|
14946
|
+
children: a.deviceLabel ? `${a.agentNodeId} · ${a.deviceLabel}` : a.agentNodeId
|
|
14855
14947
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
14856
14948
|
className: "text-[10px] text-foreground-subtle truncate",
|
|
14857
14949
|
children: a.engineLabel
|
|
14858
14950
|
})]
|
|
14859
14951
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", { children: rows.map(({ node, depth }) => {
|
|
14860
|
-
const state = getCellState(node.addonId, a
|
|
14861
|
-
const isSelected = selectedCell
|
|
14952
|
+
const state = getCellState(node.addonId, a);
|
|
14953
|
+
const isSelected = selectedCell !== null && selectedCell.addonId === node.addonId && agentColumnKey(selectedCell) === agentColumnKey(a);
|
|
14862
14954
|
const toggleProps = showToggle && state !== null ? {
|
|
14863
14955
|
enabled: state.kind === "enabled",
|
|
14864
14956
|
onChange: (next) => onToggleEnabled?.(node.addonId, next),
|
|
@@ -14870,7 +14962,7 @@ function StackedCards({ rows, agents, getCellState, onCellClick, selectedCell, o
|
|
|
14870
14962
|
className: "flex items-center gap-2",
|
|
14871
14963
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
14872
14964
|
type: "button",
|
|
14873
|
-
onClick: () => onCellClick(node.addonId, a
|
|
14965
|
+
onClick: () => onCellClick(node.addonId, a),
|
|
14874
14966
|
className: cellButtonClass(state, isSelected, "flex flex-1 min-w-0 items-start justify-between gap-3 px-3 py-2"),
|
|
14875
14967
|
style: { paddingLeft: `${12 + depth * 14}px` },
|
|
14876
14968
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(StepLabel, { node }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
@@ -14888,7 +14980,7 @@ function StackedCards({ rows, agents, getCellState, onCellClick, selectedCell, o
|
|
|
14888
14980
|
})
|
|
14889
14981
|
}, node.addonId);
|
|
14890
14982
|
}) })]
|
|
14891
|
-
}, a
|
|
14983
|
+
}, agentColumnKey(a)))
|
|
14892
14984
|
});
|
|
14893
14985
|
}
|
|
14894
14986
|
function PipelineTreeMatrix({ tree, agents, getCellState, onCellClick, selectedCell, onToggleEnabled }) {
|
|
@@ -14996,11 +15088,11 @@ function ZoneBadge() {
|
|
|
14996
15088
|
})]
|
|
14997
15089
|
});
|
|
14998
15090
|
}
|
|
14999
|
-
function StepGateCell({ node, depth, gate, busy, onSet }) {
|
|
15091
|
+
function StepGateCell({ node, depth, gate, busy, onSet, hideGate }) {
|
|
15000
15092
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
15001
15093
|
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",
|
|
15002
15094
|
style: { paddingLeft: `${12 + depth * 14}px` },
|
|
15003
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(StepLabel, { node }), gate.kind === "zone-driven" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ZoneBadge, {}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(GateControl, {
|
|
15095
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(StepLabel, { node }), hideGate ? null : gate.kind === "zone-driven" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ZoneBadge, {}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(GateControl, {
|
|
15004
15096
|
gate,
|
|
15005
15097
|
busy,
|
|
15006
15098
|
onSet
|
|
@@ -15009,11 +15101,12 @@ function StepGateCell({ node, depth, gate, busy, onSet }) {
|
|
|
15009
15101
|
}
|
|
15010
15102
|
/**
|
|
15011
15103
|
* Agents-scoped node selector for the B fallback. Styled like the shared
|
|
15012
|
-
* `NodePicker` but driven by THIS matrix's
|
|
15104
|
+
* `NodePicker` but driven by THIS matrix's NODE set — the cluster-wide
|
|
15013
15105
|
* NodePicker can list nodes (e.g. the hub) that own no pipeline column here,
|
|
15014
|
-
* which would let the operator select a node the matrix can't show.
|
|
15106
|
+
* which would let the operator select a node the matrix can't show. Selects a
|
|
15107
|
+
* NODE (grouping its device sub-columns), never a raw device column.
|
|
15015
15108
|
*/
|
|
15016
|
-
function NodeSelectorBar({
|
|
15109
|
+
function NodeSelectorBar({ nodes, selected, onSelect }) {
|
|
15017
15110
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
15018
15111
|
className: "flex flex-wrap items-center gap-1.5",
|
|
15019
15112
|
role: "tablist",
|
|
@@ -15026,7 +15119,7 @@ function NodeSelectorBar({ agents, selected, onSelect }) {
|
|
|
15026
15119
|
}),
|
|
15027
15120
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
15028
15121
|
className: "flex overflow-hidden rounded-md border border-border text-[11px] font-medium",
|
|
15029
|
-
children:
|
|
15122
|
+
children: nodes.map((a, idx) => {
|
|
15030
15123
|
const isSelected = a.agentNodeId === selected;
|
|
15031
15124
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
15032
15125
|
type: "button",
|
|
@@ -15042,8 +15135,9 @@ function NodeSelectorBar({ agents, selected, onSelect }) {
|
|
|
15042
15135
|
]
|
|
15043
15136
|
});
|
|
15044
15137
|
}
|
|
15045
|
-
function MatrixGrid({ tree, agents, gateFor, getCellState, onCellClick, selectedCell, onSetGate, gateBusy, single }) {
|
|
15138
|
+
function MatrixGrid({ tree, agents, gateFor, getCellState, onCellClick, selectedCell, onSetGate, gateBusy, single, hideGate }) {
|
|
15046
15139
|
const rows = (0, react$1.useMemo)(() => flattenTree(tree), [tree]);
|
|
15140
|
+
const groups = (0, react$1.useMemo)(() => groupAgentColumns(agents), [agents]);
|
|
15047
15141
|
const gridTemplate = single ? `minmax(0, 1.35fr) repeat(${agents.length}, minmax(0, 1fr))` : `${STEP_COL_REM}rem repeat(${agents.length}, 13rem)`;
|
|
15048
15142
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
15049
15143
|
className: cn("rounded border border-border", single ? "overflow-hidden" : "overflow-auto"),
|
|
@@ -15053,18 +15147,18 @@ function MatrixGrid({ tree, agents, gateFor, getCellState, onCellClick, selected
|
|
|
15053
15147
|
children: [
|
|
15054
15148
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
15055
15149
|
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",
|
|
15056
|
-
children: "Step · gate"
|
|
15150
|
+
children: hideGate ? "Step" : "Step · gate"
|
|
15057
15151
|
}),
|
|
15058
|
-
|
|
15152
|
+
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", {
|
|
15059
15153
|
className: "sticky top-0 z-10 min-w-0 border-b border-l border-border bg-muted/60 px-3 py-2",
|
|
15060
15154
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
15061
15155
|
className: "truncate text-xs font-semibold text-foreground",
|
|
15062
|
-
children:
|
|
15156
|
+
children: col.agentNodeId
|
|
15063
15157
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
15064
15158
|
className: "truncate text-[10px] text-foreground-subtle",
|
|
15065
|
-
children:
|
|
15159
|
+
children: col.engineLabel
|
|
15066
15160
|
})]
|
|
15067
|
-
},
|
|
15161
|
+
}, agentColumnKey(col)))),
|
|
15068
15162
|
rows.map(({ node, depth }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MatrixRow, {
|
|
15069
15163
|
node,
|
|
15070
15164
|
depth,
|
|
@@ -15074,33 +15168,35 @@ function MatrixGrid({ tree, agents, gateFor, getCellState, onCellClick, selected
|
|
|
15074
15168
|
onCellClick,
|
|
15075
15169
|
selectedCell,
|
|
15076
15170
|
onSetGate,
|
|
15077
|
-
gateBusy
|
|
15171
|
+
gateBusy,
|
|
15172
|
+
hideGate
|
|
15078
15173
|
}, node.addonId))
|
|
15079
15174
|
]
|
|
15080
15175
|
})
|
|
15081
15176
|
});
|
|
15082
15177
|
}
|
|
15083
|
-
function MatrixRow({ node, depth, agents, gate, getCellState, onCellClick, selectedCell, onSetGate, gateBusy }) {
|
|
15178
|
+
function MatrixRow({ node, depth, agents, gate, getCellState, onCellClick, selectedCell, onSetGate, gateBusy, hideGate }) {
|
|
15084
15179
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(StepGateCell, {
|
|
15085
15180
|
node,
|
|
15086
15181
|
depth,
|
|
15087
15182
|
gate,
|
|
15088
15183
|
busy: gateBusy,
|
|
15089
|
-
onSet: (next) => onSetGate(node.addonId, next)
|
|
15184
|
+
onSet: (next) => onSetGate(node.addonId, next),
|
|
15185
|
+
hideGate
|
|
15090
15186
|
}), agents.map((a) => {
|
|
15091
|
-
const state = getCellState(node.addonId, a
|
|
15092
|
-
const isSelected = selectedCell
|
|
15187
|
+
const state = getCellState(node.addonId, a);
|
|
15188
|
+
const isSelected = selectedCell !== null && selectedCell.addonId === node.addonId && agentColumnKey(selectedCell) === agentColumnKey(a);
|
|
15093
15189
|
const actionable = state.kind === "enabled" || state.kind === "skip";
|
|
15094
15190
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
15095
15191
|
type: "button",
|
|
15096
15192
|
disabled: !actionable,
|
|
15097
|
-
onClick: () => onCellClick(node.addonId, a
|
|
15193
|
+
onClick: () => onCellClick(node.addonId, a),
|
|
15098
15194
|
className: cellButtonClass(state, isSelected, cn("min-w-0 overflow-hidden border-b border-l border-border px-3 py-2", !actionable && "cursor-default hover:bg-transparent")),
|
|
15099
15195
|
children: renderCellContent(state)
|
|
15100
|
-
}, a
|
|
15196
|
+
}, agentColumnKey(a));
|
|
15101
15197
|
})] });
|
|
15102
15198
|
}
|
|
15103
|
-
function DeviceStepMatrix({ tree, agents, gateFor, getCellState, onCellClick, selectedCell, onSetGate, gateBusy, fallbackNodeId, onFallbackNodeChange }) {
|
|
15199
|
+
function DeviceStepMatrix({ tree, agents, gateFor, getCellState, onCellClick, selectedCell, onSetGate, gateBusy, fallbackNodeId, onFallbackNodeChange, hideGate }) {
|
|
15104
15200
|
const containerRef = (0, react$1.useRef)(null);
|
|
15105
15201
|
const [width, setWidth] = (0, react$1.useState)(0);
|
|
15106
15202
|
(0, react$1.useLayoutEffect)(() => {
|
|
@@ -15112,17 +15208,18 @@ function DeviceStepMatrix({ tree, agents, gateFor, getCellState, onCellClick, se
|
|
|
15112
15208
|
RO?.observe(el);
|
|
15113
15209
|
return () => RO?.disconnect();
|
|
15114
15210
|
}, []);
|
|
15115
|
-
const
|
|
15211
|
+
const nodes = (0, react$1.useMemo)(() => groupAgentColumns(agents), [agents]);
|
|
15212
|
+
const single = shouldUseSingleNode(width, nodes.length, STEP_COL_PX);
|
|
15116
15213
|
const selectedNode = (0, react$1.useMemo)(() => {
|
|
15117
|
-
if (
|
|
15118
|
-
return
|
|
15119
|
-
}, [
|
|
15120
|
-
const shownAgents = single && selectedNode ?
|
|
15214
|
+
if (nodes.length === 0) return null;
|
|
15215
|
+
return nodes.find((n) => n.agentNodeId === fallbackNodeId) ?? nodes[0] ?? null;
|
|
15216
|
+
}, [nodes, fallbackNodeId]);
|
|
15217
|
+
const shownAgents = single && selectedNode ? selectedNode.columns : agents;
|
|
15121
15218
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
15122
15219
|
ref: containerRef,
|
|
15123
15220
|
className: "w-full space-y-2",
|
|
15124
15221
|
children: [single && selectedNode && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(NodeSelectorBar, {
|
|
15125
|
-
|
|
15222
|
+
nodes,
|
|
15126
15223
|
selected: selectedNode.agentNodeId,
|
|
15127
15224
|
onSelect: onFallbackNodeChange
|
|
15128
15225
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MatrixGrid, {
|
|
@@ -15134,7 +15231,8 @@ function DeviceStepMatrix({ tree, agents, gateFor, getCellState, onCellClick, se
|
|
|
15134
15231
|
selectedCell,
|
|
15135
15232
|
onSetGate,
|
|
15136
15233
|
gateBusy,
|
|
15137
|
-
single: single && selectedNode !== null
|
|
15234
|
+
single: single && selectedNode !== null,
|
|
15235
|
+
hideGate
|
|
15138
15236
|
})]
|
|
15139
15237
|
});
|
|
15140
15238
|
}
|
|
@@ -18850,8 +18948,6 @@ var usePipelineExecutorGetAvailableEngines = trpc.pipelineExecutor.getAvailableE
|
|
|
18850
18948
|
var usePipelineExecutorGetSelectedEngine = trpc.pipelineExecutor.getSelectedEngine.useQuery;
|
|
18851
18949
|
/** Generated alias around `trpc.pipelineExecutor.getDefaultSteps.useQuery`. */
|
|
18852
18950
|
var usePipelineExecutorGetDefaultSteps = trpc.pipelineExecutor.getDefaultSteps.useQuery;
|
|
18853
|
-
/** Generated alias around `trpc.pipelineExecutor.reprobeEngine.useMutation`. */
|
|
18854
|
-
var usePipelineExecutorReprobeEngine = trpc.pipelineExecutor.reprobeEngine.useMutation;
|
|
18855
18951
|
/** Generated alias around `trpc.pipelineExecutor.getEngineProvisioning.useQuery`. */
|
|
18856
18952
|
var usePipelineExecutorGetEngineProvisioning = trpc.pipelineExecutor.getEngineProvisioning.useQuery;
|
|
18857
18953
|
/** Generated alias around `trpc.pipelineExecutor.getVideoPipelineSteps.useQuery`. */
|
|
@@ -18922,6 +19018,10 @@ var usePipelineExecutorGetDetectionConfigSchema = trpc.pipelineExecutor.getDetec
|
|
|
18922
19018
|
var usePipelineOrchestratorAssignPipeline = trpc.pipelineOrchestrator.assignPipeline.useMutation;
|
|
18923
19019
|
/** Generated alias around `trpc.pipelineOrchestrator.unassignPipeline.useMutation`. */
|
|
18924
19020
|
var usePipelineOrchestratorUnassignPipeline = trpc.pipelineOrchestrator.unassignPipeline.useMutation;
|
|
19021
|
+
/** Generated alias around `trpc.pipelineOrchestrator.setPipelineDevicePin.useMutation`. */
|
|
19022
|
+
var usePipelineOrchestratorSetPipelineDevicePin = trpc.pipelineOrchestrator.setPipelineDevicePin.useMutation;
|
|
19023
|
+
/** Generated alias around `trpc.pipelineOrchestrator.getPipelineDevicePin.useQuery`. */
|
|
19024
|
+
var usePipelineOrchestratorGetPipelineDevicePin = trpc.pipelineOrchestrator.getPipelineDevicePin.useQuery;
|
|
18925
19025
|
/** Generated alias around `trpc.pipelineOrchestrator.rebalance.useMutation`. */
|
|
18926
19026
|
var usePipelineOrchestratorRebalance = trpc.pipelineOrchestrator.rebalance.useMutation;
|
|
18927
19027
|
/** Generated alias around `trpc.pipelineOrchestrator.getPipelineAssignments.useQuery`. */
|
|
@@ -18954,8 +19054,6 @@ var usePipelineOrchestratorGetAudioAssignments = trpc.pipelineOrchestrator.getAu
|
|
|
18954
19054
|
var usePipelineOrchestratorGetAgentSettings = trpc.pipelineOrchestrator.getAgentSettings.useQuery;
|
|
18955
19055
|
/** Generated alias around `trpc.pipelineOrchestrator.listAgentSettings.useQuery`. */
|
|
18956
19056
|
var usePipelineOrchestratorListAgentSettings = trpc.pipelineOrchestrator.listAgentSettings.useQuery;
|
|
18957
|
-
/** Generated alias around `trpc.pipelineOrchestrator.setAgentAddonDefaults.useMutation`. */
|
|
18958
|
-
var usePipelineOrchestratorSetAgentAddonDefaults = trpc.pipelineOrchestrator.setAgentAddonDefaults.useMutation;
|
|
18959
19057
|
/** Generated alias around `trpc.pipelineOrchestrator.removeAgentSettings.useMutation`. */
|
|
18960
19058
|
var usePipelineOrchestratorRemoveAgentSettings = trpc.pipelineOrchestrator.removeAgentSettings.useMutation;
|
|
18961
19059
|
/** Generated alias around `trpc.pipelineOrchestrator.setAgentMaxCameras.useMutation`. */
|
|
@@ -18968,6 +19066,8 @@ var usePipelineOrchestratorSetAgentCapabilities = trpc.pipelineOrchestrator.setA
|
|
|
18968
19066
|
var usePipelineOrchestratorSetAgentReachableHost = trpc.pipelineOrchestrator.setAgentReachableHost.useMutation;
|
|
18969
19067
|
/** Generated alias around `trpc.pipelineOrchestrator.setAgentInferenceDevices.useMutation`. */
|
|
18970
19068
|
var usePipelineOrchestratorSetAgentInferenceDevices = trpc.pipelineOrchestrator.setAgentInferenceDevices.useMutation;
|
|
19069
|
+
/** Generated alias around `trpc.pipelineOrchestrator.getNodeInferenceDevices.useQuery`. */
|
|
19070
|
+
var usePipelineOrchestratorGetNodeInferenceDevices = trpc.pipelineOrchestrator.getNodeInferenceDevices.useQuery;
|
|
18971
19071
|
/** Generated alias around `trpc.pipelineOrchestrator.resetNodePipelineDefaults.useMutation`. */
|
|
18972
19072
|
var usePipelineOrchestratorResetNodePipelineDefaults = trpc.pipelineOrchestrator.resetNodePipelineDefaults.useMutation;
|
|
18973
19073
|
/** Generated alias around `trpc.pipelineOrchestrator.getCameraSettings.useQuery`. */
|
|
@@ -28829,15 +28929,34 @@ function DeviceItemPreview({ trpc, device, status, enabled, showStatusPills = fa
|
|
|
28829
28929
|
}
|
|
28830
28930
|
//#endregion
|
|
28831
28931
|
//#region src/composites/device-item/status-dot.tsx
|
|
28932
|
+
/** The states that breathe (are "alive"). Offline + disabled are static. */
|
|
28933
|
+
function isAlive(status) {
|
|
28934
|
+
return status === "online" || status === "recording-continuous" || status === "recording-events";
|
|
28935
|
+
}
|
|
28832
28936
|
function resolveTitle(status, lastChangedAt) {
|
|
28833
|
-
|
|
28834
|
-
|
|
28835
|
-
|
|
28836
|
-
|
|
28937
|
+
switch (status) {
|
|
28938
|
+
case "disabled": return "Disabled";
|
|
28939
|
+
case "online": return "Online";
|
|
28940
|
+
case "recording-continuous": return "Recording · always";
|
|
28941
|
+
case "recording-events": return "Recording · on motion";
|
|
28942
|
+
case "offline": {
|
|
28943
|
+
const lastSeen = formatLastSeen(lastChangedAt);
|
|
28944
|
+
return lastSeen === null ? "Offline" : `Offline · last seen ${lastSeen}`;
|
|
28945
|
+
}
|
|
28946
|
+
}
|
|
28947
|
+
}
|
|
28948
|
+
function colorClass(status) {
|
|
28949
|
+
switch (status) {
|
|
28950
|
+
case "disabled": return "bg-black ring-1 ring-foreground-subtle/60";
|
|
28951
|
+
case "offline": return "bg-foreground-subtle";
|
|
28952
|
+
case "recording-continuous": return "bg-danger";
|
|
28953
|
+
case "recording-events": return "bg-info";
|
|
28954
|
+
case "online": return "bg-success";
|
|
28955
|
+
}
|
|
28837
28956
|
}
|
|
28838
28957
|
function StatusDot({ status, lastChangedAt }) {
|
|
28839
28958
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
28840
|
-
className: cn("h-1.5 w-1.5 rounded-full flex-shrink-0", status
|
|
28959
|
+
className: cn("h-1.5 w-1.5 rounded-full flex-shrink-0", colorClass(status), isAlive(status) && "animate-pulse"),
|
|
28841
28960
|
title: resolveTitle(status, lastChangedAt)
|
|
28842
28961
|
});
|
|
28843
28962
|
}
|
|
@@ -47081,6 +47200,7 @@ exports.MediaPlayerHeroCard = MediaPlayerHeroCard;
|
|
|
47081
47200
|
exports.MediaPlayerInlineControl = MediaPlayerInlineControl;
|
|
47082
47201
|
exports.MediaPlayerPanel = MediaPlayerPanel;
|
|
47083
47202
|
exports.MobileDrawer = MobileDrawer;
|
|
47203
|
+
exports.ModelPicker = ModelPicker;
|
|
47084
47204
|
exports.MotionZonesSettings = MotionZonesSettings;
|
|
47085
47205
|
exports.NodeMultiSelectField = NodeMultiSelectField;
|
|
47086
47206
|
exports.NodePicker = NodePicker;
|
|
@@ -47182,6 +47302,7 @@ exports.WidgetPanel = WidgetPanel;
|
|
|
47182
47302
|
exports.WidgetRegistryProvider = WidgetRegistryProvider;
|
|
47183
47303
|
exports.WidgetSlot = WidgetSlot;
|
|
47184
47304
|
exports.ZoneEditingProvider = ZoneEditingProvider;
|
|
47305
|
+
exports.agentColumnKey = agentColumnKey;
|
|
47185
47306
|
exports.allDeviceTypeFilterOptions = allDeviceTypeFilterOptions;
|
|
47186
47307
|
exports.buildStepTreeFromSchema = buildStepTreeFromSchema;
|
|
47187
47308
|
exports.childEntityId = childEntityId;
|
|
@@ -47215,6 +47336,7 @@ exports.formatNumeric = formatNumeric;
|
|
|
47215
47336
|
exports.fuzzyMatch = fuzzyMatch;
|
|
47216
47337
|
exports.getClassColor = getClassColor;
|
|
47217
47338
|
exports.getPhaseVisual = getPhaseVisual;
|
|
47339
|
+
exports.groupAgentColumns = groupAgentColumns;
|
|
47218
47340
|
exports.groupChildrenByLayout = groupChildrenByLayout;
|
|
47219
47341
|
exports.hardwareLabel = hardwareLabel;
|
|
47220
47342
|
exports.humidifierTint = humidifierTint;
|
|
@@ -47820,7 +47942,6 @@ exports.usePipelineExecutorKillEngine = usePipelineExecutorKillEngine;
|
|
|
47820
47942
|
exports.usePipelineExecutorListLoadedEngines = usePipelineExecutorListLoadedEngines;
|
|
47821
47943
|
exports.usePipelineExecutorListReferenceImages = usePipelineExecutorListReferenceImages;
|
|
47822
47944
|
exports.usePipelineExecutorListTemplates = usePipelineExecutorListTemplates;
|
|
47823
|
-
exports.usePipelineExecutorReprobeEngine = usePipelineExecutorReprobeEngine;
|
|
47824
47945
|
exports.usePipelineExecutorRunAudioTest = usePipelineExecutorRunAudioTest;
|
|
47825
47946
|
exports.usePipelineExecutorRunPipeline = usePipelineExecutorRunPipeline;
|
|
47826
47947
|
exports.usePipelineExecutorRunPipelineBatch = usePipelineExecutorRunPipelineBatch;
|
|
@@ -47849,8 +47970,10 @@ exports.usePipelineOrchestratorGetDeviceLiveContribution = usePipelineOrchestrat
|
|
|
47849
47970
|
exports.usePipelineOrchestratorGetDeviceSettingsContribution = usePipelineOrchestratorGetDeviceSettingsContribution;
|
|
47850
47971
|
exports.usePipelineOrchestratorGetGlobalMetrics = usePipelineOrchestratorGetGlobalMetrics;
|
|
47851
47972
|
exports.usePipelineOrchestratorGetIngestOwner = usePipelineOrchestratorGetIngestOwner;
|
|
47973
|
+
exports.usePipelineOrchestratorGetNodeInferenceDevices = usePipelineOrchestratorGetNodeInferenceDevices;
|
|
47852
47974
|
exports.usePipelineOrchestratorGetPipelineAssignment = usePipelineOrchestratorGetPipelineAssignment;
|
|
47853
47975
|
exports.usePipelineOrchestratorGetPipelineAssignments = usePipelineOrchestratorGetPipelineAssignments;
|
|
47976
|
+
exports.usePipelineOrchestratorGetPipelineDevicePin = usePipelineOrchestratorGetPipelineDevicePin;
|
|
47854
47977
|
exports.usePipelineOrchestratorListAgentSettings = usePipelineOrchestratorListAgentSettings;
|
|
47855
47978
|
exports.usePipelineOrchestratorListTemplates = usePipelineOrchestratorListTemplates;
|
|
47856
47979
|
exports.usePipelineOrchestratorRebalance = usePipelineOrchestratorRebalance;
|
|
@@ -47858,7 +47981,6 @@ exports.usePipelineOrchestratorRemoveAgentSettings = usePipelineOrchestratorRemo
|
|
|
47858
47981
|
exports.usePipelineOrchestratorResetNodePipelineDefaults = usePipelineOrchestratorResetNodePipelineDefaults;
|
|
47859
47982
|
exports.usePipelineOrchestratorResolvePipeline = usePipelineOrchestratorResolvePipeline;
|
|
47860
47983
|
exports.usePipelineOrchestratorSaveTemplate = usePipelineOrchestratorSaveTemplate;
|
|
47861
|
-
exports.usePipelineOrchestratorSetAgentAddonDefaults = usePipelineOrchestratorSetAgentAddonDefaults;
|
|
47862
47984
|
exports.usePipelineOrchestratorSetAgentCapabilities = usePipelineOrchestratorSetAgentCapabilities;
|
|
47863
47985
|
exports.usePipelineOrchestratorSetAgentDetectWeight = usePipelineOrchestratorSetAgentDetectWeight;
|
|
47864
47986
|
exports.usePipelineOrchestratorSetAgentInferenceDevices = usePipelineOrchestratorSetAgentInferenceDevices;
|
|
@@ -47868,6 +47990,7 @@ exports.usePipelineOrchestratorSetCameraPipelineForAgent = usePipelineOrchestrat
|
|
|
47868
47990
|
exports.usePipelineOrchestratorSetCameraStepOverride = usePipelineOrchestratorSetCameraStepOverride;
|
|
47869
47991
|
exports.usePipelineOrchestratorSetCameraStepToggle = usePipelineOrchestratorSetCameraStepToggle;
|
|
47870
47992
|
exports.usePipelineOrchestratorSetCapabilityBinding = usePipelineOrchestratorSetCapabilityBinding;
|
|
47993
|
+
exports.usePipelineOrchestratorSetPipelineDevicePin = usePipelineOrchestratorSetPipelineDevicePin;
|
|
47871
47994
|
exports.usePipelineOrchestratorUnassignAudio = usePipelineOrchestratorUnassignAudio;
|
|
47872
47995
|
exports.usePipelineOrchestratorUnassignPipeline = usePipelineOrchestratorUnassignPipeline;
|
|
47873
47996
|
exports.usePipelineOrchestratorUpdateTemplate = usePipelineOrchestratorUpdateTemplate;
|