@camstack/ui-library 1.2.61 → 1.2.63
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +145 -124
- package/dist/index.js +145 -124
- package/dist/primitives/dialog.d.ts +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -7161,6 +7161,115 @@ function useCustomFieldRenderer(type) {
|
|
|
7161
7161
|
return (0, react$1.useContext)(CustomFieldRenderersContext)[type] ?? null;
|
|
7162
7162
|
}
|
|
7163
7163
|
//#endregion
|
|
7164
|
+
//#region src/composites/event-kind-visuals.tsx
|
|
7165
|
+
/**
|
|
7166
|
+
* Event-kind VISUALS — the UI-side half of the unified taxonomy dictionary
|
|
7167
|
+
* (`@camstack/types` `EVENT_TAXONOMY` owns the serializable data:
|
|
7168
|
+
* color / iconId / labelKey; this owns `iconId → lucide component` and
|
|
7169
|
+
* `labelKey → t()`).
|
|
7170
|
+
*
|
|
7171
|
+
* Every UI that renders an event kind (timeline, events tree, chips,
|
|
7172
|
+
* detection canvas/tree) resolves its glyph + translated label here — no
|
|
7173
|
+
* per-component hardcoded icon or label.
|
|
7174
|
+
*/
|
|
7175
|
+
/**
|
|
7176
|
+
* `iconId` → lucide component. Built ONLY from statically-imported icons
|
|
7177
|
+
* (bundle-safe). Unknown ids resolve to the neutral `Tag` fallback.
|
|
7178
|
+
*/
|
|
7179
|
+
var EVENT_KIND_ICONS = {
|
|
7180
|
+
motion: Activity,
|
|
7181
|
+
audio: Volume2,
|
|
7182
|
+
person: User,
|
|
7183
|
+
vehicle: Car,
|
|
7184
|
+
animal: PawPrint,
|
|
7185
|
+
package: Package,
|
|
7186
|
+
sensor: Radio,
|
|
7187
|
+
control: SlidersHorizontal,
|
|
7188
|
+
car: Car,
|
|
7189
|
+
truck: Truck,
|
|
7190
|
+
bus: Bus,
|
|
7191
|
+
motorcycle: Bike,
|
|
7192
|
+
bicycle: Bike,
|
|
7193
|
+
airplane: Plane,
|
|
7194
|
+
boat: Sailboat,
|
|
7195
|
+
train: TrainFront,
|
|
7196
|
+
bird: Bird,
|
|
7197
|
+
cat: Cat,
|
|
7198
|
+
dog: Dog,
|
|
7199
|
+
horse: PawPrint,
|
|
7200
|
+
sheep: PawPrint,
|
|
7201
|
+
cow: PawPrint,
|
|
7202
|
+
elephant: PawPrint,
|
|
7203
|
+
bear: PawPrint,
|
|
7204
|
+
zebra: PawPrint,
|
|
7205
|
+
giraffe: PawPrint,
|
|
7206
|
+
door: DoorOpen,
|
|
7207
|
+
pir: Radar,
|
|
7208
|
+
smoke: Flame,
|
|
7209
|
+
water: Droplet,
|
|
7210
|
+
gas: Wind,
|
|
7211
|
+
vibration: Vibrate,
|
|
7212
|
+
tamper: ShieldAlert,
|
|
7213
|
+
presence: UserCheck,
|
|
7214
|
+
generic: Tag,
|
|
7215
|
+
lock: Lock,
|
|
7216
|
+
siren: Siren,
|
|
7217
|
+
switch: ToggleRight,
|
|
7218
|
+
doorbell: BellRing,
|
|
7219
|
+
button: CircleDot,
|
|
7220
|
+
"audio-speech": MessageSquare,
|
|
7221
|
+
"audio-scream": Megaphone,
|
|
7222
|
+
"audio-crying": Baby,
|
|
7223
|
+
"audio-laughter": Laugh,
|
|
7224
|
+
"audio-music": Music,
|
|
7225
|
+
"audio-dog": Dog,
|
|
7226
|
+
"audio-cat": Cat,
|
|
7227
|
+
"audio-bird": Bird,
|
|
7228
|
+
"audio-animal": PawPrint,
|
|
7229
|
+
"audio-alarm": BellRing,
|
|
7230
|
+
"audio-doorbell": BellRing,
|
|
7231
|
+
"audio-glass_breaking": TriangleAlert,
|
|
7232
|
+
"audio-gunshot": Crosshair,
|
|
7233
|
+
"audio-vehicle": Car,
|
|
7234
|
+
"audio-siren": Siren,
|
|
7235
|
+
"audio-fire": Flame,
|
|
7236
|
+
"audio-water": Droplets,
|
|
7237
|
+
"audio-wind": Wind,
|
|
7238
|
+
"audio-door": DoorOpen,
|
|
7239
|
+
"audio-footsteps": Footprints,
|
|
7240
|
+
"audio-crowd": Users,
|
|
7241
|
+
"audio-telephone": Phone,
|
|
7242
|
+
"audio-engine": Cog,
|
|
7243
|
+
"audio-tools": Hammer,
|
|
7244
|
+
"audio-silence": VolumeX
|
|
7245
|
+
};
|
|
7246
|
+
/** Resolve an `iconId` to a lucide component (falls back to `Tag`). */
|
|
7247
|
+
function resolveEventKindIcon(iconId) {
|
|
7248
|
+
if (Object.hasOwn(EVENT_KIND_ICONS, iconId)) return EVENT_KIND_ICONS[iconId];
|
|
7249
|
+
if (iconId.startsWith("audio-")) return Volume2;
|
|
7250
|
+
return Tag;
|
|
7251
|
+
}
|
|
7252
|
+
/**
|
|
7253
|
+
* Translated label for an event kind — `t(labelKey)` when a translation
|
|
7254
|
+
* exists, else the English `label` fallback. Robust to a missing key: an
|
|
7255
|
+
* i18n backend that echoes the key unchanged (react-i18next default) is
|
|
7256
|
+
* treated as "no translation" and the fallback label is returned, so the UI
|
|
7257
|
+
* never renders a raw `eventKind.*` key.
|
|
7258
|
+
*/
|
|
7259
|
+
function eventKindLabel(descriptor, t) {
|
|
7260
|
+
if (t === void 0) return descriptor.label;
|
|
7261
|
+
const translated = t(descriptor.labelKey);
|
|
7262
|
+
return translated === descriptor.labelKey || translated.length === 0 ? descriptor.label : translated;
|
|
7263
|
+
}
|
|
7264
|
+
/** Small convenience component: renders the lucide glyph for an `iconId`. */
|
|
7265
|
+
function EventKindGlyph({ iconId, size = 16, color, className }) {
|
|
7266
|
+
return (0, react$1.createElement)(resolveEventKindIcon(iconId), {
|
|
7267
|
+
size,
|
|
7268
|
+
color,
|
|
7269
|
+
className
|
|
7270
|
+
});
|
|
7271
|
+
}
|
|
7272
|
+
//#endregion
|
|
7164
7273
|
//#region src/composites/confirm-dialog.tsx
|
|
7165
7274
|
var ConfirmContext = createSharedContext("camstack:confirm-dialog", null);
|
|
7166
7275
|
function useConfirm() {
|
|
@@ -19727,13 +19836,20 @@ function MultiSelectField({ field, value, onChange, disabled, translationFn }) {
|
|
|
19727
19836
|
checked ? "border-primary bg-primary/10 text-primary" : "border-border bg-background text-foreground hover:bg-surface",
|
|
19728
19837
|
disabled || field.disabled ? "opacity-50 cursor-not-allowed" : ""
|
|
19729
19838
|
].join(" "),
|
|
19730
|
-
children: [
|
|
19731
|
-
|
|
19732
|
-
|
|
19733
|
-
|
|
19734
|
-
|
|
19735
|
-
|
|
19736
|
-
|
|
19839
|
+
children: [
|
|
19840
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
19841
|
+
type: "checkbox",
|
|
19842
|
+
className: "sr-only",
|
|
19843
|
+
checked,
|
|
19844
|
+
disabled: disabled || field.disabled,
|
|
19845
|
+
onChange: () => toggle(opt.value)
|
|
19846
|
+
}),
|
|
19847
|
+
opt.iconId !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EventKindGlyph, {
|
|
19848
|
+
iconId: opt.iconId,
|
|
19849
|
+
size: 13
|
|
19850
|
+
}),
|
|
19851
|
+
opt.label
|
|
19852
|
+
]
|
|
19737
19853
|
}, opt.value);
|
|
19738
19854
|
})
|
|
19739
19855
|
})
|
|
@@ -21615,7 +21731,7 @@ function GroupedModelSelector({ catalog, value, onChange, disabled }) {
|
|
|
21615
21731
|
const resolutions = [...new Set(tier.options.map((o) => o.resolution))].sort((a, b) => (b ?? Infinity) - (a ?? Infinity));
|
|
21616
21732
|
const selectedResolution = resolutions.includes(current?.resolution) ? current?.resolution : resolutions[0];
|
|
21617
21733
|
const variantOptions = tier.options.filter((o) => o.resolution === selectedResolution);
|
|
21618
|
-
const resLabel = (r) => r === void 0 ? "
|
|
21734
|
+
const resLabel = (r) => r === void 0 ? "native" : `${r}`;
|
|
21619
21735
|
const selectTier = (tierId) => {
|
|
21620
21736
|
const t = family.tiers.find((x) => x.tier === tierId);
|
|
21621
21737
|
if (!t) return;
|
|
@@ -21659,7 +21775,7 @@ function GroupedModelSelector({ catalog, value, onChange, disabled }) {
|
|
|
21659
21775
|
className: "grid grid-cols-2 gap-1.5 sm:grid-cols-4",
|
|
21660
21776
|
children: family.tiers.map((t) => {
|
|
21661
21777
|
const active = t.tier === tier.tier;
|
|
21662
|
-
const
|
|
21778
|
+
const quoted = t.options.find((o) => o.resolution === selectedResolution && o.precision === "fp32") ?? t.options.find((o) => o.modelId === t.baseModelId) ?? t.options[0];
|
|
21663
21779
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
21664
21780
|
type: "button",
|
|
21665
21781
|
disabled,
|
|
@@ -21675,7 +21791,7 @@ function GroupedModelSelector({ catalog, value, onChange, disabled }) {
|
|
|
21675
21791
|
className: "text-[10px] text-foreground-subtle",
|
|
21676
21792
|
children: [
|
|
21677
21793
|
"~",
|
|
21678
|
-
|
|
21794
|
+
quoted?.sizeMB ?? 0,
|
|
21679
21795
|
" MB"
|
|
21680
21796
|
]
|
|
21681
21797
|
})]
|
|
@@ -21975,12 +22091,15 @@ function ConfigMultiSelect({ label, description, value, options, disabled, onCha
|
|
|
21975
22091
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
21976
22092
|
className: "flex flex-wrap gap-1.5",
|
|
21977
22093
|
children: options.map((o) => {
|
|
21978
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.
|
|
22094
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
21979
22095
|
type: "button",
|
|
21980
22096
|
disabled,
|
|
21981
22097
|
onClick: () => toggle(o.value),
|
|
21982
|
-
className: cn("text-[10px] font-medium px-2 py-1 rounded-md border transition-colors", value.includes(o.value) ? "bg-primary/20 text-primary border-primary/40" : "bg-surface text-foreground-subtle border-border hover:border-primary/30", disabled && "opacity-50 cursor-not-allowed"),
|
|
21983
|
-
children: o.
|
|
22098
|
+
className: cn("inline-flex items-center gap-1 text-[10px] font-medium px-2 py-1 rounded-md border transition-colors", value.includes(o.value) ? "bg-primary/20 text-primary border-primary/40" : "bg-surface text-foreground-subtle border-border hover:border-primary/30", disabled && "opacity-50 cursor-not-allowed"),
|
|
22099
|
+
children: [o.iconId !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EventKindGlyph, {
|
|
22100
|
+
iconId: o.iconId,
|
|
22101
|
+
size: 12
|
|
22102
|
+
}), o.label]
|
|
21984
22103
|
}, o.value);
|
|
21985
22104
|
})
|
|
21986
22105
|
})
|
|
@@ -44672,115 +44791,6 @@ function DoorbellRecentPanel({ history, limit = 5, latestIsFresh, className }) {
|
|
|
44672
44791
|
});
|
|
44673
44792
|
}
|
|
44674
44793
|
//#endregion
|
|
44675
|
-
//#region src/composites/event-kind-visuals.tsx
|
|
44676
|
-
/**
|
|
44677
|
-
* Event-kind VISUALS — the UI-side half of the unified taxonomy dictionary
|
|
44678
|
-
* (`@camstack/types` `EVENT_TAXONOMY` owns the serializable data:
|
|
44679
|
-
* color / iconId / labelKey; this owns `iconId → lucide component` and
|
|
44680
|
-
* `labelKey → t()`).
|
|
44681
|
-
*
|
|
44682
|
-
* Every UI that renders an event kind (timeline, events tree, chips,
|
|
44683
|
-
* detection canvas/tree) resolves its glyph + translated label here — no
|
|
44684
|
-
* per-component hardcoded icon or label.
|
|
44685
|
-
*/
|
|
44686
|
-
/**
|
|
44687
|
-
* `iconId` → lucide component. Built ONLY from statically-imported icons
|
|
44688
|
-
* (bundle-safe). Unknown ids resolve to the neutral `Tag` fallback.
|
|
44689
|
-
*/
|
|
44690
|
-
var EVENT_KIND_ICONS = {
|
|
44691
|
-
motion: Activity,
|
|
44692
|
-
audio: Volume2,
|
|
44693
|
-
person: User,
|
|
44694
|
-
vehicle: Car,
|
|
44695
|
-
animal: PawPrint,
|
|
44696
|
-
package: Package,
|
|
44697
|
-
sensor: Radio,
|
|
44698
|
-
control: SlidersHorizontal,
|
|
44699
|
-
car: Car,
|
|
44700
|
-
truck: Truck,
|
|
44701
|
-
bus: Bus,
|
|
44702
|
-
motorcycle: Bike,
|
|
44703
|
-
bicycle: Bike,
|
|
44704
|
-
airplane: Plane,
|
|
44705
|
-
boat: Sailboat,
|
|
44706
|
-
train: TrainFront,
|
|
44707
|
-
bird: Bird,
|
|
44708
|
-
cat: Cat,
|
|
44709
|
-
dog: Dog,
|
|
44710
|
-
horse: PawPrint,
|
|
44711
|
-
sheep: PawPrint,
|
|
44712
|
-
cow: PawPrint,
|
|
44713
|
-
elephant: PawPrint,
|
|
44714
|
-
bear: PawPrint,
|
|
44715
|
-
zebra: PawPrint,
|
|
44716
|
-
giraffe: PawPrint,
|
|
44717
|
-
door: DoorOpen,
|
|
44718
|
-
pir: Radar,
|
|
44719
|
-
smoke: Flame,
|
|
44720
|
-
water: Droplet,
|
|
44721
|
-
gas: Wind,
|
|
44722
|
-
vibration: Vibrate,
|
|
44723
|
-
tamper: ShieldAlert,
|
|
44724
|
-
presence: UserCheck,
|
|
44725
|
-
generic: Tag,
|
|
44726
|
-
lock: Lock,
|
|
44727
|
-
siren: Siren,
|
|
44728
|
-
switch: ToggleRight,
|
|
44729
|
-
doorbell: BellRing,
|
|
44730
|
-
button: CircleDot,
|
|
44731
|
-
"audio-speech": MessageSquare,
|
|
44732
|
-
"audio-scream": Megaphone,
|
|
44733
|
-
"audio-crying": Baby,
|
|
44734
|
-
"audio-laughter": Laugh,
|
|
44735
|
-
"audio-music": Music,
|
|
44736
|
-
"audio-dog": Dog,
|
|
44737
|
-
"audio-cat": Cat,
|
|
44738
|
-
"audio-bird": Bird,
|
|
44739
|
-
"audio-animal": PawPrint,
|
|
44740
|
-
"audio-alarm": BellRing,
|
|
44741
|
-
"audio-doorbell": BellRing,
|
|
44742
|
-
"audio-glass_breaking": TriangleAlert,
|
|
44743
|
-
"audio-gunshot": Crosshair,
|
|
44744
|
-
"audio-vehicle": Car,
|
|
44745
|
-
"audio-siren": Siren,
|
|
44746
|
-
"audio-fire": Flame,
|
|
44747
|
-
"audio-water": Droplets,
|
|
44748
|
-
"audio-wind": Wind,
|
|
44749
|
-
"audio-door": DoorOpen,
|
|
44750
|
-
"audio-footsteps": Footprints,
|
|
44751
|
-
"audio-crowd": Users,
|
|
44752
|
-
"audio-telephone": Phone,
|
|
44753
|
-
"audio-engine": Cog,
|
|
44754
|
-
"audio-tools": Hammer,
|
|
44755
|
-
"audio-silence": VolumeX
|
|
44756
|
-
};
|
|
44757
|
-
/** Resolve an `iconId` to a lucide component (falls back to `Tag`). */
|
|
44758
|
-
function resolveEventKindIcon(iconId) {
|
|
44759
|
-
if (Object.hasOwn(EVENT_KIND_ICONS, iconId)) return EVENT_KIND_ICONS[iconId];
|
|
44760
|
-
if (iconId.startsWith("audio-")) return Volume2;
|
|
44761
|
-
return Tag;
|
|
44762
|
-
}
|
|
44763
|
-
/**
|
|
44764
|
-
* Translated label for an event kind — `t(labelKey)` when a translation
|
|
44765
|
-
* exists, else the English `label` fallback. Robust to a missing key: an
|
|
44766
|
-
* i18n backend that echoes the key unchanged (react-i18next default) is
|
|
44767
|
-
* treated as "no translation" and the fallback label is returned, so the UI
|
|
44768
|
-
* never renders a raw `eventKind.*` key.
|
|
44769
|
-
*/
|
|
44770
|
-
function eventKindLabel(descriptor, t) {
|
|
44771
|
-
if (t === void 0) return descriptor.label;
|
|
44772
|
-
const translated = t(descriptor.labelKey);
|
|
44773
|
-
return translated === descriptor.labelKey || translated.length === 0 ? descriptor.label : translated;
|
|
44774
|
-
}
|
|
44775
|
-
/** Small convenience component: renders the lucide glyph for an `iconId`. */
|
|
44776
|
-
function EventKindGlyph({ iconId, size = 16, color, className }) {
|
|
44777
|
-
return (0, react$1.createElement)(resolveEventKindIcon(iconId), {
|
|
44778
|
-
size,
|
|
44779
|
-
color,
|
|
44780
|
-
className
|
|
44781
|
-
});
|
|
44782
|
-
}
|
|
44783
|
-
//#endregion
|
|
44784
44794
|
//#region src/composites/filter-bar.tsx
|
|
44785
44795
|
function FilterBar({ filters, values, onChange, className }) {
|
|
44786
44796
|
const isMobile = useIsMobile();
|
|
@@ -48360,6 +48370,8 @@ function useSystemMutation(select, opts) {
|
|
|
48360
48370
|
* — the original admin-ui copy stayed put for backward compatibility
|
|
48361
48371
|
* but new consumers should import from here.
|
|
48362
48372
|
*/
|
|
48373
|
+
/** Trailing coalesce for event-driven invalidation — see the comment inside. */
|
|
48374
|
+
var EVENT_INVALIDATION_COALESCE_MS = 1e3;
|
|
48363
48375
|
function useEventInvalidation(queryKey, categories) {
|
|
48364
48376
|
const system = useSystem();
|
|
48365
48377
|
const queryClient = (0, _tanstack_react_query.useQueryClient)();
|
|
@@ -48373,12 +48385,20 @@ function useEventInvalidation(queryKey, categories) {
|
|
|
48373
48385
|
const keyJson = JSON.stringify(queryKey);
|
|
48374
48386
|
(0, react$1.useEffect)(() => {
|
|
48375
48387
|
const subs = [];
|
|
48376
|
-
|
|
48388
|
+
let pending = null;
|
|
48389
|
+
const refreshNow = () => {
|
|
48377
48390
|
const raw = JSON.parse(keyJson);
|
|
48378
48391
|
const queryKeyToInvalidate = raw.length === 1 && Array.isArray(raw[0]) ? raw : [raw];
|
|
48379
48392
|
queryClient.invalidateQueries({ queryKey: queryKeyToInvalidate });
|
|
48380
48393
|
};
|
|
48381
|
-
refresh()
|
|
48394
|
+
const refresh = () => {
|
|
48395
|
+
if (pending !== null) return;
|
|
48396
|
+
pending = setTimeout(() => {
|
|
48397
|
+
pending = null;
|
|
48398
|
+
refreshNow();
|
|
48399
|
+
}, EVENT_INVALIDATION_COALESCE_MS);
|
|
48400
|
+
};
|
|
48401
|
+
refreshNow();
|
|
48382
48402
|
for (const category of key.split("|")) {
|
|
48383
48403
|
if (!category) continue;
|
|
48384
48404
|
try {
|
|
@@ -48386,6 +48406,7 @@ function useEventInvalidation(queryKey, categories) {
|
|
|
48386
48406
|
} catch {}
|
|
48387
48407
|
}
|
|
48388
48408
|
return () => {
|
|
48409
|
+
if (pending !== null) clearTimeout(pending);
|
|
48389
48410
|
for (const unsub of subs) unsub();
|
|
48390
48411
|
};
|
|
48391
48412
|
}, [
|
package/dist/index.js
CHANGED
|
@@ -7137,6 +7137,115 @@ function useCustomFieldRenderer(type) {
|
|
|
7137
7137
|
return useContext(CustomFieldRenderersContext)[type] ?? null;
|
|
7138
7138
|
}
|
|
7139
7139
|
//#endregion
|
|
7140
|
+
//#region src/composites/event-kind-visuals.tsx
|
|
7141
|
+
/**
|
|
7142
|
+
* Event-kind VISUALS — the UI-side half of the unified taxonomy dictionary
|
|
7143
|
+
* (`@camstack/types` `EVENT_TAXONOMY` owns the serializable data:
|
|
7144
|
+
* color / iconId / labelKey; this owns `iconId → lucide component` and
|
|
7145
|
+
* `labelKey → t()`).
|
|
7146
|
+
*
|
|
7147
|
+
* Every UI that renders an event kind (timeline, events tree, chips,
|
|
7148
|
+
* detection canvas/tree) resolves its glyph + translated label here — no
|
|
7149
|
+
* per-component hardcoded icon or label.
|
|
7150
|
+
*/
|
|
7151
|
+
/**
|
|
7152
|
+
* `iconId` → lucide component. Built ONLY from statically-imported icons
|
|
7153
|
+
* (bundle-safe). Unknown ids resolve to the neutral `Tag` fallback.
|
|
7154
|
+
*/
|
|
7155
|
+
var EVENT_KIND_ICONS = {
|
|
7156
|
+
motion: Activity,
|
|
7157
|
+
audio: Volume2,
|
|
7158
|
+
person: User,
|
|
7159
|
+
vehicle: Car,
|
|
7160
|
+
animal: PawPrint,
|
|
7161
|
+
package: Package,
|
|
7162
|
+
sensor: Radio,
|
|
7163
|
+
control: SlidersHorizontal,
|
|
7164
|
+
car: Car,
|
|
7165
|
+
truck: Truck,
|
|
7166
|
+
bus: Bus,
|
|
7167
|
+
motorcycle: Bike,
|
|
7168
|
+
bicycle: Bike,
|
|
7169
|
+
airplane: Plane,
|
|
7170
|
+
boat: Sailboat,
|
|
7171
|
+
train: TrainFront,
|
|
7172
|
+
bird: Bird,
|
|
7173
|
+
cat: Cat,
|
|
7174
|
+
dog: Dog,
|
|
7175
|
+
horse: PawPrint,
|
|
7176
|
+
sheep: PawPrint,
|
|
7177
|
+
cow: PawPrint,
|
|
7178
|
+
elephant: PawPrint,
|
|
7179
|
+
bear: PawPrint,
|
|
7180
|
+
zebra: PawPrint,
|
|
7181
|
+
giraffe: PawPrint,
|
|
7182
|
+
door: DoorOpen,
|
|
7183
|
+
pir: Radar,
|
|
7184
|
+
smoke: Flame,
|
|
7185
|
+
water: Droplet,
|
|
7186
|
+
gas: Wind,
|
|
7187
|
+
vibration: Vibrate,
|
|
7188
|
+
tamper: ShieldAlert,
|
|
7189
|
+
presence: UserCheck,
|
|
7190
|
+
generic: Tag,
|
|
7191
|
+
lock: Lock,
|
|
7192
|
+
siren: Siren,
|
|
7193
|
+
switch: ToggleRight,
|
|
7194
|
+
doorbell: BellRing,
|
|
7195
|
+
button: CircleDot,
|
|
7196
|
+
"audio-speech": MessageSquare,
|
|
7197
|
+
"audio-scream": Megaphone,
|
|
7198
|
+
"audio-crying": Baby,
|
|
7199
|
+
"audio-laughter": Laugh,
|
|
7200
|
+
"audio-music": Music,
|
|
7201
|
+
"audio-dog": Dog,
|
|
7202
|
+
"audio-cat": Cat,
|
|
7203
|
+
"audio-bird": Bird,
|
|
7204
|
+
"audio-animal": PawPrint,
|
|
7205
|
+
"audio-alarm": BellRing,
|
|
7206
|
+
"audio-doorbell": BellRing,
|
|
7207
|
+
"audio-glass_breaking": TriangleAlert,
|
|
7208
|
+
"audio-gunshot": Crosshair,
|
|
7209
|
+
"audio-vehicle": Car,
|
|
7210
|
+
"audio-siren": Siren,
|
|
7211
|
+
"audio-fire": Flame,
|
|
7212
|
+
"audio-water": Droplets,
|
|
7213
|
+
"audio-wind": Wind,
|
|
7214
|
+
"audio-door": DoorOpen,
|
|
7215
|
+
"audio-footsteps": Footprints,
|
|
7216
|
+
"audio-crowd": Users,
|
|
7217
|
+
"audio-telephone": Phone,
|
|
7218
|
+
"audio-engine": Cog,
|
|
7219
|
+
"audio-tools": Hammer,
|
|
7220
|
+
"audio-silence": VolumeX
|
|
7221
|
+
};
|
|
7222
|
+
/** Resolve an `iconId` to a lucide component (falls back to `Tag`). */
|
|
7223
|
+
function resolveEventKindIcon(iconId) {
|
|
7224
|
+
if (Object.hasOwn(EVENT_KIND_ICONS, iconId)) return EVENT_KIND_ICONS[iconId];
|
|
7225
|
+
if (iconId.startsWith("audio-")) return Volume2;
|
|
7226
|
+
return Tag;
|
|
7227
|
+
}
|
|
7228
|
+
/**
|
|
7229
|
+
* Translated label for an event kind — `t(labelKey)` when a translation
|
|
7230
|
+
* exists, else the English `label` fallback. Robust to a missing key: an
|
|
7231
|
+
* i18n backend that echoes the key unchanged (react-i18next default) is
|
|
7232
|
+
* treated as "no translation" and the fallback label is returned, so the UI
|
|
7233
|
+
* never renders a raw `eventKind.*` key.
|
|
7234
|
+
*/
|
|
7235
|
+
function eventKindLabel(descriptor, t) {
|
|
7236
|
+
if (t === void 0) return descriptor.label;
|
|
7237
|
+
const translated = t(descriptor.labelKey);
|
|
7238
|
+
return translated === descriptor.labelKey || translated.length === 0 ? descriptor.label : translated;
|
|
7239
|
+
}
|
|
7240
|
+
/** Small convenience component: renders the lucide glyph for an `iconId`. */
|
|
7241
|
+
function EventKindGlyph({ iconId, size = 16, color, className }) {
|
|
7242
|
+
return createElement(resolveEventKindIcon(iconId), {
|
|
7243
|
+
size,
|
|
7244
|
+
color,
|
|
7245
|
+
className
|
|
7246
|
+
});
|
|
7247
|
+
}
|
|
7248
|
+
//#endregion
|
|
7140
7249
|
//#region src/composites/confirm-dialog.tsx
|
|
7141
7250
|
var ConfirmContext = createSharedContext("camstack:confirm-dialog", null);
|
|
7142
7251
|
function useConfirm() {
|
|
@@ -19703,13 +19812,20 @@ function MultiSelectField({ field, value, onChange, disabled, translationFn }) {
|
|
|
19703
19812
|
checked ? "border-primary bg-primary/10 text-primary" : "border-border bg-background text-foreground hover:bg-surface",
|
|
19704
19813
|
disabled || field.disabled ? "opacity-50 cursor-not-allowed" : ""
|
|
19705
19814
|
].join(" "),
|
|
19706
|
-
children: [
|
|
19707
|
-
|
|
19708
|
-
|
|
19709
|
-
|
|
19710
|
-
|
|
19711
|
-
|
|
19712
|
-
|
|
19815
|
+
children: [
|
|
19816
|
+
/* @__PURE__ */ jsx("input", {
|
|
19817
|
+
type: "checkbox",
|
|
19818
|
+
className: "sr-only",
|
|
19819
|
+
checked,
|
|
19820
|
+
disabled: disabled || field.disabled,
|
|
19821
|
+
onChange: () => toggle(opt.value)
|
|
19822
|
+
}),
|
|
19823
|
+
opt.iconId !== void 0 && /* @__PURE__ */ jsx(EventKindGlyph, {
|
|
19824
|
+
iconId: opt.iconId,
|
|
19825
|
+
size: 13
|
|
19826
|
+
}),
|
|
19827
|
+
opt.label
|
|
19828
|
+
]
|
|
19713
19829
|
}, opt.value);
|
|
19714
19830
|
})
|
|
19715
19831
|
})
|
|
@@ -21591,7 +21707,7 @@ function GroupedModelSelector({ catalog, value, onChange, disabled }) {
|
|
|
21591
21707
|
const resolutions = [...new Set(tier.options.map((o) => o.resolution))].sort((a, b) => (b ?? Infinity) - (a ?? Infinity));
|
|
21592
21708
|
const selectedResolution = resolutions.includes(current?.resolution) ? current?.resolution : resolutions[0];
|
|
21593
21709
|
const variantOptions = tier.options.filter((o) => o.resolution === selectedResolution);
|
|
21594
|
-
const resLabel = (r) => r === void 0 ? "
|
|
21710
|
+
const resLabel = (r) => r === void 0 ? "native" : `${r}`;
|
|
21595
21711
|
const selectTier = (tierId) => {
|
|
21596
21712
|
const t = family.tiers.find((x) => x.tier === tierId);
|
|
21597
21713
|
if (!t) return;
|
|
@@ -21635,7 +21751,7 @@ function GroupedModelSelector({ catalog, value, onChange, disabled }) {
|
|
|
21635
21751
|
className: "grid grid-cols-2 gap-1.5 sm:grid-cols-4",
|
|
21636
21752
|
children: family.tiers.map((t) => {
|
|
21637
21753
|
const active = t.tier === tier.tier;
|
|
21638
|
-
const
|
|
21754
|
+
const quoted = t.options.find((o) => o.resolution === selectedResolution && o.precision === "fp32") ?? t.options.find((o) => o.modelId === t.baseModelId) ?? t.options[0];
|
|
21639
21755
|
return /* @__PURE__ */ jsxs("button", {
|
|
21640
21756
|
type: "button",
|
|
21641
21757
|
disabled,
|
|
@@ -21651,7 +21767,7 @@ function GroupedModelSelector({ catalog, value, onChange, disabled }) {
|
|
|
21651
21767
|
className: "text-[10px] text-foreground-subtle",
|
|
21652
21768
|
children: [
|
|
21653
21769
|
"~",
|
|
21654
|
-
|
|
21770
|
+
quoted?.sizeMB ?? 0,
|
|
21655
21771
|
" MB"
|
|
21656
21772
|
]
|
|
21657
21773
|
})]
|
|
@@ -21951,12 +22067,15 @@ function ConfigMultiSelect({ label, description, value, options, disabled, onCha
|
|
|
21951
22067
|
/* @__PURE__ */ jsx("div", {
|
|
21952
22068
|
className: "flex flex-wrap gap-1.5",
|
|
21953
22069
|
children: options.map((o) => {
|
|
21954
|
-
return /* @__PURE__ */
|
|
22070
|
+
return /* @__PURE__ */ jsxs("button", {
|
|
21955
22071
|
type: "button",
|
|
21956
22072
|
disabled,
|
|
21957
22073
|
onClick: () => toggle(o.value),
|
|
21958
|
-
className: cn("text-[10px] font-medium px-2 py-1 rounded-md border transition-colors", value.includes(o.value) ? "bg-primary/20 text-primary border-primary/40" : "bg-surface text-foreground-subtle border-border hover:border-primary/30", disabled && "opacity-50 cursor-not-allowed"),
|
|
21959
|
-
children: o.
|
|
22074
|
+
className: cn("inline-flex items-center gap-1 text-[10px] font-medium px-2 py-1 rounded-md border transition-colors", value.includes(o.value) ? "bg-primary/20 text-primary border-primary/40" : "bg-surface text-foreground-subtle border-border hover:border-primary/30", disabled && "opacity-50 cursor-not-allowed"),
|
|
22075
|
+
children: [o.iconId !== void 0 && /* @__PURE__ */ jsx(EventKindGlyph, {
|
|
22076
|
+
iconId: o.iconId,
|
|
22077
|
+
size: 12
|
|
22078
|
+
}), o.label]
|
|
21960
22079
|
}, o.value);
|
|
21961
22080
|
})
|
|
21962
22081
|
})
|
|
@@ -44648,115 +44767,6 @@ function DoorbellRecentPanel({ history, limit = 5, latestIsFresh, className }) {
|
|
|
44648
44767
|
});
|
|
44649
44768
|
}
|
|
44650
44769
|
//#endregion
|
|
44651
|
-
//#region src/composites/event-kind-visuals.tsx
|
|
44652
|
-
/**
|
|
44653
|
-
* Event-kind VISUALS — the UI-side half of the unified taxonomy dictionary
|
|
44654
|
-
* (`@camstack/types` `EVENT_TAXONOMY` owns the serializable data:
|
|
44655
|
-
* color / iconId / labelKey; this owns `iconId → lucide component` and
|
|
44656
|
-
* `labelKey → t()`).
|
|
44657
|
-
*
|
|
44658
|
-
* Every UI that renders an event kind (timeline, events tree, chips,
|
|
44659
|
-
* detection canvas/tree) resolves its glyph + translated label here — no
|
|
44660
|
-
* per-component hardcoded icon or label.
|
|
44661
|
-
*/
|
|
44662
|
-
/**
|
|
44663
|
-
* `iconId` → lucide component. Built ONLY from statically-imported icons
|
|
44664
|
-
* (bundle-safe). Unknown ids resolve to the neutral `Tag` fallback.
|
|
44665
|
-
*/
|
|
44666
|
-
var EVENT_KIND_ICONS = {
|
|
44667
|
-
motion: Activity,
|
|
44668
|
-
audio: Volume2,
|
|
44669
|
-
person: User,
|
|
44670
|
-
vehicle: Car,
|
|
44671
|
-
animal: PawPrint,
|
|
44672
|
-
package: Package,
|
|
44673
|
-
sensor: Radio,
|
|
44674
|
-
control: SlidersHorizontal,
|
|
44675
|
-
car: Car,
|
|
44676
|
-
truck: Truck,
|
|
44677
|
-
bus: Bus,
|
|
44678
|
-
motorcycle: Bike,
|
|
44679
|
-
bicycle: Bike,
|
|
44680
|
-
airplane: Plane,
|
|
44681
|
-
boat: Sailboat,
|
|
44682
|
-
train: TrainFront,
|
|
44683
|
-
bird: Bird,
|
|
44684
|
-
cat: Cat,
|
|
44685
|
-
dog: Dog,
|
|
44686
|
-
horse: PawPrint,
|
|
44687
|
-
sheep: PawPrint,
|
|
44688
|
-
cow: PawPrint,
|
|
44689
|
-
elephant: PawPrint,
|
|
44690
|
-
bear: PawPrint,
|
|
44691
|
-
zebra: PawPrint,
|
|
44692
|
-
giraffe: PawPrint,
|
|
44693
|
-
door: DoorOpen,
|
|
44694
|
-
pir: Radar,
|
|
44695
|
-
smoke: Flame,
|
|
44696
|
-
water: Droplet,
|
|
44697
|
-
gas: Wind,
|
|
44698
|
-
vibration: Vibrate,
|
|
44699
|
-
tamper: ShieldAlert,
|
|
44700
|
-
presence: UserCheck,
|
|
44701
|
-
generic: Tag,
|
|
44702
|
-
lock: Lock,
|
|
44703
|
-
siren: Siren,
|
|
44704
|
-
switch: ToggleRight,
|
|
44705
|
-
doorbell: BellRing,
|
|
44706
|
-
button: CircleDot,
|
|
44707
|
-
"audio-speech": MessageSquare,
|
|
44708
|
-
"audio-scream": Megaphone,
|
|
44709
|
-
"audio-crying": Baby,
|
|
44710
|
-
"audio-laughter": Laugh,
|
|
44711
|
-
"audio-music": Music,
|
|
44712
|
-
"audio-dog": Dog,
|
|
44713
|
-
"audio-cat": Cat,
|
|
44714
|
-
"audio-bird": Bird,
|
|
44715
|
-
"audio-animal": PawPrint,
|
|
44716
|
-
"audio-alarm": BellRing,
|
|
44717
|
-
"audio-doorbell": BellRing,
|
|
44718
|
-
"audio-glass_breaking": TriangleAlert,
|
|
44719
|
-
"audio-gunshot": Crosshair,
|
|
44720
|
-
"audio-vehicle": Car,
|
|
44721
|
-
"audio-siren": Siren,
|
|
44722
|
-
"audio-fire": Flame,
|
|
44723
|
-
"audio-water": Droplets,
|
|
44724
|
-
"audio-wind": Wind,
|
|
44725
|
-
"audio-door": DoorOpen,
|
|
44726
|
-
"audio-footsteps": Footprints,
|
|
44727
|
-
"audio-crowd": Users,
|
|
44728
|
-
"audio-telephone": Phone,
|
|
44729
|
-
"audio-engine": Cog,
|
|
44730
|
-
"audio-tools": Hammer,
|
|
44731
|
-
"audio-silence": VolumeX
|
|
44732
|
-
};
|
|
44733
|
-
/** Resolve an `iconId` to a lucide component (falls back to `Tag`). */
|
|
44734
|
-
function resolveEventKindIcon(iconId) {
|
|
44735
|
-
if (Object.hasOwn(EVENT_KIND_ICONS, iconId)) return EVENT_KIND_ICONS[iconId];
|
|
44736
|
-
if (iconId.startsWith("audio-")) return Volume2;
|
|
44737
|
-
return Tag;
|
|
44738
|
-
}
|
|
44739
|
-
/**
|
|
44740
|
-
* Translated label for an event kind — `t(labelKey)` when a translation
|
|
44741
|
-
* exists, else the English `label` fallback. Robust to a missing key: an
|
|
44742
|
-
* i18n backend that echoes the key unchanged (react-i18next default) is
|
|
44743
|
-
* treated as "no translation" and the fallback label is returned, so the UI
|
|
44744
|
-
* never renders a raw `eventKind.*` key.
|
|
44745
|
-
*/
|
|
44746
|
-
function eventKindLabel(descriptor, t) {
|
|
44747
|
-
if (t === void 0) return descriptor.label;
|
|
44748
|
-
const translated = t(descriptor.labelKey);
|
|
44749
|
-
return translated === descriptor.labelKey || translated.length === 0 ? descriptor.label : translated;
|
|
44750
|
-
}
|
|
44751
|
-
/** Small convenience component: renders the lucide glyph for an `iconId`. */
|
|
44752
|
-
function EventKindGlyph({ iconId, size = 16, color, className }) {
|
|
44753
|
-
return createElement(resolveEventKindIcon(iconId), {
|
|
44754
|
-
size,
|
|
44755
|
-
color,
|
|
44756
|
-
className
|
|
44757
|
-
});
|
|
44758
|
-
}
|
|
44759
|
-
//#endregion
|
|
44760
44770
|
//#region src/composites/filter-bar.tsx
|
|
44761
44771
|
function FilterBar({ filters, values, onChange, className }) {
|
|
44762
44772
|
const isMobile = useIsMobile();
|
|
@@ -48336,6 +48346,8 @@ function useSystemMutation(select, opts) {
|
|
|
48336
48346
|
* — the original admin-ui copy stayed put for backward compatibility
|
|
48337
48347
|
* but new consumers should import from here.
|
|
48338
48348
|
*/
|
|
48349
|
+
/** Trailing coalesce for event-driven invalidation — see the comment inside. */
|
|
48350
|
+
var EVENT_INVALIDATION_COALESCE_MS = 1e3;
|
|
48339
48351
|
function useEventInvalidation(queryKey, categories) {
|
|
48340
48352
|
const system = useSystem();
|
|
48341
48353
|
const queryClient = useQueryClient();
|
|
@@ -48349,12 +48361,20 @@ function useEventInvalidation(queryKey, categories) {
|
|
|
48349
48361
|
const keyJson = JSON.stringify(queryKey);
|
|
48350
48362
|
useEffect(() => {
|
|
48351
48363
|
const subs = [];
|
|
48352
|
-
|
|
48364
|
+
let pending = null;
|
|
48365
|
+
const refreshNow = () => {
|
|
48353
48366
|
const raw = JSON.parse(keyJson);
|
|
48354
48367
|
const queryKeyToInvalidate = raw.length === 1 && Array.isArray(raw[0]) ? raw : [raw];
|
|
48355
48368
|
queryClient.invalidateQueries({ queryKey: queryKeyToInvalidate });
|
|
48356
48369
|
};
|
|
48357
|
-
refresh()
|
|
48370
|
+
const refresh = () => {
|
|
48371
|
+
if (pending !== null) return;
|
|
48372
|
+
pending = setTimeout(() => {
|
|
48373
|
+
pending = null;
|
|
48374
|
+
refreshNow();
|
|
48375
|
+
}, EVENT_INVALIDATION_COALESCE_MS);
|
|
48376
|
+
};
|
|
48377
|
+
refreshNow();
|
|
48358
48378
|
for (const category of key.split("|")) {
|
|
48359
48379
|
if (!category) continue;
|
|
48360
48380
|
try {
|
|
@@ -48362,6 +48382,7 @@ function useEventInvalidation(queryKey, categories) {
|
|
|
48362
48382
|
} catch {}
|
|
48363
48383
|
}
|
|
48364
48384
|
return () => {
|
|
48385
|
+
if (pending !== null) clearTimeout(pending);
|
|
48365
48386
|
for (const unsub of subs) unsub();
|
|
48366
48387
|
};
|
|
48367
48388
|
}, [
|
|
@@ -32,7 +32,7 @@ export declare function DialogTrigger({ children, ...props }: HTMLAttributes<HTM
|
|
|
32
32
|
*/
|
|
33
33
|
declare const contentVariants: (props?: ({
|
|
34
34
|
width?: "sm" | "md" | "lg" | null | undefined;
|
|
35
|
-
scroll?: "
|
|
35
|
+
scroll?: "body" | "content" | null | undefined;
|
|
36
36
|
placement?: "center" | "sheet-on-mobile" | null | undefined;
|
|
37
37
|
} & import('class-variance-authority/types').ClassProp) | undefined) => string;
|
|
38
38
|
export type DialogPlacement = NonNullable<VariantProps<typeof contentVariants>['placement']>;
|