ai-design-system 0.1.16 → 0.1.18
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/AppSidebar/AppSidebar.tsx +12 -2
- package/components/blocks/AppSidebar/interfaces.ts +3 -0
- package/components/blocks/DashboardChart/DashboardChart.tsx +182 -0
- package/components/blocks/DashboardChart/index.ts +2 -0
- package/components/blocks/DashboardHeader/DashboardHeader.tsx +20 -0
- package/components/blocks/DashboardHeader/index.ts +2 -0
- package/components/blocks/DashboardMetrics/DashboardMetrics.tsx +41 -0
- package/components/blocks/DashboardMetrics/index.ts +2 -0
- package/components/blocks/DataTable/DataTable.tsx +42 -0
- package/components/blocks/DataTable/index.ts +2 -0
- package/components/blocks/FormReportsSection/FormReportsSection.tsx +46 -0
- package/components/blocks/FormReportsSection/index.ts +2 -0
- package/components/blocks/SectionLayout/SectionLayout.tsx +2 -2
- package/components/blocks/index.ts +15 -0
- package/components/composites/AdjustableLayout/AdjustableLayout.tsx +2 -1
- package/components/composites/DataTable/DragHandleCell.tsx +25 -0
- package/components/composites/DataTable/DraggableRow.tsx +35 -0
- package/components/composites/DataTable/EnhancedDataTable.behaviors.stories.tsx +60 -0
- package/components/composites/DataTable/EnhancedDataTable.stories.tsx +42 -0
- package/components/composites/DataTable/EnhancedDataTable.tsx +616 -0
- package/components/composites/DataTable/InlineEditCell.tsx +45 -0
- package/components/composites/DataTable/ReviewerCell.tsx +43 -0
- package/components/composites/DataTable/RowDetailDrawer.tsx +172 -0
- package/components/composites/DataTable/StatusCell.tsx +19 -0
- package/components/composites/DataTable/TableSelectColumn.tsx +32 -0
- package/components/composites/DataTable/index.ts +24 -0
- package/components/composites/DataTable/table-types.ts +31 -0
- package/components/composites/DataTable/useEnhancedDataTable.ts +99 -0
- package/components/composites/FilePreviewDialog/FilePreviewDialog.tsx +150 -0
- package/components/composites/FilePreviewDialog/index.ts +2 -0
- package/components/composites/FormReports/FormReportsDrawerForm.tsx +220 -0
- package/components/composites/FormReports/FormReportsTable.tsx +181 -0
- package/components/composites/FormReports/index.ts +24 -0
- package/components/composites/StatsCard/StatsCard.tsx +2 -2
- package/components/composites/WorkflowRunObservabilityPanel/WorkflowRunObservabilityPanel.tsx +549 -0
- package/components/composites/WorkflowRunObservabilityPanel/index.ts +17 -0
- package/components/composites/index.ts +34 -0
- package/components/features/DashboardFeature/DashboardFeature.behaviors.stories.tsx +73 -0
- package/components/features/DashboardFeature/DashboardFeature.mocks.ts +302 -0
- package/components/features/DashboardFeature/DashboardFeature.stories.tsx +63 -0
- package/components/features/DashboardFeature/DashboardFeature.tsx +131 -0
- package/components/features/DashboardFeature/README.md +48 -0
- package/components/features/DashboardFeature/index.ts +11 -0
- package/components/features/DashboardFeature/useDashboardFeature.d.ts +65 -0
- package/components/features/DashboardFeature/useDashboardFeature.mock.ts +57 -0
- package/components/features/FormReportsFeature/FormReportsFeature.behaviors.stories.tsx +87 -0
- package/components/features/FormReportsFeature/FormReportsFeature.mocks.ts +182 -0
- package/components/features/FormReportsFeature/FormReportsFeature.stories.tsx +51 -0
- package/components/features/FormReportsFeature/FormReportsFeature.tsx +132 -0
- package/components/features/FormReportsFeature/README.md +43 -0
- package/components/features/FormReportsFeature/index.ts +7 -0
- package/components/features/FormReportsFeature/useFormReportsFeature.d.ts +31 -0
- package/components/features/FormReportsFeature/useFormReportsFeature.mock.ts +47 -0
- package/components/features/PageLayout/PageLayout.tsx +8 -5
- package/components/features/SpecNavigator/README.md +23 -3
- package/components/features/SpecNavigator/SpecNavigator.behaviors.stories.tsx +29 -11
- package/components/features/SpecNavigator/SpecNavigator.mocks.ts +35 -8
- package/components/features/SpecNavigator/SpecNavigator.stories.tsx +38 -36
- package/components/features/SpecNavigator/SpecNavigator.tsx +56 -3
- package/components/features/SpecNavigator/index.ts +5 -1
- package/components/features/SpecNavigator/useSpecNavigator.d.ts +2 -2
- package/components/features/SpecNavigator/useSpecNavigator.mock.ts +4 -4
- package/components/features/WorkflowBuilder/WorkflowBuilder.stories.tsx +45 -39
- package/components/features/WorkflowBuilder/WorkflowBuilder.tsx +6 -2
- package/components/features/WorkflowObservabilityFeature/README.md +114 -0
- package/components/features/WorkflowObservabilityFeature/WorkflowObservabilityFeature.behaviors.stories.tsx +177 -0
- package/components/features/WorkflowObservabilityFeature/WorkflowObservabilityFeature.mocks.ts +145 -0
- package/components/features/WorkflowObservabilityFeature/WorkflowObservabilityFeature.stories.tsx +66 -0
- package/components/features/WorkflowObservabilityFeature/WorkflowObservabilityFeature.tsx +162 -0
- package/components/features/WorkflowObservabilityFeature/index.ts +7 -0
- package/components/features/WorkflowObservabilityFeature/useWorkflowObservabilityFeature.d.ts +25 -0
- package/components/features/WorkflowObservabilityFeature/useWorkflowObservabilityFeature.mock.ts +238 -0
- package/components/features/index.ts +12 -0
- package/components/ui/chart.tsx +3 -3
- package/components/ui/drawer.tsx +6 -2
- package/components/ui/input-group.tsx +1 -1
- package/components/ui/input.tsx +1 -1
- package/dist/index.cjs +2472 -203
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +625 -16
- package/dist/index.d.ts +150 -2
- package/dist/index.js +2464 -205
- package/dist/index.js.map +1 -1
- package/package.json +11 -2
|
@@ -17,9 +17,19 @@ import { NavUser } from "@/components/composites/NavUser"
|
|
|
17
17
|
import type { AppSidebarProps } from "./interfaces"
|
|
18
18
|
|
|
19
19
|
export const AppSidebar = React.memo<AppSidebarProps>(
|
|
20
|
-
({
|
|
20
|
+
({
|
|
21
|
+
logo,
|
|
22
|
+
mainNavigation,
|
|
23
|
+
secondaryNavigation,
|
|
24
|
+
documents,
|
|
25
|
+
user,
|
|
26
|
+
userActions,
|
|
27
|
+
variant = "inset",
|
|
28
|
+
collapsible = "offcanvas",
|
|
29
|
+
...props
|
|
30
|
+
}) => {
|
|
21
31
|
return (
|
|
22
|
-
<Sidebar {...props} variant=
|
|
32
|
+
<Sidebar {...props} variant={variant} collapsible={collapsible}>
|
|
23
33
|
<SidebarHeader>
|
|
24
34
|
{logo && (
|
|
25
35
|
<SidebarMenu>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { NavigationItem } from "@/components/composites/NavigationList/interfaces";
|
|
2
|
+
import type { SidebarProps } from "@/components/primitives/Sidebar";
|
|
2
3
|
|
|
3
4
|
export interface AppSidebarProps {
|
|
4
5
|
logo?: {
|
|
@@ -14,6 +15,8 @@ export interface AppSidebarProps {
|
|
|
14
15
|
email: string;
|
|
15
16
|
avatar?: string;
|
|
16
17
|
};
|
|
18
|
+
variant?: SidebarProps["variant"];
|
|
19
|
+
collapsible?: SidebarProps["collapsible"];
|
|
17
20
|
userActions?: { label: string; onClick: () => void }[];
|
|
18
21
|
className?: string;
|
|
19
22
|
}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
import { Area, AreaChart, CartesianGrid, XAxis } from "recharts"
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
ChartContainer,
|
|
6
|
+
ChartTooltip,
|
|
7
|
+
ChartTooltipContent,
|
|
8
|
+
} from "@/components/primitives/Chart"
|
|
9
|
+
import {
|
|
10
|
+
Card,
|
|
11
|
+
CardAction,
|
|
12
|
+
CardContent,
|
|
13
|
+
CardDescription,
|
|
14
|
+
CardHeader,
|
|
15
|
+
CardTitle,
|
|
16
|
+
} from "@/components/primitives/Card"
|
|
17
|
+
import {
|
|
18
|
+
Select,
|
|
19
|
+
SelectContent,
|
|
20
|
+
SelectItem,
|
|
21
|
+
SelectTrigger,
|
|
22
|
+
SelectValue,
|
|
23
|
+
} from "@/components/primitives/Select"
|
|
24
|
+
import { ToggleGroup, ToggleGroupItem } from "@/components/primitives/ToggleGroup"
|
|
25
|
+
|
|
26
|
+
export interface DashboardChartPoint {
|
|
27
|
+
date: string
|
|
28
|
+
desktop: number
|
|
29
|
+
mobile: number
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export type DashboardChartTimeRange = "90d" | "30d" | "7d"
|
|
33
|
+
|
|
34
|
+
export interface DashboardChartProps {
|
|
35
|
+
series: DashboardChartPoint[]
|
|
36
|
+
onTimeRangeChange?: (range: DashboardChartTimeRange) => void
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export const DashboardChart = React.memo<DashboardChartProps>(({ series, onTimeRangeChange }) => {
|
|
40
|
+
const [timeRange, setTimeRange] = React.useState<DashboardChartTimeRange>("90d")
|
|
41
|
+
|
|
42
|
+
const handleTimeRangeChange = React.useCallback(
|
|
43
|
+
(range: DashboardChartTimeRange) => {
|
|
44
|
+
setTimeRange(range)
|
|
45
|
+
onTimeRangeChange?.(range)
|
|
46
|
+
},
|
|
47
|
+
[onTimeRangeChange]
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
const filteredSeries = React.useMemo(() => {
|
|
51
|
+
const referenceDate = series.length > 0 ? new Date(series[series.length - 1].date) : new Date()
|
|
52
|
+
let daysToSubtract = 90
|
|
53
|
+
|
|
54
|
+
if (timeRange === "30d") {
|
|
55
|
+
daysToSubtract = 30
|
|
56
|
+
} else if (timeRange === "7d") {
|
|
57
|
+
daysToSubtract = 7
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const startDate = new Date(referenceDate)
|
|
61
|
+
startDate.setDate(startDate.getDate() - daysToSubtract)
|
|
62
|
+
|
|
63
|
+
return series.filter((point) => new Date(point.date) >= startDate)
|
|
64
|
+
}, [series, timeRange])
|
|
65
|
+
|
|
66
|
+
return (
|
|
67
|
+
<section className="px-4 lg:px-6">
|
|
68
|
+
<Card className="@container/card">
|
|
69
|
+
<CardHeader>
|
|
70
|
+
<CardTitle>Total Visitors</CardTitle>
|
|
71
|
+
<CardDescription>
|
|
72
|
+
<span className="hidden @[540px]/card:block">Total for the last 3 months</span>
|
|
73
|
+
<span className="@[540px]/card:hidden">Last 3 months</span>
|
|
74
|
+
</CardDescription>
|
|
75
|
+
<CardAction>
|
|
76
|
+
<ToggleGroup
|
|
77
|
+
type="single"
|
|
78
|
+
value={timeRange}
|
|
79
|
+
onValueChange={(value) => {
|
|
80
|
+
if (value) {
|
|
81
|
+
handleTimeRangeChange(value as DashboardChartTimeRange)
|
|
82
|
+
}
|
|
83
|
+
}}
|
|
84
|
+
variant="outline"
|
|
85
|
+
className="hidden *:data-[slot=toggle-group-item]:px-4! @[767px]/card:flex"
|
|
86
|
+
>
|
|
87
|
+
<ToggleGroupItem value="90d">Last 3 months</ToggleGroupItem>
|
|
88
|
+
<ToggleGroupItem value="30d">Last 30 days</ToggleGroupItem>
|
|
89
|
+
<ToggleGroupItem value="7d">Last 7 days</ToggleGroupItem>
|
|
90
|
+
</ToggleGroup>
|
|
91
|
+
<Select value={timeRange} onValueChange={(value) => handleTimeRangeChange(value as DashboardChartTimeRange)}>
|
|
92
|
+
<SelectTrigger
|
|
93
|
+
className="flex w-40 **:data-[slot=select-value]:block **:data-[slot=select-value]:truncate @[767px]/card:hidden"
|
|
94
|
+
aria-label="Select a value"
|
|
95
|
+
>
|
|
96
|
+
<SelectValue placeholder="Last 3 months" />
|
|
97
|
+
</SelectTrigger>
|
|
98
|
+
<SelectContent className="rounded-xl">
|
|
99
|
+
<SelectItem value="90d" className="rounded-lg">
|
|
100
|
+
Last 3 months
|
|
101
|
+
</SelectItem>
|
|
102
|
+
<SelectItem value="30d" className="rounded-lg">
|
|
103
|
+
Last 30 days
|
|
104
|
+
</SelectItem>
|
|
105
|
+
<SelectItem value="7d" className="rounded-lg">
|
|
106
|
+
Last 7 days
|
|
107
|
+
</SelectItem>
|
|
108
|
+
</SelectContent>
|
|
109
|
+
</Select>
|
|
110
|
+
</CardAction>
|
|
111
|
+
</CardHeader>
|
|
112
|
+
<CardContent className="px-2 pt-4 sm:px-6 sm:pt-6">
|
|
113
|
+
<ChartContainer
|
|
114
|
+
config={{
|
|
115
|
+
desktop: { label: "Desktop", color: "var(--primary)" },
|
|
116
|
+
mobile: { label: "Mobile", color: "var(--primary)" },
|
|
117
|
+
}}
|
|
118
|
+
className="aspect-auto h-[250px] w-full"
|
|
119
|
+
>
|
|
120
|
+
<AreaChart data={filteredSeries}>
|
|
121
|
+
<defs>
|
|
122
|
+
<linearGradient id="fillDesktop" x1="0" y1="0" x2="0" y2="1">
|
|
123
|
+
<stop offset="5%" stopColor="var(--color-desktop)" stopOpacity={1} />
|
|
124
|
+
<stop offset="95%" stopColor="var(--color-desktop)" stopOpacity={0.1} />
|
|
125
|
+
</linearGradient>
|
|
126
|
+
<linearGradient id="fillMobile" x1="0" y1="0" x2="0" y2="1">
|
|
127
|
+
<stop offset="5%" stopColor="var(--color-mobile)" stopOpacity={0.8} />
|
|
128
|
+
<stop offset="95%" stopColor="var(--color-mobile)" stopOpacity={0.1} />
|
|
129
|
+
</linearGradient>
|
|
130
|
+
</defs>
|
|
131
|
+
<CartesianGrid vertical={false} />
|
|
132
|
+
<XAxis
|
|
133
|
+
dataKey="date"
|
|
134
|
+
tickLine={false}
|
|
135
|
+
axisLine={false}
|
|
136
|
+
tickMargin={8}
|
|
137
|
+
minTickGap={32}
|
|
138
|
+
tickFormatter={(value) => {
|
|
139
|
+
const date = new Date(value)
|
|
140
|
+
return date.toLocaleDateString("en-US", {
|
|
141
|
+
month: "short",
|
|
142
|
+
day: "numeric",
|
|
143
|
+
})
|
|
144
|
+
}}
|
|
145
|
+
/>
|
|
146
|
+
<ChartTooltip
|
|
147
|
+
cursor={false}
|
|
148
|
+
content={
|
|
149
|
+
<ChartTooltipContent
|
|
150
|
+
labelFormatter={(value) => {
|
|
151
|
+
return new Date(String(value)).toLocaleDateString("en-US", {
|
|
152
|
+
month: "short",
|
|
153
|
+
day: "numeric",
|
|
154
|
+
})
|
|
155
|
+
}}
|
|
156
|
+
indicator="dot"
|
|
157
|
+
/>
|
|
158
|
+
}
|
|
159
|
+
/>
|
|
160
|
+
<Area
|
|
161
|
+
dataKey="mobile"
|
|
162
|
+
type="natural"
|
|
163
|
+
fill="url(#fillMobile)"
|
|
164
|
+
stroke="var(--color-mobile)"
|
|
165
|
+
stackId="a"
|
|
166
|
+
/>
|
|
167
|
+
<Area
|
|
168
|
+
dataKey="desktop"
|
|
169
|
+
type="natural"
|
|
170
|
+
fill="url(#fillDesktop)"
|
|
171
|
+
stroke="var(--color-desktop)"
|
|
172
|
+
stackId="a"
|
|
173
|
+
/>
|
|
174
|
+
</AreaChart>
|
|
175
|
+
</ChartContainer>
|
|
176
|
+
</CardContent>
|
|
177
|
+
</Card>
|
|
178
|
+
</section>
|
|
179
|
+
)
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
DashboardChart.displayName = "DashboardChart"
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
|
|
3
|
+
import { Button } from "@/components/primitives/Button"
|
|
4
|
+
|
|
5
|
+
export interface DashboardHeaderProps {
|
|
6
|
+
ctaLabel?: string
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const DashboardHeader = React.memo<DashboardHeaderProps>(({ ctaLabel = "Quick Create" }) => {
|
|
10
|
+
return (
|
|
11
|
+
<>
|
|
12
|
+
<Button variant="outline" size="sm" className="hidden sm:flex">
|
|
13
|
+
{ctaLabel}
|
|
14
|
+
</Button>
|
|
15
|
+
<div className="text-xs text-muted-foreground">GitHub</div>
|
|
16
|
+
</>
|
|
17
|
+
)
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
DashboardHeader.displayName = "DashboardHeader"
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
|
|
3
|
+
import { StatsCard } from "@/components/composites/StatsCard"
|
|
4
|
+
|
|
5
|
+
export interface DashboardMetricItem {
|
|
6
|
+
title: string
|
|
7
|
+
value: string | number
|
|
8
|
+
trend?: {
|
|
9
|
+
direction: "up" | "down"
|
|
10
|
+
value: string
|
|
11
|
+
}
|
|
12
|
+
footer?: {
|
|
13
|
+
message: string
|
|
14
|
+
description: string
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface DashboardMetricsProps {
|
|
19
|
+
items: DashboardMetricItem[]
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export const DashboardMetrics = React.memo<DashboardMetricsProps>(({ items }) => {
|
|
23
|
+
return (
|
|
24
|
+
<section className="px-4 lg:px-6">
|
|
25
|
+
<div className="flex gap-4 overflow-x-auto pb-1 [scrollbar-width:thin]">
|
|
26
|
+
{items.map((item) => (
|
|
27
|
+
<StatsCard
|
|
28
|
+
key={item.title}
|
|
29
|
+
title={item.title}
|
|
30
|
+
value={item.value}
|
|
31
|
+
trend={item.trend}
|
|
32
|
+
footer={item.footer}
|
|
33
|
+
className="@container/card basis-[calc((100%-3rem)/4)] min-w-[240px] shrink-0"
|
|
34
|
+
/>
|
|
35
|
+
))}
|
|
36
|
+
</div>
|
|
37
|
+
</section>
|
|
38
|
+
)
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
DashboardMetrics.displayName = "DashboardMetrics"
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
import { Plus } from "lucide-react"
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
EnhancedDataTable,
|
|
6
|
+
type DashboardRow,
|
|
7
|
+
type DashboardTableActionHandlers,
|
|
8
|
+
} from "@/components/composites/DataTable"
|
|
9
|
+
import type { DynamicTableSchema } from "ui-schema-contracts"
|
|
10
|
+
import { Button } from "@/components/primitives/Button"
|
|
11
|
+
|
|
12
|
+
export interface DataTableProps {
|
|
13
|
+
rows: DashboardRow[]
|
|
14
|
+
tableSchema: DynamicTableSchema
|
|
15
|
+
handlers?: DashboardTableActionHandlers
|
|
16
|
+
onCreateClick?: () => void
|
|
17
|
+
createButtonLabel?: string
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const DataTable = React.memo<DataTableProps>(({ rows, tableSchema, handlers, onCreateClick, createButtonLabel }) => {
|
|
21
|
+
return (
|
|
22
|
+
<section className="px-4 lg:px-6">
|
|
23
|
+
<EnhancedDataTable
|
|
24
|
+
data={rows}
|
|
25
|
+
tableSchema={tableSchema}
|
|
26
|
+
handlers={handlers}
|
|
27
|
+
onCreateClick={onCreateClick ?? handlers?.onCreateClick ?? handlers?.onAddSection}
|
|
28
|
+
createButtonLabel={createButtonLabel}
|
|
29
|
+
rightActions={
|
|
30
|
+
handlers?.onAddSection ? (
|
|
31
|
+
<Button variant="outline" size="sm" className="h-8" onClick={handlers.onAddSection}>
|
|
32
|
+
<Plus className="size-4" />
|
|
33
|
+
<span className="hidden lg:inline">Add Section</span>
|
|
34
|
+
</Button>
|
|
35
|
+
) : null
|
|
36
|
+
}
|
|
37
|
+
/>
|
|
38
|
+
</section>
|
|
39
|
+
)
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
DataTable.displayName = "DataTable"
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
import {
|
|
3
|
+
FormReportsTable,
|
|
4
|
+
type FormReportsColumn,
|
|
5
|
+
type FormReportsEntity,
|
|
6
|
+
type FormReportsRowAction,
|
|
7
|
+
type FormReportsTableHandlers,
|
|
8
|
+
} from "@/components/composites/FormReports"
|
|
9
|
+
|
|
10
|
+
export interface FormReportsSectionProps {
|
|
11
|
+
onCreateClick?: () => void
|
|
12
|
+
createButtonLabel?: string
|
|
13
|
+
items: FormReportsEntity[]
|
|
14
|
+
columns: FormReportsColumn[]
|
|
15
|
+
rowActions?: FormReportsRowAction[]
|
|
16
|
+
tableHandlers?: FormReportsTableHandlers
|
|
17
|
+
tableLeftActions?: React.ReactNode
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const FormReportsSection = React.memo<FormReportsSectionProps>(
|
|
21
|
+
({
|
|
22
|
+
onCreateClick,
|
|
23
|
+
createButtonLabel = "Create",
|
|
24
|
+
items,
|
|
25
|
+
columns,
|
|
26
|
+
rowActions,
|
|
27
|
+
tableHandlers,
|
|
28
|
+
tableLeftActions,
|
|
29
|
+
}) => {
|
|
30
|
+
return (
|
|
31
|
+
<section>
|
|
32
|
+
<FormReportsTable
|
|
33
|
+
items={items}
|
|
34
|
+
columns={columns}
|
|
35
|
+
rowActions={rowActions}
|
|
36
|
+
handlers={tableHandlers}
|
|
37
|
+
leftActions={tableLeftActions}
|
|
38
|
+
onCreateClick={onCreateClick}
|
|
39
|
+
createButtonLabel={createButtonLabel}
|
|
40
|
+
/>
|
|
41
|
+
</section>
|
|
42
|
+
)
|
|
43
|
+
}
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
FormReportsSection.displayName = "FormReportsSection"
|
|
@@ -26,11 +26,11 @@ export const SectionLayout = React.memo<SectionLayoutProps>(
|
|
|
26
26
|
const transformedSections = sections.map(section => ({
|
|
27
27
|
...section,
|
|
28
28
|
content: (
|
|
29
|
-
<div className="h-full flex flex-col">
|
|
29
|
+
<div className="h-full min-h-0 flex flex-col">
|
|
30
30
|
{section.header && (
|
|
31
31
|
<AppHeader {...section.header} />
|
|
32
32
|
)}
|
|
33
|
-
<div className="flex-1">
|
|
33
|
+
<div className="min-h-0 flex-1">
|
|
34
34
|
{section.content}
|
|
35
35
|
</div>
|
|
36
36
|
</div>
|
|
@@ -17,3 +17,18 @@ export type { LayoutProviderProps } from './LayoutProvider'
|
|
|
17
17
|
|
|
18
18
|
export { WorkflowCanvas } from './WorkflowCanvas'
|
|
19
19
|
export type { WorkflowCanvasProps, WorkflowNode, WorkflowEdge, WorkflowNodeData } from './WorkflowCanvas'
|
|
20
|
+
|
|
21
|
+
export { DashboardHeader } from './DashboardHeader'
|
|
22
|
+
export type { DashboardHeaderProps } from './DashboardHeader'
|
|
23
|
+
|
|
24
|
+
export { DashboardMetrics } from './DashboardMetrics'
|
|
25
|
+
export type { DashboardMetricsProps } from './DashboardMetrics'
|
|
26
|
+
|
|
27
|
+
export { DashboardChart } from './DashboardChart'
|
|
28
|
+
export type { DashboardChartProps } from './DashboardChart'
|
|
29
|
+
|
|
30
|
+
export { DataTable } from './DataTable'
|
|
31
|
+
export type { DataTableProps } from './DataTable'
|
|
32
|
+
|
|
33
|
+
export { FormReportsSection } from './FormReportsSection'
|
|
34
|
+
export type { FormReportsSectionProps } from './FormReportsSection'
|
|
@@ -175,11 +175,12 @@ export const AdjustableLayout = React.memo<AdjustableLayoutProps>(
|
|
|
175
175
|
<React.Fragment key={section.id}>
|
|
176
176
|
<div
|
|
177
177
|
className={cn(
|
|
178
|
-
"h-
|
|
178
|
+
"min-h-0 overflow-hidden bg-card border border-border rounded-md",
|
|
179
179
|
section.className
|
|
180
180
|
)}
|
|
181
181
|
style={{
|
|
182
182
|
flex: `${size} 1 0%`,
|
|
183
|
+
minHeight: 0,
|
|
183
184
|
minWidth: 0,
|
|
184
185
|
}}
|
|
185
186
|
>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { useSortable } from "@dnd-kit/sortable"
|
|
2
|
+
import { GripVertical } from "lucide-react"
|
|
3
|
+
|
|
4
|
+
import { Button } from "@/components/primitives/Button"
|
|
5
|
+
|
|
6
|
+
export interface DragHandleCellProps {
|
|
7
|
+
id: number | string
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function DragHandleCell({ id }: DragHandleCellProps) {
|
|
11
|
+
const { attributes, listeners } = useSortable({ id })
|
|
12
|
+
|
|
13
|
+
return (
|
|
14
|
+
<Button
|
|
15
|
+
{...attributes}
|
|
16
|
+
{...listeners}
|
|
17
|
+
variant="ghost"
|
|
18
|
+
size="icon"
|
|
19
|
+
className="size-7 text-muted-foreground hover:bg-transparent"
|
|
20
|
+
aria-label="Drag to reorder"
|
|
21
|
+
>
|
|
22
|
+
<GripVertical className="size-3" />
|
|
23
|
+
</Button>
|
|
24
|
+
)
|
|
25
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { useSortable } from "@dnd-kit/sortable"
|
|
2
|
+
import { CSS } from "@dnd-kit/utilities"
|
|
3
|
+
import { flexRender, type Row } from "@tanstack/react-table"
|
|
4
|
+
|
|
5
|
+
import { TableCell, TableRow } from "@/components/primitives/Table"
|
|
6
|
+
import type { DashboardRow } from "./table-types"
|
|
7
|
+
|
|
8
|
+
export interface DraggableRowProps {
|
|
9
|
+
row: Row<DashboardRow>
|
|
10
|
+
rowId: number | string
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function DraggableRow({ row, rowId }: DraggableRowProps) {
|
|
14
|
+
const { transform, transition, setNodeRef, isDragging } = useSortable({
|
|
15
|
+
id: rowId,
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
<TableRow
|
|
20
|
+
ref={setNodeRef}
|
|
21
|
+
data-row-id={String(rowId)}
|
|
22
|
+
data-state={row.getIsSelected() && "selected"}
|
|
23
|
+
data-dragging={isDragging}
|
|
24
|
+
className="relative z-0 data-[dragging=true]:z-10 data-[dragging=true]:opacity-80"
|
|
25
|
+
style={{
|
|
26
|
+
transform: CSS.Transform.toString(transform),
|
|
27
|
+
transition,
|
|
28
|
+
}}
|
|
29
|
+
>
|
|
30
|
+
{row.getVisibleCells().map((cell) => (
|
|
31
|
+
<TableCell key={cell.id}>{flexRender(cell.column.columnDef.cell, cell.getContext())}</TableCell>
|
|
32
|
+
))}
|
|
33
|
+
</TableRow>
|
|
34
|
+
)
|
|
35
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/nextjs-vite"
|
|
2
|
+
import { expect, userEvent, within } from "@storybook/test"
|
|
3
|
+
import { Toaster } from "sonner"
|
|
4
|
+
|
|
5
|
+
import { EnhancedDataTable } from "./EnhancedDataTable"
|
|
6
|
+
import type { DashboardRow } from "./table-types"
|
|
7
|
+
|
|
8
|
+
const rows: DashboardRow[] = [
|
|
9
|
+
{ id: 1, header: "Cover page", type: "Cover page", status: "In Process", target: "18", limit: "5", reviewer: "Eddie Lake" },
|
|
10
|
+
{ id: 2, header: "Table of contents", type: "Table of contents", status: "Done", target: "29", limit: "24", reviewer: "Assign reviewer" },
|
|
11
|
+
{ id: 3, header: "Executive summary", type: "Narrative", status: "Done", target: "10", limit: "13", reviewer: "Assign reviewer" },
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
const meta = {
|
|
15
|
+
title: "Composites/EnhancedDataTable/Behaviors",
|
|
16
|
+
component: EnhancedDataTable,
|
|
17
|
+
tags: ["test"],
|
|
18
|
+
parameters: {
|
|
19
|
+
layout: "fullscreen",
|
|
20
|
+
},
|
|
21
|
+
render: (args) => (
|
|
22
|
+
<>
|
|
23
|
+
<EnhancedDataTable {...args} />
|
|
24
|
+
<Toaster position="bottom-right" />
|
|
25
|
+
</>
|
|
26
|
+
),
|
|
27
|
+
} satisfies Meta<typeof EnhancedDataTable>
|
|
28
|
+
|
|
29
|
+
export default meta
|
|
30
|
+
type Story = StoryObj<typeof meta>
|
|
31
|
+
|
|
32
|
+
export const SelectAllWorks: Story = {
|
|
33
|
+
args: { data: rows },
|
|
34
|
+
play: async ({ canvasElement }) => {
|
|
35
|
+
const canvas = within(canvasElement)
|
|
36
|
+
const selectAll = canvas.getByLabelText("Select all")
|
|
37
|
+
await userEvent.click(selectAll)
|
|
38
|
+
await expect(selectAll).toBeChecked()
|
|
39
|
+
},
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export const DrawerOpensFromHeader: Story = {
|
|
43
|
+
args: { data: rows },
|
|
44
|
+
play: async ({ canvasElement }) => {
|
|
45
|
+
const canvas = within(canvasElement)
|
|
46
|
+
const trigger = canvas.getByRole("button", { name: "Cover page" })
|
|
47
|
+
await userEvent.click(trigger)
|
|
48
|
+
await expect(await canvas.findByText("Showing total visitors for the last 6 months")).toBeInTheDocument()
|
|
49
|
+
},
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export const SwitchesViewTab: Story = {
|
|
53
|
+
args: { data: rows },
|
|
54
|
+
play: async ({ canvasElement }) => {
|
|
55
|
+
const canvas = within(canvasElement)
|
|
56
|
+
const tab = canvas.getByRole("tab", { name: /Past Performance/i })
|
|
57
|
+
await userEvent.click(tab)
|
|
58
|
+
await expect(canvas.getByRole("tabpanel")).toBeInTheDocument()
|
|
59
|
+
},
|
|
60
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/nextjs-vite"
|
|
2
|
+
import { Toaster } from "sonner"
|
|
3
|
+
|
|
4
|
+
import { EnhancedDataTable } from "./EnhancedDataTable"
|
|
5
|
+
import type { DashboardRow } from "./table-types"
|
|
6
|
+
|
|
7
|
+
const data: DashboardRow[] = [
|
|
8
|
+
{ id: 1, header: "Cover page", type: "Cover page", status: "In Process", target: "18", limit: "5", reviewer: "Eddie Lake" },
|
|
9
|
+
{ id: 2, header: "Table of contents", type: "Table of contents", status: "Done", target: "29", limit: "24", reviewer: "Eddie Lake" },
|
|
10
|
+
{ id: 3, header: "Executive summary", type: "Narrative", status: "Done", target: "10", limit: "13", reviewer: "Eddie Lake" },
|
|
11
|
+
{ id: 4, header: "Technical approach", type: "Narrative", status: "Done", target: "27", limit: "23", reviewer: "Jamik Tashpulatov" },
|
|
12
|
+
{ id: 5, header: "Design", type: "Narrative", status: "In Process", target: "2", limit: "16", reviewer: "Jamik Tashpulatov" },
|
|
13
|
+
{ id: 6, header: "Capabilities", type: "Narrative", status: "In Process", target: "20", limit: "8", reviewer: "Jamik Tashpulatov" },
|
|
14
|
+
{ id: 7, header: "Integration with existing systems", type: "Narrative", status: "In Process", target: "19", limit: "21", reviewer: "Assign reviewer" },
|
|
15
|
+
{ id: 8, header: "Innovation and Advantages", type: "Narrative", status: "Done", target: "25", limit: "26", reviewer: "Assign reviewer" },
|
|
16
|
+
{ id: 9, header: "Overview of EMR's Innovative Solutions", type: "Technical content", status: "Done", target: "7", limit: "23", reviewer: "Assign reviewer" },
|
|
17
|
+
{ id: 10, header: "Advanced Algorithms and Machine Learning", type: "Narrative", status: "Done", target: "30", limit: "28", reviewer: "Assign reviewer" },
|
|
18
|
+
{ id: 11, header: "Adaptive Communication Protocols", type: "Narrative", status: "Done", target: "9", limit: "31", reviewer: "Assign reviewer" },
|
|
19
|
+
{ id: 12, header: "Advantages Over Current Technologies", type: "Narrative", status: "Not Started", target: "12", limit: "0", reviewer: "Assign reviewer" },
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
const meta = {
|
|
23
|
+
title: "Composites/EnhancedDataTable",
|
|
24
|
+
component: EnhancedDataTable,
|
|
25
|
+
tags: ["autodocs"],
|
|
26
|
+
parameters: { layout: "fullscreen" },
|
|
27
|
+
render: (args) => (
|
|
28
|
+
<>
|
|
29
|
+
<EnhancedDataTable {...args} />
|
|
30
|
+
<Toaster position="bottom-right" />
|
|
31
|
+
</>
|
|
32
|
+
),
|
|
33
|
+
} satisfies Meta<typeof EnhancedDataTable>
|
|
34
|
+
|
|
35
|
+
export default meta
|
|
36
|
+
type Story = StoryObj<typeof meta>
|
|
37
|
+
|
|
38
|
+
export const Default: Story = {
|
|
39
|
+
args: {
|
|
40
|
+
data,
|
|
41
|
+
},
|
|
42
|
+
}
|