@camstack/ui-library 0.1.25 → 0.1.27
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 +1886 -124
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +304 -3
- package/dist/index.d.ts +304 -3
- package/dist/index.js +1826 -92
- package/dist/index.js.map +1 -1
- package/package.json +10 -1
package/dist/index.cjs
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
8
|
var __export = (target, all) => {
|
|
7
9
|
for (var name in all)
|
|
@@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
17
|
}
|
|
16
18
|
return to;
|
|
17
19
|
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
18
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
29
|
|
|
20
30
|
// src/index.ts
|
|
@@ -23,11 +33,17 @@ __export(src_exports, {
|
|
|
23
33
|
AppShell: () => AppShell,
|
|
24
34
|
Badge: () => Badge,
|
|
25
35
|
Button: () => Button,
|
|
36
|
+
CLASS_COLORS: () => CLASS_COLORS,
|
|
26
37
|
Card: () => Card,
|
|
27
38
|
Checkbox: () => Checkbox,
|
|
28
39
|
CodeBlock: () => CodeBlock,
|
|
29
40
|
ConfirmDialog: () => ConfirmDialog,
|
|
41
|
+
DEFAULT_CLASS_COLORS: () => DEFAULT_CLASS_COLORS,
|
|
42
|
+
DEFAULT_COLOR: () => DEFAULT_COLOR,
|
|
30
43
|
DataTable: () => DataTable,
|
|
44
|
+
DetectionCanvas: () => DetectionCanvas,
|
|
45
|
+
DetectionResultTree: () => DetectionResultTree,
|
|
46
|
+
DevShell: () => DevShell,
|
|
31
47
|
DeviceCard: () => DeviceCard,
|
|
32
48
|
DeviceGrid: () => DeviceGrid,
|
|
33
49
|
Dialog: () => Dialog,
|
|
@@ -46,22 +62,30 @@ __export(src_exports, {
|
|
|
46
62
|
FloatingPanel: () => FloatingPanel,
|
|
47
63
|
FormField: () => FormField,
|
|
48
64
|
IconButton: () => IconButton,
|
|
65
|
+
ImageSelector: () => ImageSelector,
|
|
66
|
+
InferenceConfigSelector: () => InferenceConfigSelector,
|
|
49
67
|
Input: () => Input,
|
|
50
68
|
KeyValueList: () => KeyValueList,
|
|
51
69
|
Label: () => Label,
|
|
70
|
+
LoginForm: () => LoginForm,
|
|
52
71
|
PageHeader: () => PageHeader,
|
|
72
|
+
PipelineBuilder: () => PipelineBuilder,
|
|
73
|
+
PipelineRuntimeSelector: () => PipelineRuntimeSelector,
|
|
74
|
+
PipelineStep: () => PipelineStep,
|
|
53
75
|
Popover: () => Popover,
|
|
54
76
|
PopoverContent: () => PopoverContent,
|
|
55
77
|
PopoverTrigger: () => PopoverTrigger,
|
|
56
78
|
ProviderBadge: () => ProviderBadge,
|
|
57
79
|
ScrollArea: () => ScrollArea,
|
|
58
80
|
Select: () => Select,
|
|
81
|
+
SemanticBadge: () => SemanticBadge,
|
|
59
82
|
Separator: () => Separator,
|
|
60
83
|
Sidebar: () => Sidebar,
|
|
61
84
|
SidebarItem: () => SidebarItem,
|
|
62
85
|
Skeleton: () => Skeleton,
|
|
63
86
|
StatCard: () => StatCard,
|
|
64
87
|
StatusBadge: () => StatusBadge,
|
|
88
|
+
StepTimings: () => StepTimings,
|
|
65
89
|
Switch: () => Switch,
|
|
66
90
|
Tabs: () => Tabs,
|
|
67
91
|
TabsContent: () => TabsContent,
|
|
@@ -71,14 +95,18 @@ __export(src_exports, {
|
|
|
71
95
|
Tooltip: () => Tooltip,
|
|
72
96
|
TooltipContent: () => TooltipContent,
|
|
73
97
|
TooltipTrigger: () => TooltipTrigger,
|
|
98
|
+
VersionBadge: () => VersionBadge,
|
|
74
99
|
cn: () => cn,
|
|
75
100
|
createTheme: () => createTheme,
|
|
76
101
|
darkColors: () => darkColors,
|
|
77
102
|
defaultTheme: () => defaultTheme,
|
|
103
|
+
getClassColor: () => getClassColor,
|
|
78
104
|
lightColors: () => lightColors,
|
|
105
|
+
mountAddonPage: () => mountAddonPage,
|
|
79
106
|
providerIcons: () => providerIcons,
|
|
80
107
|
statusIcons: () => statusIcons,
|
|
81
108
|
themeToCss: () => themeToCss,
|
|
109
|
+
useDevShell: () => useDevShell,
|
|
82
110
|
useThemeMode: () => useThemeMode
|
|
83
111
|
});
|
|
84
112
|
module.exports = __toCommonJS(src_exports);
|
|
@@ -1322,8 +1350,30 @@ function ProviderBadge({
|
|
|
1322
1350
|
] });
|
|
1323
1351
|
}
|
|
1324
1352
|
|
|
1325
|
-
// src/composites/
|
|
1353
|
+
// src/composites/version-badge.tsx
|
|
1326
1354
|
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
1355
|
+
var VARIANT_STYLES = {
|
|
1356
|
+
success: "bg-emerald-400 text-emerald-950",
|
|
1357
|
+
warning: "bg-amber-400 text-amber-950",
|
|
1358
|
+
danger: "bg-red-400 text-red-950",
|
|
1359
|
+
info: "bg-blue-400 text-blue-950",
|
|
1360
|
+
neutral: "bg-foreground-subtle/20 text-foreground"
|
|
1361
|
+
};
|
|
1362
|
+
function SemanticBadge({ children, variant = "neutral", mono, className }) {
|
|
1363
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: cn(
|
|
1364
|
+
"inline-flex items-center rounded-md px-2 py-0.5 text-[11px] font-bold leading-tight",
|
|
1365
|
+
mono && "font-mono",
|
|
1366
|
+
VARIANT_STYLES[variant],
|
|
1367
|
+
className
|
|
1368
|
+
), children });
|
|
1369
|
+
}
|
|
1370
|
+
function VersionBadge({ version, preRelease, className }) {
|
|
1371
|
+
const isPreRelease = preRelease ?? /-(alpha|beta|rc|dev|canary|next)/i.test(version);
|
|
1372
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(SemanticBadge, { variant: isPreRelease ? "warning" : "success", mono: true, className, children: version });
|
|
1373
|
+
}
|
|
1374
|
+
|
|
1375
|
+
// src/composites/form-field.tsx
|
|
1376
|
+
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
1327
1377
|
function FormField({
|
|
1328
1378
|
label,
|
|
1329
1379
|
description,
|
|
@@ -1334,7 +1384,7 @@ function FormField({
|
|
|
1334
1384
|
className
|
|
1335
1385
|
}) {
|
|
1336
1386
|
const isHorizontal = orientation === "horizontal";
|
|
1337
|
-
return /* @__PURE__ */ (0,
|
|
1387
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
|
|
1338
1388
|
"div",
|
|
1339
1389
|
{
|
|
1340
1390
|
className: cn(
|
|
@@ -1343,34 +1393,34 @@ function FormField({
|
|
|
1343
1393
|
className
|
|
1344
1394
|
),
|
|
1345
1395
|
children: [
|
|
1346
|
-
/* @__PURE__ */ (0,
|
|
1347
|
-
/* @__PURE__ */ (0,
|
|
1396
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: cn(isHorizontal ? "flex-1" : ""), children: [
|
|
1397
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(Label, { children: [
|
|
1348
1398
|
label,
|
|
1349
|
-
required && /* @__PURE__ */ (0,
|
|
1399
|
+
required && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "text-danger ml-0.5", children: "*" })
|
|
1350
1400
|
] }),
|
|
1351
|
-
description && /* @__PURE__ */ (0,
|
|
1401
|
+
description && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { className: "text-foreground-subtle text-xs mt-0.5", children: description })
|
|
1352
1402
|
] }),
|
|
1353
|
-
/* @__PURE__ */ (0,
|
|
1354
|
-
error && /* @__PURE__ */ (0,
|
|
1403
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: cn(isHorizontal ? "shrink-0" : ""), children }),
|
|
1404
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { className: "text-danger text-xs", children: error })
|
|
1355
1405
|
]
|
|
1356
1406
|
}
|
|
1357
1407
|
);
|
|
1358
1408
|
}
|
|
1359
1409
|
|
|
1360
1410
|
// src/composites/page-header.tsx
|
|
1361
|
-
var
|
|
1411
|
+
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
1362
1412
|
function PageHeader({ title, subtitle, actions, className }) {
|
|
1363
|
-
return /* @__PURE__ */ (0,
|
|
1364
|
-
/* @__PURE__ */ (0,
|
|
1365
|
-
/* @__PURE__ */ (0,
|
|
1366
|
-
subtitle && /* @__PURE__ */ (0,
|
|
1413
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: cn("flex items-center justify-between mb-3", className), children: [
|
|
1414
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { children: [
|
|
1415
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("h1", { className: "text-sm font-semibold text-foreground", children: title }),
|
|
1416
|
+
subtitle && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("p", { className: "text-foreground-subtle text-xs", children: subtitle })
|
|
1367
1417
|
] }),
|
|
1368
|
-
actions && /* @__PURE__ */ (0,
|
|
1418
|
+
actions && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "flex items-center gap-2", children: actions })
|
|
1369
1419
|
] });
|
|
1370
1420
|
}
|
|
1371
1421
|
|
|
1372
1422
|
// src/composites/empty-state.tsx
|
|
1373
|
-
var
|
|
1423
|
+
var import_jsx_runtime25 = require("react/jsx-runtime");
|
|
1374
1424
|
function EmptyState({
|
|
1375
1425
|
icon: Icon,
|
|
1376
1426
|
title,
|
|
@@ -1378,18 +1428,18 @@ function EmptyState({
|
|
|
1378
1428
|
action,
|
|
1379
1429
|
className
|
|
1380
1430
|
}) {
|
|
1381
|
-
return /* @__PURE__ */ (0,
|
|
1382
|
-
Icon && /* @__PURE__ */ (0,
|
|
1383
|
-
/* @__PURE__ */ (0,
|
|
1384
|
-
/* @__PURE__ */ (0,
|
|
1385
|
-
description && /* @__PURE__ */ (0,
|
|
1431
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: cn("flex flex-col items-center justify-center gap-3 py-12", className), children: [
|
|
1432
|
+
Icon && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Icon, { className: "h-12 w-12 text-foreground-subtle", "aria-hidden": "true" }),
|
|
1433
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex flex-col items-center gap-1 text-center", children: [
|
|
1434
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("p", { className: "text-foreground-muted text-sm font-medium", children: title }),
|
|
1435
|
+
description && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("p", { className: "text-foreground-subtle text-xs max-w-xs", children: description })
|
|
1386
1436
|
] }),
|
|
1387
|
-
action && /* @__PURE__ */ (0,
|
|
1437
|
+
action && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "mt-1", children: action })
|
|
1388
1438
|
] });
|
|
1389
1439
|
}
|
|
1390
1440
|
|
|
1391
1441
|
// src/composites/confirm-dialog.tsx
|
|
1392
|
-
var
|
|
1442
|
+
var import_jsx_runtime26 = require("react/jsx-runtime");
|
|
1393
1443
|
function ConfirmDialog({
|
|
1394
1444
|
title,
|
|
1395
1445
|
message,
|
|
@@ -1401,14 +1451,14 @@ function ConfirmDialog({
|
|
|
1401
1451
|
open,
|
|
1402
1452
|
onOpenChange
|
|
1403
1453
|
}) {
|
|
1404
|
-
return /* @__PURE__ */ (0,
|
|
1405
|
-
/* @__PURE__ */ (0,
|
|
1406
|
-
/* @__PURE__ */ (0,
|
|
1407
|
-
/* @__PURE__ */ (0,
|
|
1454
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(Dialog, { open, onOpenChange, children: /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(DialogContent, { children: [
|
|
1455
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(DialogHeader, { children: [
|
|
1456
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(DialogTitle, { children: title }),
|
|
1457
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(DialogDescription, { children: message })
|
|
1408
1458
|
] }),
|
|
1409
|
-
/* @__PURE__ */ (0,
|
|
1410
|
-
/* @__PURE__ */ (0,
|
|
1411
|
-
/* @__PURE__ */ (0,
|
|
1459
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(DialogFooter, { children: [
|
|
1460
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(Button, { variant: "ghost", onClick: onCancel, children: cancelLabel }),
|
|
1461
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
1412
1462
|
Button,
|
|
1413
1463
|
{
|
|
1414
1464
|
variant: variant === "danger" ? "danger" : "primary",
|
|
@@ -1422,12 +1472,12 @@ function ConfirmDialog({
|
|
|
1422
1472
|
|
|
1423
1473
|
// src/composites/stat-card.tsx
|
|
1424
1474
|
var import_lucide_react5 = require("lucide-react");
|
|
1425
|
-
var
|
|
1475
|
+
var import_jsx_runtime27 = require("react/jsx-runtime");
|
|
1426
1476
|
function StatCard({ value, label, trend, className }) {
|
|
1427
|
-
return /* @__PURE__ */ (0,
|
|
1428
|
-
/* @__PURE__ */ (0,
|
|
1429
|
-
/* @__PURE__ */ (0,
|
|
1430
|
-
trend && /* @__PURE__ */ (0,
|
|
1477
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(Card, { className: cn("flex flex-col gap-1", className), children: [
|
|
1478
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex items-baseline gap-2", children: [
|
|
1479
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "text-2xl font-semibold text-foreground", children: value }),
|
|
1480
|
+
trend && /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
|
|
1431
1481
|
"span",
|
|
1432
1482
|
{
|
|
1433
1483
|
className: cn(
|
|
@@ -1435,27 +1485,27 @@ function StatCard({ value, label, trend, className }) {
|
|
|
1435
1485
|
trend.direction === "up" ? "text-success" : "text-danger"
|
|
1436
1486
|
),
|
|
1437
1487
|
children: [
|
|
1438
|
-
trend.direction === "up" ? /* @__PURE__ */ (0,
|
|
1488
|
+
trend.direction === "up" ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_lucide_react5.TrendingUp, { className: "h-3 w-3" }) : /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_lucide_react5.TrendingDown, { className: "h-3 w-3" }),
|
|
1439
1489
|
trend.value,
|
|
1440
1490
|
"%"
|
|
1441
1491
|
]
|
|
1442
1492
|
}
|
|
1443
1493
|
)
|
|
1444
1494
|
] }),
|
|
1445
|
-
/* @__PURE__ */ (0,
|
|
1495
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "text-xs text-foreground-muted", children: label })
|
|
1446
1496
|
] });
|
|
1447
1497
|
}
|
|
1448
1498
|
|
|
1449
1499
|
// src/composites/key-value-list.tsx
|
|
1450
|
-
var
|
|
1500
|
+
var import_jsx_runtime28 = require("react/jsx-runtime");
|
|
1451
1501
|
function KeyValueList({ items, className }) {
|
|
1452
|
-
return /* @__PURE__ */ (0,
|
|
1502
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("dl", { className: cn("flex flex-col", className), children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
|
|
1453
1503
|
"div",
|
|
1454
1504
|
{
|
|
1455
1505
|
className: "flex items-center h-7",
|
|
1456
1506
|
children: [
|
|
1457
|
-
/* @__PURE__ */ (0,
|
|
1458
|
-
/* @__PURE__ */ (0,
|
|
1507
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("dt", { className: "text-foreground-subtle text-xs w-1/3 shrink-0", children: item.key }),
|
|
1508
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("dd", { className: "text-foreground text-xs", children: item.value })
|
|
1459
1509
|
]
|
|
1460
1510
|
},
|
|
1461
1511
|
item.key
|
|
@@ -1465,7 +1515,7 @@ function KeyValueList({ items, className }) {
|
|
|
1465
1515
|
// src/composites/code-block.tsx
|
|
1466
1516
|
var import_react21 = require("react");
|
|
1467
1517
|
var import_lucide_react6 = require("lucide-react");
|
|
1468
|
-
var
|
|
1518
|
+
var import_jsx_runtime29 = require("react/jsx-runtime");
|
|
1469
1519
|
function CodeBlock({ children, maxHeight = 300, className }) {
|
|
1470
1520
|
const [copied, setCopied] = (0, import_react21.useState)(false);
|
|
1471
1521
|
const handleCopy = (0, import_react21.useCallback)(() => {
|
|
@@ -1474,9 +1524,9 @@ function CodeBlock({ children, maxHeight = 300, className }) {
|
|
|
1474
1524
|
setTimeout(() => setCopied(false), 2e3);
|
|
1475
1525
|
});
|
|
1476
1526
|
}, [children]);
|
|
1477
|
-
return /* @__PURE__ */ (0,
|
|
1478
|
-
/* @__PURE__ */ (0,
|
|
1479
|
-
/* @__PURE__ */ (0,
|
|
1527
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: cn("relative group", className), children: [
|
|
1528
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(ScrollArea, { style: { maxHeight }, children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("pre", { className: "font-mono text-xs bg-surface p-3 rounded-md border border-border-subtle", children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("code", { children }) }) }),
|
|
1529
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "absolute top-2 right-2 opacity-0 group-hover:opacity-100 transition-opacity", children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
1480
1530
|
IconButton,
|
|
1481
1531
|
{
|
|
1482
1532
|
icon: copied ? import_lucide_react6.Check : import_lucide_react6.Copy,
|
|
@@ -1491,27 +1541,27 @@ function CodeBlock({ children, maxHeight = 300, className }) {
|
|
|
1491
1541
|
|
|
1492
1542
|
// src/composites/filter-bar.tsx
|
|
1493
1543
|
var import_lucide_react7 = require("lucide-react");
|
|
1494
|
-
var
|
|
1544
|
+
var import_jsx_runtime30 = require("react/jsx-runtime");
|
|
1495
1545
|
function FilterBar({ filters, values, onChange, className }) {
|
|
1496
1546
|
const handleChange = (key, value) => {
|
|
1497
1547
|
onChange({ ...values, [key]: value });
|
|
1498
1548
|
};
|
|
1499
|
-
return /* @__PURE__ */ (0,
|
|
1549
|
+
return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("div", { className: cn("flex items-center gap-2 flex-wrap", className), children: filters.map((filter) => {
|
|
1500
1550
|
switch (filter.type) {
|
|
1501
1551
|
case "search":
|
|
1502
|
-
return /* @__PURE__ */ (0,
|
|
1552
|
+
return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
|
|
1503
1553
|
Input,
|
|
1504
1554
|
{
|
|
1505
1555
|
placeholder: filter.placeholder ?? "Search...",
|
|
1506
1556
|
value: values[filter.key] ?? "",
|
|
1507
1557
|
onChange: (e) => handleChange(filter.key, e.target.value),
|
|
1508
|
-
leftSlot: /* @__PURE__ */ (0,
|
|
1558
|
+
leftSlot: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_lucide_react7.Search, { className: "h-3 w-3 text-foreground-subtle" }),
|
|
1509
1559
|
className: "w-48"
|
|
1510
1560
|
},
|
|
1511
1561
|
filter.key
|
|
1512
1562
|
);
|
|
1513
1563
|
case "select":
|
|
1514
|
-
return /* @__PURE__ */ (0,
|
|
1564
|
+
return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
|
|
1515
1565
|
Select,
|
|
1516
1566
|
{
|
|
1517
1567
|
options: filter.options,
|
|
@@ -1522,10 +1572,10 @@ function FilterBar({ filters, values, onChange, className }) {
|
|
|
1522
1572
|
filter.key
|
|
1523
1573
|
);
|
|
1524
1574
|
case "badge-toggle":
|
|
1525
|
-
return /* @__PURE__ */ (0,
|
|
1575
|
+
return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("div", { className: "flex items-center gap-1", children: filter.options.map((option) => {
|
|
1526
1576
|
const currentValue = values[filter.key];
|
|
1527
1577
|
const isActive = currentValue === option.value;
|
|
1528
|
-
return /* @__PURE__ */ (0,
|
|
1578
|
+
return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
|
|
1529
1579
|
"button",
|
|
1530
1580
|
{
|
|
1531
1581
|
type: "button",
|
|
@@ -1533,7 +1583,7 @@ function FilterBar({ filters, values, onChange, className }) {
|
|
|
1533
1583
|
filter.key,
|
|
1534
1584
|
isActive ? void 0 : option.value
|
|
1535
1585
|
),
|
|
1536
|
-
children: /* @__PURE__ */ (0,
|
|
1586
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
|
|
1537
1587
|
Badge,
|
|
1538
1588
|
{
|
|
1539
1589
|
variant: isActive ? "info" : "default",
|
|
@@ -1552,7 +1602,7 @@ function FilterBar({ filters, values, onChange, className }) {
|
|
|
1552
1602
|
}
|
|
1553
1603
|
|
|
1554
1604
|
// src/composites/app-shell/sidebar-item.tsx
|
|
1555
|
-
var
|
|
1605
|
+
var import_jsx_runtime31 = require("react/jsx-runtime");
|
|
1556
1606
|
function SidebarItem({
|
|
1557
1607
|
label,
|
|
1558
1608
|
icon: Icon,
|
|
@@ -1561,7 +1611,7 @@ function SidebarItem({
|
|
|
1561
1611
|
active = false,
|
|
1562
1612
|
className
|
|
1563
1613
|
}) {
|
|
1564
|
-
return /* @__PURE__ */ (0,
|
|
1614
|
+
return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
|
|
1565
1615
|
"a",
|
|
1566
1616
|
{
|
|
1567
1617
|
href,
|
|
@@ -1571,18 +1621,18 @@ function SidebarItem({
|
|
|
1571
1621
|
className
|
|
1572
1622
|
),
|
|
1573
1623
|
children: [
|
|
1574
|
-
/* @__PURE__ */ (0,
|
|
1575
|
-
/* @__PURE__ */ (0,
|
|
1576
|
-
badge !== void 0 && /* @__PURE__ */ (0,
|
|
1624
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)(Icon, { className: "h-3.5 w-3.5 shrink-0" }),
|
|
1625
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: "truncate flex-1", children: label }),
|
|
1626
|
+
badge !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(Badge, { className: "ml-auto text-[10px] px-1.5 py-0", children: badge })
|
|
1577
1627
|
]
|
|
1578
1628
|
}
|
|
1579
1629
|
);
|
|
1580
1630
|
}
|
|
1581
1631
|
|
|
1582
1632
|
// src/composites/app-shell/sidebar.tsx
|
|
1583
|
-
var
|
|
1633
|
+
var import_jsx_runtime32 = require("react/jsx-runtime");
|
|
1584
1634
|
function Sidebar({ logo, sections, footer, className }) {
|
|
1585
|
-
return /* @__PURE__ */ (0,
|
|
1635
|
+
return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
|
|
1586
1636
|
"nav",
|
|
1587
1637
|
{
|
|
1588
1638
|
className: cn(
|
|
@@ -1590,14 +1640,14 @@ function Sidebar({ logo, sections, footer, className }) {
|
|
|
1590
1640
|
className
|
|
1591
1641
|
),
|
|
1592
1642
|
children: [
|
|
1593
|
-
logo && /* @__PURE__ */ (0,
|
|
1594
|
-
/* @__PURE__ */ (0,
|
|
1595
|
-
section.label && /* @__PURE__ */ (0,
|
|
1596
|
-
/* @__PURE__ */ (0,
|
|
1643
|
+
logo && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { className: "px-3 py-2 shrink-0", children: logo }),
|
|
1644
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { className: "flex-1 overflow-auto px-1 py-1", children: sections.map((section, sectionIndex) => /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: cn(sectionIndex > 0 ? "mt-3" : ""), children: [
|
|
1645
|
+
section.label && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "text-[10px] text-foreground-disabled uppercase tracking-wider px-2 mb-1 block", children: section.label }),
|
|
1646
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { className: "flex flex-col gap-0.5", children: section.items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(SidebarItem, { ...item }, item.href)) })
|
|
1597
1647
|
] }, sectionIndex)) }),
|
|
1598
|
-
footer && footer.length > 0 && /* @__PURE__ */ (0,
|
|
1599
|
-
/* @__PURE__ */ (0,
|
|
1600
|
-
/* @__PURE__ */ (0,
|
|
1648
|
+
footer && footer.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: "shrink-0 px-1 pb-1", children: [
|
|
1649
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)(Separator, { className: "mb-1" }),
|
|
1650
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { className: "flex flex-col gap-0.5", children: footer.map((item) => /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(SidebarItem, { ...item }, item.href)) })
|
|
1601
1651
|
] })
|
|
1602
1652
|
]
|
|
1603
1653
|
}
|
|
@@ -1606,29 +1656,29 @@ function Sidebar({ logo, sections, footer, className }) {
|
|
|
1606
1656
|
|
|
1607
1657
|
// src/composites/app-shell/app-shell.tsx
|
|
1608
1658
|
var import_lucide_react8 = require("lucide-react");
|
|
1609
|
-
var
|
|
1659
|
+
var import_jsx_runtime33 = require("react/jsx-runtime");
|
|
1610
1660
|
function AppShell({ sidebar, header, children, className }) {
|
|
1611
|
-
return /* @__PURE__ */ (0,
|
|
1612
|
-
/* @__PURE__ */ (0,
|
|
1613
|
-
/* @__PURE__ */ (0,
|
|
1614
|
-
header && /* @__PURE__ */ (0,
|
|
1615
|
-
header.breadcrumbs && header.breadcrumbs.length > 0 && /* @__PURE__ */ (0,
|
|
1661
|
+
return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: cn("flex h-screen", className), children: [
|
|
1662
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)(Sidebar, { ...sidebar }),
|
|
1663
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "flex flex-1 flex-col min-w-0", children: [
|
|
1664
|
+
header && /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("header", { className: "flex items-center h-10 border-b border-border px-4 shrink-0", children: [
|
|
1665
|
+
header.breadcrumbs && header.breadcrumbs.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("nav", { className: "flex items-center gap-1 text-xs flex-1 min-w-0", children: header.breadcrumbs.map((crumb, index) => {
|
|
1616
1666
|
const isLast = index === header.breadcrumbs.length - 1;
|
|
1617
|
-
return /* @__PURE__ */ (0,
|
|
1618
|
-
index > 0 && /* @__PURE__ */ (0,
|
|
1619
|
-
crumb.href && !isLast ? /* @__PURE__ */ (0,
|
|
1667
|
+
return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("span", { className: "flex items-center gap-1", children: [
|
|
1668
|
+
index > 0 && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_lucide_react8.ChevronRight, { className: "h-3 w-3 text-foreground-subtle shrink-0" }),
|
|
1669
|
+
crumb.href && !isLast ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
|
|
1620
1670
|
"a",
|
|
1621
1671
|
{
|
|
1622
1672
|
href: crumb.href,
|
|
1623
1673
|
className: "text-foreground-subtle hover:text-foreground transition-colors truncate",
|
|
1624
1674
|
children: crumb.label
|
|
1625
1675
|
}
|
|
1626
|
-
) : /* @__PURE__ */ (0,
|
|
1676
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: "text-foreground truncate", children: crumb.label })
|
|
1627
1677
|
] }, index);
|
|
1628
1678
|
}) }),
|
|
1629
|
-
header.actions && /* @__PURE__ */ (0,
|
|
1679
|
+
header.actions && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "flex items-center gap-2 ml-auto shrink-0", children: header.actions })
|
|
1630
1680
|
] }),
|
|
1631
|
-
/* @__PURE__ */ (0,
|
|
1681
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("main", { className: "flex-1 overflow-auto p-4", children })
|
|
1632
1682
|
] })
|
|
1633
1683
|
] });
|
|
1634
1684
|
}
|
|
@@ -1639,20 +1689,20 @@ var import_react_table = require("@tanstack/react-table");
|
|
|
1639
1689
|
|
|
1640
1690
|
// src/composites/data-table/data-table-header.tsx
|
|
1641
1691
|
var import_lucide_react9 = require("lucide-react");
|
|
1642
|
-
var
|
|
1692
|
+
var import_jsx_runtime34 = require("react/jsx-runtime");
|
|
1643
1693
|
function DataTableHeader({
|
|
1644
1694
|
headerGroups,
|
|
1645
1695
|
onSortingChange,
|
|
1646
1696
|
stickyHeader,
|
|
1647
1697
|
flexRender: render
|
|
1648
1698
|
}) {
|
|
1649
|
-
return /* @__PURE__ */ (0,
|
|
1699
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
1650
1700
|
"thead",
|
|
1651
1701
|
{
|
|
1652
1702
|
className: cn(
|
|
1653
1703
|
stickyHeader && "sticky top-0 z-10 bg-background"
|
|
1654
1704
|
),
|
|
1655
|
-
children: headerGroups.map((headerGroup) => /* @__PURE__ */ (0,
|
|
1705
|
+
children: headerGroups.map((headerGroup) => /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("tr", { className: "h-6", children: headerGroup.headers.map((header) => /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
1656
1706
|
HeaderCell,
|
|
1657
1707
|
{
|
|
1658
1708
|
header,
|
|
@@ -1667,7 +1717,7 @@ function DataTableHeader({
|
|
|
1667
1717
|
function HeaderCell({ header, sortable, flexRender: render }) {
|
|
1668
1718
|
const sorted = header.column.getIsSorted();
|
|
1669
1719
|
const SortIcon = sorted === "asc" ? import_lucide_react9.ArrowUp : sorted === "desc" ? import_lucide_react9.ArrowDown : import_lucide_react9.ArrowUpDown;
|
|
1670
|
-
return /* @__PURE__ */ (0,
|
|
1720
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
1671
1721
|
"th",
|
|
1672
1722
|
{
|
|
1673
1723
|
className: cn(
|
|
@@ -1675,9 +1725,9 @@ function HeaderCell({ header, sortable, flexRender: render }) {
|
|
|
1675
1725
|
sortable && "cursor-pointer select-none"
|
|
1676
1726
|
),
|
|
1677
1727
|
onClick: sortable ? header.column.getToggleSortingHandler() : void 0,
|
|
1678
|
-
children: /* @__PURE__ */ (0,
|
|
1728
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("span", { className: "inline-flex items-center gap-1", children: [
|
|
1679
1729
|
header.isPlaceholder ? null : render(header.column.columnDef.header, header.getContext()),
|
|
1680
|
-
sortable && /* @__PURE__ */ (0,
|
|
1730
|
+
sortable && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(SortIcon, { className: "h-3 w-3" })
|
|
1681
1731
|
] })
|
|
1682
1732
|
}
|
|
1683
1733
|
);
|
|
@@ -1685,7 +1735,7 @@ function HeaderCell({ header, sortable, flexRender: render }) {
|
|
|
1685
1735
|
|
|
1686
1736
|
// src/composites/data-table/data-table-row.tsx
|
|
1687
1737
|
var import_lucide_react10 = require("lucide-react");
|
|
1688
|
-
var
|
|
1738
|
+
var import_jsx_runtime35 = require("react/jsx-runtime");
|
|
1689
1739
|
function DataTableRow({
|
|
1690
1740
|
row,
|
|
1691
1741
|
onRowClick,
|
|
@@ -1693,7 +1743,7 @@ function DataTableRow({
|
|
|
1693
1743
|
flexRender: render
|
|
1694
1744
|
}) {
|
|
1695
1745
|
const actions = rowActions ? rowActions(row.original) : [];
|
|
1696
|
-
return /* @__PURE__ */ (0,
|
|
1746
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(
|
|
1697
1747
|
"tr",
|
|
1698
1748
|
{
|
|
1699
1749
|
className: cn(
|
|
@@ -1703,17 +1753,17 @@ function DataTableRow({
|
|
|
1703
1753
|
),
|
|
1704
1754
|
onClick: onRowClick ? () => onRowClick(row.original) : void 0,
|
|
1705
1755
|
children: [
|
|
1706
|
-
row.getVisibleCells().map((cell) => /* @__PURE__ */ (0,
|
|
1707
|
-
actions.length > 0 && /* @__PURE__ */ (0,
|
|
1708
|
-
/* @__PURE__ */ (0,
|
|
1756
|
+
row.getVisibleCells().map((cell) => /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(DataTableCell, { cell, flexRender: render }, cell.id)),
|
|
1757
|
+
actions.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("td", { className: "px-2 py-1.5 w-8", children: /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(Dropdown, { children: [
|
|
1758
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
|
|
1709
1759
|
DropdownTrigger,
|
|
1710
1760
|
{
|
|
1711
1761
|
className: "p-0.5 rounded hover:bg-surface-hover",
|
|
1712
1762
|
onClick: (e) => e.stopPropagation(),
|
|
1713
|
-
children: /* @__PURE__ */ (0,
|
|
1763
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_lucide_react10.MoreHorizontal, { className: "h-3.5 w-3.5 text-foreground-muted" })
|
|
1714
1764
|
}
|
|
1715
1765
|
),
|
|
1716
|
-
/* @__PURE__ */ (0,
|
|
1766
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)(DropdownContent, { className: "right-0 left-auto", children: actions.map((action) => /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
|
|
1717
1767
|
DropdownItem,
|
|
1718
1768
|
{
|
|
1719
1769
|
icon: action.icon,
|
|
@@ -1732,12 +1782,12 @@ function DataTableRow({
|
|
|
1732
1782
|
);
|
|
1733
1783
|
}
|
|
1734
1784
|
function DataTableCell({ cell, flexRender: render }) {
|
|
1735
|
-
return /* @__PURE__ */ (0,
|
|
1785
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("td", { className: "px-2 py-1.5 text-xs text-foreground", children: render(cell.column.columnDef.cell, cell.getContext()) });
|
|
1736
1786
|
}
|
|
1737
1787
|
|
|
1738
1788
|
// src/composites/data-table/data-table-pagination.tsx
|
|
1739
1789
|
var import_lucide_react11 = require("lucide-react");
|
|
1740
|
-
var
|
|
1790
|
+
var import_jsx_runtime36 = require("react/jsx-runtime");
|
|
1741
1791
|
var PAGE_SIZE_OPTIONS = [
|
|
1742
1792
|
{ value: "10", label: "10" },
|
|
1743
1793
|
{ value: "25", label: "25" },
|
|
@@ -1752,10 +1802,10 @@ function DataTablePagination({
|
|
|
1752
1802
|
}) {
|
|
1753
1803
|
const totalPages = Math.max(1, Math.ceil(total / pageSize));
|
|
1754
1804
|
const currentPage = page + 1;
|
|
1755
|
-
return /* @__PURE__ */ (0,
|
|
1756
|
-
/* @__PURE__ */ (0,
|
|
1757
|
-
/* @__PURE__ */ (0,
|
|
1758
|
-
/* @__PURE__ */ (0,
|
|
1805
|
+
return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "flex items-center justify-between px-2 py-2 text-xs text-foreground-muted", children: [
|
|
1806
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
1807
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("span", { children: "Rows per page" }),
|
|
1808
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { className: "w-16", children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
1759
1809
|
Select,
|
|
1760
1810
|
{
|
|
1761
1811
|
options: PAGE_SIZE_OPTIONS,
|
|
@@ -1767,14 +1817,14 @@ function DataTablePagination({
|
|
|
1767
1817
|
}
|
|
1768
1818
|
) })
|
|
1769
1819
|
] }),
|
|
1770
|
-
/* @__PURE__ */ (0,
|
|
1771
|
-
/* @__PURE__ */ (0,
|
|
1820
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
1821
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("span", { children: [
|
|
1772
1822
|
"Page ",
|
|
1773
1823
|
currentPage,
|
|
1774
1824
|
" of ",
|
|
1775
1825
|
totalPages
|
|
1776
1826
|
] }),
|
|
1777
|
-
/* @__PURE__ */ (0,
|
|
1827
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
1778
1828
|
IconButton,
|
|
1779
1829
|
{
|
|
1780
1830
|
icon: import_lucide_react11.ChevronLeft,
|
|
@@ -1785,7 +1835,7 @@ function DataTablePagination({
|
|
|
1785
1835
|
onClick: () => onPaginationChange?.({ pageIndex: page - 1, pageSize })
|
|
1786
1836
|
}
|
|
1787
1837
|
),
|
|
1788
|
-
/* @__PURE__ */ (0,
|
|
1838
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
1789
1839
|
IconButton,
|
|
1790
1840
|
{
|
|
1791
1841
|
icon: import_lucide_react11.ChevronRight,
|
|
@@ -1801,7 +1851,7 @@ function DataTablePagination({
|
|
|
1801
1851
|
}
|
|
1802
1852
|
|
|
1803
1853
|
// src/composites/data-table/data-table.tsx
|
|
1804
|
-
var
|
|
1854
|
+
var import_jsx_runtime37 = require("react/jsx-runtime");
|
|
1805
1855
|
function DataTable({
|
|
1806
1856
|
data,
|
|
1807
1857
|
columns: userColumns,
|
|
@@ -1824,7 +1874,7 @@ function DataTable({
|
|
|
1824
1874
|
if (!selectable) return userColumns;
|
|
1825
1875
|
const selectColumn = {
|
|
1826
1876
|
id: "__select",
|
|
1827
|
-
header: ({ table: table2 }) => /* @__PURE__ */ (0,
|
|
1877
|
+
header: ({ table: table2 }) => /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
|
|
1828
1878
|
Checkbox,
|
|
1829
1879
|
{
|
|
1830
1880
|
checked: table2.getIsAllPageRowsSelected(),
|
|
@@ -1832,7 +1882,7 @@ function DataTable({
|
|
|
1832
1882
|
"aria-label": "Select all"
|
|
1833
1883
|
}
|
|
1834
1884
|
),
|
|
1835
|
-
cell: ({ row }) => /* @__PURE__ */ (0,
|
|
1885
|
+
cell: ({ row }) => /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
|
|
1836
1886
|
Checkbox,
|
|
1837
1887
|
{
|
|
1838
1888
|
checked: row.getIsSelected(),
|
|
@@ -1870,9 +1920,9 @@ function DataTable({
|
|
|
1870
1920
|
pageCount: pagination ? Math.ceil(pagination.total / pagination.pageSize) : void 0
|
|
1871
1921
|
});
|
|
1872
1922
|
const hasActions = !!rowActions;
|
|
1873
|
-
return /* @__PURE__ */ (0,
|
|
1874
|
-
/* @__PURE__ */ (0,
|
|
1875
|
-
/* @__PURE__ */ (0,
|
|
1923
|
+
return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: cn("overflow-auto", className), children: [
|
|
1924
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("table", { className: "w-full border-collapse", children: [
|
|
1925
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
|
|
1876
1926
|
DataTableHeader,
|
|
1877
1927
|
{
|
|
1878
1928
|
headerGroups: table.getHeaderGroups(),
|
|
@@ -1881,14 +1931,14 @@ function DataTable({
|
|
|
1881
1931
|
flexRender: import_react_table.flexRender
|
|
1882
1932
|
}
|
|
1883
1933
|
),
|
|
1884
|
-
/* @__PURE__ */ (0,
|
|
1934
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)("tbody", { children: loading ? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(LoadingRows, { colSpan: columns.length + (hasActions ? 1 : 0), compact }) : table.getRowModel().rows.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
|
|
1885
1935
|
"td",
|
|
1886
1936
|
{
|
|
1887
1937
|
colSpan: columns.length + (hasActions ? 1 : 0),
|
|
1888
1938
|
className: "text-center py-8 text-xs text-foreground-muted",
|
|
1889
1939
|
children: emptyState ?? "No data"
|
|
1890
1940
|
}
|
|
1891
|
-
) }) : table.getRowModel().rows.map((row) => /* @__PURE__ */ (0,
|
|
1941
|
+
) }) : table.getRowModel().rows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
|
|
1892
1942
|
DataTableRow,
|
|
1893
1943
|
{
|
|
1894
1944
|
row,
|
|
@@ -1899,7 +1949,7 @@ function DataTable({
|
|
|
1899
1949
|
row.id
|
|
1900
1950
|
)) })
|
|
1901
1951
|
] }),
|
|
1902
|
-
pagination && /* @__PURE__ */ (0,
|
|
1952
|
+
pagination && /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
|
|
1903
1953
|
DataTablePagination,
|
|
1904
1954
|
{
|
|
1905
1955
|
page: pagination.page,
|
|
@@ -1911,11 +1961,11 @@ function DataTable({
|
|
|
1911
1961
|
] });
|
|
1912
1962
|
}
|
|
1913
1963
|
function LoadingRows({ colSpan, compact }) {
|
|
1914
|
-
return /* @__PURE__ */ (0,
|
|
1964
|
+
return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_jsx_runtime37.Fragment, { children: Array.from({ length: 5 }).map((_, rowIdx) => /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("tr", { className: compact ? "h-7" : "h-9", children: Array.from({ length: colSpan }).map((_2, colIdx) => /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("td", { className: "px-2 py-1.5", children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(Skeleton, { className: "h-3 w-full" }) }, colIdx)) }, rowIdx)) });
|
|
1915
1965
|
}
|
|
1916
1966
|
|
|
1917
1967
|
// src/composites/device-card.tsx
|
|
1918
|
-
var
|
|
1968
|
+
var import_jsx_runtime38 = require("react/jsx-runtime");
|
|
1919
1969
|
var STATUS_COLORS = {
|
|
1920
1970
|
online: "bg-success",
|
|
1921
1971
|
offline: "bg-danger",
|
|
@@ -1934,7 +1984,7 @@ function DeviceCard({
|
|
|
1934
1984
|
className
|
|
1935
1985
|
}) {
|
|
1936
1986
|
const isOffline = status === "offline";
|
|
1937
|
-
return /* @__PURE__ */ (0,
|
|
1987
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(
|
|
1938
1988
|
"div",
|
|
1939
1989
|
{
|
|
1940
1990
|
onClick,
|
|
@@ -1946,18 +1996,18 @@ function DeviceCard({
|
|
|
1946
1996
|
className
|
|
1947
1997
|
),
|
|
1948
1998
|
children: [
|
|
1949
|
-
/* @__PURE__ */ (0,
|
|
1950
|
-
/* @__PURE__ */ (0,
|
|
1951
|
-
status && /* @__PURE__ */ (0,
|
|
1999
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: "flex items-center justify-between mb-2", children: [
|
|
2000
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "text-sm font-medium truncate", children: title }),
|
|
2001
|
+
status && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: cn("h-2 w-2 rounded-full shrink-0", STATUS_COLORS[status]) })
|
|
1952
2002
|
] }),
|
|
1953
|
-
subtitle && /* @__PURE__ */ (0,
|
|
1954
|
-
badges && badges.length > 0 && /* @__PURE__ */ (0,
|
|
2003
|
+
subtitle && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { className: "text-[11px] text-foreground-muted", children: subtitle }),
|
|
2004
|
+
badges && badges.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { className: "flex flex-wrap gap-1 mt-2", children: badges.map((badge, i) => {
|
|
1955
2005
|
const cls = cn(
|
|
1956
2006
|
"rounded px-1.5 py-0.5 text-[10px] flex items-center gap-0.5",
|
|
1957
2007
|
selected ? "bg-primary/20" : "bg-surface-hover",
|
|
1958
2008
|
badge.onClick && "hover:opacity-80 transition-opacity cursor-pointer"
|
|
1959
2009
|
);
|
|
1960
|
-
return badge.onClick ? /* @__PURE__ */ (0,
|
|
2010
|
+
return badge.onClick ? /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(
|
|
1961
2011
|
"button",
|
|
1962
2012
|
{
|
|
1963
2013
|
onClick: (e) => {
|
|
@@ -1971,12 +2021,12 @@ function DeviceCard({
|
|
|
1971
2021
|
]
|
|
1972
2022
|
},
|
|
1973
2023
|
i
|
|
1974
|
-
) : /* @__PURE__ */ (0,
|
|
2024
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("span", { className: cls, children: [
|
|
1975
2025
|
badge.icon,
|
|
1976
2026
|
badge.label
|
|
1977
2027
|
] }, i);
|
|
1978
2028
|
}) }),
|
|
1979
|
-
!isOffline && actions && actions.length > 0 && /* @__PURE__ */ (0,
|
|
2029
|
+
!isOffline && actions && actions.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { className: "flex items-center gap-0.5 mt-2 -mb-1", children: actions.map((action, i) => /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
|
|
1980
2030
|
"button",
|
|
1981
2031
|
{
|
|
1982
2032
|
onClick: (e) => {
|
|
@@ -1990,21 +2040,21 @@ function DeviceCard({
|
|
|
1990
2040
|
},
|
|
1991
2041
|
i
|
|
1992
2042
|
)) }),
|
|
1993
|
-
isOffline && offlineAction && /* @__PURE__ */ (0,
|
|
2043
|
+
isOffline && offlineAction && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { className: "mt-2", onClick: (e) => e.stopPropagation(), children: offlineAction })
|
|
1994
2044
|
]
|
|
1995
2045
|
}
|
|
1996
2046
|
);
|
|
1997
2047
|
}
|
|
1998
2048
|
|
|
1999
2049
|
// src/composites/device-grid.tsx
|
|
2000
|
-
var
|
|
2050
|
+
var import_jsx_runtime39 = require("react/jsx-runtime");
|
|
2001
2051
|
function DeviceGrid({
|
|
2002
2052
|
children,
|
|
2003
2053
|
minCardWidth = 220,
|
|
2004
2054
|
gap = 3,
|
|
2005
2055
|
className
|
|
2006
2056
|
}) {
|
|
2007
|
-
return /* @__PURE__ */ (0,
|
|
2057
|
+
return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
2008
2058
|
"div",
|
|
2009
2059
|
{
|
|
2010
2060
|
className: cn(
|
|
@@ -2020,16 +2070,1716 @@ function DeviceGrid({
|
|
|
2020
2070
|
}
|
|
2021
2071
|
);
|
|
2022
2072
|
}
|
|
2073
|
+
|
|
2074
|
+
// src/composites/pipeline-step.tsx
|
|
2075
|
+
var import_react23 = require("react");
|
|
2076
|
+
var import_lucide_react12 = require("lucide-react");
|
|
2077
|
+
var import_jsx_runtime40 = require("react/jsx-runtime");
|
|
2078
|
+
var ADDON_COLORS = {
|
|
2079
|
+
"object-detection": "border-l-blue-500",
|
|
2080
|
+
"motion-detection": "border-l-amber-500",
|
|
2081
|
+
"face-detection": "border-l-purple-500",
|
|
2082
|
+
"face-recognition": "border-l-violet-500",
|
|
2083
|
+
"plate-detection": "border-l-pink-500",
|
|
2084
|
+
"plate-recognition": "border-l-rose-500",
|
|
2085
|
+
"animal-classifier": "border-l-lime-500",
|
|
2086
|
+
"bird-nabirds-classifier": "border-l-emerald-500",
|
|
2087
|
+
"bird-global-classifier": "border-l-teal-500",
|
|
2088
|
+
"audio-classification": "border-l-green-500",
|
|
2089
|
+
"segmentation-refiner": "border-l-cyan-500"
|
|
2090
|
+
};
|
|
2091
|
+
var SLOT_FALLBACK = {
|
|
2092
|
+
detector: "border-l-blue-500",
|
|
2093
|
+
cropper: "border-l-purple-500",
|
|
2094
|
+
classifier: "border-l-lime-500",
|
|
2095
|
+
refiner: "border-l-cyan-500"
|
|
2096
|
+
};
|
|
2097
|
+
function borderColor(addonId, slot) {
|
|
2098
|
+
return ADDON_COLORS[addonId] ?? SLOT_FALLBACK[slot] ?? "border-l-primary";
|
|
2099
|
+
}
|
|
2100
|
+
var BACKEND_FORMAT = {
|
|
2101
|
+
cpu: "onnx",
|
|
2102
|
+
coreml: "coreml",
|
|
2103
|
+
openvino: "openvino",
|
|
2104
|
+
cuda: "onnx",
|
|
2105
|
+
tensorrt: "onnx",
|
|
2106
|
+
"onnx-py": "onnx",
|
|
2107
|
+
pytorch: "pt"
|
|
2108
|
+
};
|
|
2109
|
+
function backendsForRuntime(runtime, caps, schema) {
|
|
2110
|
+
const allBackends = runtime === "node" ? caps.runtimes.node.backends : caps.runtimes.python.backends;
|
|
2111
|
+
if (!schema) return allBackends;
|
|
2112
|
+
const availableFormats = /* @__PURE__ */ new Set();
|
|
2113
|
+
for (const m of schema.models) {
|
|
2114
|
+
for (const fmt of Object.keys(m.formats)) {
|
|
2115
|
+
availableFormats.add(fmt);
|
|
2116
|
+
}
|
|
2117
|
+
}
|
|
2118
|
+
if (runtime === "node") availableFormats.add("onnx");
|
|
2119
|
+
return allBackends.map((b) => {
|
|
2120
|
+
const neededFormat = BACKEND_FORMAT[b.id] ?? "onnx";
|
|
2121
|
+
const hasFormat = availableFormats.has(neededFormat);
|
|
2122
|
+
return { ...b, available: b.available && hasFormat };
|
|
2123
|
+
});
|
|
2124
|
+
}
|
|
2125
|
+
function modelsForStep(schema, runtime, backend, caps) {
|
|
2126
|
+
if (!schema) return [];
|
|
2127
|
+
const fmt = runtime === "node" ? "onnx" : caps.runtimes.python.backends.find((b) => b.id === backend)?.modelFormat ?? "onnx";
|
|
2128
|
+
return schema.models.filter((m) => m.formats[fmt]).map((m) => ({
|
|
2129
|
+
id: m.id,
|
|
2130
|
+
name: m.name,
|
|
2131
|
+
downloaded: m.formats[fmt]?.downloaded ?? false
|
|
2132
|
+
}));
|
|
2133
|
+
}
|
|
2134
|
+
function runtimeOptions(caps) {
|
|
2135
|
+
const opts = [
|
|
2136
|
+
{ id: "node", label: "Node.js (ONNX)", available: true }
|
|
2137
|
+
];
|
|
2138
|
+
if (caps.runtimes.python.available && caps.runtimes.python.backends.some((b) => b.available)) {
|
|
2139
|
+
opts.unshift({ id: "python", label: "Python", available: true });
|
|
2140
|
+
}
|
|
2141
|
+
return opts;
|
|
2142
|
+
}
|
|
2143
|
+
function PipelineStep({
|
|
2144
|
+
step,
|
|
2145
|
+
schema,
|
|
2146
|
+
allSchemas,
|
|
2147
|
+
capabilities,
|
|
2148
|
+
depth = 0,
|
|
2149
|
+
onChange,
|
|
2150
|
+
onDelete,
|
|
2151
|
+
readOnly = false
|
|
2152
|
+
}) {
|
|
2153
|
+
const [expanded, setExpanded] = (0, import_react23.useState)(false);
|
|
2154
|
+
const color = borderColor(step.addonId, step.slot);
|
|
2155
|
+
const backends = backendsForRuntime(step.runtime, capabilities, schema);
|
|
2156
|
+
const rtOptions = runtimeOptions(capabilities);
|
|
2157
|
+
const currentBackendAvailable = backends.find((b) => b.id === step.backend)?.available ?? false;
|
|
2158
|
+
if (!currentBackendAvailable && !readOnly) {
|
|
2159
|
+
const firstAvailable = backends.find((b) => b.available);
|
|
2160
|
+
if (firstAvailable && firstAvailable.id !== step.backend) {
|
|
2161
|
+
queueMicrotask(() => onChange({ ...step, backend: firstAvailable.id }));
|
|
2162
|
+
}
|
|
2163
|
+
}
|
|
2164
|
+
const models = modelsForStep(schema, step.runtime, step.backend, capabilities);
|
|
2165
|
+
if (models.length > 0 && !models.some((m) => m.id === step.modelId) && !readOnly) {
|
|
2166
|
+
const defaultModel = schema?.defaultModelId ? models.find((m) => m.id === schema.defaultModelId) : null;
|
|
2167
|
+
const fallback = defaultModel ?? models[0];
|
|
2168
|
+
if (fallback && fallback.id !== step.modelId) {
|
|
2169
|
+
queueMicrotask(() => onChange({ ...step, modelId: fallback.id }));
|
|
2170
|
+
}
|
|
2171
|
+
}
|
|
2172
|
+
function handleClick(e) {
|
|
2173
|
+
if (e.target.closest(".step-config")) return;
|
|
2174
|
+
setExpanded((v) => !v);
|
|
2175
|
+
}
|
|
2176
|
+
return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "space-y-2", children: /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(
|
|
2177
|
+
"div",
|
|
2178
|
+
{
|
|
2179
|
+
className: cn(
|
|
2180
|
+
"rounded-xl border border-border bg-surface overflow-hidden border-l-4 shadow-sm",
|
|
2181
|
+
color,
|
|
2182
|
+
!step.enabled && "opacity-[0.45]"
|
|
2183
|
+
),
|
|
2184
|
+
children: [
|
|
2185
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "flex items-center gap-2.5 px-3 py-2.5 cursor-pointer select-none", onClick: handleClick, children: [
|
|
2186
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)("span", { className: "text-foreground-subtle", children: expanded ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_lucide_react12.ChevronDown, { className: "h-4 w-4" }) : /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_lucide_react12.ChevronRight, { className: "h-4 w-4" }) }),
|
|
2187
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "flex-1 min-w-0", children: [
|
|
2188
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)("span", { className: "text-[10px] uppercase tracking-wider font-medium text-foreground-subtle/60 block leading-none", children: step.slot }),
|
|
2189
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)("span", { className: "text-sm font-semibold text-foreground truncate block leading-tight", children: step.addonName }),
|
|
2190
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "flex items-center gap-1 mt-0.5 flex-wrap", children: [
|
|
2191
|
+
step.inputClasses.map((c) => /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("span", { className: "text-[9px] uppercase font-semibold tracking-wide px-1.5 py-0.5 rounded bg-blue-500/12 text-blue-400", children: c }, c)),
|
|
2192
|
+
step.inputClasses.length > 0 && step.outputClasses.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("span", { className: "text-foreground-subtle/40 text-[10px]", children: "\u2192" }),
|
|
2193
|
+
step.outputClasses.map((c) => /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("span", { className: "text-[9px] uppercase font-semibold tracking-wide px-1.5 py-0.5 rounded bg-green-500/12 text-green-400", children: c }, c))
|
|
2194
|
+
] })
|
|
2195
|
+
] }),
|
|
2196
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
2197
|
+
"button",
|
|
2198
|
+
{
|
|
2199
|
+
onClick: (e) => {
|
|
2200
|
+
e.stopPropagation();
|
|
2201
|
+
onChange({ ...step, enabled: !step.enabled });
|
|
2202
|
+
},
|
|
2203
|
+
className: cn(
|
|
2204
|
+
"relative inline-flex h-6 w-11 shrink-0 items-center rounded-full transition-colors",
|
|
2205
|
+
step.enabled ? "bg-success" : "bg-foreground-subtle/30"
|
|
2206
|
+
),
|
|
2207
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("span", { className: cn(
|
|
2208
|
+
"inline-block h-4 w-4 rounded-full bg-white shadow transition-transform",
|
|
2209
|
+
step.enabled ? "translate-x-6" : "translate-x-1"
|
|
2210
|
+
) })
|
|
2211
|
+
}
|
|
2212
|
+
)
|
|
2213
|
+
] }),
|
|
2214
|
+
expanded && /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "step-config border-t border-border bg-background px-4 py-4 space-y-3", children: [
|
|
2215
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "grid grid-cols-2 gap-3", children: [
|
|
2216
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
2217
|
+
ConfigSelect,
|
|
2218
|
+
{
|
|
2219
|
+
label: "Agent",
|
|
2220
|
+
value: step.agentId,
|
|
2221
|
+
disabled: readOnly,
|
|
2222
|
+
options: [{ value: step.agentId || "hub", label: step.agentId || "Hub (local)" }],
|
|
2223
|
+
onChange: (v) => onChange({ ...step, agentId: v })
|
|
2224
|
+
}
|
|
2225
|
+
),
|
|
2226
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
2227
|
+
ConfigSelect,
|
|
2228
|
+
{
|
|
2229
|
+
label: "Runtime",
|
|
2230
|
+
value: step.runtime,
|
|
2231
|
+
disabled: readOnly,
|
|
2232
|
+
options: rtOptions.map((r) => ({ value: r.id, label: r.label, disabled: !r.available })),
|
|
2233
|
+
onChange: (v) => onChange({ ...step, runtime: v })
|
|
2234
|
+
}
|
|
2235
|
+
),
|
|
2236
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
2237
|
+
ConfigSelect,
|
|
2238
|
+
{
|
|
2239
|
+
label: "Backend",
|
|
2240
|
+
value: step.backend,
|
|
2241
|
+
disabled: readOnly,
|
|
2242
|
+
options: backends.map((b) => ({ value: b.id, label: b.label, disabled: !b.available })),
|
|
2243
|
+
onChange: (v) => onChange({ ...step, backend: v })
|
|
2244
|
+
}
|
|
2245
|
+
),
|
|
2246
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
2247
|
+
ConfigSelect,
|
|
2248
|
+
{
|
|
2249
|
+
label: "Model",
|
|
2250
|
+
value: step.modelId,
|
|
2251
|
+
disabled: readOnly,
|
|
2252
|
+
options: models.map((m) => ({ value: m.id, label: `${m.name}${m.downloaded ? " \u2713" : ""}` })),
|
|
2253
|
+
onChange: (v) => onChange({ ...step, modelId: v })
|
|
2254
|
+
}
|
|
2255
|
+
)
|
|
2256
|
+
] }),
|
|
2257
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { children: [
|
|
2258
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "flex items-center justify-between mb-1", children: [
|
|
2259
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)("span", { className: "text-[10px] font-medium text-foreground-subtle uppercase tracking-wide", children: "Confidence" }),
|
|
2260
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("span", { className: "text-xs font-medium text-foreground tabular-nums", children: [
|
|
2261
|
+
(step.confidence * 100).toFixed(0),
|
|
2262
|
+
"%"
|
|
2263
|
+
] })
|
|
2264
|
+
] }),
|
|
2265
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
2266
|
+
"input",
|
|
2267
|
+
{
|
|
2268
|
+
type: "range",
|
|
2269
|
+
min: 0,
|
|
2270
|
+
max: 1,
|
|
2271
|
+
step: 0.01,
|
|
2272
|
+
value: step.confidence,
|
|
2273
|
+
disabled: readOnly,
|
|
2274
|
+
onChange: (e) => onChange({ ...step, confidence: Number(e.target.value) }),
|
|
2275
|
+
className: "w-full accent-primary h-1.5"
|
|
2276
|
+
}
|
|
2277
|
+
)
|
|
2278
|
+
] })
|
|
2279
|
+
] })
|
|
2280
|
+
]
|
|
2281
|
+
}
|
|
2282
|
+
) });
|
|
2283
|
+
}
|
|
2284
|
+
function ConfigSelect({ label, value, options, disabled, onChange }) {
|
|
2285
|
+
return /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { children: [
|
|
2286
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)("label", { className: "block text-[10px] font-medium text-foreground-subtle uppercase tracking-wide mb-1.5", children: label }),
|
|
2287
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(
|
|
2288
|
+
"select",
|
|
2289
|
+
{
|
|
2290
|
+
value,
|
|
2291
|
+
onChange: (e) => onChange(e.target.value),
|
|
2292
|
+
disabled,
|
|
2293
|
+
className: "w-full rounded-lg border border-border bg-surface px-3 py-2 text-xs text-foreground focus:outline-none focus:border-primary/50",
|
|
2294
|
+
children: [
|
|
2295
|
+
options.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("option", { value, children: value || "default" }),
|
|
2296
|
+
options.map((o) => /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("option", { value: o.value, disabled: o.disabled, children: o.label }, o.value))
|
|
2297
|
+
]
|
|
2298
|
+
}
|
|
2299
|
+
)
|
|
2300
|
+
] });
|
|
2301
|
+
}
|
|
2302
|
+
|
|
2303
|
+
// src/composites/pipeline-runtime-selector.tsx
|
|
2304
|
+
var import_lucide_react13 = require("lucide-react");
|
|
2305
|
+
var import_jsx_runtime41 = require("react/jsx-runtime");
|
|
2306
|
+
function PipelineRuntimeSelector({ options, value, onChange }) {
|
|
2307
|
+
return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "flex flex-wrap gap-2", children: options.map((opt) => {
|
|
2308
|
+
const active = opt.id === value;
|
|
2309
|
+
return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(
|
|
2310
|
+
"button",
|
|
2311
|
+
{
|
|
2312
|
+
onClick: () => opt.available && onChange(opt.id),
|
|
2313
|
+
disabled: !opt.available,
|
|
2314
|
+
className: `flex items-center gap-2 rounded-lg border px-3 py-2 text-xs font-medium transition-all ${active ? "border-primary/40 bg-primary/10 text-primary" : opt.available ? "border-border bg-surface text-foreground-subtle hover:bg-surface-hover hover:text-foreground" : "border-border/40 bg-surface/40 text-foreground-subtle/40 cursor-not-allowed"}`,
|
|
2315
|
+
children: [
|
|
2316
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_lucide_react13.Cpu, { className: "h-3.5 w-3.5 shrink-0" }),
|
|
2317
|
+
opt.label,
|
|
2318
|
+
opt.isBest && /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("span", { className: "inline-flex items-center gap-0.5 rounded-full bg-amber-500/15 px-1.5 py-0.5 text-[10px] font-semibold text-amber-400", children: [
|
|
2319
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_lucide_react13.Star, { className: "h-2.5 w-2.5" }),
|
|
2320
|
+
"Best"
|
|
2321
|
+
] }),
|
|
2322
|
+
opt.platformScore != null && /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("span", { className: "text-[10px] text-foreground-subtle/60", children: [
|
|
2323
|
+
"(",
|
|
2324
|
+
opt.platformScore,
|
|
2325
|
+
")"
|
|
2326
|
+
] }),
|
|
2327
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
|
|
2328
|
+
"span",
|
|
2329
|
+
{
|
|
2330
|
+
className: `h-1.5 w-1.5 rounded-full ${opt.available ? "bg-success" : "bg-danger"}`
|
|
2331
|
+
}
|
|
2332
|
+
)
|
|
2333
|
+
]
|
|
2334
|
+
},
|
|
2335
|
+
opt.id
|
|
2336
|
+
);
|
|
2337
|
+
}) });
|
|
2338
|
+
}
|
|
2339
|
+
|
|
2340
|
+
// src/composites/pipeline-builder.tsx
|
|
2341
|
+
var import_react24 = require("react");
|
|
2342
|
+
var import_lucide_react14 = require("lucide-react");
|
|
2343
|
+
|
|
2344
|
+
// src/lib/validate-template.ts
|
|
2345
|
+
function validateTemplate(steps, schema) {
|
|
2346
|
+
const availableAddonIds = new Set(
|
|
2347
|
+
schema.slots.flatMap((s) => s.addons.map((a) => a.id))
|
|
2348
|
+
);
|
|
2349
|
+
const warnings = [];
|
|
2350
|
+
function validateStep(step) {
|
|
2351
|
+
if (!availableAddonIds.has(step.addonId)) {
|
|
2352
|
+
warnings.push(`Addon "${step.addonId}" is no longer available \u2014 step removed`);
|
|
2353
|
+
return null;
|
|
2354
|
+
}
|
|
2355
|
+
const addon = schema.slots.flatMap((s) => s.addons).find((a) => a.id === step.addonId);
|
|
2356
|
+
let modelId = step.modelId;
|
|
2357
|
+
if (addon && !addon.models.some((m) => m.id === modelId)) {
|
|
2358
|
+
const fallback = addon.defaultModelId;
|
|
2359
|
+
warnings.push(`Model "${modelId}" not available for ${step.addonId} \u2014 using "${fallback}"`);
|
|
2360
|
+
modelId = fallback;
|
|
2361
|
+
}
|
|
2362
|
+
const validChildren = step.children.map((c) => validateStep(c)).filter((c) => c !== null);
|
|
2363
|
+
return { ...step, modelId, children: validChildren };
|
|
2364
|
+
}
|
|
2365
|
+
const validSteps = steps.map((s) => validateStep(s)).filter((s) => s !== null);
|
|
2366
|
+
return {
|
|
2367
|
+
valid: warnings.length === 0,
|
|
2368
|
+
steps: validSteps,
|
|
2369
|
+
warnings
|
|
2370
|
+
};
|
|
2371
|
+
}
|
|
2372
|
+
|
|
2373
|
+
// src/composites/pipeline-builder.tsx
|
|
2374
|
+
var import_jsx_runtime42 = require("react/jsx-runtime");
|
|
2375
|
+
function buildSchemaMap(schema) {
|
|
2376
|
+
const map = /* @__PURE__ */ new Map();
|
|
2377
|
+
for (const slot of schema.slots) {
|
|
2378
|
+
for (const addon of slot.addons) {
|
|
2379
|
+
map.set(addon.id, addon);
|
|
2380
|
+
}
|
|
2381
|
+
}
|
|
2382
|
+
return map;
|
|
2383
|
+
}
|
|
2384
|
+
function createDefaultStep(addon, fallbackRuntime, fallbackBackend) {
|
|
2385
|
+
return {
|
|
2386
|
+
addonId: addon.id,
|
|
2387
|
+
addonName: addon.name,
|
|
2388
|
+
slot: addon.slot,
|
|
2389
|
+
inputClasses: [...addon.inputClasses],
|
|
2390
|
+
outputClasses: [...addon.outputClasses],
|
|
2391
|
+
enabled: true,
|
|
2392
|
+
agentId: "hub",
|
|
2393
|
+
// Use per-addon defaults from backend PlatformScorer, fallback to provided
|
|
2394
|
+
runtime: addon.defaultRuntime ?? fallbackRuntime ?? "node",
|
|
2395
|
+
backend: addon.defaultBackend ?? fallbackBackend ?? "cpu",
|
|
2396
|
+
modelId: addon.defaultModelId,
|
|
2397
|
+
confidence: addon.defaultConfidence,
|
|
2398
|
+
classFilters: [...addon.inputClasses],
|
|
2399
|
+
children: []
|
|
2400
|
+
};
|
|
2401
|
+
}
|
|
2402
|
+
function PlaceholderStep({ addon, onClick }) {
|
|
2403
|
+
return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
|
|
2404
|
+
"button",
|
|
2405
|
+
{
|
|
2406
|
+
type: "button",
|
|
2407
|
+
onClick,
|
|
2408
|
+
className: "w-full rounded-xl border-2 border-dashed border-border/60 px-4 py-3 text-left transition-all hover:border-primary/30 hover:bg-surface/60 group",
|
|
2409
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "flex items-center gap-3", children: [
|
|
2410
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_lucide_react14.PlusCircle, { className: "h-[18px] w-[18px] text-foreground-subtle/30 group-hover:text-primary/60 shrink-0" }),
|
|
2411
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "flex-1 min-w-0", children: [
|
|
2412
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "text-[13px] font-medium text-foreground-subtle/50 group-hover:text-foreground-subtle block truncate", children: addon.name }),
|
|
2413
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "flex items-center gap-1 mt-0.5 flex-wrap", children: [
|
|
2414
|
+
addon.inputClasses.map((c) => /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "text-[9px] uppercase font-semibold tracking-wide px-1.5 py-0.5 rounded bg-blue-500/8 text-blue-400/50", children: c }, c)),
|
|
2415
|
+
addon.inputClasses.length > 0 && addon.outputClasses.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "text-foreground-subtle/25 text-[10px]", children: "\u2192" }),
|
|
2416
|
+
addon.outputClasses.map((c) => /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "text-[9px] uppercase font-semibold tracking-wide px-1.5 py-0.5 rounded bg-green-500/8 text-green-400/50", children: c }, c))
|
|
2417
|
+
] })
|
|
2418
|
+
] })
|
|
2419
|
+
] })
|
|
2420
|
+
}
|
|
2421
|
+
);
|
|
2422
|
+
}
|
|
2423
|
+
function PipelineBuilder({
|
|
2424
|
+
schema,
|
|
2425
|
+
capabilities,
|
|
2426
|
+
steps,
|
|
2427
|
+
onChange,
|
|
2428
|
+
templates,
|
|
2429
|
+
selectedTemplateId,
|
|
2430
|
+
onSelectTemplate,
|
|
2431
|
+
onSaveTemplate,
|
|
2432
|
+
onUpdateTemplate,
|
|
2433
|
+
onDeleteTemplate,
|
|
2434
|
+
readOnly = false,
|
|
2435
|
+
excludeAddons = []
|
|
2436
|
+
}) {
|
|
2437
|
+
const excluded = (0, import_react24.useMemo)(() => new Set(excludeAddons), [excludeAddons]);
|
|
2438
|
+
const schemaMap = (0, import_react24.useMemo)(() => buildSchemaMap(schema), [schema]);
|
|
2439
|
+
const [warnings, setWarnings] = (0, import_react24.useState)([]);
|
|
2440
|
+
const bestPlatformScore = capabilities.platformScores?.find((s) => s.available);
|
|
2441
|
+
const hasPython = capabilities.runtimes.python.available && capabilities.runtimes.python.backends.some((b) => b.available);
|
|
2442
|
+
const defaultRuntime = bestPlatformScore?.runtime ?? (hasPython ? "python" : "node");
|
|
2443
|
+
const defaultBackend = bestPlatformScore?.backend ?? (hasPython ? capabilities.runtimes.python.backends.find((b) => b.available)?.id ?? "cpu" : capabilities.runtimes.node.backends.find((b) => b.available && b.id !== "cpu")?.id ?? "cpu");
|
|
2444
|
+
const dirty = selectedTemplateId ? JSON.stringify(steps) !== JSON.stringify(templates.find((t) => t.id === selectedTemplateId)?.steps) : false;
|
|
2445
|
+
function handleSelectTemplate(e) {
|
|
2446
|
+
const id = e.target.value || null;
|
|
2447
|
+
if (id) {
|
|
2448
|
+
const tpl = templates.find((t) => t.id === id);
|
|
2449
|
+
if (tpl) {
|
|
2450
|
+
const result = validateTemplate(tpl.steps, schema);
|
|
2451
|
+
setWarnings([...result.warnings]);
|
|
2452
|
+
}
|
|
2453
|
+
} else {
|
|
2454
|
+
setWarnings([]);
|
|
2455
|
+
}
|
|
2456
|
+
onSelectTemplate(id);
|
|
2457
|
+
}
|
|
2458
|
+
function handleSave() {
|
|
2459
|
+
if (selectedTemplateId) onUpdateTemplate(selectedTemplateId, steps);
|
|
2460
|
+
}
|
|
2461
|
+
function handleSaveAs() {
|
|
2462
|
+
const name = window.prompt("Template name:");
|
|
2463
|
+
if (name?.trim()) onSaveTemplate(name.trim(), steps);
|
|
2464
|
+
}
|
|
2465
|
+
function handleDelete() {
|
|
2466
|
+
if (!selectedTemplateId) return;
|
|
2467
|
+
const tpl = templates.find((t) => t.id === selectedTemplateId);
|
|
2468
|
+
if (tpl && window.confirm(`Delete template "${tpl.name}"?`)) {
|
|
2469
|
+
onDeleteTemplate(selectedTemplateId);
|
|
2470
|
+
}
|
|
2471
|
+
}
|
|
2472
|
+
function handleStepChange(updated) {
|
|
2473
|
+
onChange(steps.map((s) => {
|
|
2474
|
+
if (s.addonId !== updated.addonId) return s;
|
|
2475
|
+
return autoEnableAncestors(updated);
|
|
2476
|
+
}));
|
|
2477
|
+
}
|
|
2478
|
+
function autoEnableAncestors(step) {
|
|
2479
|
+
const hasEnabledChild = step.children.some((c) => c.enabled || c.children.some((gc) => gc.enabled));
|
|
2480
|
+
return {
|
|
2481
|
+
...step,
|
|
2482
|
+
enabled: step.enabled || hasEnabledChild,
|
|
2483
|
+
children: step.children.map((c) => {
|
|
2484
|
+
const hasEnabledGrandchild = c.children.some((gc) => gc.enabled);
|
|
2485
|
+
return {
|
|
2486
|
+
...c,
|
|
2487
|
+
enabled: c.enabled || hasEnabledGrandchild
|
|
2488
|
+
};
|
|
2489
|
+
})
|
|
2490
|
+
};
|
|
2491
|
+
}
|
|
2492
|
+
function handleAddChildToStep(parentAddonId, addon) {
|
|
2493
|
+
const child = createDefaultStep(addon, defaultRuntime, defaultBackend);
|
|
2494
|
+
onChange(steps.map((s) => {
|
|
2495
|
+
if (s.addonId !== parentAddonId) return s;
|
|
2496
|
+
return { ...s, children: [...s.children, child] };
|
|
2497
|
+
}));
|
|
2498
|
+
}
|
|
2499
|
+
function collectIds(list) {
|
|
2500
|
+
const ids = /* @__PURE__ */ new Set();
|
|
2501
|
+
for (const s of list) {
|
|
2502
|
+
ids.add(s.addonId);
|
|
2503
|
+
for (const c of s.children) ids.add(c.addonId);
|
|
2504
|
+
const childIds = collectIds(s.children);
|
|
2505
|
+
for (const id of childIds) ids.add(id);
|
|
2506
|
+
}
|
|
2507
|
+
return ids;
|
|
2508
|
+
}
|
|
2509
|
+
const existingIds = collectIds(steps);
|
|
2510
|
+
function getChildPlaceholders(step) {
|
|
2511
|
+
const stepSchema = schemaMap.get(step.addonId);
|
|
2512
|
+
if (!stepSchema) return [];
|
|
2513
|
+
const childSlotIds = stepSchema.childSlots;
|
|
2514
|
+
const childIds = new Set(step.children.map((c) => c.addonId));
|
|
2515
|
+
const placeholders = [];
|
|
2516
|
+
for (const slot of schema.slots) {
|
|
2517
|
+
if (!childSlotIds.includes(slot.id)) continue;
|
|
2518
|
+
for (const addon of slot.addons) {
|
|
2519
|
+
if (childIds.has(addon.id) || excluded.has(addon.id)) continue;
|
|
2520
|
+
const compatible = addon.inputClasses.some((ic) => step.outputClasses.includes(ic));
|
|
2521
|
+
if (compatible) placeholders.push(addon);
|
|
2522
|
+
}
|
|
2523
|
+
}
|
|
2524
|
+
return placeholders;
|
|
2525
|
+
}
|
|
2526
|
+
function renderStep(step) {
|
|
2527
|
+
const childPlaceholders = getChildPlaceholders(step);
|
|
2528
|
+
return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "space-y-1.5", children: [
|
|
2529
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
|
|
2530
|
+
PipelineStep,
|
|
2531
|
+
{
|
|
2532
|
+
step,
|
|
2533
|
+
schema: schemaMap.get(step.addonId) ?? null,
|
|
2534
|
+
allSchemas: schemaMap,
|
|
2535
|
+
capabilities,
|
|
2536
|
+
onChange: handleStepChange,
|
|
2537
|
+
onDelete: readOnly ? void 0 : (id) => onChange(steps.filter((s) => s.addonId !== id)),
|
|
2538
|
+
readOnly
|
|
2539
|
+
}
|
|
2540
|
+
),
|
|
2541
|
+
(step.children.length > 0 || childPlaceholders.length > 0) && /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "ml-6 pl-4 border-l-2 border-dashed border-border/40 space-y-1.5", children: [
|
|
2542
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "text-[10px] font-semibold uppercase tracking-widest text-foreground-subtle/40", children: "Slot: Cropper / Classifier" }),
|
|
2543
|
+
step.children.map((child) => {
|
|
2544
|
+
const childChildPlaceholders = getChildPlaceholders(child);
|
|
2545
|
+
return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "space-y-1.5", children: [
|
|
2546
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
|
|
2547
|
+
PipelineStep,
|
|
2548
|
+
{
|
|
2549
|
+
step: child,
|
|
2550
|
+
schema: schemaMap.get(child.addonId) ?? null,
|
|
2551
|
+
allSchemas: schemaMap,
|
|
2552
|
+
capabilities,
|
|
2553
|
+
depth: 1,
|
|
2554
|
+
onChange: (updated) => {
|
|
2555
|
+
handleStepChange({
|
|
2556
|
+
...step,
|
|
2557
|
+
children: step.children.map((c) => c.addonId === updated.addonId ? updated : c)
|
|
2558
|
+
});
|
|
2559
|
+
},
|
|
2560
|
+
onDelete: readOnly ? void 0 : (id) => {
|
|
2561
|
+
handleStepChange({
|
|
2562
|
+
...step,
|
|
2563
|
+
children: step.children.filter((c) => c.addonId !== id)
|
|
2564
|
+
});
|
|
2565
|
+
},
|
|
2566
|
+
readOnly
|
|
2567
|
+
}
|
|
2568
|
+
),
|
|
2569
|
+
(child.children.length > 0 || childChildPlaceholders.length > 0) && /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "ml-6 pl-4 border-l-2 border-dashed border-border/30 space-y-1.5", children: [
|
|
2570
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "text-[10px] font-semibold uppercase tracking-widest text-foreground-subtle/30", children: "Slot: Recognizer" }),
|
|
2571
|
+
child.children.map((grandchild) => /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
|
|
2572
|
+
PipelineStep,
|
|
2573
|
+
{
|
|
2574
|
+
step: grandchild,
|
|
2575
|
+
schema: schemaMap.get(grandchild.addonId) ?? null,
|
|
2576
|
+
allSchemas: schemaMap,
|
|
2577
|
+
capabilities,
|
|
2578
|
+
depth: 2,
|
|
2579
|
+
onChange: (updatedGrandchild) => {
|
|
2580
|
+
handleStepChange({
|
|
2581
|
+
...step,
|
|
2582
|
+
children: step.children.map(
|
|
2583
|
+
(c) => c.addonId === child.addonId ? { ...c, children: c.children.map((gc) => gc.addonId === updatedGrandchild.addonId ? updatedGrandchild : gc) } : c
|
|
2584
|
+
)
|
|
2585
|
+
});
|
|
2586
|
+
},
|
|
2587
|
+
onDelete: readOnly ? void 0 : (id) => {
|
|
2588
|
+
handleStepChange({
|
|
2589
|
+
...step,
|
|
2590
|
+
children: step.children.map(
|
|
2591
|
+
(c) => c.addonId === child.addonId ? { ...c, children: c.children.filter((gc) => gc.addonId !== id) } : c
|
|
2592
|
+
)
|
|
2593
|
+
});
|
|
2594
|
+
},
|
|
2595
|
+
readOnly
|
|
2596
|
+
},
|
|
2597
|
+
grandchild.addonId
|
|
2598
|
+
)),
|
|
2599
|
+
!readOnly && childChildPlaceholders.map((addon) => /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
|
|
2600
|
+
PlaceholderStep,
|
|
2601
|
+
{
|
|
2602
|
+
addon,
|
|
2603
|
+
onClick: () => {
|
|
2604
|
+
const newChild = createDefaultStep(addon, defaultRuntime, defaultBackend);
|
|
2605
|
+
handleStepChange({
|
|
2606
|
+
...step,
|
|
2607
|
+
children: step.children.map(
|
|
2608
|
+
(c) => c.addonId === child.addonId ? { ...c, children: [...c.children, newChild] } : c
|
|
2609
|
+
)
|
|
2610
|
+
});
|
|
2611
|
+
}
|
|
2612
|
+
},
|
|
2613
|
+
addon.id
|
|
2614
|
+
))
|
|
2615
|
+
] })
|
|
2616
|
+
] }, child.addonId);
|
|
2617
|
+
}),
|
|
2618
|
+
!readOnly && childPlaceholders.map((addon) => /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
|
|
2619
|
+
PlaceholderStep,
|
|
2620
|
+
{
|
|
2621
|
+
addon,
|
|
2622
|
+
onClick: () => handleAddChildToStep(step.addonId, addon)
|
|
2623
|
+
},
|
|
2624
|
+
addon.id
|
|
2625
|
+
))
|
|
2626
|
+
] })
|
|
2627
|
+
] }, step.addonId);
|
|
2628
|
+
}
|
|
2629
|
+
const rootSlots = schema.slots.filter((s) => s.parentSlot === null).sort((a, b) => a.priority - b.priority);
|
|
2630
|
+
return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "space-y-4", children: [
|
|
2631
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { className: "rounded-xl border border-border bg-surface p-3", children: /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
2632
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { className: "relative flex-1 min-w-0", children: /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(
|
|
2633
|
+
"select",
|
|
2634
|
+
{
|
|
2635
|
+
value: selectedTemplateId ?? "",
|
|
2636
|
+
onChange: handleSelectTemplate,
|
|
2637
|
+
className: "w-full rounded-lg border border-border bg-background px-3 py-2 text-sm text-foreground focus:outline-none focus:border-primary/50",
|
|
2638
|
+
children: [
|
|
2639
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)("option", { value: "", children: "No template" }),
|
|
2640
|
+
templates.map((t) => /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("option", { value: t.id, children: t.name }, t.id))
|
|
2641
|
+
]
|
|
2642
|
+
}
|
|
2643
|
+
) }),
|
|
2644
|
+
dirty && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "h-1.5 w-1.5 rounded-full bg-amber-500 shrink-0" }),
|
|
2645
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
|
|
2646
|
+
"button",
|
|
2647
|
+
{
|
|
2648
|
+
onClick: handleSave,
|
|
2649
|
+
disabled: !selectedTemplateId || readOnly,
|
|
2650
|
+
title: "Save",
|
|
2651
|
+
className: cn(
|
|
2652
|
+
"p-2 rounded-lg border border-border transition-colors",
|
|
2653
|
+
selectedTemplateId && !readOnly ? "text-foreground-subtle hover:bg-surface-hover" : "text-foreground-subtle/30 cursor-not-allowed"
|
|
2654
|
+
),
|
|
2655
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_lucide_react14.Save, { className: "h-4 w-4" })
|
|
2656
|
+
}
|
|
2657
|
+
),
|
|
2658
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
|
|
2659
|
+
"button",
|
|
2660
|
+
{
|
|
2661
|
+
onClick: handleSaveAs,
|
|
2662
|
+
disabled: readOnly,
|
|
2663
|
+
title: "Save As",
|
|
2664
|
+
className: cn(
|
|
2665
|
+
"p-2 rounded-lg border border-border transition-colors",
|
|
2666
|
+
!readOnly ? "text-foreground-subtle hover:bg-surface-hover" : "text-foreground-subtle/30 cursor-not-allowed"
|
|
2667
|
+
),
|
|
2668
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_lucide_react14.CopyPlus, { className: "h-4 w-4" })
|
|
2669
|
+
}
|
|
2670
|
+
),
|
|
2671
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
|
|
2672
|
+
"button",
|
|
2673
|
+
{
|
|
2674
|
+
onClick: handleDelete,
|
|
2675
|
+
disabled: !selectedTemplateId || readOnly,
|
|
2676
|
+
title: "Delete",
|
|
2677
|
+
className: cn(
|
|
2678
|
+
"p-2 rounded-lg border border-border transition-colors",
|
|
2679
|
+
selectedTemplateId && !readOnly ? "text-foreground-subtle hover:text-danger" : "text-foreground-subtle/30 cursor-not-allowed"
|
|
2680
|
+
),
|
|
2681
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_lucide_react14.Trash2, { className: "h-4 w-4" })
|
|
2682
|
+
}
|
|
2683
|
+
)
|
|
2684
|
+
] }) }),
|
|
2685
|
+
warnings.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "rounded-lg border border-amber-500/30 bg-amber-500/5 p-3 text-xs text-amber-400 space-y-1", children: [
|
|
2686
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "flex items-center justify-between", children: [
|
|
2687
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "font-medium", children: "Template loaded with warnings:" }),
|
|
2688
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)("button", { onClick: () => setWarnings([]), className: "text-amber-400/60 hover:text-amber-400", children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_lucide_react14.X, { className: "h-3.5 w-3.5" }) })
|
|
2689
|
+
] }),
|
|
2690
|
+
warnings.map((w, i) => /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { children: [
|
|
2691
|
+
"\u2022 ",
|
|
2692
|
+
w
|
|
2693
|
+
] }, i))
|
|
2694
|
+
] }),
|
|
2695
|
+
rootSlots.map((slot) => {
|
|
2696
|
+
const slotSteps = steps.filter((s) => s.slot === slot.id && !excluded.has(s.addonId));
|
|
2697
|
+
const missingRootAddons = slot.addons.filter((a) => !existingIds.has(a.id) && !excluded.has(a.id));
|
|
2698
|
+
return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "space-y-2", children: [
|
|
2699
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("span", { className: "text-[10px] font-semibold uppercase tracking-widest text-foreground-subtle/50", children: [
|
|
2700
|
+
"Slot: ",
|
|
2701
|
+
slot.label
|
|
2702
|
+
] }),
|
|
2703
|
+
slotSteps.map((step) => renderStep(step)),
|
|
2704
|
+
!readOnly && missingRootAddons.map((addon) => /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(PlaceholderStep, { addon, onClick: () => {
|
|
2705
|
+
onChange([...steps, createDefaultStep(addon, defaultRuntime, defaultBackend)]);
|
|
2706
|
+
} }, addon.id))
|
|
2707
|
+
] }, slot.id);
|
|
2708
|
+
})
|
|
2709
|
+
] });
|
|
2710
|
+
}
|
|
2711
|
+
|
|
2712
|
+
// src/composites/detection-colors.ts
|
|
2713
|
+
var CLASS_COLORS = {
|
|
2714
|
+
// Primary detection classes
|
|
2715
|
+
person: "#3b82f6",
|
|
2716
|
+
// blue-500
|
|
2717
|
+
vehicle: "#f59e0b",
|
|
2718
|
+
// amber-500
|
|
2719
|
+
animal: "#22c55e",
|
|
2720
|
+
// green-500
|
|
2721
|
+
// Sub-detection classes
|
|
2722
|
+
face: "#a855f7",
|
|
2723
|
+
// purple-500
|
|
2724
|
+
plate: "#ec4899",
|
|
2725
|
+
// pink-500
|
|
2726
|
+
// Specific animal types
|
|
2727
|
+
bird: "#14b8a6",
|
|
2728
|
+
// teal-500
|
|
2729
|
+
dog: "#84cc16",
|
|
2730
|
+
// lime-500
|
|
2731
|
+
cat: "#f97316",
|
|
2732
|
+
// orange-500
|
|
2733
|
+
// Specific vehicle types
|
|
2734
|
+
car: "#f59e0b",
|
|
2735
|
+
// amber-500
|
|
2736
|
+
truck: "#d97706",
|
|
2737
|
+
// amber-600
|
|
2738
|
+
bus: "#b45309",
|
|
2739
|
+
// amber-700
|
|
2740
|
+
motorcycle: "#eab308",
|
|
2741
|
+
// yellow-500
|
|
2742
|
+
bicycle: "#ca8a04",
|
|
2743
|
+
// yellow-600
|
|
2744
|
+
// Other
|
|
2745
|
+
motion: "#facc15"
|
|
2746
|
+
// yellow-400
|
|
2747
|
+
};
|
|
2748
|
+
var FALLBACK_PALETTE = [
|
|
2749
|
+
"#ef4444",
|
|
2750
|
+
// red-500
|
|
2751
|
+
"#8b5cf6",
|
|
2752
|
+
// violet-500
|
|
2753
|
+
"#06b6d4",
|
|
2754
|
+
// cyan-500
|
|
2755
|
+
"#f97316",
|
|
2756
|
+
// orange-500
|
|
2757
|
+
"#10b981",
|
|
2758
|
+
// emerald-500
|
|
2759
|
+
"#6366f1",
|
|
2760
|
+
// indigo-500
|
|
2761
|
+
"#e11d48",
|
|
2762
|
+
// rose-600
|
|
2763
|
+
"#0891b2",
|
|
2764
|
+
// cyan-600
|
|
2765
|
+
"#7c3aed",
|
|
2766
|
+
// violet-600
|
|
2767
|
+
"#059669"
|
|
2768
|
+
// emerald-600
|
|
2769
|
+
];
|
|
2770
|
+
var DEFAULT_COLOR = "#f59e42";
|
|
2771
|
+
function getClassColor(className, customColors) {
|
|
2772
|
+
if (customColors?.[className]) return customColors[className];
|
|
2773
|
+
if (customColors?.[className.toLowerCase()]) return customColors[className.toLowerCase()];
|
|
2774
|
+
if (CLASS_COLORS[className]) return CLASS_COLORS[className];
|
|
2775
|
+
if (CLASS_COLORS[className.toLowerCase()]) return CLASS_COLORS[className.toLowerCase()];
|
|
2776
|
+
let hash = 0;
|
|
2777
|
+
for (let i = 0; i < className.length; i++) {
|
|
2778
|
+
hash = hash * 31 + (className.codePointAt(i) ?? 0) >>> 0;
|
|
2779
|
+
}
|
|
2780
|
+
return FALLBACK_PALETTE[hash % FALLBACK_PALETTE.length] ?? DEFAULT_COLOR;
|
|
2781
|
+
}
|
|
2782
|
+
|
|
2783
|
+
// src/composites/detection-canvas.tsx
|
|
2784
|
+
var import_react25 = require("react");
|
|
2785
|
+
var import_jsx_runtime43 = require("react/jsx-runtime");
|
|
2786
|
+
var DEFAULT_CLASS_COLORS = CLASS_COLORS;
|
|
2787
|
+
function DetectionCanvas({
|
|
2788
|
+
src,
|
|
2789
|
+
imageWidth,
|
|
2790
|
+
imageHeight,
|
|
2791
|
+
detections = [],
|
|
2792
|
+
classColors,
|
|
2793
|
+
aspectRatio,
|
|
2794
|
+
className,
|
|
2795
|
+
placeholder,
|
|
2796
|
+
showConfidence = true,
|
|
2797
|
+
minConfidence = 0,
|
|
2798
|
+
borderWidth = 2
|
|
2799
|
+
}) {
|
|
2800
|
+
function getColor(className2) {
|
|
2801
|
+
return getClassColor(className2, classColors);
|
|
2802
|
+
}
|
|
2803
|
+
const ratio = aspectRatio ?? (imageWidth && imageHeight ? `${imageWidth}/${imageHeight}` : "16/9");
|
|
2804
|
+
const filteredDetections = detections.filter((d) => d.confidence >= minConfidence);
|
|
2805
|
+
return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
|
|
2806
|
+
"div",
|
|
2807
|
+
{
|
|
2808
|
+
className: cn(
|
|
2809
|
+
"rounded-lg border border-border bg-surface overflow-hidden relative",
|
|
2810
|
+
className
|
|
2811
|
+
),
|
|
2812
|
+
style: { aspectRatio: ratio },
|
|
2813
|
+
children: src ? /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(import_jsx_runtime43.Fragment, { children: [
|
|
2814
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)("img", { src, className: "absolute inset-0 w-full h-full object-fill", alt: "" }),
|
|
2815
|
+
filteredDetections.map(
|
|
2816
|
+
(d, i) => d.mask && d.maskWidth && d.maskHeight ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
|
|
2817
|
+
MaskOverlay,
|
|
2818
|
+
{
|
|
2819
|
+
mask: d.mask,
|
|
2820
|
+
maskWidth: d.maskWidth,
|
|
2821
|
+
maskHeight: d.maskHeight,
|
|
2822
|
+
bbox: d.bbox,
|
|
2823
|
+
imageWidth,
|
|
2824
|
+
imageHeight,
|
|
2825
|
+
color: getColor(d.className)
|
|
2826
|
+
},
|
|
2827
|
+
`mask-${i}`
|
|
2828
|
+
) : null
|
|
2829
|
+
),
|
|
2830
|
+
filteredDetections.map((d, i) => /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
|
|
2831
|
+
BoundingBox,
|
|
2832
|
+
{
|
|
2833
|
+
detection: d,
|
|
2834
|
+
imageWidth,
|
|
2835
|
+
imageHeight,
|
|
2836
|
+
color: getColor(d.className),
|
|
2837
|
+
showConfidence,
|
|
2838
|
+
borderWidth: d.mask ? 1 : borderWidth,
|
|
2839
|
+
children: d.children?.filter((c) => {
|
|
2840
|
+
if (c.confidence < minConfidence) return false;
|
|
2841
|
+
const [cx1, cy1, cx2, cy2] = c.bbox;
|
|
2842
|
+
const cw = cx2 - cx1;
|
|
2843
|
+
const ch = cy2 - cy1;
|
|
2844
|
+
if (cw <= 0 || ch <= 0) return false;
|
|
2845
|
+
const [px1, py1, px2, py2] = d.bbox;
|
|
2846
|
+
const pw = px2 - px1;
|
|
2847
|
+
const ph = py2 - py1;
|
|
2848
|
+
if (pw > 0 && ph > 0 && cw * ch / (pw * ph) > 0.8) return false;
|
|
2849
|
+
return true;
|
|
2850
|
+
}).map((child, j) => /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
|
|
2851
|
+
ChildBoundingBox,
|
|
2852
|
+
{
|
|
2853
|
+
child,
|
|
2854
|
+
parentBbox: d.bbox,
|
|
2855
|
+
color: getColor(child.className),
|
|
2856
|
+
showConfidence
|
|
2857
|
+
},
|
|
2858
|
+
`child-${j}`
|
|
2859
|
+
))
|
|
2860
|
+
},
|
|
2861
|
+
`det-${i}`
|
|
2862
|
+
))
|
|
2863
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: "w-full h-full flex items-center justify-center text-foreground-subtle text-sm", children: placeholder ?? "No image loaded" })
|
|
2864
|
+
}
|
|
2865
|
+
);
|
|
2866
|
+
}
|
|
2867
|
+
function BoundingBox({
|
|
2868
|
+
detection,
|
|
2869
|
+
imageWidth,
|
|
2870
|
+
imageHeight,
|
|
2871
|
+
color,
|
|
2872
|
+
showConfidence,
|
|
2873
|
+
borderWidth,
|
|
2874
|
+
children
|
|
2875
|
+
}) {
|
|
2876
|
+
const [x1, y1, x2, y2] = detection.bbox;
|
|
2877
|
+
const labelCount = 1 + (detection.labelsData?.length ?? 0);
|
|
2878
|
+
const labelHeightPx = labelCount * 16 + 4;
|
|
2879
|
+
const topPct = y1 / imageHeight * 100;
|
|
2880
|
+
const containerRef = (0, import_react25.useRef)(null);
|
|
2881
|
+
const showBelow = topPct < labelHeightPx / imageHeight * 100 * 1.5;
|
|
2882
|
+
const labelsElement = /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
|
|
2883
|
+
"div",
|
|
2884
|
+
{
|
|
2885
|
+
className: `absolute left-0 flex flex-col items-start gap-px ${showBelow ? "" : ""}`,
|
|
2886
|
+
style: showBelow ? { top: "100%", marginTop: "2px" } : { bottom: "100%", marginBottom: "2px" },
|
|
2887
|
+
children: [
|
|
2888
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
|
|
2889
|
+
"span",
|
|
2890
|
+
{
|
|
2891
|
+
className: "text-[10px] px-1 rounded-sm whitespace-nowrap text-white",
|
|
2892
|
+
style: { backgroundColor: color },
|
|
2893
|
+
children: [
|
|
2894
|
+
detection.className,
|
|
2895
|
+
showConfidence && ` ${(detection.confidence * 100).toFixed(0)}%`
|
|
2896
|
+
]
|
|
2897
|
+
}
|
|
2898
|
+
),
|
|
2899
|
+
detection.labelsData?.map((l, k) => /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
|
|
2900
|
+
"span",
|
|
2901
|
+
{
|
|
2902
|
+
className: "text-[9px] font-semibold px-1 rounded-sm whitespace-nowrap text-white",
|
|
2903
|
+
style: { backgroundColor: getClassColor(l.addonId ?? l.label) },
|
|
2904
|
+
children: [
|
|
2905
|
+
l.label,
|
|
2906
|
+
" ",
|
|
2907
|
+
(l.score * 100).toFixed(0),
|
|
2908
|
+
"%"
|
|
2909
|
+
]
|
|
2910
|
+
},
|
|
2911
|
+
k
|
|
2912
|
+
))
|
|
2913
|
+
]
|
|
2914
|
+
}
|
|
2915
|
+
);
|
|
2916
|
+
return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
|
|
2917
|
+
"div",
|
|
2918
|
+
{
|
|
2919
|
+
ref: containerRef,
|
|
2920
|
+
className: "absolute rounded-sm",
|
|
2921
|
+
style: {
|
|
2922
|
+
left: `${x1 / imageWidth * 100}%`,
|
|
2923
|
+
top: `${y1 / imageHeight * 100}%`,
|
|
2924
|
+
width: `${(x2 - x1) / imageWidth * 100}%`,
|
|
2925
|
+
height: `${(y2 - y1) / imageHeight * 100}%`,
|
|
2926
|
+
borderWidth: `${borderWidth}px`,
|
|
2927
|
+
borderStyle: "solid",
|
|
2928
|
+
borderColor: color
|
|
2929
|
+
},
|
|
2930
|
+
children: [
|
|
2931
|
+
labelsElement,
|
|
2932
|
+
children
|
|
2933
|
+
]
|
|
2934
|
+
}
|
|
2935
|
+
);
|
|
2936
|
+
}
|
|
2937
|
+
function MaskOverlay({
|
|
2938
|
+
mask,
|
|
2939
|
+
maskWidth,
|
|
2940
|
+
maskHeight,
|
|
2941
|
+
bbox,
|
|
2942
|
+
imageWidth,
|
|
2943
|
+
imageHeight,
|
|
2944
|
+
color
|
|
2945
|
+
}) {
|
|
2946
|
+
const canvasRef = (0, import_react25.useRef)(null);
|
|
2947
|
+
(0, import_react25.useEffect)(() => {
|
|
2948
|
+
const canvas = canvasRef.current;
|
|
2949
|
+
if (!canvas) return;
|
|
2950
|
+
const ctx = canvas.getContext("2d");
|
|
2951
|
+
if (!ctx) return;
|
|
2952
|
+
const binary = atob(mask);
|
|
2953
|
+
const bytes = new Uint8Array(binary.length);
|
|
2954
|
+
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
|
|
2955
|
+
const r = parseInt(color.slice(1, 3), 16);
|
|
2956
|
+
const g = parseInt(color.slice(3, 5), 16);
|
|
2957
|
+
const b = parseInt(color.slice(5, 7), 16);
|
|
2958
|
+
canvas.width = maskWidth;
|
|
2959
|
+
canvas.height = maskHeight;
|
|
2960
|
+
const imageData = ctx.createImageData(maskWidth, maskHeight);
|
|
2961
|
+
const totalPixels = maskWidth * maskHeight;
|
|
2962
|
+
for (let i = 0; i < totalPixels; i++) {
|
|
2963
|
+
const val = i < bytes.length ? bytes[i] : 0;
|
|
2964
|
+
const px = i * 4;
|
|
2965
|
+
if (val > 0) {
|
|
2966
|
+
imageData.data[px] = r;
|
|
2967
|
+
imageData.data[px + 1] = g;
|
|
2968
|
+
imageData.data[px + 2] = b;
|
|
2969
|
+
imageData.data[px + 3] = 120;
|
|
2970
|
+
}
|
|
2971
|
+
}
|
|
2972
|
+
ctx.putImageData(imageData, 0, 0);
|
|
2973
|
+
}, [mask, maskWidth, maskHeight, color]);
|
|
2974
|
+
const [x1, y1, x2, y2] = bbox;
|
|
2975
|
+
return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
|
|
2976
|
+
"canvas",
|
|
2977
|
+
{
|
|
2978
|
+
ref: canvasRef,
|
|
2979
|
+
className: "absolute pointer-events-none",
|
|
2980
|
+
style: {
|
|
2981
|
+
left: `${x1 / imageWidth * 100}%`,
|
|
2982
|
+
top: `${y1 / imageHeight * 100}%`,
|
|
2983
|
+
width: `${(x2 - x1) / imageWidth * 100}%`,
|
|
2984
|
+
height: `${(y2 - y1) / imageHeight * 100}%`,
|
|
2985
|
+
imageRendering: "pixelated"
|
|
2986
|
+
}
|
|
2987
|
+
}
|
|
2988
|
+
);
|
|
2989
|
+
}
|
|
2990
|
+
function ChildBoundingBox({
|
|
2991
|
+
child,
|
|
2992
|
+
parentBbox,
|
|
2993
|
+
color,
|
|
2994
|
+
showConfidence
|
|
2995
|
+
}) {
|
|
2996
|
+
const [px1, py1, px2, py2] = parentBbox;
|
|
2997
|
+
const [cx1, cy1, cx2, cy2] = child.bbox;
|
|
2998
|
+
const pw = px2 - px1;
|
|
2999
|
+
const ph = py2 - py1;
|
|
3000
|
+
if (pw <= 0 || ph <= 0) return null;
|
|
3001
|
+
return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
|
|
3002
|
+
"div",
|
|
3003
|
+
{
|
|
3004
|
+
className: "absolute rounded-sm",
|
|
3005
|
+
style: {
|
|
3006
|
+
left: `${Math.max(0, (cx1 - px1) / pw * 100)}%`,
|
|
3007
|
+
top: `${Math.max(0, (cy1 - py1) / ph * 100)}%`,
|
|
3008
|
+
width: `${Math.min(100, (cx2 - cx1) / pw * 100)}%`,
|
|
3009
|
+
height: `${Math.min(100, (cy2 - cy1) / ph * 100)}%`,
|
|
3010
|
+
borderWidth: "1px",
|
|
3011
|
+
borderStyle: "solid",
|
|
3012
|
+
borderColor: color
|
|
3013
|
+
},
|
|
3014
|
+
children: (() => {
|
|
3015
|
+
const labelCount = 1 + (child.labelsData?.length ?? 0);
|
|
3016
|
+
const relTop = (cy1 - py1) / ph * 100;
|
|
3017
|
+
const showBelow = relTop < labelCount * 6;
|
|
3018
|
+
return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
|
|
3019
|
+
"div",
|
|
3020
|
+
{
|
|
3021
|
+
className: "absolute left-0 flex flex-col items-start gap-px",
|
|
3022
|
+
style: showBelow ? { top: "100%", marginTop: "1px" } : { bottom: "100%", marginBottom: "1px" },
|
|
3023
|
+
children: [
|
|
3024
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
|
|
3025
|
+
"span",
|
|
3026
|
+
{
|
|
3027
|
+
className: "text-[9px] px-0.5 rounded-sm whitespace-nowrap text-white",
|
|
3028
|
+
style: { backgroundColor: color },
|
|
3029
|
+
children: [
|
|
3030
|
+
child.className,
|
|
3031
|
+
showConfidence && ` ${(child.confidence * 100).toFixed(0)}%`
|
|
3032
|
+
]
|
|
3033
|
+
}
|
|
3034
|
+
),
|
|
3035
|
+
child.labelsData?.map((l, k) => /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
|
|
3036
|
+
"span",
|
|
3037
|
+
{
|
|
3038
|
+
className: "text-[8px] font-semibold px-0.5 rounded-sm whitespace-nowrap text-white",
|
|
3039
|
+
style: { backgroundColor: getClassColor(l.addonId ?? l.label) },
|
|
3040
|
+
children: [
|
|
3041
|
+
l.label,
|
|
3042
|
+
" ",
|
|
3043
|
+
(l.score * 100).toFixed(0),
|
|
3044
|
+
"%"
|
|
3045
|
+
]
|
|
3046
|
+
},
|
|
3047
|
+
k
|
|
3048
|
+
))
|
|
3049
|
+
]
|
|
3050
|
+
}
|
|
3051
|
+
);
|
|
3052
|
+
})()
|
|
3053
|
+
}
|
|
3054
|
+
);
|
|
3055
|
+
}
|
|
3056
|
+
|
|
3057
|
+
// src/composites/detection-result-tree.tsx
|
|
3058
|
+
var import_jsx_runtime44 = require("react/jsx-runtime");
|
|
3059
|
+
function DetectionResultTree({
|
|
3060
|
+
detections,
|
|
3061
|
+
classColors,
|
|
3062
|
+
className,
|
|
3063
|
+
hiddenKeys,
|
|
3064
|
+
onToggleVisibility
|
|
3065
|
+
}) {
|
|
3066
|
+
const colors = classColors;
|
|
3067
|
+
if (detections.length === 0) {
|
|
3068
|
+
return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", { className: "text-sm text-foreground-subtle italic text-center py-4", children: "No detections" });
|
|
3069
|
+
}
|
|
3070
|
+
return /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className, children: [
|
|
3071
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "text-xs font-medium text-foreground-subtle uppercase tracking-wide mb-2", children: [
|
|
3072
|
+
"Detections (",
|
|
3073
|
+
detections.length,
|
|
3074
|
+
")"
|
|
3075
|
+
] }),
|
|
3076
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", { className: "space-y-2", children: detections.map((d, i) => /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
|
|
3077
|
+
DetectionNode,
|
|
3078
|
+
{
|
|
3079
|
+
detection: d,
|
|
3080
|
+
path: String(i),
|
|
3081
|
+
colors,
|
|
3082
|
+
hiddenKeys,
|
|
3083
|
+
onToggleVisibility
|
|
3084
|
+
},
|
|
3085
|
+
i
|
|
3086
|
+
)) })
|
|
3087
|
+
] });
|
|
3088
|
+
}
|
|
3089
|
+
function DetectionNode({
|
|
3090
|
+
detection,
|
|
3091
|
+
path,
|
|
3092
|
+
colors,
|
|
3093
|
+
hiddenKeys,
|
|
3094
|
+
onToggleVisibility
|
|
3095
|
+
}) {
|
|
3096
|
+
const color = getClassColor(detection.className, colors);
|
|
3097
|
+
const isVisible = !hiddenKeys?.has(path);
|
|
3098
|
+
return /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: `rounded-md border border-border bg-surface p-3 space-y-1 ${isVisible ? "" : "opacity-40"}`, children: [
|
|
3099
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "flex justify-between items-center", children: [
|
|
3100
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
3101
|
+
onToggleVisibility && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
|
|
3102
|
+
"input",
|
|
3103
|
+
{
|
|
3104
|
+
type: "checkbox",
|
|
3105
|
+
checked: isVisible,
|
|
3106
|
+
onChange: () => onToggleVisibility(path, !isVisible),
|
|
3107
|
+
className: "h-3.5 w-3.5 rounded border-border accent-primary cursor-pointer shrink-0"
|
|
3108
|
+
}
|
|
3109
|
+
),
|
|
3110
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
|
|
3111
|
+
"span",
|
|
3112
|
+
{
|
|
3113
|
+
className: "h-2.5 w-2.5 rounded-full shrink-0",
|
|
3114
|
+
style: { backgroundColor: color }
|
|
3115
|
+
}
|
|
3116
|
+
),
|
|
3117
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: "text-sm font-medium text-foreground", children: detection.className }),
|
|
3118
|
+
detection.mask && detection.maskWidth && detection.maskHeight && /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("span", { className: "text-[9px] font-mono px-1 py-0.5 rounded bg-primary/10 text-primary", children: [
|
|
3119
|
+
"mask ",
|
|
3120
|
+
detection.maskWidth,
|
|
3121
|
+
"x",
|
|
3122
|
+
detection.maskHeight
|
|
3123
|
+
] })
|
|
3124
|
+
] }),
|
|
3125
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)(ConfidenceBadge, { confidence: detection.confidence })
|
|
3126
|
+
] }),
|
|
3127
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "text-[10px] text-foreground-subtle font-mono", children: [
|
|
3128
|
+
"bbox: [",
|
|
3129
|
+
detection.bbox.map((v) => Math.round(v)).join(", "),
|
|
3130
|
+
"]"
|
|
3131
|
+
] }),
|
|
3132
|
+
detection.labelsData && detection.labelsData.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", { className: "flex flex-wrap gap-1 mt-1", children: detection.labelsData.map((l, k) => /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(
|
|
3133
|
+
"span",
|
|
3134
|
+
{
|
|
3135
|
+
className: "inline-flex items-center gap-1 text-[10px] font-medium px-1.5 py-0.5 rounded-full",
|
|
3136
|
+
style: { backgroundColor: getClassColor(l.addonId ?? l.label, colors) + "20", color: getClassColor(l.addonId ?? l.label, colors) },
|
|
3137
|
+
children: [
|
|
3138
|
+
l.label,
|
|
3139
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("span", { className: "opacity-60", children: [
|
|
3140
|
+
(l.score * 100).toFixed(0),
|
|
3141
|
+
"%"
|
|
3142
|
+
] }),
|
|
3143
|
+
l.addonId && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: "opacity-40 text-[8px]", children: l.addonId })
|
|
3144
|
+
]
|
|
3145
|
+
},
|
|
3146
|
+
k
|
|
3147
|
+
)) }),
|
|
3148
|
+
detection.children && detection.children.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
|
|
3149
|
+
ChildrenTree,
|
|
3150
|
+
{
|
|
3151
|
+
children: detection.children,
|
|
3152
|
+
parentPath: path,
|
|
3153
|
+
colors,
|
|
3154
|
+
hiddenKeys,
|
|
3155
|
+
onToggleVisibility
|
|
3156
|
+
}
|
|
3157
|
+
)
|
|
3158
|
+
] });
|
|
3159
|
+
}
|
|
3160
|
+
function ChildrenTree({
|
|
3161
|
+
children,
|
|
3162
|
+
parentPath,
|
|
3163
|
+
colors,
|
|
3164
|
+
hiddenKeys,
|
|
3165
|
+
onToggleVisibility
|
|
3166
|
+
}) {
|
|
3167
|
+
return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", { className: "ml-4 mt-1.5 space-y-1.5 border-l-2 border-border pl-3", children: children.map((child, j) => {
|
|
3168
|
+
const childPath = `${parentPath}.${j}`;
|
|
3169
|
+
const childColor = getClassColor(child.className, colors);
|
|
3170
|
+
const isVisible = !hiddenKeys?.has(childPath);
|
|
3171
|
+
return /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: `text-xs space-y-0.5 ${isVisible ? "" : "opacity-40"}`, children: [
|
|
3172
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "flex items-center gap-1.5", children: [
|
|
3173
|
+
onToggleVisibility && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
|
|
3174
|
+
"input",
|
|
3175
|
+
{
|
|
3176
|
+
type: "checkbox",
|
|
3177
|
+
checked: isVisible,
|
|
3178
|
+
onChange: () => onToggleVisibility(childPath, !isVisible),
|
|
3179
|
+
className: "h-3 w-3 rounded border-border accent-primary cursor-pointer shrink-0"
|
|
3180
|
+
}
|
|
3181
|
+
),
|
|
3182
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
|
|
3183
|
+
"span",
|
|
3184
|
+
{
|
|
3185
|
+
className: "h-1.5 w-1.5 rounded-full shrink-0",
|
|
3186
|
+
style: { backgroundColor: childColor }
|
|
3187
|
+
}
|
|
3188
|
+
),
|
|
3189
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: "font-medium", style: { color: childColor }, children: child.className }),
|
|
3190
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("span", { className: "text-foreground-subtle", children: [
|
|
3191
|
+
(child.confidence * 100).toFixed(0),
|
|
3192
|
+
"%"
|
|
3193
|
+
] }),
|
|
3194
|
+
child.mask && child.maskWidth && child.maskHeight && /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("span", { className: "text-[9px] font-mono px-1 py-0.5 rounded bg-primary/10 text-primary", children: [
|
|
3195
|
+
"mask ",
|
|
3196
|
+
child.maskWidth,
|
|
3197
|
+
"x",
|
|
3198
|
+
child.maskHeight
|
|
3199
|
+
] })
|
|
3200
|
+
] }),
|
|
3201
|
+
child.labelsData && child.labelsData.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", { className: "flex flex-wrap gap-1 ml-5 mt-0.5", children: child.labelsData.map((l, k) => /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(
|
|
3202
|
+
"span",
|
|
3203
|
+
{
|
|
3204
|
+
className: "inline-flex items-center gap-0.5 text-[9px] font-medium px-1 py-0.5 rounded-full",
|
|
3205
|
+
style: { backgroundColor: getClassColor(l.addonId ?? l.label, colors) + "20", color: getClassColor(l.addonId ?? l.label, colors) },
|
|
3206
|
+
children: [
|
|
3207
|
+
l.label,
|
|
3208
|
+
" ",
|
|
3209
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("span", { className: "opacity-60", children: [
|
|
3210
|
+
(l.score * 100).toFixed(0),
|
|
3211
|
+
"%"
|
|
3212
|
+
] })
|
|
3213
|
+
]
|
|
3214
|
+
},
|
|
3215
|
+
k
|
|
3216
|
+
)) }),
|
|
3217
|
+
child.children && child.children.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
|
|
3218
|
+
ChildrenTree,
|
|
3219
|
+
{
|
|
3220
|
+
children: child.children,
|
|
3221
|
+
parentPath: childPath,
|
|
3222
|
+
colors,
|
|
3223
|
+
hiddenKeys,
|
|
3224
|
+
onToggleVisibility
|
|
3225
|
+
}
|
|
3226
|
+
)
|
|
3227
|
+
] }, j);
|
|
3228
|
+
}) });
|
|
3229
|
+
}
|
|
3230
|
+
function ConfidenceBadge({ confidence }) {
|
|
3231
|
+
const level = confidence >= 0.8 ? "bg-success/10 text-success" : confidence >= 0.5 ? "bg-warning/10 text-warning" : "bg-danger/10 text-danger";
|
|
3232
|
+
return /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("span", { className: `text-xs font-medium px-2 py-0.5 rounded-full ${level}`, children: [
|
|
3233
|
+
(confidence * 100).toFixed(1),
|
|
3234
|
+
"%"
|
|
3235
|
+
] });
|
|
3236
|
+
}
|
|
3237
|
+
|
|
3238
|
+
// src/composites/step-timings.tsx
|
|
3239
|
+
var import_jsx_runtime45 = require("react/jsx-runtime");
|
|
3240
|
+
function StepTimings({ timings, totalMs, className }) {
|
|
3241
|
+
const entries = Object.entries(timings);
|
|
3242
|
+
if (entries.length === 0 && totalMs === void 0) return null;
|
|
3243
|
+
return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: `rounded-lg border border-border bg-surface p-3 space-y-2 ${className ?? ""}`, children: [
|
|
3244
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: "text-xs font-medium text-foreground-subtle uppercase tracking-wide", children: "Timings" }),
|
|
3245
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "space-y-1 text-xs", children: [
|
|
3246
|
+
entries.map(([step, ms]) => /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "flex justify-between", children: [
|
|
3247
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "text-foreground-subtle", children: step }),
|
|
3248
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("span", { className: "font-mono text-foreground", children: [
|
|
3249
|
+
ms.toFixed(1),
|
|
3250
|
+
"ms"
|
|
3251
|
+
] })
|
|
3252
|
+
] }, step)),
|
|
3253
|
+
totalMs !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "flex justify-between pt-1 border-t border-border font-medium text-foreground", children: [
|
|
3254
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { children: "Total" }),
|
|
3255
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("span", { className: "font-mono", children: [
|
|
3256
|
+
totalMs.toFixed(1),
|
|
3257
|
+
"ms"
|
|
3258
|
+
] })
|
|
3259
|
+
] })
|
|
3260
|
+
] })
|
|
3261
|
+
] });
|
|
3262
|
+
}
|
|
3263
|
+
|
|
3264
|
+
// src/composites/image-selector.tsx
|
|
3265
|
+
var import_jsx_runtime46 = require("react/jsx-runtime");
|
|
3266
|
+
function ImageSelector({
|
|
3267
|
+
images,
|
|
3268
|
+
selectedFilename,
|
|
3269
|
+
uploadedName,
|
|
3270
|
+
onSelect,
|
|
3271
|
+
onUpload,
|
|
3272
|
+
className
|
|
3273
|
+
}) {
|
|
3274
|
+
const handleUploadClick = () => {
|
|
3275
|
+
const input = document.createElement("input");
|
|
3276
|
+
input.type = "file";
|
|
3277
|
+
input.accept = "image/*";
|
|
3278
|
+
input.onchange = (ev) => {
|
|
3279
|
+
const file = ev.target.files?.[0];
|
|
3280
|
+
if (!file) return;
|
|
3281
|
+
const reader = new FileReader();
|
|
3282
|
+
reader.onload = (e) => {
|
|
3283
|
+
const dataUrl = e.target?.result;
|
|
3284
|
+
const b64 = dataUrl.split(",")[1];
|
|
3285
|
+
if (b64) onUpload(b64, file.name, dataUrl);
|
|
3286
|
+
};
|
|
3287
|
+
reader.readAsDataURL(file);
|
|
3288
|
+
};
|
|
3289
|
+
input.click();
|
|
3290
|
+
};
|
|
3291
|
+
return /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: `flex flex-wrap items-center gap-2 ${className ?? ""}`, children: [
|
|
3292
|
+
images.map((img) => /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
|
|
3293
|
+
"button",
|
|
3294
|
+
{
|
|
3295
|
+
onClick: () => onSelect(img.filename),
|
|
3296
|
+
className: `px-3 py-1.5 text-xs rounded-md border transition-colors ${selectedFilename === img.filename ? "bg-primary text-primary-foreground border-primary" : "bg-surface border-border text-foreground hover:border-primary/50"}`,
|
|
3297
|
+
children: img.id
|
|
3298
|
+
},
|
|
3299
|
+
img.filename
|
|
3300
|
+
)),
|
|
3301
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
|
|
3302
|
+
"button",
|
|
3303
|
+
{
|
|
3304
|
+
onClick: handleUploadClick,
|
|
3305
|
+
className: "px-3 py-1.5 text-xs rounded-md border border-border bg-surface text-foreground hover:bg-surface-hover transition-colors",
|
|
3306
|
+
children: "Upload..."
|
|
3307
|
+
}
|
|
3308
|
+
),
|
|
3309
|
+
uploadedName && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "text-xs text-foreground-subtle", children: uploadedName })
|
|
3310
|
+
] });
|
|
3311
|
+
}
|
|
3312
|
+
|
|
3313
|
+
// src/composites/inference-config-selector.tsx
|
|
3314
|
+
var import_jsx_runtime47 = require("react/jsx-runtime");
|
|
3315
|
+
var SELECT_CLASS = "w-full px-3 py-2 text-sm rounded-md border border-border bg-surface text-foreground focus:outline-none focus:ring-2 focus:ring-primary/50";
|
|
3316
|
+
function InferenceConfigSelector({
|
|
3317
|
+
runtime,
|
|
3318
|
+
backend,
|
|
3319
|
+
modelId,
|
|
3320
|
+
agentId = "hub",
|
|
3321
|
+
runtimes,
|
|
3322
|
+
backends,
|
|
3323
|
+
models,
|
|
3324
|
+
agents = [],
|
|
3325
|
+
onRuntimeChange,
|
|
3326
|
+
onBackendChange,
|
|
3327
|
+
onModelChange,
|
|
3328
|
+
onAgentChange,
|
|
3329
|
+
layout = "grid",
|
|
3330
|
+
className,
|
|
3331
|
+
showAgent = false
|
|
3332
|
+
}) {
|
|
3333
|
+
const containerClass = layout === "grid" ? "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4" : layout === "horizontal" ? "flex flex-wrap items-end gap-4" : "space-y-3";
|
|
3334
|
+
return /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: `${containerClass} ${className ?? ""}`, children: [
|
|
3335
|
+
showAgent && agents.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("label", { className: "space-y-1", children: [
|
|
3336
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "text-xs font-medium text-foreground-subtle", children: "Agent" }),
|
|
3337
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
|
|
3338
|
+
"select",
|
|
3339
|
+
{
|
|
3340
|
+
value: agentId,
|
|
3341
|
+
onChange: (e) => onAgentChange?.(e.target.value),
|
|
3342
|
+
className: SELECT_CLASS,
|
|
3343
|
+
children: agents.map((a) => /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("option", { value: a.id, children: [
|
|
3344
|
+
a.name,
|
|
3345
|
+
" (",
|
|
3346
|
+
a.status,
|
|
3347
|
+
")"
|
|
3348
|
+
] }, a.id))
|
|
3349
|
+
}
|
|
3350
|
+
)
|
|
3351
|
+
] }),
|
|
3352
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("label", { className: "space-y-1", children: [
|
|
3353
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "text-xs font-medium text-foreground-subtle", children: "Runtime" }),
|
|
3354
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
|
|
3355
|
+
"select",
|
|
3356
|
+
{
|
|
3357
|
+
value: runtime,
|
|
3358
|
+
onChange: (e) => onRuntimeChange(e.target.value),
|
|
3359
|
+
className: SELECT_CLASS,
|
|
3360
|
+
children: runtimes.map((r) => /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("option", { value: r.value, disabled: !r.available, children: [
|
|
3361
|
+
r.label,
|
|
3362
|
+
!r.available ? " (unavailable)" : ""
|
|
3363
|
+
] }, r.value))
|
|
3364
|
+
}
|
|
3365
|
+
)
|
|
3366
|
+
] }),
|
|
3367
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("label", { className: "space-y-1", children: [
|
|
3368
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "text-xs font-medium text-foreground-subtle", children: "Backend" }),
|
|
3369
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
|
|
3370
|
+
"select",
|
|
3371
|
+
{
|
|
3372
|
+
value: backend,
|
|
3373
|
+
onChange: (e) => onBackendChange(e.target.value),
|
|
3374
|
+
className: SELECT_CLASS,
|
|
3375
|
+
children: backends.map((b) => /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("option", { value: b.id, disabled: !b.available, children: [
|
|
3376
|
+
b.label,
|
|
3377
|
+
!b.available ? " (unavailable)" : ""
|
|
3378
|
+
] }, b.id))
|
|
3379
|
+
}
|
|
3380
|
+
)
|
|
3381
|
+
] }),
|
|
3382
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("label", { className: "space-y-1", children: [
|
|
3383
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "text-xs font-medium text-foreground-subtle", children: "Model" }),
|
|
3384
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
|
|
3385
|
+
"select",
|
|
3386
|
+
{
|
|
3387
|
+
value: modelId,
|
|
3388
|
+
onChange: (e) => onModelChange(e.target.value),
|
|
3389
|
+
className: SELECT_CLASS,
|
|
3390
|
+
children: models.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("option", { value: "", children: "No compatible models" }) : models.map((m) => /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("option", { value: m.id, children: [
|
|
3391
|
+
m.name,
|
|
3392
|
+
m.downloaded ? " \u2713" : ""
|
|
3393
|
+
] }, m.id))
|
|
3394
|
+
}
|
|
3395
|
+
)
|
|
3396
|
+
] })
|
|
3397
|
+
] });
|
|
3398
|
+
}
|
|
3399
|
+
|
|
3400
|
+
// src/composites/mount-addon-page.tsx
|
|
3401
|
+
var import_react28 = require("react");
|
|
3402
|
+
var import_client2 = require("react-dom/client");
|
|
3403
|
+
|
|
3404
|
+
// src/composites/dev-shell.tsx
|
|
3405
|
+
var import_react27 = require("react");
|
|
3406
|
+
var import_client = require("@trpc/client");
|
|
3407
|
+
var import_superjson = __toESM(require("superjson"), 1);
|
|
3408
|
+
|
|
3409
|
+
// src/composites/login-form.tsx
|
|
3410
|
+
var import_react26 = require("react");
|
|
3411
|
+
var import_jsx_runtime48 = require("react/jsx-runtime");
|
|
3412
|
+
function EyeIcon({ className }) {
|
|
3413
|
+
return /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(
|
|
3414
|
+
"svg",
|
|
3415
|
+
{
|
|
3416
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
3417
|
+
viewBox: "0 0 24 24",
|
|
3418
|
+
fill: "none",
|
|
3419
|
+
stroke: "currentColor",
|
|
3420
|
+
strokeWidth: "2",
|
|
3421
|
+
strokeLinecap: "round",
|
|
3422
|
+
strokeLinejoin: "round",
|
|
3423
|
+
className,
|
|
3424
|
+
children: [
|
|
3425
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("path", { d: "M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0" }),
|
|
3426
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("circle", { cx: "12", cy: "12", r: "3" })
|
|
3427
|
+
]
|
|
3428
|
+
}
|
|
3429
|
+
);
|
|
3430
|
+
}
|
|
3431
|
+
function EyeOffIcon({ className }) {
|
|
3432
|
+
return /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(
|
|
3433
|
+
"svg",
|
|
3434
|
+
{
|
|
3435
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
3436
|
+
viewBox: "0 0 24 24",
|
|
3437
|
+
fill: "none",
|
|
3438
|
+
stroke: "currentColor",
|
|
3439
|
+
strokeWidth: "2",
|
|
3440
|
+
strokeLinecap: "round",
|
|
3441
|
+
strokeLinejoin: "round",
|
|
3442
|
+
className,
|
|
3443
|
+
children: [
|
|
3444
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("path", { d: "M10.733 5.076a10.744 10.744 0 0 1 11.205 6.575 1 1 0 0 1 0 .696 10.747 10.747 0 0 1-1.444 2.49" }),
|
|
3445
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("path", { d: "M14.084 14.158a3 3 0 0 1-4.242-4.242" }),
|
|
3446
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("path", { d: "M17.479 17.499a10.75 10.75 0 0 1-15.417-5.151 1 1 0 0 1 0-.696 10.75 10.75 0 0 1 4.446-5.143" }),
|
|
3447
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("path", { d: "m2 2 20 20" })
|
|
3448
|
+
]
|
|
3449
|
+
}
|
|
3450
|
+
);
|
|
3451
|
+
}
|
|
3452
|
+
function SpinnerIcon({ className }) {
|
|
3453
|
+
return /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
3454
|
+
"svg",
|
|
3455
|
+
{
|
|
3456
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
3457
|
+
viewBox: "0 0 24 24",
|
|
3458
|
+
fill: "none",
|
|
3459
|
+
stroke: "currentColor",
|
|
3460
|
+
strokeWidth: "2",
|
|
3461
|
+
strokeLinecap: "round",
|
|
3462
|
+
strokeLinejoin: "round",
|
|
3463
|
+
className,
|
|
3464
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("path", { d: "M21 12a9 9 0 1 1-6.219-8.56" })
|
|
3465
|
+
}
|
|
3466
|
+
);
|
|
3467
|
+
}
|
|
3468
|
+
function LoginForm({
|
|
3469
|
+
onLogin,
|
|
3470
|
+
serverUrl,
|
|
3471
|
+
logoSrc,
|
|
3472
|
+
error: externalError,
|
|
3473
|
+
className
|
|
3474
|
+
}) {
|
|
3475
|
+
const [username, setUsername] = (0, import_react26.useState)("");
|
|
3476
|
+
const [password, setPassword] = (0, import_react26.useState)("");
|
|
3477
|
+
const [showPassword, setShowPassword] = (0, import_react26.useState)(false);
|
|
3478
|
+
const [submitting, setSubmitting] = (0, import_react26.useState)(false);
|
|
3479
|
+
const [internalError, setInternalError] = (0, import_react26.useState)(null);
|
|
3480
|
+
const error = externalError ?? internalError;
|
|
3481
|
+
const handleSubmit = async (e) => {
|
|
3482
|
+
e.preventDefault();
|
|
3483
|
+
if (submitting) return;
|
|
3484
|
+
setInternalError(null);
|
|
3485
|
+
setSubmitting(true);
|
|
3486
|
+
try {
|
|
3487
|
+
await onLogin(username, password);
|
|
3488
|
+
} catch (err) {
|
|
3489
|
+
const message = err instanceof Error ? err.message : "Login failed. Please try again.";
|
|
3490
|
+
setInternalError(message);
|
|
3491
|
+
} finally {
|
|
3492
|
+
setSubmitting(false);
|
|
3493
|
+
}
|
|
3494
|
+
};
|
|
3495
|
+
return /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
3496
|
+
"div",
|
|
3497
|
+
{
|
|
3498
|
+
className: cn(
|
|
3499
|
+
"flex min-h-screen items-center justify-center bg-background p-4",
|
|
3500
|
+
className
|
|
3501
|
+
),
|
|
3502
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "w-full max-w-sm", children: [
|
|
3503
|
+
logoSrc && /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: "flex justify-center mb-8", children: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("img", { src: logoSrc, alt: "Logo", className: "h-12" }) }),
|
|
3504
|
+
serverUrl && /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("p", { className: "mb-4 text-center text-xs text-foreground-subtle truncate", children: serverUrl }),
|
|
3505
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(
|
|
3506
|
+
"form",
|
|
3507
|
+
{
|
|
3508
|
+
onSubmit: handleSubmit,
|
|
3509
|
+
className: "space-y-4 rounded-xl border border-border bg-surface p-6 shadow-xl shadow-black/10",
|
|
3510
|
+
children: [
|
|
3511
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: "rounded-md bg-danger/10 border border-danger/20 px-3 py-2 text-xs text-danger", children: error }),
|
|
3512
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "space-y-1.5", children: [
|
|
3513
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("label", { className: "text-xs font-medium text-foreground-subtle", children: "Username" }),
|
|
3514
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
3515
|
+
"input",
|
|
3516
|
+
{
|
|
3517
|
+
type: "text",
|
|
3518
|
+
value: username,
|
|
3519
|
+
onChange: (e) => setUsername(e.target.value),
|
|
3520
|
+
autoComplete: "username",
|
|
3521
|
+
required: true,
|
|
3522
|
+
className: "w-full rounded-lg border border-border bg-background px-3 py-2.5 text-sm text-foreground placeholder:text-foreground-subtle focus:outline-none focus:ring-2 focus:ring-primary/50 focus:border-primary"
|
|
3523
|
+
}
|
|
3524
|
+
)
|
|
3525
|
+
] }),
|
|
3526
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "space-y-1.5", children: [
|
|
3527
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("label", { className: "text-xs font-medium text-foreground-subtle", children: "Password" }),
|
|
3528
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "relative", children: [
|
|
3529
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
3530
|
+
"input",
|
|
3531
|
+
{
|
|
3532
|
+
type: showPassword ? "text" : "password",
|
|
3533
|
+
value: password,
|
|
3534
|
+
onChange: (e) => setPassword(e.target.value),
|
|
3535
|
+
autoComplete: "current-password",
|
|
3536
|
+
required: true,
|
|
3537
|
+
className: "w-full rounded-lg border border-border bg-background px-3 py-2.5 pr-10 text-sm text-foreground placeholder:text-foreground-subtle focus:outline-none focus:ring-2 focus:ring-primary/50 focus:border-primary"
|
|
3538
|
+
}
|
|
3539
|
+
),
|
|
3540
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
3541
|
+
"button",
|
|
3542
|
+
{
|
|
3543
|
+
type: "button",
|
|
3544
|
+
onClick: () => setShowPassword((prev) => !prev),
|
|
3545
|
+
className: "absolute right-2.5 top-1/2 -translate-y-1/2 text-foreground-subtle hover:text-foreground",
|
|
3546
|
+
tabIndex: -1,
|
|
3547
|
+
children: showPassword ? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(EyeOffIcon, { className: "h-4 w-4" }) : /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(EyeIcon, { className: "h-4 w-4" })
|
|
3548
|
+
}
|
|
3549
|
+
)
|
|
3550
|
+
] })
|
|
3551
|
+
] }),
|
|
3552
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(
|
|
3553
|
+
"button",
|
|
3554
|
+
{
|
|
3555
|
+
type: "submit",
|
|
3556
|
+
disabled: submitting,
|
|
3557
|
+
className: "w-full rounded-lg bg-primary px-4 py-2.5 text-sm font-semibold text-primary-foreground hover:bg-primary/90 disabled:opacity-50 disabled:cursor-not-allowed transition-colors flex items-center justify-center gap-2",
|
|
3558
|
+
children: [
|
|
3559
|
+
submitting && /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(SpinnerIcon, { className: "h-4 w-4 animate-spin" }),
|
|
3560
|
+
submitting ? "Logging in..." : "Log in"
|
|
3561
|
+
]
|
|
3562
|
+
}
|
|
3563
|
+
)
|
|
3564
|
+
]
|
|
3565
|
+
}
|
|
3566
|
+
)
|
|
3567
|
+
] })
|
|
3568
|
+
}
|
|
3569
|
+
);
|
|
3570
|
+
}
|
|
3571
|
+
|
|
3572
|
+
// src/composites/dev-shell.tsx
|
|
3573
|
+
var import_jsx_runtime49 = require("react/jsx-runtime");
|
|
3574
|
+
var STORAGE_KEY = "camstack_dev_token";
|
|
3575
|
+
var DevShellContext = (0, import_react27.createContext)(null);
|
|
3576
|
+
function useDevShell() {
|
|
3577
|
+
const ctx = (0, import_react27.useContext)(DevShellContext);
|
|
3578
|
+
if (!ctx) {
|
|
3579
|
+
throw new Error("useDevShell must be used within a DevShell");
|
|
3580
|
+
}
|
|
3581
|
+
return ctx;
|
|
3582
|
+
}
|
|
3583
|
+
function getStoredToken() {
|
|
3584
|
+
if (typeof window === "undefined") return null;
|
|
3585
|
+
return localStorage.getItem(STORAGE_KEY);
|
|
3586
|
+
}
|
|
3587
|
+
function SunIcon({ className }) {
|
|
3588
|
+
return /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(
|
|
3589
|
+
"svg",
|
|
3590
|
+
{
|
|
3591
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
3592
|
+
viewBox: "0 0 24 24",
|
|
3593
|
+
fill: "none",
|
|
3594
|
+
stroke: "currentColor",
|
|
3595
|
+
strokeWidth: "2",
|
|
3596
|
+
strokeLinecap: "round",
|
|
3597
|
+
strokeLinejoin: "round",
|
|
3598
|
+
className,
|
|
3599
|
+
children: [
|
|
3600
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)("circle", { cx: "12", cy: "12", r: "4" }),
|
|
3601
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)("path", { d: "M12 2v2" }),
|
|
3602
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)("path", { d: "M12 20v2" }),
|
|
3603
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)("path", { d: "m4.93 4.93 1.41 1.41" }),
|
|
3604
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)("path", { d: "m17.66 17.66 1.41 1.41" }),
|
|
3605
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)("path", { d: "M2 12h2" }),
|
|
3606
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)("path", { d: "M20 12h2" }),
|
|
3607
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)("path", { d: "m6.34 17.66-1.41 1.41" }),
|
|
3608
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)("path", { d: "m19.07 4.93-1.41 1.41" })
|
|
3609
|
+
]
|
|
3610
|
+
}
|
|
3611
|
+
);
|
|
3612
|
+
}
|
|
3613
|
+
function MoonIcon({ className }) {
|
|
3614
|
+
return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
|
|
3615
|
+
"svg",
|
|
3616
|
+
{
|
|
3617
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
3618
|
+
viewBox: "0 0 24 24",
|
|
3619
|
+
fill: "none",
|
|
3620
|
+
stroke: "currentColor",
|
|
3621
|
+
strokeWidth: "2",
|
|
3622
|
+
strokeLinecap: "round",
|
|
3623
|
+
strokeLinejoin: "round",
|
|
3624
|
+
className,
|
|
3625
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("path", { d: "M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z" })
|
|
3626
|
+
}
|
|
3627
|
+
);
|
|
3628
|
+
}
|
|
3629
|
+
function DevShellInner({
|
|
3630
|
+
children,
|
|
3631
|
+
serverUrl,
|
|
3632
|
+
title,
|
|
3633
|
+
token,
|
|
3634
|
+
onLogout
|
|
3635
|
+
}) {
|
|
3636
|
+
const theme = useThemeMode();
|
|
3637
|
+
const trpc = (0, import_react27.useMemo)(
|
|
3638
|
+
() => {
|
|
3639
|
+
const wsUrl = serverUrl.replace(/^http/, "ws") + "/trpc";
|
|
3640
|
+
const wsClient = (0, import_client.createWSClient)({
|
|
3641
|
+
url: wsUrl,
|
|
3642
|
+
connectionParams: () => ({ token })
|
|
3643
|
+
});
|
|
3644
|
+
return (0, import_client.createTRPCClient)({
|
|
3645
|
+
links: [
|
|
3646
|
+
(0, import_client.splitLink)({
|
|
3647
|
+
condition: (op) => op.type === "subscription",
|
|
3648
|
+
true: (0, import_client.wsLink)({ client: wsClient, transformer: import_superjson.default }),
|
|
3649
|
+
false: (0, import_client.httpLink)({
|
|
3650
|
+
url: `${serverUrl}/trpc`,
|
|
3651
|
+
transformer: import_superjson.default,
|
|
3652
|
+
headers: () => ({ authorization: `Bearer ${token}` })
|
|
3653
|
+
})
|
|
3654
|
+
})
|
|
3655
|
+
]
|
|
3656
|
+
});
|
|
3657
|
+
},
|
|
3658
|
+
[serverUrl, token]
|
|
3659
|
+
);
|
|
3660
|
+
const contextValue = (0, import_react27.useMemo)(
|
|
3661
|
+
() => ({ trpc, token, logout: onLogout }),
|
|
3662
|
+
[trpc, token, onLogout]
|
|
3663
|
+
);
|
|
3664
|
+
return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(DevShellContext.Provider, { value: contextValue, children: /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: "min-h-screen bg-background text-foreground", children: [
|
|
3665
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: "flex items-center justify-between border-b border-border bg-surface px-4 py-2", children: [
|
|
3666
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
3667
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: "rounded bg-warning/20 px-2 py-0.5 text-xs font-bold text-warning", children: "DEV MODE" }),
|
|
3668
|
+
title && /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: "text-sm font-medium text-foreground", children: title }),
|
|
3669
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: "text-xs text-foreground-subtle", children: serverUrl })
|
|
3670
|
+
] }),
|
|
3671
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
3672
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(
|
|
3673
|
+
"button",
|
|
3674
|
+
{
|
|
3675
|
+
type: "button",
|
|
3676
|
+
onClick: theme.toggleMode,
|
|
3677
|
+
className: "flex items-center gap-1.5 rounded-md px-2 py-1 text-xs font-medium text-foreground-subtle hover:text-foreground hover:bg-surface-hover transition-colors",
|
|
3678
|
+
title: `Theme: ${theme.mode}`,
|
|
3679
|
+
children: [
|
|
3680
|
+
theme.resolvedMode === "dark" ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(SunIcon, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(MoonIcon, { className: "h-3.5 w-3.5" }),
|
|
3681
|
+
theme.mode === "dark" ? "Dark" : theme.mode === "light" ? "Light" : "System"
|
|
3682
|
+
]
|
|
3683
|
+
}
|
|
3684
|
+
),
|
|
3685
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
|
|
3686
|
+
"button",
|
|
3687
|
+
{
|
|
3688
|
+
type: "button",
|
|
3689
|
+
onClick: onLogout,
|
|
3690
|
+
className: "rounded-md px-2.5 py-1 text-xs font-medium text-danger hover:bg-danger/10 transition-colors",
|
|
3691
|
+
children: "Logout"
|
|
3692
|
+
}
|
|
3693
|
+
)
|
|
3694
|
+
] })
|
|
3695
|
+
] }),
|
|
3696
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)("div", { className: "p-4", children: children({ trpc, theme }) })
|
|
3697
|
+
] }) });
|
|
3698
|
+
}
|
|
3699
|
+
function DevShell({
|
|
3700
|
+
children,
|
|
3701
|
+
serverUrl = "https://localhost:4443",
|
|
3702
|
+
title
|
|
3703
|
+
}) {
|
|
3704
|
+
const [token, setToken] = (0, import_react27.useState)(getStoredToken);
|
|
3705
|
+
const handleLogin = (0, import_react27.useCallback)(
|
|
3706
|
+
async (username, password) => {
|
|
3707
|
+
const anonClient = (0, import_client.createTRPCClient)({
|
|
3708
|
+
links: [
|
|
3709
|
+
(0, import_client.httpLink)({
|
|
3710
|
+
url: `${serverUrl}/trpc`,
|
|
3711
|
+
transformer: import_superjson.default
|
|
3712
|
+
})
|
|
3713
|
+
]
|
|
3714
|
+
});
|
|
3715
|
+
const res = await anonClient.auth.login.mutate({ username, password });
|
|
3716
|
+
if (!res?.token) throw new Error("No token returned");
|
|
3717
|
+
localStorage.setItem(STORAGE_KEY, res.token);
|
|
3718
|
+
setToken(res.token);
|
|
3719
|
+
},
|
|
3720
|
+
[serverUrl]
|
|
3721
|
+
);
|
|
3722
|
+
const handleLogout = (0, import_react27.useCallback)(() => {
|
|
3723
|
+
localStorage.removeItem(STORAGE_KEY);
|
|
3724
|
+
setToken(null);
|
|
3725
|
+
}, []);
|
|
3726
|
+
if (!token) {
|
|
3727
|
+
return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(ThemeProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(LoginForm, { onLogin: handleLogin, serverUrl }) });
|
|
3728
|
+
}
|
|
3729
|
+
return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(ThemeProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
|
|
3730
|
+
DevShellInner,
|
|
3731
|
+
{
|
|
3732
|
+
serverUrl,
|
|
3733
|
+
title,
|
|
3734
|
+
token,
|
|
3735
|
+
onLogout: handleLogout,
|
|
3736
|
+
children
|
|
3737
|
+
}
|
|
3738
|
+
) });
|
|
3739
|
+
}
|
|
3740
|
+
|
|
3741
|
+
// src/composites/mount-addon-page.tsx
|
|
3742
|
+
function mountAddonPage(PageComponent, options = {}) {
|
|
3743
|
+
const {
|
|
3744
|
+
serverUrl = "https://localhost:4443",
|
|
3745
|
+
title,
|
|
3746
|
+
rootId = "root"
|
|
3747
|
+
} = options;
|
|
3748
|
+
const root = document.getElementById(rootId);
|
|
3749
|
+
if (!root) {
|
|
3750
|
+
console.error(`[mountAddonPage] Element #${rootId} not found`);
|
|
3751
|
+
return;
|
|
3752
|
+
}
|
|
3753
|
+
(0, import_client2.createRoot)(root).render(
|
|
3754
|
+
(0, import_react28.createElement)(DevShell, {
|
|
3755
|
+
serverUrl,
|
|
3756
|
+
title,
|
|
3757
|
+
children: ({ trpc, theme }) => (0, import_react28.createElement)(PageComponent, {
|
|
3758
|
+
trpc,
|
|
3759
|
+
theme: { isDark: theme.resolvedMode === "dark" },
|
|
3760
|
+
navigate: (path) => {
|
|
3761
|
+
console.log("[dev] navigate:", path);
|
|
3762
|
+
}
|
|
3763
|
+
})
|
|
3764
|
+
})
|
|
3765
|
+
);
|
|
3766
|
+
}
|
|
2023
3767
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2024
3768
|
0 && (module.exports = {
|
|
2025
3769
|
AppShell,
|
|
2026
3770
|
Badge,
|
|
2027
3771
|
Button,
|
|
3772
|
+
CLASS_COLORS,
|
|
2028
3773
|
Card,
|
|
2029
3774
|
Checkbox,
|
|
2030
3775
|
CodeBlock,
|
|
2031
3776
|
ConfirmDialog,
|
|
3777
|
+
DEFAULT_CLASS_COLORS,
|
|
3778
|
+
DEFAULT_COLOR,
|
|
2032
3779
|
DataTable,
|
|
3780
|
+
DetectionCanvas,
|
|
3781
|
+
DetectionResultTree,
|
|
3782
|
+
DevShell,
|
|
2033
3783
|
DeviceCard,
|
|
2034
3784
|
DeviceGrid,
|
|
2035
3785
|
Dialog,
|
|
@@ -2048,22 +3798,30 @@ function DeviceGrid({
|
|
|
2048
3798
|
FloatingPanel,
|
|
2049
3799
|
FormField,
|
|
2050
3800
|
IconButton,
|
|
3801
|
+
ImageSelector,
|
|
3802
|
+
InferenceConfigSelector,
|
|
2051
3803
|
Input,
|
|
2052
3804
|
KeyValueList,
|
|
2053
3805
|
Label,
|
|
3806
|
+
LoginForm,
|
|
2054
3807
|
PageHeader,
|
|
3808
|
+
PipelineBuilder,
|
|
3809
|
+
PipelineRuntimeSelector,
|
|
3810
|
+
PipelineStep,
|
|
2055
3811
|
Popover,
|
|
2056
3812
|
PopoverContent,
|
|
2057
3813
|
PopoverTrigger,
|
|
2058
3814
|
ProviderBadge,
|
|
2059
3815
|
ScrollArea,
|
|
2060
3816
|
Select,
|
|
3817
|
+
SemanticBadge,
|
|
2061
3818
|
Separator,
|
|
2062
3819
|
Sidebar,
|
|
2063
3820
|
SidebarItem,
|
|
2064
3821
|
Skeleton,
|
|
2065
3822
|
StatCard,
|
|
2066
3823
|
StatusBadge,
|
|
3824
|
+
StepTimings,
|
|
2067
3825
|
Switch,
|
|
2068
3826
|
Tabs,
|
|
2069
3827
|
TabsContent,
|
|
@@ -2073,14 +3831,18 @@ function DeviceGrid({
|
|
|
2073
3831
|
Tooltip,
|
|
2074
3832
|
TooltipContent,
|
|
2075
3833
|
TooltipTrigger,
|
|
3834
|
+
VersionBadge,
|
|
2076
3835
|
cn,
|
|
2077
3836
|
createTheme,
|
|
2078
3837
|
darkColors,
|
|
2079
3838
|
defaultTheme,
|
|
3839
|
+
getClassColor,
|
|
2080
3840
|
lightColors,
|
|
3841
|
+
mountAddonPage,
|
|
2081
3842
|
providerIcons,
|
|
2082
3843
|
statusIcons,
|
|
2083
3844
|
themeToCss,
|
|
3845
|
+
useDevShell,
|
|
2084
3846
|
useThemeMode
|
|
2085
3847
|
});
|
|
2086
3848
|
//# sourceMappingURL=index.cjs.map
|