@cadraos/sdk 0.3.9 → 0.3.11
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/chat/index.cjs +0 -4
- package/dist/chat/index.cjs.map +1 -1
- package/dist/chat/index.js +0 -4
- package/dist/chat/index.js.map +1 -1
- package/dist/index.cjs +0 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +0 -4
- package/dist/index.js.map +1 -1
- package/dist/kanban/engine/index.cjs +0 -6
- package/dist/kanban/engine/index.cjs.map +1 -1
- package/dist/kanban/engine/index.js +0 -6
- package/dist/kanban/engine/index.js.map +1 -1
- package/dist/kanban/index.cjs +277 -41
- package/dist/kanban/index.cjs.map +1 -1
- package/dist/kanban/index.d.cts +110 -5
- package/dist/kanban/index.d.ts +110 -5
- package/dist/kanban/index.js +277 -41
- package/dist/kanban/index.js.map +1 -1
- package/dist/teams/index.cjs +0 -4
- package/dist/teams/index.cjs.map +1 -1
- package/dist/teams/index.js +0 -4
- package/dist/teams/index.js.map +1 -1
- package/package.json +1 -1
package/dist/kanban/index.cjs
CHANGED
|
@@ -265,9 +265,12 @@ function useKanbanBoard(options) {
|
|
|
265
265
|
]);
|
|
266
266
|
setBoard(nextBoard);
|
|
267
267
|
setCards(cardList.cards);
|
|
268
|
-
setSelectedCard(
|
|
269
|
-
|
|
270
|
-
|
|
268
|
+
setSelectedCard((prev) => {
|
|
269
|
+
if (!prev) return prev;
|
|
270
|
+
const next = cardList.cards.find((c) => c.id === prev.id);
|
|
271
|
+
if (!next) return prev;
|
|
272
|
+
return next.run ? next : { ...next, run: prev.run };
|
|
273
|
+
});
|
|
271
274
|
} catch (err) {
|
|
272
275
|
fail(err, "Failed to load board");
|
|
273
276
|
} finally {
|
|
@@ -282,9 +285,12 @@ function useKanbanBoard(options) {
|
|
|
282
285
|
]);
|
|
283
286
|
setBoard(nextBoard);
|
|
284
287
|
setCards(cardList.cards);
|
|
285
|
-
setSelectedCard(
|
|
286
|
-
|
|
287
|
-
|
|
288
|
+
setSelectedCard((prev) => {
|
|
289
|
+
if (!prev) return prev;
|
|
290
|
+
const next = cardList.cards.find((c) => c.id === prev.id);
|
|
291
|
+
if (!next) return prev;
|
|
292
|
+
return next.run ? next : { ...next, run: prev.run };
|
|
293
|
+
});
|
|
288
294
|
} catch {
|
|
289
295
|
}
|
|
290
296
|
}, [adapter]);
|
|
@@ -305,7 +311,7 @@ function useKanbanBoard(options) {
|
|
|
305
311
|
try {
|
|
306
312
|
const full = await adapter.getCard(cardId);
|
|
307
313
|
setSelectedCard(
|
|
308
|
-
(prev) => prev
|
|
314
|
+
(prev) => prev == null || prev.id === cardId ? full : prev
|
|
309
315
|
);
|
|
310
316
|
} catch (err) {
|
|
311
317
|
if (!known) fail(err, "Failed to open card");
|
|
@@ -414,6 +420,27 @@ function useKanbanBoard(options) {
|
|
|
414
420
|
},
|
|
415
421
|
[refresh]
|
|
416
422
|
);
|
|
423
|
+
const deleteCard = react.useCallback(
|
|
424
|
+
async (cardId) => {
|
|
425
|
+
if (!adapter.deleteCard) return false;
|
|
426
|
+
setError(null);
|
|
427
|
+
const prevCards = cards;
|
|
428
|
+
const prevSelected = selectedCard;
|
|
429
|
+
setCards((prev) => prev.filter((c) => c.id !== cardId));
|
|
430
|
+
setSelectedCard((prev) => prev && prev.id === cardId ? null : prev);
|
|
431
|
+
try {
|
|
432
|
+
await adapter.deleteCard(cardId);
|
|
433
|
+
void silentRefresh();
|
|
434
|
+
return true;
|
|
435
|
+
} catch (err) {
|
|
436
|
+
setCards(prevCards);
|
|
437
|
+
setSelectedCard(prevSelected);
|
|
438
|
+
fail(err, "Failed to delete card");
|
|
439
|
+
return false;
|
|
440
|
+
}
|
|
441
|
+
},
|
|
442
|
+
[adapter, cards, selectedCard, silentRefresh, fail]
|
|
443
|
+
);
|
|
417
444
|
return {
|
|
418
445
|
board,
|
|
419
446
|
lanes: board?.lanes ?? [],
|
|
@@ -429,6 +456,7 @@ function useKanbanBoard(options) {
|
|
|
429
456
|
createCard,
|
|
430
457
|
updateCard,
|
|
431
458
|
transitionCard,
|
|
459
|
+
deleteCard,
|
|
432
460
|
handleRunTerminal
|
|
433
461
|
};
|
|
434
462
|
}
|
|
@@ -2722,6 +2750,9 @@ function KanbanCard({
|
|
|
2722
2750
|
onClick,
|
|
2723
2751
|
selected,
|
|
2724
2752
|
dueState,
|
|
2753
|
+
draggable,
|
|
2754
|
+
onDragStart,
|
|
2755
|
+
onDragEnd,
|
|
2725
2756
|
className
|
|
2726
2757
|
}) {
|
|
2727
2758
|
const runStatus = card.run?.status;
|
|
@@ -2750,10 +2781,20 @@ function KanbanCard({
|
|
|
2750
2781
|
onClick: () => onClick?.(card),
|
|
2751
2782
|
"aria-pressed": selected,
|
|
2752
2783
|
"aria-busy": isWorking,
|
|
2784
|
+
draggable,
|
|
2785
|
+
onDragStart: draggable ? (e) => {
|
|
2786
|
+
e.dataTransfer.effectAllowed = "move";
|
|
2787
|
+
e.dataTransfer.setData("text/plain", card.id);
|
|
2788
|
+
onDragStart?.(card);
|
|
2789
|
+
} : void 0,
|
|
2790
|
+
onDragEnd: draggable ? () => onDragEnd?.() : void 0,
|
|
2753
2791
|
className: cn9(
|
|
2754
|
-
|
|
2792
|
+
// Solid card: fill + border + a faint token top-sheen (adapts to theme),
|
|
2793
|
+
// matching the host's cockpit cards (work-shell v2 visual pass).
|
|
2794
|
+
"relative w-full text-left rounded-xl border bg-card bg-gradient-to-b from-foreground/[0.03] to-transparent p-3 shadow-sm motion-safe:transition-shadow",
|
|
2755
2795
|
"hover:shadow-md hover:border-primary/40",
|
|
2756
2796
|
"focus:outline-none focus:ring-2 focus:ring-ring/50",
|
|
2797
|
+
draggable && "cursor-grab active:cursor-grabbing",
|
|
2757
2798
|
// The working card carries the SINGLE focal motion on the board (F11).
|
|
2758
2799
|
isWorking ? "border-info/60 ring-2 ring-info/40 animate-pulse" : selected ? "border-primary/60 ring-2 ring-primary/30" : "border-border",
|
|
2759
2800
|
className
|
|
@@ -2830,6 +2871,11 @@ function CapMeter({ count, cap, className }) {
|
|
|
2830
2871
|
}
|
|
2831
2872
|
);
|
|
2832
2873
|
}
|
|
2874
|
+
var AGENT_GROUPS = [
|
|
2875
|
+
{ kind: "cadra", label: "Cadra agents" },
|
|
2876
|
+
{ kind: "remote", label: "Your own agents" },
|
|
2877
|
+
{ kind: "human", label: "Teammates" }
|
|
2878
|
+
];
|
|
2833
2879
|
function AgentKindIcon({ kind }) {
|
|
2834
2880
|
const common = {
|
|
2835
2881
|
viewBox: "0 0 24 24",
|
|
@@ -2872,17 +2918,55 @@ function OnlineDot({ online }) {
|
|
|
2872
2918
|
}
|
|
2873
2919
|
);
|
|
2874
2920
|
}
|
|
2921
|
+
function RemoteBadge() {
|
|
2922
|
+
return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 rounded-full border border-accent/40 bg-accent/15 px-1.5 py-px text-[10px] font-semibold leading-4 text-accent", children: "Remote" });
|
|
2923
|
+
}
|
|
2875
2924
|
function LaneAgentPicker({
|
|
2876
2925
|
selected,
|
|
2877
2926
|
options,
|
|
2878
2927
|
onSelect,
|
|
2879
2928
|
canEdit = true,
|
|
2880
2929
|
lockedReason,
|
|
2930
|
+
onEditAgent,
|
|
2881
2931
|
className
|
|
2882
2932
|
}) {
|
|
2883
2933
|
const [open, setOpen] = react.useState(false);
|
|
2934
|
+
const [placement, setPlacement] = react.useState(null);
|
|
2884
2935
|
const rootRef = react.useRef(null);
|
|
2936
|
+
const triggerRef = react.useRef(null);
|
|
2885
2937
|
const editable = canEdit && !!onSelect && (options?.length ?? 0) > 0;
|
|
2938
|
+
const openMenu = () => {
|
|
2939
|
+
const el = triggerRef.current;
|
|
2940
|
+
if (el && typeof window !== "undefined") {
|
|
2941
|
+
const rect = el.getBoundingClientRect();
|
|
2942
|
+
const vw = window.innerWidth || 0;
|
|
2943
|
+
const vh = window.innerHeight || 0;
|
|
2944
|
+
const margin = 8;
|
|
2945
|
+
const gap = 4;
|
|
2946
|
+
const desired = 288;
|
|
2947
|
+
const width = Math.max(
|
|
2948
|
+
Math.min(rect.width || 224, Math.max(vw - margin * 2, 160)),
|
|
2949
|
+
160
|
|
2950
|
+
);
|
|
2951
|
+
const left = Math.min(
|
|
2952
|
+
Math.max(rect.left, margin),
|
|
2953
|
+
Math.max(vw - width - margin, margin)
|
|
2954
|
+
);
|
|
2955
|
+
const spaceBelow = vh - rect.bottom - gap - margin;
|
|
2956
|
+
const spaceAbove = rect.top - gap - margin;
|
|
2957
|
+
const flipUp = spaceBelow < desired && spaceAbove > spaceBelow;
|
|
2958
|
+
const maxHeight = Math.max(
|
|
2959
|
+
Math.min(desired, flipUp ? spaceAbove : spaceBelow),
|
|
2960
|
+
120
|
|
2961
|
+
);
|
|
2962
|
+
setPlacement(
|
|
2963
|
+
flipUp ? { bottom: Math.max(vh - rect.top + gap, margin), left, width, maxHeight } : { top: rect.bottom + gap, left, width, maxHeight }
|
|
2964
|
+
);
|
|
2965
|
+
} else {
|
|
2966
|
+
setPlacement(null);
|
|
2967
|
+
}
|
|
2968
|
+
setOpen(true);
|
|
2969
|
+
};
|
|
2886
2970
|
react.useEffect(() => {
|
|
2887
2971
|
if (!open) return;
|
|
2888
2972
|
const onDocDown = (e) => {
|
|
@@ -2916,14 +3000,28 @@ function LaneAgentPicker({
|
|
|
2916
3000
|
}
|
|
2917
3001
|
),
|
|
2918
3002
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate text-left", children: displayLabel }),
|
|
3003
|
+
kind === "remote" && /* @__PURE__ */ jsxRuntime.jsx(RemoteBadge, {}),
|
|
2919
3004
|
/* @__PURE__ */ jsxRuntime.jsx(OnlineDot, { online: selected?.online })
|
|
2920
3005
|
] });
|
|
3006
|
+
const grouped = AGENT_GROUPS.map((group) => ({
|
|
3007
|
+
...group,
|
|
3008
|
+
items: (options ?? []).filter((opt) => (opt.kind ?? "cadra") === group.kind)
|
|
3009
|
+
})).filter((group) => group.items.length > 0);
|
|
3010
|
+
const menuStyle = placement ? {
|
|
3011
|
+
position: "fixed",
|
|
3012
|
+
top: placement.top,
|
|
3013
|
+
bottom: placement.bottom,
|
|
3014
|
+
left: placement.left,
|
|
3015
|
+
width: placement.width,
|
|
3016
|
+
maxHeight: placement.maxHeight
|
|
3017
|
+
} : void 0;
|
|
2921
3018
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: rootRef, className: cn9("relative mt-2 w-full", className), children: [
|
|
2922
3019
|
editable ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2923
3020
|
"button",
|
|
2924
3021
|
{
|
|
3022
|
+
ref: triggerRef,
|
|
2925
3023
|
type: "button",
|
|
2926
|
-
onClick: () => setOpen(
|
|
3024
|
+
onClick: () => open ? setOpen(false) : openMenu(),
|
|
2927
3025
|
"aria-haspopup": "listbox",
|
|
2928
3026
|
"aria-expanded": open,
|
|
2929
3027
|
"aria-label": `Assigned agent: ${displayLabel}. Change`,
|
|
@@ -3001,47 +3099,106 @@ function LaneAgentPicker({
|
|
|
3001
3099
|
),
|
|
3002
3100
|
/* @__PURE__ */ jsxRuntime.jsx("span", { children: lockedReason })
|
|
3003
3101
|
] }),
|
|
3004
|
-
editable && open && /* @__PURE__ */ jsxRuntime.
|
|
3005
|
-
"
|
|
3102
|
+
editable && open && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3103
|
+
"div",
|
|
3006
3104
|
{
|
|
3007
|
-
|
|
3008
|
-
"aria-label": "Assign an agent",
|
|
3105
|
+
style: menuStyle,
|
|
3009
3106
|
className: cn9(
|
|
3010
|
-
"
|
|
3011
|
-
"
|
|
3107
|
+
"flex flex-col overflow-hidden rounded-lg border border-border bg-popover shadow-lg",
|
|
3108
|
+
menuStyle ? "z-50" : "absolute z-20 mt-1 max-h-64 w-full"
|
|
3012
3109
|
),
|
|
3013
|
-
children:
|
|
3014
|
-
|
|
3015
|
-
|
|
3110
|
+
children: [
|
|
3111
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3112
|
+
"ul",
|
|
3113
|
+
{
|
|
3114
|
+
role: "listbox",
|
|
3115
|
+
"aria-label": "Assign an agent",
|
|
3116
|
+
className: "min-h-0 flex-1 overflow-y-auto p-1",
|
|
3117
|
+
children: grouped.map((group) => /* @__PURE__ */ jsxRuntime.jsxs("li", { role: "presentation", children: [
|
|
3118
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-2 pb-1 pt-2 text-[10px] font-semibold uppercase tracking-wide text-muted-foreground", children: group.label }),
|
|
3119
|
+
/* @__PURE__ */ jsxRuntime.jsx("ul", { role: "group", "aria-label": group.label, children: group.items.map((opt) => {
|
|
3120
|
+
const isSelected = opt.id === selected?.id;
|
|
3121
|
+
const optKind = opt.kind ?? "cadra";
|
|
3122
|
+
return /* @__PURE__ */ jsxRuntime.jsx("li", { role: "option", "aria-selected": isSelected, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3123
|
+
"button",
|
|
3124
|
+
{
|
|
3125
|
+
type: "button",
|
|
3126
|
+
onClick: () => {
|
|
3127
|
+
onSelect(opt.id);
|
|
3128
|
+
setOpen(false);
|
|
3129
|
+
},
|
|
3130
|
+
className: cn9(
|
|
3131
|
+
"flex min-h-11 w-full items-center gap-1.5 rounded-md px-2 text-left text-xs font-medium",
|
|
3132
|
+
"hover:bg-muted focus:outline-none focus:ring-2 focus:ring-ring/50",
|
|
3133
|
+
isSelected ? "text-primary" : "text-foreground"
|
|
3134
|
+
),
|
|
3135
|
+
children: [
|
|
3136
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3137
|
+
"span",
|
|
3138
|
+
{
|
|
3139
|
+
className: cn9(
|
|
3140
|
+
"grid h-5 w-5 shrink-0 place-items-center rounded-full",
|
|
3141
|
+
optKind === "cadra" ? "bg-primary/15 text-primary" : "bg-secondary text-foreground"
|
|
3142
|
+
),
|
|
3143
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(AgentKindIcon, { kind: optKind })
|
|
3144
|
+
}
|
|
3145
|
+
),
|
|
3146
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate", children: opt.label }),
|
|
3147
|
+
optKind === "remote" && /* @__PURE__ */ jsxRuntime.jsx(RemoteBadge, {}),
|
|
3148
|
+
/* @__PURE__ */ jsxRuntime.jsx(OnlineDot, { online: opt.online }),
|
|
3149
|
+
isSelected && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3150
|
+
"svg",
|
|
3151
|
+
{
|
|
3152
|
+
viewBox: "0 0 24 24",
|
|
3153
|
+
fill: "none",
|
|
3154
|
+
stroke: "currentColor",
|
|
3155
|
+
strokeWidth: 2,
|
|
3156
|
+
strokeLinecap: "round",
|
|
3157
|
+
strokeLinejoin: "round",
|
|
3158
|
+
"aria-hidden": true,
|
|
3159
|
+
className: "h-3.5 w-3.5 shrink-0",
|
|
3160
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M20 6L9 17l-5-5" })
|
|
3161
|
+
}
|
|
3162
|
+
)
|
|
3163
|
+
]
|
|
3164
|
+
}
|
|
3165
|
+
) }, opt.id);
|
|
3166
|
+
}) })
|
|
3167
|
+
] }, group.kind))
|
|
3168
|
+
}
|
|
3169
|
+
),
|
|
3170
|
+
onEditAgent && selected && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-t border-border p-1", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3016
3171
|
"button",
|
|
3017
3172
|
{
|
|
3018
3173
|
type: "button",
|
|
3019
3174
|
onClick: () => {
|
|
3020
|
-
|
|
3175
|
+
onEditAgent(selected.id);
|
|
3021
3176
|
setOpen(false);
|
|
3022
3177
|
},
|
|
3023
3178
|
className: cn9(
|
|
3024
|
-
"flex min-h-11 w-full items-center gap-1.5 rounded-md px-2 text-left text-xs font-medium",
|
|
3025
|
-
"hover:bg-muted focus:outline-none focus:ring-2 focus:ring-ring/50"
|
|
3026
|
-
isSelected ? "text-primary" : "text-foreground"
|
|
3179
|
+
"flex min-h-11 w-full items-center gap-1.5 rounded-md px-2 text-left text-xs font-medium text-foreground",
|
|
3180
|
+
"hover:bg-muted focus:outline-none focus:ring-2 focus:ring-ring/50"
|
|
3027
3181
|
),
|
|
3028
3182
|
children: [
|
|
3029
3183
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3030
|
-
"
|
|
3184
|
+
"svg",
|
|
3031
3185
|
{
|
|
3032
|
-
|
|
3033
|
-
|
|
3034
|
-
|
|
3035
|
-
|
|
3036
|
-
|
|
3186
|
+
viewBox: "0 0 24 24",
|
|
3187
|
+
fill: "none",
|
|
3188
|
+
stroke: "currentColor",
|
|
3189
|
+
strokeWidth: 2,
|
|
3190
|
+
strokeLinecap: "round",
|
|
3191
|
+
strokeLinejoin: "round",
|
|
3192
|
+
"aria-hidden": true,
|
|
3193
|
+
className: "h-3.5 w-3.5 shrink-0 text-muted-foreground",
|
|
3194
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M17 3a2.85 2.83 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5Z" })
|
|
3037
3195
|
}
|
|
3038
3196
|
),
|
|
3039
|
-
|
|
3040
|
-
/* @__PURE__ */ jsxRuntime.jsx(OnlineDot, { online: opt.online })
|
|
3197
|
+
"Edit this agent"
|
|
3041
3198
|
]
|
|
3042
3199
|
}
|
|
3043
|
-
) }
|
|
3044
|
-
|
|
3200
|
+
) })
|
|
3201
|
+
]
|
|
3045
3202
|
}
|
|
3046
3203
|
)
|
|
3047
3204
|
] });
|
|
@@ -3066,6 +3223,12 @@ function KanbanColumn({
|
|
|
3066
3223
|
count,
|
|
3067
3224
|
agentPicker,
|
|
3068
3225
|
canEditHandlers,
|
|
3226
|
+
draggableCards,
|
|
3227
|
+
dragActive,
|
|
3228
|
+
dropAllowed,
|
|
3229
|
+
onCardDragStart,
|
|
3230
|
+
onCardDragEnd,
|
|
3231
|
+
onLaneDrop,
|
|
3069
3232
|
className
|
|
3070
3233
|
}) {
|
|
3071
3234
|
const headerCount = count ?? cards.length;
|
|
@@ -3076,9 +3239,21 @@ function KanbanColumn({
|
|
|
3076
3239
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3077
3240
|
"div",
|
|
3078
3241
|
{
|
|
3242
|
+
onDragOver: dropAllowed ? (e) => {
|
|
3243
|
+
e.preventDefault();
|
|
3244
|
+
e.dataTransfer.dropEffect = "move";
|
|
3245
|
+
} : void 0,
|
|
3246
|
+
onDrop: dropAllowed && onLaneDrop ? (e) => {
|
|
3247
|
+
e.preventDefault();
|
|
3248
|
+
onLaneDrop(lane);
|
|
3249
|
+
} : void 0,
|
|
3079
3250
|
className: cn9(
|
|
3080
|
-
"flex w-[85vw] max-w-sm snap-start shrink-0 flex-col rounded-xl bg-muted/40 border border-border sm:w-72 sm:max-w-none",
|
|
3251
|
+
"flex w-[85vw] max-w-sm snap-start shrink-0 flex-col rounded-xl bg-muted/40 border border-border transition sm:w-72 sm:max-w-none",
|
|
3081
3252
|
isScheduled && "border-border",
|
|
3253
|
+
// MV4 drag affordance: allowed targets glow; other lanes dim so the
|
|
3254
|
+
// valid drop zones read at a glance.
|
|
3255
|
+
dragActive && dropAllowed && "border-primary/60 ring-2 ring-primary/40 bg-primary/5",
|
|
3256
|
+
dragActive && !dropAllowed && "opacity-55",
|
|
3082
3257
|
className
|
|
3083
3258
|
),
|
|
3084
3259
|
children: [
|
|
@@ -3147,7 +3322,10 @@ function KanbanColumn({
|
|
|
3147
3322
|
card,
|
|
3148
3323
|
onClick: onCardClick,
|
|
3149
3324
|
selected: card.id === selectedCardId,
|
|
3150
|
-
dueState: dueStateFor(card, lane, now)
|
|
3325
|
+
dueState: dueStateFor(card, lane, now),
|
|
3326
|
+
draggable: draggableCards,
|
|
3327
|
+
onDragStart: onCardDragStart,
|
|
3328
|
+
onDragEnd: onCardDragEnd
|
|
3151
3329
|
},
|
|
3152
3330
|
card.id
|
|
3153
3331
|
)),
|
|
@@ -3307,6 +3485,8 @@ function KanbanBoard({
|
|
|
3307
3485
|
laneAgentPicker,
|
|
3308
3486
|
scheduleStatus,
|
|
3309
3487
|
focusCardId,
|
|
3488
|
+
renderCardDrawer,
|
|
3489
|
+
enableDrag,
|
|
3310
3490
|
className
|
|
3311
3491
|
}) {
|
|
3312
3492
|
const {
|
|
@@ -3321,6 +3501,7 @@ function KanbanBoard({
|
|
|
3321
3501
|
createCard,
|
|
3322
3502
|
updateCard,
|
|
3323
3503
|
transitionCard,
|
|
3504
|
+
deleteCard,
|
|
3324
3505
|
handleRunTerminal
|
|
3325
3506
|
} = useKanbanBoard({ adapter, onError, onCardCreated, pollIntervalMs });
|
|
3326
3507
|
const lastFocusedRef = react.useRef(void 0);
|
|
@@ -3365,6 +3546,44 @@ function KanbanBoard({
|
|
|
3365
3546
|
(cardId, toLane) => transitionCard({ cardId, targetLane: toLane }),
|
|
3366
3547
|
[transitionCard]
|
|
3367
3548
|
);
|
|
3549
|
+
const [dragging, setDragging] = react.useState(null);
|
|
3550
|
+
const draggingRef = react.useRef(null);
|
|
3551
|
+
const dropInFlightRef = react.useRef(null);
|
|
3552
|
+
const allowedDropLanes = react.useMemo(() => {
|
|
3553
|
+
if (!dragging || !board?.transitions) return /* @__PURE__ */ new Set();
|
|
3554
|
+
return new Set(
|
|
3555
|
+
board.transitions.filter((t) => t.fromLane === dragging.lane && t.manualAllowed).map((t) => t.toLane)
|
|
3556
|
+
);
|
|
3557
|
+
}, [dragging, board?.transitions]);
|
|
3558
|
+
const handleCardDragStart = react.useCallback((card) => {
|
|
3559
|
+
const d = { id: card.id, lane: card.lane };
|
|
3560
|
+
draggingRef.current = d;
|
|
3561
|
+
setDragging(d);
|
|
3562
|
+
}, []);
|
|
3563
|
+
const handleCardDragEnd = react.useCallback(() => {
|
|
3564
|
+
draggingRef.current = null;
|
|
3565
|
+
setDragging(null);
|
|
3566
|
+
}, []);
|
|
3567
|
+
const handleLaneDrop = react.useCallback(
|
|
3568
|
+
(lane) => {
|
|
3569
|
+
const cur = draggingRef.current;
|
|
3570
|
+
draggingRef.current = null;
|
|
3571
|
+
setDragging(null);
|
|
3572
|
+
if (!cur || lane.key === cur.lane) return;
|
|
3573
|
+
if (dropInFlightRef.current === cur.id) return;
|
|
3574
|
+
const allowed = (board?.transitions ?? []).some(
|
|
3575
|
+
(t) => t.fromLane === cur.lane && t.toLane === lane.key && t.manualAllowed
|
|
3576
|
+
);
|
|
3577
|
+
if (!allowed) return;
|
|
3578
|
+
dropInFlightRef.current = cur.id;
|
|
3579
|
+
void Promise.resolve(transitionCard({ cardId: cur.id, targetLane: lane.key })).finally(
|
|
3580
|
+
() => {
|
|
3581
|
+
if (dropInFlightRef.current === cur.id) dropInFlightRef.current = null;
|
|
3582
|
+
}
|
|
3583
|
+
);
|
|
3584
|
+
},
|
|
3585
|
+
[board?.transitions, transitionCard]
|
|
3586
|
+
);
|
|
3368
3587
|
const initialLaneKey = lanes.find((l) => !l.terminal)?.key ?? lanes[0]?.key;
|
|
3369
3588
|
const selectedLane = selectedCard ? lanes.find((l) => l.key === selectedCard.lane) : void 0;
|
|
3370
3589
|
const canAdvanceSelected = !!selectedLane && !selectedLane.terminal;
|
|
@@ -3385,12 +3604,32 @@ function KanbanBoard({
|
|
|
3385
3604
|
showCreate: enableCreate && lane.key === initialLaneKey,
|
|
3386
3605
|
count: laneCounts?.[lane.key],
|
|
3387
3606
|
agentPicker: laneAgentPicker?.(lane),
|
|
3388
|
-
canEditHandlers
|
|
3607
|
+
canEditHandlers,
|
|
3608
|
+
draggableCards: enableDrag && enableAdvance,
|
|
3609
|
+
dragActive: !!dragging,
|
|
3610
|
+
dropAllowed: !!dragging && dragging.lane !== lane.key && allowedDropLanes.has(lane.key),
|
|
3611
|
+
onCardDragStart: handleCardDragStart,
|
|
3612
|
+
onCardDragEnd: handleCardDragEnd,
|
|
3613
|
+
onLaneDrop: handleLaneDrop
|
|
3389
3614
|
},
|
|
3390
3615
|
lane.id ?? lane.key
|
|
3391
3616
|
))
|
|
3392
3617
|
] }),
|
|
3393
|
-
selectedCard &&
|
|
3618
|
+
selectedCard && (renderCardDrawer ? renderCardDrawer({
|
|
3619
|
+
card: selectedCard,
|
|
3620
|
+
adapter,
|
|
3621
|
+
lanes,
|
|
3622
|
+
transitions: enableAdvance ? board?.transitions : void 0,
|
|
3623
|
+
canAdvance: canAdvanceSelected,
|
|
3624
|
+
onClose: closeCard,
|
|
3625
|
+
onRetry: onRetryCard ? handleRetry : void 0,
|
|
3626
|
+
onUpdate: enableEdit ? handleUpdate : void 0,
|
|
3627
|
+
onAdvance: enableAdvance ? handleAdvance : void 0,
|
|
3628
|
+
onTransition: enableAdvance ? handleTransition : void 0,
|
|
3629
|
+
onDelete: adapter.deleteCard ? deleteCard : void 0,
|
|
3630
|
+
onRunTerminal: handleRunTerminal,
|
|
3631
|
+
onError
|
|
3632
|
+
}) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
3394
3633
|
CardDrawer,
|
|
3395
3634
|
{
|
|
3396
3635
|
card: selectedCard,
|
|
@@ -3406,7 +3645,7 @@ function KanbanBoard({
|
|
|
3406
3645
|
onRunTerminal: handleRunTerminal,
|
|
3407
3646
|
onError
|
|
3408
3647
|
}
|
|
3409
|
-
)
|
|
3648
|
+
))
|
|
3410
3649
|
] })
|
|
3411
3650
|
] });
|
|
3412
3651
|
}
|
|
@@ -3431,6 +3670,7 @@ function composeAdapter(source, boardConfigUuid, version, cardSource) {
|
|
|
3431
3670
|
transitionCard(input) {
|
|
3432
3671
|
return cardSource.transitionCard(input);
|
|
3433
3672
|
},
|
|
3673
|
+
...cardSource.deleteCard ? { deleteCard: (id) => cardSource.deleteCard(id) } : {},
|
|
3434
3674
|
...cardSource.createRunStream ? { createRunStream: (id) => cardSource.createRunStream(id) } : {}
|
|
3435
3675
|
};
|
|
3436
3676
|
}
|
|
@@ -4804,7 +5044,6 @@ var AgentsAPI = class extends BaseResourceAPI {
|
|
|
4804
5044
|
super(http, "/api/v1/agents");
|
|
4805
5045
|
this.getStreamConfig = getStreamConfig;
|
|
4806
5046
|
}
|
|
4807
|
-
getStreamConfig;
|
|
4808
5047
|
// ===== LIST Operations =====
|
|
4809
5048
|
/**
|
|
4810
5049
|
* List all agents in the organization
|
|
@@ -5710,7 +5949,6 @@ var SessionsAPI = class extends BaseResourceAPI {
|
|
|
5710
5949
|
super(http, "/api/v1/sessions");
|
|
5711
5950
|
this.getStreamConfig = getStreamConfig;
|
|
5712
5951
|
}
|
|
5713
|
-
getStreamConfig;
|
|
5714
5952
|
// ===== LIST Operations =====
|
|
5715
5953
|
/**
|
|
5716
5954
|
* List all sessions in the organization
|
|
@@ -6030,7 +6268,6 @@ var KanbanAPI = class extends BaseResourceAPI {
|
|
|
6030
6268
|
super(http, "/api/v1/kanban");
|
|
6031
6269
|
this.getStreamConfig = getStreamConfig;
|
|
6032
6270
|
}
|
|
6033
|
-
getStreamConfig;
|
|
6034
6271
|
// ===== BOARD =====
|
|
6035
6272
|
/**
|
|
6036
6273
|
* Get the current org's board (lanes in declared order). Auto-provisions
|
|
@@ -6232,7 +6469,6 @@ var RemoteAgentsAPI = class extends BaseResourceAPI {
|
|
|
6232
6469
|
super(http, "/api/v1/remote-agents");
|
|
6233
6470
|
this.getStreamConfig = getStreamConfig;
|
|
6234
6471
|
}
|
|
6235
|
-
getStreamConfig;
|
|
6236
6472
|
/**
|
|
6237
6473
|
* List all remote agents in the organization
|
|
6238
6474
|
*
|