@sentry/junior-dashboard 0.263.0 → 0.265.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (197) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +2 -5
  3. package/dist/app.js +119 -35
  4. package/dist/client.js +148 -135
  5. package/dist/index.d.ts +0 -1
  6. package/dist/index.js +119 -35
  7. package/dist/tailwind.css +1 -1
  8. package/package.json +9 -4
  9. package/src/api/schema.ts +0 -1
  10. package/src/app.ts +5 -20
  11. package/src/client/App.tsx +29 -31
  12. package/src/client/api.ts +7 -0
  13. package/src/client/components/BottomSheet.tsx +26 -18
  14. package/src/client/components/CopyButton.tsx +83 -0
  15. package/src/client/components/DetailsPanel.tsx +133 -0
  16. package/src/client/components/Drawer.tsx +34 -33
  17. package/src/client/components/FilterBar.tsx +16 -31
  18. package/src/client/components/Metric.tsx +33 -23
  19. package/src/client/components/PageContentSkeleton.tsx +1 -1
  20. package/src/client/components/Pagination.tsx +1 -1
  21. package/src/client/components/ParticipantAvatarStack.tsx +40 -36
  22. package/src/client/components/ProfileMenu.tsx +27 -93
  23. package/src/client/components/README.md +101 -64
  24. package/src/client/components/SegmentedNav.tsx +1 -1
  25. package/src/client/components/ShimmerText.tsx +2 -6
  26. package/src/client/components/ThemeSwitcher.tsx +19 -15
  27. package/src/client/components/charts/ActivityChart.tsx +173 -288
  28. package/src/client/components/charts/CacheWrites.tsx +63 -50
  29. package/src/client/components/charts/InputCacheChart.tsx +137 -131
  30. package/src/client/components/charts/README.md +4 -4
  31. package/src/client/components/charts/SystemMetricCharts.tsx +68 -95
  32. package/src/client/components/charts/WorkspaceUsageChart.tsx +42 -62
  33. package/src/client/components/controls/DirectorySortSelect.tsx +3 -3
  34. package/src/client/components/controls/TimeRangeSelector.tsx +10 -15
  35. package/src/client/components/layout/DashboardHeader.tsx +44 -90
  36. package/src/client/components/layout/SecondaryNavigation.tsx +2 -1
  37. package/src/client/components/layout/VisualViewportShell.tsx +2 -2
  38. package/src/client/components/ui/accordion.tsx +77 -0
  39. package/src/client/components/ui/alert-dialog.tsx +89 -0
  40. package/src/client/components/ui/button.tsx +85 -0
  41. package/src/client/components/ui/chart.tsx +74 -0
  42. package/src/client/components/ui/checkbox.tsx +26 -0
  43. package/src/client/components/ui/collapsible.tsx +22 -0
  44. package/src/client/components/ui/field.tsx +49 -0
  45. package/src/client/components/ui/input.tsx +35 -0
  46. package/src/client/components/ui/native-select.tsx +57 -0
  47. package/src/client/components/ui/popover.tsx +67 -0
  48. package/src/client/components/ui/radio-group.tsx +32 -0
  49. package/src/client/components/ui/sheet.tsx +151 -0
  50. package/src/client/components/ui/skeleton.tsx +19 -0
  51. package/src/client/components/ui/table.tsx +80 -0
  52. package/src/client/components/ui/tabs.tsx +75 -0
  53. package/src/client/components/ui/textarea.tsx +17 -0
  54. package/src/client/components/ui/toast.tsx +215 -0
  55. package/src/client/components/ui/toggle-group.tsx +36 -0
  56. package/src/client/components/ui/toggle.tsx +37 -0
  57. package/src/client/components/ui/tooltip.tsx +168 -0
  58. package/src/client/components/ui/trace.tsx +96 -0
  59. package/src/client/components/ui/useSheet.ts +74 -0
  60. package/src/client/conversations/ChatLayout.tsx +7 -3
  61. package/src/client/conversations/ConversationBrief.tsx +17 -6
  62. package/src/client/conversations/ConversationChildAgents.tsx +87 -58
  63. package/src/client/conversations/ConversationComposer.tsx +26 -12
  64. package/src/client/conversations/ConversationDetails.tsx +198 -95
  65. package/src/client/conversations/ConversationEventDetails.tsx +141 -0
  66. package/src/client/conversations/ConversationEventLog.tsx +150 -129
  67. package/src/client/conversations/ConversationHeader.tsx +8 -3
  68. package/src/client/conversations/ConversationHeaderActions.tsx +90 -82
  69. package/src/client/conversations/ConversationHomeList.tsx +1 -1
  70. package/src/client/conversations/ConversationLinkedWork.tsx +118 -0
  71. package/src/client/conversations/ConversationMeta.tsx +111 -92
  72. package/src/client/conversations/ConversationPage.tsx +241 -110
  73. package/src/client/conversations/ConversationSidebar.tsx +48 -29
  74. package/src/client/conversations/ConversationUsageBreakdown.tsx +16 -3
  75. package/src/client/conversations/ConversationWatches.tsx +165 -0
  76. package/src/client/conversations/ConversationWorkspace.tsx +12 -22
  77. package/src/client/conversations/ConversationWorkspaceLoading.tsx +1 -1
  78. package/src/client/conversations/DetailsList.tsx +124 -0
  79. package/src/client/conversations/EventDetails.tsx +42 -8
  80. package/src/client/conversations/ForkConversationButton.tsx +27 -16
  81. package/src/client/conversations/ObjectCard.tsx +20 -8
  82. package/src/client/conversations/PendingMailboxStack.tsx +52 -33
  83. package/src/client/conversations/README.md +93 -19
  84. package/src/client/conversations/ShareConversationButton.tsx +28 -3
  85. package/src/client/conversations/SubagentTranscriptDrawer.tsx +21 -15
  86. package/src/client/conversations/ToolFrame.tsx +36 -52
  87. package/src/client/conversations/TranscriptActivityGroup.tsx +13 -4
  88. package/src/client/conversations/TranscriptAutomationTriggerView.tsx +5 -4
  89. package/src/client/conversations/TranscriptContextEventView.tsx +25 -11
  90. package/src/client/conversations/TranscriptHeadingRow.tsx +7 -7
  91. package/src/client/conversations/TranscriptLoading.tsx +1 -1
  92. package/src/client/conversations/TranscriptMarkdown.tsx +25 -20
  93. package/src/client/conversations/TranscriptMessageContextView.tsx +8 -2
  94. package/src/client/conversations/TranscriptMessageView.tsx +6 -1
  95. package/src/client/conversations/TranscriptReasoningView.tsx +54 -68
  96. package/src/client/conversations/TranscriptSubagentView.tsx +3 -3
  97. package/src/client/conversations/TranscriptTimestamp.tsx +9 -7
  98. package/src/client/conversations/TranscriptToolView.tsx +1 -1
  99. package/src/client/conversations/TranscriptTurnContextView.tsx +99 -27
  100. package/src/client/conversations/TranscriptView.tsx +63 -27
  101. package/src/client/conversations/eventLog.ts +57 -0
  102. package/src/client/conversations/eventTime.ts +60 -0
  103. package/src/client/conversations/queries.ts +29 -0
  104. package/src/client/conversations/transcriptBottomPinning.ts +34 -0
  105. package/src/client/format.ts +5 -0
  106. package/src/client/lib/utils.ts +1 -0
  107. package/src/client/pages/ConnectionsPage.tsx +2 -2
  108. package/src/client/pages/PersonalTokensPage.tsx +4 -4
  109. package/src/client/pages/SettingsPage.tsx +9 -10
  110. package/src/client/pages/admin/ServiceAccountsSection.tsx +2 -2
  111. package/src/client/pages/automations/AutomationCostChart.tsx +50 -71
  112. package/src/client/pages/automations/AutomationDeleteDialog.tsx +87 -0
  113. package/src/client/pages/automations/AutomationDetails.tsx +193 -0
  114. package/src/client/pages/automations/AutomationEditPage.tsx +7 -8
  115. package/src/client/pages/automations/AutomationEditor.tsx +41 -29
  116. package/src/client/pages/automations/AutomationEditorLoading.tsx +1 -1
  117. package/src/client/pages/automations/AutomationEventFields.tsx +202 -119
  118. package/src/client/pages/automations/AutomationExecutionChart.tsx +51 -64
  119. package/src/client/pages/automations/AutomationExecutionStatusChart.tsx +47 -70
  120. package/src/client/pages/automations/AutomationExecutionsPage.tsx +150 -126
  121. package/src/client/pages/automations/AutomationFilters.tsx +189 -74
  122. package/src/client/pages/automations/AutomationLifecycle.tsx +109 -78
  123. package/src/client/pages/automations/AutomationOutcomeFields.tsx +26 -24
  124. package/src/client/pages/automations/AutomationRecentRuns.tsx +143 -0
  125. package/src/client/pages/automations/AutomationRow.tsx +12 -138
  126. package/src/client/pages/automations/AutomationRunDetails.tsx +307 -0
  127. package/src/client/pages/automations/AutomationRunsPage.tsx +119 -94
  128. package/src/client/pages/automations/AutomationScheduleFields.tsx +51 -51
  129. package/src/client/pages/automations/AutomationStatus.tsx +201 -0
  130. package/src/client/pages/automations/AutomationVersionsPage.tsx +65 -28
  131. package/src/client/pages/automations/AutomationsPage.tsx +80 -68
  132. package/src/client/pages/automations/AutomationsPageLayout.tsx +46 -14
  133. package/src/client/pages/automations/README.md +57 -0
  134. package/src/client/pages/automations/TriggerFilters.tsx +22 -0
  135. package/src/client/pages/automations/automationFormat.ts +37 -23
  136. package/src/client/pages/code/CodeActivityChart.tsx +59 -101
  137. package/src/client/pages/code/CodePage.tsx +52 -55
  138. package/src/client/pages/code/RepositoryPage.tsx +6 -8
  139. package/src/client/pages/locations/LocationActivityChart.tsx +53 -70
  140. package/src/client/pages/locations/LocationDirectoryActivityChart.tsx +60 -80
  141. package/src/client/pages/memory/MemoryCostChart.tsx +79 -103
  142. package/src/client/pages/memory/MemoryDetails.tsx +218 -0
  143. package/src/client/pages/memory/MemoryPage.tsx +168 -112
  144. package/src/client/pages/memory/MemoryPageLayout.tsx +33 -9
  145. package/src/client/pages/memory/MemoryTimeline.tsx +46 -69
  146. package/src/client/pages/memory/memoryRecord.ts +1 -1
  147. package/src/client/pages/people/ContributionGrid.tsx +23 -16
  148. package/src/client/pages/people/PeopleActivityChart.tsx +68 -107
  149. package/src/client/pages/people/ProfileCodeChanges.tsx +5 -5
  150. package/src/client/pages/system/BaseSandboxCard.tsx +1 -1
  151. package/src/client/pages/system/ConversationActivityChart.tsx +49 -67
  152. package/src/client/pages/system/GuardianActivity.tsx +1 -2
  153. package/src/client/pages/system/PluginBarChart.tsx +106 -87
  154. package/src/client/pages/system/PluginReportRecordSet.tsx +25 -24
  155. package/src/client/pages/system/README.md +23 -0
  156. package/src/client/pages/system/SystemNavigation.tsx +5 -1
  157. package/src/client/pages/system/WorkspaceDeleteDialog.tsx +111 -0
  158. package/src/client/pages/system/WorkspaceDetails.tsx +200 -43
  159. package/src/client/pages/system/WorkspaceEditor.tsx +59 -61
  160. package/src/client/pages/system/WorkspaceFormPage.tsx +23 -47
  161. package/src/client/pages/system/WorkspaceList.tsx +20 -30
  162. package/src/client/pages/system/WorkspacesPage.tsx +117 -119
  163. package/src/client/pages/system/sandboxSize.ts +8 -0
  164. package/src/client/pages/system/workspaceQueries.ts +53 -0
  165. package/src/client/pages/user/PluginUserPage.tsx +51 -2
  166. package/src/client/pages/user/pluginUserPageData.ts +1 -6
  167. package/src/client/styles.ts +4 -0
  168. package/src/client.tsx +7 -1
  169. package/src/mock-reporting/automation-collection.ts +4 -2
  170. package/src/mock-reporting/fixtures.ts +23 -7
  171. package/src/mock-reporting/routes.ts +12 -0
  172. package/src/mock-reporting/watches.ts +94 -0
  173. package/src/shell.ts +4 -9
  174. package/src/tailwind.css +77 -10
  175. package/src/client/components/Button.tsx +0 -118
  176. package/src/client/components/Field.tsx +0 -53
  177. package/src/client/components/SegmentedTabs.tsx +0 -119
  178. package/src/client/components/Select.tsx +0 -52
  179. package/src/client/components/Sheet.LICENSE +0 -21
  180. package/src/client/components/Sheet.tsx +0 -141
  181. package/src/client/components/Skeleton.tsx +0 -17
  182. package/src/client/components/TextInput.tsx +0 -58
  183. package/src/client/components/Tooltip.tsx +0 -216
  184. package/src/client/components/charts/useChartLayout.ts +0 -27
  185. package/src/client/conversations/ConversationDetailsFrame.tsx +0 -91
  186. package/src/client/conversations/CopyMarkdownButton.tsx +0 -65
  187. package/src/client/pages/automations/AutomationDetailsDrawer.tsx +0 -219
  188. package/src/client/pages/dev/ChartFixtures.tsx +0 -325
  189. package/src/client/pages/dev/ComponentsPage.tsx +0 -899
  190. package/src/client/pages/dev/ConversationFixture.tsx +0 -231
  191. package/src/client/pages/dev/ObjectFixtures.tsx +0 -138
  192. package/src/client/pages/dev/SegmentedFixtures.tsx +0 -59
  193. package/src/client/pages/dev/SelectFixtures.tsx +0 -62
  194. package/src/client/pages/dev/TranscriptActivityFixtures.tsx +0 -206
  195. package/src/client/pages/memory/MemoryDetailsDrawer.tsx +0 -167
  196. package/src/client/pages/system/SandboxSizeSummary.tsx +0 -47
  197. package/src/client/pages/system/SnapshotSummary.tsx +0 -78
