@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
|
@@ -3,6 +3,7 @@ import type { ReactNode } from "react";
|
|
|
3
3
|
import { cn } from "../styles";
|
|
4
4
|
import { Card } from "./layout/Card";
|
|
5
5
|
import { SearchInput } from "./SearchInput";
|
|
6
|
+
import { Tabs, TabsList, TabsTrigger } from "./ui/tabs";
|
|
6
7
|
|
|
7
8
|
/** Lay out labeled filter groups and an optional search field. */
|
|
8
9
|
export function FilterBar(props: {
|
|
@@ -69,43 +70,27 @@ export function FilterTabList(props: {
|
|
|
69
70
|
value: string;
|
|
70
71
|
}) {
|
|
71
72
|
return (
|
|
72
|
-
<
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
aria-selected={selected}
|
|
82
|
-
className={cn(
|
|
83
|
-
"relative flex min-w-0 cursor-pointer items-center justify-between gap-2 border-0 bg-transparent px-3 py-2.5 font-sans font-medium text-xs transition-colors after:absolute after:inset-x-2 after:bottom-0 after:h-px sm:shrink-0 sm:justify-start",
|
|
84
|
-
selected
|
|
85
|
-
? "text-dashboard-accent-text after:bg-dashboard-accent"
|
|
86
|
-
: "text-dashboard-text-muted after:bg-transparent hover:text-dashboard-text",
|
|
87
|
-
)}
|
|
73
|
+
<Tabs onValueChange={props.onChange} value={props.value}>
|
|
74
|
+
<TabsList
|
|
75
|
+
aria-label={props.ariaLabel}
|
|
76
|
+
className="grid grid-cols-3 sm:flex sm:overflow-x-auto"
|
|
77
|
+
variant="line"
|
|
78
|
+
>
|
|
79
|
+
{props.items.map((item) => (
|
|
80
|
+
<TabsTrigger
|
|
81
|
+
className="group/tab justify-between sm:shrink-0 sm:justify-start"
|
|
88
82
|
key={item.value || "all"}
|
|
89
|
-
|
|
90
|
-
role="tab"
|
|
91
|
-
type="button"
|
|
83
|
+
value={item.value}
|
|
92
84
|
>
|
|
93
85
|
{item.label}
|
|
94
86
|
{item.count !== undefined ? (
|
|
95
|
-
<span
|
|
96
|
-
className={cn(
|
|
97
|
-
"rounded-sm border px-1.5 py-0.5 text-xs",
|
|
98
|
-
selected
|
|
99
|
-
? "border-dashboard-accent/20 bg-dashboard-accent/10 text-dashboard-accent-text"
|
|
100
|
-
: "border-dashboard-border bg-dashboard-fill-soft text-dashboard-text-muted",
|
|
101
|
-
)}
|
|
102
|
-
>
|
|
87
|
+
<span className="rounded-sm border border-dashboard-border bg-dashboard-fill-soft px-1.5 py-0.5 text-xs text-dashboard-text-muted group-data-active/tab:border-dashboard-accent/20 group-data-active/tab:bg-dashboard-accent/10 group-data-active/tab:text-dashboard-accent-text">
|
|
103
88
|
{item.count.toLocaleString("en-US")}
|
|
104
89
|
</span>
|
|
105
90
|
) : null}
|
|
106
|
-
</
|
|
107
|
-
)
|
|
108
|
-
|
|
109
|
-
</
|
|
91
|
+
</TabsTrigger>
|
|
92
|
+
))}
|
|
93
|
+
</TabsList>
|
|
94
|
+
</Tabs>
|
|
110
95
|
);
|
|
111
96
|
}
|
|
@@ -1,17 +1,13 @@
|
|
|
1
1
|
import { ExternalLink, X } from "lucide-react";
|
|
2
2
|
import {
|
|
3
3
|
type MouseEvent,
|
|
4
|
-
useEffect,
|
|
5
|
-
useId,
|
|
6
|
-
useRef,
|
|
7
4
|
useState,
|
|
8
5
|
type ComponentPropsWithoutRef,
|
|
9
6
|
} from "react";
|
|
10
7
|
|
|
11
|
-
import {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
} from "../bodyScrollLock";
|
|
8
|
+
import { Button } from "./ui/button";
|
|
9
|
+
import { Dialog, DialogClose, DialogContent, DialogTitle } from "./ui/dialog";
|
|
10
|
+
import { useSheet } from "./ui/useSheet";
|
|
15
11
|
|
|
16
12
|
/** Return true when an image link click should open the inline preview. */
|
|
17
13
|
export function shouldPreviewImageAttachment(
|
|
@@ -45,9 +41,6 @@ export function ImageAttachment(
|
|
|
45
41
|
triggerClassName?: string;
|
|
46
42
|
} & Omit<ComponentPropsWithoutRef<"img">, "alt" | "className" | "src">,
|
|
47
43
|
) {
|
|
48
|
-
const dialogRef = useRef<HTMLDialogElement>(null);
|
|
49
|
-
const bodyScrollLockedRef = useRef(false);
|
|
50
|
-
const titleId = useId();
|
|
51
44
|
const [open, setOpen] = useState(false);
|
|
52
45
|
const {
|
|
53
46
|
context,
|
|
@@ -58,20 +51,6 @@ export function ImageAttachment(
|
|
|
58
51
|
...imageProps
|
|
59
52
|
} = props;
|
|
60
53
|
|
|
61
|
-
const unlockBodyScroll = () => {
|
|
62
|
-
if (!bodyScrollLockedRef.current) return;
|
|
63
|
-
releaseBodyScrollLock();
|
|
64
|
-
bodyScrollLockedRef.current = false;
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
const close = () => {
|
|
68
|
-
dialogRef.current?.close();
|
|
69
|
-
setOpen(false);
|
|
70
|
-
unlockBodyScroll();
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
useEffect(() => () => unlockBodyScroll(), []);
|
|
74
|
-
|
|
75
54
|
return (
|
|
76
55
|
<>
|
|
77
56
|
<a
|
|
@@ -80,12 +59,7 @@ export function ImageAttachment(
|
|
|
80
59
|
onClick={(event) => {
|
|
81
60
|
if (!shouldPreviewImageAttachment(event)) return;
|
|
82
61
|
event.preventDefault();
|
|
83
|
-
const dialog = dialogRef.current;
|
|
84
|
-
if (!dialog || dialog.open) return;
|
|
85
|
-
acquireBodyScrollLock();
|
|
86
|
-
bodyScrollLockedRef.current = true;
|
|
87
62
|
setOpen(true);
|
|
88
|
-
dialog.showModal();
|
|
89
63
|
}}
|
|
90
64
|
rel="noreferrer"
|
|
91
65
|
target="_blank"
|
|
@@ -97,62 +71,74 @@ export function ImageAttachment(
|
|
|
97
71
|
src={src}
|
|
98
72
|
/>
|
|
99
73
|
</a>
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
74
|
+
{open ? (
|
|
75
|
+
<ImagePreview
|
|
76
|
+
context={context}
|
|
77
|
+
filename={filename}
|
|
78
|
+
onClose={() => setOpen(false)}
|
|
79
|
+
src={src}
|
|
80
|
+
/>
|
|
81
|
+
) : null}
|
|
82
|
+
</>
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Show one image above the page. `useSheet` shares the document scroll lock
|
|
88
|
+
* with sheets and keeps Escape and backdrop dismissal on the front modal.
|
|
89
|
+
*/
|
|
90
|
+
function ImagePreview(props: {
|
|
91
|
+
context?: string;
|
|
92
|
+
filename: string;
|
|
93
|
+
onClose(): void;
|
|
94
|
+
src: string;
|
|
95
|
+
}) {
|
|
96
|
+
const sheet = useSheet(props.onClose);
|
|
97
|
+
return (
|
|
98
|
+
<Dialog {...sheet.rootProps}>
|
|
99
|
+
<DialogContent
|
|
100
|
+
{...sheet.contentProps}
|
|
101
|
+
className="top-0 left-0 h-dvh w-screen max-w-none translate-x-0 translate-y-0 gap-0 overflow-hidden rounded-none border-0 bg-dashboard-ink p-0 shadow-none sm:max-w-none md:top-1/2 md:left-1/2 md:h-[min(90dvh,960px)] md:w-[min(92vw,1440px)] md:-translate-x-1/2 md:-translate-y-1/2 md:rounded-lg md:border"
|
|
111
102
|
>
|
|
112
103
|
<div className="grid h-full min-h-0 grid-rows-[auto_minmax(0,1fr)] bg-dashboard-bg-elevated">
|
|
113
104
|
<header className="grid grid-cols-[minmax(0,1fr)_auto_auto] items-center gap-1.5 border-b border-dashboard-border-strong bg-dashboard-surface-raised px-3 py-2 pt-[max(0.5rem,env(safe-area-inset-top))] md:px-4">
|
|
114
105
|
<div className="min-w-0">
|
|
115
|
-
<
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
{filename}
|
|
120
|
-
</div>
|
|
121
|
-
{context ? (
|
|
106
|
+
<DialogTitle className="truncate font-mono text-xs leading-normal font-normal">
|
|
107
|
+
{props.filename}
|
|
108
|
+
</DialogTitle>
|
|
109
|
+
{props.context ? (
|
|
122
110
|
<div className="truncate font-mono text-2xs text-dashboard-text-muted">
|
|
123
|
-
{context}
|
|
111
|
+
{props.context}
|
|
124
112
|
</div>
|
|
125
113
|
) : null}
|
|
126
114
|
</div>
|
|
127
115
|
<a
|
|
128
116
|
className="inline-flex min-h-10 items-center gap-1.5 rounded-md px-2.5 text-xs font-medium text-dashboard-text-muted no-underline transition-colors hover:bg-dashboard-fill-hover hover:text-dashboard-text"
|
|
129
|
-
href={src}
|
|
117
|
+
href={props.src}
|
|
130
118
|
rel="noreferrer"
|
|
131
119
|
target="_blank"
|
|
132
120
|
>
|
|
133
121
|
<ExternalLink aria-hidden="true" size={14} />
|
|
134
122
|
<span className="max-sm:sr-only">Open raw file</span>
|
|
135
123
|
</a>
|
|
136
|
-
<
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
124
|
+
<DialogClose
|
|
125
|
+
render={
|
|
126
|
+
<Button className="h-10 gap-1.5 border-0 bg-transparent px-2.5 text-xs text-dashboard-text-muted hover:bg-dashboard-fill-hover hover:text-dashboard-text" />
|
|
127
|
+
}
|
|
140
128
|
>
|
|
141
129
|
<X aria-hidden="true" size={16} />
|
|
142
130
|
<span>Close</span>
|
|
143
|
-
</
|
|
131
|
+
</DialogClose>
|
|
144
132
|
</header>
|
|
145
133
|
<div className="grid min-h-0 place-items-center overflow-auto p-3 pb-[max(0.75rem,env(safe-area-inset-bottom))] md:p-6">
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
/>
|
|
152
|
-
) : null}
|
|
134
|
+
<img
|
|
135
|
+
alt={props.filename}
|
|
136
|
+
className="max-h-full max-w-full object-contain"
|
|
137
|
+
src={props.src}
|
|
138
|
+
/>
|
|
153
139
|
</div>
|
|
154
140
|
</div>
|
|
155
|
-
</
|
|
156
|
-
|
|
141
|
+
</DialogContent>
|
|
142
|
+
</Dialog>
|
|
157
143
|
);
|
|
158
144
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { ReactNode } from "react";
|
|
2
2
|
|
|
3
3
|
import { cn } from "../styles";
|
|
4
|
+
import { Alert } from "./ui/alert";
|
|
4
5
|
|
|
5
6
|
/** Render a compact error message with consistent alert semantics. */
|
|
6
7
|
export function InlineError(props: {
|
|
@@ -8,11 +9,14 @@ export function InlineError(props: {
|
|
|
8
9
|
className?: string;
|
|
9
10
|
}) {
|
|
10
11
|
return (
|
|
11
|
-
<
|
|
12
|
-
className={cn(
|
|
13
|
-
|
|
12
|
+
<Alert
|
|
13
|
+
className={cn(
|
|
14
|
+
"block rounded-none border-0 bg-transparent p-0 text-rose-300",
|
|
15
|
+
props.className,
|
|
16
|
+
)}
|
|
17
|
+
variant="destructive"
|
|
14
18
|
>
|
|
15
19
|
{props.children}
|
|
16
|
-
</
|
|
20
|
+
</Alert>
|
|
17
21
|
);
|
|
18
22
|
}
|
|
@@ -2,7 +2,7 @@ import type { ReactNode } from "react";
|
|
|
2
2
|
|
|
3
3
|
import { cn } from "../styles";
|
|
4
4
|
import { ShimmerText } from "./ShimmerText";
|
|
5
|
-
import { Tooltip } from "./
|
|
5
|
+
import { Tooltip, TooltipContent, TooltipTrigger } from "./ui/tooltip";
|
|
6
6
|
|
|
7
7
|
export type MetricTooltipLine = {
|
|
8
8
|
label?: string;
|
|
@@ -85,34 +85,44 @@ export function MetricValue(props: {
|
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
return (
|
|
88
|
-
<Tooltip
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
88
|
+
<Tooltip>
|
|
89
|
+
<TooltipTrigger
|
|
90
|
+
render={
|
|
91
|
+
<span
|
|
92
|
+
className={cn(
|
|
93
|
+
"inline-flex border-b border-dotted border-dashboard-border-interactive outline-none transition-colors hover:border-dashboard-border-heavy focus-visible:border-dashboard-border-heavy",
|
|
94
|
+
props.className,
|
|
95
|
+
)}
|
|
96
|
+
tabIndex={0}
|
|
97
|
+
>
|
|
98
|
+
{props.children}
|
|
99
|
+
</span>
|
|
100
|
+
}
|
|
101
|
+
/>
|
|
102
|
+
<TooltipContent
|
|
103
|
+
align={
|
|
104
|
+
props.align === "left"
|
|
105
|
+
? "start"
|
|
106
|
+
: props.align === "right"
|
|
107
|
+
? "end"
|
|
108
|
+
: "center"
|
|
109
|
+
}
|
|
110
|
+
className={cn(
|
|
111
|
+
"w-[calc(100vw-2rem)] max-w-80 rounded-lg bg-dashboard-bg text-left font-normal shadow-xl shadow-black/35",
|
|
112
|
+
props.tooltipCard ? "p-3 leading-snug" : "px-3 py-2 leading-relaxed",
|
|
113
|
+
)}
|
|
114
|
+
side={props.tooltipPlacement === "above" ? "top" : "bottom"}
|
|
115
|
+
>
|
|
116
|
+
{props.tooltipCard ? (
|
|
117
|
+
<span className="block max-h-[min(30rem,var(--available-height,30rem))] overflow-y-auto">
|
|
97
118
|
{props.tooltipCard}
|
|
98
119
|
</span>
|
|
99
120
|
) : tooltip ? (
|
|
100
121
|
<span className="block max-h-72 overflow-y-auto">
|
|
101
122
|
<TooltipLines lines={tooltip} />
|
|
102
123
|
</span>
|
|
103
|
-
) : null
|
|
104
|
-
|
|
105
|
-
placement={props.tooltipPlacement ?? "below"}
|
|
106
|
-
>
|
|
107
|
-
<span
|
|
108
|
-
className={cn(
|
|
109
|
-
"inline-flex border-b border-dotted border-dashboard-border-interactive outline-none transition-colors hover:border-dashboard-border-heavy focus-visible:border-dashboard-border-heavy",
|
|
110
|
-
props.className,
|
|
111
|
-
)}
|
|
112
|
-
tabIndex={0}
|
|
113
|
-
>
|
|
114
|
-
{props.children}
|
|
115
|
-
</span>
|
|
124
|
+
) : null}
|
|
125
|
+
</TooltipContent>
|
|
116
126
|
</Tooltip>
|
|
117
127
|
);
|
|
118
128
|
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ComponentProps, ReactNode } from "react";
|
|
2
2
|
import type { LucideIcon } from "lucide-react";
|
|
3
3
|
|
|
4
4
|
import { cn } from "../styles";
|
|
5
|
+
import { Alert, AlertDescription, AlertTitle } from "./ui/alert";
|
|
6
|
+
import { Button } from "./ui/button";
|
|
5
7
|
|
|
6
8
|
type NoticeTone = "default" | "error";
|
|
7
9
|
|
|
@@ -14,7 +16,7 @@ type NoticeProps = {
|
|
|
14
16
|
tone?: NoticeTone;
|
|
15
17
|
};
|
|
16
18
|
|
|
17
|
-
type NoticeActionProps =
|
|
19
|
+
type NoticeActionProps = ComponentProps<typeof Button> & {
|
|
18
20
|
tone?: NoticeTone;
|
|
19
21
|
};
|
|
20
22
|
|
|
@@ -29,11 +31,10 @@ export function Notice({
|
|
|
29
31
|
}: NoticeProps) {
|
|
30
32
|
const isError = tone === "error";
|
|
31
33
|
return (
|
|
32
|
-
<
|
|
33
|
-
className=
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
)}
|
|
34
|
+
<Alert
|
|
35
|
+
className="block gap-0 overflow-hidden rounded-xl p-0 shadow-[0_16px_40px_rgba(0,0,0,0.5)]"
|
|
36
|
+
role={isError ? "alert" : "status"}
|
|
37
|
+
variant={isError ? "destructive" : "default"}
|
|
37
38
|
>
|
|
38
39
|
<div className="flex min-w-0 items-center gap-3 px-3 py-3">
|
|
39
40
|
{Icon ? (
|
|
@@ -48,31 +49,26 @@ export function Notice({
|
|
|
48
49
|
<Icon aria-hidden="true" size={16} />
|
|
49
50
|
</div>
|
|
50
51
|
) : null}
|
|
51
|
-
<div className="min-w-0 flex-1"
|
|
52
|
-
<
|
|
53
|
-
className={cn(
|
|
54
|
-
"font-display text-sm font-medium leading-snug",
|
|
55
|
-
isError ? "text-rose-50" : "text-dashboard-text",
|
|
56
|
-
)}
|
|
57
|
-
>
|
|
52
|
+
<div className="min-w-0 flex-1">
|
|
53
|
+
<AlertTitle className="font-display text-sm leading-snug">
|
|
58
54
|
{title}
|
|
59
55
|
{detail ? " " : null}
|
|
60
|
-
</
|
|
56
|
+
</AlertTitle>
|
|
61
57
|
{detail ? (
|
|
62
|
-
<
|
|
58
|
+
<AlertDescription
|
|
63
59
|
className={cn(
|
|
64
60
|
"mt-0.5 truncate font-sans text-xs",
|
|
65
|
-
isError
|
|
61
|
+
isError && "text-rose-100/70",
|
|
66
62
|
)}
|
|
67
63
|
>
|
|
68
64
|
{detail}
|
|
69
|
-
</
|
|
65
|
+
</AlertDescription>
|
|
70
66
|
) : null}
|
|
71
67
|
</div>
|
|
72
68
|
{action}
|
|
73
69
|
</div>
|
|
74
70
|
{children}
|
|
75
|
-
</
|
|
71
|
+
</Alert>
|
|
76
72
|
);
|
|
77
73
|
}
|
|
78
74
|
|
|
@@ -80,22 +76,19 @@ export function Notice({
|
|
|
80
76
|
export function NoticeAction({
|
|
81
77
|
className,
|
|
82
78
|
tone = "default",
|
|
83
|
-
type = "button",
|
|
84
79
|
...props
|
|
85
80
|
}: NoticeActionProps) {
|
|
86
81
|
const isError = tone === "error";
|
|
87
82
|
return (
|
|
88
|
-
<
|
|
83
|
+
<Button
|
|
89
84
|
{...props}
|
|
90
85
|
className={cn(
|
|
91
|
-
"shrink-0
|
|
92
|
-
isError ? "focus:ring-rose-300/40" : "focus:ring-dashboard-focus/35",
|
|
86
|
+
"h-auto shrink-0 rounded-lg border-0 px-3 py-1.5 text-xs leading-normal",
|
|
93
87
|
isError
|
|
94
|
-
? "
|
|
95
|
-
: "
|
|
88
|
+
? "bg-rose-200/15 text-rose-50 hover:bg-rose-200/25 hover:text-rose-50 focus-visible:outline-rose-300/55 data-disabled:hover:bg-rose-200/15 data-disabled:hover:text-rose-50"
|
|
89
|
+
: "bg-dashboard-accent/10 text-dashboard-accent-text hover:bg-dashboard-accent/20 hover:text-dashboard-accent-text data-disabled:hover:bg-dashboard-accent/10 data-disabled:hover:text-dashboard-accent-text",
|
|
96
90
|
className,
|
|
97
91
|
)}
|
|
98
|
-
type={type}
|
|
99
92
|
/>
|
|
100
93
|
);
|
|
101
94
|
}
|
|
@@ -1,7 +1,12 @@
|
|
|
1
|
-
import { ChevronLeft, ChevronRight } from "lucide-react";
|
|
2
|
-
|
|
3
1
|
import { cn } from "../styles";
|
|
4
|
-
import { Button } from "./
|
|
2
|
+
import { Button } from "./ui/button";
|
|
3
|
+
import {
|
|
4
|
+
Pagination,
|
|
5
|
+
PaginationContent,
|
|
6
|
+
PaginationItem,
|
|
7
|
+
PaginationNext,
|
|
8
|
+
PaginationPrevious,
|
|
9
|
+
} from "./ui/pagination";
|
|
5
10
|
|
|
6
11
|
/** Render a centered load-more control for cursor or progressive lists. */
|
|
7
12
|
export function LoadMorePagination(props: {
|
|
@@ -54,10 +59,9 @@ export function PagePagination(props: {
|
|
|
54
59
|
const end = Math.min(props.total, current * props.pageSize);
|
|
55
60
|
|
|
56
61
|
return (
|
|
57
|
-
<
|
|
58
|
-
aria-label="Pagination"
|
|
62
|
+
<Pagination
|
|
59
63
|
className={cn(
|
|
60
|
-
"flex
|
|
64
|
+
"flex-wrap items-center justify-between gap-3",
|
|
61
65
|
props.className,
|
|
62
66
|
)}
|
|
63
67
|
>
|
|
@@ -65,27 +69,23 @@ export function PagePagination(props: {
|
|
|
65
69
|
Showing {start.toLocaleString("en-US")}-{end.toLocaleString("en-US")} of{" "}
|
|
66
70
|
{props.total.toLocaleString("en-US")}
|
|
67
71
|
</p>
|
|
68
|
-
<
|
|
69
|
-
<
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
>
|
|
75
|
-
|
|
76
|
-
</Button>
|
|
77
|
-
<span className="min-w-16 text-center font-sans tabular-nums text-xs text-dashboard-text-muted">
|
|
72
|
+
<PaginationContent>
|
|
73
|
+
<PaginationItem>
|
|
74
|
+
<PaginationPrevious
|
|
75
|
+
disabled={current <= 1}
|
|
76
|
+
onClick={() => props.onPageChange(current - 1)}
|
|
77
|
+
/>
|
|
78
|
+
</PaginationItem>
|
|
79
|
+
<PaginationItem className="min-w-16 text-center font-sans tabular-nums text-xs text-dashboard-text-muted">
|
|
78
80
|
{current} / {props.pageCount}
|
|
79
|
-
</
|
|
80
|
-
<
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
>
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
</div>
|
|
89
|
-
</div>
|
|
81
|
+
</PaginationItem>
|
|
82
|
+
<PaginationItem>
|
|
83
|
+
<PaginationNext
|
|
84
|
+
disabled={current >= props.pageCount}
|
|
85
|
+
onClick={() => props.onPageChange(current + 1)}
|
|
86
|
+
/>
|
|
87
|
+
</PaginationItem>
|
|
88
|
+
</PaginationContent>
|
|
89
|
+
</Pagination>
|
|
90
90
|
);
|
|
91
91
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { ActorIdentity } from "@sentry/junior/api/schema";
|
|
2
2
|
|
|
3
3
|
import { actorLabel } from "../format";
|
|
4
|
-
import { cn } from "../styles";
|
|
5
4
|
import type { Conversation } from "../types";
|
|
6
5
|
import { ActorAvatar } from "./ActorAvatar";
|
|
7
|
-
import {
|
|
6
|
+
import { Avatar, AvatarFallback } from "./ui/avatar";
|
|
7
|
+
import { Tooltip, TooltipContent, TooltipTrigger } from "./ui/tooltip";
|
|
8
8
|
|
|
9
9
|
const MAX_VISIBLE_PARTICIPANTS = 3;
|
|
10
10
|
|
|
@@ -51,28 +51,31 @@ function ParticipantTooltipContent(props: { participant: ActorIdentity }) {
|
|
|
51
51
|
);
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
function
|
|
54
|
+
function ParticipantAvatar(props: {
|
|
55
55
|
participant: ActorIdentity;
|
|
56
56
|
size: ParticipantAvatarStackProps["size"];
|
|
57
57
|
}) {
|
|
58
58
|
const label = participantDescription(props.participant);
|
|
59
59
|
return (
|
|
60
|
-
<Tooltip
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
60
|
+
<Tooltip>
|
|
61
|
+
<TooltipTrigger
|
|
62
|
+
render={
|
|
63
|
+
<span
|
|
64
|
+
aria-label={label}
|
|
65
|
+
className="relative -ml-1 inline-flex rounded-full first:ml-0 pointer-events-none focus-visible:z-10 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-dashboard-focus [@media(hover:hover)_and_(pointer:fine)]:pointer-events-auto"
|
|
66
|
+
onKeyDown={(event) => event.stopPropagation()}
|
|
67
|
+
tabIndex={0}
|
|
68
|
+
>
|
|
69
|
+
<ActorAvatar
|
|
70
|
+
name={participantName(props.participant)}
|
|
71
|
+
size={props.size}
|
|
72
|
+
/>
|
|
73
|
+
</span>
|
|
74
|
+
}
|
|
75
|
+
/>
|
|
76
|
+
<TooltipContent>
|
|
77
|
+
<ParticipantTooltipContent participant={props.participant} />
|
|
78
|
+
</TooltipContent>
|
|
76
79
|
</Tooltip>
|
|
77
80
|
);
|
|
78
81
|
}
|
|
@@ -98,15 +101,32 @@ export function ParticipantAvatarStack(props: ParticipantAvatarStackProps) {
|
|
|
98
101
|
role="group"
|
|
99
102
|
>
|
|
100
103
|
{visible.map((participant, index) => (
|
|
101
|
-
<
|
|
104
|
+
<ParticipantAvatar
|
|
102
105
|
key={participantKey(participant, index)}
|
|
103
106
|
participant={participant}
|
|
104
107
|
size={props.size}
|
|
105
108
|
/>
|
|
106
109
|
))}
|
|
107
110
|
{hidden.length > 0 ? (
|
|
108
|
-
<Tooltip
|
|
109
|
-
|
|
111
|
+
<Tooltip>
|
|
112
|
+
<TooltipTrigger
|
|
113
|
+
render={
|
|
114
|
+
<Avatar
|
|
115
|
+
aria-label={`${hidden.length} more participants: ${hidden
|
|
116
|
+
.map(participantDescription)
|
|
117
|
+
.join("; ")}`}
|
|
118
|
+
className="-ml-1 pointer-events-none bg-dashboard-surface-active shadow-none focus-visible:z-10 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-dashboard-focus [@media(hover:hover)_and_(pointer:fine)]:pointer-events-auto"
|
|
119
|
+
onKeyDown={(event) => event.stopPropagation()}
|
|
120
|
+
size={props.size === "list" ? "sm" : "default"}
|
|
121
|
+
tabIndex={0}
|
|
122
|
+
>
|
|
123
|
+
<AvatarFallback className="tabular-nums tracking-normal text-dashboard-text-muted">
|
|
124
|
+
+{hidden.length}
|
|
125
|
+
</AvatarFallback>
|
|
126
|
+
</Avatar>
|
|
127
|
+
}
|
|
128
|
+
/>
|
|
129
|
+
<TooltipContent>
|
|
110
130
|
<span className="grid gap-1 font-sans">
|
|
111
131
|
{hidden.map((participant, index) => (
|
|
112
132
|
<span key={participantKey(participant, index)}>
|
|
@@ -114,23 +134,7 @@ export function ParticipantAvatarStack(props: ParticipantAvatarStackProps) {
|
|
|
114
134
|
</span>
|
|
115
135
|
))}
|
|
116
136
|
</span>
|
|
117
|
-
|
|
118
|
-
focusable
|
|
119
|
-
triggerClassName="-ml-1 pointer-events-none [@media(hover:hover)_and_(pointer:fine)]:pointer-events-auto"
|
|
120
|
-
>
|
|
121
|
-
<span
|
|
122
|
-
aria-label={`${hidden.length} more participants: ${hidden
|
|
123
|
-
.map(participantDescription)
|
|
124
|
-
.join("; ")}`}
|
|
125
|
-
className={cn(
|
|
126
|
-
"relative inline-grid shrink-0 place-items-center rounded-full border-2 border-dashboard-bg bg-dashboard-surface-active font-sans font-semibold tabular-nums leading-none text-dashboard-text-muted focus-visible:z-10 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-dashboard-focus",
|
|
127
|
-
props.size === "list" ? "size-6 text-2xs" : "size-7 text-xs",
|
|
128
|
-
)}
|
|
129
|
-
onKeyDown={(event) => event.stopPropagation()}
|
|
130
|
-
tabIndex={0}
|
|
131
|
-
>
|
|
132
|
-
+{hidden.length}
|
|
133
|
-
</span>
|
|
137
|
+
</TooltipContent>
|
|
134
138
|
</Tooltip>
|
|
135
139
|
) : null}
|
|
136
140
|
</span>
|