@sentry/junior-dashboard 0.264.0 → 0.266.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 (213) 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/ActorAvatar.tsx +10 -22
  14. package/src/client/components/BottomSheet.tsx +12 -2
  15. package/src/client/components/ConnectionBanner.tsx +4 -3
  16. package/src/client/components/CopyButton.tsx +82 -0
  17. package/src/client/components/DetailsPanel.tsx +133 -0
  18. package/src/client/components/Drawer.tsx +15 -24
  19. package/src/client/components/EmptyTelemetry.tsx +5 -3
  20. package/src/client/components/FilterBar.tsx +16 -31
  21. package/src/client/components/ImageAttachment.tsx +49 -63
  22. package/src/client/components/InlineError.tsx +8 -4
  23. package/src/client/components/Metric.tsx +33 -23
  24. package/src/client/components/Notice.tsx +19 -26
  25. package/src/client/components/PageContentSkeleton.tsx +1 -1
  26. package/src/client/components/Pagination.tsx +27 -27
  27. package/src/client/components/ParticipantAvatarStack.tsx +43 -39
  28. package/src/client/components/ProfileMenu.tsx +27 -93
  29. package/src/client/components/README.md +103 -78
  30. package/src/client/components/SearchInput.tsx +51 -41
  31. package/src/client/components/SegmentedNav.tsx +1 -1
  32. package/src/client/components/ShimmerText.tsx +2 -6
  33. package/src/client/components/ThemeSwitcher.tsx +19 -15
  34. package/src/client/components/VersionDriftBanner.tsx +9 -7
  35. package/src/client/components/charts/ActivityChart.tsx +173 -288
  36. package/src/client/components/charts/CacheWrites.tsx +59 -37
  37. package/src/client/components/charts/InputCacheChart.tsx +137 -131
  38. package/src/client/components/charts/README.md +4 -4
  39. package/src/client/components/charts/SystemMetricCharts.tsx +68 -95
  40. package/src/client/components/charts/WorkspaceUsageChart.tsx +42 -62
  41. package/src/client/components/controls/DirectorySortSelect.tsx +3 -3
  42. package/src/client/components/controls/TimeRangeSelector.tsx +10 -15
  43. package/src/client/components/layout/DashboardHeader.tsx +44 -90
  44. package/src/client/components/layout/SecondaryNavigation.tsx +2 -1
  45. package/src/client/components/layout/VisualViewportShell.tsx +2 -2
  46. package/src/client/components/ui/accordion.tsx +77 -0
  47. package/src/client/components/ui/alert-dialog.tsx +89 -0
  48. package/src/client/components/ui/alert.tsx +64 -0
  49. package/src/client/components/ui/avatar.tsx +53 -0
  50. package/src/client/components/ui/button.tsx +86 -0
  51. package/src/client/components/ui/chart.tsx +74 -0
  52. package/src/client/components/ui/checkbox.tsx +26 -0
  53. package/src/client/components/ui/collapsible.tsx +22 -0
  54. package/src/client/components/ui/dialog.tsx +66 -0
  55. package/src/client/components/ui/empty.tsx +32 -0
  56. package/src/client/components/ui/field.tsx +49 -0
  57. package/src/client/components/ui/input-group.tsx +96 -0
  58. package/src/client/components/ui/input.tsx +35 -0
  59. package/src/client/components/ui/native-select.tsx +57 -0
  60. package/src/client/components/ui/pagination.tsx +60 -0
  61. package/src/client/components/ui/popover.tsx +67 -0
  62. package/src/client/components/ui/radio-group.tsx +32 -0
  63. package/src/client/components/ui/sheet.tsx +13 -3
  64. package/src/client/components/ui/skeleton.tsx +19 -0
  65. package/src/client/components/ui/spinner.tsx +21 -0
  66. package/src/client/components/ui/table.tsx +101 -0
  67. package/src/client/components/ui/tabs.tsx +75 -0
  68. package/src/client/components/ui/textarea.tsx +17 -0
  69. package/src/client/components/ui/toast.tsx +215 -0
  70. package/src/client/components/ui/toggle-group.tsx +36 -0
  71. package/src/client/components/ui/toggle.tsx +37 -0
  72. package/src/client/components/ui/tooltip.tsx +168 -0
  73. package/src/client/components/ui/trace.tsx +96 -0
  74. package/src/client/conversations/ChatLayout.tsx +7 -3
  75. package/src/client/conversations/ConversationBrief.tsx +17 -6
  76. package/src/client/conversations/ConversationChildAgents.tsx +5 -5
  77. package/src/client/conversations/ConversationComposer.tsx +26 -12
  78. package/src/client/conversations/ConversationDetails.tsx +147 -62
  79. package/src/client/conversations/ConversationEventDetails.tsx +141 -0
  80. package/src/client/conversations/ConversationEventLog.tsx +150 -129
  81. package/src/client/conversations/ConversationHeader.tsx +13 -7
  82. package/src/client/conversations/ConversationHeaderActions.tsx +97 -93
  83. package/src/client/conversations/ConversationHomeList.tsx +1 -1
  84. package/src/client/conversations/ConversationLinkedWork.tsx +118 -0
  85. package/src/client/conversations/ConversationMeta.tsx +55 -88
  86. package/src/client/conversations/ConversationPage.tsx +220 -101
  87. package/src/client/conversations/ConversationSidebar.tsx +49 -29
  88. package/src/client/conversations/ConversationUsageBreakdown.tsx +108 -65
  89. package/src/client/conversations/ConversationWatches.tsx +173 -0
  90. package/src/client/conversations/ConversationWorkspace.tsx +12 -22
  91. package/src/client/conversations/ConversationWorkspaceLoading.tsx +1 -1
  92. package/src/client/conversations/DetailsList.tsx +139 -0
  93. package/src/client/conversations/EventDetails.tsx +42 -8
  94. package/src/client/conversations/EventUsage.tsx +99 -74
  95. package/src/client/conversations/ForkConversationButton.tsx +27 -16
  96. package/src/client/conversations/ObjectCard.tsx +20 -8
  97. package/src/client/conversations/PendingMailboxStack.tsx +52 -38
  98. package/src/client/conversations/README.md +89 -13
  99. package/src/client/conversations/ShareConversationButton.tsx +28 -17
  100. package/src/client/conversations/SubagentTranscriptDrawer.tsx +21 -15
  101. package/src/client/conversations/ToolFrame.tsx +36 -52
  102. package/src/client/conversations/TranscriptActivityGroup.tsx +13 -4
  103. package/src/client/conversations/TranscriptAutomationTriggerView.tsx +5 -4
  104. package/src/client/conversations/TranscriptContextEventView.tsx +25 -11
  105. package/src/client/conversations/TranscriptEventView.tsx +35 -16
  106. package/src/client/conversations/TranscriptHeadingRow.tsx +7 -7
  107. package/src/client/conversations/TranscriptLoading.tsx +1 -1
  108. package/src/client/conversations/TranscriptMarkdown.tsx +25 -20
  109. package/src/client/conversations/TranscriptMessageContextView.tsx +35 -18
  110. package/src/client/conversations/TranscriptMessageView.tsx +6 -1
  111. package/src/client/conversations/TranscriptReasoningView.tsx +54 -68
  112. package/src/client/conversations/TranscriptStructuredEventView.tsx +25 -15
  113. package/src/client/conversations/TranscriptSummary.tsx +34 -2
  114. package/src/client/conversations/TranscriptTimestamp.tsx +9 -7
  115. package/src/client/conversations/TranscriptToolView.tsx +1 -1
  116. package/src/client/conversations/TranscriptTurnContextView.tsx +144 -65
  117. package/src/client/conversations/TranscriptView.tsx +63 -27
  118. package/src/client/conversations/eventLog.ts +58 -0
  119. package/src/client/conversations/eventTime.ts +60 -0
  120. package/src/client/conversations/queries.ts +29 -0
  121. package/src/client/conversations/transcriptBottomPinning.ts +34 -0
  122. package/src/client/conversations/transcriptMentions.tsx +18 -5
  123. package/src/client/format.ts +5 -0
  124. package/src/client/pages/ConnectionsPage.tsx +2 -2
  125. package/src/client/pages/PersonalTokensPage.tsx +4 -4
  126. package/src/client/pages/SettingsPage.tsx +9 -10
  127. package/src/client/pages/admin/ServiceAccountsSection.tsx +2 -2
  128. package/src/client/pages/automations/AutomationCostChart.tsx +50 -71
  129. package/src/client/pages/automations/AutomationDeleteDialog.tsx +87 -0
  130. package/src/client/pages/automations/AutomationDetails.tsx +193 -0
  131. package/src/client/pages/automations/AutomationEditPage.tsx +7 -8
  132. package/src/client/pages/automations/AutomationEditor.tsx +41 -29
  133. package/src/client/pages/automations/AutomationEditorLoading.tsx +1 -1
  134. package/src/client/pages/automations/AutomationEventFields.tsx +202 -119
  135. package/src/client/pages/automations/AutomationExecutionChart.tsx +51 -64
  136. package/src/client/pages/automations/AutomationExecutionStatusChart.tsx +47 -70
  137. package/src/client/pages/automations/AutomationExecutionsPage.tsx +150 -126
  138. package/src/client/pages/automations/AutomationFilters.tsx +189 -74
  139. package/src/client/pages/automations/AutomationLifecycle.tsx +109 -78
  140. package/src/client/pages/automations/AutomationOutcomeFields.tsx +26 -24
  141. package/src/client/pages/automations/AutomationRecentRuns.tsx +143 -0
  142. package/src/client/pages/automations/AutomationRow.tsx +12 -138
  143. package/src/client/pages/automations/AutomationRunDetails.tsx +307 -0
  144. package/src/client/pages/automations/AutomationRunsPage.tsx +119 -94
  145. package/src/client/pages/automations/AutomationScheduleFields.tsx +51 -51
  146. package/src/client/pages/automations/AutomationStatus.tsx +201 -0
  147. package/src/client/pages/automations/AutomationVersionsPage.tsx +65 -28
  148. package/src/client/pages/automations/AutomationsPage.tsx +80 -68
  149. package/src/client/pages/automations/AutomationsPageLayout.tsx +46 -14
  150. package/src/client/pages/automations/README.md +57 -0
  151. package/src/client/pages/automations/TriggerFilters.tsx +22 -0
  152. package/src/client/pages/automations/automationFormat.ts +37 -23
  153. package/src/client/pages/code/CodeActivityChart.tsx +59 -101
  154. package/src/client/pages/code/CodePage.tsx +52 -55
  155. package/src/client/pages/code/RepositoryPage.tsx +6 -8
  156. package/src/client/pages/locations/LocationActivityChart.tsx +53 -70
  157. package/src/client/pages/locations/LocationDirectoryActivityChart.tsx +60 -80
  158. package/src/client/pages/memory/MemoryCostChart.tsx +79 -103
  159. package/src/client/pages/memory/MemoryDetails.tsx +218 -0
  160. package/src/client/pages/memory/MemoryPage.tsx +168 -112
  161. package/src/client/pages/memory/MemoryPageLayout.tsx +33 -9
  162. package/src/client/pages/memory/MemoryTimeline.tsx +46 -69
  163. package/src/client/pages/memory/memoryRecord.ts +1 -1
  164. package/src/client/pages/people/ContributionGrid.tsx +23 -16
  165. package/src/client/pages/people/PeopleActivityChart.tsx +68 -107
  166. package/src/client/pages/people/ProfileCodeChanges.tsx +5 -5
  167. package/src/client/pages/system/BaseSandboxCard.tsx +1 -1
  168. package/src/client/pages/system/ConversationActivityChart.tsx +49 -67
  169. package/src/client/pages/system/GuardianActivity.tsx +1 -2
  170. package/src/client/pages/system/PluginBarChart.tsx +106 -87
  171. package/src/client/pages/system/PluginReportRecordSet.tsx +25 -24
  172. package/src/client/pages/system/README.md +23 -0
  173. package/src/client/pages/system/SystemNavigation.tsx +5 -1
  174. package/src/client/pages/system/WorkspaceDeleteDialog.tsx +111 -0
  175. package/src/client/pages/system/WorkspaceDetails.tsx +200 -43
  176. package/src/client/pages/system/WorkspaceEditor.tsx +59 -61
  177. package/src/client/pages/system/WorkspaceFormPage.tsx +23 -47
  178. package/src/client/pages/system/WorkspaceList.tsx +20 -30
  179. package/src/client/pages/system/WorkspacesPage.tsx +117 -119
  180. package/src/client/pages/system/sandboxSize.ts +8 -0
  181. package/src/client/pages/system/workspaceQueries.ts +53 -0
  182. package/src/client/pages/user/PluginUserPage.tsx +51 -2
  183. package/src/client/pages/user/pluginUserPageData.ts +1 -6
  184. package/src/client/styles.ts +4 -0
  185. package/src/client.tsx +7 -1
  186. package/src/mock-reporting/automation-collection.ts +4 -2
  187. package/src/mock-reporting/fixtures.ts +23 -7
  188. package/src/mock-reporting/routes.ts +12 -0
  189. package/src/mock-reporting/watches.ts +94 -0
  190. package/src/shell.ts +4 -9
  191. package/src/tailwind.css +0 -10
  192. package/src/client/components/Button.tsx +0 -118
  193. package/src/client/components/Field.tsx +0 -53
  194. package/src/client/components/SegmentedTabs.tsx +0 -119
  195. package/src/client/components/Select.tsx +0 -52
  196. package/src/client/components/Skeleton.tsx +0 -17
  197. package/src/client/components/TextInput.tsx +0 -58
  198. package/src/client/components/Tooltip.tsx +0 -216
  199. package/src/client/components/charts/useChartLayout.ts +0 -27
  200. package/src/client/components/ui/sheet.LICENSE +0 -21
  201. package/src/client/conversations/ConversationDetailsFrame.tsx +0 -119
  202. package/src/client/conversations/CopyMarkdownButton.tsx +0 -65
  203. package/src/client/pages/automations/AutomationDetailsDrawer.tsx +0 -219
  204. package/src/client/pages/dev/ChartFixtures.tsx +0 -325
  205. package/src/client/pages/dev/ComponentsPage.tsx +0 -899
  206. package/src/client/pages/dev/ConversationFixture.tsx +0 -231
  207. package/src/client/pages/dev/ObjectFixtures.tsx +0 -138
  208. package/src/client/pages/dev/SegmentedFixtures.tsx +0 -59
  209. package/src/client/pages/dev/SelectFixtures.tsx +0 -62
  210. package/src/client/pages/dev/TranscriptActivityFixtures.tsx +0 -206
  211. package/src/client/pages/memory/MemoryDetailsDrawer.tsx +0 -167
  212. package/src/client/pages/system/SandboxSizeSummary.tsx +0 -47
  213. package/src/client/pages/system/SnapshotSummary.tsx +0 -78
