@sentry/junior-dashboard 0.264.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 (191) 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 +145 -136
  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 +5 -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 +12 -2
  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 +15 -24
  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 +86 -77
  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 +13 -3
  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/conversations/ChatLayout.tsx +7 -3
  60. package/src/client/conversations/ConversationBrief.tsx +17 -6
  61. package/src/client/conversations/ConversationComposer.tsx +26 -12
  62. package/src/client/conversations/ConversationDetails.tsx +147 -62
  63. package/src/client/conversations/ConversationEventDetails.tsx +141 -0
  64. package/src/client/conversations/ConversationEventLog.tsx +150 -129
  65. package/src/client/conversations/ConversationHeader.tsx +8 -3
  66. package/src/client/conversations/ConversationHeaderActions.tsx +90 -82
  67. package/src/client/conversations/ConversationHomeList.tsx +1 -1
  68. package/src/client/conversations/ConversationLinkedWork.tsx +118 -0
  69. package/src/client/conversations/ConversationMeta.tsx +55 -88
  70. package/src/client/conversations/ConversationPage.tsx +220 -101
  71. package/src/client/conversations/ConversationSidebar.tsx +48 -29
  72. package/src/client/conversations/ConversationWatches.tsx +165 -0
  73. package/src/client/conversations/ConversationWorkspace.tsx +12 -22
  74. package/src/client/conversations/ConversationWorkspaceLoading.tsx +1 -1
  75. package/src/client/conversations/DetailsList.tsx +124 -0
  76. package/src/client/conversations/EventDetails.tsx +42 -8
  77. package/src/client/conversations/ForkConversationButton.tsx +27 -16
  78. package/src/client/conversations/ObjectCard.tsx +20 -8
  79. package/src/client/conversations/PendingMailboxStack.tsx +52 -33
  80. package/src/client/conversations/README.md +86 -13
  81. package/src/client/conversations/ShareConversationButton.tsx +25 -13
  82. package/src/client/conversations/SubagentTranscriptDrawer.tsx +21 -15
  83. package/src/client/conversations/ToolFrame.tsx +36 -52
  84. package/src/client/conversations/TranscriptActivityGroup.tsx +13 -4
  85. package/src/client/conversations/TranscriptAutomationTriggerView.tsx +5 -4
  86. package/src/client/conversations/TranscriptContextEventView.tsx +25 -11
  87. package/src/client/conversations/TranscriptHeadingRow.tsx +7 -7
  88. package/src/client/conversations/TranscriptLoading.tsx +1 -1
  89. package/src/client/conversations/TranscriptMarkdown.tsx +25 -20
  90. package/src/client/conversations/TranscriptMessageContextView.tsx +8 -2
  91. package/src/client/conversations/TranscriptMessageView.tsx +6 -1
  92. package/src/client/conversations/TranscriptReasoningView.tsx +54 -68
  93. package/src/client/conversations/TranscriptTimestamp.tsx +9 -7
  94. package/src/client/conversations/TranscriptToolView.tsx +1 -1
  95. package/src/client/conversations/TranscriptTurnContextView.tsx +99 -27
  96. package/src/client/conversations/TranscriptView.tsx +63 -27
  97. package/src/client/conversations/eventLog.ts +57 -0
  98. package/src/client/conversations/eventTime.ts +60 -0
  99. package/src/client/conversations/queries.ts +29 -0
  100. package/src/client/conversations/transcriptBottomPinning.ts +34 -0
  101. package/src/client/format.ts +5 -0
  102. package/src/client/pages/ConnectionsPage.tsx +2 -2
  103. package/src/client/pages/PersonalTokensPage.tsx +4 -4
  104. package/src/client/pages/SettingsPage.tsx +9 -10
  105. package/src/client/pages/admin/ServiceAccountsSection.tsx +2 -2
  106. package/src/client/pages/automations/AutomationCostChart.tsx +50 -71
  107. package/src/client/pages/automations/AutomationDeleteDialog.tsx +87 -0
  108. package/src/client/pages/automations/AutomationDetails.tsx +193 -0
  109. package/src/client/pages/automations/AutomationEditPage.tsx +7 -8
  110. package/src/client/pages/automations/AutomationEditor.tsx +41 -29
  111. package/src/client/pages/automations/AutomationEditorLoading.tsx +1 -1
  112. package/src/client/pages/automations/AutomationEventFields.tsx +202 -119
  113. package/src/client/pages/automations/AutomationExecutionChart.tsx +51 -64
  114. package/src/client/pages/automations/AutomationExecutionStatusChart.tsx +47 -70
  115. package/src/client/pages/automations/AutomationExecutionsPage.tsx +150 -126
  116. package/src/client/pages/automations/AutomationFilters.tsx +189 -74
  117. package/src/client/pages/automations/AutomationLifecycle.tsx +109 -78
  118. package/src/client/pages/automations/AutomationOutcomeFields.tsx +26 -24
  119. package/src/client/pages/automations/AutomationRecentRuns.tsx +143 -0
  120. package/src/client/pages/automations/AutomationRow.tsx +12 -138
  121. package/src/client/pages/automations/AutomationRunDetails.tsx +307 -0
  122. package/src/client/pages/automations/AutomationRunsPage.tsx +119 -94
  123. package/src/client/pages/automations/AutomationScheduleFields.tsx +51 -51
  124. package/src/client/pages/automations/AutomationStatus.tsx +201 -0
  125. package/src/client/pages/automations/AutomationVersionsPage.tsx +65 -28
  126. package/src/client/pages/automations/AutomationsPage.tsx +80 -68
  127. package/src/client/pages/automations/AutomationsPageLayout.tsx +46 -14
  128. package/src/client/pages/automations/README.md +57 -0
  129. package/src/client/pages/automations/TriggerFilters.tsx +22 -0
  130. package/src/client/pages/automations/automationFormat.ts +37 -23
  131. package/src/client/pages/code/CodeActivityChart.tsx +59 -101
  132. package/src/client/pages/code/CodePage.tsx +52 -55
  133. package/src/client/pages/code/RepositoryPage.tsx +6 -8
  134. package/src/client/pages/locations/LocationActivityChart.tsx +53 -70
  135. package/src/client/pages/locations/LocationDirectoryActivityChart.tsx +60 -80
  136. package/src/client/pages/memory/MemoryCostChart.tsx +79 -103
  137. package/src/client/pages/memory/MemoryDetails.tsx +218 -0
  138. package/src/client/pages/memory/MemoryPage.tsx +168 -112
  139. package/src/client/pages/memory/MemoryPageLayout.tsx +33 -9
  140. package/src/client/pages/memory/MemoryTimeline.tsx +46 -69
  141. package/src/client/pages/memory/memoryRecord.ts +1 -1
  142. package/src/client/pages/people/ContributionGrid.tsx +23 -16
  143. package/src/client/pages/people/PeopleActivityChart.tsx +68 -107
  144. package/src/client/pages/people/ProfileCodeChanges.tsx +5 -5
  145. package/src/client/pages/system/BaseSandboxCard.tsx +1 -1
  146. package/src/client/pages/system/ConversationActivityChart.tsx +49 -67
  147. package/src/client/pages/system/GuardianActivity.tsx +1 -2
  148. package/src/client/pages/system/PluginBarChart.tsx +106 -87
  149. package/src/client/pages/system/PluginReportRecordSet.tsx +25 -24
  150. package/src/client/pages/system/README.md +23 -0
  151. package/src/client/pages/system/SystemNavigation.tsx +5 -1
  152. package/src/client/pages/system/WorkspaceDeleteDialog.tsx +111 -0
  153. package/src/client/pages/system/WorkspaceDetails.tsx +200 -43
  154. package/src/client/pages/system/WorkspaceEditor.tsx +59 -61
  155. package/src/client/pages/system/WorkspaceFormPage.tsx +23 -47
  156. package/src/client/pages/system/WorkspaceList.tsx +20 -30
  157. package/src/client/pages/system/WorkspacesPage.tsx +117 -119
  158. package/src/client/pages/system/sandboxSize.ts +8 -0
  159. package/src/client/pages/system/workspaceQueries.ts +53 -0
  160. package/src/client/pages/user/PluginUserPage.tsx +51 -2
  161. package/src/client/pages/user/pluginUserPageData.ts +1 -6
  162. package/src/client/styles.ts +4 -0
  163. package/src/client.tsx +7 -1
  164. package/src/mock-reporting/automation-collection.ts +4 -2
  165. package/src/mock-reporting/fixtures.ts +23 -7
  166. package/src/mock-reporting/routes.ts +12 -0
  167. package/src/mock-reporting/watches.ts +94 -0
  168. package/src/shell.ts +4 -9
  169. package/src/tailwind.css +0 -10
  170. package/src/client/components/Button.tsx +0 -118
  171. package/src/client/components/Field.tsx +0 -53
  172. package/src/client/components/SegmentedTabs.tsx +0 -119
  173. package/src/client/components/Select.tsx +0 -52
  174. package/src/client/components/Skeleton.tsx +0 -17
  175. package/src/client/components/TextInput.tsx +0 -58
  176. package/src/client/components/Tooltip.tsx +0 -216
  177. package/src/client/components/charts/useChartLayout.ts +0 -27
  178. package/src/client/components/ui/sheet.LICENSE +0 -21
  179. package/src/client/conversations/ConversationDetailsFrame.tsx +0 -119
  180. package/src/client/conversations/CopyMarkdownButton.tsx +0 -65
  181. package/src/client/pages/automations/AutomationDetailsDrawer.tsx +0 -219
  182. package/src/client/pages/dev/ChartFixtures.tsx +0 -325
  183. package/src/client/pages/dev/ComponentsPage.tsx +0 -899
  184. package/src/client/pages/dev/ConversationFixture.tsx +0 -231
  185. package/src/client/pages/dev/ObjectFixtures.tsx +0 -138
  186. package/src/client/pages/dev/SegmentedFixtures.tsx +0 -59
  187. package/src/client/pages/dev/SelectFixtures.tsx +0 -62
  188. package/src/client/pages/dev/TranscriptActivityFixtures.tsx +0 -206
  189. package/src/client/pages/memory/MemoryDetailsDrawer.tsx +0 -167
  190. package/src/client/pages/system/SandboxSizeSummary.tsx +0 -47
  191. package/src/client/pages/system/SnapshotSummary.tsx +0 -78
