@sentry/junior-dashboard 0.248.0 → 0.250.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 (139) hide show
  1. package/README.md +3 -0
  2. package/dist/app.js +2 -2
  3. package/dist/client.js +40 -38
  4. package/dist/index.js +2 -2
  5. package/dist/tailwind.css +1 -1
  6. package/package.json +3 -3
  7. package/src/client/App.tsx +19 -5
  8. package/src/client/components/ActorAvatar.tsx +7 -4
  9. package/src/client/components/AutomationCard.tsx +2 -2
  10. package/src/client/components/Button.tsx +12 -11
  11. package/src/client/components/ConversationList.tsx +3 -3
  12. package/src/client/components/ConversationSummary.tsx +2 -1
  13. package/src/client/components/DetailList.tsx +3 -3
  14. package/src/client/components/Drawer.tsx +2 -2
  15. package/src/client/components/EmptyTelemetry.tsx +1 -1
  16. package/src/client/components/Field.tsx +1 -2
  17. package/src/client/components/FilterBar.tsx +6 -6
  18. package/src/client/components/Metric.tsx +4 -4
  19. package/src/client/components/Notice.tsx +7 -7
  20. package/src/client/components/PageContentSkeleton.tsx +2 -2
  21. package/src/client/components/Pagination.tsx +2 -2
  22. package/src/client/components/ParticipantAvatarStack.tsx +4 -4
  23. package/src/client/components/ProfileMenu.tsx +17 -7
  24. package/src/client/components/README.md +122 -58
  25. package/src/client/components/SearchInput.tsx +4 -3
  26. package/src/client/components/SegmentedNav.tsx +10 -17
  27. package/src/client/components/SegmentedTabs.tsx +3 -3
  28. package/src/client/components/Select.tsx +1 -1
  29. package/src/client/components/SelectableRow.tsx +2 -2
  30. package/src/client/components/Skeleton.tsx +1 -1
  31. package/src/client/components/StatusChip.tsx +1 -1
  32. package/src/client/components/StatusDot.tsx +1 -1
  33. package/src/client/components/TextInput.tsx +1 -1
  34. package/src/client/components/Tooltip.tsx +2 -2
  35. package/src/client/components/VersionDriftBanner.tsx +2 -2
  36. package/src/client/components/charts/ActivityChart.tsx +5 -6
  37. package/src/client/components/charts/CacheWrites.tsx +3 -3
  38. package/src/client/components/charts/ChartHeader.tsx +4 -4
  39. package/src/client/components/charts/ChartLegend.tsx +1 -1
  40. package/src/client/components/charts/InputCacheChart.tsx +5 -5
  41. package/src/client/components/charts/WorkspaceUsageChart.tsx +4 -11
  42. package/src/client/components/controls/DirectorySortSelect.tsx +2 -2
  43. package/src/client/components/directory/DirectoryMetric.tsx +2 -2
  44. package/src/client/components/directory/DirectoryRowsSkeleton.tsx +5 -5
  45. package/src/client/components/directory/DirectoryTable.tsx +3 -3
  46. package/src/client/components/layout/CardHeader.tsx +4 -4
  47. package/src/client/components/layout/DashboardChrome.tsx +9 -3
  48. package/src/client/components/layout/DashboardHeader.tsx +7 -7
  49. package/src/client/components/layout/PageHeader.tsx +2 -2
  50. package/src/client/components/layout/SecondaryNavigation.tsx +7 -14
  51. package/src/client/components/layout/SectionIntro.tsx +1 -1
  52. package/src/client/components/layout/SectionTitle.tsx +1 -1
  53. package/src/client/components/metrics/StatCard.tsx +2 -2
  54. package/src/client/conversations/ConversationArchiveNotices.tsx +1 -1
  55. package/src/client/conversations/ConversationBrief.tsx +4 -4
  56. package/src/client/conversations/ConversationChildAgents.tsx +7 -4
  57. package/src/client/conversations/ConversationComposer.tsx +8 -7
  58. package/src/client/conversations/ConversationHeader.tsx +5 -5
  59. package/src/client/conversations/ConversationHeaderActions.tsx +9 -9
  60. package/src/client/conversations/ConversationHomeList.tsx +3 -3
  61. package/src/client/conversations/ConversationListStatusIcon.tsx +1 -1
  62. package/src/client/conversations/ConversationMemories.tsx +4 -4
  63. package/src/client/conversations/ConversationMeta.tsx +10 -10
  64. package/src/client/conversations/ConversationPage.tsx +2 -1
  65. package/src/client/conversations/ConversationSidebar.tsx +6 -6
  66. package/src/client/conversations/ConversationUsageBreakdown.tsx +4 -4
  67. package/src/client/conversations/ConversationWorkspace.tsx +1 -1
  68. package/src/client/conversations/ConversationWorkspaceLoading.tsx +4 -4
  69. package/src/client/conversations/CopyMarkdownButton.tsx +1 -1
  70. package/src/client/conversations/EventUsage.tsx +2 -2
  71. package/src/client/conversations/PendingMailboxStack.tsx +5 -5
  72. package/src/client/conversations/README.md +9 -0
  73. package/src/client/conversations/SubagentTranscriptDrawer.tsx +39 -23
  74. package/src/client/conversations/ToolFrame.tsx +36 -14
  75. package/src/client/conversations/TranscriptActivityGroup.tsx +10 -3
  76. package/src/client/conversations/TranscriptAttachmentsDeliveredView.tsx +4 -6
  77. package/src/client/conversations/TranscriptContextEventView.tsx +2 -2
  78. package/src/client/conversations/TranscriptEventView.tsx +1 -1
  79. package/src/client/conversations/TranscriptMarkdown.tsx +3 -3
  80. package/src/client/conversations/TranscriptMessageContextView.tsx +7 -7
  81. package/src/client/conversations/TranscriptMessageView.tsx +2 -6
  82. package/src/client/conversations/TranscriptRailEvent.tsx +20 -8
  83. package/src/client/conversations/TranscriptReasoningView.tsx +12 -12
  84. package/src/client/conversations/TranscriptStructuredEventView.tsx +16 -11
  85. package/src/client/conversations/TranscriptSubagentView.tsx +64 -39
  86. package/src/client/conversations/TranscriptText.tsx +5 -4
  87. package/src/client/conversations/TranscriptToolView.tsx +9 -11
  88. package/src/client/conversations/TranscriptTurnContextView.tsx +3 -3
  89. package/src/client/conversations/TranscriptView.tsx +3 -3
  90. package/src/client/conversations/UsageCard.tsx +1 -1
  91. package/src/client/conversations/eventTranscript.ts +7 -0
  92. package/src/client/conversations/transcriptMarkdownLinks.ts +2 -4
  93. package/src/client/conversations/transcriptStyles.ts +1 -1
  94. package/src/client/pages/ConnectionsPage.tsx +207 -0
  95. package/src/client/pages/PersonalTokensPage.tsx +4 -4
  96. package/src/client/pages/admin/AdminPage.tsx +2 -2
  97. package/src/client/pages/automations/AutomationCostChart.tsx +2 -2
  98. package/src/client/pages/automations/AutomationDetailsDrawer.tsx +5 -10
  99. package/src/client/pages/automations/AutomationEditor.tsx +1 -1
  100. package/src/client/pages/automations/AutomationExecutionChart.tsx +2 -2
  101. package/src/client/pages/automations/AutomationExecutionStatusChart.tsx +2 -2
  102. package/src/client/pages/automations/AutomationExecutionsPage.tsx +4 -4
  103. package/src/client/pages/automations/AutomationRow.tsx +4 -4
  104. package/src/client/pages/automations/AutomationRunsPage.tsx +3 -3
  105. package/src/client/pages/automations/AutomationScheduleFields.tsx +1 -1
  106. package/src/client/pages/automations/AutomationVersionsPage.tsx +1 -1
  107. package/src/client/pages/code/CodeActivityChart.tsx +7 -6
  108. package/src/client/pages/code/CodeChangeRow.tsx +1 -1
  109. package/src/client/pages/code/CodePage.tsx +5 -5
  110. package/src/client/pages/code/RepositoryPage.tsx +2 -2
  111. package/src/client/pages/dev/ChartFixtures.tsx +265 -21
  112. package/src/client/pages/dev/ComponentsPage.tsx +40 -146
  113. package/src/client/pages/dev/TranscriptActivityFixtures.tsx +206 -0
  114. package/src/client/pages/locations/LocationDetailPage.tsx +4 -4
  115. package/src/client/pages/locations/LocationDirectory.tsx +1 -1
  116. package/src/client/pages/locations/PrivateActivityCard.tsx +3 -3
  117. package/src/client/pages/memory/MemoryCostChart.tsx +3 -5
  118. package/src/client/pages/memory/MemoryDetailsDrawer.tsx +5 -5
  119. package/src/client/pages/memory/MemoryPage.tsx +15 -15
  120. package/src/client/pages/memory/MemoryTimeline.tsx +3 -5
  121. package/src/client/pages/people/ContributionGrid.tsx +8 -5
  122. package/src/client/pages/people/PersonProfilePage.tsx +3 -6
  123. package/src/client/pages/people/ProfilePluginReports.tsx +2 -2
  124. package/src/client/pages/system/GuardianActivity.tsx +9 -9
  125. package/src/client/pages/system/PluginBarChart.tsx +4 -6
  126. package/src/client/pages/system/PluginDetails.tsx +11 -7
  127. package/src/client/pages/system/PluginPanels.tsx +8 -8
  128. package/src/client/pages/system/PluginReportRecordSet.tsx +14 -14
  129. package/src/client/pages/system/PluginReports.tsx +7 -11
  130. package/src/client/pages/system/SkillInventory.tsx +9 -9
  131. package/src/client/pages/system/SystemActivity.tsx +1 -1
  132. package/src/client/pages/system/SystemPage.tsx +3 -6
  133. package/src/client/pages/system/WorkspaceDetails.tsx +2 -5
  134. package/src/client/pages/system/WorkspaceEditor.tsx +2 -2
  135. package/src/client/pages/system/WorkspaceList.tsx +2 -2
  136. package/src/client/pages/user/PluginUserPage.tsx +3 -3
  137. package/src/client/styles.ts +5 -4
  138. package/src/client/types.ts +2 -0
  139. package/src/tailwind.css +36 -38
