@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.
- package/LICENSE +201 -0
- package/README.md +2 -5
- package/dist/app.js +119 -35
- package/dist/client.js +145 -136
- package/dist/index.d.ts +0 -1
- package/dist/index.js +119 -35
- package/dist/tailwind.css +1 -1
- package/package.json +5 -4
- package/src/api/schema.ts +0 -1
- package/src/app.ts +5 -20
- package/src/client/App.tsx +29 -31
- package/src/client/api.ts +7 -0
- package/src/client/components/ActorAvatar.tsx +10 -22
- package/src/client/components/BottomSheet.tsx +12 -2
- package/src/client/components/ConnectionBanner.tsx +4 -3
- package/src/client/components/CopyButton.tsx +82 -0
- package/src/client/components/DetailsPanel.tsx +133 -0
- package/src/client/components/Drawer.tsx +15 -24
- package/src/client/components/EmptyTelemetry.tsx +5 -3
- package/src/client/components/FilterBar.tsx +16 -31
- package/src/client/components/ImageAttachment.tsx +49 -63
- package/src/client/components/InlineError.tsx +8 -4
- package/src/client/components/Metric.tsx +33 -23
- package/src/client/components/Notice.tsx +19 -26
- package/src/client/components/PageContentSkeleton.tsx +1 -1
- package/src/client/components/Pagination.tsx +27 -27
- package/src/client/components/ParticipantAvatarStack.tsx +43 -39
- package/src/client/components/ProfileMenu.tsx +27 -93
- package/src/client/components/README.md +103 -78
- package/src/client/components/SearchInput.tsx +51 -41
- package/src/client/components/SegmentedNav.tsx +1 -1
- package/src/client/components/ShimmerText.tsx +2 -6
- package/src/client/components/ThemeSwitcher.tsx +19 -15
- package/src/client/components/VersionDriftBanner.tsx +9 -7
- package/src/client/components/charts/ActivityChart.tsx +173 -288
- package/src/client/components/charts/CacheWrites.tsx +59 -37
- package/src/client/components/charts/InputCacheChart.tsx +137 -131
- package/src/client/components/charts/README.md +4 -4
- package/src/client/components/charts/SystemMetricCharts.tsx +68 -95
- package/src/client/components/charts/WorkspaceUsageChart.tsx +42 -62
- package/src/client/components/controls/DirectorySortSelect.tsx +3 -3
- package/src/client/components/controls/TimeRangeSelector.tsx +10 -15
- package/src/client/components/layout/DashboardHeader.tsx +44 -90
- package/src/client/components/layout/SecondaryNavigation.tsx +2 -1
- package/src/client/components/layout/VisualViewportShell.tsx +2 -2
- package/src/client/components/ui/accordion.tsx +77 -0
- package/src/client/components/ui/alert-dialog.tsx +89 -0
- package/src/client/components/ui/alert.tsx +64 -0
- package/src/client/components/ui/avatar.tsx +53 -0
- package/src/client/components/ui/button.tsx +86 -0
- package/src/client/components/ui/chart.tsx +74 -0
- package/src/client/components/ui/checkbox.tsx +26 -0
- package/src/client/components/ui/collapsible.tsx +22 -0
- package/src/client/components/ui/dialog.tsx +66 -0
- package/src/client/components/ui/empty.tsx +32 -0
- package/src/client/components/ui/field.tsx +49 -0
- package/src/client/components/ui/input-group.tsx +96 -0
- package/src/client/components/ui/input.tsx +35 -0
- package/src/client/components/ui/native-select.tsx +57 -0
- package/src/client/components/ui/pagination.tsx +60 -0
- package/src/client/components/ui/popover.tsx +67 -0
- package/src/client/components/ui/radio-group.tsx +32 -0
- package/src/client/components/ui/sheet.tsx +13 -3
- package/src/client/components/ui/skeleton.tsx +19 -0
- package/src/client/components/ui/spinner.tsx +21 -0
- package/src/client/components/ui/table.tsx +101 -0
- package/src/client/components/ui/tabs.tsx +75 -0
- package/src/client/components/ui/textarea.tsx +17 -0
- package/src/client/components/ui/toast.tsx +215 -0
- package/src/client/components/ui/toggle-group.tsx +36 -0
- package/src/client/components/ui/toggle.tsx +37 -0
- package/src/client/components/ui/tooltip.tsx +168 -0
- package/src/client/components/ui/trace.tsx +96 -0
- package/src/client/conversations/ChatLayout.tsx +7 -3
- package/src/client/conversations/ConversationBrief.tsx +17 -6
- package/src/client/conversations/ConversationChildAgents.tsx +5 -5
- package/src/client/conversations/ConversationComposer.tsx +26 -12
- package/src/client/conversations/ConversationDetails.tsx +147 -62
- package/src/client/conversations/ConversationEventDetails.tsx +141 -0
- package/src/client/conversations/ConversationEventLog.tsx +150 -129
- package/src/client/conversations/ConversationHeader.tsx +13 -7
- package/src/client/conversations/ConversationHeaderActions.tsx +97 -93
- package/src/client/conversations/ConversationHomeList.tsx +1 -1
- package/src/client/conversations/ConversationLinkedWork.tsx +118 -0
- package/src/client/conversations/ConversationMeta.tsx +55 -88
- package/src/client/conversations/ConversationPage.tsx +220 -101
- package/src/client/conversations/ConversationSidebar.tsx +49 -29
- package/src/client/conversations/ConversationUsageBreakdown.tsx +108 -65
- package/src/client/conversations/ConversationWatches.tsx +173 -0
- package/src/client/conversations/ConversationWorkspace.tsx +12 -22
- package/src/client/conversations/ConversationWorkspaceLoading.tsx +1 -1
- package/src/client/conversations/DetailsList.tsx +139 -0
- package/src/client/conversations/EventDetails.tsx +42 -8
- package/src/client/conversations/EventUsage.tsx +99 -74
- package/src/client/conversations/ForkConversationButton.tsx +27 -16
- package/src/client/conversations/ObjectCard.tsx +20 -8
- package/src/client/conversations/PendingMailboxStack.tsx +52 -38
- package/src/client/conversations/README.md +89 -13
- package/src/client/conversations/ShareConversationButton.tsx +28 -17
- package/src/client/conversations/SubagentTranscriptDrawer.tsx +21 -15
- package/src/client/conversations/ToolFrame.tsx +36 -52
- package/src/client/conversations/TranscriptActivityGroup.tsx +13 -4
- package/src/client/conversations/TranscriptAutomationTriggerView.tsx +5 -4
- package/src/client/conversations/TranscriptContextEventView.tsx +25 -11
- package/src/client/conversations/TranscriptEventView.tsx +35 -16
- package/src/client/conversations/TranscriptHeadingRow.tsx +7 -7
- package/src/client/conversations/TranscriptLoading.tsx +1 -1
- package/src/client/conversations/TranscriptMarkdown.tsx +25 -20
- package/src/client/conversations/TranscriptMessageContextView.tsx +35 -18
- package/src/client/conversations/TranscriptMessageView.tsx +6 -1
- package/src/client/conversations/TranscriptReasoningView.tsx +54 -68
- package/src/client/conversations/TranscriptStructuredEventView.tsx +25 -15
- package/src/client/conversations/TranscriptSummary.tsx +34 -2
- package/src/client/conversations/TranscriptTimestamp.tsx +9 -7
- package/src/client/conversations/TranscriptToolView.tsx +1 -1
- package/src/client/conversations/TranscriptTurnContextView.tsx +144 -65
- package/src/client/conversations/TranscriptView.tsx +63 -27
- package/src/client/conversations/eventLog.ts +58 -0
- package/src/client/conversations/eventTime.ts +60 -0
- package/src/client/conversations/queries.ts +29 -0
- package/src/client/conversations/transcriptBottomPinning.ts +34 -0
- package/src/client/conversations/transcriptMentions.tsx +18 -5
- package/src/client/format.ts +5 -0
- package/src/client/pages/ConnectionsPage.tsx +2 -2
- package/src/client/pages/PersonalTokensPage.tsx +4 -4
- package/src/client/pages/SettingsPage.tsx +9 -10
- package/src/client/pages/admin/ServiceAccountsSection.tsx +2 -2
- package/src/client/pages/automations/AutomationCostChart.tsx +50 -71
- package/src/client/pages/automations/AutomationDeleteDialog.tsx +87 -0
- package/src/client/pages/automations/AutomationDetails.tsx +193 -0
- package/src/client/pages/automations/AutomationEditPage.tsx +7 -8
- package/src/client/pages/automations/AutomationEditor.tsx +41 -29
- package/src/client/pages/automations/AutomationEditorLoading.tsx +1 -1
- package/src/client/pages/automations/AutomationEventFields.tsx +202 -119
- package/src/client/pages/automations/AutomationExecutionChart.tsx +51 -64
- package/src/client/pages/automations/AutomationExecutionStatusChart.tsx +47 -70
- package/src/client/pages/automations/AutomationExecutionsPage.tsx +150 -126
- package/src/client/pages/automations/AutomationFilters.tsx +189 -74
- package/src/client/pages/automations/AutomationLifecycle.tsx +109 -78
- package/src/client/pages/automations/AutomationOutcomeFields.tsx +26 -24
- package/src/client/pages/automations/AutomationRecentRuns.tsx +143 -0
- package/src/client/pages/automations/AutomationRow.tsx +12 -138
- package/src/client/pages/automations/AutomationRunDetails.tsx +307 -0
- package/src/client/pages/automations/AutomationRunsPage.tsx +119 -94
- package/src/client/pages/automations/AutomationScheduleFields.tsx +51 -51
- package/src/client/pages/automations/AutomationStatus.tsx +201 -0
- package/src/client/pages/automations/AutomationVersionsPage.tsx +65 -28
- package/src/client/pages/automations/AutomationsPage.tsx +80 -68
- package/src/client/pages/automations/AutomationsPageLayout.tsx +46 -14
- package/src/client/pages/automations/README.md +57 -0
- package/src/client/pages/automations/TriggerFilters.tsx +22 -0
- package/src/client/pages/automations/automationFormat.ts +37 -23
- package/src/client/pages/code/CodeActivityChart.tsx +59 -101
- package/src/client/pages/code/CodePage.tsx +52 -55
- package/src/client/pages/code/RepositoryPage.tsx +6 -8
- package/src/client/pages/locations/LocationActivityChart.tsx +53 -70
- package/src/client/pages/locations/LocationDirectoryActivityChart.tsx +60 -80
- package/src/client/pages/memory/MemoryCostChart.tsx +79 -103
- package/src/client/pages/memory/MemoryDetails.tsx +218 -0
- package/src/client/pages/memory/MemoryPage.tsx +168 -112
- package/src/client/pages/memory/MemoryPageLayout.tsx +33 -9
- package/src/client/pages/memory/MemoryTimeline.tsx +46 -69
- package/src/client/pages/memory/memoryRecord.ts +1 -1
- package/src/client/pages/people/ContributionGrid.tsx +23 -16
- package/src/client/pages/people/PeopleActivityChart.tsx +68 -107
- package/src/client/pages/people/ProfileCodeChanges.tsx +5 -5
- package/src/client/pages/system/BaseSandboxCard.tsx +1 -1
- package/src/client/pages/system/ConversationActivityChart.tsx +49 -67
- package/src/client/pages/system/GuardianActivity.tsx +1 -2
- package/src/client/pages/system/PluginBarChart.tsx +106 -87
- package/src/client/pages/system/PluginReportRecordSet.tsx +25 -24
- package/src/client/pages/system/README.md +23 -0
- package/src/client/pages/system/SystemNavigation.tsx +5 -1
- package/src/client/pages/system/WorkspaceDeleteDialog.tsx +111 -0
- package/src/client/pages/system/WorkspaceDetails.tsx +200 -43
- package/src/client/pages/system/WorkspaceEditor.tsx +59 -61
- package/src/client/pages/system/WorkspaceFormPage.tsx +23 -47
- package/src/client/pages/system/WorkspaceList.tsx +20 -30
- package/src/client/pages/system/WorkspacesPage.tsx +117 -119
- package/src/client/pages/system/sandboxSize.ts +8 -0
- package/src/client/pages/system/workspaceQueries.ts +53 -0
- package/src/client/pages/user/PluginUserPage.tsx +51 -2
- package/src/client/pages/user/pluginUserPageData.ts +1 -6
- package/src/client/styles.ts +4 -0
- package/src/client.tsx +7 -1
- package/src/mock-reporting/automation-collection.ts +4 -2
- package/src/mock-reporting/fixtures.ts +23 -7
- package/src/mock-reporting/routes.ts +12 -0
- package/src/mock-reporting/watches.ts +94 -0
- package/src/shell.ts +4 -9
- package/src/tailwind.css +0 -10
- package/src/client/components/Button.tsx +0 -118
- package/src/client/components/Field.tsx +0 -53
- package/src/client/components/SegmentedTabs.tsx +0 -119
- package/src/client/components/Select.tsx +0 -52
- package/src/client/components/Skeleton.tsx +0 -17
- package/src/client/components/TextInput.tsx +0 -58
- package/src/client/components/Tooltip.tsx +0 -216
- package/src/client/components/charts/useChartLayout.ts +0 -27
- package/src/client/components/ui/sheet.LICENSE +0 -21
- package/src/client/conversations/ConversationDetailsFrame.tsx +0 -119
- package/src/client/conversations/CopyMarkdownButton.tsx +0 -65
- package/src/client/pages/automations/AutomationDetailsDrawer.tsx +0 -219
- package/src/client/pages/dev/ChartFixtures.tsx +0 -325
- package/src/client/pages/dev/ComponentsPage.tsx +0 -899
- package/src/client/pages/dev/ConversationFixture.tsx +0 -231
- package/src/client/pages/dev/ObjectFixtures.tsx +0 -138
- package/src/client/pages/dev/SegmentedFixtures.tsx +0 -59
- package/src/client/pages/dev/SelectFixtures.tsx +0 -62
- package/src/client/pages/dev/TranscriptActivityFixtures.tsx +0 -206
- package/src/client/pages/memory/MemoryDetailsDrawer.tsx +0 -167
- package/src/client/pages/system/SandboxSizeSummary.tsx +0 -47
- package/src/client/pages/system/SnapshotSummary.tsx +0 -78
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
import type { ConversationUsage } from "@sentry/junior/api/schema";
|
|
2
2
|
|
|
3
3
|
import { formatCostBreakdown, summarizeCost } from "../format";
|
|
4
|
+
import {
|
|
5
|
+
Table,
|
|
6
|
+
TableBody,
|
|
7
|
+
TableCell,
|
|
8
|
+
TableHead,
|
|
9
|
+
TableFooter,
|
|
10
|
+
TableHeader,
|
|
11
|
+
TableRow,
|
|
12
|
+
} from "../components/ui/table";
|
|
4
13
|
import { cn } from "../styles";
|
|
5
14
|
|
|
6
15
|
/** Align recorded token counts with their costs without adding overlapping counters. */
|
|
@@ -31,83 +40,53 @@ export function EventUsage({ usage }: { usage?: ConversationUsage }) {
|
|
|
31
40
|
);
|
|
32
41
|
}
|
|
33
42
|
|
|
43
|
+
const total = rows.find((row) => row.label === "Total");
|
|
34
44
|
return (
|
|
35
45
|
<>
|
|
36
|
-
<
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
>
|
|
41
|
-
<
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
<
|
|
47
|
-
<
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
"py-2 text-left font-normal",
|
|
73
|
-
row.label === "Total"
|
|
74
|
-
? "font-semibold text-dashboard-text"
|
|
75
|
-
: "text-dashboard-text-muted",
|
|
76
|
-
)}
|
|
77
|
-
>
|
|
78
|
-
{row.label}
|
|
79
|
-
</th>
|
|
80
|
-
<td className="py-2 text-right font-sans tabular-nums text-dashboard-text">
|
|
81
|
-
{row.tokens === undefined ? (
|
|
82
|
-
<span
|
|
83
|
-
aria-label="Not recorded"
|
|
84
|
-
className="text-dashboard-text-faint"
|
|
85
|
-
>
|
|
86
|
-
—
|
|
87
|
-
</span>
|
|
88
|
-
) : (
|
|
89
|
-
row.tokens.toLocaleString("en-US")
|
|
90
|
-
)}
|
|
91
|
-
</td>
|
|
92
|
-
<td className="py-2 text-right font-sans tabular-nums text-dashboard-text">
|
|
93
|
-
{row.cost === undefined ? (
|
|
94
|
-
<span
|
|
95
|
-
aria-label="Not recorded separately"
|
|
96
|
-
className="text-dashboard-text-faint"
|
|
97
|
-
>
|
|
98
|
-
—
|
|
99
|
-
</span>
|
|
100
|
-
) : (
|
|
101
|
-
<span title={`${row.cost} USD`}>
|
|
102
|
-
{formatCostBreakdown({ total: row.cost })}
|
|
103
|
-
</span>
|
|
104
|
-
)}
|
|
105
|
-
</td>
|
|
106
|
-
</tr>
|
|
46
|
+
<Table
|
|
47
|
+
aria-label="Model call token and cost breakdown"
|
|
48
|
+
className="min-w-72 table-fixed text-xs leading-relaxed"
|
|
49
|
+
>
|
|
50
|
+
<colgroup>
|
|
51
|
+
<col />
|
|
52
|
+
<col className="w-24" />
|
|
53
|
+
<col className="w-24" />
|
|
54
|
+
</colgroup>
|
|
55
|
+
<TableHeader>
|
|
56
|
+
<TableRow className="border-dashboard-border">
|
|
57
|
+
<TableHead
|
|
58
|
+
scope="col"
|
|
59
|
+
className="px-0 py-2 leading-relaxed font-normal"
|
|
60
|
+
>
|
|
61
|
+
Usage
|
|
62
|
+
</TableHead>
|
|
63
|
+
<TableHead
|
|
64
|
+
scope="col"
|
|
65
|
+
className="px-0 py-2 text-right leading-relaxed font-normal"
|
|
66
|
+
>
|
|
67
|
+
Tokens
|
|
68
|
+
</TableHead>
|
|
69
|
+
<TableHead
|
|
70
|
+
scope="col"
|
|
71
|
+
className="px-0 py-2 text-right leading-relaxed font-normal"
|
|
72
|
+
>
|
|
73
|
+
Cost (USD)
|
|
74
|
+
</TableHead>
|
|
75
|
+
</TableRow>
|
|
76
|
+
</TableHeader>
|
|
77
|
+
<TableBody>
|
|
78
|
+
{rows
|
|
79
|
+
.filter((row) => row !== total)
|
|
80
|
+
.map((row) => (
|
|
81
|
+
<UsageRow key={row.label} {...row} />
|
|
107
82
|
))}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
83
|
+
</TableBody>
|
|
84
|
+
{total ? (
|
|
85
|
+
<TableFooter className="font-semibold">
|
|
86
|
+
<UsageRow {...total} total />
|
|
87
|
+
</TableFooter>
|
|
88
|
+
) : null}
|
|
89
|
+
</Table>
|
|
111
90
|
<p className="m-0 text-xs leading-relaxed text-dashboard-text-muted">
|
|
112
91
|
This call only · Estimated costs
|
|
113
92
|
<br />
|
|
@@ -116,3 +95,49 @@ export function EventUsage({ usage }: { usage?: ConversationUsage }) {
|
|
|
116
95
|
</>
|
|
117
96
|
);
|
|
118
97
|
}
|
|
98
|
+
|
|
99
|
+
function UsageRow(props: {
|
|
100
|
+
cost?: number;
|
|
101
|
+
label: string;
|
|
102
|
+
tokens?: number;
|
|
103
|
+
total?: boolean;
|
|
104
|
+
}) {
|
|
105
|
+
return (
|
|
106
|
+
<TableRow>
|
|
107
|
+
<TableHead
|
|
108
|
+
scope="row"
|
|
109
|
+
className={cn(
|
|
110
|
+
"px-0 py-2 leading-relaxed",
|
|
111
|
+
props.total
|
|
112
|
+
? "font-semibold text-dashboard-text"
|
|
113
|
+
: "font-normal text-dashboard-text-muted",
|
|
114
|
+
)}
|
|
115
|
+
>
|
|
116
|
+
{props.label}
|
|
117
|
+
</TableHead>
|
|
118
|
+
<TableCell className="px-0 py-2 text-right font-sans tabular-nums">
|
|
119
|
+
{props.tokens === undefined ? (
|
|
120
|
+
<span aria-label="Not recorded" className="text-dashboard-text-faint">
|
|
121
|
+
—
|
|
122
|
+
</span>
|
|
123
|
+
) : (
|
|
124
|
+
props.tokens.toLocaleString("en-US")
|
|
125
|
+
)}
|
|
126
|
+
</TableCell>
|
|
127
|
+
<TableCell className="px-0 py-2 text-right font-sans tabular-nums">
|
|
128
|
+
{props.cost === undefined ? (
|
|
129
|
+
<span
|
|
130
|
+
aria-label="Not recorded separately"
|
|
131
|
+
className="text-dashboard-text-faint"
|
|
132
|
+
>
|
|
133
|
+
—
|
|
134
|
+
</span>
|
|
135
|
+
) : (
|
|
136
|
+
<span title={`${props.cost} USD`}>
|
|
137
|
+
{formatCostBreakdown({ total: props.cost })}
|
|
138
|
+
</span>
|
|
139
|
+
)}
|
|
140
|
+
</TableCell>
|
|
141
|
+
</TableRow>
|
|
142
|
+
);
|
|
143
|
+
}
|
|
@@ -2,10 +2,15 @@ import { GitFork } from "lucide-react";
|
|
|
2
2
|
import { useId, useState } from "react";
|
|
3
3
|
import { createPortal } from "react-dom";
|
|
4
4
|
import { useNavigate } from "react-router";
|
|
5
|
-
import { Button } from "../components/
|
|
5
|
+
import { Button } from "../components/ui/button";
|
|
6
|
+
import { Textarea } from "../components/ui/textarea";
|
|
7
|
+
import { Field, FieldLabel } from "../components/ui/field";
|
|
8
|
+
import {
|
|
9
|
+
Tooltip,
|
|
10
|
+
TooltipContent,
|
|
11
|
+
TooltipTrigger,
|
|
12
|
+
} from "../components/ui/tooltip";
|
|
6
13
|
import { Drawer } from "../components/Drawer";
|
|
7
|
-
import { Field } from "../components/Field";
|
|
8
|
-
import { TextArea } from "../components/TextInput";
|
|
9
14
|
import { DashboardApiError } from "../http";
|
|
10
15
|
import { conversationPath } from "./conversationRoutes";
|
|
11
16
|
import { useForkConversation } from "./queries";
|
|
@@ -17,14 +22,20 @@ export function ForkConversationButton(props: ForkTarget) {
|
|
|
17
22
|
const [open, setOpen] = useState(false);
|
|
18
23
|
return (
|
|
19
24
|
<>
|
|
20
|
-
<
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
<Tooltip>
|
|
26
|
+
<TooltipTrigger
|
|
27
|
+
render={
|
|
28
|
+
<Button
|
|
29
|
+
size="icon"
|
|
30
|
+
aria-label="Fork after this message"
|
|
31
|
+
onClick={() => setOpen(true)}
|
|
32
|
+
>
|
|
33
|
+
<GitFork size={14} aria-hidden="true" />
|
|
34
|
+
</Button>
|
|
35
|
+
}
|
|
36
|
+
/>
|
|
37
|
+
<TooltipContent size="compact">Fork after this message</TooltipContent>
|
|
38
|
+
</Tooltip>
|
|
28
39
|
{open
|
|
29
40
|
? createPortal(
|
|
30
41
|
<ForkConversationDialog
|
|
@@ -82,12 +93,12 @@ function ForkConversationDialog(props: ForkTarget & { onClose(): void }) {
|
|
|
82
93
|
<p className="m-0">
|
|
83
94
|
Creates a fork of the conversation from this point.
|
|
84
95
|
</p>
|
|
85
|
-
<Field
|
|
86
|
-
<
|
|
96
|
+
<Field>
|
|
97
|
+
<FieldLabel htmlFor={inputId}>Message</FieldLabel>
|
|
98
|
+
<Textarea
|
|
87
99
|
id={inputId}
|
|
88
|
-
prose
|
|
89
100
|
autoFocus
|
|
90
|
-
className="min-h-28"
|
|
101
|
+
className="min-h-28 leading-relaxed"
|
|
91
102
|
placeholder="Message Junior…"
|
|
92
103
|
value={message}
|
|
93
104
|
disabled={fork.isPending}
|
|
@@ -112,7 +123,7 @@ function ForkConversationDialog(props: ForkTarget & { onClose(): void }) {
|
|
|
112
123
|
</p>
|
|
113
124
|
) : null}
|
|
114
125
|
<Button
|
|
115
|
-
|
|
126
|
+
variant="primary"
|
|
116
127
|
type="submit"
|
|
117
128
|
disabled={!message.trim() || fork.isPending}
|
|
118
129
|
>
|
|
@@ -3,10 +3,16 @@ import {
|
|
|
3
3
|
objectFactFields,
|
|
4
4
|
objectPresentation,
|
|
5
5
|
} from "@sentry/junior-plugin-api";
|
|
6
|
-
import { ArrowUpRight } from "lucide-react";
|
|
6
|
+
import { ArrowUpRight, ChevronRight } from "lucide-react";
|
|
7
7
|
import { ObjectIcon } from "../components/ObjectIcon";
|
|
8
8
|
import { AutomationCard } from "../components/AutomationCard";
|
|
9
9
|
import { StatusChip } from "../components/StatusChip";
|
|
10
|
+
import {
|
|
11
|
+
Collapsible,
|
|
12
|
+
CollapsibleContent,
|
|
13
|
+
CollapsibleTrigger,
|
|
14
|
+
} from "../components/ui/collapsible";
|
|
15
|
+
import { dashboardDisclosureChevronClass } from "../styles";
|
|
10
16
|
|
|
11
17
|
/** Show the latest saved annotation. Opening a source is always explicit. */
|
|
12
18
|
export function ObjectCard({ card }: { card: OwnedObjectAnnotation }) {
|
|
@@ -78,14 +84,20 @@ export function ObjectCard({ card }: { card: OwnedObjectAnnotation }) {
|
|
|
78
84
|
)}
|
|
79
85
|
{fields.length > 0 && facts(fields)}
|
|
80
86
|
{card.description && (
|
|
81
|
-
<
|
|
82
|
-
<
|
|
87
|
+
<Collapsible className="min-w-0 border-t border-dashboard-border pt-3">
|
|
88
|
+
<CollapsibleTrigger className="group flex cursor-pointer items-center gap-1 text-xs font-medium text-dashboard-text-muted focus-visible:outline-dashboard-focus">
|
|
89
|
+
<ChevronRight
|
|
90
|
+
aria-hidden="true"
|
|
91
|
+
className={dashboardDisclosureChevronClass}
|
|
92
|
+
/>
|
|
83
93
|
More details
|
|
84
|
-
</
|
|
85
|
-
<
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
94
|
+
</CollapsibleTrigger>
|
|
95
|
+
<CollapsibleContent hiddenUntilFound>
|
|
96
|
+
<p className="mb-0 mt-3 whitespace-pre-wrap break-words text-sm text-dashboard-text-muted">
|
|
97
|
+
{card.description}
|
|
98
|
+
</p>
|
|
99
|
+
</CollapsibleContent>
|
|
100
|
+
</Collapsible>
|
|
89
101
|
)}
|
|
90
102
|
{card.warning && (
|
|
91
103
|
<p className="m-0 break-words text-xs text-amber-500">
|
|
@@ -9,13 +9,17 @@ import {
|
|
|
9
9
|
import {
|
|
10
10
|
AlertCircle,
|
|
11
11
|
Clock3,
|
|
12
|
-
LoaderCircle,
|
|
13
12
|
SkipForward,
|
|
14
13
|
X,
|
|
15
14
|
type LucideIcon,
|
|
16
15
|
} from "lucide-react";
|
|
17
16
|
|
|
18
|
-
import {
|
|
17
|
+
import {
|
|
18
|
+
Tooltip,
|
|
19
|
+
TooltipContent,
|
|
20
|
+
TooltipTrigger,
|
|
21
|
+
} from "../components/ui/tooltip";
|
|
22
|
+
import { Spinner } from "../components/ui/spinner";
|
|
19
23
|
import { actorLabel } from "../format";
|
|
20
24
|
import type { ConversationMailboxMessage } from "./conversationOutbox";
|
|
21
25
|
import {
|
|
@@ -29,12 +33,12 @@ const COLLAPSED_PENDING_ROW_COUNT = 2;
|
|
|
29
33
|
|
|
30
34
|
function pendingDeliveryMeta(
|
|
31
35
|
message: Pick<ConversationMailboxMessage, "clientStatus" | "delivery">,
|
|
32
|
-
): { icon: LucideIcon; label: string
|
|
36
|
+
): { icon: LucideIcon | typeof Spinner; label: string } {
|
|
33
37
|
if (message.clientStatus === "failed") {
|
|
34
38
|
return { icon: AlertCircle, label: "Failed to send" };
|
|
35
39
|
}
|
|
36
40
|
if (message.clientStatus === "sending") {
|
|
37
|
-
return { icon:
|
|
41
|
+
return { icon: Spinner, label: "Sending" };
|
|
38
42
|
}
|
|
39
43
|
if (message.delivery === "interrupt") {
|
|
40
44
|
return { icon: SkipForward, label: "Interrupt" };
|
|
@@ -44,13 +48,18 @@ function pendingDeliveryMeta(
|
|
|
44
48
|
|
|
45
49
|
function PendingMetaIcon(props: { children: ReactElement; label: string }) {
|
|
46
50
|
return (
|
|
47
|
-
<Tooltip
|
|
48
|
-
<
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
51
|
+
<Tooltip>
|
|
52
|
+
<TooltipTrigger
|
|
53
|
+
render={
|
|
54
|
+
<span
|
|
55
|
+
aria-label={props.label}
|
|
56
|
+
className="inline-flex text-dashboard-text-muted"
|
|
57
|
+
>
|
|
58
|
+
{props.children}
|
|
59
|
+
</span>
|
|
60
|
+
}
|
|
61
|
+
/>
|
|
62
|
+
<TooltipContent>{props.label}</TooltipContent>
|
|
54
63
|
</Tooltip>
|
|
55
64
|
);
|
|
56
65
|
}
|
|
@@ -69,43 +78,48 @@ function PendingMetaIcons(props: {
|
|
|
69
78
|
return (
|
|
70
79
|
<TranscriptHeadingMeta className="flex min-w-0 items-center justify-end gap-1.5 text-xs leading-none text-dashboard-text-muted">
|
|
71
80
|
{props.showSlack ? (
|
|
72
|
-
<Tooltip
|
|
73
|
-
<
|
|
74
|
-
|
|
75
|
-
|
|
81
|
+
<Tooltip>
|
|
82
|
+
<TooltipTrigger
|
|
83
|
+
render={
|
|
84
|
+
<span className="inline-flex text-dashboard-text-muted">
|
|
85
|
+
<SlackMark className="size-3.5" />
|
|
86
|
+
</span>
|
|
87
|
+
}
|
|
88
|
+
/>
|
|
89
|
+
<TooltipContent>Slack</TooltipContent>
|
|
76
90
|
</Tooltip>
|
|
77
91
|
) : null}
|
|
78
92
|
<PendingMetaIcon label={delivery.label}>
|
|
79
93
|
<DeliveryIcon
|
|
80
94
|
aria-hidden="true"
|
|
81
|
-
className=
|
|
82
|
-
size={13}
|
|
95
|
+
className="size-3.25"
|
|
83
96
|
strokeWidth={2.2}
|
|
84
97
|
/>
|
|
85
98
|
</PendingMetaIcon>
|
|
86
99
|
{props.onCancel ? (
|
|
87
|
-
<Tooltip
|
|
88
|
-
<
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
100
|
+
<Tooltip>
|
|
101
|
+
<TooltipTrigger
|
|
102
|
+
render={
|
|
103
|
+
<button
|
|
104
|
+
aria-label={
|
|
105
|
+
props.cancelError
|
|
106
|
+
? "Could not remove. Try again."
|
|
107
|
+
: "Remove queued message"
|
|
108
|
+
}
|
|
109
|
+
className="inline-flex size-5 cursor-pointer items-center justify-center rounded-md border-0 bg-transparent p-0 text-dashboard-text-muted transition-colors hover:bg-dashboard-fill-hover hover:text-amber-50 focus-visible:outline focus-visible:outline-1 focus-visible:outline-amber-200/55 disabled:cursor-default disabled:opacity-50"
|
|
110
|
+
disabled={props.cancelDisabled}
|
|
111
|
+
onClick={props.onCancel}
|
|
112
|
+
type="button"
|
|
113
|
+
>
|
|
114
|
+
{props.cancelPending ? (
|
|
115
|
+
<Spinner aria-hidden="true" className="size-3.25" />
|
|
116
|
+
) : (
|
|
117
|
+
<X aria-hidden="true" size={14} strokeWidth={2.2} />
|
|
118
|
+
)}
|
|
119
|
+
</button>
|
|
93
120
|
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
onClick={props.onCancel}
|
|
97
|
-
type="button"
|
|
98
|
-
>
|
|
99
|
-
{props.cancelPending ? (
|
|
100
|
-
<LoaderCircle
|
|
101
|
-
aria-hidden="true"
|
|
102
|
-
className="animate-spin"
|
|
103
|
-
size={13}
|
|
104
|
-
/>
|
|
105
|
-
) : (
|
|
106
|
-
<X aria-hidden="true" size={14} strokeWidth={2.2} />
|
|
107
|
-
)}
|
|
108
|
-
</button>
|
|
121
|
+
/>
|
|
122
|
+
<TooltipContent>Remove queued message</TooltipContent>
|
|
109
123
|
</Tooltip>
|
|
110
124
|
) : null}
|
|
111
125
|
</TranscriptHeadingMeta>
|
|
@@ -16,9 +16,13 @@ shared controls and overlays.
|
|
|
16
16
|
`flush` when the text already sits on the transcript edge. It extends the
|
|
17
17
|
padded control around that text. Do not repeat negative margins at call sites.
|
|
18
18
|
The caller owns the native `details` element and its content.
|
|
19
|
+
`TranscriptSummaryTrigger` gives a `ui/collapsible` trigger the same look.
|
|
20
|
+
Its caller owns the `Collapsible` and its content. Transcript search holds
|
|
21
|
+
event and context rows open.
|
|
19
22
|
- Activity rows (tools, reasoning, and grouped rail events) share one
|
|
20
23
|
layout: a 1rem icon column, an 8px gap, then the title and metadata.
|
|
21
|
-
|
|
24
|
+
Tool and reasoning rows use `ui/trace`. Transcript search forces them open.
|
|
25
|
+
Expanded content sits in `TraceCollapsibleContent` under the title.
|
|
22
26
|
`TranscriptActivityNesting` tells a rail event that it is inside an activity
|
|
23
27
|
group. Outside a group, the rail icon sits in the avatar column so the text
|
|
24
28
|
lines up with message text.
|
|
@@ -40,23 +44,46 @@ shared controls and overlays.
|
|
|
40
44
|
Automation. Render this text with `TranscriptText` or `MentionText`. Both
|
|
41
45
|
require `mentions`, so a caller cannot forget them. Do not resolve names in
|
|
42
46
|
the dashboard, and do not rewrite tokens into links on the server.
|
|
43
|
-
- `TranscriptTurnContextView` owns context content.
|
|
44
|
-
|
|
47
|
+
- `TranscriptTurnContextView` owns context content. A transcript with a
|
|
48
|
+
`turnContextPanel` shows the context in the page panel. See "Page panel".
|
|
49
|
+
Other transcripts, such as a subagent drawer, open a modal `Drawer`. Each
|
|
50
|
+
`Transcript` sets the panel for its own rows, so a nested transcript does not
|
|
51
|
+
use the panel of the page behind it. The panel keys context by message id,
|
|
52
|
+
so every control for one message shows the same open state.
|
|
45
53
|
|
|
46
|
-
Review these components together
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
browser tests cover opening, closing, and keyboard interaction.
|
|
54
|
+
Review these components together on the mock Conversations. Run
|
|
55
|
+
`JUNIOR_DASHBOARD_MOCK_CONVERSATIONS=true pnpm dev` for messages, events,
|
|
56
|
+
activity, context, typing, and attachments. Keep visual checks out of automated
|
|
57
|
+
assertions; browser tests cover opening, closing, and keyboard interaction.
|
|
50
58
|
|
|
51
59
|
## Conversation details
|
|
52
60
|
|
|
53
|
-
`ConversationPage` owns whether details are open.
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
61
|
+
`ConversationPage` owns whether details are open. At 1440px and above, details
|
|
62
|
+
open by default. An explicit choice lasts for the current Conversation. The page
|
|
63
|
+
is keyed by the Conversation, so switching Conversations resets that choice.
|
|
64
|
+
`ConversationHeader` toggles details and restores focus through explicit control
|
|
65
|
+
refs after dismissal.
|
|
57
66
|
|
|
58
|
-
|
|
59
|
-
|
|
67
|
+
## Page panel
|
|
68
|
+
|
|
69
|
+
The Conversation page has one panel on the right. It shows Conversation
|
|
70
|
+
details, event details, or turn context. Only one shows at a time. Each uses
|
|
71
|
+
`DetailsPanel`: a 400px aside at 1280px and above, and a `BottomSheet` below.
|
|
72
|
+
|
|
73
|
+
- Event details and turn context show in place of Conversation details.
|
|
74
|
+
- When you close them, Conversation details show again if they are open. The
|
|
75
|
+
details stay open by choice or by the 1440px default.
|
|
76
|
+
- A link that opens an event sets details to closed. When you close that
|
|
77
|
+
event, no panel shows.
|
|
78
|
+
- The details control closes event details and turn context, then shows or
|
|
79
|
+
hides Conversation details.
|
|
80
|
+
- Turn context belongs to the Conversation view. A view change closes it.
|
|
81
|
+
Select the same context control again to close it.
|
|
82
|
+
- Closing a panel returns focus to the row or control that opened it.
|
|
83
|
+
|
|
84
|
+
`ConversationDetails` owns one set of tabs and content. It supplies its title and
|
|
85
|
+
actions to `DetailsPanel`, which uses a 400px aside at 1280px and above. The chat
|
|
86
|
+
and aside scroll separately.
|
|
60
87
|
Smaller windows use `BottomSheet` with a visible title and close control. The sheet and
|
|
61
88
|
side drawers use the shadcn Base UI `Sheet` and share the app's document
|
|
62
89
|
scroll lock. A resize changes the frame and keeps the selected tab. Tabs stay
|
|
@@ -64,3 +91,52 @@ fixed above the scrolling content in both layouts. The sheet title and close con
|
|
|
64
91
|
control, tap the backdrop, or press Escape to dismiss it. Base UI owns the
|
|
65
92
|
transition lifecycle.
|
|
66
93
|
A pending exit cannot close a new panel or a different Conversation.
|
|
94
|
+
|
|
95
|
+
## Event log
|
|
96
|
+
|
|
97
|
+
`ChatLayout` keeps the Conversation header outside the transcript scroll region.
|
|
98
|
+
`ConversationEventLog` fills the pane without a card border or page inset. Its
|
|
99
|
+
search toolbar and column labels stay together at the top while rows scroll.
|
|
100
|
+
`Transcript` shares the search value with its owner, or keeps it locally when
|
|
101
|
+
used alone. Event log search stays visible; the transcript search toggle is for
|
|
102
|
+
the Conversation view.
|
|
103
|
+
|
|
104
|
+
Rows keep time, event type, and summary in columns when the pane is at least
|
|
105
|
+
512px wide. Smaller panes put the summary below time and type. Model and usage
|
|
106
|
+
metadata share one optional line. Missing model metadata is omitted from rows.
|
|
107
|
+
Selected rows have a background and an accent edge. Up and Down select the
|
|
108
|
+
previous or next visible row while a row has focus. Selection stops at the
|
|
109
|
+
ends of the filtered list. The selected row stays clear of the fixed toolbar.
|
|
110
|
+
`eventLogRows` and `filterEventLogRows` own the row text and search match.
|
|
111
|
+
The page uses them too, so its step controls follow the same rows.
|
|
112
|
+
|
|
113
|
+
The timezone toggle uses `useEventTime` to share a UTC/local preference through
|
|
114
|
+
`@uidotdev/usehooks` and browser local storage. It applies to event row clocks
|
|
115
|
+
and detail timestamps. Local mode follows the browser timezone. The button uses
|
|
116
|
+
a generic zone name because a log can span standard and daylight-saving time.
|
|
117
|
+
Detail timestamps use the zone name for each event date. The mode, not
|
|
118
|
+
the timezone identifier, persists across visits and tabs. This hook belongs to
|
|
119
|
+
the client-rendered event viewer. Raw JSON retains the original ISO values.
|
|
120
|
+
|
|
121
|
+
## Event details
|
|
122
|
+
|
|
123
|
+
The URL owns the selected event in the main Conversation. `ConversationPage`
|
|
124
|
+
places `ConversationEventDetails` beside the log in the page panel. Selecting
|
|
125
|
+
another row changes the event and resets its scroll position and disclosures.
|
|
126
|
+
Closing returns focus to that row. Switching Conversations removes the panel.
|
|
127
|
+
|
|
128
|
+
The previous and next controls select the adjacent visible row. They follow
|
|
129
|
+
the event search, like Up and Down. They are necessary below 1280px, where the
|
|
130
|
+
sheet covers the log. At the ends of the list, the control is disabled but
|
|
131
|
+
keeps focus. The sheet title is the event type.
|
|
132
|
+
|
|
133
|
+
A linked event can be older than the loaded pages. While the event loads, the
|
|
134
|
+
panel stays open. Only its header shows placeholders, so it does not compete
|
|
135
|
+
with the log. While the transcript loads, `ConversationEventLogLoading` shows
|
|
136
|
+
the log toolbar, columns, and row skeletons in the event log view.
|
|
137
|
+
|
|
138
|
+
Standalone transcripts, such as a subagent drawer, keep selection in
|
|
139
|
+
`ConversationEventLog`. Their event details use a nested drawer on desktop and
|
|
140
|
+
`BottomSheet` on smaller screens. This keeps the main log free of modal behavior
|
|
141
|
+
while a nested transcript retains its parent drawer's focus rules. These event
|
|
142
|
+
details have the same previous and next controls.
|
|
@@ -2,8 +2,12 @@ import { useState } from "react";
|
|
|
2
2
|
import { useHref } from "react-router";
|
|
3
3
|
import { Check, Share2 } from "lucide-react";
|
|
4
4
|
|
|
5
|
-
import { Button } from "../components/
|
|
6
|
-
import {
|
|
5
|
+
import { Button } from "../components/ui/button";
|
|
6
|
+
import {
|
|
7
|
+
Tooltip,
|
|
8
|
+
TooltipContent,
|
|
9
|
+
TooltipTrigger,
|
|
10
|
+
} from "../components/ui/tooltip";
|
|
7
11
|
import { conversationPath } from "./conversationRoutes";
|
|
8
12
|
|
|
9
13
|
/** Share a conversation link without changing who can access it. */
|
|
@@ -72,27 +76,34 @@ export function ShareConversationButton(props: {
|
|
|
72
76
|
);
|
|
73
77
|
const button =
|
|
74
78
|
props.layout === "icon" ? (
|
|
75
|
-
<
|
|
76
|
-
<
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
79
|
+
<Tooltip>
|
|
80
|
+
<TooltipTrigger
|
|
81
|
+
render={
|
|
82
|
+
<Button
|
|
83
|
+
focusableWhenDisabled
|
|
84
|
+
aria-label={label}
|
|
85
|
+
className="text-dashboard-text-muted"
|
|
86
|
+
disabled={status === "sharing"}
|
|
87
|
+
onClick={() => void shareLink()}
|
|
88
|
+
size="icon"
|
|
89
|
+
>
|
|
90
|
+
<Icon aria-hidden="true" size={15} />
|
|
91
|
+
</Button>
|
|
92
|
+
}
|
|
93
|
+
/>
|
|
94
|
+
<TooltipContent size="compact" side="bottom">
|
|
95
|
+
{label}
|
|
96
|
+
</TooltipContent>
|
|
97
|
+
</Tooltip>
|
|
86
98
|
) : props.layout === "menu" ? (
|
|
87
|
-
<
|
|
99
|
+
<Button
|
|
88
100
|
aria-label={label}
|
|
89
|
-
className="flex w-full cursor-pointer 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 transition-colors hover:bg-dashboard-fill-hover focus-visible:bg-dashboard-fill-hover focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50"
|
|
90
101
|
disabled={status === "sharing"}
|
|
91
102
|
onClick={() => void shareLink()}
|
|
92
|
-
|
|
103
|
+
size="menu"
|
|
93
104
|
>
|
|
94
105
|
{content}
|
|
95
|
-
</
|
|
106
|
+
</Button>
|
|
96
107
|
) : (
|
|
97
108
|
<Button
|
|
98
109
|
aria-label={label}
|