@@ -0,0 +1,77 @@
1
+ import { Accordion as AccordionPrimitive } from "@base-ui/react/accordion";
2
+ import { cn } from "@dashboard/lib/utils";
3
+ import { ChevronDownIcon, ChevronUpIcon } from "lucide-react";
4
+
5
+ /** Group sections with Base UI disclosure and keyboard behavior. */
6
+ function Accordion({ className, ...props }: AccordionPrimitive.Root.Props) {
7
+ return (
8
+ <AccordionPrimitive.Root
9
+ data-slot="accordion"
10
+ className={cn("flex w-full flex-col", className)}
11
+ {...props}
12
+ />
13
+ );
14
+ }
15
+
16
+ /** Keep one section’s trigger and panel state together. */
17
+ function AccordionItem({ className, ...props }: AccordionPrimitive.Item.Props) {
18
+ return (
19
+ <AccordionPrimitive.Item
20
+ data-slot="accordion-item"
21
+ className={cn(
22
+ "not-last:border-b not-last:border-dashboard-border-subtle",
23
+ className,
24
+ )}
25
+ {...props}
26
+ />
27
+ );
28
+ }
29
+
30
+ /** Render the section heading and its expand or collapse control. */
31
+ function AccordionTrigger({
32
+ className,
33
+ children,
34
+ ...props
35
+ }: AccordionPrimitive.Trigger.Props) {
36
+ return (
37
+ <AccordionPrimitive.Header className="flex">
38
+ <AccordionPrimitive.Trigger
39
+ data-slot="accordion-trigger"
40
+ className={cn(
41
+ "group/accordion-trigger relative flex min-w-0 flex-1 cursor-pointer items-center justify-between gap-3 rounded-sm py-2.5 text-left font-sans text-sm font-medium text-dashboard-text transition-colors hover:text-dashboard-text-solid outline-none focus-visible:outline-2 focus-visible:outline-dashboard-focus aria-disabled:pointer-events-none aria-disabled:opacity-50 **:data-[slot=accordion-trigger-icon]:ml-auto **:data-[slot=accordion-trigger-icon]:size-4 **:data-[slot=accordion-trigger-icon]:text-dashboard-text-muted",
42
+ className,
43
+ )}
44
+ {...props}
45
+ >
46
+ {children}
47
+ <ChevronDownIcon
48
+ data-slot="accordion-trigger-icon"
49
+ className="pointer-events-none shrink-0 group-aria-expanded/accordion-trigger:hidden"
50
+ />
51
+ <ChevronUpIcon
52
+ data-slot="accordion-trigger-icon"
53
+ className="pointer-events-none hidden shrink-0 group-aria-expanded/accordion-trigger:inline"
54
+ />
55
+ </AccordionPrimitive.Trigger>
56
+ </AccordionPrimitive.Header>
57
+ );
58
+ }
59
+
60
+ /** Reveal section content with measured height and reduced-motion support. */
61
+ function AccordionContent({
62
+ className,
63
+ children,
64
+ ...props
65
+ }: AccordionPrimitive.Panel.Props) {
66
+ return (
67
+ <AccordionPrimitive.Panel
68
+ data-slot="accordion-content"
69
+ className="h-(--accordion-panel-height) overflow-hidden text-sm transition-[height] duration-180 ease-out data-ending-style:h-0 data-starting-style:h-0 motion-reduce:transition-none"
70
+ {...props}
71
+ >
72
+ <div className={cn("pt-0 pb-2.5", className)}>{children}</div>
73
+ </AccordionPrimitive.Panel>
74
+ );
75
+ }
76
+
77
+ export { Accordion, AccordionItem, AccordionTrigger, AccordionContent };
@@ -0,0 +1,89 @@
1
+ import type { ComponentProps } from "react";
2
+ import { AlertDialog as AlertDialogPrimitive } from "@base-ui/react/alert-dialog";
3
+ import { cn } from "@dashboard/lib/utils";
4
+ import { Button } from "./button";
5
+
6
+ /** Require an explicit response before a destructive action. */
7
+ export function AlertDialog(props: AlertDialogPrimitive.Root.Props) {
8
+ return <AlertDialogPrimitive.Root {...props} />;
9
+ }
10
+
11
+ /** Show a named confirmation above the page with modal focus handling. */
12
+ export function AlertDialogContent({
13
+ className,
14
+ ...props
15
+ }: AlertDialogPrimitive.Popup.Props) {
16
+ return (
17
+ <AlertDialogPrimitive.Portal>
18
+ <AlertDialogPrimitive.Backdrop className="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" />
19
+ <AlertDialogPrimitive.Popup
20
+ data-dashboard-modal=""
21
+ data-slot="alert-dialog-content"
22
+ className={cn(
23
+ "fixed top-1/2 left-1/2 z-50 grid grid-cols-1 max-h-[calc(100dvh-2rem)] w-[calc(100%-2rem)] max-w-sm -translate-x-1/2 -translate-y-1/2 gap-4 overflow-y-auto rounded-xl border border-dashboard-border-emphasis bg-dashboard-surface-raised p-5 text-dashboard-text shadow-lg outline-none transition-[opacity,scale] duration-180 motion-reduce:transition-none data-ending-style:opacity-0 data-starting-style:opacity-0 data-ending-style:scale-95 data-starting-style:scale-95",
24
+ className,
25
+ )}
26
+ {...props}
27
+ />
28
+ </AlertDialogPrimitive.Portal>
29
+ );
30
+ }
31
+
32
+ /** Name the action that needs confirmation. */
33
+ export function AlertDialogTitle({
34
+ className,
35
+ ...props
36
+ }: AlertDialogPrimitive.Title.Props) {
37
+ return (
38
+ <AlertDialogPrimitive.Title
39
+ className={cn("m-0 font-display text-lg font-medium", className)}
40
+ {...props}
41
+ />
42
+ );
43
+ }
44
+
45
+ /** Describe what the action changes before the user confirms it. */
46
+ export function AlertDialogDescription({
47
+ className,
48
+ ...props
49
+ }: AlertDialogPrimitive.Description.Props) {
50
+ return (
51
+ <AlertDialogPrimitive.Description
52
+ className={cn(
53
+ "m-0 break-words text-sm leading-relaxed text-dashboard-text-muted",
54
+ className,
55
+ )}
56
+ {...props}
57
+ />
58
+ );
59
+ }
60
+
61
+ /** Keep confirmation controls together and reachable on small screens. */
62
+ export function AlertDialogFooter({
63
+ className,
64
+ ...props
65
+ }: ComponentProps<"div">) {
66
+ return (
67
+ <div
68
+ className={cn("flex flex-wrap justify-end gap-2", className)}
69
+ {...props}
70
+ />
71
+ );
72
+ }
73
+
74
+ /** Run the confirmed action; its owner decides when the dialog can close. */
75
+ export function AlertDialogAction(props: ComponentProps<typeof Button>) {
76
+ return (
77
+ <Button data-slot="alert-dialog-action" className="min-h-11" {...props} />
78
+ );
79
+ }
80
+
81
+ /** Cancel through Base UI so focus returns to the source control. */
82
+ export function AlertDialogCancel(props: AlertDialogPrimitive.Close.Props) {
83
+ return (
84
+ <AlertDialogPrimitive.Close
85
+ render={<Button className="min-h-11" />}
86
+ {...props}
87
+ />
88
+ );
89
+ }
@@ -0,0 +1,85 @@
1
+ import { Button as ButtonPrimitive } from "@base-ui/react/button";
2
+ import { cva, type VariantProps } from "class-variance-authority";
3
+ import { cn } from "@dashboard/lib/utils";
4
+
5
+ const commandButtonClass =
6
+ "inline-flex h-9 max-w-full items-center justify-center gap-2 rounded-md border px-3 text-sm font-medium leading-none focus-visible:outline-2 focus-visible:outline-offset-2";
7
+
8
+ /** Style the dashboard command, primary, danger, and icon button surfaces. Links use it with `className`. */
9
+ const buttonVariants = cva(
10
+ "cursor-pointer font-sans no-underline transition-colors data-disabled:cursor-not-allowed data-disabled:opacity-50",
11
+ {
12
+ variants: {
13
+ variant: {
14
+ default: "",
15
+ primary: "",
16
+ danger: "",
17
+ },
18
+ size: {
19
+ default: "",
20
+ icon: "grid size-9 place-items-center rounded-md border-0 bg-transparent p-0 text-dashboard-text-muted focus-visible:outline-2 focus-visible:outline-offset-1 data-disabled:hover:!bg-transparent data-disabled:hover:!text-dashboard-text-muted",
21
+ },
22
+ },
23
+ compoundVariants: [
24
+ {
25
+ size: "default",
26
+ variant: "default",
27
+ className: cn(
28
+ commandButtonClass,
29
+ "border-dashboard-border-emphasis bg-dashboard-surface-raised text-dashboard-text hover:border-dashboard-border-heavy hover:bg-dashboard-surface-hover hover:text-dashboard-text focus-visible:outline-dashboard-focus data-disabled:hover:border-dashboard-border-emphasis data-disabled:hover:bg-dashboard-surface-raised data-disabled:hover:text-dashboard-text",
30
+ ),
31
+ },
32
+ {
33
+ size: "default",
34
+ variant: "primary",
35
+ className: cn(
36
+ commandButtonClass,
37
+ "border-dashboard-text-solid bg-dashboard-text-solid text-dashboard-text-inverse hover:border-dashboard-text-subtle hover:bg-dashboard-text-subtle focus-visible:outline-dashboard-focus data-disabled:hover:border-dashboard-text-solid data-disabled:hover:bg-dashboard-text-solid",
38
+ ),
39
+ },
40
+ {
41
+ size: "default",
42
+ variant: "danger",
43
+ className: cn(
44
+ commandButtonClass,
45
+ "border-dashboard-border-strong bg-transparent text-dashboard-text-muted hover:border-rose-300/40 hover:text-rose-300 focus-visible:outline-rose-300/55 data-disabled:hover:border-dashboard-border-strong data-disabled:hover:text-dashboard-text-muted",
46
+ ),
47
+ },
48
+ {
49
+ size: "icon",
50
+ variant: ["default", "primary"],
51
+ className:
52
+ "hover:!bg-dashboard-fill-strong hover:!text-dashboard-text focus-visible:outline-dashboard-focus",
53
+ },
54
+ {
55
+ size: "icon",
56
+ variant: "danger",
57
+ className:
58
+ "hover:!bg-rose-300/10 hover:!text-rose-300 focus-visible:outline-rose-300/55",
59
+ },
60
+ ],
61
+ defaultVariants: {
62
+ variant: "default",
63
+ size: "default",
64
+ },
65
+ },
66
+ );
67
+
68
+ /** Render a Base UI button with a dashboard button surface. */
69
+ function Button({
70
+ className,
71
+ variant = "default",
72
+ size = "default",
73
+ ...props
74
+ }: Omit<ButtonPrimitive.Props, "className"> &
75
+ VariantProps<typeof buttonVariants> & { className?: string }) {
76
+ return (
77
+ <ButtonPrimitive
78
+ data-slot="button"
79
+ className={cn(buttonVariants({ variant, size }), className)}
80
+ {...props}
81
+ />
82
+ );
83
+ }
84
+
85
+ export { Button, buttonVariants };
@@ -0,0 +1,74 @@
1
+ import * as React from "react";
2
+ import * as RechartsPrimitive from "recharts";
3
+ import { cn } from "@dashboard/lib/utils";
4
+
5
+ const INITIAL_DIMENSION = { width: 320, height: 200 } as const;
6
+
7
+ type ChartConfig = Record<
8
+ string,
9
+ {
10
+ label?: React.ReactNode;
11
+ color?: string;
12
+ }
13
+ >;
14
+
15
+ /**
16
+ * Size a Recharts chart to its box and expose each config color as
17
+ * `var(--color-<key>)` inside it.
18
+ */
19
+ function ChartContainer({
20
+ id,
21
+ className,
22
+ children,
23
+ config,
24
+ ...props
25
+ }: React.ComponentProps<"div"> & {
26
+ config: ChartConfig;
27
+ children: React.ComponentProps<
28
+ typeof RechartsPrimitive.ResponsiveContainer
29
+ >["children"];
30
+ }) {
31
+ const uniqueId = React.useId();
32
+ const chartId = `chart-${id ?? uniqueId.replace(/:/g, "")}`;
33
+
34
+ return (
35
+ <div
36
+ data-slot="chart"
37
+ data-chart={chartId}
38
+ className={cn(
39
+ "flex aspect-video justify-center font-sans text-2xs tabular-nums [&_.recharts-cartesian-axis-tick-value]:fill-dashboard-text-muted [&_.recharts-cartesian-grid_line[stroke='#ccc']]:stroke-dashboard-border-subtle [&_.recharts-curve.recharts-tooltip-cursor]:stroke-dashboard-border [&_.recharts-dot[stroke='#fff']]:stroke-transparent [&_.recharts-layer]:outline-hidden [&_.recharts-rectangle.recharts-tooltip-cursor]:fill-dashboard-fill-soft [&_.recharts-reference-line_[stroke='#ccc']]:stroke-dashboard-border [&_.recharts-surface]:outline-hidden [&_.recharts-surface]:focus-visible:outline-2 [&_.recharts-surface]:focus-visible:outline-dashboard-focus",
40
+ className,
41
+ )}
42
+ {...props}
43
+ >
44
+ <ChartStyle id={chartId} config={config} />
45
+ <RechartsPrimitive.ResponsiveContainer
46
+ initialDimension={INITIAL_DIMENSION}
47
+ >
48
+ {children}
49
+ </RechartsPrimitive.ResponsiveContainer>
50
+ </div>
51
+ );
52
+ }
53
+
54
+ const ChartStyle = ({ id, config }: { id: string; config: ChartConfig }) => {
55
+ const colors = Object.entries(config).flatMap(([key, { color }]) =>
56
+ color ? [` --color-${key}: ${color};`] : [],
57
+ );
58
+
59
+ if (!colors.length) {
60
+ return null;
61
+ }
62
+
63
+ return (
64
+ <style
65
+ dangerouslySetInnerHTML={{
66
+ __html: `[data-chart=${id}] {\n${colors.join("\n")}\n}`,
67
+ }}
68
+ />
69
+ );
70
+ };
71
+
72
+ const ChartTooltip = RechartsPrimitive.Tooltip;
73
+
74
+ export { ChartContainer, ChartTooltip };
@@ -0,0 +1,26 @@
1
+ import { Checkbox as CheckboxPrimitive } from "@base-ui/react/checkbox";
2
+ import { cn } from "@dashboard/lib/utils";
3
+ import { CheckIcon } from "lucide-react";
4
+
5
+ /** Render a Base UI checkbox with the dashboard control surface. */
6
+ function Checkbox({
7
+ className,
8
+ ...props
9
+ }: Omit<CheckboxPrimitive.Root.Props, "className"> & { className?: string }) {
10
+ return (
11
+ <CheckboxPrimitive.Root
12
+ data-slot="checkbox"
13
+ className={cn(
14
+ "grid size-4 shrink-0 cursor-pointer place-items-center rounded-sm border border-dashboard-border-interactive bg-dashboard-control text-dashboard-text-inverse transition-colors focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-dashboard-focus data-checked:border-dashboard-focus data-checked:bg-dashboard-focus data-disabled:cursor-not-allowed data-disabled:opacity-50",
15
+ className,
16
+ )}
17
+ {...props}
18
+ >
19
+ <CheckboxPrimitive.Indicator data-slot="checkbox-indicator">
20
+ <CheckIcon aria-hidden="true" size={12} strokeWidth={3} />
21
+ </CheckboxPrimitive.Indicator>
22
+ </CheckboxPrimitive.Root>
23
+ );
24
+ }
25
+
26
+ export { Checkbox };
@@ -0,0 +1,22 @@
1
+ import { Collapsible as CollapsiblePrimitive } from "@base-ui/react/collapsible";
2
+
3
+ /** Own open state for one trigger and its panel. */
4
+ function Collapsible({ ...props }: CollapsiblePrimitive.Root.Props) {
5
+ return <CollapsiblePrimitive.Root data-slot="collapsible" {...props} />;
6
+ }
7
+
8
+ /** Toggle the panel and expose its state with `aria-expanded`. */
9
+ function CollapsibleTrigger({ ...props }: CollapsiblePrimitive.Trigger.Props) {
10
+ return (
11
+ <CollapsiblePrimitive.Trigger data-slot="collapsible-trigger" {...props} />
12
+ );
13
+ }
14
+
15
+ /** Render the panel only while open, unless `keepMounted` is set. */
16
+ function CollapsibleContent({ ...props }: CollapsiblePrimitive.Panel.Props) {
17
+ return (
18
+ <CollapsiblePrimitive.Panel data-slot="collapsible-content" {...props} />
19
+ );
20
+ }
21
+
22
+ export { Collapsible, CollapsibleTrigger, CollapsibleContent };
@@ -0,0 +1,49 @@
1
+ import type { ComponentProps } from "react";
2
+ import { cn } from "@dashboard/lib/utils";
3
+
4
+ /** Stack a label, control, and messages for one form field. */
5
+ function Field({ className, ...props }: ComponentProps<"div">) {
6
+ return (
7
+ <div data-slot="field" className={cn("grid gap-2", className)} {...props} />
8
+ );
9
+ }
10
+
11
+ /** Label the field control. */
12
+ function FieldLabel({ className, ...props }: ComponentProps<"label">) {
13
+ return (
14
+ <label
15
+ data-slot="field-label"
16
+ className={cn("text-sm font-semibold text-dashboard-text", className)}
17
+ {...props}
18
+ />
19
+ );
20
+ }
21
+
22
+ /** Give help text below the field control. */
23
+ function FieldDescription({ className, ...props }: ComponentProps<"p">) {
24
+ return (
25
+ <p
26
+ data-slot="field-description"
27
+ className={cn(
28
+ "m-0 text-xs leading-relaxed text-dashboard-text-muted sm:text-sm",
29
+ className,
30
+ )}
31
+ {...props}
32
+ />
33
+ );
34
+ }
35
+
36
+ /** Announce a field validation error. Render nothing when there is no error. */
37
+ function FieldError({ className, ...props }: ComponentProps<"p">) {
38
+ if (!props.children) return null;
39
+ return (
40
+ <p
41
+ role="alert"
42
+ data-slot="field-error"
43
+ className={cn("m-0 text-xs leading-relaxed text-rose-300", className)}
44
+ {...props}
45
+ />
46
+ );
47
+ }
48
+
49
+ export { Field, FieldDescription, FieldError, FieldLabel };
@@ -0,0 +1,35 @@
1
+ import { Input as InputPrimitive } from "@base-ui/react/input";
2
+ import { cva, type VariantProps } from "class-variance-authority";
3
+ import { cn } from "@dashboard/lib/utils";
4
+
5
+ /** Style the dashboard text control surface shared by inputs and text areas. */
6
+ export const textControlClass =
7
+ "block w-full rounded-md border border-dashboard-border-emphasis bg-dashboard-ink px-3 py-2 font-sans text-sm text-dashboard-text placeholder:text-dashboard-text-muted/70 focus:border-dashboard-focus focus:outline-none focus:ring-1 focus:ring-dashboard-focus/25 aria-invalid:border-rose-300 disabled:cursor-not-allowed disabled:opacity-50";
8
+
9
+ const inputVariants = cva(textControlClass, {
10
+ variants: {
11
+ size: {
12
+ default: "",
13
+ comfortable: "min-h-11 text-base sm:min-h-10 sm:text-sm",
14
+ },
15
+ },
16
+ defaultVariants: { size: "default" },
17
+ });
18
+
19
+ /** Render a Base UI text input. Use `size="comfortable"` for larger mobile controls. */
20
+ function Input({
21
+ className,
22
+ size,
23
+ ...props
24
+ }: Omit<InputPrimitive.Props, "className" | "size"> &
25
+ VariantProps<typeof inputVariants> & { className?: string }) {
26
+ return (
27
+ <InputPrimitive
28
+ data-slot="input"
29
+ className={cn(inputVariants({ size }), className)}
30
+ {...props}
31
+ />
32
+ );
33
+ }
34
+
35
+ export { Input };
@@ -0,0 +1,57 @@
1
+ import type { ComponentProps } from "react";
2
+ import { cva, type VariantProps } from "class-variance-authority";
3
+ import { ChevronDownIcon } from "lucide-react";
4
+ import { cn } from "@dashboard/lib/utils";
5
+
6
+ const nativeSelectVariants = cva(
7
+ "block w-full min-w-0 appearance-none pr-9 disabled:cursor-not-allowed disabled:opacity-60 forced-colors:appearance-auto [color-scheme:var(--dashboard-color-scheme,dark)]",
8
+ {
9
+ variants: {
10
+ variant: {
11
+ /** Form field. Touch screens get the taller target. */
12
+ form: "min-h-11 rounded-md border border-dashboard-border-emphasis bg-dashboard-ink py-2 pl-3 text-base text-dashboard-text focus:border-dashboard-focus focus:outline-none aria-invalid:border-rose-300 sm:min-h-10 sm:text-sm",
13
+ /** Compact control in a filter bar. */
14
+ filter:
15
+ "h-9 rounded-lg border border-dashboard-border-emphasis bg-dashboard-control pl-2 text-sm text-dashboard-text transition-colors hover:border-dashboard-border-interactive focus:border-dashboard-focus focus:outline-none focus:ring-1 focus:ring-dashboard-focus/25",
16
+ /** Borderless sort control that fills its frame. */
17
+ sort: "h-full bg-dashboard-control pl-2 font-sans text-xs text-dashboard-text-muted outline-none",
18
+ },
19
+ },
20
+ defaultVariants: { variant: "form" },
21
+ },
22
+ );
23
+
24
+ /** Keep native choices and draw the dashboard arrow. */
25
+ function NativeSelect({
26
+ className,
27
+ variant,
28
+ ...props
29
+ }: Omit<ComponentProps<"select">, "size"> &
30
+ VariantProps<typeof nativeSelectVariants>) {
31
+ return (
32
+ <span
33
+ data-slot="native-select-wrapper"
34
+ className={cn(
35
+ "relative block w-full min-w-0",
36
+ variant === "sort" && "h-full",
37
+ className,
38
+ )}
39
+ >
40
+ <select
41
+ data-slot="native-select"
42
+ className={nativeSelectVariants({ variant })}
43
+ {...props}
44
+ />
45
+ <ChevronDownIcon
46
+ aria-hidden="true"
47
+ data-slot="native-select-icon"
48
+ className={cn(
49
+ "pointer-events-none absolute top-1/2 right-3 size-4 -translate-y-1/2 text-dashboard-text-muted forced-colors:hidden",
50
+ props.disabled && "opacity-60",
51
+ )}
52
+ />
53
+ </span>
54
+ );
55
+ }
56
+
57
+ export { NativeSelect };
@@ -0,0 +1,67 @@
1
+ import { Popover as PopoverPrimitive } from "@base-ui/react/popover";
2
+ import { cn } from "@dashboard/lib/utils";
3
+
4
+ /** Own an anchored popover's state and dismissal. */
5
+ export function Popover(props: PopoverPrimitive.Root.Props) {
6
+ return <PopoverPrimitive.Root {...props} />;
7
+ }
8
+
9
+ /** Open a popover from the owning control. */
10
+ export function PopoverTrigger(props: PopoverPrimitive.Trigger.Props) {
11
+ return <PopoverPrimitive.Trigger data-slot="popover-trigger" {...props} />;
12
+ }
13
+
14
+ /** Position popover content within the viewport and share its themed surface. */
15
+ export function PopoverContent({
16
+ className,
17
+ align = "center",
18
+ side = "bottom",
19
+ ...props
20
+ }: PopoverPrimitive.Popup.Props &
21
+ Pick<PopoverPrimitive.Positioner.Props, "align" | "side">) {
22
+ return (
23
+ <PopoverPrimitive.Portal>
24
+ <PopoverPrimitive.Positioner
25
+ align={align}
26
+ side={side}
27
+ sideOffset={8}
28
+ className="isolate z-50"
29
+ >
30
+ <PopoverPrimitive.Popup
31
+ data-slot="popover-content"
32
+ className={cn(
33
+ "w-80 max-w-[calc(100vw-2rem)] max-h-(--available-height) origin-(--transform-origin) overflow-y-auto rounded-lg border border-dashboard-border-emphasis bg-dashboard-surface-raised p-4 text-sm text-dashboard-text shadow-lg outline-none focus-visible:outline-2 focus-visible:outline-dashboard-focus transition-[opacity,scale] duration-180 motion-reduce:transition-none data-ending-style:opacity-0 data-starting-style:opacity-0 data-ending-style:scale-95 data-starting-style:scale-95",
34
+ className,
35
+ )}
36
+ {...props}
37
+ />
38
+ </PopoverPrimitive.Positioner>
39
+ </PopoverPrimitive.Portal>
40
+ );
41
+ }
42
+
43
+ /** Name a popover through its visible heading. */
44
+ export function PopoverTitle({
45
+ className,
46
+ ...props
47
+ }: PopoverPrimitive.Title.Props) {
48
+ return (
49
+ <PopoverPrimitive.Title
50
+ className={cn("m-0 text-sm font-medium", className)}
51
+ {...props}
52
+ />
53
+ );
54
+ }
55
+
56
+ /** Explain a popover without duplicating its heading. */
57
+ export function PopoverDescription({
58
+ className,
59
+ ...props
60
+ }: PopoverPrimitive.Description.Props) {
61
+ return (
62
+ <PopoverPrimitive.Description
63
+ className={cn("m-0 leading-relaxed text-dashboard-text-muted", className)}
64
+ {...props}
65
+ />
66
+ );
67
+ }
@@ -0,0 +1,32 @@
1
+ import { Radio as RadioPrimitive } from "@base-ui/react/radio";
2
+ import { RadioGroup as RadioGroupPrimitive } from "@base-ui/react/radio-group";
3
+ import { cn } from "@dashboard/lib/utils";
4
+
5
+ /** Own the selected value and arrow-key focus for a set of radios. */
6
+ function RadioGroup<Value>(props: RadioGroupPrimitive.Props<Value>) {
7
+ return <RadioGroupPrimitive data-slot="radio-group" {...props} />;
8
+ }
9
+
10
+ /** Render one Base UI radio with the dashboard control surface. */
11
+ function RadioGroupItem({
12
+ className,
13
+ ...props
14
+ }: Omit<RadioPrimitive.Root.Props, "className"> & { className?: string }) {
15
+ return (
16
+ <RadioPrimitive.Root
17
+ data-slot="radio-group-item"
18
+ className={cn(
19
+ "grid size-4 shrink-0 cursor-pointer place-items-center rounded-full border border-dashboard-border-interactive bg-dashboard-control transition-colors focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-dashboard-focus data-checked:border-dashboard-focus data-checked:bg-dashboard-focus data-disabled:cursor-not-allowed data-disabled:opacity-50",
20
+ className,
21
+ )}
22
+ {...props}
23
+ >
24
+ <RadioPrimitive.Indicator
25
+ data-slot="radio-group-indicator"
26
+ className="size-1.5 rounded-full bg-dashboard-text-inverse"
27
+ />
28
+ </RadioPrimitive.Root>
29
+ );
30
+ }
31
+
32
+ export { RadioGroup, RadioGroupItem };
@@ -1,9 +1,8 @@
1
- // Adapted from shadcn/ui Base UI Sheet. See sheet.LICENSE.
2
1
  import * as React from "react";