@@ -0,0 +1,53 @@
1
+ import { Avatar as AvatarPrimitive } from "@base-ui/react/avatar";
2
+ import { cn } from "@dashboard/lib/utils";
3
+
4
+ /** Render a round avatar frame. Use `size="sm"` in dense lists. */
5
+ function Avatar({
6
+ className,
7
+ size = "default",
8
+ ...props
9
+ }: AvatarPrimitive.Root.Props & {
10
+ size?: "default" | "sm";
11
+ }) {
12
+ return (
13
+ <AvatarPrimitive.Root
14
+ data-slot="avatar"
15
+ data-size={size}
16
+ className={cn(
17
+ "group/avatar relative inline-grid size-7 shrink-0 place-items-center overflow-hidden rounded-full border-2 border-dashboard-bg bg-dashboard-focus shadow-sm select-none data-[size=sm]:size-6",
18
+ className,
19
+ )}
20
+ {...props}
21
+ />
22
+ );
23
+ }
24
+
25
+ /** Show the avatar image after it loads. */
26
+ function AvatarImage({ className, ...props }: AvatarPrimitive.Image.Props) {
27
+ return (
28
+ <AvatarPrimitive.Image
29
+ data-slot="avatar-image"
30
+ className={cn("size-full object-cover", className)}
31
+ {...props}
32
+ />
33
+ );
34
+ }
35
+
36
+ /** Show initials or a count while the image is missing, loading, or broken. */
37
+ function AvatarFallback({
38
+ className,
39
+ ...props
40
+ }: AvatarPrimitive.Fallback.Props) {
41
+ return (
42
+ <AvatarPrimitive.Fallback
43
+ data-slot="avatar-fallback"
44
+ className={cn(
45
+ "grid size-full place-items-center font-sans text-xs leading-none font-semibold tracking-tight text-dashboard-text-inverse group-data-[size=sm]/avatar:text-2xs",
46
+ className,
47
+ )}
48
+ {...props}
49
+ />
50
+ );
51
+ }
52
+
53
+ export { Avatar, AvatarImage, AvatarFallback };
@@ -0,0 +1,86 @@
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, icon, and menu row 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
+ menu: "flex w-full items-center gap-2.5 rounded-md border-0 bg-transparent px-2.5 py-2 text-left text-sm font-semibold text-dashboard-text hover:bg-dashboard-fill-strong focus-visible:bg-dashboard-fill-strong focus-visible:outline-none data-disabled:hover:bg-transparent",
22
+ },
23
+ },
24
+ compoundVariants: [
25
+ {
26
+ size: "default",
27
+ variant: "default",
28
+ className: cn(
29
+ commandButtonClass,
30
+ "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",
31
+ ),
32
+ },
33
+ {
34
+ size: "default",
35
+ variant: "primary",
36
+ className: cn(
37
+ commandButtonClass,
38
+ "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",
39
+ ),
40
+ },
41
+ {
42
+ size: "default",
43
+ variant: "danger",
44
+ className: cn(
45
+ commandButtonClass,
46
+ "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",
47
+ ),
48
+ },
49
+ {
50
+ size: "icon",
51
+ variant: ["default", "primary"],
52
+ className:
53
+ "hover:!bg-dashboard-fill-strong hover:!text-dashboard-text focus-visible:outline-dashboard-focus",
54
+ },
55
+ {
56
+ size: "icon",
57
+ variant: "danger",
58
+ className:
59
+ "hover:!bg-rose-300/10 hover:!text-rose-300 focus-visible:outline-rose-300/55",
60
+ },
61
+ ],
62
+ defaultVariants: {
63
+ variant: "default",
64
+ size: "default",
65
+ },
66
+ },
67
+ );
68
+
69
+ /** Render a Base UI button with a dashboard button surface. */
70
+ function Button({
71
+ className,
72
+ variant = "default",
73
+ size = "default",
74
+ ...props
75
+ }: Omit<ButtonPrimitive.Props, "className"> &
76
+ VariantProps<typeof buttonVariants> & { className?: string }) {
77
+ return (
78
+ <ButtonPrimitive
79
+ data-slot="button"
80
+ className={cn(buttonVariants({ variant, size }), className)}
81
+ {...props}
82
+ />
83
+ );
84
+ }
85
+
86
+ 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,66 @@
1
+ import { Dialog as DialogPrimitive } from "@base-ui/react/dialog";
2
+ import { cn } from "@dashboard/lib/utils";
3
+
4
+ /** Own the open state and modal focus rules for a dialog. */
5
+ function Dialog({ ...props }: DialogPrimitive.Root.Props) {
6
+ return <DialogPrimitive.Root data-slot="dialog" {...props} />;
7
+ }
8
+
9
+ function DialogPortal({ ...props }: DialogPrimitive.Portal.Props) {
10
+ return <DialogPrimitive.Portal data-slot="dialog-portal" {...props} />;
11
+ }
12
+
13
+ /** Close the dialog through Base UI dismissal and focus handling. */
14
+ function DialogClose({ ...props }: DialogPrimitive.Close.Props) {
15
+ return <DialogPrimitive.Close data-slot="dialog-close" {...props} />;
16
+ }
17
+
18
+ function DialogOverlay({
19
+ className,
20
+ ...props
21
+ }: DialogPrimitive.Backdrop.Props) {
22
+ return (
23
+ <DialogPrimitive.Backdrop
24
+ data-slot="dialog-overlay"
25
+ className={cn(
26
+ "fixed inset-0 isolate z-50 bg-dashboard-overlay transition-opacity duration-180 motion-reduce:transition-none data-ending-style:opacity-0 data-starting-style:opacity-0",
27
+ className,
28
+ )}
29
+ {...props}
30
+ />
31
+ );
32
+ }
33
+
34
+ /** Show the dialog above a backdrop, centered in the viewport. */
35
+ function DialogContent({ className, ...props }: DialogPrimitive.Popup.Props) {
36
+ return (
37
+ <DialogPortal>
38
+ <DialogOverlay />
39
+ <DialogPrimitive.Popup
40
+ data-slot="dialog-content"
41
+ data-dashboard-modal=""
42
+ className={cn(
43
+ "fixed top-1/2 left-1/2 z-50 grid w-full max-w-[calc(100%-2rem)] -translate-x-1/2 -translate-y-1/2 gap-4 rounded-xl border border-dashboard-border-emphasis bg-dashboard-surface-raised p-4 text-sm text-dashboard-text shadow-lg outline-none transition-[opacity,scale] duration-180 motion-reduce:transition-none sm:max-w-sm data-ending-style:opacity-0 data-starting-style:opacity-0 data-ending-style:scale-95 data-starting-style:scale-95",
44
+ className,
45
+ )}
46
+ {...props}
47
+ />
48
+ </DialogPortal>
49
+ );
50
+ }
51
+
52
+ /** Give the dialog its accessible name. */
53
+ function DialogTitle({ className, ...props }: DialogPrimitive.Title.Props) {
54
+ return (
55
+ <DialogPrimitive.Title
56
+ data-slot="dialog-title"
57
+ className={cn(
58
+ "m-0 text-base leading-none font-medium text-dashboard-text",
59
+ className,
60
+ )}
61
+ {...props}
62
+ />
63
+ );
64
+ }
65
+
66
+ export { Dialog, DialogClose, DialogContent, DialogTitle };
@@ -0,0 +1,32 @@
1
+ import type { ComponentProps } from "react";
2
+ import { cn } from "@dashboard/lib/utils";
3
+
4
+ /** Frame an empty state inside a page or list region. */
5
+ function Empty({ className, ...props }: ComponentProps<"div">) {
6
+ return (
7
+ <div
8
+ data-slot="empty"
9
+ className={cn(
10
+ "min-w-0 rounded-lg border border-dashboard-border-strong bg-dashboard-bg px-4 py-3",
11
+ className,
12
+ )}
13
+ {...props}
14
+ />
15
+ );
16
+ }
17
+
18
+ /** Explain why the region is empty and what the user can do next. */
19
+ function EmptyDescription({ className, ...props }: ComponentProps<"div">) {
20
+ return (
21
+ <div
22
+ data-slot="empty-description"
23
+ className={cn(
24
+ "text-base leading-relaxed text-dashboard-text-muted",
25
+ className,
26
+ )}
27
+ {...props}
28
+ />
29
+ );
30
+ }
31
+
32
+ export { Empty, EmptyDescription };
@@ -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,96 @@
1
+ import type { ComponentProps } from "react";
2
+ import { cva, type VariantProps } from "class-variance-authority";
3
+ import { cn } from "@dashboard/lib/utils";
4
+
5
+ import { Button } from "@dashboard/components/ui/button";
6
+ import { Input } from "@dashboard/components/ui/input";
7
+
8
+ /** Frame one text input with its icons and inline buttons. */
9
+ function InputGroup({ className, ...props }: ComponentProps<"div">) {
10
+ return (
11
+ <div
12
+ data-slot="input-group"
13
+ role="group"
14
+ className={cn(
15
+ "group/input-group relative flex h-9 w-full min-w-0 items-center rounded-md border border-dashboard-border bg-dashboard-overlay-soft transition-colors outline-none hover:border-dashboard-border-emphasis has-[[data-slot=input-group-control]:focus-visible]:border-dashboard-focus has-[[data-slot=input-group-control]:focus-visible]:ring-1 has-[[data-slot=input-group-control]:focus-visible]:ring-dashboard-focus/25",
16
+ className,
17
+ )}
18
+ {...props}
19
+ />
20
+ );
21
+ }
22
+
23
+ const inputGroupAddonVariants = cva(
24
+ "flex h-auto cursor-text items-center justify-center gap-2 py-1.5 text-sm font-medium text-dashboard-text-muted select-none",
25
+ {
26
+ variants: {
27
+ align: {
28
+ "inline-start": "order-first pl-2.5",
29
+ "inline-end": "order-last pr-1.5",
30
+ },
31
+ },
32
+ defaultVariants: {
33
+ align: "inline-start",
34
+ },
35
+ },
36
+ );
37
+
38
+ /** Place an icon or button before or after the input. A click on the addon focuses the input. */
39
+ function InputGroupAddon({
40
+ className,
41
+ align = "inline-start",
42
+ ...props
43
+ }: ComponentProps<"div"> & VariantProps<typeof inputGroupAddonVariants>) {
44
+ return (
45
+ <div
46
+ role="group"
47
+ data-slot="input-group-addon"
48
+ data-align={align}
49
+ className={cn(inputGroupAddonVariants({ align }), className)}
50
+ onClick={(e) => {
51
+ if ((e.target as HTMLElement).closest("button")) {
52
+ return;
53
+ }
54
+ e.currentTarget.parentElement?.querySelector("input")?.focus();
55
+ }}
56
+ {...props}
57
+ />
58
+ );
59
+ }
60
+
61
+ /** Render a compact icon button inside an input group. */
62
+ function InputGroupButton({
63
+ className,
64
+ type = "button",
65
+ ...props
66
+ }: Omit<ComponentProps<typeof Button>, "size" | "type"> & {
67
+ type?: "button" | "submit" | "reset";
68
+ }) {
69
+ return (
70
+ <Button
71
+ type={type}
72
+ size="icon"
73
+ className={cn("size-6", className)}
74
+ {...props}
75
+ />
76
+ );
77
+ }
78
+
79
+ /** Render the text input inside an input group. */
80
+ function InputGroupInput({
81
+ className,
82
+ ...props
83
+ }: ComponentProps<typeof Input>) {
84
+ return (
85
+ <Input
86
+ data-slot="input-group-control"
87
+ className={cn(
88
+ "h-full min-w-0 flex-1 rounded-none border-0 bg-transparent px-2 focus:ring-0",
89
+ className,
90
+ )}
91
+ {...props}
92
+ />
93
+ );
94
+ }
95
+
96
+ export { InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput };
@@ -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,60 @@
1
+ import type { ComponentProps } from "react";
2
+ import { ChevronLeftIcon, ChevronRightIcon } from "lucide-react";
3
+ import { cn } from "@dashboard/lib/utils";
4
+
5
+ import { Button } from "@dashboard/components/ui/button";
6
+
7
+ /** Mark a page control group as navigation. */
8
+ function Pagination({ className, ...props }: ComponentProps<"nav">) {
9
+ return (
10
+ <nav
11
+ role="navigation"
12
+ aria-label="Pagination"
13
+ data-slot="pagination"
14
+ className={cn("flex w-full justify-center", className)}
15
+ {...props}
16
+ />
17
+ );
18
+ }
19
+
20
+ /** Hold the page controls as a list. */
21
+ function PaginationContent({ className, ...props }: ComponentProps<"ul">) {
22
+ return (
23
+ <ul
24
+ data-slot="pagination-content"
25
+ className={cn("flex items-center gap-2", className)}
26
+ {...props}
27
+ />
28
+ );
29
+ }
30
+
31
+ /** Hold one page control. */
32
+ function PaginationItem({ ...props }: ComponentProps<"li">) {
33
+ return <li data-slot="pagination-item" {...props} />;
34
+ }
35
+
36
+ /** Go to the previous page. */
37
+ function PaginationPrevious(props: ComponentProps<typeof Button>) {
38
+ return (
39
+ <Button aria-label="Previous page" size="icon" {...props}>
40
+ <ChevronLeftIcon aria-hidden="true" size={16} />
41
+ </Button>
42
+ );
43
+ }
44
+
45
+ /** Go to the next page. */
46
+ function PaginationNext(props: ComponentProps<typeof Button>) {
47
+ return (
48
+ <Button aria-label="Next page" size="icon" {...props}>
49
+ <ChevronRightIcon aria-hidden="true" size={16} />
50
+ </Button>
51
+ );
52
+ }
53
+
54
+ export {
55
+ Pagination,
56
+ PaginationContent,
57
+ PaginationItem,
58
+ PaginationNext,
59
+ PaginationPrevious,
60
+ };