@greatapps/greatagents-ui 0.1.0 → 0.2.0
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.d.ts +152 -1
- package/dist/index.js +3154 -0
- package/dist/index.js.map +1 -1
- package/package.json +13 -3
- package/src/components/agents/agent-edit-form.tsx +218 -0
- package/src/components/agents/agent-form-dialog.tsx +177 -0
- package/src/components/agents/agent-objectives-list.tsx +406 -0
- package/src/components/agents/agent-prompt-editor.tsx +406 -0
- package/src/components/agents/agent-tabs.tsx +63 -0
- package/src/components/agents/agent-tools-list.tsx +377 -0
- package/src/components/agents/agents-table.tsx +205 -0
- package/src/components/tools/tool-credentials-form.tsx +572 -0
- package/src/components/tools/tool-form-dialog.tsx +342 -0
- package/src/components/tools/tools-table.tsx +225 -0
- package/src/components/ui/sortable.tsx +577 -0
- package/src/index.ts +16 -0
- package/src/lib/compose-refs.ts +44 -0
- package/src/pages/agent-detail-page.tsx +112 -0
- package/src/pages/agents-page.tsx +45 -0
- package/src/pages/credentials-page.tsx +50 -0
- package/src/pages/index.ts +4 -0
- package/src/pages/tools-page.tsx +52 -0
|
@@ -0,0 +1,577 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type Announcements,
|
|
3
|
+
closestCenter,
|
|
4
|
+
closestCorners,
|
|
5
|
+
DndContext,
|
|
6
|
+
type DndContextProps,
|
|
7
|
+
type DragEndEvent,
|
|
8
|
+
type DraggableAttributes,
|
|
9
|
+
type DraggableSyntheticListeners,
|
|
10
|
+
DragOverlay,
|
|
11
|
+
type DragStartEvent,
|
|
12
|
+
type DropAnimation,
|
|
13
|
+
defaultDropAnimationSideEffects,
|
|
14
|
+
KeyboardSensor,
|
|
15
|
+
MouseSensor,
|
|
16
|
+
type ScreenReaderInstructions,
|
|
17
|
+
TouchSensor,
|
|
18
|
+
type UniqueIdentifier,
|
|
19
|
+
useSensor,
|
|
20
|
+
useSensors,
|
|
21
|
+
} from "@dnd-kit/core";
|
|
22
|
+
import {
|
|
23
|
+
restrictToHorizontalAxis,
|
|
24
|
+
restrictToParentElement,
|
|
25
|
+
restrictToVerticalAxis,
|
|
26
|
+
} from "@dnd-kit/modifiers";
|
|
27
|
+
import {
|
|
28
|
+
arrayMove,
|
|
29
|
+
horizontalListSortingStrategy,
|
|
30
|
+
SortableContext,
|
|
31
|
+
type SortableContextProps,
|
|
32
|
+
sortableKeyboardCoordinates,
|
|
33
|
+
useSortable,
|
|
34
|
+
verticalListSortingStrategy,
|
|
35
|
+
} from "@dnd-kit/sortable";
|
|
36
|
+
import { CSS } from "@dnd-kit/utilities";
|
|
37
|
+
import { Slot as SlotPrimitive } from "radix-ui";
|
|
38
|
+
import * as React from "react";
|
|
39
|
+
import * as ReactDOM from "react-dom";
|
|
40
|
+
import { useComposedRefs } from "../../lib/compose-refs";
|
|
41
|
+
import { cn } from "../../lib";
|
|
42
|
+
|
|
43
|
+
const orientationConfig = {
|
|
44
|
+
vertical: {
|
|
45
|
+
modifiers: [restrictToVerticalAxis, restrictToParentElement],
|
|
46
|
+
strategy: verticalListSortingStrategy,
|
|
47
|
+
collisionDetection: closestCenter,
|
|
48
|
+
},
|
|
49
|
+
horizontal: {
|
|
50
|
+
modifiers: [restrictToHorizontalAxis, restrictToParentElement],
|
|
51
|
+
strategy: horizontalListSortingStrategy,
|
|
52
|
+
collisionDetection: closestCenter,
|
|
53
|
+
},
|
|
54
|
+
mixed: {
|
|
55
|
+
modifiers: [restrictToParentElement],
|
|
56
|
+
strategy: undefined,
|
|
57
|
+
collisionDetection: closestCorners,
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const ROOT_NAME = "Sortable";
|
|
62
|
+
const CONTENT_NAME = "SortableContent";
|
|
63
|
+
const ITEM_NAME = "SortableItem";
|
|
64
|
+
const ITEM_HANDLE_NAME = "SortableItemHandle";
|
|
65
|
+
const OVERLAY_NAME = "SortableOverlay";
|
|
66
|
+
|
|
67
|
+
interface SortableRootContextValue<T> {
|
|
68
|
+
id: string;
|
|
69
|
+
items: UniqueIdentifier[];
|
|
70
|
+
modifiers: DndContextProps["modifiers"];
|
|
71
|
+
strategy: SortableContextProps["strategy"];
|
|
72
|
+
activeId: UniqueIdentifier | null;
|
|
73
|
+
setActiveId: (id: UniqueIdentifier | null) => void;
|
|
74
|
+
getItemValue: (item: T) => UniqueIdentifier;
|
|
75
|
+
flatCursor: boolean;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const SortableRootContext =
|
|
79
|
+
React.createContext<SortableRootContextValue<unknown> | null>(null);
|
|
80
|
+
|
|
81
|
+
function useSortableContext(consumerName: string) {
|
|
82
|
+
const context = React.useContext(SortableRootContext);
|
|
83
|
+
if (!context) {
|
|
84
|
+
throw new Error(`\`${consumerName}\` must be used within \`${ROOT_NAME}\``);
|
|
85
|
+
}
|
|
86
|
+
return context;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
interface GetItemValue<T> {
|
|
90
|
+
/**
|
|
91
|
+
* Callback that returns a unique identifier for each sortable item. Required for array of objects.
|
|
92
|
+
* @example getItemValue={(item) => item.id}
|
|
93
|
+
*/
|
|
94
|
+
getItemValue: (item: T) => UniqueIdentifier;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
type SortableProps<T> = DndContextProps &
|
|
98
|
+
(T extends object ? GetItemValue<T> : Partial<GetItemValue<T>>) & {
|
|
99
|
+
value: T[];
|
|
100
|
+
onValueChange?: (items: T[]) => void;
|
|
101
|
+
onMove?: (
|
|
102
|
+
event: DragEndEvent & { activeIndex: number; overIndex: number },
|
|
103
|
+
) => void;
|
|
104
|
+
strategy?: SortableContextProps["strategy"];
|
|
105
|
+
orientation?: "vertical" | "horizontal" | "mixed";
|
|
106
|
+
flatCursor?: boolean;
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
function Sortable<T>(props: SortableProps<T>) {
|
|
110
|
+
const {
|
|
111
|
+
value,
|
|
112
|
+
onValueChange,
|
|
113
|
+
collisionDetection,
|
|
114
|
+
modifiers,
|
|
115
|
+
strategy,
|
|
116
|
+
onMove,
|
|
117
|
+
orientation = "vertical",
|
|
118
|
+
flatCursor = false,
|
|
119
|
+
getItemValue: getItemValueProp,
|
|
120
|
+
accessibility,
|
|
121
|
+
...sortableProps
|
|
122
|
+
} = props;
|
|
123
|
+
|
|
124
|
+
const id = React.useId();
|
|
125
|
+
const [activeId, setActiveId] = React.useState<UniqueIdentifier | null>(null);
|
|
126
|
+
|
|
127
|
+
const sensors = useSensors(
|
|
128
|
+
useSensor(MouseSensor),
|
|
129
|
+
useSensor(TouchSensor),
|
|
130
|
+
useSensor(KeyboardSensor, {
|
|
131
|
+
coordinateGetter: sortableKeyboardCoordinates,
|
|
132
|
+
}),
|
|
133
|
+
);
|
|
134
|
+
const config = React.useMemo(
|
|
135
|
+
() => orientationConfig[orientation],
|
|
136
|
+
[orientation],
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
const getItemValue = React.useCallback(
|
|
140
|
+
(item: T): UniqueIdentifier => {
|
|
141
|
+
if (typeof item === "object" && !getItemValueProp) {
|
|
142
|
+
throw new Error(
|
|
143
|
+
"`getItemValue` is required when using array of objects",
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
return getItemValueProp
|
|
147
|
+
? getItemValueProp(item)
|
|
148
|
+
: (item as UniqueIdentifier);
|
|
149
|
+
},
|
|
150
|
+
[getItemValueProp],
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
const items = React.useMemo(() => {
|
|
154
|
+
return value.map((item) => getItemValue(item));
|
|
155
|
+
}, [value, getItemValue]);
|
|
156
|
+
|
|
157
|
+
/* eslint-disable react-hooks/preserve-manual-memoization, react-hooks/exhaustive-deps -- shadcn sortable: intentional dependency on specific props */
|
|
158
|
+
const onDragStart = React.useCallback(
|
|
159
|
+
(event: DragStartEvent) => {
|
|
160
|
+
sortableProps.onDragStart?.(event);
|
|
161
|
+
|
|
162
|
+
if (event.activatorEvent.defaultPrevented) return;
|
|
163
|
+
|
|
164
|
+
setActiveId(event.active.id);
|
|
165
|
+
},
|
|
166
|
+
[sortableProps.onDragStart],
|
|
167
|
+
);
|
|
168
|
+
|
|
169
|
+
const onDragEnd = React.useCallback(
|
|
170
|
+
(event: DragEndEvent) => {
|
|
171
|
+
sortableProps.onDragEnd?.(event);
|
|
172
|
+
|
|
173
|
+
if (event.activatorEvent.defaultPrevented) return;
|
|
174
|
+
|
|
175
|
+
const { active, over } = event;
|
|
176
|
+
if (over && active.id !== over?.id) {
|
|
177
|
+
const activeIndex = value.findIndex(
|
|
178
|
+
(item) => getItemValue(item) === active.id,
|
|
179
|
+
);
|
|
180
|
+
const overIndex = value.findIndex(
|
|
181
|
+
(item) => getItemValue(item) === over.id,
|
|
182
|
+
);
|
|
183
|
+
|
|
184
|
+
if (onMove) {
|
|
185
|
+
onMove({ ...event, activeIndex, overIndex });
|
|
186
|
+
} else {
|
|
187
|
+
onValueChange?.(arrayMove(value, activeIndex, overIndex));
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
setActiveId(null);
|
|
191
|
+
},
|
|
192
|
+
[value, onValueChange, onMove, getItemValue, sortableProps.onDragEnd],
|
|
193
|
+
);
|
|
194
|
+
|
|
195
|
+
const onDragCancel = React.useCallback(
|
|
196
|
+
(event: DragEndEvent) => {
|
|
197
|
+
sortableProps.onDragCancel?.(event);
|
|
198
|
+
|
|
199
|
+
if (event.activatorEvent.defaultPrevented) return;
|
|
200
|
+
|
|
201
|
+
setActiveId(null);
|
|
202
|
+
},
|
|
203
|
+
[sortableProps.onDragCancel],
|
|
204
|
+
);
|
|
205
|
+
/* eslint-enable react-hooks/preserve-manual-memoization, react-hooks/exhaustive-deps */
|
|
206
|
+
|
|
207
|
+
const announcements: Announcements = React.useMemo(
|
|
208
|
+
() => ({
|
|
209
|
+
onDragStart({ active }) {
|
|
210
|
+
const activeValue = active.id.toString();
|
|
211
|
+
return `Grabbed sortable item "${activeValue}". Current position is ${active.data.current?.sortable.index + 1} of ${value.length}. Use arrow keys to move, space to drop.`;
|
|
212
|
+
},
|
|
213
|
+
onDragOver({ active, over }) {
|
|
214
|
+
if (over) {
|
|
215
|
+
const overIndex = over.data.current?.sortable.index ?? 0;
|
|
216
|
+
const activeIndex = active.data.current?.sortable.index ?? 0;
|
|
217
|
+
const moveDirection = overIndex > activeIndex ? "down" : "up";
|
|
218
|
+
const activeValue = active.id.toString();
|
|
219
|
+
return `Sortable item "${activeValue}" moved ${moveDirection} to position ${overIndex + 1} of ${value.length}.`;
|
|
220
|
+
}
|
|
221
|
+
return "Sortable item is no longer over a droppable area. Press escape to cancel.";
|
|
222
|
+
},
|
|
223
|
+
onDragEnd({ active, over }) {
|
|
224
|
+
const activeValue = active.id.toString();
|
|
225
|
+
if (over) {
|
|
226
|
+
const overIndex = over.data.current?.sortable.index ?? 0;
|
|
227
|
+
return `Sortable item "${activeValue}" dropped at position ${overIndex + 1} of ${value.length}.`;
|
|
228
|
+
}
|
|
229
|
+
return `Sortable item "${activeValue}" dropped. No changes were made.`;
|
|
230
|
+
},
|
|
231
|
+
onDragCancel({ active }) {
|
|
232
|
+
const activeIndex = active.data.current?.sortable.index ?? 0;
|
|
233
|
+
const activeValue = active.id.toString();
|
|
234
|
+
return `Sorting cancelled. Sortable item "${activeValue}" returned to position ${activeIndex + 1} of ${value.length}.`;
|
|
235
|
+
},
|
|
236
|
+
onDragMove({ active, over }) {
|
|
237
|
+
if (over) {
|
|
238
|
+
const overIndex = over.data.current?.sortable.index ?? 0;
|
|
239
|
+
const activeIndex = active.data.current?.sortable.index ?? 0;
|
|
240
|
+
const moveDirection = overIndex > activeIndex ? "down" : "up";
|
|
241
|
+
const activeValue = active.id.toString();
|
|
242
|
+
return `Sortable item "${activeValue}" is moving ${moveDirection} to position ${overIndex + 1} of ${value.length}.`;
|
|
243
|
+
}
|
|
244
|
+
return "Sortable item is no longer over a droppable area. Press escape to cancel.";
|
|
245
|
+
},
|
|
246
|
+
}),
|
|
247
|
+
[value],
|
|
248
|
+
);
|
|
249
|
+
|
|
250
|
+
const screenReaderInstructions: ScreenReaderInstructions = React.useMemo(
|
|
251
|
+
() => ({
|
|
252
|
+
draggable: `
|
|
253
|
+
To pick up a sortable item, press space or enter.
|
|
254
|
+
While dragging, use the ${orientation === "vertical" ? "up and down" : orientation === "horizontal" ? "left and right" : "arrow"} keys to move the item.
|
|
255
|
+
Press space or enter again to drop the item in its new position, or press escape to cancel.
|
|
256
|
+
`,
|
|
257
|
+
}),
|
|
258
|
+
[orientation],
|
|
259
|
+
);
|
|
260
|
+
|
|
261
|
+
const contextValue = React.useMemo(
|
|
262
|
+
() => ({
|
|
263
|
+
id,
|
|
264
|
+
items,
|
|
265
|
+
modifiers: modifiers ?? config.modifiers,
|
|
266
|
+
strategy: strategy ?? config.strategy,
|
|
267
|
+
activeId,
|
|
268
|
+
setActiveId,
|
|
269
|
+
getItemValue,
|
|
270
|
+
flatCursor,
|
|
271
|
+
}),
|
|
272
|
+
[
|
|
273
|
+
id,
|
|
274
|
+
items,
|
|
275
|
+
modifiers,
|
|
276
|
+
strategy,
|
|
277
|
+
config.modifiers,
|
|
278
|
+
config.strategy,
|
|
279
|
+
activeId,
|
|
280
|
+
getItemValue,
|
|
281
|
+
flatCursor,
|
|
282
|
+
],
|
|
283
|
+
);
|
|
284
|
+
|
|
285
|
+
return (
|
|
286
|
+
<SortableRootContext.Provider
|
|
287
|
+
value={contextValue as SortableRootContextValue<unknown>}
|
|
288
|
+
>
|
|
289
|
+
<DndContext
|
|
290
|
+
collisionDetection={collisionDetection ?? config.collisionDetection}
|
|
291
|
+
modifiers={modifiers ?? config.modifiers}
|
|
292
|
+
sensors={sensors}
|
|
293
|
+
{...sortableProps}
|
|
294
|
+
id={id}
|
|
295
|
+
onDragStart={onDragStart}
|
|
296
|
+
onDragEnd={onDragEnd}
|
|
297
|
+
onDragCancel={onDragCancel}
|
|
298
|
+
accessibility={{
|
|
299
|
+
announcements,
|
|
300
|
+
screenReaderInstructions,
|
|
301
|
+
...accessibility,
|
|
302
|
+
}}
|
|
303
|
+
/>
|
|
304
|
+
</SortableRootContext.Provider>
|
|
305
|
+
);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
const SortableContentContext = React.createContext<boolean>(false);
|
|
309
|
+
|
|
310
|
+
interface SortableContentProps extends React.ComponentProps<"div"> {
|
|
311
|
+
strategy?: SortableContextProps["strategy"];
|
|
312
|
+
children: React.ReactNode;
|
|
313
|
+
asChild?: boolean;
|
|
314
|
+
withoutSlot?: boolean;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
function SortableContent(props: SortableContentProps) {
|
|
318
|
+
const {
|
|
319
|
+
strategy: strategyProp,
|
|
320
|
+
asChild,
|
|
321
|
+
withoutSlot,
|
|
322
|
+
children,
|
|
323
|
+
ref,
|
|
324
|
+
...contentProps
|
|
325
|
+
} = props;
|
|
326
|
+
|
|
327
|
+
const context = useSortableContext(CONTENT_NAME);
|
|
328
|
+
|
|
329
|
+
const ContentPrimitive = asChild ? SlotPrimitive.Slot : "div";
|
|
330
|
+
|
|
331
|
+
return (
|
|
332
|
+
<SortableContentContext.Provider value={true}>
|
|
333
|
+
<SortableContext
|
|
334
|
+
items={context.items}
|
|
335
|
+
strategy={strategyProp ?? context.strategy}
|
|
336
|
+
>
|
|
337
|
+
{withoutSlot ? (
|
|
338
|
+
children
|
|
339
|
+
) : (
|
|
340
|
+
<ContentPrimitive
|
|
341
|
+
data-slot="sortable-content"
|
|
342
|
+
{...contentProps}
|
|
343
|
+
ref={ref}
|
|
344
|
+
>
|
|
345
|
+
{children}
|
|
346
|
+
</ContentPrimitive>
|
|
347
|
+
)}
|
|
348
|
+
</SortableContext>
|
|
349
|
+
</SortableContentContext.Provider>
|
|
350
|
+
);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
interface SortableItemContextValue {
|
|
354
|
+
id: string;
|
|
355
|
+
attributes: DraggableAttributes;
|
|
356
|
+
listeners: DraggableSyntheticListeners | undefined;
|
|
357
|
+
setActivatorNodeRef: (node: HTMLElement | null) => void;
|
|
358
|
+
isDragging?: boolean;
|
|
359
|
+
disabled?: boolean;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
const SortableItemContext =
|
|
363
|
+
React.createContext<SortableItemContextValue | null>(null);
|
|
364
|
+
|
|
365
|
+
function useSortableItemContext(consumerName: string) {
|
|
366
|
+
const context = React.useContext(SortableItemContext);
|
|
367
|
+
if (!context) {
|
|
368
|
+
throw new Error(`\`${consumerName}\` must be used within \`${ITEM_NAME}\``);
|
|
369
|
+
}
|
|
370
|
+
return context;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
interface SortableItemProps extends React.ComponentProps<"div"> {
|
|
374
|
+
value: UniqueIdentifier;
|
|
375
|
+
asHandle?: boolean;
|
|
376
|
+
asChild?: boolean;
|
|
377
|
+
disabled?: boolean;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
function SortableItem(props: SortableItemProps) {
|
|
381
|
+
const {
|
|
382
|
+
value,
|
|
383
|
+
style,
|
|
384
|
+
asHandle,
|
|
385
|
+
asChild,
|
|
386
|
+
disabled,
|
|
387
|
+
className,
|
|
388
|
+
ref,
|
|
389
|
+
...itemProps
|
|
390
|
+
} = props;
|
|
391
|
+
|
|
392
|
+
const inSortableContent = React.useContext(SortableContentContext);
|
|
393
|
+
const inSortableOverlay = React.useContext(SortableOverlayContext);
|
|
394
|
+
|
|
395
|
+
if (!inSortableContent && !inSortableOverlay) {
|
|
396
|
+
throw new Error(
|
|
397
|
+
`\`${ITEM_NAME}\` must be used within \`${CONTENT_NAME}\` or \`${OVERLAY_NAME}\``,
|
|
398
|
+
);
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
if (value === "") {
|
|
402
|
+
throw new Error(`\`${ITEM_NAME}\` value cannot be an empty string`);
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
const context = useSortableContext(ITEM_NAME);
|
|
406
|
+
const id = React.useId();
|
|
407
|
+
const {
|
|
408
|
+
attributes,
|
|
409
|
+
listeners,
|
|
410
|
+
setNodeRef,
|
|
411
|
+
setActivatorNodeRef,
|
|
412
|
+
transform,
|
|
413
|
+
transition,
|
|
414
|
+
isDragging,
|
|
415
|
+
} = useSortable({ id: value, disabled });
|
|
416
|
+
|
|
417
|
+
const composedRef = useComposedRefs(ref, (node) => {
|
|
418
|
+
if (disabled) return;
|
|
419
|
+
setNodeRef(node);
|
|
420
|
+
if (asHandle) setActivatorNodeRef(node);
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
const composedStyle = React.useMemo<React.CSSProperties>(() => {
|
|
424
|
+
return {
|
|
425
|
+
transform: CSS.Translate.toString(transform),
|
|
426
|
+
transition,
|
|
427
|
+
...style,
|
|
428
|
+
};
|
|
429
|
+
}, [transform, transition, style]);
|
|
430
|
+
|
|
431
|
+
const itemContext = React.useMemo<SortableItemContextValue>(
|
|
432
|
+
() => ({
|
|
433
|
+
id,
|
|
434
|
+
attributes,
|
|
435
|
+
listeners,
|
|
436
|
+
setActivatorNodeRef,
|
|
437
|
+
isDragging,
|
|
438
|
+
disabled,
|
|
439
|
+
}),
|
|
440
|
+
[id, attributes, listeners, setActivatorNodeRef, isDragging, disabled],
|
|
441
|
+
);
|
|
442
|
+
|
|
443
|
+
const ItemPrimitive = asChild ? SlotPrimitive.Slot : "div";
|
|
444
|
+
|
|
445
|
+
return (
|
|
446
|
+
<SortableItemContext.Provider value={itemContext}>
|
|
447
|
+
<ItemPrimitive
|
|
448
|
+
id={id}
|
|
449
|
+
data-disabled={disabled}
|
|
450
|
+
data-dragging={isDragging ? "" : undefined}
|
|
451
|
+
data-slot="sortable-item"
|
|
452
|
+
{...itemProps}
|
|
453
|
+
{...(asHandle && !disabled ? attributes : {})}
|
|
454
|
+
{...(asHandle && !disabled ? listeners : {})}
|
|
455
|
+
ref={composedRef}
|
|
456
|
+
style={composedStyle}
|
|
457
|
+
className={cn(
|
|
458
|
+
"focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-1",
|
|
459
|
+
{
|
|
460
|
+
"touch-none select-none": asHandle,
|
|
461
|
+
"cursor-default": context.flatCursor,
|
|
462
|
+
"data-dragging:cursor-grabbing": !context.flatCursor,
|
|
463
|
+
"cursor-grab": !isDragging && asHandle && !context.flatCursor,
|
|
464
|
+
"opacity-50": isDragging,
|
|
465
|
+
"pointer-events-none opacity-50": disabled,
|
|
466
|
+
},
|
|
467
|
+
className,
|
|
468
|
+
)}
|
|
469
|
+
/>
|
|
470
|
+
</SortableItemContext.Provider>
|
|
471
|
+
);
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
interface SortableItemHandleProps extends React.ComponentProps<"button"> {
|
|
475
|
+
asChild?: boolean;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
function SortableItemHandle(props: SortableItemHandleProps) {
|
|
479
|
+
const { asChild, disabled, className, ref, ...itemHandleProps } = props;
|
|
480
|
+
|
|
481
|
+
const context = useSortableContext(ITEM_HANDLE_NAME);
|
|
482
|
+
const itemContext = useSortableItemContext(ITEM_HANDLE_NAME);
|
|
483
|
+
|
|
484
|
+
const isDisabled = disabled ?? itemContext.disabled;
|
|
485
|
+
|
|
486
|
+
const composedRef = useComposedRefs(ref, (node) => {
|
|
487
|
+
if (!isDisabled) return;
|
|
488
|
+
itemContext.setActivatorNodeRef(node);
|
|
489
|
+
});
|
|
490
|
+
|
|
491
|
+
const HandlePrimitive = asChild ? SlotPrimitive.Slot : "button";
|
|
492
|
+
|
|
493
|
+
return (
|
|
494
|
+
<HandlePrimitive
|
|
495
|
+
type="button"
|
|
496
|
+
aria-controls={itemContext.id}
|
|
497
|
+
data-disabled={isDisabled}
|
|
498
|
+
data-dragging={itemContext.isDragging ? "" : undefined}
|
|
499
|
+
data-slot="sortable-item-handle"
|
|
500
|
+
{...itemHandleProps}
|
|
501
|
+
{...(isDisabled ? {} : itemContext.attributes)}
|
|
502
|
+
{...(isDisabled ? {} : itemContext.listeners)}
|
|
503
|
+
ref={composedRef}
|
|
504
|
+
className={cn(
|
|
505
|
+
"select-none disabled:pointer-events-none disabled:opacity-50",
|
|
506
|
+
context.flatCursor
|
|
507
|
+
? "cursor-default"
|
|
508
|
+
: "cursor-grab data-dragging:cursor-grabbing",
|
|
509
|
+
className,
|
|
510
|
+
)}
|
|
511
|
+
disabled={isDisabled}
|
|
512
|
+
/>
|
|
513
|
+
);
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
const SortableOverlayContext = React.createContext(false);
|
|
517
|
+
|
|
518
|
+
const dropAnimation: DropAnimation = {
|
|
519
|
+
sideEffects: defaultDropAnimationSideEffects({
|
|
520
|
+
styles: {
|
|
521
|
+
active: {
|
|
522
|
+
opacity: "0.4",
|
|
523
|
+
},
|
|
524
|
+
},
|
|
525
|
+
}),
|
|
526
|
+
};
|
|
527
|
+
|
|
528
|
+
interface SortableOverlayProps
|
|
529
|
+
extends Omit<React.ComponentProps<typeof DragOverlay>, "children"> {
|
|
530
|
+
container?: Element | DocumentFragment | null;
|
|
531
|
+
children?:
|
|
532
|
+
| ((params: { value: UniqueIdentifier }) => React.ReactNode)
|
|
533
|
+
| React.ReactNode;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
function SortableOverlay(props: SortableOverlayProps) {
|
|
537
|
+
const { container: containerProp, children, ...overlayProps } = props;
|
|
538
|
+
|
|
539
|
+
const context = useSortableContext(OVERLAY_NAME);
|
|
540
|
+
|
|
541
|
+
const [mounted, setMounted] = React.useState(false);
|
|
542
|
+
|
|
543
|
+
React.useLayoutEffect(() => setMounted(true), []);
|
|
544
|
+
|
|
545
|
+
const container =
|
|
546
|
+
containerProp ?? (mounted ? globalThis.document?.body : null);
|
|
547
|
+
|
|
548
|
+
if (!container) return null;
|
|
549
|
+
|
|
550
|
+
return ReactDOM.createPortal(
|
|
551
|
+
<DragOverlay
|
|
552
|
+
dropAnimation={dropAnimation}
|
|
553
|
+
modifiers={context.modifiers}
|
|
554
|
+
className={cn(!context.flatCursor && "cursor-grabbing")}
|
|
555
|
+
{...overlayProps}
|
|
556
|
+
>
|
|
557
|
+
<SortableOverlayContext.Provider value={true}>
|
|
558
|
+
{context.activeId
|
|
559
|
+
? typeof children === "function"
|
|
560
|
+
? children({ value: context.activeId })
|
|
561
|
+
: children
|
|
562
|
+
: null}
|
|
563
|
+
</SortableOverlayContext.Provider>
|
|
564
|
+
</DragOverlay>,
|
|
565
|
+
container,
|
|
566
|
+
);
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
export {
|
|
570
|
+
Sortable,
|
|
571
|
+
SortableContent,
|
|
572
|
+
SortableItem,
|
|
573
|
+
SortableItemHandle,
|
|
574
|
+
SortableOverlay,
|
|
575
|
+
//
|
|
576
|
+
type SortableProps,
|
|
577
|
+
};
|
package/src/index.ts
CHANGED
|
@@ -24,3 +24,19 @@ export { cn } from "./lib";
|
|
|
24
24
|
|
|
25
25
|
// Hooks
|
|
26
26
|
export * from "./hooks";
|
|
27
|
+
|
|
28
|
+
// Components
|
|
29
|
+
export { AgentsTable } from "./components/agents/agents-table";
|
|
30
|
+
export { AgentFormDialog } from "./components/agents/agent-form-dialog";
|
|
31
|
+
export { AgentEditForm } from "./components/agents/agent-edit-form";
|
|
32
|
+
export { AgentTabs } from "./components/agents/agent-tabs";
|
|
33
|
+
export { AgentPromptEditor } from "./components/agents/agent-prompt-editor";
|
|
34
|
+
export { AgentObjectivesList } from "./components/agents/agent-objectives-list";
|
|
35
|
+
export { AgentToolsList } from "./components/agents/agent-tools-list";
|
|
36
|
+
export { ToolsTable } from "./components/tools/tools-table";
|
|
37
|
+
export { ToolFormDialog } from "./components/tools/tool-form-dialog";
|
|
38
|
+
export { ToolCredentialsForm } from "./components/tools/tool-credentials-form";
|
|
39
|
+
export { Sortable, SortableContent, SortableItem, SortableItemHandle, SortableOverlay } from "./components/ui/sortable";
|
|
40
|
+
|
|
41
|
+
// Page Compositions
|
|
42
|
+
export * from "./pages";
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
|
|
3
|
+
type PossibleRef<T> = React.Ref<T> | undefined;
|
|
4
|
+
|
|
5
|
+
function setRef<T>(ref: PossibleRef<T>, value: T) {
|
|
6
|
+
if (typeof ref === "function") {
|
|
7
|
+
return ref(value);
|
|
8
|
+
}
|
|
9
|
+
if (ref !== null && ref !== undefined) {
|
|
10
|
+
ref.current = value;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function composeRefs<T>(...refs: PossibleRef<T>[]): React.RefCallback<T> {
|
|
15
|
+
return (node) => {
|
|
16
|
+
let hasCleanup = false;
|
|
17
|
+
const cleanups = refs.map((ref) => {
|
|
18
|
+
const cleanup = setRef(ref, node);
|
|
19
|
+
if (!hasCleanup && typeof cleanup === "function") {
|
|
20
|
+
hasCleanup = true;
|
|
21
|
+
}
|
|
22
|
+
return cleanup;
|
|
23
|
+
});
|
|
24
|
+
if (hasCleanup) {
|
|
25
|
+
return () => {
|
|
26
|
+
for (let i = 0; i < cleanups.length; i++) {
|
|
27
|
+
const cleanup = cleanups[i];
|
|
28
|
+
if (typeof cleanup === "function") {
|
|
29
|
+
cleanup();
|
|
30
|
+
} else {
|
|
31
|
+
setRef(refs[i], null);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function useComposedRefs<T>(...refs: PossibleRef<T>[]): React.RefCallback<T> {
|
|
40
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
41
|
+
return React.useCallback(composeRefs(...refs), refs);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export { composeRefs, useComposedRefs };
|