@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
|
@@ -10,8 +10,13 @@ import {
|
|
|
10
10
|
X,
|
|
11
11
|
} from "lucide-react";
|
|
12
12
|
|
|
13
|
-
import { Button
|
|
14
|
-
import {
|
|
13
|
+
import { Button } from "../components/ui/button";
|
|
14
|
+
import {
|
|
15
|
+
Tooltip,
|
|
16
|
+
TooltipContent,
|
|
17
|
+
TooltipTrigger,
|
|
18
|
+
} from "../components/ui/tooltip";
|
|
19
|
+
import { ToggleGroup, ToggleGroupItem } from "../components/ui/toggle-group";
|
|
15
20
|
import { cn } from "../styles";
|
|
16
21
|
import type { TranscriptViewMode } from "./transcriptRenderModel";
|
|
17
22
|
import { ShareConversationButton } from "./ShareConversationButton";
|
|
@@ -43,17 +48,19 @@ export function ConversationHeaderActions(props: {
|
|
|
43
48
|
if (layout === "menu") {
|
|
44
49
|
return (
|
|
45
50
|
<div className="grid gap-0.5">
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
51
|
+
{props.view === "rich" ? (
|
|
52
|
+
<MenuActionButton
|
|
53
|
+
label={props.searchOpen ? "Hide search" : "Search transcript"}
|
|
54
|
+
onClick={props.onSearchClick}
|
|
55
|
+
pressed={props.searchOpen}
|
|
56
|
+
>
|
|
57
|
+
{props.searchOpen ? (
|
|
58
|
+
<X aria-hidden="true" size={16} strokeWidth={2} />
|
|
59
|
+
) : (
|
|
60
|
+
<Search aria-hidden="true" size={16} strokeWidth={2} />
|
|
61
|
+
)}
|
|
62
|
+
</MenuActionButton>
|
|
63
|
+
) : null}
|
|
57
64
|
<MenuActionButton
|
|
58
65
|
label="Conversation"
|
|
59
66
|
onClick={() => props.onViewChange("rich")}
|
|
@@ -88,10 +95,12 @@ export function ConversationHeaderActions(props: {
|
|
|
88
95
|
|
|
89
96
|
return (
|
|
90
97
|
<div className="flex shrink-0 items-center gap-0.5">
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
98
|
+
{props.view === "rich" ? (
|
|
99
|
+
<TranscriptSearchToggle
|
|
100
|
+
onClick={props.onSearchClick}
|
|
101
|
+
open={props.searchOpen}
|
|
102
|
+
/>
|
|
103
|
+
) : null}
|
|
95
104
|
{props.copyAction}
|
|
96
105
|
<ArchiveConversationButton {...props.archive} layout="bar" />
|
|
97
106
|
<Button
|
|
@@ -115,67 +124,55 @@ export function TranscriptViewToggle(props: {
|
|
|
115
124
|
value: TranscriptViewMode;
|
|
116
125
|
}) {
|
|
117
126
|
return (
|
|
118
|
-
<
|
|
127
|
+
<ToggleGroup
|
|
119
128
|
aria-label="Transcript view"
|
|
120
129
|
className={
|
|
121
130
|
props.labelled
|
|
122
|
-
? "inline-flex
|
|
123
|
-
: "inline-flex
|
|
131
|
+
? "inline-flex gap-6"
|
|
132
|
+
: "inline-flex gap-0.5 rounded-md border border-dashboard-border bg-dashboard-overlay-soft p-0.5"
|
|
124
133
|
}
|
|
125
|
-
|
|
134
|
+
onValueChange={([next]) => {
|
|
135
|
+
if (next) props.onChange(next);
|
|
136
|
+
}}
|
|
137
|
+
value={[props.value]}
|
|
126
138
|
>
|
|
127
|
-
<
|
|
128
|
-
active={props.value === "rich"}
|
|
129
|
-
label="Conversation"
|
|
130
|
-
labelled={props.labelled}
|
|
131
|
-
onClick={() => props.onChange("rich")}
|
|
132
|
-
>
|
|
139
|
+
<ViewModeItem label="Conversation" labelled={props.labelled} value="rich">
|
|
133
140
|
<MessagesSquare aria-hidden="true" size={14} strokeWidth={2} />
|
|
134
|
-
</
|
|
135
|
-
<
|
|
136
|
-
active={props.value === "raw"}
|
|
137
|
-
label="Event log"
|
|
138
|
-
labelled={props.labelled}
|
|
139
|
-
onClick={() => props.onChange("raw")}
|
|
140
|
-
>
|
|
141
|
+
</ViewModeItem>
|
|
142
|
+
<ViewModeItem label="Event log" labelled={props.labelled} value="raw">
|
|
141
143
|
<ScrollText aria-hidden="true" size={14} strokeWidth={2} />
|
|
142
|
-
</
|
|
143
|
-
</
|
|
144
|
+
</ViewModeItem>
|
|
145
|
+
</ToggleGroup>
|
|
144
146
|
);
|
|
145
147
|
}
|
|
146
148
|
|
|
147
|
-
function
|
|
148
|
-
active: boolean;
|
|
149
|
+
function ViewModeItem(props: {
|
|
149
150
|
children: ReactNode;
|
|
150
151
|
label: string;
|
|
151
152
|
labelled?: boolean;
|
|
152
|
-
|
|
153
|
+
value: TranscriptViewMode;
|
|
153
154
|
}) {
|
|
154
|
-
const
|
|
155
|
-
<
|
|
155
|
+
const item = (
|
|
156
|
+
<ToggleGroupItem
|
|
156
157
|
aria-label={props.label}
|
|
157
|
-
className={
|
|
158
|
-
"!no-underline",
|
|
158
|
+
className={
|
|
159
159
|
props.labelled
|
|
160
|
-
? "relative
|
|
161
|
-
: "
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
? "text-dashboard-text after:bg-dashboard-text-solid"
|
|
165
|
-
: "bg-dashboard-fill-hover text-dashboard-text"),
|
|
166
|
-
)}
|
|
167
|
-
onClick={props.onClick}
|
|
168
|
-
pressed={props.active}
|
|
169
|
-
variant="text"
|
|
160
|
+
? "relative h-11 min-w-0 gap-2 rounded-none border-0 px-0 text-sm hover:bg-transparent after:absolute after:inset-x-0 after:bottom-0 after:h-0.5 data-pressed:border-0 data-pressed:bg-transparent data-pressed:after:bg-dashboard-text-solid"
|
|
161
|
+
: "size-7 min-w-0 border-0 px-0 data-pressed:border-0 data-pressed:bg-dashboard-fill-hover"
|
|
162
|
+
}
|
|
163
|
+
value={props.value}
|
|
170
164
|
>
|
|
171
165
|
{props.children}
|
|
172
166
|
{props.labelled ? props.label : null}
|
|
173
|
-
</
|
|
167
|
+
</ToggleGroupItem>
|
|
174
168
|
);
|
|
175
169
|
return props.labelled ? (
|
|
176
|
-
|
|
170
|
+
item
|
|
177
171
|
) : (
|
|
178
|
-
<
|
|
172
|
+
<Tooltip>
|
|
173
|
+
<TooltipTrigger render={item} />
|
|
174
|
+
<TooltipContent size="compact">{props.label}</TooltipContent>
|
|
175
|
+
</Tooltip>
|
|
179
176
|
);
|
|
180
177
|
}
|
|
181
178
|
|
|
@@ -188,21 +185,26 @@ export function HeaderIconButton(props: {
|
|
|
188
185
|
pressed?: boolean;
|
|
189
186
|
}) {
|
|
190
187
|
return (
|
|
191
|
-
<
|
|
192
|
-
<
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
188
|
+
<Tooltip>
|
|
189
|
+
<TooltipTrigger
|
|
190
|
+
render={
|
|
191
|
+
<Button
|
|
192
|
+
ref={props.ref}
|
|
193
|
+
aria-label={props.label}
|
|
194
|
+
aria-pressed={props.pressed}
|
|
195
|
+
className={cn(
|
|
196
|
+
"text-dashboard-text-muted",
|
|
197
|
+
props.pressed && "bg-dashboard-fill-strong text-dashboard-text",
|
|
198
|
+
)}
|
|
199
|
+
onClick={props.onClick}
|
|
200
|
+
size="icon"
|
|
201
|
+
>
|
|
202
|
+
{props.children}
|
|
203
|
+
</Button>
|
|
204
|
+
}
|
|
205
|
+
/>
|
|
206
|
+
<TooltipContent size="compact">{props.label}</TooltipContent>
|
|
207
|
+
</Tooltip>
|
|
206
208
|
);
|
|
207
209
|
}
|
|
208
210
|
|
|
@@ -233,19 +235,16 @@ function MenuActionButton(props: {
|
|
|
233
235
|
pressed?: boolean;
|
|
234
236
|
}) {
|
|
235
237
|
return (
|
|
236
|
-
<
|
|
238
|
+
<Button
|
|
237
239
|
aria-label={props.label}
|
|
238
240
|
aria-pressed={props.pressed}
|
|
239
|
-
className={
|
|
240
|
-
"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-strong focus-visible:bg-dashboard-fill-strong focus-visible:outline-none",
|
|
241
|
-
props.pressed && "bg-dashboard-fill-strong",
|
|
242
|
-
)}
|
|
241
|
+
className={props.pressed ? "bg-dashboard-fill-strong" : undefined}
|
|
243
242
|
onClick={props.onClick}
|
|
244
|
-
|
|
243
|
+
size="menu"
|
|
245
244
|
>
|
|
246
245
|
{props.children}
|
|
247
246
|
<span>{props.label}</span>
|
|
248
|
-
</
|
|
247
|
+
</Button>
|
|
249
248
|
);
|
|
250
249
|
}
|
|
251
250
|
|
|
@@ -260,29 +259,34 @@ function ArchiveConversationButton(
|
|
|
260
259
|
const Icon = props.archived ? ArchiveRestore : Archive;
|
|
261
260
|
if (props.layout === "menu") {
|
|
262
261
|
return (
|
|
263
|
-
<
|
|
262
|
+
<Button
|
|
264
263
|
aria-label={label}
|
|
265
|
-
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-strong focus-visible:bg-dashboard-fill-strong focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50"
|
|
266
264
|
disabled={props.disabled}
|
|
267
265
|
onClick={props.onClick}
|
|
268
|
-
|
|
266
|
+
size="menu"
|
|
269
267
|
>
|
|
270
268
|
<Icon aria-hidden="true" size={16} strokeWidth={2} />
|
|
271
269
|
<span>{label}</span>
|
|
272
|
-
</
|
|
270
|
+
</Button>
|
|
273
271
|
);
|
|
274
272
|
}
|
|
275
273
|
return (
|
|
276
|
-
<
|
|
277
|
-
<
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
274
|
+
<Tooltip>
|
|
275
|
+
<TooltipTrigger
|
|
276
|
+
render={
|
|
277
|
+
<Button
|
|
278
|
+
focusableWhenDisabled
|
|
279
|
+
aria-label={label}
|
|
280
|
+
className="hidden shrink-0 text-dashboard-text-muted md:grid"
|
|
281
|
+
disabled={props.disabled}
|
|
282
|
+
onClick={props.onClick}
|
|
283
|
+
size="icon"
|
|
284
|
+
>
|
|
285
|
+
<Icon aria-hidden="true" size={15} strokeWidth={2} />
|
|
286
|
+
</Button>
|
|
287
|
+
}
|
|
288
|
+
/>
|
|
289
|
+
<TooltipContent size="compact">{label}</TooltipContent>
|
|
290
|
+
</Tooltip>
|
|
287
291
|
);
|
|
288
292
|
}
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
visualStatusForConversation,
|
|
10
10
|
} from "../format";
|
|
11
11
|
import { EmptyTelemetry } from "../components/EmptyTelemetry";
|
|
12
|
-
import { Skeleton } from "../components/
|
|
12
|
+
import { Skeleton } from "../components/ui/skeleton";
|
|
13
13
|
import {
|
|
14
14
|
conversationParticipants,
|
|
15
15
|
ParticipantAvatarStack,
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import type { ObjectType } from "@sentry/junior-plugin-api";
|
|
2
|
+
import type { ConversationDetailReport } from "@sentry/junior/api/schema";
|
|
3
|
+
|
|
4
|
+
import { ObjectIcon } from "../components/ObjectIcon";
|
|
5
|
+
import { DetailsList, DetailsRow, DetailsRowLine } from "./DetailsList";
|
|
6
|
+
|
|
7
|
+
type ConversationAnnotation = NonNullable<
|
|
8
|
+
ConversationDetailReport["annotations"]
|
|
9
|
+
>[number];
|
|
10
|
+
|
|
11
|
+
/** One annotation that links to work outside Junior. */
|
|
12
|
+
export type ConversationLink = {
|
|
13
|
+
description?: string;
|
|
14
|
+
facts?: { type: string };
|
|
15
|
+
key: string;
|
|
16
|
+
label: string;
|
|
17
|
+
objectType: ObjectType;
|
|
18
|
+
plugin: string;
|
|
19
|
+
status?: string;
|
|
20
|
+
url: string;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const resourceLinkStatusLabels: Record<string, string> = {
|
|
24
|
+
closed: "Closed",
|
|
25
|
+
draft: "Draft",
|
|
26
|
+
merged: "Merged",
|
|
27
|
+
open: "Open",
|
|
28
|
+
warning: "Needs attention",
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/** Name a link status for a reader, such as "Merged" for `merged`. */
|
|
32
|
+
export function linkStatusLabel(status: string | undefined): string {
|
|
33
|
+
if (!status) return "";
|
|
34
|
+
return (
|
|
35
|
+
resourceLinkStatusLabels[status] ??
|
|
36
|
+
status.charAt(0).toUpperCase() + status.slice(1)
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Pick the annotations that link to outside work, newest first as saved. A
|
|
42
|
+
* resource link without an object type takes the type of its sidebar
|
|
43
|
+
* annotation.
|
|
44
|
+
*/
|
|
45
|
+
export function conversationLinks(
|
|
46
|
+
detail: ConversationDetailReport | undefined,
|
|
47
|
+
): ConversationLink[] {
|
|
48
|
+
return (detail?.annotations ?? []).flatMap(
|
|
49
|
+
(annotation: ConversationAnnotation): ConversationLink[] => {
|
|
50
|
+
if (!annotation.url) return [];
|
|
51
|
+
const objectType =
|
|
52
|
+
annotation.objectType ??
|
|
53
|
+
detail?.sidebarAnnotations?.find(
|
|
54
|
+
(sidebar) => sidebar.key === annotation.key,
|
|
55
|
+
)?.objectType ??
|
|
56
|
+
"item";
|
|
57
|
+
const description =
|
|
58
|
+
annotation.kind === "object"
|
|
59
|
+
? annotation.title !== annotation.label
|
|
60
|
+
? annotation.title
|
|
61
|
+
: annotation.description
|
|
62
|
+
: annotation.description;
|
|
63
|
+
return [
|
|
64
|
+
{
|
|
65
|
+
...(description ? { description } : undefined),
|
|
66
|
+
...(annotation.kind === "object" && annotation.facts
|
|
67
|
+
? { facts: annotation.facts }
|
|
68
|
+
: undefined),
|
|
69
|
+
key: `${annotation.plugin}:${annotation.key}`,
|
|
70
|
+
label: annotation.label,
|
|
71
|
+
objectType,
|
|
72
|
+
plugin: annotation.plugin,
|
|
73
|
+
...(annotation.status ? { status: annotation.status } : undefined),
|
|
74
|
+
url: annotation.url,
|
|
75
|
+
},
|
|
76
|
+
];
|
|
77
|
+
},
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** Show the outside work that a Conversation links to, one row each. */
|
|
82
|
+
export function ConversationLinkedWork(props: { links: ConversationLink[] }) {
|
|
83
|
+
return (
|
|
84
|
+
<DetailsList
|
|
85
|
+
itemKey={(link) => link.key}
|
|
86
|
+
items={props.links}
|
|
87
|
+
renderItem={(link) => {
|
|
88
|
+
const status = linkStatusLabel(link.status);
|
|
89
|
+
return (
|
|
90
|
+
<DetailsRow
|
|
91
|
+
href={link.url}
|
|
92
|
+
icon={
|
|
93
|
+
// The row text names the status, so the icon stays silent.
|
|
94
|
+
<ObjectIcon
|
|
95
|
+
decorative
|
|
96
|
+
facts={link.facts}
|
|
97
|
+
objectType={link.objectType}
|
|
98
|
+
size={14}
|
|
99
|
+
status={link.status}
|
|
100
|
+
/>
|
|
101
|
+
}
|
|
102
|
+
meta={status}
|
|
103
|
+
title={link.label}
|
|
104
|
+
tooltip={[link.label, link.plugin, status, link.description]
|
|
105
|
+
.filter(Boolean)
|
|
106
|
+
.join(" · ")}
|
|
107
|
+
>
|
|
108
|
+
{link.description ? (
|
|
109
|
+
<DetailsRowLine className="line-clamp-2 break-words">
|
|
110
|
+
{link.description}
|
|
111
|
+
</DetailsRowLine>
|
|
112
|
+
) : null}
|
|
113
|
+
</DetailsRow>
|
|
114
|
+
);
|
|
115
|
+
}}
|
|
116
|
+
/>
|
|
117
|
+
);
|
|
118
|
+
}
|
|
@@ -24,7 +24,12 @@ import {
|
|
|
24
24
|
summarizeUsage,
|
|
25
25
|
automationPath,
|
|
26
26
|
} from "../format";
|
|
27
|
-
import {
|
|
27
|
+
import {
|
|
28
|
+
Tooltip,
|
|
29
|
+
TooltipContent,
|
|
30
|
+
TooltipTitle,
|
|
31
|
+
TooltipTrigger,
|
|
32
|
+
} from "../components/ui/tooltip";
|
|
28
33
|
import { MetricList, type MetricListItem } from "../components/Metric";
|
|
29
34
|
import { cn, dashboardInlineLinkClass } from "../styles";
|
|
30
35
|
import {
|
|
@@ -39,6 +44,7 @@ import {
|
|
|
39
44
|
type SidebarAnnotation,
|
|
40
45
|
type SidebarAnnotationBadgeGroup,
|
|
41
46
|
} from "./sidebarAnnotationBadges";
|
|
47
|
+
import { conversationLinks, linkStatusLabel } from "./ConversationLinkedWork";
|
|
42
48
|
|
|
43
49
|
const MOBILE_MEDIA_QUERY = "(max-width: 767px)";
|
|
44
50
|
|
|
@@ -100,13 +106,6 @@ export function ConversationPrivacyChip(props: {
|
|
|
100
106
|
);
|
|
101
107
|
}
|
|
102
108
|
|
|
103
|
-
type ResourceLinkStatus = NonNullable<
|
|
104
|
-
Extract<
|
|
105
|
-
NonNullable<ConversationDetailReport["annotations"]>[number],
|
|
106
|
-
{ kind: "resource_link" }
|
|
107
|
-
>["status"]
|
|
108
|
-
>;
|
|
109
|
-
|
|
110
109
|
/** True when the conversation has at least one resource-link annotation. */
|
|
111
110
|
export function hasConversationAnnotations(
|
|
112
111
|
annotations: ConversationDetailReport["annotations"] | undefined,
|
|
@@ -136,9 +135,36 @@ export function ConversationSidebarAnnotations(props: {
|
|
|
136
135
|
: [];
|
|
137
136
|
|
|
138
137
|
return (
|
|
139
|
-
<Tooltip
|
|
140
|
-
|
|
141
|
-
|
|
138
|
+
<Tooltip>
|
|
139
|
+
<TooltipTrigger
|
|
140
|
+
render={
|
|
141
|
+
<span
|
|
142
|
+
aria-label={`Linked work, newest first: ${details.join(", ")}`}
|
|
143
|
+
className="inline-flex min-w-0 max-w-full items-center"
|
|
144
|
+
>
|
|
145
|
+
{useMobileFacepile ? (
|
|
146
|
+
<SidebarAnnotationIconFacepile
|
|
147
|
+
annotations={mobileFacepileAnnotations}
|
|
148
|
+
// Discs sit on the sidebar panel / row surface.
|
|
149
|
+
cutoutColor="var(--color-dashboard-surface-panel)"
|
|
150
|
+
/>
|
|
151
|
+
) : (
|
|
152
|
+
<span className="inline-flex min-w-0 items-center gap-1">
|
|
153
|
+
{badges.labeledGroups.map((group) => (
|
|
154
|
+
<SidebarAnnotationGroupChip group={group} key={group.label} />
|
|
155
|
+
))}
|
|
156
|
+
{badges.overflowGroupCount > 0 ? (
|
|
157
|
+
<span className="inline-flex h-5 min-w-7 shrink-0 items-center justify-center rounded-full border border-dashboard-border-strong bg-dashboard-control px-1.5 font-sans text-2xs tabular-nums leading-none text-dashboard-text-muted">
|
|
158
|
+
+{badges.overflowGroupCount}
|
|
159
|
+
</span>
|
|
160
|
+
) : null}
|
|
161
|
+
</span>
|
|
162
|
+
)}
|
|
163
|
+
</span>
|
|
164
|
+
}
|
|
165
|
+
/>
|
|
166
|
+
<TooltipContent align="start">
|
|
167
|
+
<TooltipTitle>Linked work</TooltipTitle>
|
|
142
168
|
<ul className="m-0 list-none space-y-1 p-0">
|
|
143
169
|
{annotations.map((annotation, index) => (
|
|
144
170
|
<li
|
|
@@ -158,33 +184,7 @@ export function ConversationSidebarAnnotations(props: {
|
|
|
158
184
|
</li>
|
|
159
185
|
))}
|
|
160
186
|
</ul>
|
|
161
|
-
|
|
162
|
-
label="Linked work"
|
|
163
|
-
triggerClassName="min-w-0"
|
|
164
|
-
>
|
|
165
|
-
<span
|
|
166
|
-
aria-label={`Linked work, newest first: ${details.join(", ")}`}
|
|
167
|
-
className="inline-flex min-w-0 max-w-full items-center"
|
|
168
|
-
>
|
|
169
|
-
{useMobileFacepile ? (
|
|
170
|
-
<SidebarAnnotationIconFacepile
|
|
171
|
-
annotations={mobileFacepileAnnotations}
|
|
172
|
-
// Discs sit on the sidebar panel / row surface.
|
|
173
|
-
cutoutColor="var(--color-dashboard-surface-panel)"
|
|
174
|
-
/>
|
|
175
|
-
) : (
|
|
176
|
-
<span className="inline-flex min-w-0 items-center gap-1">
|
|
177
|
-
{badges.labeledGroups.map((group) => (
|
|
178
|
-
<SidebarAnnotationGroupChip group={group} key={group.label} />
|
|
179
|
-
))}
|
|
180
|
-
{badges.overflowGroupCount > 0 ? (
|
|
181
|
-
<span className="inline-flex h-5 min-w-7 shrink-0 items-center justify-center rounded-full border border-dashboard-border-strong bg-dashboard-control px-1.5 font-sans text-2xs tabular-nums leading-none text-dashboard-text-muted">
|
|
182
|
-
+{badges.overflowGroupCount}
|
|
183
|
-
</span>
|
|
184
|
-
) : null}
|
|
185
|
-
</span>
|
|
186
|
-
)}
|
|
187
|
-
</span>
|
|
187
|
+
</TooltipContent>
|
|
188
188
|
</Tooltip>
|
|
189
189
|
);
|
|
190
190
|
}
|
|
@@ -412,48 +412,35 @@ function SidebarAnnotationIcon(props: {
|
|
|
412
412
|
);
|
|
413
413
|
}
|
|
414
414
|
|
|
415
|
-
/** Render
|
|
415
|
+
/** Render linked work as a compact strip under the conversation title. */
|
|
416
416
|
export function ConversationAnnotations(props: {
|
|
417
417
|
detail: ConversationDetailReport | undefined;
|
|
418
|
-
layout?: "list" | "strip";
|
|
419
418
|
}) {
|
|
420
|
-
const links =
|
|
421
|
-
props.detail?.annotations?.filter(
|
|
422
|
-
(annotation) => annotation.url !== null,
|
|
423
|
-
) ?? [];
|
|
419
|
+
const links = conversationLinks(props.detail);
|
|
424
420
|
if (links.length === 0) return null;
|
|
425
421
|
return (
|
|
426
|
-
<div
|
|
427
|
-
className={cn(
|
|
428
|
-
"flex gap-x-4 gap-y-2",
|
|
429
|
-
props.layout === "strip" ? "overflow-x-auto" : "flex-col",
|
|
430
|
-
)}
|
|
431
|
-
>
|
|
422
|
+
<div className="flex gap-x-4 gap-y-2 overflow-x-auto">
|
|
432
423
|
{links.map((link) => (
|
|
433
424
|
<a
|
|
434
|
-
className=
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
? "px-1 py-0.5 text-xs hover:text-dashboard-accent-text"
|
|
438
|
-
: "min-h-10 border border-dashboard-border px-3 py-2 text-sm hover:border-dashboard-border-interactive hover:bg-dashboard-surface-hover",
|
|
439
|
-
)}
|
|
440
|
-
href={link.url ?? undefined}
|
|
441
|
-
key={`${link.plugin}:${link.key}`}
|
|
425
|
+
className="inline-flex min-w-0 max-w-full shrink-0 items-center gap-2 rounded-md px-1 py-0.5 font-sans text-xs leading-snug text-dashboard-text no-underline transition-colors hover:text-dashboard-accent-text focus-visible:outline focus-visible:outline-2 focus-visible:outline-dashboard-focus"
|
|
426
|
+
href={link.url}
|
|
427
|
+
key={link.key}
|
|
442
428
|
rel="noreferrer"
|
|
443
429
|
target="_blank"
|
|
444
|
-
title={
|
|
430
|
+
title={[
|
|
431
|
+
link.label,
|
|
432
|
+
link.plugin,
|
|
433
|
+
linkStatusLabel(link.status),
|
|
434
|
+
link.description,
|
|
435
|
+
]
|
|
436
|
+
.filter(Boolean)
|
|
437
|
+
.join(" · ")}
|
|
445
438
|
>
|
|
446
439
|
<ObjectIcon
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
props.detail?.sidebarAnnotations?.find(
|
|
450
|
-
(annotation) => annotation.key === link.key,
|
|
451
|
-
)?.objectType ??
|
|
452
|
-
"item"
|
|
453
|
-
}
|
|
454
|
-
status={link.status}
|
|
455
|
-
facts={link.kind === "object" ? link.facts : undefined}
|
|
440
|
+
facts={link.facts}
|
|
441
|
+
objectType={link.objectType}
|
|
456
442
|
size={16}
|
|
443
|
+
status={link.status}
|
|
457
444
|
/>
|
|
458
445
|
<span className="min-w-0 break-words">{link.label}</span>
|
|
459
446
|
</a>
|
|
@@ -462,26 +449,6 @@ export function ConversationAnnotations(props: {
|
|
|
462
449
|
);
|
|
463
450
|
}
|
|
464
451
|
|
|
465
|
-
function resourceLinkTitle(link: {
|
|
466
|
-
description?: string;
|
|
467
|
-
label: string;
|
|
468
|
-
plugin: string;
|
|
469
|
-
status?: ResourceLinkStatus;
|
|
470
|
-
}): string {
|
|
471
|
-
const statusLabel = link.status
|
|
472
|
-
? {
|
|
473
|
-
open: "Open",
|
|
474
|
-
draft: "Draft",
|
|
475
|
-
closed: "Closed",
|
|
476
|
-
merged: "Merged",
|
|
477
|
-
warning: "Needs attention",
|
|
478
|
-
}[link.status]
|
|
479
|
-
: undefined;
|
|
480
|
-
return [link.label, link.plugin, statusLabel, link.description]
|
|
481
|
-
.filter(Boolean)
|
|
482
|
-
.join(" · ");
|
|
483
|
-
}
|
|
484
|
-
|
|
485
452
|
function LocationLink(props: { label: string; locationUrl?: string }) {
|
|
486
453
|
return props.locationUrl ? (
|
|
487
454
|
<a
|