3
2
  import { Dialog as SheetPrimitive } from "@base-ui/react/dialog";
4
3
  import { cn } from "@dashboard/lib/utils";
5
4
 
6
- import { Button } from "../Button";
5
+ import { Button } from "./button";
7
6
  import { XIcon } from "lucide-react";
8
7
 
9
8
  /** Own the open state and modal focus rules for a shadcn sheet. */
@@ -44,10 +43,12 @@ function SheetContent({
44
43
  children,
45
44
  side = "right",
46
45
  showCloseButton = true,
46
+ closeButtonProps,
47
47
  ...props
48
48
  }: SheetPrimitive.Popup.Props & {
49
49
  side?: "top" | "right" | "bottom" | "left";
50
50
  showCloseButton?: boolean;
51
+ closeButtonProps?: React.ComponentProps<typeof Button>;
51
52
  }) {
52
53
  // Keep portal order tied to the app tree when a resize mounts another sheet.
53
54
  const portalRef = React.useRef<HTMLDivElement>(null);
@@ -70,7 +71,16 @@ function SheetContent({
70
71
  {showCloseButton && (
71
72
  <SheetPrimitive.Close
72
73
  data-slot="sheet-close"
73
- render={<Button className="absolute top-3 right-3" size="icon" />}
74
+ render={
75
+ <Button
76
+ {...closeButtonProps}
77
+ className={cn(
78
+ "absolute top-3 right-3",
79
+ closeButtonProps?.className,
80
+ )}
81
+ size="icon"
82
+ />
83
+ }
74
84
  >
75
85
  <XIcon aria-hidden="true" size={15} strokeWidth={2.25} />
76
86
  <span className="sr-only">Close</span>
@@ -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 };