@@ -4,19 +4,19 @@ import {
4
4
  } from "../../components/controls/TimeRangeSelector";
5
5
  import type { DailyConversationActivity } from "@sentry/junior/api/schema";
6
6
 
7
+ import { Bar, BarChart, CartesianGrid } from "recharts";
7
8
  import {
8
9
  ActivityChartAverageLine,
9
- ActivityChartDateLabels,
10
- ActivityChartGrid,
11
10
  activityChartAverage,
12
- ActivityChartTooltip,
13
- ActivityTooltipRows,
14
- ChartSvg,
15
- createActivityChartLayout,
11
+ activityChartMargin,
12
+ ActivityChartTooltipContent,
13
+ ActivityChartXAxis,
14
+ ActivityChartYAxis,
16
15
  } from "../../components/charts/ActivityChart";
17
16
  import { ChartLegend } from "../../components/charts/ChartLegend";
18
17
  import { Card } from "../../components/layout/Card";
19
18
  import { CardHeader } from "../../components/layout/CardHeader";
19
+ import { ChartContainer, ChartTooltip } from "../../components/ui/chart";
20
20
  import { formatActivityChartAverage } from "../../format";
21
21
 
22
22
  /** Plot daily conversation volume across one public location. */
@@ -27,12 +27,9 @@ export function LocationActivityChart(props: {
27
27
  }) {
28
28
  const bucketUnit = props.bucketUnit ?? "day";
29
29
 
30
- const layout = createActivityChartLayout(240);
31
30
  const values = props.days.map((day) => day.conversations);
32
31
  const maximum = Math.max(1, ...values);
33
32
  const average = activityChartAverage(values);
34
- const step = layout.plotWidth / Math.max(1, props.days.length);
35
- const barWidth = Math.max(4, Math.min(20, step * 0.55));
36
33
 
37
34
  return (
38
35
  <Card>
@@ -54,68 +51,54 @@ export function LocationActivityChart(props: {
54
51
  }
55
52
  />
56
53
  <div className="px-2 py-3 sm:px-4 sm:py-4">
57
- <ChartSvg
58
- aria-label="Daily conversations for this location"
59
- className="min-h-52 w-full overflow-visible"
60
- layout={layout}
61
- >
62
- <defs>
63
- <linearGradient id="location-bars" x1="0" x2="0" y1="0" y2="1">
64
- <stop offset="0%" stopColor="var(--color-cyan-400)" />
65
- <stop
66
- offset="100%"
67
- stopColor="var(--color-amber-500)"
68
- stopOpacity="0.65"
69
- />
70
- </linearGradient>
71
- </defs>
72
- <ActivityChartGrid layout={layout} maximum={maximum} />
73
- {props.days.map((day, index) => {
74
- const barHeight = (day.conversations / maximum) * layout.plotHeight;
75
- const x = layout.left + index * step + (step - barWidth) / 2;
76
- const y = layout.top + layout.plotHeight - barHeight;
77
- return (
78
- <ActivityChartTooltip
79
- key={day.date}
80
- content={
81
- <ActivityTooltipRows
82
- rows={[
83
- ["conversations", day.conversations],
84
- ["active", day.active],
85
- ["failed", day.failed],
86
- ]}
87
- />
88
- }
89
- date={day.date}
90
- summary={`${day.conversations} conversations, ${day.active} active, ${day.failed} failed`}
91
- >
92
- <rect
93
- fill="url(#location-bars)"
94
- height={Math.max(day.conversations ? 2 : 0, barHeight)}
95
- opacity={day.conversations ? 0.9 : 0.18}
96
- rx="2"
97
- tabIndex={0}
98
- width={barWidth}
99
- x={x}
100
- y={y}
54
+ <ChartContainer className="aspect-auto h-60 w-full" config={{}}>
55
+ <BarChart
56
+ aria-label="Daily conversations for this location"
57
+ data={props.days}
58
+ margin={activityChartMargin}
59
+ role="img"
60
+ >
61
+ <defs>
62
+ <linearGradient id="location-bars" x1="0" x2="0" y1="0" y2="1">
63
+ <stop offset="0%" stopColor="var(--color-cyan-400)" />
64
+ <stop
65
+ offset="100%"
66
+ stopColor="var(--color-amber-500)"
67
+ stopOpacity="0.65"
101
68
  />
102
- </ActivityChartTooltip>
103
- );
104
- })}
105
- <ActivityChartAverageLine
106
- unit={timeRangeBucketAverageUnit(bucketUnit)}
107
- average={average}
108
- format={formatActivityChartAverage}
109
- layout={layout}
110
- maximum={maximum}
111
- stroke="var(--color-cyan-400)"
112
- />
113
- <ActivityChartDateLabels
114
- dates={props.days.map((day) => day.date)}
115
- layout={layout}
116
- xPosition={(index) => layout.left + index * step + step / 2}
117
- />
118
- </ChartSvg>
69
+ </linearGradient>
70
+ </defs>
71
+ <CartesianGrid strokeDasharray="3 5" vertical={false} />
72
+ <ActivityChartYAxis maximum={maximum} />
73
+ <ActivityChartXAxis keys={props.days.map((day) => day.date)} />
74
+ <ChartTooltip
75
+ content={
76
+ <ActivityChartTooltipContent
77
+ rows={(day: DailyConversationActivity) => [
78
+ ["conversations", day.conversations],
79
+ ["active", day.active],
80
+ ["failed", day.failed],
81
+ ]}
82
+ />
83
+ }
84
+ />
85
+ <Bar
86
+ dataKey="conversations"
87
+ fill="url(#location-bars)"
88
+ fillOpacity={0.9}
89
+ isAnimationActive={false}
90
+ maxBarSize={20}
91
+ minPointSize={(value) => (value ? 2 : 0)}
92
+ radius={2}
93
+ />
94
+ <ActivityChartAverageLine
95
+ unit={timeRangeBucketAverageUnit(bucketUnit)}
96
+ average={average}
97
+ format={formatActivityChartAverage}
98
+ stroke="var(--color-cyan-400)"
99
+ />
100
+ </BarChart>
101
+ </ChartContainer>
119
102
  </div>
120
103
  </Card>
121
104
  );
@@ -5,17 +5,35 @@ import {
5
5
  } from "../../components/controls/TimeRangeSelector";
6
6
  import type { LocationActivityDayReport } from "@sentry/junior/api/schema";
7
7
 
8
+ import { Bar, BarChart, CartesianGrid } from "recharts";
8
9
  import {
9
- ActivityChartDateLabels,
10
- ActivityChartGrid,
11
- ActivityChartTooltip,
12
- ActivityTooltipRows,
13
- ChartSvg,
14
- createActivityChartLayout,
10
+ activityChartMargin,
11
+ ActivityChartTooltipContent,
12
+ ActivityChartXAxis,
13
+ ActivityChartYAxis,
15
14
  } from "../../components/charts/ActivityChart";
16
15
  import { ChartLegend } from "../../components/charts/ChartLegend";
17
16
  import { Card } from "../../components/layout/Card";
18
17
  import { CardHeader } from "../../components/layout/CardHeader";
18
+ import { ChartContainer, ChartTooltip } from "../../components/ui/chart";
19
+
20
+ const series = [
21
+ {
22
+ color: "var(--color-cyan-400)",
23
+ dataKey: "publicConversations",
24
+ key: "public",
25
+ label: "public",
26
+ },
27
+ {
28
+ color: "var(--color-amber-400)",
29
+ dataKey: "privateConversations",
30
+ key: "private",
31
+ label: "private",
32
+ },
33
+ ] as const;
34
+ const chartConfig = Object.fromEntries(
35
+ series.map((item) => [item.key, { color: item.color, label: item.label }]),
36
+ );
19
37
 
20
38
  /** Compare public and privacy-preserving private conversation volume by day. */
21
39
  export function LocationDirectoryActivityChart(props: {
@@ -26,7 +44,6 @@ export function LocationDirectoryActivityChart(props: {
26
44
  const bucketUnit = props.bucketUnit ?? "day";
27
45
  const perBucket = `Conversations per ${timeRangeBucketPerLabel(bucketUnit)}`;
28
46
 
29
- const layout = createActivityChartLayout(260);
30
47
  const maximum = Math.max(
31
48
  1,
32
49
  ...props.days.flatMap((day) => [
@@ -34,10 +51,6 @@ export function LocationDirectoryActivityChart(props: {
34
51
  day.publicConversations,
35
52
  ]),
36
53
  );
37
- const step = layout.plotWidth / Math.max(1, props.days.length);
38
- const groupWidth = Math.max(3, Math.min(18, step * 0.8));
39
- const gap = Math.min(2, groupWidth * 0.15);
40
- const barWidth = Math.max(1.5, (groupWidth - gap) / 2);
41
54
  return (
42
55
  <Card>
43
56
  <CardHeader
@@ -47,81 +60,48 @@ export function LocationDirectoryActivityChart(props: {
47
60
  <ChartLegend
48
61
  ariaLabel="Conversation visibility legend"
49
62
  inline
50
- items={[
51
- {
52
- color: "var(--color-cyan-400)",
53
- key: "public",
54
- label: "public",
55
- },
56
- {
57
- color: "var(--color-amber-400)",
58
- key: "private",
59
- label: "private",
60
- },
61
- ]}
63
+ items={series}
62
64
  />
63
65
  }
64
66
  />
65
67
  <div className="px-2 py-3 sm:px-4 sm:py-4">
66
- <ChartSvg
67
- aria-label={`Public and private ${perBucket.toLowerCase()}`}
68
- className="min-h-56 w-full overflow-visible"
69
- layout={layout}
68
+ <ChartContainer
69
+ className="aspect-auto h-65 w-full"
70
+ config={chartConfig}
70
71
  >
71
- <ActivityChartGrid layout={layout} maximum={maximum} />
72
- {props.days.flatMap((day, index) => {
73
- const groupX = layout.left + index * step + (step - groupWidth) / 2;
74
- return (
75
- [
76
- {
77
- count: day.publicConversations,
78
- fill: "var(--color-cyan-400)",
79
- key: "public",
80
- x: groupX,
81
- },
82
- {
83
- count: day.privateConversations,
84
- fill: "var(--color-amber-400)",
85
- key: "private",
86
- x: groupX + barWidth + gap,
87
- },
88
- ] as const
89
- ).map((bar) => {
90
- const barHeight = (bar.count / maximum) * layout.plotHeight;
91
- return (
92
- <ActivityChartTooltip
93
- key={`${day.date}-${bar.key}`}
94
- content={
95
- <ActivityTooltipRows
96
- rows={[
97
- ["public", day.publicConversations],
98
- ["private", day.privateConversations],
99
- ]}
100
- />
72
+ <BarChart
73
+ aria-label={`Public and private ${perBucket.toLowerCase()}`}
74
+ barGap={2}
75
+ data={props.days}
76
+ margin={activityChartMargin}
77
+ role="img"
78
+ >
79
+ <CartesianGrid strokeDasharray="3 5" vertical={false} />
80
+ <ActivityChartYAxis maximum={maximum} />
81
+ <ActivityChartXAxis keys={props.days.map((day) => day.date)} />
82
+ <ChartTooltip
83
+ content={
84
+ <ActivityChartTooltipContent
85
+ rows={(day: LocationActivityDayReport) =>
86
+ series.map((item) => [item.label, day[item.dataKey]])
101
87
  }
102
- date={day.date}
103
- summary={`${day.publicConversations} public conversations, ${day.privateConversations} private conversations`}
104
- >
105
- <rect
106
- fill={bar.fill}
107
- height={Math.max(bar.count ? 2 : 0, barHeight)}
108
- opacity={bar.count ? 0.85 : 0.12}
109
- rx="1.5"
110
- tabIndex={0}
111
- width={barWidth}
112
- x={bar.x}
113
- y={layout.top + layout.plotHeight - barHeight}
114
- />
115
- </ActivityChartTooltip>
116
- );
117
- });
118
- })}
119
- <ActivityChartDateLabels
120
- dates={props.days.map((day) => day.date)}
121
- layout={layout}
122
- xPosition={(index) => layout.left + index * step + step / 2}
123
- />
124
- </ChartSvg>
88
+ />
89
+ }
90
+ />
91
+ {series.map((item) => (
92
+ <Bar
93
+ dataKey={item.dataKey}
94
+ fill={`var(--color-${item.key})`}
95
+ fillOpacity={0.85}
96
+ isAnimationActive={false}
97
+ key={item.key}
98
+ maxBarSize={8}
99
+ minPointSize={(value) => (value ? 2 : 0)}
100
+ radius={1.5}
101
+ />
102
+ ))}
103
+ </BarChart>
104
+ </ChartContainer>
125
105
  </div>
126
106
  </Card>
127
107
  );
@@ -3,22 +3,31 @@ import {
3
3
  timeRangeBucketAverageUnit,
4
4
  type TimeRangeDays,
5
5
  } from "../../components/controls/TimeRangeSelector";
6
+ import { Bar, BarChart, CartesianGrid } from "recharts";
6
7
  import {
7
8
  ActivityChartAverageLine,
8
- ActivityChartDateLabels,
9
- ActivityChartGrid,
10
9
  activityChartAverage,
11
- ActivityChartTooltip,
12
- ActivityTooltipRows,
13
- ChartSvg,
14
- createActivityChartLayout,
10
+ activityChartMargin,
11
+ ActivityChartTooltipContent,
12
+ ActivityChartXAxis,
13
+ ActivityChartYAxis,
15
14
  } from "../../components/charts/ActivityChart";
16
15
  import { ChartLegend } from "../../components/charts/ChartLegend";
17
16
 
18
17
  import { Card } from "../../components/layout/Card";
18
+ import { ChartContainer, ChartTooltip } from "../../components/ui/chart";
19
19
  import { formatCostSummary } from "../../format";
20
20
  import type { MemoryCostDay } from "./memoryDashboard";
21
21
 
22
+ const chartConfig = {
23
+ extraction: { color: "var(--color-cyan-300)", label: "Extraction" },
24
+ recall: { color: "var(--color-fuchsia-400)", label: "Recall" },
25
+ };
26
+
27
+ function formatCost(value: number): string {
28
+ return formatCostSummary({ total: value });
29
+ }
30
+
22
31
  /** Render stacked memory extraction and recall cost from durable plugin events. */
23
32
  export function MemoryCostChart(props: {
24
33
  bucketUnit?: TimeRangeBucketUnit;
@@ -30,15 +39,20 @@ export function MemoryCostChart(props: {
30
39
  const bucketUnit = props.bucketUnit ?? "day";
31
40
 
32
41
  const recallByDate = new Map(props.recallDays.map((day) => [day.date, day]));
33
- const days = props.extractionDays.map((extraction) => ({
34
- date: extraction.date,
35
- extraction,
36
- recall: recallByDate.get(extraction.date) ?? {
42
+ const days = props.extractionDays.map((extraction) => {
43
+ const recall = recallByDate.get(extraction.date) ?? {
37
44
  costUsd: 0,
38
45
  date: extraction.date,
39
46
  events: 0,
40
- },
41
- }));
47
+ };
48
+ return {
49
+ date: extraction.date,
50
+ extraction,
51
+ extractionCost: extraction.costUsd,
52
+ recall,
53
+ recallCost: recall.costUsd,
54
+ };
55
+ });
42
56
  const extractionTotal = days.reduce(
43
57
  (sum, day) => sum + day.extraction.costUsd,
44
58
  0,
@@ -54,11 +68,6 @@ export function MemoryCostChart(props: {
54
68
  );
55
69
  const maximum = Math.max(0.01, ...dayTotals);
56
70
  const average = activityChartAverage(dayTotals);
57
- // Cost charts need a wider left gutter for currency tick labels.
58
- const layout = createActivityChartLayout(200, { left: 112 });
59
- const step =
60
- days.length > 0 ? layout.plotWidth / days.length : layout.plotWidth;
61
- const barWidth = Math.max(2, Math.min(13, step * 0.68));
62
71
 
63
72
  return (
64
73
  <Card className="min-h-[17rem] p-4 sm:p-5">
@@ -90,93 +99,60 @@ export function MemoryCostChart(props: {
90
99
  </div>
91
100
 
92
101
  <div className="relative mt-4 overflow-hidden">
93
- <ChartSvg
94
- aria-label={`Memory extraction and recall cost during the last ${props.range === 1 ? "24 hours" : `${props.range} days`}`}
95
- className="min-h-40"
96
- layout={layout}
102
+ <ChartContainer
103
+ className="aspect-auto h-50 w-full"
104
+ config={chartConfig}
97
105
  >
98
- <ActivityChartGrid
99
- format={(value) => formatCostSummary({ total: value })}
100
- layout={layout}
101
- maximum={maximum}
102
- />
103
- {days.map((day, index) => {
104
- const extractionHeight =
105
- (day.extraction.costUsd / maximum) * layout.plotHeight;
106
- const recallHeight =
107
- (day.recall.costUsd / maximum) * layout.plotHeight;
108
- const x = layout.left + index * step + (step - barWidth) / 2;
109
- const dayTotal = day.extraction.costUsd + day.recall.costUsd;
110
- return (
111
- <ActivityChartTooltip
112
- key={day.date}
113
- content={
114
- <ActivityTooltipRows
115
- rows={[
116
- [
117
- "extraction",
118
- `${formatCostSummary({ total: day.extraction.costUsd })} · ${formatRunCount(day.extraction.events)}`,
119
- ],
120
- [
121
- "recall",
122
- `${formatCostSummary({ total: day.recall.costUsd })} · ${formatRunCount(day.recall.events)}`,
123
- ],
124
- ["total", formatCostSummary({ total: dayTotal })],
125
- ]}
126
- />
127
- }
128
- date={day.date}
129
- summary={`extraction ${formatCostSummary({ total: day.extraction.costUsd })}, ${formatRunCount(day.extraction.events)}; recall ${formatCostSummary({ total: day.recall.costUsd })}, ${formatRunCount(day.recall.events)}`}
130
- >
131
- <g tabIndex={0}>
132
- <rect
133
- fill="var(--color-cyan-300)"
134
- height={extractionHeight}
135
- opacity={day.extraction.costUsd > 0 ? 0.82 : 0.1}
136
- rx="1"
137
- width={barWidth}
138
- x={x}
139
- y={layout.top + layout.plotHeight - extractionHeight}
140
- />
141
- <rect
142
- fill="var(--color-fuchsia-400)"
143
- height={recallHeight}
144
- opacity={day.recall.costUsd > 0 ? 0.82 : 0.1}
145
- rx="1"
146
- width={barWidth}
147
- x={x}
148
- y={
149
- layout.top +
150
- layout.plotHeight -
151
- extractionHeight -
152
- recallHeight
153
- }
154
- />
155
- <rect
156
- fill="transparent"
157
- height={layout.plotHeight}
158
- width={Math.max(barWidth, 8)}
159
- x={x - (Math.max(barWidth, 8) - barWidth) / 2}
160
- y={layout.top}
161
- />
162
- </g>
163
- </ActivityChartTooltip>
164
- );
165
- })}
166
- <ActivityChartAverageLine
167
- unit={timeRangeBucketAverageUnit(bucketUnit)}
168
- average={average}
169
- format={(value) => formatCostSummary({ total: value })}
170
- layout={layout}
171
- maximum={maximum}
172
- stroke="var(--color-slate-200)"
173
- />
174
- <ActivityChartDateLabels
175
- dates={days.map((day) => day.date)}
176
- layout={layout}
177
- xPosition={(index) => layout.left + index * step + step / 2}
178
- />
179
- </ChartSvg>
106
+ <BarChart
107
+ aria-label={`Memory extraction and recall cost during the last ${props.range === 1 ? "24 hours" : `${props.range} days`}`}
108
+ data={days}
109
+ margin={activityChartMargin}
110
+ role="img"
111
+ >
112
+ <CartesianGrid strokeDasharray="3 5" vertical={false} />
113
+ <ActivityChartYAxis format={formatCost} maximum={maximum} />
114
+ <ActivityChartXAxis keys={days.map((day) => day.date)} />
115
+ <ChartTooltip
116
+ content={
117
+ <ActivityChartTooltipContent
118
+ rows={(day: (typeof days)[number]) => [
119
+ [
120
+ "extraction",
121
+ `${formatCost(day.extractionCost)} · ${formatRunCount(day.extraction.events)}`,
122
+ ],
123
+ [
124
+ "recall",
125
+ `${formatCost(day.recallCost)} · ${formatRunCount(day.recall.events)}`,
126
+ ],
127
+ ["total", formatCost(day.extractionCost + day.recallCost)],
128
+ ]}
129
+ />
130
+ }
131
+ />
132
+ <Bar
133
+ dataKey="extractionCost"
134
+ fill="var(--color-extraction)"
135
+ fillOpacity={0.82}
136
+ isAnimationActive={false}
137
+ maxBarSize={13}
138
+ stackId="cost"
139
+ />
140
+ <Bar
141
+ dataKey="recallCost"
142
+ fill="var(--color-recall)"
143
+ fillOpacity={0.82}
144
+ isAnimationActive={false}
145
+ maxBarSize={13}
146
+ stackId="cost"
147
+ />
148
+ <ActivityChartAverageLine
149
+ unit={timeRangeBucketAverageUnit(bucketUnit)}
150
+ average={average}
151
+ format={formatCost}
152
+ stroke="var(--color-slate-200)"
153
+ />
154
+ </BarChart>
155
+ </ChartContainer>
180
156
  {runs === 0 ? (
181
157
  <div className="pointer-events-none absolute inset-0 grid place-items-center pt-12 font-sans text-xs text-dashboard-text-muted">
182
158
  No memory extraction or recall ran in this period.