@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
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import type { AutomationExecutionStatusDay } from "@sentry/junior/api/schema";
|
|
2
|
+
import { Bar, BarChart, CartesianGrid } from "recharts";
|
|
2
3
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
ChartSvg,
|
|
8
|
-
createActivityChartLayout,
|
|
4
|
+
activityChartMargin,
|
|
5
|
+
ActivityChartTooltipContent,
|
|
6
|
+
ActivityChartXAxis,
|
|
7
|
+
ActivityChartYAxis,
|
|
9
8
|
} from "../../components/charts/ActivityChart";
|
|
10
9
|
import { ChartLegend } from "../../components/charts/ChartLegend";
|
|
11
10
|
import {
|
|
@@ -13,6 +12,7 @@ import {
|
|
|
13
12
|
type TimeRangeDays,
|
|
14
13
|
} from "../../components/controls/TimeRangeSelector";
|
|
15
14
|
import { Card } from "../../components/layout/Card";
|
|
15
|
+
import { ChartContainer, ChartTooltip } from "../../components/ui/chart";
|
|
16
16
|
|
|
17
17
|
const series = [
|
|
18
18
|
{ color: "var(--color-emerald-300)", key: "completed", label: "Completed" },
|
|
@@ -20,6 +20,10 @@ const series = [
|
|
|
20
20
|
{ color: "var(--color-amber-300)", key: "blocked", label: "Blocked" },
|
|
21
21
|
] as const;
|
|
22
22
|
|
|
23
|
+
const chartConfig = Object.fromEntries(
|
|
24
|
+
series.map((item) => [item.key, { color: item.color, label: item.label }]),
|
|
25
|
+
);
|
|
26
|
+
|
|
23
27
|
/** Render one automation's terminal executions by status over a trailing window. */
|
|
24
28
|
export function AutomationExecutionStatusChart(props: {
|
|
25
29
|
bucketUnit?: TimeRangeBucketUnit;
|
|
@@ -30,12 +34,8 @@ export function AutomationExecutionStatusChart(props: {
|
|
|
30
34
|
const bucketUnit = props.bucketUnit ?? "day";
|
|
31
35
|
|
|
32
36
|
const days = props.days;
|
|
33
|
-
const layout = createActivityChartLayout(220);
|
|
34
37
|
const totals = days.map((day) => day.completed + day.failed + day.blocked);
|
|
35
38
|
const maximum = Math.max(1, ...totals);
|
|
36
|
-
const step =
|
|
37
|
-
days.length > 0 ? layout.plotWidth / days.length : layout.plotWidth;
|
|
38
|
-
const barWidth = Math.max(2, Math.min(13, step * 0.68));
|
|
39
39
|
const hasExecutions = totals.some((total) => total > 0);
|
|
40
40
|
|
|
41
41
|
return (
|
|
@@ -59,67 +59,44 @@ export function AutomationExecutionStatusChart(props: {
|
|
|
59
59
|
/>
|
|
60
60
|
|
|
61
61
|
<div className="relative mt-3 overflow-hidden">
|
|
62
|
-
<
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
layout={layout}
|
|
62
|
+
<ChartContainer
|
|
63
|
+
className="aspect-auto h-55 w-full"
|
|
64
|
+
config={chartConfig}
|
|
66
65
|
>
|
|
67
|
-
<
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
]
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
x={x}
|
|
102
|
-
y={layout.top + layout.plotHeight - stackedHeight}
|
|
103
|
-
/>
|
|
104
|
-
);
|
|
105
|
-
})}
|
|
106
|
-
<rect
|
|
107
|
-
fill="transparent"
|
|
108
|
-
height={layout.plotHeight}
|
|
109
|
-
width={Math.max(barWidth, 8)}
|
|
110
|
-
x={x - (Math.max(barWidth, 8) - barWidth) / 2}
|
|
111
|
-
y={layout.top}
|
|
112
|
-
/>
|
|
113
|
-
</g>
|
|
114
|
-
</ActivityChartTooltip>
|
|
115
|
-
);
|
|
116
|
-
})}
|
|
117
|
-
<ActivityChartDateLabels
|
|
118
|
-
dates={days.map((day) => day.date)}
|
|
119
|
-
layout={layout}
|
|
120
|
-
xPosition={(index) => layout.left + index * step + step / 2}
|
|
121
|
-
/>
|
|
122
|
-
</ChartSvg>
|
|
66
|
+
<BarChart
|
|
67
|
+
aria-label={`Automation executions during the last ${props.range === 1 ? "24 hours" : `${props.range} days`}`}
|
|
68
|
+
data={days}
|
|
69
|
+
margin={activityChartMargin}
|
|
70
|
+
role="img"
|
|
71
|
+
>
|
|
72
|
+
<CartesianGrid strokeDasharray="3 5" vertical={false} />
|
|
73
|
+
<ActivityChartYAxis maximum={maximum} />
|
|
74
|
+
<ActivityChartXAxis keys={days.map((day) => day.date)} />
|
|
75
|
+
<ChartTooltip
|
|
76
|
+
content={
|
|
77
|
+
<ActivityChartTooltipContent
|
|
78
|
+
rows={(day: AutomationExecutionStatusDay) => [
|
|
79
|
+
["completed", day.completed],
|
|
80
|
+
["failed", day.failed],
|
|
81
|
+
["blocked", day.blocked],
|
|
82
|
+
["total", day.completed + day.failed + day.blocked],
|
|
83
|
+
]}
|
|
84
|
+
/>
|
|
85
|
+
}
|
|
86
|
+
/>
|
|
87
|
+
{series.map((item) => (
|
|
88
|
+
<Bar
|
|
89
|
+
dataKey={item.key}
|
|
90
|
+
fill={`var(--color-${item.key})`}
|
|
91
|
+
fillOpacity={0.82}
|
|
92
|
+
isAnimationActive={false}
|
|
93
|
+
key={item.key}
|
|
94
|
+
maxBarSize={13}
|
|
95
|
+
stackId="status"
|
|
96
|
+
/>
|
|
97
|
+
))}
|
|
98
|
+
</BarChart>
|
|
99
|
+
</ChartContainer>
|
|
123
100
|
{!hasExecutions ? (
|
|
124
101
|
<div className="pointer-events-none absolute inset-0 grid place-items-center pt-12 font-sans text-xs text-dashboard-text-muted">
|
|
125
102
|
No automation executions in this period.
|
|
@@ -1,21 +1,16 @@
|
|
|
1
|
-
import { useMemo, useState } from "react";
|
|
1
|
+
import { useMemo, useState, type KeyboardEvent } from "react";
|
|
2
2
|
import { ArrowLeft } from "lucide-react";
|
|
3
|
-
import {
|
|
4
|
-
Link,
|
|
5
|
-
Navigate,
|
|
6
|
-
useNavigate,
|
|
7
|
-
useParams,
|
|
8
|
-
useSearchParams,
|
|
9
|
-
} from "react-router";
|
|
3
|
+
import { Link, Navigate, useParams, useSearchParams } from "react-router";
|
|
10
4
|
import type {
|
|
11
5
|
AutomationExecution,
|
|
12
6
|
AutomationExecutionList,
|
|
7
|
+
AutomationRun,
|
|
13
8
|
} from "@sentry/junior/api/schema";
|
|
14
9
|
|
|
15
10
|
import { useAutomationExecutionsData } from "../../api";
|
|
16
11
|
import { InlineError } from "../../components/InlineError";
|
|
17
12
|
import { PageContentSkeleton } from "../../components/PageContentSkeleton";
|
|
18
|
-
import
|
|
13
|
+
import { SelectableRow } from "../../components/SelectableRow";
|
|
19
14
|
import { StatusDot } from "../../components/StatusDot";
|
|
20
15
|
import {
|
|
21
16
|
selectTimeSeries,
|
|
@@ -24,83 +19,130 @@ import {
|
|
|
24
19
|
} from "../../components/controls/TimeRangeSelector";
|
|
25
20
|
import { Card } from "../../components/layout/Card";
|
|
26
21
|
import { PageHeader } from "../../components/layout/PageHeader";
|
|
27
|
-
import { conversationPath } from "../../conversations/conversationRoutes";
|
|
28
22
|
import {
|
|
29
23
|
formatCompactNumber,
|
|
30
24
|
formatCostSummary,
|
|
31
25
|
formatRuntime,
|
|
32
|
-
formatTime,
|
|
33
26
|
automationPath,
|
|
34
27
|
} from "../../format";
|
|
35
28
|
import { DashboardApiError } from "../../http";
|
|
36
29
|
import { pathWithSearch } from "../../searchParams";
|
|
37
30
|
import { cn } from "../../styles";
|
|
38
31
|
import { AutomationExecutionStatusChart } from "./AutomationExecutionStatusChart";
|
|
32
|
+
import {
|
|
33
|
+
AUTOMATION_RUN_PARAM,
|
|
34
|
+
AutomationRunDetails,
|
|
35
|
+
AutomationRunsFrame,
|
|
36
|
+
RunConversationLink,
|
|
37
|
+
useAutomationRunSelection,
|
|
38
|
+
} from "./AutomationRunDetails";
|
|
39
|
+
import {
|
|
40
|
+
automationRunStatusTone,
|
|
41
|
+
automationRunTitle,
|
|
42
|
+
formatAutomationRunTime,
|
|
43
|
+
} from "./automationFormat";
|
|
39
44
|
|
|
40
45
|
/** Leading conversation column flexes; metric columns stay equal fixed widths. */
|
|
41
|
-
const EXECUTION_GRID =
|
|
46
|
+
const EXECUTION_GRID =
|
|
47
|
+
"grid-cols-[minmax(0,1fr)_5.5rem_5.5rem_5.5rem_auto_2rem]";
|
|
42
48
|
|
|
43
|
-
/** Render one automation's terminal executions
|
|
49
|
+
/** Render one automation's terminal executions beside the selected run. */
|
|
44
50
|
export function AutomationExecutionsPage(props: { enabled: boolean }) {
|
|
45
51
|
const { automationId } = useParams();
|
|
46
52
|
const [searchParams] = useSearchParams();
|
|
47
53
|
const query = useAutomationExecutionsData(props.enabled, automationId);
|
|
54
|
+
const backSearch = new URLSearchParams(searchParams);
|
|
55
|
+
backSearch.delete(AUTOMATION_RUN_PARAM);
|
|
48
56
|
const backTo = pathWithSearch(
|
|
49
57
|
automationId ? automationPath(automationId) : "/automations/list",
|
|
50
|
-
|
|
58
|
+
backSearch,
|
|
59
|
+
);
|
|
60
|
+
const runs = useMemo(
|
|
61
|
+
() =>
|
|
62
|
+
query.data
|
|
63
|
+
? query.data.executions.map(
|
|
64
|
+
(execution): AutomationRun => ({
|
|
65
|
+
...execution,
|
|
66
|
+
automationId: query.data.automation.id,
|
|
67
|
+
automationTitle: query.data.automation.title,
|
|
68
|
+
kind: query.data.automation.kind,
|
|
69
|
+
}),
|
|
70
|
+
)
|
|
71
|
+
: [],
|
|
72
|
+
[query.data],
|
|
73
|
+
);
|
|
74
|
+
const selection = useAutomationRunSelection(
|
|
75
|
+
runs.map((run) => run.executionId),
|
|
51
76
|
);
|
|
52
77
|
|
|
53
78
|
if (!automationId) {
|
|
54
79
|
return <Navigate replace to="/automations" />;
|
|
55
80
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
81
|
+
const loading = !query.data && !query.error;
|
|
82
|
+
return (
|
|
83
|
+
<AutomationRunsFrame
|
|
84
|
+
details={
|
|
85
|
+
selection.runId ? (
|
|
86
|
+
<AutomationRunDetails
|
|
87
|
+
key={selection.runId}
|
|
88
|
+
loading={loading}
|
|
89
|
+
onClose={selection.close}
|
|
90
|
+
run={runs.find((run) => run.executionId === selection.runId)}
|
|
91
|
+
showAutomation={false}
|
|
92
|
+
/>
|
|
93
|
+
) : null
|
|
94
|
+
}
|
|
95
|
+
label="Executions list"
|
|
96
|
+
listRef={selection.listRef}
|
|
97
|
+
>
|
|
98
|
+
{query.data ? (
|
|
99
|
+
<AutomationExecutionsView
|
|
100
|
+
backTo={backTo}
|
|
101
|
+
data={query.data}
|
|
102
|
+
onRowsKeyDown={selection.onRowsKeyDown}
|
|
103
|
+
onSelect={selection.toggle}
|
|
104
|
+
selectedRunId={selection.runId}
|
|
76
105
|
/>
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
106
|
+
) : (
|
|
107
|
+
<>
|
|
108
|
+
<PageHeader
|
|
109
|
+
description="Terminal runs for one scheduled or event automation."
|
|
110
|
+
title="Automation executions"
|
|
111
|
+
/>
|
|
112
|
+
{loading ? (
|
|
113
|
+
<PageContentSkeleton
|
|
114
|
+
label="Loading automation executions"
|
|
115
|
+
variant="list"
|
|
116
|
+
/>
|
|
117
|
+
) : (
|
|
118
|
+
<Card padding="md">
|
|
119
|
+
<InlineError>
|
|
120
|
+
{query.error instanceof DashboardApiError &&
|
|
121
|
+
query.error.status === 404
|
|
122
|
+
? "This automation was not found or is not visible to you."
|
|
123
|
+
: "Automation executions could not be loaded. Try again."}
|
|
124
|
+
</InlineError>
|
|
125
|
+
<Link
|
|
126
|
+
className="mt-3 inline-flex items-center gap-2 font-sans text-xs text-dashboard-text-muted no-underline hover:text-dashboard-text"
|
|
127
|
+
to={automationPath(automationId)}
|
|
128
|
+
>
|
|
129
|
+
<ArrowLeft aria-hidden="true" size={14} />
|
|
130
|
+
Back to automations
|
|
131
|
+
</Link>
|
|
132
|
+
</Card>
|
|
133
|
+
)}
|
|
134
|
+
</>
|
|
135
|
+
)}
|
|
136
|
+
</AutomationRunsFrame>
|
|
137
|
+
);
|
|
99
138
|
}
|
|
100
139
|
|
|
101
140
|
function AutomationExecutionsView(props: {
|
|
102
141
|
backTo: string;
|
|
103
142
|
data: AutomationExecutionList;
|
|
143
|
+
onRowsKeyDown(event: KeyboardEvent<HTMLElement>): void;
|
|
144
|
+
onSelect(executionId: string): void;
|
|
145
|
+
selectedRunId: string | undefined;
|
|
104
146
|
}) {
|
|
105
147
|
const { data } = props;
|
|
106
148
|
const [range, setRange] = useState<TimeRangeDays>(30);
|
|
@@ -171,24 +213,29 @@ function AutomationExecutionsView(props: {
|
|
|
171
213
|
<div className="min-w-0 overflow-x-auto">
|
|
172
214
|
<div className="min-w-[36rem]">
|
|
173
215
|
<div
|
|
216
|
+
aria-hidden="true"
|
|
174
217
|
className={cn(
|
|
175
218
|
"sticky top-0 z-[1] hidden items-center gap-4 border-b border-dashboard-border-subtle bg-dashboard-overlay-soft px-4 py-2.5 font-sans font-medium text-xs text-dashboard-text-muted md:grid",
|
|
176
219
|
EXECUTION_GRID,
|
|
177
220
|
)}
|
|
178
|
-
role="row"
|
|
179
221
|
>
|
|
180
|
-
<div>
|
|
222
|
+
<div>Run</div>
|
|
181
223
|
<div>Duration</div>
|
|
182
224
|
<div>Tokens</div>
|
|
183
225
|
<div>Cost</div>
|
|
184
|
-
<div className="sr-only">Status</div>
|
|
185
226
|
</div>
|
|
186
|
-
<div
|
|
227
|
+
<div
|
|
228
|
+
className="min-w-0"
|
|
229
|
+
onKeyDown={props.onRowsKeyDown}
|
|
230
|
+
role="list"
|
|
231
|
+
>
|
|
187
232
|
{data.executions.map((execution) => (
|
|
188
233
|
<ExecutionRow
|
|
189
234
|
execution={execution}
|
|
190
235
|
fallbackTitle={data.automation.title}
|
|
191
236
|
key={execution.executionId}
|
|
237
|
+
onSelect={() => props.onSelect(execution.executionId)}
|
|
238
|
+
selected={props.selectedRunId === execution.executionId}
|
|
192
239
|
/>
|
|
193
240
|
))}
|
|
194
241
|
</div>
|
|
@@ -209,12 +256,10 @@ function AutomationExecutionsView(props: {
|
|
|
209
256
|
function ExecutionRow(props: {
|
|
210
257
|
execution: AutomationExecution;
|
|
211
258
|
fallbackTitle: string;
|
|
259
|
+
onSelect(): void;
|
|
260
|
+
selected: boolean;
|
|
212
261
|
}) {
|
|
213
|
-
const { execution
|
|
214
|
-
const navigate = useNavigate();
|
|
215
|
-
const title =
|
|
216
|
-
execution.title?.trim() ||
|
|
217
|
-
(execution.conversationId ? fallbackTitle : "No conversation");
|
|
262
|
+
const { execution } = props;
|
|
218
263
|
const costLabel =
|
|
219
264
|
formatCostSummary(
|
|
220
265
|
execution.costUsd === undefined
|
|
@@ -226,56 +271,52 @@ function ExecutionRow(props: {
|
|
|
226
271
|
execution.totalTokens === undefined
|
|
227
272
|
? "—"
|
|
228
273
|
: formatCompactNumber(execution.totalTokens);
|
|
229
|
-
const
|
|
230
|
-
if (!execution.conversationId) return;
|
|
231
|
-
navigate(conversationPath(execution.conversationId));
|
|
232
|
-
};
|
|
274
|
+
const tone = automationRunStatusTone(execution.status);
|
|
233
275
|
|
|
234
276
|
return (
|
|
235
277
|
<div
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
EXECUTION_GRID,
|
|
240
|
-
execution.conversationId
|
|
241
|
-
? "cursor-pointer hover:bg-dashboard-fill-soft"
|
|
242
|
-
: "cursor-default opacity-80",
|
|
243
|
-
)}
|
|
244
|
-
onClick={openConversation}
|
|
245
|
-
onKeyDown={(event) => {
|
|
246
|
-
if (!execution.conversationId) return;
|
|
247
|
-
if (event.key === "Enter" || event.key === " ") {
|
|
248
|
-
event.preventDefault();
|
|
249
|
-
openConversation();
|
|
250
|
-
}
|
|
251
|
-
}}
|
|
252
|
-
role={execution.conversationId ? "link" : "row"}
|
|
253
|
-
tabIndex={execution.conversationId ? 0 : undefined}
|
|
278
|
+
className="border-b border-dashboard-border-subtle last:border-b-0"
|
|
279
|
+
data-run-id={execution.executionId}
|
|
280
|
+
role="listitem"
|
|
254
281
|
>
|
|
255
|
-
<
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
282
|
+
<SelectableRow
|
|
283
|
+
className={cn(
|
|
284
|
+
"grid min-w-0 items-center gap-4 overflow-hidden px-4 py-3 max-md:grid-cols-1 max-md:gap-y-2 max-md:py-3.5",
|
|
285
|
+
EXECUTION_GRID,
|
|
286
|
+
)}
|
|
287
|
+
onSelect={props.onSelect}
|
|
288
|
+
selected={props.selected}
|
|
289
|
+
>
|
|
290
|
+
<button
|
|
291
|
+
aria-expanded={props.selected}
|
|
292
|
+
className="block min-w-0 cursor-pointer rounded-md border-0 bg-transparent p-0 text-left focus-visible:outline focus-visible:outline-2 focus-visible:outline-dashboard-focus"
|
|
293
|
+
onClick={props.onSelect}
|
|
294
|
+
type="button"
|
|
295
|
+
>
|
|
296
|
+
<span className="flex min-w-0 items-center gap-2 overflow-hidden">
|
|
297
|
+
<StatusDot
|
|
298
|
+
className="md:hidden"
|
|
299
|
+
label={execution.status}
|
|
300
|
+
tone={tone}
|
|
301
|
+
/>
|
|
302
|
+
<span className="min-w-0 truncate text-sm font-medium leading-snug text-dashboard-text">
|
|
303
|
+
{automationRunTitle(execution, props.fallbackTitle)}
|
|
304
|
+
</span>
|
|
305
|
+
</span>
|
|
306
|
+
<span className="mt-1 block truncate text-xs leading-relaxed text-dashboard-text-muted">
|
|
307
|
+
{formatAutomationRunTime(execution.executedAt)}
|
|
308
|
+
</span>
|
|
309
|
+
</button>
|
|
310
|
+
<MetricCell label="Duration" value={durationLabel} />
|
|
311
|
+
<MetricCell label="Tokens" value={tokensLabel} />
|
|
312
|
+
<MetricCell label="Cost" value={costLabel} />
|
|
313
|
+
<div className="hidden justify-self-center md:block">
|
|
314
|
+
<StatusDot label={execution.status} tone={tone} />
|
|
265
315
|
</div>
|
|
266
|
-
<div className="
|
|
267
|
-
{
|
|
316
|
+
<div className="max-md:hidden">
|
|
317
|
+
<RunConversationLink conversationId={execution.conversationId} />
|
|
268
318
|
</div>
|
|
269
|
-
</
|
|
270
|
-
<MetricCell label="Duration" value={durationLabel} />
|
|
271
|
-
<MetricCell label="Tokens" value={tokensLabel} />
|
|
272
|
-
<MetricCell label="Cost" value={costLabel} />
|
|
273
|
-
<div className="hidden justify-self-center md:block">
|
|
274
|
-
<StatusDot
|
|
275
|
-
label={execution.status}
|
|
276
|
-
tone={runStatusTone(execution.status)}
|
|
277
|
-
/>
|
|
278
|
-
</div>
|
|
319
|
+
</SelectableRow>
|
|
279
320
|
</div>
|
|
280
321
|
);
|
|
281
322
|
}
|
|
@@ -297,12 +338,6 @@ function MetricCell(props: { label: string; value: string }) {
|
|
|
297
338
|
);
|
|
298
339
|
}
|
|
299
340
|
|
|
300
|
-
function runStatusTone(status: AutomationExecution["status"]): StatusChipTone {
|
|
301
|
-
if (status === "failed") return "danger";
|
|
302
|
-
if (status === "blocked") return "warning";
|
|
303
|
-
return "success";
|
|
304
|
-
}
|
|
305
|
-
|
|
306
341
|
function countByStatus(executions: AutomationExecution[]) {
|
|
307
342
|
return executions.reduce(
|
|
308
343
|
(counts, execution) => {
|
|
@@ -312,14 +347,3 @@ function countByStatus(executions: AutomationExecution[]) {
|
|
|
312
347
|
{ blocked: 0, completed: 0, failed: 0 },
|
|
313
348
|
);
|
|
314
349
|
}
|
|
315
|
-
|
|
316
|
-
function formatRunDate(value: string): string {
|
|
317
|
-
return formatTime(value, {
|
|
318
|
-
day: "numeric",
|
|
319
|
-
hour: "numeric",
|
|
320
|
-
minute: "2-digit",
|
|
321
|
-
month: "short",
|
|
322
|
-
timeZoneName: "short",
|
|
323
|
-
year: "numeric",
|
|
324
|
-
});
|
|
325
|
-
}
|