@sentry/junior-dashboard 0.263.0 → 0.265.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.
Files changed (197) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +2 -5
  3. package/dist/app.js +119 -35
  4. package/dist/client.js +148 -135
  5. package/dist/index.d.ts +0 -1
  6. package/dist/index.js +119 -35
  7. package/dist/tailwind.css +1 -1
  8. package/package.json +9 -4
  9. package/src/api/schema.ts +0 -1
  10. package/src/app.ts +5 -20
  11. package/src/client/App.tsx +29 -31
  12. package/src/client/api.ts +7 -0
  13. package/src/client/components/BottomSheet.tsx +26 -18
  14. package/src/client/components/CopyButton.tsx +83 -0
  15. package/src/client/components/DetailsPanel.tsx +133 -0
  16. package/src/client/components/Drawer.tsx +34 -33
  17. package/src/client/components/FilterBar.tsx +16 -31
  18. package/src/client/components/Metric.tsx +33 -23
  19. package/src/client/components/PageContentSkeleton.tsx +1 -1
  20. package/src/client/components/Pagination.tsx +1 -1
  21. package/src/client/components/ParticipantAvatarStack.tsx +40 -36
  22. package/src/client/components/ProfileMenu.tsx +27 -93
  23. package/src/client/components/README.md +101 -64
  24. package/src/client/components/SegmentedNav.tsx +1 -1
  25. package/src/client/components/ShimmerText.tsx +2 -6
  26. package/src/client/components/ThemeSwitcher.tsx +19 -15
  27. package/src/client/components/charts/ActivityChart.tsx +173 -288
  28. package/src/client/components/charts/CacheWrites.tsx +63 -50
  29. package/src/client/components/charts/InputCacheChart.tsx +137 -131
  30. package/src/client/components/charts/README.md +4 -4
  31. package/src/client/components/charts/SystemMetricCharts.tsx +68 -95
  32. package/src/client/components/charts/WorkspaceUsageChart.tsx +42 -62
  33. package/src/client/components/controls/DirectorySortSelect.tsx +3 -3
  34. package/src/client/components/controls/TimeRangeSelector.tsx +10 -15
  35. package/src/client/components/layout/DashboardHeader.tsx +44 -90
  36. package/src/client/components/layout/SecondaryNavigation.tsx +2 -1
  37. package/src/client/components/layout/VisualViewportShell.tsx +2 -2
  38. package/src/client/components/ui/accordion.tsx +77 -0
  39. package/src/client/components/ui/alert-dialog.tsx +89 -0
  40. package/src/client/components/ui/button.tsx +85 -0
  41. package/src/client/components/ui/chart.tsx +74 -0
  42. package/src/client/components/ui/checkbox.tsx +26 -0
  43. package/src/client/components/ui/collapsible.tsx +22 -0
  44. package/src/client/components/ui/field.tsx +49 -0
  45. package/src/client/components/ui/input.tsx +35 -0
  46. package/src/client/components/ui/native-select.tsx +57 -0
  47. package/src/client/components/ui/popover.tsx +67 -0
  48. package/src/client/components/ui/radio-group.tsx +32 -0
  49. package/src/client/components/ui/sheet.tsx +151 -0
  50. package/src/client/components/ui/skeleton.tsx +19 -0
  51. package/src/client/components/ui/table.tsx +80 -0
  52. package/src/client/components/ui/tabs.tsx +75 -0
  53. package/src/client/components/ui/textarea.tsx +17 -0
  54. package/src/client/components/ui/toast.tsx +215 -0
  55. package/src/client/components/ui/toggle-group.tsx +36 -0
  56. package/src/client/components/ui/toggle.tsx +37 -0
  57. package/src/client/components/ui/tooltip.tsx +168 -0
  58. package/src/client/components/ui/trace.tsx +96 -0
  59. package/src/client/components/ui/useSheet.ts +74 -0
  60. package/src/client/conversations/ChatLayout.tsx +7 -3
  61. package/src/client/conversations/ConversationBrief.tsx +17 -6
  62. package/src/client/conversations/ConversationChildAgents.tsx +87 -58
  63. package/src/client/conversations/ConversationComposer.tsx +26 -12
  64. package/src/client/conversations/ConversationDetails.tsx +198 -95
  65. package/src/client/conversations/ConversationEventDetails.tsx +141 -0
  66. package/src/client/conversations/ConversationEventLog.tsx +150 -129
  67. package/src/client/conversations/ConversationHeader.tsx +8 -3
  68. package/src/client/conversations/ConversationHeaderActions.tsx +90 -82
  69. package/src/client/conversations/ConversationHomeList.tsx +1 -1
  70. package/src/client/conversations/ConversationLinkedWork.tsx +118 -0
  71. package/src/client/conversations/ConversationMeta.tsx +111 -92
  72. package/src/client/conversations/ConversationPage.tsx +241 -110
  73. package/src/client/conversations/ConversationSidebar.tsx +48 -29
  74. package/src/client/conversations/ConversationUsageBreakdown.tsx +16 -3
  75. package/src/client/conversations/ConversationWatches.tsx +165 -0
  76. package/src/client/conversations/ConversationWorkspace.tsx +12 -22
  77. package/src/client/conversations/ConversationWorkspaceLoading.tsx +1 -1
  78. package/src/client/conversations/DetailsList.tsx +124 -0
  79. package/src/client/conversations/EventDetails.tsx +42 -8
  80. package/src/client/conversations/ForkConversationButton.tsx +27 -16
  81. package/src/client/conversations/ObjectCard.tsx +20 -8
  82. package/src/client/conversations/PendingMailboxStack.tsx +52 -33
  83. package/src/client/conversations/README.md +93 -19
  84. package/src/client/conversations/ShareConversationButton.tsx +28 -3
  85. package/src/client/conversations/SubagentTranscriptDrawer.tsx +21 -15
  86. package/src/client/conversations/ToolFrame.tsx +36 -52
  87. package/src/client/conversations/TranscriptActivityGroup.tsx +13 -4
  88. package/src/client/conversations/TranscriptAutomationTriggerView.tsx +5 -4
  89. package/src/client/conversations/TranscriptContextEventView.tsx +25 -11
  90. package/src/client/conversations/TranscriptHeadingRow.tsx +7 -7
  91. package/src/client/conversations/TranscriptLoading.tsx +1 -1
  92. package/src/client/conversations/TranscriptMarkdown.tsx +25 -20
  93. package/src/client/conversations/TranscriptMessageContextView.tsx +8 -2
  94. package/src/client/conversations/TranscriptMessageView.tsx +6 -1
  95. package/src/client/conversations/TranscriptReasoningView.tsx +54 -68
  96. package/src/client/conversations/TranscriptSubagentView.tsx +3 -3
  97. package/src/client/conversations/TranscriptTimestamp.tsx +9 -7
  98. package/src/client/conversations/TranscriptToolView.tsx +1 -1
  99. package/src/client/conversations/TranscriptTurnContextView.tsx +99 -27
  100. package/src/client/conversations/TranscriptView.tsx +63 -27
  101. package/src/client/conversations/eventLog.ts +57 -0
  102. package/src/client/conversations/eventTime.ts +60 -0
  103. package/src/client/conversations/queries.ts +29 -0
  104. package/src/client/conversations/transcriptBottomPinning.ts +34 -0
  105. package/src/client/format.ts +5 -0
  106. package/src/client/lib/utils.ts +1 -0
  107. package/src/client/pages/ConnectionsPage.tsx +2 -2
  108. package/src/client/pages/PersonalTokensPage.tsx +4 -4
  109. package/src/client/pages/SettingsPage.tsx +9 -10
  110. package/src/client/pages/admin/ServiceAccountsSection.tsx +2 -2
  111. package/src/client/pages/automations/AutomationCostChart.tsx +50 -71
  112. package/src/client/pages/automations/AutomationDeleteDialog.tsx +87 -0
  113. package/src/client/pages/automations/AutomationDetails.tsx +193 -0
  114. package/src/client/pages/automations/AutomationEditPage.tsx +7 -8
  115. package/src/client/pages/automations/AutomationEditor.tsx +41 -29
  116. package/src/client/pages/automations/AutomationEditorLoading.tsx +1 -1
  117. package/src/client/pages/automations/AutomationEventFields.tsx +202 -119
  118. package/src/client/pages/automations/AutomationExecutionChart.tsx +51 -64
  119. package/src/client/pages/automations/AutomationExecutionStatusChart.tsx +47 -70
  120. package/src/client/pages/automations/AutomationExecutionsPage.tsx +150 -126
  121. package/src/client/pages/automations/AutomationFilters.tsx +189 -74
  122. package/src/client/pages/automations/AutomationLifecycle.tsx +109 -78
  123. package/src/client/pages/automations/AutomationOutcomeFields.tsx +26 -24
  124. package/src/client/pages/automations/AutomationRecentRuns.tsx +143 -0
  125. package/src/client/pages/automations/AutomationRow.tsx +12 -138
  126. package/src/client/pages/automations/AutomationRunDetails.tsx +307 -0
  127. package/src/client/pages/automations/AutomationRunsPage.tsx +119 -94
  128. package/src/client/pages/automations/AutomationScheduleFields.tsx +51 -51
  129. package/src/client/pages/automations/AutomationStatus.tsx +201 -0
  130. package/src/client/pages/automations/AutomationVersionsPage.tsx +65 -28
  131. package/src/client/pages/automations/AutomationsPage.tsx +80 -68
  132. package/src/client/pages/automations/AutomationsPageLayout.tsx +46 -14
  133. package/src/client/pages/automations/README.md +57 -0
  134. package/src/client/pages/automations/TriggerFilters.tsx +22 -0
  135. package/src/client/pages/automations/automationFormat.ts +37 -23
  136. package/src/client/pages/code/CodeActivityChart.tsx +59 -101
  137. package/src/client/pages/code/CodePage.tsx +52 -55
  138. package/src/client/pages/code/RepositoryPage.tsx +6 -8
  139. package/src/client/pages/locations/LocationActivityChart.tsx +53 -70
  140. package/src/client/pages/locations/LocationDirectoryActivityChart.tsx +60 -80
  141. package/src/client/pages/memory/MemoryCostChart.tsx +79 -103
  142. package/src/client/pages/memory/MemoryDetails.tsx +218 -0
  143. package/src/client/pages/memory/MemoryPage.tsx +168 -112
  144. package/src/client/pages/memory/MemoryPageLayout.tsx +33 -9
  145. package/src/client/pages/memory/MemoryTimeline.tsx +46 -69
  146. package/src/client/pages/memory/memoryRecord.ts +1 -1
  147. package/src/client/pages/people/ContributionGrid.tsx +23 -16
  148. package/src/client/pages/people/PeopleActivityChart.tsx +68 -107
  149. package/src/client/pages/people/ProfileCodeChanges.tsx +5 -5
  150. package/src/client/pages/system/BaseSandboxCard.tsx +1 -1
  151. package/src/client/pages/system/ConversationActivityChart.tsx +49 -67
  152. package/src/client/pages/system/GuardianActivity.tsx +1 -2
  153. package/src/client/pages/system/PluginBarChart.tsx +106 -87
  154. package/src/client/pages/system/PluginReportRecordSet.tsx +25 -24
  155. package/src/client/pages/system/README.md +23 -0
  156. package/src/client/pages/system/SystemNavigation.tsx +5 -1
  157. package/src/client/pages/system/WorkspaceDeleteDialog.tsx +111 -0
  158. package/src/client/pages/system/WorkspaceDetails.tsx +200 -43
  159. package/src/client/pages/system/WorkspaceEditor.tsx +59 -61
  160. package/src/client/pages/system/WorkspaceFormPage.tsx +23 -47
  161. package/src/client/pages/system/WorkspaceList.tsx +20 -30
  162. package/src/client/pages/system/WorkspacesPage.tsx +117 -119
  163. package/src/client/pages/system/sandboxSize.ts +8 -0
  164. package/src/client/pages/system/workspaceQueries.ts +53 -0
  165. package/src/client/pages/user/PluginUserPage.tsx +51 -2
  166. package/src/client/pages/user/pluginUserPageData.ts +1 -6
  167. package/src/client/styles.ts +4 -0
  168. package/src/client.tsx +7 -1
  169. package/src/mock-reporting/automation-collection.ts +4 -2
  170. package/src/mock-reporting/fixtures.ts +23 -7
  171. package/src/mock-reporting/routes.ts +12 -0
  172. package/src/mock-reporting/watches.ts +94 -0
  173. package/src/shell.ts +4 -9
  174. package/src/tailwind.css +77 -10
  175. package/src/client/components/Button.tsx +0 -118
  176. package/src/client/components/Field.tsx +0 -53
  177. package/src/client/components/SegmentedTabs.tsx +0 -119
  178. package/src/client/components/Select.tsx +0 -52
  179. package/src/client/components/Sheet.LICENSE +0 -21
  180. package/src/client/components/Sheet.tsx +0 -141
  181. package/src/client/components/Skeleton.tsx +0 -17
  182. package/src/client/components/TextInput.tsx +0 -58
  183. package/src/client/components/Tooltip.tsx +0 -216
  184. package/src/client/components/charts/useChartLayout.ts +0 -27
  185. package/src/client/conversations/ConversationDetailsFrame.tsx +0 -91
  186. package/src/client/conversations/CopyMarkdownButton.tsx +0 -65
  187. package/src/client/pages/automations/AutomationDetailsDrawer.tsx +0 -219
  188. package/src/client/pages/dev/ChartFixtures.tsx +0 -325
  189. package/src/client/pages/dev/ComponentsPage.tsx +0 -899
  190. package/src/client/pages/dev/ConversationFixture.tsx +0 -231
  191. package/src/client/pages/dev/ObjectFixtures.tsx +0 -138
  192. package/src/client/pages/dev/SegmentedFixtures.tsx +0 -59
  193. package/src/client/pages/dev/SelectFixtures.tsx +0 -62
  194. package/src/client/pages/dev/TranscriptActivityFixtures.tsx +0 -206
  195. package/src/client/pages/memory/MemoryDetailsDrawer.tsx +0 -167
  196. package/src/client/pages/system/SandboxSizeSummary.tsx +0 -47
  197. package/src/client/pages/system/SnapshotSummary.tsx +0 -78