@@ -9,15 +9,18 @@ export function ActorAvatar(props: {
9
9
  }) {
10
10
  const [failedUrl, setFailedUrl] = useState<string>();
11
11
  const words = props.name.trim().split(/\s+/).filter(Boolean);
12
+ // The compact size fits one initial at the 12px type floor.
12
13
  const initials =
13
- words.length > 1
14
- ? `${words[0]![0]}${words.at(-1)![0]}`
15
- : props.name.slice(0, 2);
14
+ props.size === "list"
15
+ ? props.name.trim().slice(0, 1)
16
+ : words.length > 1
17
+ ? `${words[0]![0]}${words.at(-1)![0]}`
18
+ : props.name.slice(0, 2);
16
19
  return (
17
20
  <span
18
21
  aria-hidden="true"
19
22
  className={cn(
20
- "relative inline-grid shrink-0 place-items-center overflow-hidden rounded-full border-2 border-dashboard-bg bg-dashboard-focus font-sans font-bold leading-none text-dashboard-text-inverse shadow-sm",
23
+ "relative inline-grid shrink-0 place-items-center overflow-hidden rounded-full border-2 border-dashboard-bg bg-dashboard-focus font-sans font-semibold leading-none tracking-tight text-dashboard-text-inverse shadow-sm",
21
24
  props.size === "list" ? "size-6 text-2xs" : "size-7 text-xs",
22
25
  )}
23
26
  >
@@ -21,7 +21,7 @@ export function AutomationCard({
21
21
  className="my-1 w-full min-w-0 max-w-[37.5rem] overflow-hidden rounded-xl border border-dashboard-border-emphasis bg-dashboard-surface-panel text-sm"
22
22
  >
23
23
  <div className="flex items-center gap-3 px-4 pb-3 pt-4 md:px-5">
24
- <span className="grid size-9 shrink-0 place-items-center rounded-lg border border-dashboard-border bg-dashboard-fill-soft text-cyan-100">
24
+ <span className="grid size-9 shrink-0 place-items-center rounded-lg border border-dashboard-border bg-dashboard-fill-soft text-dashboard-accent-text">
25
25
  <ObjectIcon objectType="automation" status={card.status} size={18} />
26
26
  </span>
27
27
  <span className="min-w-0 flex-1 break-words text-base font-semibold text-dashboard-text">
@@ -65,7 +65,7 @@ export function AutomationCard({
65
65
  <div className="flex flex-wrap items-center justify-between gap-x-4 gap-y-2 border-t border-dashboard-border bg-dashboard-fill-faint px-4 py-3 md:px-5">
66
66
  <Link
67
67
  to={automationPath(card.id)}
68
- className="inline-flex shrink-0 items-center gap-2 rounded-sm text-xs font-medium text-cyan-100 no-underline hover:underline focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-dashboard-focus"
68
+ className="inline-flex shrink-0 items-center gap-2 rounded-sm text-xs font-medium text-dashboard-accent-text no-underline hover:underline focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-dashboard-focus"
69
69
  >
70
70
  Open automation
71
71
  <ArrowUpRight aria-hidden="true" size={14} />
@@ -18,10 +18,10 @@ export type ToggleButtonProps = ButtonHTMLAttributes<HTMLButtonElement> & {
18
18
  };
19
19
 
20
20
  const buttonClassName =
21
- "inline-flex h-9 max-w-full items-center gap-2 rounded border border-dashboard-border-emphasis bg-dashboard-surface-raised px-3 font-mono text-sm font-semibold leading-none text-dashboard-text transition-colors hover:border-dashboard-border-heavy hover:bg-dashboard-surface-hover hover:text-dashboard-text";
21
+ "inline-flex h-9 max-w-full items-center justify-center gap-2 rounded-md border border-dashboard-border-emphasis bg-dashboard-surface-raised px-3 font-sans text-sm font-medium leading-none text-dashboard-text transition-colors hover:border-dashboard-border-heavy hover:bg-dashboard-surface-hover hover:text-dashboard-text focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-dashboard-focus";
22
22
 
23
23
  const dangerButtonClassName =
24
- "inline-flex h-9 max-w-full items-center justify-center gap-1.5 rounded border border-dashboard-border-strong bg-transparent px-3 font-mono text-xs font-semibold text-dashboard-text-muted transition-colors hover:border-rose-300/40 hover:text-rose-300";
24
+ "inline-flex h-9 max-w-full items-center justify-center gap-2 rounded-md border border-dashboard-border-strong bg-transparent px-3 font-sans text-sm font-medium leading-none text-dashboard-text-muted transition-colors hover:border-rose-300/40 hover:text-rose-300 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-rose-300/55";
25
25
 
26
26
  /** Render the dashboard's standard bordered command button surface. */
27
27
  export function Button({
@@ -36,16 +36,16 @@ export function Button({
36
36
  <button
37
37
  {...props}
38
38
  className={cn(
39
- "font-mono transition-colors disabled:cursor-not-allowed disabled:opacity-50",
39
+ "font-sans transition-colors disabled:cursor-not-allowed disabled:opacity-50",
40
40
  size === "icon"
41
41
  ? cn(
42
- "grid size-9 place-items-center rounded-md border-0 bg-transparent p-0 focus-visible:outline focus-visible:outline-1 disabled:hover:!bg-transparent",
42
+ "grid size-9 place-items-center rounded-md border-0 bg-transparent p-0 focus-visible:outline-2 focus-visible:outline-offset-1 disabled:hover:!bg-transparent",
43
43
  isDanger
44
44
  ? "text-dashboard-text-muted hover:!bg-rose-300/10 hover:!text-rose-300 focus-visible:outline-rose-300/55 disabled:hover:!text-dashboard-text-muted"
45
- : "text-dashboard-text-muted hover:!bg-dashboard-fill-strong hover:!text-dashboard-text focus-visible:outline-cyan-300/55 disabled:hover:!text-dashboard-text-muted",
45
+ : "text-dashboard-text-muted hover:!bg-dashboard-fill-strong hover:!text-dashboard-text focus-visible:outline-dashboard-focus disabled:hover:!text-dashboard-text-muted",
46
46
  )
47
47
  : tone === "primary"
48
- ? "inline-flex h-9 items-center justify-center gap-2 rounded border border-dashboard-text-solid bg-dashboard-text-solid px-3 font-sans text-sm font-semibold text-dashboard-text-inverse hover:bg-dashboard-text-subtle focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-dashboard-focus"
48
+ ? "inline-flex h-9 items-center justify-center gap-2 rounded-md border border-dashboard-text-solid bg-dashboard-text-solid px-3 font-sans text-sm font-medium leading-none text-dashboard-text-inverse hover:border-dashboard-text-subtle hover:bg-dashboard-text-subtle disabled:hover:border-dashboard-text-solid disabled:hover:bg-dashboard-text-solid focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-dashboard-focus"
49
49
  : isDanger
50
50
  ? cn(
51
51
  dangerButtonClassName,
@@ -96,21 +96,22 @@ export function ToggleButton({
96
96
  }
97
97
 
98
98
  const toggleButtonBase: Record<ToggleButtonVariant, string> = {
99
- pill: "cursor-pointer rounded border px-2 py-1 font-mono text-xs font-semibold uppercase leading-tight transition-colors focus-visible:outline focus-visible:outline-1 focus-visible:outline-cyan-300/55",
99
+ pill: "cursor-pointer rounded-md border px-2 py-1 font-sans text-xs font-medium leading-tight transition-colors focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-dashboard-focus",
100
100
  segment:
101
- "h-7 min-w-10 cursor-pointer rounded border px-2 font-mono text-xs transition-colors focus-visible:outline focus-visible:outline-1 focus-visible:outline-cyan-300/55",
102
- text: "cursor-pointer border-0 bg-transparent px-1.5 py-1 font-mono uppercase tracking-normal underline-offset-4 transition-colors focus-visible:outline focus-visible:outline-1 focus-visible:outline-cyan-300/55",
101
+ "inline-flex h-7 min-w-10 cursor-pointer items-center justify-center rounded-md border px-2 font-sans text-xs font-medium transition-colors focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-dashboard-focus",
102
+ text: "cursor-pointer rounded-sm border-0 bg-transparent px-1.5 py-1 font-sans font-medium underline-offset-4 transition-colors focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-dashboard-focus",
103
103
  };
104
104
 
105
105
  const toggleButtonPressed: Record<ToggleButtonVariant, string> = {
106
106
  pill: "border-dashboard-border-heavy bg-dashboard-text-solid text-dashboard-text-inverse",
107
- segment: "border-amber-500/30 bg-amber-500/20 text-amber-400",
107
+ segment:
108
+ "border-dashboard-border-interactive bg-dashboard-surface-active text-dashboard-text",
108
109
  text: "text-dashboard-text underline decoration-dashboard-text-solid",
109
110
  };
110
111
 
111
112
  const toggleButtonIdle: Record<ToggleButtonVariant, string> = {
112
113
  pill: "border-dashboard-border-strong bg-dashboard-surface-raised text-dashboard-text-muted hover:border-dashboard-border-interactive hover:bg-dashboard-surface-hover hover:text-dashboard-text",
113
114
  segment:
114
- "border-dashboard-border-strong bg-dashboard-fill-faint text-dashboard-text-muted hover:bg-dashboard-fill-strong hover:text-dashboard-text",
115
+ "border-transparent bg-transparent text-dashboard-text-muted hover:bg-dashboard-fill-hover hover:text-dashboard-text",
115
116
  text: "text-dashboard-text-muted hover:text-dashboard-text",
116
117
  };
@@ -28,7 +28,7 @@ export function ConversationList(props: {
28
28
  return (
29
29
  <div className="min-w-0" role="table">
30
30
  <div
31
- className="sticky top-0 z-[1] grid grid-cols-[minmax(13rem,1.7fr)_minmax(13rem,1fr)] items-center gap-3 border-b border-dashboard-border-subtle bg-dashboard-overlay-soft px-3 py-2.5 font-mono text-xs uppercase tracking-[0.1em] text-dashboard-text-muted max-md:hidden"
31
+ className="sticky top-0 z-[1] grid grid-cols-[minmax(13rem,1.7fr)_minmax(13rem,1fr)] items-center gap-3 border-b border-dashboard-border-subtle bg-dashboard-overlay-soft px-3 py-2.5 font-sans font-medium text-xs text-dashboard-text-muted max-md:hidden"
32
32
  role="row"
33
33
  >
34
34
  <div>Conversation</div>
@@ -85,8 +85,8 @@ function conversationRecordClass(
85
85
  selected: boolean | undefined,
86
86
  ): string {
87
87
  return cn(
88
- "group grid min-w-0 cursor-pointer grid-cols-[minmax(13rem,1.7fr)_minmax(13rem,1fr)] items-center gap-3 overflow-hidden border-b border-b-white/[0.055] px-3 py-3 text-left text-inherit no-underline transition-colors hover:bg-white/[0.035] max-md:grid-cols-1 max-md:px-4 max-md:py-4",
88
+ "group grid min-w-0 cursor-pointer grid-cols-[minmax(13rem,1.7fr)_minmax(13rem,1fr)] items-center gap-3 overflow-hidden border-b border-b-dashboard-border-subtle px-3 py-3 text-left text-inherit no-underline transition-colors hover:bg-dashboard-fill-soft max-md:grid-cols-1 max-md:px-4 max-md:py-4",
89
89
  status === "idle" && "saturate-50",
90
- selected && "bg-cyan-400/[0.045]",
90
+ selected && "bg-dashboard-accent/[0.045]",
91
91
  );
92
92
  }
@@ -11,6 +11,7 @@ import {
11
11
  conversationParticipants,
12
12
  ParticipantAvatarStack,
13
13
  } from "./ParticipantAvatarStack";
14
+ import { cn, dashboardInlineLinkClass } from "../styles";
14
15
 
15
16
  /** Render the shared conversation title and identity. */
16
17
  export function ConversationSummary(props: { conversation: Conversation }) {
@@ -38,7 +39,7 @@ function ConversationIdentity(props: { conversation: Conversation }) {
38
39
  {location && props.conversation.locationId ? (
39
40
  <>
40
41
  <Link
41
- className="font-semibold text-dashboard-text underline decoration-white/20 underline-offset-2 transition-colors hover:text-dashboard-text hover:decoration-white/60"
42
+ className={cn("font-semibold", dashboardInlineLinkClass)}
42
43
  onClick={(event: MouseEvent<HTMLAnchorElement>) =>
43
44
  event.stopPropagation()
44
45
  }
@@ -7,7 +7,7 @@ export function DetailList(props: { children: ReactNode; className?: string }) {
7
7
  return (
8
8
  <dl
9
9
  className={cn(
10
- "grid gap-px overflow-hidden rounded border border-white/[0.06] bg-white/[0.055]",
10
+ "grid gap-px overflow-hidden rounded-md border border-dashboard-border-subtle bg-dashboard-fill-hover",
11
11
  props.className,
12
12
  )}
13
13
  >
@@ -23,8 +23,8 @@ export function Detail(props: {
23
23
  valueClassName?: string;
24
24
  }) {
25
25
  return (
26
- <div className="min-w-0 bg-[#09090b] px-3 py-3">
27
- <dt className="font-mono text-xs uppercase tracking-[0.12em] text-dashboard-text-muted">
26
+ <div className="min-w-0 bg-dashboard-bg-elevated px-3 py-3">
27
+ <dt className="font-sans font-medium text-xs text-dashboard-text-muted">
28
28
  {props.label}
29
29
  </dt>
30
30
  <dd
@@ -112,7 +112,7 @@ export function Drawer(props: {
112
112
  />
113
113
  <aside
114
114
  className={cn(
115
- "absolute top-0 right-0 grid h-full w-full grid-rows-[auto_minmax(0,1fr)] bg-dashboard-bg-elevated shadow-[-20px_0_60px_rgba(0,0,0,0.45)] md:border-l md:border-dashboard-border-emphasis",
115
+ "absolute top-0 right-0 grid h-full w-full grid-rows-[auto_minmax(0,1fr)] bg-dashboard-bg-elevated shadow-[-20px_0_60px_rgba(0,0,0,0.45)] md:border-l md:border-dashboard-border-strong",
116
116
  props.width === "wide"
117
117
  ? "md:w-[min(760px,94vw)]"
118
118
  : props.width === "narrow"
@@ -120,7 +120,7 @@ export function Drawer(props: {
120
120
  : "md:w-[min(560px,94vw)]",
121
121
  )}
122
122
  >
123
- <header className="relative grid grid-cols-[minmax(0,1fr)_auto] gap-3 border-b border-dashboard-border-strong bg-dashboard-surface-raised px-4 py-3 pt-[max(0.75rem,env(safe-area-inset-top))] md:px-5">
123
+ <header className="relative grid grid-cols-[minmax(0,1fr)_auto] gap-3 border-b border-dashboard-border bg-dashboard-bg-elevated px-4 py-3 pt-[max(0.75rem,env(safe-area-inset-top))] md:px-5">
124
124
  <div className="min-w-0">{props.header}</div>
125
125
  <div className="flex items-start gap-1.5">
126
126
  {props.actions}
@@ -3,7 +3,7 @@ import type { ReactNode } from "react";
3
3
  /** Render the dashboard empty-state block with quiet warning context. */
4
4
  export function EmptyTelemetry(props: { children: ReactNode }) {
5
5
  return (
6
- <div className="min-w-0 rounded-lg border border-white/10 bg-[#050505] px-4 py-3 text-base leading-relaxed text-dashboard-text-muted">
6
+ <div className="min-w-0 rounded-lg border border-dashboard-border-strong bg-dashboard-bg px-4 py-3 text-base leading-relaxed text-dashboard-text-muted">
7
7
  {props.children}
8
8
  </div>
9
9
  );
@@ -5,8 +5,7 @@ import { cn } from "../styles";
5
5
  export type FieldSize = "compact" | "default";
6
6
 
7
7
  const labelClass: Record<FieldSize, string> = {
8
- compact:
9
- "font-mono text-xs uppercase tracking-[0.12em] text-dashboard-text-muted",
8
+ compact: "font-sans font-medium text-xs text-dashboard-text-muted",
10
9
  default: "text-sm font-semibold text-dashboard-text",
11
10
  };
12
11
 
@@ -41,7 +41,7 @@ export function FilterGroup(props: {
41
41
  }) {
42
42
  return (
43
43
  <div className={cn("min-w-0", props.className)}>
44
- <div className="mb-2 font-mono text-xs uppercase tracking-[0.12em] text-dashboard-text-muted">
44
+ <div className="mb-2 font-sans font-medium text-xs text-dashboard-text-muted">
45
45
  {props.label}
46
46
  </div>
47
47
  <div
@@ -71,7 +71,7 @@ export function FilterTabList(props: {
71
71
  return (
72
72
  <div
73
73
  aria-label={props.ariaLabel}
74
- className="grid min-w-0 grid-cols-3 gap-1 border-b border-white/[0.06] sm:flex sm:overflow-x-auto"
74
+ className="grid min-w-0 grid-cols-3 gap-1 border-b border-dashboard-border-subtle sm:flex sm:overflow-x-auto"
75
75
  role="tablist"
76
76
  >
77
77
  {props.items.map((item) => {
@@ -80,9 +80,9 @@ export function FilterTabList(props: {
80
80
  <button
81
81
  aria-selected={selected}
82
82
  className={cn(
83
- "relative flex min-w-0 cursor-pointer items-center justify-between gap-2 border-0 bg-transparent px-3 py-2.5 font-mono text-xs uppercase tracking-[0.1em] transition-colors after:absolute after:inset-x-2 after:bottom-0 after:h-px sm:shrink-0 sm:justify-start",
83
+ "relative flex min-w-0 cursor-pointer items-center justify-between gap-2 border-0 bg-transparent px-3 py-2.5 font-sans font-medium text-xs transition-colors after:absolute after:inset-x-2 after:bottom-0 after:h-px sm:shrink-0 sm:justify-start",
84
84
  selected
85
- ? "text-cyan-100 after:bg-cyan-300"
85
+ ? "text-dashboard-accent-text after:bg-dashboard-accent"
86
86
  : "text-dashboard-text-muted after:bg-transparent hover:text-dashboard-text",
87
87
  )}
88
88
  key={item.value || "all"}
@@ -96,8 +96,8 @@ export function FilterTabList(props: {
96
96
  className={cn(
97
97
  "rounded-sm border px-1.5 py-0.5 text-xs",
98
98
  selected
99
- ? "border-cyan-300/20 bg-cyan-300/10 text-cyan-100"
100
- : "border-white/[0.07] bg-white/[0.025] text-dashboard-text-muted",
99
+ ? "border-dashboard-accent/20 bg-dashboard-accent/10 text-dashboard-accent-text"
100
+ : "border-dashboard-border bg-dashboard-fill-soft text-dashboard-text-muted",
101
101
  )}
102
102
  >
103
103
  {item.count.toLocaleString("en-US")}
@@ -28,10 +28,10 @@ function TooltipLines(props: { lines: MetricTooltipLine[] }) {
28
28
  : cn(
29
29
  "col-span-2 block min-w-0 break-words text-dashboard-text",
30
30
  line.valueStyle === "heading" &&
31
- "font-mono font-semibold text-dashboard-text",
31
+ "font-sans tabular-nums font-semibold text-dashboard-text",
32
32
  line.valueStyle === "heading" &&
33
33
  index > 0 &&
34
- "mt-1 border-t border-white/10 pt-2",
34
+ "mt-1 border-t border-dashboard-border-strong pt-2",
35
35
  )
36
36
  }
37
37
  key={`${index}-${line.label ?? ""}-${line.value}-${line.live ? "live" : ""}`}
@@ -88,7 +88,7 @@ export function MetricValue(props: {
88
88
  <Tooltip
89
89
  align={props.align}
90
90
  className={cn(
91
- "w-[calc(100vw-2rem)] max-w-80 rounded-lg border border-white/15 bg-[#050505] text-left text-xs font-normal text-dashboard-text-muted shadow-xl shadow-black/35",
91
+ "w-[calc(100vw-2rem)] max-w-80 rounded-lg border border-dashboard-border-emphasis bg-dashboard-bg text-left text-xs font-normal text-dashboard-text-muted shadow-xl shadow-black/35",
92
92
  props.tooltipCard ? "p-3 leading-snug" : "px-3 py-2 leading-relaxed",
93
93
  )}
94
94
  content={
@@ -106,7 +106,7 @@ export function MetricValue(props: {
106
106
  >
107
107
  <span
108
108
  className={cn(
109
- "inline-flex border-b border-dotted border-white/20 outline-none transition-colors hover:border-white/45 focus-visible:border-white/45",
109
+ "inline-flex border-b border-dotted border-dashboard-border-interactive outline-none transition-colors hover:border-dashboard-border-heavy focus-visible:border-dashboard-border-heavy",
110
110
  props.className,
111
111
  )}
112
112
  tabIndex={0}
@@ -31,8 +31,8 @@ export function Notice({
31
31
  return (
32
32
  <div
33
33
  className={cn(
34
- "overflow-hidden rounded-xl shadow-[0_16px_40px_rgba(0,0,0,0.5)]",
35
- isError ? "bg-[#1f1216]" : "bg-[#111719]",
34
+ "overflow-hidden rounded-xl border bg-dashboard-surface-raised shadow-[0_16px_40px_rgba(0,0,0,0.5)]",
35
+ isError ? "border-rose-300/25" : "border-dashboard-border-strong",
36
36
  )}
37
37
  >
38
38
  <div className="flex min-w-0 items-center gap-3 px-3 py-3">
@@ -42,7 +42,7 @@ export function Notice({
42
42
  "grid size-8 shrink-0 place-items-center rounded-lg",
43
43
  isError
44
44
  ? "bg-rose-300/15 text-rose-100"
45
- : "bg-cyan-300/10 text-cyan-100/80",
45
+ : "bg-dashboard-accent/10 text-dashboard-accent-text/80",
46
46
  )}
47
47
  >
48
48
  <Icon aria-hidden="true" size={16} />
@@ -61,7 +61,7 @@ export function Notice({
61
61
  {detail ? (
62
62
  <div
63
63
  className={cn(
64
- "mt-0.5 truncate font-mono text-xs",
64
+ "mt-0.5 truncate font-sans text-xs",
65
65
  isError ? "text-rose-100/70" : "text-dashboard-text-muted",
66
66
  )}
67
67
  >
@@ -89,10 +89,10 @@ export function NoticeAction({
89
89
  {...props}
90
90
  className={cn(
91
91
  "shrink-0 cursor-pointer px-3 py-1.5 text-xs transition focus:outline-none focus:ring-2 disabled:cursor-not-allowed disabled:opacity-40",
92
- isError ? "focus:ring-rose-300/40" : "focus:ring-cyan-300/35",
92
+ isError ? "focus:ring-rose-300/40" : "focus:ring-dashboard-focus/35",
93
93
  isError
94
- ? "rounded-lg bg-rose-200/15 font-display font-medium text-rose-50 hover:bg-rose-200/25"
95
- : "rounded-lg bg-cyan-200/10 font-display font-medium text-cyan-100 hover:bg-cyan-200/20",
94
+ ? "rounded-lg bg-rose-200/15 font-sans font-medium text-rose-50 hover:bg-rose-200/25"
95
+ : "rounded-lg bg-dashboard-accent/10 font-sans font-medium text-dashboard-accent-text hover:bg-dashboard-accent/20",
96
96
  className,
97
97
  )}
98
98
  type={type}
@@ -96,7 +96,7 @@ function LibrarySkeleton() {
96
96
  return (
97
97
  <>
98
98
  <div className="flex flex-wrap items-end justify-between gap-4">
99
- <SkeletonBone className="h-7 w-56 rounded bg-dashboard-fill-soft" />
99
+ <SkeletonBone className="h-7 w-56 rounded-md bg-dashboard-fill-soft" />
100
100
  <SkeletonBone className="h-10 w-full max-w-md rounded-lg border border-dashboard-border-subtle bg-dashboard-fill-faint sm:w-72" />
101
101
  </div>
102
102
  <div
@@ -108,7 +108,7 @@ function LibrarySkeleton() {
108
108
  className="flex items-center justify-between gap-2 px-3 py-2.5 sm:justify-start"
109
109
  key={index}
110
110
  >
111
- <SkeletonBone className="h-3 w-12 rounded bg-dashboard-fill-soft" />
111
+ <SkeletonBone className="h-3 w-12 rounded-md bg-dashboard-fill-soft" />
112
112
  <SkeletonBone className="h-5 w-8 rounded-sm border border-dashboard-border-subtle bg-dashboard-fill-faint" />
113
113
  </div>
114
114
  ))}
@@ -61,7 +61,7 @@ export function PagePagination(props: {
61
61
  props.className,
62
62
  )}
63
63
  >
64
- <p className="m-0 font-mono text-xs text-dashboard-text-muted">
64
+ <p className="m-0 font-sans tabular-nums text-xs text-dashboard-text-muted">
65
65
  Showing {start.toLocaleString("en-US")}-{end.toLocaleString("en-US")} of{" "}
66
66
  {props.total.toLocaleString("en-US")}
67
67
  </p>
@@ -74,7 +74,7 @@ export function PagePagination(props: {
74
74
  >
75
75
  <ChevronLeft aria-hidden="true" size={16} />
76
76
  </Button>
77
- <span className="min-w-16 text-center font-mono text-xs text-dashboard-text-muted">
77
+ <span className="min-w-16 text-center font-sans tabular-nums text-xs text-dashboard-text-muted">
78
78
  {current} / {props.pageCount}
79
79
  </span>
80
80
  <Button
@@ -45,7 +45,7 @@ function ParticipantTooltipContent(props: { participant: ActorIdentity }) {
45
45
  <span className="grid gap-0.5 font-sans">
46
46
  <span className="font-semibold text-dashboard-text">{name}</span>
47
47
  {email && email !== name ? (
48
- <span className="font-mono text-dashboard-text-muted">{email}</span>
48
+ <span className="font-sans text-dashboard-text-muted">{email}</span>
49
49
  ) : null}
50
50
  </span>
51
51
  );
@@ -60,7 +60,7 @@ function Avatar(props: {
60
60
  <Tooltip
61
61
  content={<ParticipantTooltipContent participant={props.participant} />}
62
62
  focusable
63
- triggerClassName="-ml-1.5 first:ml-0 pointer-events-none [@media(hover:hover)_and_(pointer:fine)]:pointer-events-auto"
63
+ triggerClassName="-ml-1 first:ml-0 pointer-events-none [@media(hover:hover)_and_(pointer:fine)]:pointer-events-auto"
64
64
  >
65
65
  <span
66
66
  aria-label={label}
@@ -116,14 +116,14 @@ export function ParticipantAvatarStack(props: ParticipantAvatarStackProps) {
116
116
  </span>
117
117
  }
118
118
  focusable
119
- triggerClassName="-ml-1.5 pointer-events-none [@media(hover:hover)_and_(pointer:fine)]:pointer-events-auto"
119
+ triggerClassName="-ml-1 pointer-events-none [@media(hover:hover)_and_(pointer:fine)]:pointer-events-auto"
120
120
  >
121
121
  <span
122
122
  aria-label={`${hidden.length} more participants: ${hidden
123
123
  .map(participantDescription)
124
124
  .join("; ")}`}
125
125
  className={cn(
126
- "relative inline-grid shrink-0 place-items-center rounded-full border-2 border-dashboard-bg bg-dashboard-fill-strong font-mono font-semibold leading-none text-dashboard-text-muted focus-visible:z-10 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-dashboard-focus",
126
+ "relative inline-grid shrink-0 place-items-center rounded-full border-2 border-dashboard-bg bg-dashboard-surface-active font-sans font-semibold tabular-nums leading-none text-dashboard-text-muted focus-visible:z-10 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-dashboard-focus",
127
127
  props.size === "list" ? "size-6 text-2xs" : "size-7 text-xs",
128
128
  )}
129
129
  onKeyDown={(event) => event.stopPropagation()}
@@ -3,6 +3,7 @@ import {
3
3
  ChevronDown,
4
4
  KeyRound,
5
5
  LogOut,
6
+ Plug,
6
7
  Settings,
7
8
  ShieldCheck,
8
9
  UserRound,
@@ -155,7 +156,7 @@ export function ProfileMenu({
155
156
  ) : null}
156
157
  </div>
157
158
  </div>
158
- <div className="mt-2 flex flex-wrap items-center gap-x-3 gap-y-1 font-mono text-xs tabular-nums text-dashboard-text-muted">
159
+ <div className="mt-2 flex flex-wrap items-center gap-x-3 gap-y-1 font-sans text-xs tabular-nums text-dashboard-text-muted">
159
160
  <span>
160
161
  7d{" "}
161
162
  <span className="font-semibold text-dashboard-text">
@@ -194,6 +195,14 @@ export function ProfileMenu({
194
195
  <KeyRound aria-hidden="true" size={16} strokeWidth={2} />
195
196
  API tokens
196
197
  </Link>
198
+ <Link
199
+ className={profileLinkClass}
200
+ onClick={close}
201
+ to="/settings/connections"
202
+ >
203
+ <Plug aria-hidden="true" size={16} strokeWidth={2} />
204
+ Connected accounts
205
+ </Link>
197
206
  {identity.user.isAdmin ? (
198
207
  <Link className={profileLinkClass} onClick={close} to="/admin">
199
208
  <ShieldCheck aria-hidden="true" size={16} strokeWidth={2} />
@@ -230,11 +239,9 @@ export function ProfileMenu({
230
239
  return (
231
240
  <div
232
241
  aria-label={`Personal model spend: 7 days ${sevenDaySpend}, 30 days ${thirtyDaySpend}`}
233
- className="grid gap-1.5 rounded-lg border border-dashboard-border bg-dashboard-fill-soft px-3 py-2.5 font-mono text-xs tabular-nums text-dashboard-text-muted"
242
+ className="grid gap-1.5 rounded-lg border border-dashboard-border bg-dashboard-fill-soft px-3 py-2.5 font-sans text-xs tabular-nums text-dashboard-text-muted"
234
243
  >
235
- <span className="text-xs font-medium uppercase tracking-[0.08em]">
236
- Spend
237
- </span>
244
+ <span className="text-xs font-medium">Spend</span>
238
245
  <span className="whitespace-nowrap">
239
246
  7d{" "}
240
247
  <span className="font-semibold text-dashboard-text">
@@ -254,7 +261,7 @@ export function ProfileMenu({
254
261
  if (variant === "sheet-links") {
255
262
  // Match primary sheet rows exactly.
256
263
  const sheetItemClass = cn(
257
- "rounded-lg border-0 bg-transparent px-3 py-3 text-left font-mono text-sm font-medium tracking-normal no-underline transition-colors hover:bg-dashboard-fill-soft focus-visible:bg-dashboard-fill-soft focus-visible:outline-none",
264
+ "rounded-lg border-0 bg-transparent px-3 py-3 text-left font-sans text-sm font-medium no-underline transition-colors hover:bg-dashboard-fill-soft focus-visible:bg-dashboard-fill-soft focus-visible:outline-none",
258
265
  dashboardInteractiveTextClass,
259
266
  );
260
267
  return (
@@ -268,6 +275,9 @@ export function ProfileMenu({
268
275
  <Link className={sheetItemClass} to="/settings/api-tokens">
269
276
  API tokens
270
277
  </Link>
278
+ <Link className={sheetItemClass} to="/settings/connections">
279
+ Connected accounts
280
+ </Link>
271
281
  {identity.user.isAdmin ? (
272
282
  <Link className={sheetItemClass} to="/admin">
273
283
  Admin
@@ -313,7 +323,7 @@ export function ProfileMenu({
313
323
  {name}
314
324
  </p>
315
325
  {name !== email ? (
316
- <p className="mt-0.5 mb-0 truncate font-mono text-xs text-dashboard-text-muted">
326
+ <p className="mt-0.5 mb-0 truncate font-sans text-xs text-dashboard-text-muted">
317
327
  {email}
318
328
  </p>
319
329
  ) : null}