@workerdeck/ui 3.5.0 → 3.6.1
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/build/index.mjs +127 -23
- package/build/index.mjs.map +1 -1
- package/build/scoped.css +43 -0
- package/package.json +4 -4
- package/src/components/agent/SessionBrowser.tsx +3 -1
- package/src/components/agent/SessionGroups.tsx +126 -3
- package/src/components/agent/SessionItem.tsx +37 -16
- package/src/styles/theme.css +5 -0
package/build/index.mjs
CHANGED
|
@@ -6,7 +6,7 @@ import { Anchor, ArrowRight, Atom, Beaker, BedDouble, BellRing, Bike, Binary, Bl
|
|
|
6
6
|
import { AlertDialog as AlertDialog$1 } from "@base-ui/react/alert-dialog";
|
|
7
7
|
import { Popover as Popover$1 } from "@base-ui/react/popover";
|
|
8
8
|
import { Toaster as Toaster$1, toast } from "sonner";
|
|
9
|
-
import { STATE_LABELS, STATE_ORDER, adaptersOf, addCustomGroup, clearFilters, displayCustomized, displayedTasks, facetFilterCount, filterRows, groupRows, hasFacetFilter, isAgentRecord, isTeamCollapsed, moveCustomGroup, moveToCustomGroup, newCustomGroupId, projectLabel, projectName, projectSubpath, projectsOf, removeCustomGroup, renameCustomGroup, scopeActive, sessionKey, sessionLabel, subagentLabel, subsetSummary, taskSummary, teamSummary, toggleTeamCollapsed, visibleShells, visibleSubagents, visibleTasks } from "@workerdeck/protocol";
|
|
9
|
+
import { PROJECT_ACCENTS, STATE_LABELS, STATE_ORDER, adaptersOf, addCustomGroup, clearFilters, customGroupColor, displayCustomized, displayedTasks, facetFilterCount, filterRows, groupRows, hasFacetFilter, isAgentRecord, isTeamCollapsed, moveCustomGroup, moveToCustomGroup, newCustomGroupId, projectLabel, projectName, projectSubpath, projectsOf, removeCustomGroup, renameCustomGroup, scopeActive, sessionKey, sessionLabel, styleCustomGroup, subagentLabel, subsetSummary, taskSummary, teamSummary, toggleTeamCollapsed, visibleShells, visibleSubagents, visibleTasks } from "@workerdeck/protocol";
|
|
10
10
|
//#region src/components/ui/Card.tsx
|
|
11
11
|
function Card({ className, ...props }) {
|
|
12
12
|
return /* @__PURE__ */ jsx("div", {
|
|
@@ -1156,11 +1156,18 @@ function SessionItem({ row, active = false, activeStepKey, showGateway, showProj
|
|
|
1156
1156
|
cost === "-" ? void 0 : cost
|
|
1157
1157
|
].filter((part) => Boolean(part));
|
|
1158
1158
|
const model = friendlyModel(info.model);
|
|
1159
|
+
const status = statusLine(info.statusLabel);
|
|
1160
|
+
const needsYou = row.state === "attention" || row.teamState === "attention" || badgeState === "attention";
|
|
1159
1161
|
const parts = [];
|
|
1160
1162
|
if (model) parts.push(/* @__PURE__ */ jsx("span", {
|
|
1161
1163
|
className: vendorTextClass(engine, info.model),
|
|
1162
1164
|
children: model
|
|
1163
1165
|
}, "model"));
|
|
1166
|
+
if (status) parts.push(/* @__PURE__ */ jsx("span", {
|
|
1167
|
+
title: status,
|
|
1168
|
+
className: "text-fg-3",
|
|
1169
|
+
children: status
|
|
1170
|
+
}, "status"));
|
|
1164
1171
|
if (project !== void 0) parts.push(/* @__PURE__ */ jsxs("span", {
|
|
1165
1172
|
title: projectTitle,
|
|
1166
1173
|
children: [/* @__PURE__ */ jsx(ProjectIcon, {
|
|
@@ -1235,7 +1242,7 @@ function SessionItem({ row, active = false, activeStepKey, showGateway, showProj
|
|
|
1235
1242
|
});
|
|
1236
1243
|
}
|
|
1237
1244
|
},
|
|
1238
|
-
className: cn("group flex w-full cursor-pointer flex-col p-1 text-left outline-none", "rounded-[4px] transition-colors focus-visible:ring-2 focus-visible:ring-ring", holdsOpenStep ? "bg-row-selected-weak" : active ? "bg-row-selected" : "hover:bg-row-hover", className),
|
|
1245
|
+
className: cn("group flex w-full cursor-pointer flex-col p-1 text-left outline-none", "rounded-[4px] transition-colors focus-visible:ring-2 focus-visible:ring-ring", needsYou ? cn("bg-row-attention", active && "ring-1 ring-accent ring-inset") : holdsOpenStep ? "bg-row-selected-weak" : active ? "bg-row-selected" : "hover:bg-row-hover", className),
|
|
1239
1246
|
children: [agent && variant === "member" ? /* @__PURE__ */ jsxs("div", {
|
|
1240
1247
|
className: cn("flex h-6 items-center gap-1.5 overflow-hidden py-0.5 pr-0.5 pl-1.5", info.engineAsleep && "opacity-60"),
|
|
1241
1248
|
children: [
|
|
@@ -1245,9 +1252,10 @@ function SessionItem({ row, active = false, activeStepKey, showGateway, showProj
|
|
|
1245
1252
|
size: 22
|
|
1246
1253
|
}),
|
|
1247
1254
|
nameLabel,
|
|
1248
|
-
|
|
1255
|
+
status ? /* @__PURE__ */ jsx("span", {
|
|
1256
|
+
title: status,
|
|
1249
1257
|
className: "min-w-0 flex-1 truncate text-body-sm text-fg-3",
|
|
1250
|
-
children:
|
|
1258
|
+
children: status
|
|
1251
1259
|
}) : /* @__PURE__ */ jsx("span", { className: "flex-1" }),
|
|
1252
1260
|
unread,
|
|
1253
1261
|
/* @__PURE__ */ jsx("span", {
|
|
@@ -1269,6 +1277,10 @@ function SessionItem({ row, active = false, activeStepKey, showGateway, showProj
|
|
|
1269
1277
|
children: [
|
|
1270
1278
|
nameLabel,
|
|
1271
1279
|
agent?.leads ? /* @__PURE__ */ jsx(LeadChip, {}) : null,
|
|
1280
|
+
agent ? /* @__PURE__ */ jsx("span", {
|
|
1281
|
+
className: "w-max max-w-max min-w-0 grow basis-0 truncate text-label text-fg-4/70",
|
|
1282
|
+
children: time
|
|
1283
|
+
}) : null,
|
|
1272
1284
|
/* @__PURE__ */ jsx("span", { className: "flex-1" }),
|
|
1273
1285
|
unread,
|
|
1274
1286
|
teamUnseen > 0 ? /* @__PURE__ */ jsxs("span", {
|
|
@@ -1287,20 +1299,14 @@ function SessionItem({ row, active = false, activeStepKey, showGateway, showProj
|
|
|
1287
1299
|
}), /* @__PURE__ */ jsxs("div", {
|
|
1288
1300
|
className: "flex h-5 items-center gap-1.5 overflow-hidden text-body-sm tracking-[-0.005em]",
|
|
1289
1301
|
children: [
|
|
1290
|
-
agent ? /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
1291
|
-
className: "
|
|
1292
|
-
children:
|
|
1293
|
-
}) : null, /* @__PURE__ */ jsxs("span", {
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
className: vendorTextClass(engine, info.model),
|
|
1299
|
-
children: model
|
|
1300
|
-
}),
|
|
1301
|
-
" · "
|
|
1302
|
-
] }) : info.title ? "· " : null, time]
|
|
1303
|
-
})] }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("span", {
|
|
1302
|
+
agent ? /* @__PURE__ */ jsxs(Fragment$1, { children: [model ? /* @__PURE__ */ jsx("span", {
|
|
1303
|
+
className: cn("shrink-0", vendorTextClass(engine, info.model)),
|
|
1304
|
+
children: model
|
|
1305
|
+
}) : null, status ? /* @__PURE__ */ jsxs("span", {
|
|
1306
|
+
title: status,
|
|
1307
|
+
className: "min-w-0 truncate text-fg-3",
|
|
1308
|
+
children: [model ? "· " : "", status]
|
|
1309
|
+
}) : null] }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("span", {
|
|
1304
1310
|
className: "min-w-0 truncate text-fg-4",
|
|
1305
1311
|
children: parts.map((part, i) => /* @__PURE__ */ jsxs(Fragment, { children: [i > 0 ? " · " : "", part] }, i))
|
|
1306
1312
|
}), /* @__PURE__ */ jsxs("span", {
|
|
@@ -1399,6 +1405,9 @@ function NameEditor({ initial, placeholder, onCommit, onCancel }) {
|
|
|
1399
1405
|
className: cn("-my-0.5 min-w-0 flex-1 rounded-sm border border-ring bg-bg px-1 py-px", "text-body-sm leading-5 text-fg-1 outline-none")
|
|
1400
1406
|
});
|
|
1401
1407
|
}
|
|
1408
|
+
function statusLine(label) {
|
|
1409
|
+
return label ? label.emoji ? `${label.emoji} ${label.text}` : label.text : void 0;
|
|
1410
|
+
}
|
|
1402
1411
|
//#endregion
|
|
1403
1412
|
//#region src/lib/team-drop.ts
|
|
1404
1413
|
function dropZone(offsetY, height) {
|
|
@@ -1610,10 +1619,11 @@ function useGroupDrag(groups, onChange, options) {
|
|
|
1610
1619
|
return id;
|
|
1611
1620
|
},
|
|
1612
1621
|
rename: (id, name) => onChange(renameCustomGroup(groups, id, name)),
|
|
1622
|
+
style: (id, look) => onChange(styleCustomGroup(groups, id, look)),
|
|
1613
1623
|
remove: (id) => onChange(removeCustomGroup(groups, id))
|
|
1614
1624
|
};
|
|
1615
1625
|
}
|
|
1616
|
-
function CustomGroupHeader({ group, editing, onEditingChange, onRename, onRemove, dragProps }) {
|
|
1626
|
+
function CustomGroupHeader({ group, look, editing, onEditingChange, onRename, onRemove, onStyle, dragProps }) {
|
|
1617
1627
|
if (editing) return /* @__PURE__ */ jsx(GroupNameInput, {
|
|
1618
1628
|
initial: group.label ?? "",
|
|
1619
1629
|
onRename,
|
|
@@ -1624,9 +1634,13 @@ function CustomGroupHeader({ group, editing, onEditingChange, onRename, onRemove
|
|
|
1624
1634
|
...dragProps,
|
|
1625
1635
|
label: group.label ?? "",
|
|
1626
1636
|
count: group.rows.length,
|
|
1637
|
+
caps: !custom,
|
|
1627
1638
|
className: cn("group/heading", custom && "cursor-grab"),
|
|
1628
1639
|
onDoubleClick: custom ? () => onEditingChange(true) : void 0,
|
|
1629
|
-
leading: custom ? /* @__PURE__ */ jsx(GripVertical, { className: "-ml-1.5 size-3 opacity-0 group-hover/heading:opacity-60" })
|
|
1640
|
+
leading: custom ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(GripVertical, { className: "-mr-1.5 -ml-1.5 size-3 opacity-0 group-hover/heading:opacity-60" }), look ? /* @__PURE__ */ jsx(GroupBadge, {
|
|
1641
|
+
group: look,
|
|
1642
|
+
onStyle
|
|
1643
|
+
}) : null] }) : void 0,
|
|
1630
1644
|
actions: custom ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(HeadingAction, {
|
|
1631
1645
|
label: "Rename group",
|
|
1632
1646
|
onClick: () => onEditingChange(true),
|
|
@@ -1666,14 +1680,14 @@ function GroupNameInput({ initial, onRename, onDone }) {
|
|
|
1666
1680
|
})
|
|
1667
1681
|
});
|
|
1668
1682
|
}
|
|
1669
|
-
function GroupHeading({ label, count, leading, actions, className, ...rest }) {
|
|
1683
|
+
function GroupHeading({ label, count, leading, actions, caps = true, className, ...rest }) {
|
|
1670
1684
|
return /* @__PURE__ */ jsxs("div", {
|
|
1671
1685
|
...rest,
|
|
1672
1686
|
className: cn("group/heading flex min-h-5 items-center gap-2 px-2 text-label font-medium text-fg-4", className),
|
|
1673
1687
|
children: [
|
|
1674
1688
|
leading,
|
|
1675
1689
|
/* @__PURE__ */ jsx("span", {
|
|
1676
|
-
className: "min-w-0 truncate uppercase tracking-wide",
|
|
1690
|
+
className: cn("min-w-0 truncate", caps ? "uppercase tracking-wide" : "text-fg-3"),
|
|
1677
1691
|
children: label
|
|
1678
1692
|
}),
|
|
1679
1693
|
/* @__PURE__ */ jsx("span", {
|
|
@@ -1710,6 +1724,94 @@ function NewGroupButton({ onClick }) {
|
|
|
1710
1724
|
children: [/* @__PURE__ */ jsx(Plus, {}), "New group"]
|
|
1711
1725
|
});
|
|
1712
1726
|
}
|
|
1727
|
+
const ICON_PX = 64;
|
|
1728
|
+
function GroupBadge({ group, onStyle }) {
|
|
1729
|
+
const [error, setError] = useState();
|
|
1730
|
+
const file = useRef(null);
|
|
1731
|
+
const mark = group.icon ? /* @__PURE__ */ jsx("img", {
|
|
1732
|
+
src: group.icon,
|
|
1733
|
+
alt: "",
|
|
1734
|
+
className: "size-3.5 rounded-[3px] object-cover",
|
|
1735
|
+
draggable: false
|
|
1736
|
+
}) : /* @__PURE__ */ jsx("span", {
|
|
1737
|
+
className: "size-2 rounded-[2px]",
|
|
1738
|
+
style: { background: customGroupColor(group) }
|
|
1739
|
+
});
|
|
1740
|
+
if (!onStyle) return /* @__PURE__ */ jsx("span", {
|
|
1741
|
+
className: "flex size-3.5 shrink-0 items-center justify-center",
|
|
1742
|
+
children: mark
|
|
1743
|
+
});
|
|
1744
|
+
return /* @__PURE__ */ jsxs(Popover, { children: [/* @__PURE__ */ jsx(PopoverTrigger, { render: /* @__PURE__ */ jsx("button", {
|
|
1745
|
+
type: "button",
|
|
1746
|
+
"aria-label": `Colour or image for ${group.name}`,
|
|
1747
|
+
title: "Colour or image",
|
|
1748
|
+
onClick: (e) => e.stopPropagation(),
|
|
1749
|
+
onDoubleClick: (e) => e.stopPropagation(),
|
|
1750
|
+
className: "flex size-3.5 shrink-0 items-center justify-center rounded-[3px] hover:ring-1 hover:ring-border",
|
|
1751
|
+
children: mark
|
|
1752
|
+
}) }), /* @__PURE__ */ jsxs(PopoverContent, {
|
|
1753
|
+
align: "start",
|
|
1754
|
+
className: "flex w-44 flex-col gap-2",
|
|
1755
|
+
children: [
|
|
1756
|
+
/* @__PURE__ */ jsx("div", {
|
|
1757
|
+
className: "grid grid-cols-4 gap-1.5",
|
|
1758
|
+
children: PROJECT_ACCENTS.map((color) => /* @__PURE__ */ jsx("button", {
|
|
1759
|
+
type: "button",
|
|
1760
|
+
"aria-label": `Colour ${color}`,
|
|
1761
|
+
onClick: () => onStyle({
|
|
1762
|
+
color,
|
|
1763
|
+
icon: null
|
|
1764
|
+
}),
|
|
1765
|
+
className: cn("h-6 rounded-[4px] ring-offset-1 ring-offset-surface", !group.icon && customGroupColor(group) === color && "ring-2 ring-fg-3"),
|
|
1766
|
+
style: { background: color }
|
|
1767
|
+
}, color))
|
|
1768
|
+
}),
|
|
1769
|
+
/* @__PURE__ */ jsx("input", {
|
|
1770
|
+
ref: file,
|
|
1771
|
+
type: "file",
|
|
1772
|
+
accept: "image/*",
|
|
1773
|
+
className: "hidden",
|
|
1774
|
+
onChange: (e) => {
|
|
1775
|
+
const picked = e.target.files?.[0];
|
|
1776
|
+
e.target.value = "";
|
|
1777
|
+
if (!picked) return;
|
|
1778
|
+
setError(void 0);
|
|
1779
|
+
iconFromFile(picked).then((icon) => onStyle({ icon })).catch(() => setError("That image could not be read"));
|
|
1780
|
+
}
|
|
1781
|
+
}),
|
|
1782
|
+
/* @__PURE__ */ jsxs(Button, {
|
|
1783
|
+
variant: "outline",
|
|
1784
|
+
size: "xs",
|
|
1785
|
+
onClick: () => file.current?.click(),
|
|
1786
|
+
children: [/* @__PURE__ */ jsx(Image, {}), "Choose image…"]
|
|
1787
|
+
}),
|
|
1788
|
+
group.icon ? /* @__PURE__ */ jsx(Button, {
|
|
1789
|
+
variant: "ghost",
|
|
1790
|
+
size: "xs",
|
|
1791
|
+
onClick: () => onStyle({ icon: null }),
|
|
1792
|
+
children: "Remove image"
|
|
1793
|
+
}) : null,
|
|
1794
|
+
error ? /* @__PURE__ */ jsx("span", {
|
|
1795
|
+
className: "text-label text-danger",
|
|
1796
|
+
children: error
|
|
1797
|
+
}) : null
|
|
1798
|
+
]
|
|
1799
|
+
})] });
|
|
1800
|
+
}
|
|
1801
|
+
async function iconFromFile(file) {
|
|
1802
|
+
const bitmap = await createImageBitmap(file);
|
|
1803
|
+
const canvas = document.createElement("canvas");
|
|
1804
|
+
canvas.width = ICON_PX;
|
|
1805
|
+
canvas.height = ICON_PX;
|
|
1806
|
+
const context = canvas.getContext("2d");
|
|
1807
|
+
if (!context) throw new Error("no canvas");
|
|
1808
|
+
const scale = Math.max(ICON_PX / bitmap.width, ICON_PX / bitmap.height);
|
|
1809
|
+
const width = bitmap.width * scale;
|
|
1810
|
+
const height = bitmap.height * scale;
|
|
1811
|
+
context.drawImage(bitmap, (ICON_PX - width) / 2, (ICON_PX - height) / 2, width, height);
|
|
1812
|
+
bitmap.close();
|
|
1813
|
+
return canvas.toDataURL("image/png");
|
|
1814
|
+
}
|
|
1713
1815
|
//#endregion
|
|
1714
1816
|
//#region src/components/agent/SessionBrowser.tsx
|
|
1715
1817
|
function rowShapeClass(active) {
|
|
@@ -1752,6 +1854,8 @@ function SessionBrowser({ rows, config, onConfigChange, scope, activeId, activeS
|
|
|
1752
1854
|
const heading = (group) => {
|
|
1753
1855
|
if (custom) return /* @__PURE__ */ jsx(CustomGroupHeader, {
|
|
1754
1856
|
group,
|
|
1857
|
+
look: config.customGroups?.find((custom) => custom.id === group.custom),
|
|
1858
|
+
onStyle: (look) => group.custom && drag.style(group.custom, look),
|
|
1755
1859
|
editing: group.custom !== void 0 && editingGroup === group.custom,
|
|
1756
1860
|
onEditingChange: (editing) => setEditingGroup(editing ? group.custom : void 0),
|
|
1757
1861
|
onRename: (name) => group.custom && drag.rename(group.custom, name),
|
|
@@ -1854,7 +1958,7 @@ function SessionBrowser({ rows, config, onConfigChange, scope, activeId, activeS
|
|
|
1854
1958
|
title: "Nothing here",
|
|
1855
1959
|
description: "No session to show."
|
|
1856
1960
|
}) : /* @__PURE__ */ jsxs("div", {
|
|
1857
|
-
className: "flex flex-col gap-
|
|
1961
|
+
className: "flex flex-col gap-2 px-1",
|
|
1858
1962
|
children: [groups.map((group) => /* @__PURE__ */ jsxs("div", {
|
|
1859
1963
|
...draggable ? drag.container(group) : {},
|
|
1860
1964
|
className: cn("flex flex-col gap-1 rounded-md", draggable && drag.isOver(`group:${group.key}`) && "bg-row-hover/50"),
|