@@ -0,0 +1,151 @@
1
+ import * as React from "react";
2
+ import { Dialog as SheetPrimitive } from "@base-ui/react/dialog";
3
+ import { cn } from "@dashboard/lib/utils";
4
+
5
+ import { Button } from "./button";
6
+ import { XIcon } from "lucide-react";
7
+
8
+ /** Own the open state and modal focus rules for a shadcn sheet. */
9
+ function Sheet({ ...props }: SheetPrimitive.Root.Props) {
10
+ return <SheetPrimitive.Root data-slot="sheet" {...props} />;
11
+ }
12
+
13
+ /** Open the sheet from a button and restore focus when it closes. */
14
+ function SheetTrigger({ ...props }: SheetPrimitive.Trigger.Props) {
15
+ return <SheetPrimitive.Trigger data-slot="sheet-trigger" {...props} />;
16
+ }
17
+
18
+ /** Close the sheet through Base UI dismissal and focus handling. */
19
+ function SheetClose({ ...props }: SheetPrimitive.Close.Props) {
20
+ return <SheetPrimitive.Close data-slot="sheet-close" {...props} />;
21
+ }
22
+
23
+ function SheetPortal({ ...props }: SheetPrimitive.Portal.Props) {
24
+ return <SheetPrimitive.Portal data-slot="sheet-portal" {...props} />;
25
+ }
26
+
27
+ function SheetOverlay({ className, ...props }: SheetPrimitive.Backdrop.Props) {
28
+ return (
29
+ <SheetPrimitive.Backdrop
30
+ data-slot="sheet-overlay"
31
+ className={cn(
32
+ "fixed inset-0 z-50 bg-dashboard-overlay transition-opacity duration-180 motion-reduce:transition-none data-ending-style:opacity-0 data-starting-style:opacity-0",
33
+ className,
34
+ )}
35
+ {...props}
36
+ />
37
+ );
38
+ }
39
+
40
+ /** Place the sheet on one edge with themed chrome and a close control. */
41
+ function SheetContent({
42
+ className,
43
+ children,
44
+ side = "right",
45
+ showCloseButton = true,
46
+ closeButtonProps,
47
+ ...props
48
+ }: SheetPrimitive.Popup.Props & {
49
+ side?: "top" | "right" | "bottom" | "left";
50
+ showCloseButton?: boolean;
51
+ closeButtonProps?: React.ComponentProps<typeof Button>;
52
+ }) {
53
+ // Keep portal order tied to the app tree when a resize mounts another sheet.
54
+ const portalRef = React.useRef<HTMLDivElement>(null);
55
+ return (
56
+ <>
57
+ <div ref={portalRef} className="contents" />
58
+ <SheetPortal container={portalRef}>
59
+ <SheetOverlay />
60
+ <SheetPrimitive.Popup
61
+ data-slot="sheet-content"
62
+ data-dashboard-modal=""
63
+ data-side={side}
64
+ className={cn(
65
+ "fixed z-50 flex flex-col gap-4 border-dashboard-border-strong bg-popover bg-clip-padding text-sm text-popover-foreground shadow-lg transition-[opacity,transform] duration-180 ease-[cubic-bezier(0.2,0.8,0.2,1)] motion-reduce:transition-none data-ending-style:opacity-0 data-starting-style:opacity-0 data-[side=bottom]:inset-x-0 data-[side=bottom]:bottom-0 data-[side=bottom]:h-auto data-[side=bottom]:border-t data-[side=bottom]:data-ending-style:translate-y-[2.5rem] data-[side=bottom]:data-starting-style:translate-y-[2.5rem] data-[side=left]:inset-y-0 data-[side=left]:left-0 data-[side=left]:h-full data-[side=left]:w-3/4 data-[side=left]:border-r data-[side=left]:data-ending-style:translate-x-[-2.5rem] data-[side=left]:data-starting-style:translate-x-[-2.5rem] data-[side=right]:inset-y-0 data-[side=right]:right-0 data-[side=right]:h-full data-[side=right]:w-3/4 data-[side=right]:border-l data-[side=right]:data-ending-style:translate-x-[2.5rem] data-[side=right]:data-starting-style:translate-x-[2.5rem] data-[side=top]:inset-x-0 data-[side=top]:top-0 data-[side=top]:h-auto data-[side=top]:border-b data-[side=top]:data-ending-style:translate-y-[-2.5rem] data-[side=top]:data-starting-style:translate-y-[-2.5rem] data-[side=left]:sm:max-w-sm data-[side=right]:sm:max-w-sm",
66
+ className,
67
+ )}
68
+ {...props}
69
+ >
70
+ {children}
71
+ {showCloseButton && (
72
+ <SheetPrimitive.Close
73
+ data-slot="sheet-close"
74
+ render={
75
+ <Button
76
+ {...closeButtonProps}
77
+ className={cn(
78
+ "absolute top-3 right-3",
79
+ closeButtonProps?.className,
80
+ )}
81
+ size="icon"
82
+ />
83
+ }
84
+ >
85
+ <XIcon aria-hidden="true" size={15} strokeWidth={2.25} />
86
+ <span className="sr-only">Close</span>
87
+ </SheetPrimitive.Close>
88
+ )}
89
+ </SheetPrimitive.Popup>
90
+ </SheetPortal>
91
+ </>
92
+ );
93
+ }
94
+
95
+ /** Group the sheet title and description clear of the close control. */
96
+ function SheetHeader({ className, ...props }: React.ComponentProps<"div">) {
97
+ return (
98
+ <div
99
+ data-slot="sheet-header"
100
+ className={cn("flex flex-col gap-1 p-4 pr-14", className)}
101
+ {...props}
102
+ />
103
+ );
104
+ }
105
+
106
+ /** Keep sheet actions at the bottom of the content. */
107
+ function SheetFooter({ className, ...props }: React.ComponentProps<"div">) {
108
+ return (
109
+ <div
110
+ data-slot="sheet-footer"
111
+ className={cn("mt-auto flex flex-col gap-2 p-4", className)}
112
+ {...props}
113
+ />
114
+ );
115
+ }
116
+
117
+ /** Give the sheet its accessible name. */
118
+ function SheetTitle({ className, ...props }: SheetPrimitive.Title.Props) {
119
+ return (
120
+ <SheetPrimitive.Title
121
+ data-slot="sheet-title"
122
+ className={cn("text-lg font-semibold text-foreground", className)}
123
+ {...props}
124
+ />
125
+ );
126
+ }
127
+
128
+ /** Describe the sheet for assistive technology. */
129
+ function SheetDescription({
130
+ className,
131
+ ...props
132
+ }: SheetPrimitive.Description.Props) {
133
+ return (
134
+ <SheetPrimitive.Description
135
+ data-slot="sheet-description"
136
+ className={cn("text-sm text-muted-foreground", className)}
137
+ {...props}
138
+ />
139
+ );
140
+ }
141
+
142
+ export {
143
+ Sheet,
144
+ SheetTrigger,
145
+ SheetClose,
146
+ SheetContent,
147
+ SheetHeader,
148
+ SheetFooter,
149
+ SheetTitle,
150
+ SheetDescription,
151
+ };
@@ -0,0 +1,19 @@
1
+ import type { ComponentProps } from "react";
2
+ import { cn } from "@dashboard/lib/utils";
3
+
4
+ /** Hide one content placeholder from assistive technology. */
5
+ function Skeleton({ className, ...props }: ComponentProps<"div">) {
6
+ return (
7
+ <div
8
+ aria-hidden="true"
9
+ data-slot="skeleton"
10
+ className={cn(
11
+ "animate-pulse rounded-md bg-dashboard-fill-soft motion-reduce:animate-none",
12
+ className,
13
+ )}
14
+ {...props}
15
+ />
16
+ );
17
+ }
18
+
19
+ export { Skeleton };
@@ -0,0 +1,80 @@
1
+ import type { ComponentProps } from "react";
2
+ import { cn } from "@dashboard/lib/utils";
3
+
4
+ /** Render a data table that scrolls sideways when it is wider than its box. */
5
+ function Table({ className, ...props }: ComponentProps<"table">) {
6
+ return (
7
+ <div
8
+ data-slot="table-container"
9
+ className="relative w-full overflow-x-auto"
10
+ >
11
+ <table
12
+ data-slot="table"
13
+ className={cn("w-full border-collapse text-left text-sm", className)}
14
+ {...props}
15
+ />
16
+ </div>
17
+ );
18
+ }
19
+
20
+ function TableHeader({ className, ...props }: ComponentProps<"thead">) {
21
+ return (
22
+ <thead
23
+ data-slot="table-header"
24
+ className={cn("[&_tr]:hover:bg-transparent", className)}
25
+ {...props}
26
+ />
27
+ );
28
+ }
29
+
30
+ function TableBody({ className, ...props }: ComponentProps<"tbody">) {
31
+ return (
32
+ <tbody
33
+ data-slot="table-body"
34
+ className={cn("[&_tr:last-child]:border-0", className)}
35
+ {...props}
36
+ />
37
+ );
38
+ }
39
+
40
+ function TableRow({ className, ...props }: ComponentProps<"tr">) {
41
+ return (
42
+ <tr
43
+ data-slot="table-row"
44
+ className={cn(
45
+ "border-b border-dashboard-border-subtle transition-colors hover:bg-dashboard-fill-soft has-aria-expanded:bg-dashboard-fill-soft data-[state=selected]:bg-dashboard-surface-active",
46
+ className,
47
+ )}
48
+ {...props}
49
+ />
50
+ );
51
+ }
52
+
53
+ /** Render a column header in the dashboard label style. */
54
+ function TableHead({ className, ...props }: ComponentProps<"th">) {
55
+ return (
56
+ <th
57
+ data-slot="table-head"
58
+ className={cn(
59
+ "px-2 py-2.5 text-left align-middle font-sans text-xs font-medium whitespace-nowrap text-dashboard-text-muted [&:has([role=checkbox])]:pr-0",
60
+ className,
61
+ )}
62
+ {...props}
63
+ />
64
+ );
65
+ }
66
+
67
+ function TableCell({ className, ...props }: ComponentProps<"td">) {
68
+ return (
69
+ <td
70
+ data-slot="table-cell"
71
+ className={cn(
72
+ "p-2 align-middle whitespace-nowrap text-dashboard-text [&:has([role=checkbox])]:pr-0",
73
+ className,
74
+ )}
75
+ {...props}
76
+ />
77
+ );
78
+ }
79
+
80
+ export { Table, TableHeader, TableBody, TableHead, TableRow, TableCell };
@@ -0,0 +1,75 @@
1
+ import { Tabs as TabsPrimitive } from "@base-ui/react/tabs";
2
+ import { cva, type VariantProps } from "class-variance-authority";
3
+ import { cn } from "@dashboard/lib/utils";
4
+
5
+ /** Own the selected panel and link each tab to its panel. */
6
+ function Tabs({ className, ...props }: TabsPrimitive.Root.Props) {
7
+ return (
8
+ <TabsPrimitive.Root
9
+ data-slot="tabs"
10
+ className={cn("grid min-w-0 gap-4", className)}
11
+ {...props}
12
+ />
13
+ );
14
+ }
15
+
16
+ const tabsListVariants = cva("group/tabs-list flex min-w-0", {
17
+ variants: {
18
+ variant: {
19
+ /** A pill track. Tabs share the row equally on wide screens. */
20
+ default:
21
+ "gap-1 rounded-lg border border-dashboard-border bg-dashboard-surface-panel p-1",
22
+ /** Underlined tabs on a bottom border, for collection filters. */
23
+ line: "gap-1 border-b border-dashboard-border-subtle",
24
+ },
25
+ },
26
+ defaultVariants: { variant: "default" },
27
+ });
28
+
29
+ /** Hold the tabs. `variant` sets the look of the row and its tabs. */
30
+ function TabsList({
31
+ className,
32
+ variant = "default",
33
+ ...props
34
+ }: TabsPrimitive.List.Props & VariantProps<typeof tabsListVariants>) {
35
+ return (
36
+ <TabsPrimitive.List
37
+ data-slot="tabs-list"
38
+ data-variant={variant}
39
+ className={cn(tabsListVariants({ variant }), className)}
40
+ {...props}
41
+ />
42
+ );
43
+ }
44
+
45
+ /** Select one panel. The active tab uses the strong fill or the accent line. */
46
+ function TabsTrigger({ className, ...props }: TabsPrimitive.Tab.Props) {
47
+ return (
48
+ <TabsPrimitive.Tab
49
+ data-slot="tabs-trigger"
50
+ className={cn(
51
+ "inline-flex min-w-0 cursor-pointer items-center gap-1.5 border-0 bg-transparent font-sans text-xs font-medium text-dashboard-text-muted transition-colors hover:text-dashboard-text focus-visible:outline focus-visible:outline-2 focus-visible:outline-dashboard-focus",
52
+ "group-data-[variant=default]/tabs-list:min-h-9 group-data-[variant=default]/tabs-list:flex-auto group-data-[variant=default]/tabs-list:justify-center group-data-[variant=default]/tabs-list:rounded-md group-data-[variant=default]/tabs-list:px-1.5 group-data-[variant=default]/tabs-list:py-2 group-data-[variant=default]/tabs-list:hover:bg-dashboard-fill-faint group-data-[variant=default]/tabs-list:data-active:bg-dashboard-fill-strong group-data-[variant=default]/tabs-list:data-active:text-dashboard-text group-data-[variant=default]/tabs-list:sm:flex-1",
53
+ "group-data-[variant=line]/tabs-list:relative group-data-[variant=line]/tabs-list:gap-2 group-data-[variant=line]/tabs-list:px-3 group-data-[variant=line]/tabs-list:py-2.5 group-data-[variant=line]/tabs-list:after:absolute group-data-[variant=line]/tabs-list:after:inset-x-2 group-data-[variant=line]/tabs-list:after:bottom-0 group-data-[variant=line]/tabs-list:after:h-px group-data-[variant=line]/tabs-list:data-active:text-dashboard-accent-text group-data-[variant=line]/tabs-list:data-active:after:bg-dashboard-accent",
54
+ className,
55
+ )}
56
+ {...props}
57
+ />
58
+ );
59
+ }
60
+
61
+ /** Show the content for the selected tab. */
62
+ function TabsContent({ className, ...props }: TabsPrimitive.Panel.Props) {
63
+ return (
64
+ <TabsPrimitive.Panel
65
+ data-slot="tabs-content"
66
+ className={cn(
67
+ "min-w-0 rounded-md focus-visible:outline focus-visible:outline-2 focus-visible:outline-dashboard-focus",
68
+ className,
69
+ )}
70
+ {...props}
71
+ />
72
+ );
73
+ }
74
+
75
+ export { Tabs, TabsList, TabsTrigger, TabsContent };
@@ -0,0 +1,17 @@
1
+ import type { ComponentProps } from "react";
2
+ import { cn } from "@dashboard/lib/utils";
3
+
4
+ import { textControlClass } from "./input";
5
+
6
+ /** Render a text area with the dashboard text control surface. */
7
+ function Textarea({ className, ...props }: ComponentProps<"textarea">) {
8
+ return (
9
+ <textarea
10
+ data-slot="textarea"
11
+ className={cn(textControlClass, "min-h-36", className)}
12
+ {...props}
13
+ />
14
+ );
15
+ }
16
+
17
+ export { Textarea };
@@ -0,0 +1,215 @@
1
+ import * as React from "react";
2
+ import { Toast as ToastPrimitive } from "@base-ui/react/toast";
3
+ import { cn } from "@dashboard/lib/utils";
4
+
5
+ import { Button } from "./button";
6
+ import {
7
+ XIcon,
8
+ CircleCheckIcon,
9
+ InfoIcon,
10
+ TriangleAlertIcon,
11
+ OctagonXIcon,
12
+ Loader2Icon,
13
+ } from "lucide-react";
14
+
15
+ function ToastProvider({ ...props }: ToastPrimitive.Provider.Props) {
16
+ return <ToastPrimitive.Provider {...props} />;
17
+ }
18
+
19
+ function ToastPortal({ ...props }: ToastPrimitive.Portal.Props) {
20
+ return <ToastPrimitive.Portal data-slot="toast-portal" {...props} />;
21
+ }
22
+
23
+ function ToastViewport({ className, ...props }: ToastPrimitive.Viewport.Props) {
24
+ return (
25
+ <ToastPrimitive.Viewport
26
+ data-slot="toast-viewport"
27
+ className={cn(
28
+ "pointer-events-none fixed inset-x-4 bottom-[max(5.25rem,env(safe-area-inset-bottom))] z-[60] mx-auto w-auto max-w-sm outline-none sm:right-4 sm:left-auto sm:mx-0 sm:w-full",
29
+ className,
30
+ )}
31
+ {...props}
32
+ />
33
+ );
34
+ }
35
+
36
+ function Toast({ className, ...props }: ToastPrimitive.Root.Props) {
37
+ return (
38
+ <ToastPrimitive.Root
39
+ data-slot="toast"
40
+ className={cn(
41
+ "group/toast pointer-events-auto absolute right-0 bottom-0 z-[calc(1000-var(--toast-index))] w-full origin-bottom rounded-lg border border-dashboard-border-emphasis bg-dashboard-surface-raised text-dashboard-text shadow-lg will-change-transform outline-none select-none focus-visible:outline-2 focus-visible:outline-dashboard-focus",
42
+ "[--gap:0.75rem] [--height:var(--toast-frontmost-height,var(--toast-height))] [--offset-y:calc(var(--toast-offset-y)*-1+calc(var(--toast-index)*var(--gap)*-1)+var(--toast-swipe-movement-y))] [--peek:0.75rem] [--scale:calc(max(0,1-(var(--toast-index)*0.1)))] [--shrink:calc(1-var(--scale))]",
43
+ "h-(--height) [transform:translateX(var(--toast-swipe-movement-x))_translateY(calc(var(--toast-swipe-movement-y)-(var(--toast-index)*var(--peek))-(var(--shrink)*var(--height))))_scale(var(--scale))] [transition:transform_180ms_ease-out,opacity_180ms,height_180ms] motion-reduce:transition-none",
44
+ "after:absolute after:top-full after:left-0 after:h-[calc(var(--gap)+1px)] after:w-full after:content-['']",
45
+ "data-expanded:h-(--toast-height) data-expanded:[transform:translateX(var(--toast-swipe-movement-x))_translateY(var(--offset-y))]",
46
+ "data-limited:opacity-0 data-starting-style:[transform:translateY(150%)]",
47
+ "[&[data-ending-style]:not([data-limited]):not([data-swipe-direction])]:[transform:translateY(150%)]",
48
+ "data-ending-style:data-[swipe-direction=down]:[transform:translateY(calc(var(--toast-swipe-movement-y)+150%))]",
49
+ "data-ending-style:data-[swipe-direction=left]:[transform:translateX(calc(var(--toast-swipe-movement-x)-150%))_translateY(var(--offset-y))]",
50
+ "data-ending-style:data-[swipe-direction=right]:[transform:translateX(calc(var(--toast-swipe-movement-x)+150%))_translateY(var(--offset-y))]",
51
+ "data-ending-style:data-[swipe-direction=up]:[transform:translateY(calc(var(--toast-swipe-movement-y)-150%))]",
52
+ "data-expanded:data-ending-style:data-[swipe-direction=down]:[transform:translateY(calc(var(--toast-swipe-movement-y)+150%))]",
53
+ "data-expanded:data-ending-style:data-[swipe-direction=left]:[transform:translateX(calc(var(--toast-swipe-movement-x)-150%))_translateY(var(--offset-y))]",
54
+ "data-expanded:data-ending-style:data-[swipe-direction=right]:[transform:translateX(calc(var(--toast-swipe-movement-x)+150%))_translateY(var(--offset-y))]",
55
+ "data-expanded:data-ending-style:data-[swipe-direction=up]:[transform:translateY(calc(var(--toast-swipe-movement-y)-150%))]",
56
+ className,
57
+ )}
58
+ {...props}
59
+ />
60
+ );
61
+ }
62
+
63
+ function ToastContent({ className, ...props }: ToastPrimitive.Content.Props) {
64
+ return (
65
+ <ToastPrimitive.Content
66
+ data-slot="toast-content"
67
+ className={cn(
68
+ "flex h-full items-center gap-3 overflow-hidden p-4 transition-opacity duration-180 motion-reduce:transition-none ease-[cubic-bezier(0.22,1,0.36,1)] data-behind:opacity-0 data-expanded:opacity-100",
69
+ className,
70
+ )}
71
+ {...props}
72
+ />
73
+ );
74
+ }
75
+
76
+ function ToastTitle({ className, ...props }: ToastPrimitive.Title.Props) {
77
+ return (
78
+ <ToastPrimitive.Title
79
+ data-slot="toast-title"
80
+ className={cn("break-words text-sm font-medium", className)}
81
+ {...props}
82
+ />
83
+ );
84
+ }
85
+
86
+ function ToastDescription({
87
+ className,
88
+ ...props
89
+ }: ToastPrimitive.Description.Props) {
90
+ return (
91
+ <ToastPrimitive.Description
92
+ data-slot="toast-description"
93
+ className={cn("break-words text-sm text-dashboard-text-muted", className)}
94
+ {...props}
95
+ />
96
+ );
97
+ }
98
+
99
+ function ToastAction({
100
+ className,
101
+ render = <Button />,
102
+ ...props
103
+ }: ToastPrimitive.Action.Props) {
104
+ return (
105
+ <ToastPrimitive.Action
106
+ data-slot="toast-action"
107
+ render={render}
108
+ className={cn("shrink-0", className)}
109
+ {...props}
110
+ />
111
+ );
112
+ }
113
+
114
+ function ToastClose({
115
+ className,
116
+ children,
117
+ render = <Button size="icon" />,
118
+ ...props
119
+ }: ToastPrimitive.Close.Props) {
120
+ return (
121
+ <ToastPrimitive.Close
122
+ data-slot="toast-close"
123
+ aria-label="Close toast"
124
+ render={render}
125
+ className={cn(
126
+ "relative shrink-0 text-dashboard-text-muted after:absolute after:-inset-2 after:content-[''] hover:text-dashboard-text",
127
+ className,
128
+ )}
129
+ {...props}
130
+ >
131
+ {children ?? <XIcon aria-hidden="true" />}
132
+ </ToastPrimitive.Close>
133
+ );
134
+ }
135
+
136
+ function ToastIcon({ type }: { type: string | undefined }) {
137
+ let icon: React.ReactNode = null;
138
+
139
+ if (type === "success") {
140
+ icon = <CircleCheckIcon aria-hidden="true" />;
141
+ }
142
+
143
+ if (type === "info") {
144
+ icon = <InfoIcon aria-hidden="true" />;
145
+ }
146
+
147
+ if (type === "warning") {
148
+ icon = <TriangleAlertIcon aria-hidden="true" />;
149
+ }
150
+
151
+ if (type === "error") {
152
+ icon = <OctagonXIcon className="text-rose-300" aria-hidden="true" />;
153
+ }
154
+
155
+ if (type === "loading") {
156
+ icon = (
157
+ <Loader2Icon
158
+ className="animate-spin motion-reduce:animate-none"
159
+ aria-hidden="true"
160
+ />
161
+ );
162
+ }
163
+
164
+ if (!icon) {
165
+ return null;
166
+ }
167
+
168
+ return (
169
+ <span
170
+ data-slot="toast-icon"
171
+ className="shrink-0 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4"
172
+ >
173
+ {icon}
174
+ </span>
175
+ );
176
+ }
177
+
178
+ function ToastList() {
179
+ const { toasts } = ToastPrimitive.useToastManager();
180
+
181
+ return toasts.map((toastItem) => (
182
+ <Toast key={toastItem.id} toast={toastItem}>
183
+ <ToastContent>
184
+ <ToastIcon type={toastItem.type} />
185
+ <div className="flex min-w-0 flex-1 flex-col gap-1">
186
+ <ToastTitle />
187
+ <ToastDescription />
188
+ </div>
189
+ {toastItem.actionProps ? (
190
+ <ToastAction {...toastItem.actionProps} />
191
+ ) : null}
192
+ <ToastClose />
193
+ </ToastContent>
194
+ </Toast>
195
+ ));
196
+ }
197
+
198
+ /** Own notification state for one mounted dashboard and render its toast stack. */
199
+ function Toaster({ children, ...props }: ToastPrimitive.Provider.Props) {
200
+ return (
201
+ <ToastProvider limit={3} timeout={4000} {...props}>
202
+ {children}
203
+ <ToastPortal>
204
+ <ToastViewport>
205
+ <ToastList />
206
+ </ToastViewport>
207
+ </ToastPortal>
208
+ </ToastProvider>
209
+ );
210
+ }
211
+
212
+ /** Show short notifications through the nearest mounted Toaster. */
213
+ const useToastManager = ToastPrimitive.useToastManager;
214
+
215
+ export { Toaster, useToastManager };
@@ -0,0 +1,36 @@
1
+ import { Toggle as TogglePrimitive } from "@base-ui/react/toggle";
2
+ import { ToggleGroup as ToggleGroupPrimitive } from "@base-ui/react/toggle-group";
3
+ import type { VariantProps } from "class-variance-authority";
4
+ import { cn } from "@dashboard/lib/utils";
5
+ import { toggleVariants } from "./toggle";
6
+
7
+ /** Own the pressed values and arrow-key focus across a row of items. */
8
+ function ToggleGroup<Value extends string>({
9
+ className,
10
+ ...props
11
+ }: ToggleGroupPrimitive.Props<Value>) {
12
+ return (
13
+ <ToggleGroupPrimitive
14
+ data-slot="toggle-group"
15
+ className={cn("flex items-center gap-1", className)}
16
+ {...props}
17
+ />
18
+ );
19
+ }
20
+
21
+ /** Render one item with a `ui/toggle` look. */
22
+ function ToggleGroupItem<Value extends string>({
23
+ className,
24
+ variant,
25
+ ...props
26
+ }: TogglePrimitive.Props<Value> & VariantProps<typeof toggleVariants>) {
27
+ return (
28
+ <TogglePrimitive
29
+ data-slot="toggle-group-item"
30
+ className={cn(toggleVariants({ variant }), className)}
31
+ {...props}
32
+ />
33
+ );
34
+ }
35
+
36
+ export { ToggleGroup, ToggleGroupItem };
@@ -0,0 +1,37 @@
1
+ import { Toggle as TogglePrimitive } from "@base-ui/react/toggle";
2
+ import { cva, type VariantProps } from "class-variance-authority";
3
+ import { cn } from "@dashboard/lib/utils";
4
+
5
+ /** Pressed-state looks shared by `Toggle` and `ToggleGroupItem`. */
6
+ const toggleVariants = cva(
7
+ "inline-flex cursor-pointer items-center justify-center font-sans text-xs font-medium transition-colors focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-dashboard-focus",
8
+ {
9
+ variants: {
10
+ variant: {
11
+ /** Quiet when off. The pressed state uses the active surface. */
12
+ default:
13
+ "h-7 min-w-10 rounded-md border border-transparent bg-transparent px-2 text-dashboard-text-muted hover:bg-dashboard-fill-hover hover:text-dashboard-text data-pressed:border-dashboard-border-interactive data-pressed:bg-dashboard-surface-active data-pressed:text-dashboard-text",
14
+ /** A bordered filter chip. The pressed state fills solid. */
15
+ pill: "rounded-md border border-dashboard-border-strong bg-dashboard-surface-raised px-2 py-1 leading-tight text-dashboard-text-muted hover:border-dashboard-border-interactive hover:bg-dashboard-surface-hover hover:text-dashboard-text data-pressed:border-dashboard-border-heavy data-pressed:bg-dashboard-text-solid data-pressed:text-dashboard-text-inverse",
16
+ },
17
+ },
18
+ defaultVariants: { variant: "default" },
19
+ },
20
+ );
21
+
22
+ /** Turn one setting on or off. */
23
+ function Toggle<Value extends string>({
24
+ className,
25
+ variant,
26
+ ...props
27
+ }: TogglePrimitive.Props<Value> & VariantProps<typeof toggleVariants>) {
28
+ return (
29
+ <TogglePrimitive
30
+ data-slot="toggle"
31
+ className={cn(toggleVariants({ variant }), className)}
32
+ {...props}
33
+ />
34
+ );
35
+ }
36
+
37
+ export { Toggle, toggleVariants };