@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.
- package/LICENSE +201 -0
- package/README.md +2 -5
- package/dist/app.js +119 -35
- package/dist/client.js +148 -135
- package/dist/index.d.ts +0 -1
- package/dist/index.js +119 -35
- package/dist/tailwind.css +1 -1
- package/package.json +9 -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/BottomSheet.tsx +26 -18
- package/src/client/components/CopyButton.tsx +83 -0
- package/src/client/components/DetailsPanel.tsx +133 -0
- package/src/client/components/Drawer.tsx +34 -33
- package/src/client/components/FilterBar.tsx +16 -31
- package/src/client/components/Metric.tsx +33 -23
- package/src/client/components/PageContentSkeleton.tsx +1 -1
- package/src/client/components/Pagination.tsx +1 -1
- package/src/client/components/ParticipantAvatarStack.tsx +40 -36
- package/src/client/components/ProfileMenu.tsx +27 -93
- package/src/client/components/README.md +101 -64
- 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/charts/ActivityChart.tsx +173 -288
- package/src/client/components/charts/CacheWrites.tsx +63 -50
- 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/button.tsx +85 -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/field.tsx +49 -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/popover.tsx +67 -0
- package/src/client/components/ui/radio-group.tsx +32 -0
- package/src/client/components/ui/sheet.tsx +151 -0
- package/src/client/components/ui/skeleton.tsx +19 -0
- package/src/client/components/ui/table.tsx +80 -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/components/ui/useSheet.ts +74 -0
- package/src/client/conversations/ChatLayout.tsx +7 -3
- package/src/client/conversations/ConversationBrief.tsx +17 -6
- package/src/client/conversations/ConversationChildAgents.tsx +87 -58
- package/src/client/conversations/ConversationComposer.tsx +26 -12
- package/src/client/conversations/ConversationDetails.tsx +198 -95
- package/src/client/conversations/ConversationEventDetails.tsx +141 -0
- package/src/client/conversations/ConversationEventLog.tsx +150 -129
- package/src/client/conversations/ConversationHeader.tsx +8 -3
- package/src/client/conversations/ConversationHeaderActions.tsx +90 -82
- package/src/client/conversations/ConversationHomeList.tsx +1 -1
- package/src/client/conversations/ConversationLinkedWork.tsx +118 -0
- package/src/client/conversations/ConversationMeta.tsx +111 -92
- package/src/client/conversations/ConversationPage.tsx +241 -110
- package/src/client/conversations/ConversationSidebar.tsx +48 -29
- package/src/client/conversations/ConversationUsageBreakdown.tsx +16 -3
- package/src/client/conversations/ConversationWatches.tsx +165 -0
- package/src/client/conversations/ConversationWorkspace.tsx +12 -22
- package/src/client/conversations/ConversationWorkspaceLoading.tsx +1 -1
- package/src/client/conversations/DetailsList.tsx +124 -0
- package/src/client/conversations/EventDetails.tsx +42 -8
- package/src/client/conversations/ForkConversationButton.tsx +27 -16
- package/src/client/conversations/ObjectCard.tsx +20 -8
- package/src/client/conversations/PendingMailboxStack.tsx +52 -33
- package/src/client/conversations/README.md +93 -19
- package/src/client/conversations/ShareConversationButton.tsx +28 -3
- 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/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 +8 -2
- package/src/client/conversations/TranscriptMessageView.tsx +6 -1
- package/src/client/conversations/TranscriptReasoningView.tsx +54 -68
- package/src/client/conversations/TranscriptSubagentView.tsx +3 -3
- package/src/client/conversations/TranscriptTimestamp.tsx +9 -7
- package/src/client/conversations/TranscriptToolView.tsx +1 -1
- package/src/client/conversations/TranscriptTurnContextView.tsx +99 -27
- package/src/client/conversations/TranscriptView.tsx +63 -27
- package/src/client/conversations/eventLog.ts +57 -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/format.ts +5 -0
- package/src/client/lib/utils.ts +1 -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 +77 -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/Sheet.LICENSE +0 -21
- package/src/client/components/Sheet.tsx +0 -141
- 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/conversations/ConversationDetailsFrame.tsx +0 -91
- 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
|
@@ -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
|
+
}
|
|
@@ -16,13 +16,20 @@ import type { ConversationDetailReport } from "@sentry/junior/api/schema";
|
|
|
16
16
|
|
|
17
17
|
import {
|
|
18
18
|
formatConversationDuration,
|
|
19
|
+
formatRelativeTime,
|
|
20
|
+
formatTime,
|
|
19
21
|
slackLocationLabel,
|
|
20
22
|
summarizeCost,
|
|
21
23
|
summarizeModelUsage,
|
|
22
24
|
summarizeUsage,
|
|
23
25
|
automationPath,
|
|
24
26
|
} from "../format";
|
|
25
|
-
import {
|
|
27
|
+
import {
|
|
28
|
+
Tooltip,
|
|
29
|
+
TooltipContent,
|
|
30
|
+
TooltipTitle,
|
|
31
|
+
TooltipTrigger,
|
|
32
|
+
} from "../components/ui/tooltip";
|
|
26
33
|
import { MetricList, type MetricListItem } from "../components/Metric";
|
|
27
34
|
import { cn, dashboardInlineLinkClass } from "../styles";
|
|
28
35
|
import {
|
|
@@ -37,6 +44,7 @@ import {
|
|
|
37
44
|
type SidebarAnnotation,
|
|
38
45
|
type SidebarAnnotationBadgeGroup,
|
|
39
46
|
} from "./sidebarAnnotationBadges";
|
|
47
|
+
import { conversationLinks, linkStatusLabel } from "./ConversationLinkedWork";
|
|
40
48
|
|
|
41
49
|
const MOBILE_MEDIA_QUERY = "(max-width: 767px)";
|
|
42
50
|
|
|
@@ -98,13 +106,6 @@ export function ConversationPrivacyChip(props: {
|
|
|
98
106
|
);
|
|
99
107
|
}
|
|
100
108
|
|
|
101
|
-
type ResourceLinkStatus = NonNullable<
|
|
102
|
-
Extract<
|
|
103
|
-
NonNullable<ConversationDetailReport["annotations"]>[number],
|
|
104
|
-
{ kind: "resource_link" }
|
|
105
|
-
>["status"]
|
|
106
|
-
>;
|
|
107
|
-
|
|
108
109
|
/** True when the conversation has at least one resource-link annotation. */
|
|
109
110
|
export function hasConversationAnnotations(
|
|
110
111
|
annotations: ConversationDetailReport["annotations"] | undefined,
|
|
@@ -134,9 +135,36 @@ export function ConversationSidebarAnnotations(props: {
|
|
|
134
135
|
: [];
|
|
135
136
|
|
|
136
137
|
return (
|
|
137
|
-
<Tooltip
|
|
138
|
-
|
|
139
|
-
|
|
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>
|
|
140
168
|
<ul className="m-0 list-none space-y-1 p-0">
|
|
141
169
|
{annotations.map((annotation, index) => (
|
|
142
170
|
<li
|
|
@@ -156,33 +184,7 @@ export function ConversationSidebarAnnotations(props: {
|
|
|
156
184
|
</li>
|
|
157
185
|
))}
|
|
158
186
|
</ul>
|
|
159
|
-
|
|
160
|
-
label="Linked work"
|
|
161
|
-
triggerClassName="min-w-0"
|
|
162
|
-
>
|
|
163
|
-
<span
|
|
164
|
-
aria-label={`Linked work, newest first: ${details.join(", ")}`}
|
|
165
|
-
className="inline-flex min-w-0 max-w-full items-center"
|
|
166
|
-
>
|
|
167
|
-
{useMobileFacepile ? (
|
|
168
|
-
<SidebarAnnotationIconFacepile
|
|
169
|
-
annotations={mobileFacepileAnnotations}
|
|
170
|
-
// Discs sit on the sidebar panel / row surface.
|
|
171
|
-
cutoutColor="var(--color-dashboard-surface-panel)"
|
|
172
|
-
/>
|
|
173
|
-
) : (
|
|
174
|
-
<span className="inline-flex min-w-0 items-center gap-1">
|
|
175
|
-
{badges.labeledGroups.map((group) => (
|
|
176
|
-
<SidebarAnnotationGroupChip group={group} key={group.label} />
|
|
177
|
-
))}
|
|
178
|
-
{badges.overflowGroupCount > 0 ? (
|
|
179
|
-
<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">
|
|
180
|
-
+{badges.overflowGroupCount}
|
|
181
|
-
</span>
|
|
182
|
-
) : null}
|
|
183
|
-
</span>
|
|
184
|
-
)}
|
|
185
|
-
</span>
|
|
187
|
+
</TooltipContent>
|
|
186
188
|
</Tooltip>
|
|
187
189
|
);
|
|
188
190
|
}
|
|
@@ -410,48 +412,35 @@ function SidebarAnnotationIcon(props: {
|
|
|
410
412
|
);
|
|
411
413
|
}
|
|
412
414
|
|
|
413
|
-
/** Render
|
|
415
|
+
/** Render linked work as a compact strip under the conversation title. */
|
|
414
416
|
export function ConversationAnnotations(props: {
|
|
415
417
|
detail: ConversationDetailReport | undefined;
|
|
416
|
-
layout?: "list" | "strip";
|
|
417
418
|
}) {
|
|
418
|
-
const links =
|
|
419
|
-
props.detail?.annotations?.filter(
|
|
420
|
-
(annotation) => annotation.url !== null,
|
|
421
|
-
) ?? [];
|
|
419
|
+
const links = conversationLinks(props.detail);
|
|
422
420
|
if (links.length === 0) return null;
|
|
423
421
|
return (
|
|
424
|
-
<div
|
|
425
|
-
className={cn(
|
|
426
|
-
"flex gap-x-4 gap-y-2",
|
|
427
|
-
props.layout === "strip" ? "overflow-x-auto" : "flex-col",
|
|
428
|
-
)}
|
|
429
|
-
>
|
|
422
|
+
<div className="flex gap-x-4 gap-y-2 overflow-x-auto">
|
|
430
423
|
{links.map((link) => (
|
|
431
424
|
<a
|
|
432
|
-
className=
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
? "px-1 py-0.5 text-xs hover:text-dashboard-accent-text"
|
|
436
|
-
: "min-h-10 border border-dashboard-border px-3 py-2 text-sm hover:border-dashboard-border-interactive hover:bg-dashboard-surface-hover",
|
|
437
|
-
)}
|
|
438
|
-
href={link.url ?? undefined}
|
|
439
|
-
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}
|
|
440
428
|
rel="noreferrer"
|
|
441
429
|
target="_blank"
|
|
442
|
-
title={
|
|
430
|
+
title={[
|
|
431
|
+
link.label,
|
|
432
|
+
link.plugin,
|
|
433
|
+
linkStatusLabel(link.status),
|
|
434
|
+
link.description,
|
|
435
|
+
]
|
|
436
|
+
.filter(Boolean)
|
|
437
|
+
.join(" · ")}
|
|
443
438
|
>
|
|
444
439
|
<ObjectIcon
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
props.detail?.sidebarAnnotations?.find(
|
|
448
|
-
(annotation) => annotation.key === link.key,
|
|
449
|
-
)?.objectType ??
|
|
450
|
-
"item"
|
|
451
|
-
}
|
|
452
|
-
status={link.status}
|
|
453
|
-
facts={link.kind === "object" ? link.facts : undefined}
|
|
440
|
+
facts={link.facts}
|
|
441
|
+
objectType={link.objectType}
|
|
454
442
|
size={16}
|
|
443
|
+
status={link.status}
|
|
455
444
|
/>
|
|
456
445
|
<span className="min-w-0 break-words">{link.label}</span>
|
|
457
446
|
</a>
|
|
@@ -460,26 +449,6 @@ export function ConversationAnnotations(props: {
|
|
|
460
449
|
);
|
|
461
450
|
}
|
|
462
451
|
|
|
463
|
-
function resourceLinkTitle(link: {
|
|
464
|
-
description?: string;
|
|
465
|
-
label: string;
|
|
466
|
-
plugin: string;
|
|
467
|
-
status?: ResourceLinkStatus;
|
|
468
|
-
}): string {
|
|
469
|
-
const statusLabel = link.status
|
|
470
|
-
? {
|
|
471
|
-
open: "Open",
|
|
472
|
-
draft: "Draft",
|
|
473
|
-
closed: "Closed",
|
|
474
|
-
merged: "Merged",
|
|
475
|
-
warning: "Needs attention",
|
|
476
|
-
}[link.status]
|
|
477
|
-
: undefined;
|
|
478
|
-
return [link.label, link.plugin, statusLabel, link.description]
|
|
479
|
-
.filter(Boolean)
|
|
480
|
-
.join(" · ");
|
|
481
|
-
}
|
|
482
|
-
|
|
483
452
|
function LocationLink(props: { label: string; locationUrl?: string }) {
|
|
484
453
|
return props.locationUrl ? (
|
|
485
454
|
<a
|
|
@@ -547,7 +516,13 @@ export function hasConversationStats(props: {
|
|
|
547
516
|
return conversationStatItems(props).length > 0;
|
|
548
517
|
}
|
|
549
518
|
|
|
550
|
-
|
|
519
|
+
type ConversationStatItem = MetricListItem & { label: string };
|
|
520
|
+
|
|
521
|
+
/**
|
|
522
|
+
* Render runtime, source, token, and cost metadata. The compact variant is one
|
|
523
|
+
* line under the conversation title. The full variant is a labeled list for
|
|
524
|
+
* conversation details.
|
|
525
|
+
*/
|
|
551
526
|
export function ConversationStats(props: {
|
|
552
527
|
conversation: Conversation | undefined;
|
|
553
528
|
detail?: ConversationDetailReport;
|
|
@@ -556,6 +531,24 @@ export function ConversationStats(props: {
|
|
|
556
531
|
const stats = conversationStatItems(props);
|
|
557
532
|
if (stats.length === 0) return null;
|
|
558
533
|
|
|
534
|
+
if ((props.variant ?? "full") === "full") {
|
|
535
|
+
return (
|
|
536
|
+
<dl className="m-0 grid min-w-0 gap-2 text-xs leading-snug">
|
|
537
|
+
{stats.map((item) => (
|
|
538
|
+
<div
|
|
539
|
+
className="flex min-w-0 items-baseline justify-between gap-4"
|
|
540
|
+
key={item.key}
|
|
541
|
+
>
|
|
542
|
+
<dt className="shrink-0 text-dashboard-text-muted">{item.label}</dt>
|
|
543
|
+
<dd className="m-0 min-w-0 break-words text-right tabular-nums text-dashboard-text">
|
|
544
|
+
{item.content}
|
|
545
|
+
</dd>
|
|
546
|
+
</div>
|
|
547
|
+
))}
|
|
548
|
+
</dl>
|
|
549
|
+
);
|
|
550
|
+
}
|
|
551
|
+
|
|
559
552
|
return (
|
|
560
553
|
<MetricList
|
|
561
554
|
className="break-words text-xs leading-[1.45] text-dashboard-text-muted"
|
|
@@ -568,7 +561,7 @@ function conversationStatItems(props: {
|
|
|
568
561
|
conversation: Conversation | undefined;
|
|
569
562
|
detail?: ConversationDetailReport;
|
|
570
563
|
variant?: "compact" | "full";
|
|
571
|
-
}):
|
|
564
|
+
}): ConversationStatItem[] {
|
|
572
565
|
if (!props.conversation) return [];
|
|
573
566
|
const variant = props.variant ?? "full";
|
|
574
567
|
const completeDetail = props.detail?.previousCursor
|
|
@@ -590,17 +583,37 @@ function conversationStatItems(props: {
|
|
|
590
583
|
const sourceTask = props.detail?.sourceTask;
|
|
591
584
|
const childAgentTotals =
|
|
592
585
|
props.detail?.childAgentTotals ?? props.conversation.childAgentTotals;
|
|
593
|
-
const
|
|
586
|
+
const lastActivityAt = props.conversation.lastSeenAt;
|
|
587
|
+
const rawStats: Array<ConversationStatItem | undefined> = [
|
|
594
588
|
location
|
|
595
589
|
? {
|
|
596
590
|
content: <LocationLink label={location} locationUrl={locationUrl} />,
|
|
597
591
|
key: "location",
|
|
592
|
+
label: "Location",
|
|
598
593
|
}
|
|
599
594
|
: undefined,
|
|
600
595
|
variant === "full" && sourceTask
|
|
601
596
|
? {
|
|
602
597
|
content: <SourceTask sourceTask={sourceTask} />,
|
|
603
598
|
key: "source-task",
|
|
599
|
+
label: "Source",
|
|
600
|
+
}
|
|
601
|
+
: undefined,
|
|
602
|
+
variant === "full" && lastActivityAt
|
|
603
|
+
? {
|
|
604
|
+
content: (
|
|
605
|
+
<time
|
|
606
|
+
dateTime={lastActivityAt}
|
|
607
|
+
title={formatTime(lastActivityAt, {
|
|
608
|
+
dateStyle: "medium",
|
|
609
|
+
timeStyle: "short",
|
|
610
|
+
})}
|
|
611
|
+
>
|
|
612
|
+
{formatRelativeTime(lastActivityAt)}
|
|
613
|
+
</time>
|
|
614
|
+
),
|
|
615
|
+
key: "last-activity",
|
|
616
|
+
label: "Last activity",
|
|
604
617
|
}
|
|
605
618
|
: undefined,
|
|
606
619
|
durationLabel !== "none"
|
|
@@ -615,6 +628,7 @@ function conversationStatItems(props: {
|
|
|
615
628
|
/>
|
|
616
629
|
),
|
|
617
630
|
key: "duration",
|
|
631
|
+
label: "Runtime",
|
|
618
632
|
}
|
|
619
633
|
: undefined,
|
|
620
634
|
tokenSummary
|
|
@@ -637,6 +651,7 @@ function conversationStatItems(props: {
|
|
|
637
651
|
/>
|
|
638
652
|
),
|
|
639
653
|
key: "tokens",
|
|
654
|
+
label: "Tokens",
|
|
640
655
|
}
|
|
641
656
|
: undefined,
|
|
642
657
|
costSummary ||
|
|
@@ -659,14 +674,18 @@ function conversationStatItems(props: {
|
|
|
659
674
|
/>
|
|
660
675
|
),
|
|
661
676
|
key: "cost",
|
|
677
|
+
label: "Cost",
|
|
662
678
|
}
|
|
663
679
|
: undefined,
|
|
664
680
|
childAgentTotals
|
|
665
681
|
? {
|
|
666
682
|
content: <SubagentsMetric childAgentTotals={childAgentTotals} />,
|
|
667
683
|
key: "subagents",
|
|
684
|
+
label: "Subagents",
|
|
668
685
|
}
|
|
669
686
|
: undefined,
|
|
670
687
|
];
|
|
671
|
-
return rawStats.filter(
|
|
688
|
+
return rawStats.filter(
|
|
689
|
+
(item): item is ConversationStatItem => item !== undefined,
|
|
690
|
+
);
|
|
672
691
|
}
|