ai-design-system 0.1.41 → 0.1.43
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/components/blocks/AIConversation/AIConversation.tsx +12 -4
- package/components/blocks/WorkflowCanvas/WorkflowCanvas.tsx +2 -1
- package/components/composites/AppHeader/AppHeader.mocks.ts +1 -1
- package/components/composites/DataTable/DataTable.tsx +3 -2
- package/components/composites/DataTable/EnhancedDataTable.tsx +1 -1
- package/components/composites/DataTable/InlineEditCell.tsx +7 -5
- package/components/composites/DataTable/ReviewerCell.tsx +2 -2
- package/components/composites/DataTable/RowDetailDrawer.tsx +8 -8
- package/components/composites/DataTable/StatusCell.tsx +1 -1
- package/components/composites/DataTable/useEnhancedDataTable.ts +3 -3
- package/components/composites/DocumentTabBar/DocumentTabBar.tsx +8 -2
- package/components/composites/FilePreviewDialog/FilePreviewDialog.tsx +15 -10
- package/components/composites/FormReports/FormReportsDrawerForm.tsx +14 -7
- package/components/features/AIDocEditor/AIDocEditor.mocks.ts +14 -1
- package/components/features/AIDocEditor/AIDocEditor.tsx +7 -2
- package/components/features/AIDocEditor/useAIDocEditor.mock.ts +18 -4
- package/components/features/DashboardFeature/DashboardFeature.mocks.ts +7 -7
- package/components/features/FormReportsFeature/FormReportsFeature.mocks.ts +11 -50
- package/components/features/RefinementPanel/useRefinementPanel.mock.ts +1 -1
- package/components/features/SpecNavigator/SpecNavigator.tsx +33 -10
- package/components/features/WorkflowBuilder/useWorkflowBuilder.mock.ts +4 -0
- package/components/index.ts +1 -1
- package/components/primitives/Drawer/Drawer.tsx +7 -11
- package/components/primitives/Popover/Popover.tsx +2 -5
- package/dist/index.cjs +42 -121
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +38 -18
- package/dist/index.js +43 -122
- package/dist/index.js.map +1 -1
- package/package.json +5 -3
|
@@ -6,12 +6,11 @@ import {
|
|
|
6
6
|
ConversationScrollButton,
|
|
7
7
|
type ConversationProps,
|
|
8
8
|
} from "@/components/ai-elements/conversation"
|
|
9
|
-
import {
|
|
9
|
+
import type { ToolCall, SubAgent } from "@/components/composites"
|
|
10
10
|
import { UserMessage } from "@/components/composites/UserMessage"
|
|
11
11
|
import { SpecialistMessage } from "@/components/composites/SpecialistMessage"
|
|
12
12
|
import { OrchestratorMessage } from "@/components/composites/OrchestratorMessage"
|
|
13
13
|
import { ToolCallDisplay } from "@/components/composites/ToolCallDisplay"
|
|
14
|
-
import type { SubAgent } from "@/components/composites/AgentIndicator"
|
|
15
14
|
|
|
16
15
|
/**
|
|
17
16
|
* AIConversation Section
|
|
@@ -23,6 +22,17 @@ import type { SubAgent } from "@/components/composites/AgentIndicator"
|
|
|
23
22
|
* Based on reference implementation from deep-agents-ui ChatInterface.
|
|
24
23
|
*/
|
|
25
24
|
|
|
25
|
+
interface AIMessage {
|
|
26
|
+
id: string;
|
|
27
|
+
type: 'human' | 'ai';
|
|
28
|
+
role: string;
|
|
29
|
+
content: string;
|
|
30
|
+
avatarSrc?: string;
|
|
31
|
+
avatarName?: string;
|
|
32
|
+
toolCalls?: ToolCall[];
|
|
33
|
+
subAgents?: SubAgent[];
|
|
34
|
+
}
|
|
35
|
+
|
|
26
36
|
export interface AIConversationProps
|
|
27
37
|
extends Omit<ConversationProps, "children"> {
|
|
28
38
|
/**
|
|
@@ -137,7 +147,6 @@ export const AIConversation = React.memo<AIConversationProps>(
|
|
|
137
147
|
status: subAgent.status,
|
|
138
148
|
toolCalls: [],
|
|
139
149
|
}}
|
|
140
|
-
showAvatar={showAvatars}
|
|
141
150
|
isNested={true}
|
|
142
151
|
/>
|
|
143
152
|
))}
|
|
@@ -156,7 +165,6 @@ export const AIConversation = React.memo<AIConversationProps>(
|
|
|
156
165
|
toolCalls: message.toolCalls?.filter((tc) => tc.name !== "task"),
|
|
157
166
|
status: "completed",
|
|
158
167
|
}}
|
|
159
|
-
showAvatar={showAvatars}
|
|
160
168
|
isNested={false}
|
|
161
169
|
/>
|
|
162
170
|
)
|
|
@@ -109,7 +109,8 @@ function WorkflowCanvasInner({
|
|
|
109
109
|
onEdgesChange={onEdgesChange}
|
|
110
110
|
onNodesChange={onNodesChange}
|
|
111
111
|
onPaneClick={onPaneClick}
|
|
112
|
-
|
|
112
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
113
|
+
onNodeClick={onNodeClick as any}
|
|
113
114
|
onEdgeClick={onEdgeClick}
|
|
114
115
|
>
|
|
115
116
|
{topLeft && (
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
flexRender,
|
|
9
9
|
type ColumnDef,
|
|
10
10
|
} from "@tanstack/react-table"
|
|
11
|
+
import type { Table as TanStackTable } from "@tanstack/react-table"
|
|
11
12
|
import { Table, TableHeader, TableBody, TableRow, TableHead, TableCell } from "@/components/primitives/Table"
|
|
12
13
|
import { TablePagination } from "@/components/composites/TablePagination"
|
|
13
14
|
import { TableToolbar } from "@/components/composites/TableToolbar"
|
|
@@ -45,7 +46,7 @@ export function DataTable<TData, TValue>({
|
|
|
45
46
|
|
|
46
47
|
return (
|
|
47
48
|
<div className={`space-y-4 ${className || ""}`}>
|
|
48
|
-
{enableFiltering && <TableToolbar table={table} searchColumn={searchColumn} />}
|
|
49
|
+
{enableFiltering && <TableToolbar table={table as unknown as TanStackTable<unknown>} searchColumn={searchColumn} />}
|
|
49
50
|
<div className="rounded-md border">
|
|
50
51
|
<Table>
|
|
51
52
|
<TableHeader>
|
|
@@ -87,7 +88,7 @@ export function DataTable<TData, TValue>({
|
|
|
87
88
|
</TableBody>
|
|
88
89
|
</Table>
|
|
89
90
|
</div>
|
|
90
|
-
{enablePagination && <TablePagination table={table} />}
|
|
91
|
+
{enablePagination && <TablePagination table={table as unknown as TanStackTable<unknown>} />}
|
|
91
92
|
</div>
|
|
92
93
|
)
|
|
93
94
|
}
|
|
@@ -439,7 +439,7 @@ export function EnhancedDataTable({
|
|
|
439
439
|
(event: DragEndEvent) => {
|
|
440
440
|
const { active, over } = event
|
|
441
441
|
if (active && over && active.id !== over.id) {
|
|
442
|
-
reorderById(active.id, over.id)
|
|
442
|
+
reorderById(String(active.id), String(over.id))
|
|
443
443
|
}
|
|
444
444
|
},
|
|
445
445
|
[reorderById]
|
|
@@ -14,16 +14,18 @@ export interface InlineEditCellProps {
|
|
|
14
14
|
export function InlineEditCell({ row, field, onSave }: InlineEditCellProps) {
|
|
15
15
|
const inputId = `${row.id}-${field}`
|
|
16
16
|
const defaultValue = row[field]
|
|
17
|
+
const rowId = row.id as number
|
|
18
|
+
const rowHeader = row.header as string
|
|
17
19
|
|
|
18
20
|
const onSubmit = React.useCallback(
|
|
19
21
|
(event: React.FormEvent<HTMLFormElement>) => {
|
|
20
22
|
event.preventDefault()
|
|
21
23
|
const formData = new FormData(event.currentTarget)
|
|
22
24
|
const value = String(formData.get(field) ?? "").trim()
|
|
23
|
-
onSave(
|
|
24
|
-
toast.success(`Saved ${field} for ${
|
|
25
|
+
onSave(rowId, field, value)
|
|
26
|
+
toast.success(`Saved ${field} for ${rowHeader}`)
|
|
25
27
|
},
|
|
26
|
-
[field, onSave,
|
|
28
|
+
[field, onSave, rowId, rowHeader]
|
|
27
29
|
)
|
|
28
30
|
|
|
29
31
|
return (
|
|
@@ -34,10 +36,10 @@ export function InlineEditCell({ row, field, onSave }: InlineEditCellProps) {
|
|
|
34
36
|
<Input
|
|
35
37
|
id={inputId}
|
|
36
38
|
name={field}
|
|
37
|
-
defaultValue={defaultValue}
|
|
39
|
+
defaultValue={String(defaultValue)}
|
|
38
40
|
className="h-8 w-16 border-transparent bg-transparent text-right shadow-none hover:bg-input/30 focus-visible:border focus-visible:bg-background"
|
|
39
41
|
onBlur={(event) => {
|
|
40
|
-
onSave(row.id, field, event.target.value)
|
|
42
|
+
onSave(row.id as number, field, event.target.value)
|
|
41
43
|
}}
|
|
42
44
|
/>
|
|
43
45
|
</form>
|
|
@@ -16,7 +16,7 @@ export function ReviewerCell({ row, onAssign }: ReviewerCellProps) {
|
|
|
16
16
|
const isAssigned = row.reviewer !== "Assign reviewer"
|
|
17
17
|
|
|
18
18
|
if (isAssigned) {
|
|
19
|
-
return <span>{row.reviewer}</span>
|
|
19
|
+
return <span>{row.reviewer as React.ReactNode}</span>
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
const id = `${row.id}-reviewer`
|
|
@@ -26,7 +26,7 @@ export function ReviewerCell({ row, onAssign }: ReviewerCellProps) {
|
|
|
26
26
|
<Label htmlFor={id} className="sr-only">
|
|
27
27
|
Reviewer
|
|
28
28
|
</Label>
|
|
29
|
-
<Select onValueChange={(value) => onAssign(row.id, value)}>
|
|
29
|
+
<Select onValueChange={(value) => onAssign(row.id as number, value)}>
|
|
30
30
|
<SelectTrigger id={id} className="w-[170px]">
|
|
31
31
|
<SelectValue placeholder="Assign reviewer" />
|
|
32
32
|
</SelectTrigger>
|
|
@@ -67,12 +67,12 @@ export function RowDetailDrawer({ item, onChange }: RowDetailDrawerProps) {
|
|
|
67
67
|
<Drawer open={open} onOpenChange={setOpen} direction={isMobile ? "bottom" : "right"}>
|
|
68
68
|
<DrawerTrigger asChild>
|
|
69
69
|
<Button variant="link" className="w-fit px-0 text-left text-foreground">
|
|
70
|
-
{item.header}
|
|
70
|
+
{item.header as React.ReactNode}
|
|
71
71
|
</Button>
|
|
72
72
|
</DrawerTrigger>
|
|
73
73
|
<DrawerContent>
|
|
74
74
|
<DrawerHeader className="gap-1">
|
|
75
|
-
<DrawerTitle>{item.header}</DrawerTitle>
|
|
75
|
+
<DrawerTitle>{item.header as React.ReactNode}</DrawerTitle>
|
|
76
76
|
<DrawerDescription>Showing total visitors for the last 6 months</DrawerDescription>
|
|
77
77
|
</DrawerHeader>
|
|
78
78
|
<div className="flex flex-col gap-4 overflow-y-auto px-4 text-sm">
|
|
@@ -103,12 +103,12 @@ export function RowDetailDrawer({ item, onChange }: RowDetailDrawerProps) {
|
|
|
103
103
|
<form className="flex flex-col gap-4" onSubmit={(e) => e.preventDefault()}>
|
|
104
104
|
<div className="flex flex-col gap-3">
|
|
105
105
|
<Label htmlFor="drawer-header">Header</Label>
|
|
106
|
-
<Input id="drawer-header" defaultValue={item.header} onBlur={(e) => onChange(item.id, "header", e.target.value)} />
|
|
106
|
+
<Input id="drawer-header" defaultValue={String(item.header)} onBlur={(e) => onChange(item.id as number, "header", e.target.value)} />
|
|
107
107
|
</div>
|
|
108
108
|
<div className="grid grid-cols-2 gap-4">
|
|
109
109
|
<div className="flex flex-col gap-3">
|
|
110
110
|
<Label htmlFor="drawer-type">Type</Label>
|
|
111
|
-
<Select defaultValue={item.type} onValueChange={(value) => onChange(item.id, "type", value)}>
|
|
111
|
+
<Select defaultValue={String(item.type)} onValueChange={(value) => onChange(item.id as number, "type", value)}>
|
|
112
112
|
<SelectTrigger id="drawer-type" className="w-full">
|
|
113
113
|
<SelectValue placeholder="Select a type" />
|
|
114
114
|
</SelectTrigger>
|
|
@@ -123,7 +123,7 @@ export function RowDetailDrawer({ item, onChange }: RowDetailDrawerProps) {
|
|
|
123
123
|
</div>
|
|
124
124
|
<div className="flex flex-col gap-3">
|
|
125
125
|
<Label htmlFor="drawer-status">Status</Label>
|
|
126
|
-
<Select defaultValue={item.status} onValueChange={(value) => onChange(item.id, "status", value)}>
|
|
126
|
+
<Select defaultValue={String(item.status)} onValueChange={(value) => onChange(item.id as number, "status", value)}>
|
|
127
127
|
<SelectTrigger id="drawer-status" className="w-full">
|
|
128
128
|
<SelectValue placeholder="Select a status" />
|
|
129
129
|
</SelectTrigger>
|
|
@@ -138,16 +138,16 @@ export function RowDetailDrawer({ item, onChange }: RowDetailDrawerProps) {
|
|
|
138
138
|
<div className="grid grid-cols-2 gap-4">
|
|
139
139
|
<div className="flex flex-col gap-3">
|
|
140
140
|
<Label htmlFor="drawer-target">Target</Label>
|
|
141
|
-
<Input id="drawer-target" defaultValue={item.target} onBlur={(e) => onChange(item.id, "target", e.target.value)} />
|
|
141
|
+
<Input id="drawer-target" defaultValue={String(item.target)} onBlur={(e) => onChange(item.id as number, "target", e.target.value)} />
|
|
142
142
|
</div>
|
|
143
143
|
<div className="flex flex-col gap-3">
|
|
144
144
|
<Label htmlFor="drawer-limit">Limit</Label>
|
|
145
|
-
<Input id="drawer-limit" defaultValue={item.limit} onBlur={(e) => onChange(item.id, "limit", e.target.value)} />
|
|
145
|
+
<Input id="drawer-limit" defaultValue={String(item.limit)} onBlur={(e) => onChange(item.id as number, "limit", e.target.value)} />
|
|
146
146
|
</div>
|
|
147
147
|
</div>
|
|
148
148
|
<div className="flex flex-col gap-3">
|
|
149
149
|
<Label htmlFor="drawer-reviewer">Reviewer</Label>
|
|
150
|
-
<Select defaultValue={item.reviewer} onValueChange={(value) => onChange(item.id, "reviewer", value)}>
|
|
150
|
+
<Select defaultValue={String(item.reviewer)} onValueChange={(value) => onChange(item.id as number, "reviewer", value)}>
|
|
151
151
|
<SelectTrigger id="drawer-reviewer" className="w-full">
|
|
152
152
|
<SelectValue placeholder="Select a reviewer" />
|
|
153
153
|
</SelectTrigger>
|
|
@@ -13,7 +13,7 @@ export function StatusCell({ status }: StatusCellProps) {
|
|
|
13
13
|
{status === "Done" ? <CheckCircle2 className="size-3 text-green-500" /> : null}
|
|
14
14
|
{status === "In Process" ? <LoaderCircle className="size-3 animate-spin" /> : null}
|
|
15
15
|
{status === "Not Started" ? <CircleSlash className="size-3" /> : null}
|
|
16
|
-
{status}
|
|
16
|
+
{status as React.ReactNode}
|
|
17
17
|
</Badge>
|
|
18
18
|
)
|
|
19
19
|
}
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
type SortingState,
|
|
13
13
|
type VisibilityState,
|
|
14
14
|
} from "@tanstack/react-table"
|
|
15
|
-
import { arrayMove
|
|
15
|
+
import { arrayMove } from "@dnd-kit/sortable"
|
|
16
16
|
|
|
17
17
|
import type { DashboardRow } from "./table-types"
|
|
18
18
|
|
|
@@ -54,7 +54,7 @@ export function useEnhancedDataTable({ data: initialData, columns, onReorder, se
|
|
|
54
54
|
})
|
|
55
55
|
}, [serverPagination])
|
|
56
56
|
|
|
57
|
-
const dataIds = React.useMemo<
|
|
57
|
+
const dataIds = React.useMemo<string[]>(() => data.map((item) => String(item.id)), [data])
|
|
58
58
|
|
|
59
59
|
const table = useReactTable({
|
|
60
60
|
data,
|
|
@@ -86,7 +86,7 @@ export function useEnhancedDataTable({ data: initialData, columns, onReorder, se
|
|
|
86
86
|
})
|
|
87
87
|
|
|
88
88
|
const reorderById = React.useCallback(
|
|
89
|
-
(activeId:
|
|
89
|
+
(activeId: string, overId: string) => {
|
|
90
90
|
if (activeId === overId) {
|
|
91
91
|
return
|
|
92
92
|
}
|
|
@@ -9,7 +9,13 @@ import React from 'react'
|
|
|
9
9
|
import { Tabs, TabsList, TabsTrigger, Button, ScrollArea } from '@/components/primitives'
|
|
10
10
|
import { X, Circle } from 'lucide-react'
|
|
11
11
|
import { cn } from '@/lib/utils'
|
|
12
|
-
|
|
12
|
+
export interface DocumentFile {
|
|
13
|
+
id: string
|
|
14
|
+
name: string
|
|
15
|
+
isDirty?: boolean
|
|
16
|
+
format?: string
|
|
17
|
+
lastModified?: number
|
|
18
|
+
}
|
|
13
19
|
|
|
14
20
|
/**
|
|
15
21
|
* Props for DocumentTabBar composite
|
|
@@ -70,7 +76,7 @@ export const DocumentTabBar = React.memo<DocumentTabBarProps>(
|
|
|
70
76
|
)}
|
|
71
77
|
data-slot="document-tab-bar"
|
|
72
78
|
>
|
|
73
|
-
<ScrollArea
|
|
79
|
+
<ScrollArea className="flex-1">
|
|
74
80
|
<Tabs
|
|
75
81
|
value={activeTabId || tabs[0]?.id}
|
|
76
82
|
onValueChange={onTabSelect}
|
|
@@ -13,6 +13,7 @@ interface ChecklistItem {
|
|
|
13
13
|
id: string;
|
|
14
14
|
label: string;
|
|
15
15
|
checked: boolean;
|
|
16
|
+
isTask: boolean;
|
|
16
17
|
}
|
|
17
18
|
|
|
18
19
|
function parseChecklistItems(content?: string) {
|
|
@@ -50,6 +51,7 @@ function parseChecklistItems(content?: string) {
|
|
|
50
51
|
id: `checklist-${index}`,
|
|
51
52
|
label: taskMatch[2],
|
|
52
53
|
checked: taskMatch[1].toLowerCase() === "x",
|
|
54
|
+
isTask: true,
|
|
53
55
|
});
|
|
54
56
|
return items;
|
|
55
57
|
}
|
|
@@ -61,6 +63,7 @@ function parseChecklistItems(content?: string) {
|
|
|
61
63
|
id: `checklist-${index}`,
|
|
62
64
|
label: numberStripped,
|
|
63
65
|
checked: false,
|
|
66
|
+
isTask: false,
|
|
64
67
|
});
|
|
65
68
|
|
|
66
69
|
return items;
|
|
@@ -121,16 +124,18 @@ export const FilePreviewDialog = React.memo<FilePreviewDialogProps>(
|
|
|
121
124
|
key={item.id}
|
|
122
125
|
className="flex items-start gap-3 rounded-md px-1 py-1 text-sm leading-6"
|
|
123
126
|
>
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
127
|
+
{item.isTask && (
|
|
128
|
+
<Checkbox
|
|
129
|
+
checked={checkedItems[item.id] ?? false}
|
|
130
|
+
onCheckedChange={(checked) => {
|
|
131
|
+
setCheckedItems((prev) => ({
|
|
132
|
+
...prev,
|
|
133
|
+
[item.id]: checked === true,
|
|
134
|
+
}));
|
|
135
|
+
}}
|
|
136
|
+
className="mt-1"
|
|
137
|
+
/>
|
|
138
|
+
)}
|
|
134
139
|
<span>{item.label}</span>
|
|
135
140
|
</label>
|
|
136
141
|
))}
|
|
@@ -15,12 +15,19 @@ import { Label } from "@/components/primitives/Label"
|
|
|
15
15
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/primitives/Select"
|
|
16
16
|
import { Checkbox } from "@/components/primitives/Checkbox"
|
|
17
17
|
import { Textarea } from "@/components/primitives/Textarea"
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
18
|
+
type FormFieldType = "text" | "number" | "date" | "textarea" | "select" | "boolean"
|
|
19
|
+
type FormFieldValue = string | number | boolean | null
|
|
20
|
+
interface FormFieldOption { value: string; label: string }
|
|
21
|
+
interface FormFieldDefinition {
|
|
22
|
+
name: string
|
|
23
|
+
label: string
|
|
24
|
+
type: FormFieldType
|
|
25
|
+
required?: boolean
|
|
26
|
+
placeholder?: string
|
|
27
|
+
description?: string
|
|
28
|
+
defaultValue?: FormFieldValue
|
|
29
|
+
options?: FormFieldOption[]
|
|
30
|
+
}
|
|
24
31
|
|
|
25
32
|
export type FormReportsFieldType = FormFieldType
|
|
26
33
|
|
|
@@ -142,7 +149,7 @@ export const FormReportsDrawerForm = React.memo<FormReportsDrawerFormProps>(
|
|
|
142
149
|
<SelectValue placeholder={field.placeholder ?? `Select ${field.label}`} />
|
|
143
150
|
</SelectTrigger>
|
|
144
151
|
<SelectContent>
|
|
145
|
-
{(field.options ?? []).map((option) => (
|
|
152
|
+
{(field.options ?? []).map((option: FormFieldOption) => (
|
|
146
153
|
<SelectItem key={option.value} value={option.value}>
|
|
147
154
|
{option.label}
|
|
148
155
|
</SelectItem>
|
|
@@ -9,7 +9,20 @@
|
|
|
9
9
|
|
|
10
10
|
import type { JSONContent } from '@tiptap/core'
|
|
11
11
|
import type { Annotation, User } from '@/types/ai-editor'
|
|
12
|
-
|
|
12
|
+
|
|
13
|
+
interface DocumentFile {
|
|
14
|
+
id: string
|
|
15
|
+
name: string
|
|
16
|
+
isDirty?: boolean
|
|
17
|
+
format?: string
|
|
18
|
+
lastModified?: number
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
interface DocumentWithAnnotations {
|
|
22
|
+
file: DocumentFile
|
|
23
|
+
content: JSONContent | string
|
|
24
|
+
annotations: Annotation[]
|
|
25
|
+
}
|
|
13
26
|
|
|
14
27
|
/**
|
|
15
28
|
* Sample document content for stories and tests
|
|
@@ -38,7 +38,12 @@ import { DocumentTabBar } from '@/components/composites/DocumentTabBar'
|
|
|
38
38
|
import { cn } from '@/lib/utils'
|
|
39
39
|
import type { JSONContent } from '@tiptap/core'
|
|
40
40
|
import type { Annotation, User } from '@/types/ai-editor/annotations'
|
|
41
|
-
|
|
41
|
+
|
|
42
|
+
interface DocumentWithAnnotations {
|
|
43
|
+
file: { id: string; name: string; isDirty?: boolean; format?: 'json' | 'markdown' | string; lastModified?: number }
|
|
44
|
+
content: JSONContent | string
|
|
45
|
+
annotations: Annotation[]
|
|
46
|
+
}
|
|
42
47
|
|
|
43
48
|
/**
|
|
44
49
|
* Props for AIDocEditor feature component - Single document mode (backward compatible)
|
|
@@ -240,7 +245,7 @@ export const AIDocEditor = React.memo<AIDocEditorProps>(
|
|
|
240
245
|
<div className="flex-1 overflow-auto">
|
|
241
246
|
<DocumentEditorWithComments
|
|
242
247
|
content={currentDocument.content}
|
|
243
|
-
format={currentDocument.file.format}
|
|
248
|
+
format={currentDocument.file.format as 'json' | 'markdown' | undefined}
|
|
244
249
|
annotations={currentDocument.annotations}
|
|
245
250
|
currentUserId={currentUser.id}
|
|
246
251
|
currentUserName={currentUser.name}
|
|
@@ -6,10 +6,24 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import { useState, useCallback } from 'react'
|
|
9
|
+
import type { JSONContent } from '@tiptap/core'
|
|
9
10
|
import type { Annotation } from '@/types/ai-editor/annotations'
|
|
10
|
-
import type { DocumentFile, DocumentWithAnnotations } from '@/types/ai-editor'
|
|
11
11
|
import type { UseAIDocEditorReturn, UseAIMultiTabDocEditorReturn } from './useAIDocEditor'
|
|
12
12
|
|
|
13
|
+
interface DocumentFile {
|
|
14
|
+
id: string
|
|
15
|
+
name: string
|
|
16
|
+
isDirty: boolean
|
|
17
|
+
format?: 'json' | 'markdown'
|
|
18
|
+
lastModified: number
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
interface DocumentWithAnnotations {
|
|
22
|
+
file: DocumentFile
|
|
23
|
+
content: JSONContent | string
|
|
24
|
+
annotations: Annotation[]
|
|
25
|
+
}
|
|
26
|
+
|
|
13
27
|
type MultiDocMockConfig = {
|
|
14
28
|
multiDoc: true
|
|
15
29
|
initialDocuments?: DocumentWithAnnotations[]
|
|
@@ -76,9 +90,9 @@ function useMultiTabDocEditorMockState(
|
|
|
76
90
|
)
|
|
77
91
|
const [loading, setLoading] = useState(false)
|
|
78
92
|
|
|
79
|
-
const addDocument = useCallback((file: DocumentFile, content:
|
|
93
|
+
const addDocument = useCallback((file: DocumentFile, content: unknown) => {
|
|
80
94
|
console.log('[Multi-Tab Mock] Adding document:', file.name)
|
|
81
|
-
setDocuments(prev => [...prev, { file, content, annotations: [] }])
|
|
95
|
+
setDocuments(prev => [...prev, { file, content: content as JSONContent | string, annotations: [] }])
|
|
82
96
|
setActiveDocumentId(file.id)
|
|
83
97
|
}, [])
|
|
84
98
|
|
|
@@ -227,6 +241,6 @@ export function useAIDocEditorMock(
|
|
|
227
241
|
* @param initialDocuments - Initial documents to display
|
|
228
242
|
* @returns Mock implementation of UseAIMultiTabDocEditorReturn
|
|
229
243
|
*/
|
|
230
|
-
export function useAIMultiTabDocEditorMock(initialDocuments:
|
|
244
|
+
export function useAIMultiTabDocEditorMock(initialDocuments: unknown[] = []): UseAIMultiTabDocEditorReturn {
|
|
231
245
|
return useMultiTabDocEditorMockState(initialDocuments as DocumentWithAnnotations[])
|
|
232
246
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { DashboardRow } from "@/components/composites/DataTable"
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
}
|
|
2
|
+
import type { FormReportsFieldDefinition } from "@/components/composites/FormReports"
|
|
3
|
+
|
|
4
|
+
const formSchema = {
|
|
5
|
+
parse<T>(input: T): T { return input },
|
|
6
|
+
} as const
|
|
7
7
|
import {
|
|
8
8
|
DYNAMIC_TABLE_SCHEMA_VERSION,
|
|
9
9
|
FORM_SCHEMA_VERSION,
|
|
@@ -154,9 +154,9 @@ const dashboardCreateFormSchemaInput = {
|
|
|
154
154
|
placeholder: "Enable immediately",
|
|
155
155
|
},
|
|
156
156
|
],
|
|
157
|
-
}
|
|
157
|
+
}
|
|
158
158
|
|
|
159
|
-
export const dashboardCreateFields:
|
|
159
|
+
export const dashboardCreateFields: FormReportsFieldDefinition[] = formSchema.parse(dashboardCreateFormSchemaInput).fields as unknown as FormReportsFieldDefinition[]
|
|
160
160
|
|
|
161
161
|
export const dashboardKpis = [
|
|
162
162
|
{
|
|
@@ -4,10 +4,6 @@ import type {
|
|
|
4
4
|
FormReportsFieldDefinition,
|
|
5
5
|
FormReportsRowAction,
|
|
6
6
|
} from "@/components/composites/FormReports"
|
|
7
|
-
import {
|
|
8
|
-
formSchema,
|
|
9
|
-
type FormSchema,
|
|
10
|
-
} from "design-schema/schemas/form"
|
|
11
7
|
import {
|
|
12
8
|
DYNAMIC_TABLE_SCHEMA_VERSION,
|
|
13
9
|
FORM_SCHEMA_VERSION,
|
|
@@ -15,59 +11,24 @@ import {
|
|
|
15
11
|
type DynamicTableSchema,
|
|
16
12
|
} from "ui-schema-contracts"
|
|
17
13
|
|
|
14
|
+
const formSchema = {
|
|
15
|
+
parse<T>(input: T): T { return input },
|
|
16
|
+
}
|
|
17
|
+
|
|
18
18
|
export const formReportsEntityName = "Feature Flag"
|
|
19
19
|
|
|
20
20
|
const formReportsFormSchemaInput = {
|
|
21
21
|
schemaVersion: FORM_SCHEMA_VERSION,
|
|
22
22
|
fields: [
|
|
23
|
-
{
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
placeholder: "my-flag",
|
|
29
|
-
description: "Unique identifier for this entity.",
|
|
30
|
-
},
|
|
31
|
-
{
|
|
32
|
-
name: "project",
|
|
33
|
-
label: "Project",
|
|
34
|
-
type: "select",
|
|
35
|
-
placeholder: "Select project",
|
|
36
|
-
options: [
|
|
37
|
-
{ label: "Website", value: "website" },
|
|
38
|
-
{ label: "Dashboard", value: "dashboard" },
|
|
39
|
-
{ label: "Mobile App", value: "mobile" },
|
|
40
|
-
],
|
|
41
|
-
},
|
|
42
|
-
{
|
|
43
|
-
name: "description",
|
|
44
|
-
label: "Description",
|
|
45
|
-
type: "textarea",
|
|
46
|
-
placeholder: "Describe what this entity controls...",
|
|
47
|
-
},
|
|
48
|
-
{
|
|
49
|
-
name: "type",
|
|
50
|
-
label: "Type",
|
|
51
|
-
type: "select",
|
|
52
|
-
defaultValue: "boolean",
|
|
53
|
-
options: [
|
|
54
|
-
{ label: "Boolean", value: "boolean" },
|
|
55
|
-
{ label: "String", value: "string" },
|
|
56
|
-
{ label: "Number", value: "number" },
|
|
57
|
-
{ label: "JSON", value: "json" },
|
|
58
|
-
],
|
|
59
|
-
},
|
|
60
|
-
{
|
|
61
|
-
name: "enabled",
|
|
62
|
-
label: "Enabled",
|
|
63
|
-
type: "boolean",
|
|
64
|
-
defaultValue: true,
|
|
65
|
-
placeholder: "Enable immediately",
|
|
66
|
-
},
|
|
23
|
+
{ name: "slug", label: "Slug", type: "text", required: true, placeholder: "my-flag", description: "Unique identifier for this entity." },
|
|
24
|
+
{ name: "project", label: "Project", type: "select", placeholder: "Select project", options: [{ label: "Website", value: "website" }, { label: "Dashboard", value: "dashboard" }, { label: "Mobile App", value: "mobile" }] },
|
|
25
|
+
{ name: "description", label: "Description", type: "textarea", placeholder: "Describe what this entity controls..." },
|
|
26
|
+
{ name: "type", label: "Type", type: "select", defaultValue: "boolean", options: [{ label: "Boolean", value: "boolean" }, { label: "String", value: "string" }, { label: "Number", value: "number" }, { label: "JSON", value: "json" }] },
|
|
27
|
+
{ name: "enabled", label: "Enabled", type: "boolean", defaultValue: true, placeholder: "Enable immediately" },
|
|
67
28
|
],
|
|
68
|
-
}
|
|
29
|
+
}
|
|
69
30
|
|
|
70
|
-
export const formReportsFields: FormReportsFieldDefinition[] = formSchema.parse(formReportsFormSchemaInput).fields
|
|
31
|
+
export const formReportsFields: FormReportsFieldDefinition[] = formSchema.parse(formReportsFormSchemaInput).fields as unknown as FormReportsFieldDefinition[]
|
|
71
32
|
|
|
72
33
|
const formReportsTableSchemaInput = {
|
|
73
34
|
schemaVersion: DYNAMIC_TABLE_SCHEMA_VERSION,
|
|
@@ -66,7 +66,7 @@ export function useRefinementPanelMock(
|
|
|
66
66
|
}, [reviewMessages, reviewFileChanges, apiDelay]);
|
|
67
67
|
|
|
68
68
|
const onSubmit = useCallback(async (message: PromptInputMessage, _event: FormEvent<HTMLFormElement>) => {
|
|
69
|
-
await handleSubmit(message.text);
|
|
69
|
+
await handleSubmit(message.text || '');
|
|
70
70
|
}, [handleSubmit]);
|
|
71
71
|
|
|
72
72
|
// Simulate approval: clear file changes and add success message
|
|
@@ -1,12 +1,24 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import {
|
|
3
|
-
FilePreviewDialog,
|
|
4
|
-
FileQueue,
|
|
5
|
-
type FileGroup,
|
|
6
|
-
type FileItem,
|
|
7
|
-
} from "@/components/composites";
|
|
2
|
+
import { FilePreviewDialog, FileQueue } from "@/components/composites";
|
|
8
3
|
import { cn } from "@/lib/utils";
|
|
9
4
|
|
|
5
|
+
interface FileItem {
|
|
6
|
+
id: string;
|
|
7
|
+
name: string;
|
|
8
|
+
path?: string;
|
|
9
|
+
icon?: string;
|
|
10
|
+
iconColor?: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
interface FileGroup {
|
|
14
|
+
id: string;
|
|
15
|
+
title: string;
|
|
16
|
+
icon?: string;
|
|
17
|
+
iconColor?: string;
|
|
18
|
+
files: FileItem[];
|
|
19
|
+
defaultOpen?: boolean;
|
|
20
|
+
}
|
|
21
|
+
|
|
10
22
|
/**
|
|
11
23
|
* SpecNavigator Feature
|
|
12
24
|
*
|
|
@@ -14,17 +26,28 @@ import { cn } from "@/lib/utils";
|
|
|
14
26
|
* Uses FileQueue block for rendering grouped file lists.
|
|
15
27
|
*/
|
|
16
28
|
|
|
17
|
-
export interface SpecNavigatorFile
|
|
18
|
-
/** Optional markdown content rendered in the preview dialog */
|
|
19
|
-
previewContent?: string;
|
|
29
|
+
export interface SpecNavigatorFile {
|
|
20
30
|
/** Optional dialog title override */
|
|
21
31
|
previewTitle?: string;
|
|
22
32
|
/** Optional dialog subtitle or path description */
|
|
23
33
|
previewDescription?: string;
|
|
34
|
+
/** Optional markdown content rendered in the preview dialog */
|
|
35
|
+
previewContent?: string;
|
|
36
|
+
/** Unique identifier */
|
|
37
|
+
id: string;
|
|
38
|
+
/** File name (shown as label) */
|
|
39
|
+
name: string;
|
|
40
|
+
/** File path prefix (shown as secondary info) */
|
|
41
|
+
path?: string;
|
|
24
42
|
}
|
|
25
43
|
|
|
26
|
-
export interface SpecNavigatorGroup
|
|
44
|
+
export interface SpecNavigatorGroup {
|
|
45
|
+
id: string;
|
|
46
|
+
title: string;
|
|
47
|
+
icon?: string;
|
|
48
|
+
iconColor?: string;
|
|
27
49
|
files: SpecNavigatorFile[];
|
|
50
|
+
defaultOpen?: boolean;
|
|
28
51
|
}
|
|
29
52
|
|
|
30
53
|
/**
|