@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,13 +1,37 @@
|
|
|
1
|
+
import { useState } from "react";
|
|
1
2
|
import { useQuery } from "@tanstack/react-query";
|
|
3
|
+
import {
|
|
4
|
+
describeEventTrigger,
|
|
5
|
+
eventMatchFilterText,
|
|
6
|
+
eventTriggerProblems,
|
|
7
|
+
eventTypeText,
|
|
8
|
+
eventsWithoutMatchField,
|
|
9
|
+
} from "@sentry/junior-plugin-api";
|
|
2
10
|
import {
|
|
3
11
|
automationEventCatalogSchema,
|
|
4
12
|
type AutomationEdit,
|
|
5
13
|
} from "@sentry/junior/api/schema";
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
14
|
+
import {
|
|
15
|
+
AlertDialog,
|
|
16
|
+
AlertDialogAction,
|
|
17
|
+
AlertDialogCancel,
|
|
18
|
+
AlertDialogContent,
|
|
19
|
+
AlertDialogDescription,
|
|
20
|
+
AlertDialogFooter,
|
|
21
|
+
AlertDialogTitle,
|
|
22
|
+
} from "../../components/ui/alert-dialog";
|
|
23
|
+
import { Button } from "../../components/ui/button";
|
|
24
|
+
import { Input } from "../../components/ui/input";
|
|
25
|
+
import {
|
|
26
|
+
Field,
|
|
27
|
+
FieldDescription,
|
|
28
|
+
FieldError,
|
|
29
|
+
FieldLabel,
|
|
30
|
+
} from "../../components/ui/field";
|
|
31
|
+
import { NativeSelect } from "../../components/ui/native-select";
|
|
10
32
|
import { FormNotice } from "../../components/FormNotice";
|
|
33
|
+
import { TriggerFilters } from "./TriggerFilters";
|
|
34
|
+
import { Checkbox } from "../../components/ui/checkbox";
|
|
11
35
|
import { fetchDashboardJson } from "../../http";
|
|
12
36
|
|
|
13
37
|
type Trigger = Extract<AutomationEdit, { kind: "event" }>["trigger"];
|
|
@@ -16,8 +40,11 @@ type Trigger = Extract<AutomationEdit, { kind: "event" }>["trigger"];
|
|
|
16
40
|
export function AutomationEventFields(props: {
|
|
17
41
|
value: Trigger;
|
|
18
42
|
original: Trigger;
|
|
43
|
+
/** Base UI checkboxes do not inherit a native fieldset's disabled state. */
|
|
44
|
+
disabled?: boolean;
|
|
19
45
|
onChange(value: Trigger): void;
|
|
20
46
|
}) {
|
|
47
|
+
const [replacement, setReplacement] = useState<Trigger>();
|
|
21
48
|
const catalog = useQuery({
|
|
22
49
|
queryKey: ["dashboard", "automation-event-catalog"],
|
|
23
50
|
queryFn: ({ signal }) =>
|
|
@@ -28,25 +55,25 @@ export function AutomationEventFields(props: {
|
|
|
28
55
|
),
|
|
29
56
|
retry: false,
|
|
30
57
|
});
|
|
31
|
-
const
|
|
32
|
-
(item) =>
|
|
33
|
-
|
|
34
|
-
|
|
58
|
+
const sourceResourceTypes =
|
|
59
|
+
catalog.data?.filter((item) => item.namespace === props.value.namespace) ??
|
|
60
|
+
[];
|
|
61
|
+
const resource = sourceResourceTypes.find(
|
|
62
|
+
(item) => item.type === props.value.resourceType,
|
|
35
63
|
);
|
|
64
|
+
const problems = catalog.data
|
|
65
|
+
? eventTriggerProblems(sourceResourceTypes, props.value)
|
|
66
|
+
: [];
|
|
67
|
+
// A filter that a selected event does not set is fixable here. Other
|
|
68
|
+
// problems mean the catalog changed after the trigger was saved.
|
|
36
69
|
const unsupported =
|
|
37
|
-
!resource ||
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
)
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
return (Array.isArray(value) ? value : [value]).some(
|
|
45
|
-
(item) =>
|
|
46
|
-
typeof item !== field.kind ||
|
|
47
|
-
(field.enum && !field.enum.includes(String(item))),
|
|
48
|
-
);
|
|
49
|
-
});
|
|
70
|
+
!resource || problems.some((problem) => problem.reason !== "field_not_set");
|
|
71
|
+
const matchFields = Object.entries(resource?.matchFields ?? {});
|
|
72
|
+
const shownMatchFields = matchFields.filter(
|
|
73
|
+
([key, field]) =>
|
|
74
|
+
props.value.match?.[key] !== undefined ||
|
|
75
|
+
eventsWithoutMatchField(field, props.value.events).length === 0,
|
|
76
|
+
);
|
|
50
77
|
const setMatch = (
|
|
51
78
|
key: string,
|
|
52
79
|
value: NonNullable<Trigger["match"]>[string] | undefined,
|
|
@@ -70,16 +97,17 @@ export function AutomationEventFields(props: {
|
|
|
70
97
|
<FormNotice title="Saved trigger · Kept unchanged">
|
|
71
98
|
Some saved values are not in the current catalog. You can edit other
|
|
72
99
|
fields, or select a new resource type to replace the trigger.
|
|
73
|
-
<
|
|
74
|
-
{
|
|
75
|
-
|
|
100
|
+
<SavedTrigger
|
|
101
|
+
resourceTypes={sourceResourceTypes}
|
|
102
|
+
trigger={props.value}
|
|
103
|
+
/>
|
|
76
104
|
</FormNotice>
|
|
77
105
|
) : null}
|
|
78
|
-
<Field
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
<
|
|
106
|
+
<Field>
|
|
107
|
+
<FieldLabel htmlFor="trigger-resource">
|
|
108
|
+
{unsupported ? "Replace trigger" : "Resource type"}
|
|
109
|
+
</FieldLabel>
|
|
110
|
+
<NativeSelect
|
|
83
111
|
id="trigger-resource"
|
|
84
112
|
value={
|
|
85
113
|
unsupported
|
|
@@ -91,13 +119,7 @@ export function AutomationEventFields(props: {
|
|
|
91
119
|
(item) => `${item.namespace}:${item.type}` === e.target.value,
|
|
92
120
|
);
|
|
93
121
|
if (!next) return;
|
|
94
|
-
|
|
95
|
-
!window.confirm(
|
|
96
|
-
"Replace the saved trigger? Its resource, events, and conditions will be cleared.",
|
|
97
|
-
)
|
|
98
|
-
)
|
|
99
|
-
return;
|
|
100
|
-
props.onChange({
|
|
122
|
+
setReplacement({
|
|
101
123
|
namespace: next.namespace,
|
|
102
124
|
resourceType: next.type,
|
|
103
125
|
identifier: "",
|
|
@@ -117,12 +139,38 @@ export function AutomationEventFields(props: {
|
|
|
117
139
|
{item.namespace} · {item.type.replaceAll("_", " ")}
|
|
118
140
|
</option>
|
|
119
141
|
))}
|
|
120
|
-
</
|
|
142
|
+
</NativeSelect>
|
|
121
143
|
</Field>
|
|
144
|
+
<AlertDialog
|
|
145
|
+
onOpenChange={(open) => {
|
|
146
|
+
if (!open) setReplacement(undefined);
|
|
147
|
+
}}
|
|
148
|
+
open={replacement !== undefined}
|
|
149
|
+
>
|
|
150
|
+
<AlertDialogContent>
|
|
151
|
+
<AlertDialogTitle>Replace the saved trigger?</AlertDialogTitle>
|
|
152
|
+
<AlertDialogDescription>
|
|
153
|
+
Its resource, events, and filters will be cleared.
|
|
154
|
+
</AlertDialogDescription>
|
|
155
|
+
<AlertDialogFooter>
|
|
156
|
+
<AlertDialogCancel>Cancel</AlertDialogCancel>
|
|
157
|
+
<AlertDialogAction
|
|
158
|
+
onClick={() => {
|
|
159
|
+
if (replacement) props.onChange(replacement);
|
|
160
|
+
setReplacement(undefined);
|
|
161
|
+
}}
|
|
162
|
+
variant="primary"
|
|
163
|
+
>
|
|
164
|
+
Replace trigger
|
|
165
|
+
</AlertDialogAction>
|
|
166
|
+
</AlertDialogFooter>
|
|
167
|
+
</AlertDialogContent>
|
|
168
|
+
</AlertDialog>
|
|
122
169
|
{!unsupported && resource ? (
|
|
123
170
|
<>
|
|
124
|
-
<Field
|
|
125
|
-
<
|
|
171
|
+
<Field>
|
|
172
|
+
<FieldLabel htmlFor="trigger-label">Resource name</FieldLabel>
|
|
173
|
+
<Input
|
|
126
174
|
size="comfortable"
|
|
127
175
|
id="trigger-label"
|
|
128
176
|
value={props.value.label}
|
|
@@ -131,12 +179,11 @@ export function AutomationEventFields(props: {
|
|
|
131
179
|
}
|
|
132
180
|
/>
|
|
133
181
|
</Field>
|
|
134
|
-
<Field
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
<TextInput
|
|
182
|
+
<Field>
|
|
183
|
+
<FieldLabel htmlFor="trigger-identifier">
|
|
184
|
+
Resource identifier
|
|
185
|
+
</FieldLabel>
|
|
186
|
+
<Input
|
|
140
187
|
size="comfortable"
|
|
141
188
|
id="trigger-identifier"
|
|
142
189
|
value={props.value.identifier}
|
|
@@ -144,6 +191,9 @@ export function AutomationEventFields(props: {
|
|
|
144
191
|
props.onChange({ ...props.value, identifier: e.target.value })
|
|
145
192
|
}
|
|
146
193
|
/>
|
|
194
|
+
<FieldDescription id="trigger-identifier-help">
|
|
195
|
+
Use the exact provider resource identifier, not its display name.
|
|
196
|
+
</FieldDescription>
|
|
147
197
|
</Field>
|
|
148
198
|
<fieldset>
|
|
149
199
|
<legend className="mb-2 text-sm font-semibold">
|
|
@@ -155,11 +205,11 @@ export function AutomationEventFields(props: {
|
|
|
155
205
|
key={event}
|
|
156
206
|
className="flex min-h-11 cursor-pointer items-start gap-3 px-3 py-3 text-sm"
|
|
157
207
|
>
|
|
158
|
-
<
|
|
159
|
-
|
|
160
|
-
className="mt-0.5 size-4 shrink-0 accent-dashboard-focus"
|
|
208
|
+
<Checkbox
|
|
209
|
+
className="mt-0.5"
|
|
161
210
|
checked={props.value.events.includes(event)}
|
|
162
|
-
|
|
211
|
+
disabled={props.disabled}
|
|
212
|
+
onCheckedChange={() =>
|
|
163
213
|
props.onChange({
|
|
164
214
|
...props.value,
|
|
165
215
|
events: props.value.events.includes(event)
|
|
@@ -169,84 +219,89 @@ export function AutomationEventFields(props: {
|
|
|
169
219
|
}
|
|
170
220
|
/>
|
|
171
221
|
<span className="min-w-0 break-words">
|
|
172
|
-
{event
|
|
173
|
-
{resource.guidance?.[event] ? (
|
|
174
|
-
<span className="mt-1 block text-xs leading-relaxed text-dashboard-text-muted">
|
|
175
|
-
{resource.guidance[event]}
|
|
176
|
-
</span>
|
|
177
|
-
) : null}
|
|
222
|
+
{eventTypeText(event)}
|
|
178
223
|
</span>
|
|
179
224
|
</label>
|
|
180
225
|
))}
|
|
181
226
|
</div>
|
|
182
227
|
</fieldset>
|
|
183
|
-
{
|
|
228
|
+
{matchFields.length ? (
|
|
184
229
|
<fieldset className="grid gap-4">
|
|
185
|
-
<legend className="mb-3 text-sm font-semibold">
|
|
230
|
+
<legend className="mb-3 text-sm font-semibold">Filters</legend>
|
|
186
231
|
<p className="m-0 text-xs leading-relaxed text-dashboard-text-muted">
|
|
187
|
-
|
|
188
|
-
value.
|
|
232
|
+
Every filter must match. Leave a filter blank to match any
|
|
233
|
+
value.
|
|
234
|
+
{shownMatchFields.length < matchFields.length
|
|
235
|
+
? " Filters that a selected event does not set are hidden."
|
|
236
|
+
: null}
|
|
189
237
|
</p>
|
|
190
|
-
{
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
238
|
+
{shownMatchFields.map(([key, field]) => {
|
|
239
|
+
const value = props.value.match?.[key];
|
|
240
|
+
const problem = problems.find(
|
|
241
|
+
(candidate) => candidate.field === key,
|
|
242
|
+
);
|
|
243
|
+
return (
|
|
244
|
+
<Field key={key}>
|
|
245
|
+
<FieldLabel htmlFor={`match-${key}`}>{key}</FieldLabel>
|
|
246
|
+
{Array.isArray(value) ? (
|
|
247
|
+
<div className="text-sm">
|
|
248
|
+
<span className="break-all">
|
|
249
|
+
{eventMatchFilterText(key, field, value)}
|
|
250
|
+
</span>{" "}
|
|
251
|
+
<Button onClick={() => setMatch(key, undefined)}>
|
|
252
|
+
Remove filter
|
|
253
|
+
</Button>
|
|
254
|
+
</div>
|
|
255
|
+
) : field.kind === "boolean" || field.enum ? (
|
|
256
|
+
<NativeSelect
|
|
257
|
+
id={`match-${key}`}
|
|
258
|
+
value={value === undefined ? "" : String(value)}
|
|
259
|
+
onChange={(e) =>
|
|
260
|
+
setMatch(
|
|
261
|
+
key,
|
|
262
|
+
e.target.value === ""
|
|
263
|
+
? undefined
|
|
264
|
+
: field.kind === "boolean"
|
|
265
|
+
? e.target.value === "true"
|
|
266
|
+
: e.target.value,
|
|
267
|
+
)
|
|
268
|
+
}
|
|
269
|
+
>
|
|
270
|
+
<option value="">Any value</option>
|
|
271
|
+
{(field.enum ?? ["true", "false"]).map((v) => (
|
|
272
|
+
<option key={v}>{v}</option>
|
|
273
|
+
))}
|
|
274
|
+
</NativeSelect>
|
|
275
|
+
) : (
|
|
276
|
+
<Input
|
|
277
|
+
size="comfortable"
|
|
278
|
+
id={`match-${key}`}
|
|
279
|
+
type={field.kind === "number" ? "number" : "text"}
|
|
280
|
+
step="any"
|
|
281
|
+
value={value === undefined ? "" : String(value)}
|
|
282
|
+
onChange={(e) =>
|
|
283
|
+
setMatch(
|
|
284
|
+
key,
|
|
285
|
+
e.target.value === ""
|
|
286
|
+
? undefined
|
|
287
|
+
: field.kind === "number"
|
|
288
|
+
? e.target.valueAsNumber
|
|
289
|
+
: e.target.value,
|
|
290
|
+
)
|
|
291
|
+
}
|
|
292
|
+
/>
|
|
293
|
+
)}
|
|
294
|
+
{field.description ? (
|
|
295
|
+
<FieldDescription id={`match-${key}-help`}>
|
|
296
|
+
{field.description}
|
|
297
|
+
</FieldDescription>
|
|
298
|
+
) : null}
|
|
299
|
+
{problem ? (
|
|
300
|
+
<FieldError>{problem.message}</FieldError>
|
|
301
|
+
) : null}
|
|
302
|
+
</Field>
|
|
303
|
+
);
|
|
304
|
+
})}
|
|
250
305
|
</fieldset>
|
|
251
306
|
) : null}
|
|
252
307
|
</>
|
|
@@ -262,3 +317,31 @@ export function AutomationEventFields(props: {
|
|
|
262
317
|
</>
|
|
263
318
|
);
|
|
264
319
|
}
|
|
320
|
+
|
|
321
|
+
/** Show the saved trigger and its problems in the same words as the details. */
|
|
322
|
+
function SavedTrigger(props: {
|
|
323
|
+
resourceTypes: Parameters<typeof describeEventTrigger>[0];
|
|
324
|
+
trigger: Trigger;
|
|
325
|
+
}) {
|
|
326
|
+
const description = describeEventTrigger(props.resourceTypes, props.trigger);
|
|
327
|
+
return (
|
|
328
|
+
<>
|
|
329
|
+
<ul className="my-2 list-disc pl-5">
|
|
330
|
+
{description.problems.map((problem) => (
|
|
331
|
+
<li key={problem}>{problem}</li>
|
|
332
|
+
))}
|
|
333
|
+
</ul>
|
|
334
|
+
<div className="text-xs">
|
|
335
|
+
<p className="m-0 break-words">
|
|
336
|
+
{props.trigger.namespace} ·{" "}
|
|
337
|
+
{props.trigger.resourceType.replaceAll("_", " ")} ·{" "}
|
|
338
|
+
{props.trigger.identifier}
|
|
339
|
+
</p>
|
|
340
|
+
<p className="m-0 mt-1 break-words text-dashboard-text-muted">
|
|
341
|
+
{description.events.join(", ")}
|
|
342
|
+
</p>
|
|
343
|
+
<TriggerFilters filters={description.filters} />
|
|
344
|
+
</div>
|
|
345
|
+
</>
|
|
346
|
+
);
|
|
347
|
+
}
|
|
@@ -4,21 +4,23 @@ import {
|
|
|
4
4
|
type TimeRangeDays,
|
|
5
5
|
} from "../../components/controls/TimeRangeSelector";
|
|
6
6
|
import type { AutomationExecutionDay } from "@sentry/junior/api/schema";
|
|
7
|
+
import { Bar, BarChart, CartesianGrid } from "recharts";
|
|
7
8
|
import {
|
|
8
9
|
ActivityChartAverageLine,
|
|
9
|
-
ActivityChartDateLabels,
|
|
10
|
-
ActivityChartGrid,
|
|
11
10
|
activityChartAverage,
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
activityChartMargin,
|
|
12
|
+
ActivityChartTooltipContent,
|
|
13
|
+
ActivityChartXAxis,
|
|
14
|
+
ActivityChartYAxis,
|
|
16
15
|
} from "../../components/charts/ActivityChart";
|
|
16
|
+
import { ChartContainer, ChartTooltip } from "../../components/ui/chart";
|
|
17
17
|
|
|
18
18
|
import { Card } from "../../components/layout/Card";
|
|
19
19
|
import { formatActivityChartAverage } from "../../format";
|
|
20
20
|
|
|
21
|
-
const
|
|
21
|
+
const chartConfig = {
|
|
22
|
+
total: { color: "var(--color-amber-400)", label: "Executions" },
|
|
23
|
+
};
|
|
22
24
|
|
|
23
25
|
/** Render completed automation executions over a trailing window. */
|
|
24
26
|
export function AutomationExecutionChart(props: {
|
|
@@ -29,12 +31,11 @@ export function AutomationExecutionChart(props: {
|
|
|
29
31
|
}) {
|
|
30
32
|
const bucketUnit = props.bucketUnit ?? "day";
|
|
31
33
|
|
|
32
|
-
const days = props.days
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
const
|
|
37
|
-
const totals = days.map((day) => day.scheduled + day.event);
|
|
34
|
+
const days = props.days.map((day) => ({
|
|
35
|
+
date: day.date,
|
|
36
|
+
total: day.scheduled + day.event,
|
|
37
|
+
}));
|
|
38
|
+
const totals = days.map((day) => day.total);
|
|
38
39
|
const maximum = Math.max(1, ...totals);
|
|
39
40
|
const average = activityChartAverage(totals);
|
|
40
41
|
const hasExecutions = totals.some((total) => total > 0);
|
|
@@ -51,58 +52,44 @@ export function AutomationExecutionChart(props: {
|
|
|
51
52
|
</div>
|
|
52
53
|
|
|
53
54
|
<div className="relative mt-5 overflow-hidden">
|
|
54
|
-
<
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
layout={layout}
|
|
55
|
+
<ChartContainer
|
|
56
|
+
className="aspect-auto h-50 w-full"
|
|
57
|
+
config={chartConfig}
|
|
58
58
|
>
|
|
59
|
-
<
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
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
|
-
unit={timeRangeBucketAverageUnit(bucketUnit)}
|
|
94
|
-
average={average}
|
|
95
|
-
format={formatActivityChartAverage}
|
|
96
|
-
layout={layout}
|
|
97
|
-
maximum={maximum}
|
|
98
|
-
stroke="var(--color-slate-200)"
|
|
99
|
-
/>
|
|
100
|
-
<ActivityChartDateLabels
|
|
101
|
-
dates={days.map((day) => day.date)}
|
|
102
|
-
layout={layout}
|
|
103
|
-
xPosition={(index) => layout.left + index * step + step / 2}
|
|
104
|
-
/>
|
|
105
|
-
</ChartSvg>
|
|
59
|
+
<BarChart
|
|
60
|
+
aria-label={`Automation executions during the last ${props.range === 1 ? "24 hours" : `${props.range} days`}`}
|
|
61
|
+
data={days}
|
|
62
|
+
margin={activityChartMargin}
|
|
63
|
+
role="img"
|
|
64
|
+
>
|
|
65
|
+
<CartesianGrid strokeDasharray="3 5" vertical={false} />
|
|
66
|
+
<ActivityChartYAxis maximum={maximum} />
|
|
67
|
+
<ActivityChartXAxis keys={days.map((day) => day.date)} />
|
|
68
|
+
<ChartTooltip
|
|
69
|
+
content={
|
|
70
|
+
<ActivityChartTooltipContent
|
|
71
|
+
rows={(day: (typeof days)[number]) => [
|
|
72
|
+
["executions", day.total],
|
|
73
|
+
]}
|
|
74
|
+
/>
|
|
75
|
+
}
|
|
76
|
+
/>
|
|
77
|
+
<Bar
|
|
78
|
+
dataKey="total"
|
|
79
|
+
fill="var(--color-total)"
|
|
80
|
+
fillOpacity={0.82}
|
|
81
|
+
isAnimationActive={false}
|
|
82
|
+
maxBarSize={13}
|
|
83
|
+
radius={1}
|
|
84
|
+
/>
|
|
85
|
+
<ActivityChartAverageLine
|
|
86
|
+
unit={timeRangeBucketAverageUnit(bucketUnit)}
|
|
87
|
+
average={average}
|
|
88
|
+
format={formatActivityChartAverage}
|
|
89
|
+
stroke="var(--color-slate-200)"
|
|
90
|
+
/>
|
|
91
|
+
</BarChart>
|
|
92
|
+
</ChartContainer>
|
|
106
93
|
{!hasExecutions ? (
|
|
107
94
|
<div className="pointer-events-none absolute inset-0 grid place-items-center pt-12 font-sans text-xs text-dashboard-text-muted">
|
|
108
95
|
No automation executions in this period.
|