@workflow/web-shared 5.0.0-beta.6 → 5.0.0-beta.8
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/dist/components/error-boundary.js +1 -1
- package/dist/components/event-list-view.d.ts +12 -0
- package/dist/components/event-list-view.d.ts.map +1 -1
- package/dist/components/event-list-view.js +26 -13
- package/dist/components/hook-actions.js +1 -1
- package/dist/components/index.js +1 -1
- package/dist/components/new-trace-viewer/components/copy-button.js +2 -2
- package/dist/components/new-trace-viewer/components/event-list.js +3 -3
- package/dist/components/new-trace-viewer/components/middle-truncate/copy-selection.js +1 -1
- package/dist/components/new-trace-viewer/components/middle-truncate/middle-truncate.js +1 -1
- package/dist/components/new-trace-viewer/components/middle-truncate/truncate.js +1 -1
- package/dist/components/new-trace-viewer/components/middle-truncate/use-middle-truncate.js +1 -1
- package/dist/components/new-trace-viewer/components/split-pane.js +1 -1
- package/dist/components/new-trace-viewer/components/timeline.d.ts +1 -1
- package/dist/components/new-trace-viewer/components/timeline.d.ts.map +1 -1
- package/dist/components/new-trace-viewer/components/timeline.js +187 -103
- package/dist/components/new-trace-viewer/context.js +1 -1
- package/dist/components/new-trace-viewer/detail-panel.js +2 -2
- package/dist/components/new-trace-viewer/icons.js +1 -1
- package/dist/components/new-trace-viewer/trace-viewer.d.ts.map +1 -1
- package/dist/components/new-trace-viewer/trace-viewer.js +53 -26
- package/dist/components/new-trace-viewer/types.js +1 -1
- package/dist/components/new-trace-viewer/util/constants.js +1 -1
- package/dist/components/new-trace-viewer/utils.d.ts +8 -4
- package/dist/components/new-trace-viewer/utils.d.ts.map +1 -1
- package/dist/components/new-trace-viewer/utils.js +31 -6
- package/dist/components/run-trace-view.js +1 -1
- package/dist/components/sidebar/attribute-panel.d.ts.map +1 -1
- package/dist/components/sidebar/attribute-panel.js +99 -73
- package/dist/components/sidebar/conversation-view.js +1 -1
- package/dist/components/sidebar/copyable-data-block.d.ts +1 -0
- package/dist/components/sidebar/copyable-data-block.d.ts.map +1 -1
- package/dist/components/sidebar/copyable-data-block.js +16 -15
- package/dist/components/sidebar/detail-card.d.ts +5 -6
- package/dist/components/sidebar/detail-card.d.ts.map +1 -1
- package/dist/components/sidebar/detail-card.js +32 -16
- package/dist/components/sidebar/entity-detail-panel.d.ts.map +1 -1
- package/dist/components/sidebar/entity-detail-panel.js +6 -3
- package/dist/components/sidebar/events-list.d.ts.map +1 -1
- package/dist/components/sidebar/events-list.js +21 -15
- package/dist/components/sidebar/resolve-hook-modal.js +1 -1
- package/dist/components/sidebar/sidebar-data-context.js +1 -1
- package/dist/components/stream-viewer.js +1 -1
- package/dist/components/trace-viewer/components/map.js +1 -1
- package/dist/components/trace-viewer/components/markers.js +1 -1
- package/dist/components/trace-viewer/components/node.js +1 -1
- package/dist/components/trace-viewer/components/search-input.js +1 -1
- package/dist/components/trace-viewer/components/search.js +1 -1
- package/dist/components/trace-viewer/components/span-content.js +1 -1
- package/dist/components/trace-viewer/components/span-detail-panel.js +1 -1
- package/dist/components/trace-viewer/components/span-segments.js +1 -1
- package/dist/components/trace-viewer/components/span-strategies.js +1 -1
- package/dist/components/trace-viewer/components/ui.js +1 -1
- package/dist/components/trace-viewer/components/zoom-button.js +1 -1
- package/dist/components/trace-viewer/components/zoom-icons.js +1 -1
- package/dist/components/trace-viewer/context.js +1 -1
- package/dist/components/trace-viewer/index.js +1 -1
- package/dist/components/trace-viewer/trace-viewer.js +1 -1
- package/dist/components/trace-viewer/types.js +1 -1
- package/dist/components/trace-viewer/util/constants.js +1 -1
- package/dist/components/trace-viewer/util/scrollbar-width.js +1 -1
- package/dist/components/trace-viewer/util/timing.js +1 -1
- package/dist/components/trace-viewer/util/tree.js +1 -1
- package/dist/components/trace-viewer/util/use-immediate-style.js +1 -1
- package/dist/components/trace-viewer/util/use-streaming-spans.js +1 -1
- package/dist/components/trace-viewer/util/use-trackpad-zoom.js +1 -1
- package/dist/components/trace-viewer/worker.js +1 -1
- package/dist/components/trace-viewer-new.js +1 -1
- package/dist/components/ui/alert.js +1 -1
- package/dist/components/ui/button.d.ts +10 -0
- package/dist/components/ui/button.d.ts.map +1 -0
- package/dist/components/ui/button.js +39 -0
- package/dist/components/ui/card.js +1 -1
- package/dist/components/ui/data-inspector.d.ts +1 -0
- package/dist/components/ui/data-inspector.d.ts.map +1 -1
- package/dist/components/ui/data-inspector.js +4 -9
- package/dist/components/ui/decrypt-button.js +1 -1
- package/dist/components/ui/error-card.js +1 -1
- package/dist/components/ui/error-stack-block.d.ts.map +1 -1
- package/dist/components/ui/error-stack-block.js +4 -18
- package/dist/components/ui/inspector-theme.js +1 -1
- package/dist/components/ui/load-more-button.js +1 -1
- package/dist/components/ui/menu-dropdown.js +1 -1
- package/dist/components/ui/skeleton.js +1 -1
- package/dist/components/ui/spinner.js +1 -1
- package/dist/components/ui/timestamp-tooltip.js +1 -1
- package/dist/components/workflow-trace-view.js +1 -1
- package/dist/components/workflow-traces/event-colors.js +1 -1
- package/dist/components/workflow-traces/trace-colors.js +1 -1
- package/dist/components/workflow-traces/trace-span-construction.js +1 -1
- package/dist/components/workflow-traces/trace-time-utils.js +1 -1
- package/dist/hooks/use-dark-mode.js +1 -1
- package/dist/hooks/use-reduced-motion.d.ts +10 -0
- package/dist/hooks/use-reduced-motion.d.ts.map +1 -0
- package/dist/hooks/use-reduced-motion.js +29 -0
- package/dist/index.js +1 -1
- package/dist/lib/event-analysis.js +1 -1
- package/dist/lib/event-materialization.js +1 -1
- package/dist/lib/hydration.js +1 -1
- package/dist/lib/stream-display.js +1 -1
- package/dist/lib/toast.js +1 -1
- package/dist/lib/trace-builder.js +1 -1
- package/dist/lib/utils.js +1 -1
- package/package.json +5 -5
- package/src/components/event-list-view.tsx +29 -13
- package/src/components/new-trace-viewer/components/copy-button.tsx +1 -1
- package/src/components/new-trace-viewer/components/event-list.tsx +2 -2
- package/src/components/new-trace-viewer/components/timeline.tsx +353 -192
- package/src/components/new-trace-viewer/detail-panel.tsx +1 -1
- package/src/components/new-trace-viewer/trace-viewer.tsx +93 -59
- package/src/components/new-trace-viewer/utils.ts +40 -8
- package/src/components/sidebar/attribute-panel.tsx +212 -235
- package/src/components/sidebar/copyable-data-block.tsx +49 -27
- package/src/components/sidebar/detail-card.tsx +119 -41
- package/src/components/sidebar/entity-detail-panel.tsx +28 -28
- package/src/components/sidebar/events-list.tsx +51 -79
- package/src/components/ui/button.tsx +61 -0
- package/src/components/ui/data-inspector.tsx +9 -18
- package/src/components/ui/error-stack-block.tsx +7 -26
- package/src/hooks/use-reduced-motion.ts +34 -0
- package/dist/components/error-boundary.js.map +0 -1
- package/dist/components/event-list-view.js.map +0 -1
- package/dist/components/hook-actions.js.map +0 -1
- package/dist/components/index.js.map +0 -1
- package/dist/components/new-trace-viewer/components/copy-button.js.map +0 -1
- package/dist/components/new-trace-viewer/components/event-list.js.map +0 -1
- package/dist/components/new-trace-viewer/components/middle-truncate/copy-selection.js.map +0 -1
- package/dist/components/new-trace-viewer/components/middle-truncate/middle-truncate.js.map +0 -1
- package/dist/components/new-trace-viewer/components/middle-truncate/truncate.js.map +0 -1
- package/dist/components/new-trace-viewer/components/middle-truncate/use-middle-truncate.js.map +0 -1
- package/dist/components/new-trace-viewer/components/split-pane.js.map +0 -1
- package/dist/components/new-trace-viewer/components/timeline.js.map +0 -1
- package/dist/components/new-trace-viewer/context.js.map +0 -1
- package/dist/components/new-trace-viewer/detail-panel.js.map +0 -1
- package/dist/components/new-trace-viewer/icons.js.map +0 -1
- package/dist/components/new-trace-viewer/trace-viewer.js.map +0 -1
- package/dist/components/new-trace-viewer/types.js.map +0 -1
- package/dist/components/new-trace-viewer/util/constants.js.map +0 -1
- package/dist/components/new-trace-viewer/utils.js.map +0 -1
- package/dist/components/run-trace-view.js.map +0 -1
- package/dist/components/sidebar/attribute-panel.js.map +0 -1
- package/dist/components/sidebar/conversation-view.js.map +0 -1
- package/dist/components/sidebar/copyable-data-block.js.map +0 -1
- package/dist/components/sidebar/detail-card.js.map +0 -1
- package/dist/components/sidebar/entity-detail-panel.js.map +0 -1
- package/dist/components/sidebar/events-list.js.map +0 -1
- package/dist/components/sidebar/resolve-hook-modal.js.map +0 -1
- package/dist/components/sidebar/sidebar-data-context.js.map +0 -1
- package/dist/components/stream-viewer.js.map +0 -1
- package/dist/components/trace-viewer/components/map.js.map +0 -1
- package/dist/components/trace-viewer/components/markers.js.map +0 -1
- package/dist/components/trace-viewer/components/node.js.map +0 -1
- package/dist/components/trace-viewer/components/search-input.js.map +0 -1
- package/dist/components/trace-viewer/components/search.js.map +0 -1
- package/dist/components/trace-viewer/components/span-content.js.map +0 -1
- package/dist/components/trace-viewer/components/span-detail-panel.js.map +0 -1
- package/dist/components/trace-viewer/components/span-segments.js.map +0 -1
- package/dist/components/trace-viewer/components/span-strategies.js.map +0 -1
- package/dist/components/trace-viewer/components/ui.js.map +0 -1
- package/dist/components/trace-viewer/components/zoom-button.js.map +0 -1
- package/dist/components/trace-viewer/components/zoom-icons.js.map +0 -1
- package/dist/components/trace-viewer/context.js.map +0 -1
- package/dist/components/trace-viewer/index.js.map +0 -1
- package/dist/components/trace-viewer/trace-viewer.js.map +0 -1
- package/dist/components/trace-viewer/types.js.map +0 -1
- package/dist/components/trace-viewer/util/constants.js.map +0 -1
- package/dist/components/trace-viewer/util/scrollbar-width.js.map +0 -1
- package/dist/components/trace-viewer/util/timing.js.map +0 -1
- package/dist/components/trace-viewer/util/tree.js.map +0 -1
- package/dist/components/trace-viewer/util/use-immediate-style.js.map +0 -1
- package/dist/components/trace-viewer/util/use-streaming-spans.js.map +0 -1
- package/dist/components/trace-viewer/util/use-trackpad-zoom.js.map +0 -1
- package/dist/components/trace-viewer/worker.js.map +0 -1
- package/dist/components/trace-viewer-new.js.map +0 -1
- package/dist/components/ui/alert.js.map +0 -1
- package/dist/components/ui/card.js.map +0 -1
- package/dist/components/ui/data-inspector.js.map +0 -1
- package/dist/components/ui/decrypt-button.js.map +0 -1
- package/dist/components/ui/error-card.js.map +0 -1
- package/dist/components/ui/error-stack-block.js.map +0 -1
- package/dist/components/ui/inspector-theme.js.map +0 -1
- package/dist/components/ui/load-more-button.js.map +0 -1
- package/dist/components/ui/menu-dropdown.js.map +0 -1
- package/dist/components/ui/skeleton.js.map +0 -1
- package/dist/components/ui/spinner.js.map +0 -1
- package/dist/components/ui/timestamp-tooltip.js.map +0 -1
- package/dist/components/workflow-trace-view.js.map +0 -1
- package/dist/components/workflow-traces/event-colors.js.map +0 -1
- package/dist/components/workflow-traces/trace-colors.js.map +0 -1
- package/dist/components/workflow-traces/trace-span-construction.js.map +0 -1
- package/dist/components/workflow-traces/trace-time-utils.js.map +0 -1
- package/dist/hooks/use-dark-mode.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/lib/event-analysis.js.map +0 -1
- package/dist/lib/event-materialization.js.map +0 -1
- package/dist/lib/hydration.js.map +0 -1
- package/dist/lib/stream-display.js.map +0 -1
- package/dist/lib/toast.js.map +0 -1
- package/dist/lib/trace-builder.js.map +0 -1
- package/dist/lib/utils.js.map +0 -1
|
@@ -1,8 +1,48 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
3
|
+
import { Lock } from 'lucide-react';
|
|
4
|
+
import { useContext } from 'react';
|
|
5
|
+
import { CopyButton } from '../new-trace-viewer/components/copy-button';
|
|
6
|
+
import { Button } from '../ui/button';
|
|
7
|
+
import { DataInspector, DecryptClickContext } from '../ui/data-inspector';
|
|
8
|
+
import { Spinner } from '../ui/spinner';
|
|
9
|
+
|
|
10
|
+
const encryptedPlaceholderPreview = `{
|
|
11
|
+
"input": "[encrypted]",
|
|
12
|
+
"result": "[encrypted]"
|
|
13
|
+
}`;
|
|
14
|
+
|
|
15
|
+
export function EncryptedDataBlock() {
|
|
16
|
+
const ctx = useContext(DecryptClickContext);
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
<div className="relative min-h-20 overflow-hidden rounded-md border border-gray-alpha-400 bg-background-100">
|
|
20
|
+
<pre
|
|
21
|
+
aria-hidden="true"
|
|
22
|
+
className="pointer-events-none m-0 select-none p-3 font-mono text-label-12 text-gray-900 blur-[4px]"
|
|
23
|
+
>
|
|
24
|
+
{encryptedPlaceholderPreview}
|
|
25
|
+
</pre>
|
|
26
|
+
<div className="absolute inset-0 flex items-center justify-center">
|
|
27
|
+
{ctx ? (
|
|
28
|
+
<Button onClick={ctx.onDecrypt} disabled={ctx.isDecrypting} size="xs">
|
|
29
|
+
{ctx.isDecrypting ? (
|
|
30
|
+
<Spinner size={10} />
|
|
31
|
+
) : (
|
|
32
|
+
<Lock className="h-3 w-3" />
|
|
33
|
+
)}
|
|
34
|
+
<span>Decrypt</span>
|
|
35
|
+
</Button>
|
|
36
|
+
) : (
|
|
37
|
+
<span className="inline-flex items-center gap-1 rounded border border-gray-alpha-400 bg-gray-100 px-1.5 py-0.5 text-button-12 font-medium text-gray-700">
|
|
38
|
+
<Lock className="h-3 w-3" />
|
|
39
|
+
Encrypted
|
|
40
|
+
</span>
|
|
41
|
+
)}
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
|
+
);
|
|
45
|
+
}
|
|
6
46
|
|
|
7
47
|
const serializeForClipboard = (value: unknown): string => {
|
|
8
48
|
if (typeof value === 'string') return value;
|
|
@@ -21,31 +61,13 @@ const serializeForClipboard = (value: unknown): string => {
|
|
|
21
61
|
};
|
|
22
62
|
|
|
23
63
|
export function CopyableDataBlock({ data }: { data: unknown }) {
|
|
24
|
-
const toast = useToast();
|
|
25
64
|
return (
|
|
26
|
-
<div
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
aria-label="Copy data"
|
|
33
|
-
title="Copy"
|
|
34
|
-
className="!absolute !right-2 !top-2 !flex !h-6 !w-6 !items-center !justify-center !rounded-md !border !bg-[var(--ds-background-100)] !text-[var(--ds-gray-800)] transition-transform transition-colors duration-100 hover:!bg-[var(--ds-gray-alpha-200)] active:!scale-95 active:!bg-[var(--ds-gray-alpha-300)]"
|
|
35
|
-
style={{ borderColor: 'var(--ds-gray-300)' }}
|
|
36
|
-
onClick={() => {
|
|
37
|
-
navigator.clipboard
|
|
38
|
-
.writeText(serializeForClipboard(data))
|
|
39
|
-
.then(() => {
|
|
40
|
-
toast.success('Copied to clipboard');
|
|
41
|
-
})
|
|
42
|
-
.catch(() => {
|
|
43
|
-
toast.error('Failed to copy');
|
|
44
|
-
});
|
|
45
|
-
}}
|
|
46
|
-
>
|
|
47
|
-
<Copy size={12} />
|
|
48
|
-
</button>
|
|
65
|
+
<div className="relative overflow-x-auto rounded-md border border-gray-alpha-400 p-3">
|
|
66
|
+
<CopyButton
|
|
67
|
+
copyText={serializeForClipboard(data)}
|
|
68
|
+
ariaLabel="Copy data"
|
|
69
|
+
className="absolute right-2 top-2 z-10 flex h-6 w-6 items-center justify-center rounded-md border border-gray-alpha-400 !bg-background-100 p-0 text-gray-900 transition-transform transition-colors duration-100 hover:bg-gray-200 active:scale-95 active:bg-gray-300"
|
|
70
|
+
/>
|
|
49
71
|
<DataInspector data={data} />
|
|
50
72
|
</div>
|
|
51
73
|
);
|
|
@@ -1,65 +1,143 @@
|
|
|
1
|
-
import { ChevronRight } from 'lucide-react';
|
|
2
|
-
import type
|
|
1
|
+
import { ChevronDown, ChevronRight } from 'lucide-react';
|
|
2
|
+
import { type ReactNode, useState } from 'react';
|
|
3
|
+
import { cn } from '../../lib/utils';
|
|
3
4
|
|
|
4
5
|
export function DetailCard({
|
|
5
6
|
summary,
|
|
6
7
|
children,
|
|
7
8
|
onToggle,
|
|
8
9
|
disabled = false,
|
|
10
|
+
defaultOpen = false,
|
|
11
|
+
variant = 'section',
|
|
12
|
+
trailing,
|
|
9
13
|
summaryClassName,
|
|
10
14
|
contentClassName,
|
|
11
15
|
}: {
|
|
12
16
|
summary: ReactNode;
|
|
13
17
|
children?: ReactNode;
|
|
14
|
-
/** Called when the detail card is expanded/collapsed */
|
|
15
18
|
onToggle?: (open: boolean) => void;
|
|
16
|
-
/** Renders a non-expandable summary card when true. */
|
|
17
19
|
disabled?: boolean;
|
|
18
|
-
|
|
20
|
+
defaultOpen?: boolean;
|
|
21
|
+
variant?: 'section' | 'card';
|
|
22
|
+
trailing?: ReactNode;
|
|
19
23
|
summaryClassName?: string;
|
|
20
|
-
/** Extra classes for expanded content wrapper. */
|
|
21
24
|
contentClassName?: string;
|
|
22
25
|
}) {
|
|
23
|
-
|
|
26
|
+
const [open, setOpen] = useState(defaultOpen);
|
|
27
|
+
|
|
28
|
+
const handleToggle = (e: React.SyntheticEvent<HTMLDetailsElement>) => {
|
|
29
|
+
// React surfaces `toggle` as a bubbling synthetic event even though the
|
|
30
|
+
// native event doesn't bubble. Without this guard, a nested <details>
|
|
31
|
+
// (e.g. an event card inside the Events section) collapsing would flip
|
|
32
|
+
// the outer DetailCard's state. Only react to direct toggles.
|
|
33
|
+
if (e.target !== e.currentTarget) return;
|
|
34
|
+
const next = e.currentTarget.open;
|
|
35
|
+
setOpen(next);
|
|
36
|
+
onToggle?.(next);
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
if (variant === 'card') {
|
|
40
|
+
if (disabled) {
|
|
41
|
+
return (
|
|
42
|
+
<div
|
|
43
|
+
className={cn(
|
|
44
|
+
'list-none px-3 py-4 bg-background-200 [&::-webkit-details-marker]:hidden',
|
|
45
|
+
summaryClassName
|
|
46
|
+
)}
|
|
47
|
+
style={{ cursor: 'not-allowed', opacity: 0.8 }}
|
|
48
|
+
>
|
|
49
|
+
{summary}
|
|
50
|
+
</div>
|
|
51
|
+
);
|
|
52
|
+
}
|
|
24
53
|
return (
|
|
25
|
-
<
|
|
26
|
-
className=
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
backgroundColor: 'var(--ds-gray-100)',
|
|
30
|
-
color: 'var(--ds-gray-700)',
|
|
31
|
-
cursor: 'not-allowed',
|
|
32
|
-
opacity: 0.8,
|
|
33
|
-
}}
|
|
54
|
+
<details
|
|
55
|
+
className="group/card last:border-b border-gray-alpha-400"
|
|
56
|
+
open={open}
|
|
57
|
+
onToggle={handleToggle}
|
|
34
58
|
>
|
|
35
|
-
|
|
36
|
-
|
|
59
|
+
<summary
|
|
60
|
+
className={cn(
|
|
61
|
+
'list-none cursor-pointer px-3 py-4 border-t border-gray-alpha-400 bg-background-200 hover:bg-gray-100 [&::-webkit-details-marker]:hidden',
|
|
62
|
+
summaryClassName
|
|
63
|
+
)}
|
|
64
|
+
>
|
|
65
|
+
<span className="flex items-center gap-1.5">
|
|
66
|
+
<ChevronRight
|
|
67
|
+
size={14}
|
|
68
|
+
className={cn(
|
|
69
|
+
'shrink-0 text-gray-700 group-hover/card:text-gray-1000',
|
|
70
|
+
open && 'rotate-90'
|
|
71
|
+
)}
|
|
72
|
+
/>
|
|
73
|
+
{summary}
|
|
74
|
+
</span>
|
|
75
|
+
</summary>
|
|
76
|
+
<div className={contentClassName}>{children}</div>
|
|
77
|
+
</details>
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Shared height with the expandable summary row. Keeps the trailing /
|
|
82
|
+
// disabled / chevron variants visually identical in height regardless of
|
|
83
|
+
// what's in the trailing slot.
|
|
84
|
+
const rowClasses =
|
|
85
|
+
'flex h-9 items-center gap-2 px-2 -mx-2 text-heading-14 font-medium my-2';
|
|
86
|
+
|
|
87
|
+
if (trailing) {
|
|
88
|
+
return (
|
|
89
|
+
<section className="-mx-4 border-t px-4 border-gray-alpha-400">
|
|
90
|
+
<div className={cn(rowClasses, summaryClassName)}>
|
|
91
|
+
<div className="isolate relative shrink-0 w-3.5 h-3.5 text-gray-700">
|
|
92
|
+
<ChevronRight
|
|
93
|
+
size={14}
|
|
94
|
+
className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2"
|
|
95
|
+
/>
|
|
96
|
+
</div>
|
|
97
|
+
<span className="min-w-0 flex-1">{summary}</span>
|
|
98
|
+
<div className="shrink-0 pr-1">{trailing}</div>
|
|
99
|
+
</div>
|
|
100
|
+
</section>
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (disabled) {
|
|
105
|
+
return (
|
|
106
|
+
<section className="-mx-4 border-t px-4 border-gray-alpha-400">
|
|
107
|
+
<div
|
|
108
|
+
className={cn(rowClasses, summaryClassName)}
|
|
109
|
+
style={{ color: 'var(--ds-gray-700)', cursor: 'not-allowed' }}
|
|
110
|
+
>
|
|
111
|
+
<span className="min-w-0 flex-1">{summary}</span>
|
|
112
|
+
</div>
|
|
113
|
+
</section>
|
|
37
114
|
);
|
|
38
115
|
}
|
|
39
116
|
|
|
40
117
|
return (
|
|
41
|
-
<
|
|
42
|
-
className="group"
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
118
|
+
<section className="-mx-4 border-t px-4 border-gray-alpha-400">
|
|
119
|
+
<details className="group" open={open} onToggle={handleToggle}>
|
|
120
|
+
<summary
|
|
121
|
+
className={cn(
|
|
122
|
+
'group/trigger list-none cursor-pointer rounded hover:bg-gray-alpha-100 [&::-webkit-details-marker]:hidden',
|
|
123
|
+
rowClasses,
|
|
124
|
+
summaryClassName
|
|
125
|
+
)}
|
|
126
|
+
>
|
|
127
|
+
<div className="isolate relative shrink-0 text-gray-700 group-hover/trigger:text-gray-1000 w-3.5 h-3.5">
|
|
128
|
+
<ChevronRight
|
|
129
|
+
size={14}
|
|
130
|
+
className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 opacity-100 group-open:opacity-0"
|
|
131
|
+
/>
|
|
132
|
+
<ChevronDown
|
|
133
|
+
size={14}
|
|
134
|
+
className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 opacity-0 group-open:opacity-100"
|
|
135
|
+
/>
|
|
136
|
+
</div>
|
|
137
|
+
<span className="min-w-0 flex-1">{summary}</span>
|
|
138
|
+
</summary>
|
|
139
|
+
<div className={cn('mb-3', contentClassName)}>{children}</div>
|
|
140
|
+
</details>
|
|
141
|
+
</section>
|
|
64
142
|
);
|
|
65
143
|
}
|
|
@@ -9,6 +9,7 @@ import { DecryptClickContext } from '../ui/data-inspector';
|
|
|
9
9
|
import { AttributePanel } from './attribute-panel';
|
|
10
10
|
import { EventsList } from './events-list';
|
|
11
11
|
import { ResolveHookModal } from './resolve-hook-modal';
|
|
12
|
+
import { useSidebarDataOptional } from './sidebar-data-context';
|
|
12
13
|
|
|
13
14
|
// Type guards for runtime validation of span attribute data
|
|
14
15
|
function isStep(data: unknown): data is Step {
|
|
@@ -116,6 +117,9 @@ export function EntityDetailPanel({
|
|
|
116
117
|
new Set()
|
|
117
118
|
);
|
|
118
119
|
|
|
120
|
+
const sidebar = useSidebarDataOptional();
|
|
121
|
+
const hasEncryptedData = Boolean(sidebar?.hasEncryptedData && !encryptionKey);
|
|
122
|
+
|
|
119
123
|
const data = selectedSpan?.data;
|
|
120
124
|
const rawEvents = selectedSpan?.rawEvents;
|
|
121
125
|
const rawEventsLength = rawEvents?.length ?? 0;
|
|
@@ -345,9 +349,11 @@ export function EntityDetailPanel({
|
|
|
345
349
|
return (
|
|
346
350
|
<div className="flex h-full flex-col">
|
|
347
351
|
<DecryptClickContext.Provider
|
|
348
|
-
value={
|
|
352
|
+
value={
|
|
353
|
+
onDecrypt ? { onDecrypt, isDecrypting, hasEncryptedData } : undefined
|
|
354
|
+
}
|
|
349
355
|
>
|
|
350
|
-
<div className="flex-1 overflow-y-auto px-
|
|
356
|
+
<div className="flex-1 overflow-y-auto px-4 pb-8">
|
|
351
357
|
{hasPendingActions && (
|
|
352
358
|
<div
|
|
353
359
|
className="mb-4 rounded-lg border p-2"
|
|
@@ -412,32 +418,26 @@ export function EntityDetailPanel({
|
|
|
412
418
|
</div>
|
|
413
419
|
)}
|
|
414
420
|
|
|
415
|
-
<
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
onLoadEventData={onLoadEventData}
|
|
436
|
-
encryptionKey={encryptionKey}
|
|
437
|
-
/>
|
|
438
|
-
</section>
|
|
439
|
-
)}
|
|
440
|
-
</div>
|
|
421
|
+
<AttributePanel
|
|
422
|
+
data={displayData}
|
|
423
|
+
moduleSpecifier={moduleSpecifier}
|
|
424
|
+
expiredAt={run.expiredAt}
|
|
425
|
+
isLoading={loading}
|
|
426
|
+
error={error ?? undefined}
|
|
427
|
+
onStreamClick={onStreamClick}
|
|
428
|
+
onRunClick={onRunClick}
|
|
429
|
+
onDecrypt={onDecrypt}
|
|
430
|
+
isDecrypting={isDecrypting}
|
|
431
|
+
resource={resource}
|
|
432
|
+
/>
|
|
433
|
+
|
|
434
|
+
{resource !== 'run' && rawEvents && (
|
|
435
|
+
<EventsList
|
|
436
|
+
events={rawEvents}
|
|
437
|
+
onLoadEventData={onLoadEventData}
|
|
438
|
+
encryptionKey={encryptionKey}
|
|
439
|
+
/>
|
|
440
|
+
)}
|
|
441
441
|
</div>
|
|
442
442
|
</DecryptClickContext.Provider>
|
|
443
443
|
|
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { EVENT_DATA_REF_FIELDS, type Event } from '@workflow/world';
|
|
4
|
-
import { useCallback,
|
|
5
|
-
import { isExpiredMarker } from '../../lib/hydration';
|
|
4
|
+
import { useCallback, useLayoutEffect, useMemo, useRef, useState } from 'react';
|
|
5
|
+
import { hasEncryptedFields, isExpiredMarker } from '../../lib/hydration';
|
|
6
6
|
import { ErrorCard } from '../ui/error-card';
|
|
7
7
|
import {
|
|
8
8
|
ErrorStackBlock,
|
|
9
9
|
isStructuredErrorWithStack,
|
|
10
10
|
} from '../ui/error-stack-block';
|
|
11
11
|
import { Skeleton } from '../ui/skeleton';
|
|
12
|
-
import {
|
|
13
|
-
import { CopyableDataBlock } from './copyable-data-block';
|
|
12
|
+
import { CopyableDataBlock, EncryptedDataBlock } from './copyable-data-block';
|
|
14
13
|
import { DetailCard } from './detail-card';
|
|
15
14
|
|
|
16
15
|
/**
|
|
@@ -94,7 +93,7 @@ function EventItem({
|
|
|
94
93
|
|
|
95
94
|
// When the encryption key changes and this event was previously expanded,
|
|
96
95
|
// re-load the data so it gets decrypted
|
|
97
|
-
|
|
96
|
+
useLayoutEffect(() => {
|
|
98
97
|
if (!encryptionKey || !wasExpandedRef.current) return;
|
|
99
98
|
loadedDataRef.current = null;
|
|
100
99
|
setLoadedData(null);
|
|
@@ -102,25 +101,27 @@ function EventItem({
|
|
|
102
101
|
}, [encryptionKey, loadEventData]);
|
|
103
102
|
|
|
104
103
|
const createdAt = new Date(event.createdAt);
|
|
104
|
+
const createdAtTime = createdAt.toLocaleTimeString(undefined, {
|
|
105
|
+
hour: 'numeric',
|
|
106
|
+
minute: 'numeric',
|
|
107
|
+
second: 'numeric',
|
|
108
|
+
});
|
|
105
109
|
|
|
106
110
|
const displayPayload = isLoading ? loadedData : mergedDisplay;
|
|
107
111
|
|
|
108
112
|
return (
|
|
109
113
|
<DetailCard
|
|
110
|
-
|
|
114
|
+
variant="card"
|
|
115
|
+
summaryClassName="px-3 py-2"
|
|
111
116
|
summary={
|
|
112
|
-
|
|
113
|
-
<span
|
|
114
|
-
className="font-medium"
|
|
115
|
-
style={{ color: 'var(--ds-gray-1000)' }}
|
|
116
|
-
>
|
|
117
|
+
<div className="flex w-full items-center justify-between gap-3">
|
|
118
|
+
<span className="text-gray-1000 text-label-12 font-mono">
|
|
117
119
|
{event.eventType}
|
|
118
|
-
</span>{' '}
|
|
119
|
-
-{' '}
|
|
120
|
-
<span style={{ color: 'var(--ds-gray-700)' }}>
|
|
121
|
-
{localMillisecondTime(createdAt.getTime())}
|
|
122
120
|
</span>
|
|
123
|
-
|
|
121
|
+
<span className="shrink-0 text-label-13 text-gray-900">
|
|
122
|
+
{createdAtTime}
|
|
123
|
+
</span>
|
|
124
|
+
</div>
|
|
124
125
|
}
|
|
125
126
|
onToggle={
|
|
126
127
|
canHaveData
|
|
@@ -131,47 +132,17 @@ function EventItem({
|
|
|
131
132
|
}
|
|
132
133
|
>
|
|
133
134
|
{/* Event attributes */}
|
|
134
|
-
<div
|
|
135
|
-
className="flex
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
backgroundColor: 'var(--ds-gray-100)',
|
|
139
|
-
}}
|
|
140
|
-
>
|
|
141
|
-
<div
|
|
142
|
-
className="flex min-h-[32px] items-center justify-between gap-4 px-2.5 py-1.5"
|
|
143
|
-
style={{ borderColor: 'var(--ds-gray-300)' }}
|
|
144
|
-
>
|
|
145
|
-
<span
|
|
146
|
-
className="text-[13px] font-medium"
|
|
147
|
-
style={{ color: 'var(--ds-gray-700)' }}
|
|
148
|
-
>
|
|
149
|
-
Event ID
|
|
150
|
-
</span>
|
|
151
|
-
<span
|
|
152
|
-
className="max-w-[70%] truncate text-right text-[13px] font-mono"
|
|
153
|
-
style={{ color: 'var(--ds-gray-1000)' }}
|
|
154
|
-
title={event.eventId}
|
|
155
|
-
>
|
|
135
|
+
<div className="flex flex-col bg-background-200 [&:has(+_*)]:border-b [&:has(+_*)]:border-gray-alpha-400">
|
|
136
|
+
<div className="flex items-center justify-between gap-2 py-2 px-3">
|
|
137
|
+
<span className="text-label-12 text-gray-900">Event ID</span>
|
|
138
|
+
<span className="max-w-[70%] truncate text-right text-label-12 font-mono">
|
|
156
139
|
{event.eventId}
|
|
157
140
|
</span>
|
|
158
141
|
</div>
|
|
159
142
|
{event.correlationId && (
|
|
160
|
-
<div
|
|
161
|
-
className="
|
|
162
|
-
|
|
163
|
-
>
|
|
164
|
-
<span
|
|
165
|
-
className="text-[13px] font-medium"
|
|
166
|
-
style={{ color: 'var(--ds-gray-700)' }}
|
|
167
|
-
>
|
|
168
|
-
Correlation ID
|
|
169
|
-
</span>
|
|
170
|
-
<span
|
|
171
|
-
className="max-w-[70%] truncate text-right text-[13px] font-mono"
|
|
172
|
-
style={{ color: 'var(--ds-gray-1000)' }}
|
|
173
|
-
title={event.correlationId}
|
|
174
|
-
>
|
|
143
|
+
<div className="flex items-center justify-between gap-2 py-2 px-3">
|
|
144
|
+
<span className="text-label-12 text-gray-900">Correlation ID</span>
|
|
145
|
+
<span className="max-w-[70%] truncate text-right text-label-12 font-mono">
|
|
175
146
|
{event.correlationId}
|
|
176
147
|
</span>
|
|
177
148
|
</div>
|
|
@@ -180,12 +151,7 @@ function EventItem({
|
|
|
180
151
|
|
|
181
152
|
{/* Loading state */}
|
|
182
153
|
{isLoading && (
|
|
183
|
-
<div
|
|
184
|
-
className="mt-2 rounded-md border p-3"
|
|
185
|
-
style={{
|
|
186
|
-
borderColor: 'var(--ds-gray-300)',
|
|
187
|
-
}}
|
|
188
|
-
>
|
|
154
|
+
<div className="p-3">
|
|
189
155
|
<Skeleton className="h-4 w-[35%]" />
|
|
190
156
|
<Skeleton className="mt-2 h-4 w-[90%]" />
|
|
191
157
|
<Skeleton className="mt-2 h-4 w-[75%]" />
|
|
@@ -203,7 +169,7 @@ function EventItem({
|
|
|
203
169
|
|
|
204
170
|
{/* Event data */}
|
|
205
171
|
{displayPayload != null && (
|
|
206
|
-
<div className="
|
|
172
|
+
<div className="[&>div]:border-none [&>div]:rounded-none">
|
|
207
173
|
<EventDataBlock eventType={event.eventType} data={displayPayload} />
|
|
208
174
|
</div>
|
|
209
175
|
)}
|
|
@@ -258,6 +224,10 @@ function EventDataBlock({
|
|
|
258
224
|
);
|
|
259
225
|
}
|
|
260
226
|
|
|
227
|
+
if (hasEncryptedFields({ eventType, eventData: data })) {
|
|
228
|
+
return <EncryptedDataBlock />;
|
|
229
|
+
}
|
|
230
|
+
|
|
261
231
|
// For error events (step_failed, step_retrying), the eventData has the shape
|
|
262
232
|
// { error: StructuredError, stack?: string, ... }. Check both the top-level
|
|
263
233
|
// value and the nested `error` field for a stack trace.
|
|
@@ -311,26 +281,28 @@ export function EventsList({
|
|
|
311
281
|
[events]
|
|
312
282
|
);
|
|
313
283
|
|
|
284
|
+
const hasEvents = sortedEvents.length > 0 && !error;
|
|
285
|
+
|
|
286
|
+
if (!hasEvents && !isLoading) {
|
|
287
|
+
return <DetailCard summary="Events" disabled />;
|
|
288
|
+
}
|
|
289
|
+
|
|
314
290
|
return (
|
|
315
|
-
<
|
|
316
|
-
<h3
|
|
317
|
-
className="text-label-14 font-medium mt-4 mb-2"
|
|
318
|
-
style={{ color: 'var(--ds-gray-1000)' }}
|
|
319
|
-
>
|
|
320
|
-
Events
|
|
321
|
-
</h3>
|
|
291
|
+
<DetailCard summary="Events" contentClassName="mb-0" defaultOpen>
|
|
322
292
|
{isLoading ? (
|
|
323
|
-
<div className="flex flex-col
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
293
|
+
<div className="flex flex-col -mx-4">
|
|
294
|
+
{[0, 1, 2].map((i) => (
|
|
295
|
+
<div
|
|
296
|
+
key={i}
|
|
297
|
+
className="flex items-center justify-between gap-3 bg-background-200 px-4 py-2"
|
|
298
|
+
>
|
|
299
|
+
<Skeleton className="h-4 w-32 rounded" />
|
|
300
|
+
<Skeleton className="h-3 w-16 rounded" />
|
|
301
|
+
</div>
|
|
302
|
+
))}
|
|
327
303
|
</div>
|
|
328
|
-
) :
|
|
329
|
-
|
|
330
|
-
<div className="text-sm">No events found</div>
|
|
331
|
-
)}
|
|
332
|
-
{sortedEvents.length > 0 && !error ? (
|
|
333
|
-
<div className="flex flex-col gap-4">
|
|
304
|
+
) : (
|
|
305
|
+
<div className="flex flex-col -mx-4">
|
|
334
306
|
{sortedEvents.map((event) => (
|
|
335
307
|
<EventItem
|
|
336
308
|
key={event.eventId}
|
|
@@ -340,7 +312,7 @@ export function EventsList({
|
|
|
340
312
|
/>
|
|
341
313
|
))}
|
|
342
314
|
</div>
|
|
343
|
-
)
|
|
344
|
-
</
|
|
315
|
+
)}
|
|
316
|
+
</DetailCard>
|
|
345
317
|
);
|
|
346
318
|
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { cva, type VariantProps } from 'class-variance-authority';
|
|
3
|
+
import { cn } from '../../lib/utils';
|
|
4
|
+
|
|
5
|
+
const buttonVariants = cva(
|
|
6
|
+
[
|
|
7
|
+
'outline-none m-0 border-0 align-baseline no-underline group/trigger',
|
|
8
|
+
'relative cursor-pointer select-none transform translate-z-0',
|
|
9
|
+
'inline-flex max-w-full items-center justify-center gap-x-1 whitespace-nowrap rounded-md font-medium',
|
|
10
|
+
'!text-gray-100',
|
|
11
|
+
'bg-gray-1000',
|
|
12
|
+
'transition-[border-color,background,color,transform,box-shadow] duration-150 ease-in-out',
|
|
13
|
+
'hover:bg-[var(--themed-hover-bg,_hsl(0,_0%,_22%))] dark-theme:hover:bg-[var(--themed-hover-bg,_hsl(0,_0%,_80%))]',
|
|
14
|
+
// disabled styles
|
|
15
|
+
'disabled:cursor-not-allowed aria-disabled:cursor-not-allowed',
|
|
16
|
+
'disabled:bg-gray-100 disabled:!text-gray-700 disabled:hover:bg-gray-100',
|
|
17
|
+
'aria-disabled:bg-gray-100 aria-disabled:text-gray-700 aria-disabled:hover:bg-gray-100',
|
|
18
|
+
],
|
|
19
|
+
{
|
|
20
|
+
variants: {
|
|
21
|
+
variant: {
|
|
22
|
+
default: '',
|
|
23
|
+
secondary:
|
|
24
|
+
'border border-gray-alpha-400 [--themed-bg:_var(--ds-background-100)] [--themed-fg:_var(--ds-gray-1000)] [--themed-hover-bg:_var(--ds-gray-alpha-200)]',
|
|
25
|
+
ghost:
|
|
26
|
+
'[--themed-bg:_transparent] [--themed-fg:_var(--ds-gray-1000)] [--themed-hover-bg:_var(--ds-gray-alpha-100)]',
|
|
27
|
+
},
|
|
28
|
+
size: {
|
|
29
|
+
default: 'h-10 px-4 text-[14px]',
|
|
30
|
+
sm: 'h-8 px-3 text-[14px]',
|
|
31
|
+
xs: 'h-6 px-1.5 py-0.5 text-button-12',
|
|
32
|
+
icon: 'h-8 w-8',
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
defaultVariants: {
|
|
36
|
+
variant: 'default',
|
|
37
|
+
size: 'default',
|
|
38
|
+
},
|
|
39
|
+
}
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
export type ButtonProps = React.ButtonHTMLAttributes<HTMLButtonElement> &
|
|
43
|
+
VariantProps<typeof buttonVariants>;
|
|
44
|
+
|
|
45
|
+
export function Button({
|
|
46
|
+
className,
|
|
47
|
+
variant,
|
|
48
|
+
size,
|
|
49
|
+
type = 'button',
|
|
50
|
+
...props
|
|
51
|
+
}: ButtonProps) {
|
|
52
|
+
return (
|
|
53
|
+
<button
|
|
54
|
+
type={type}
|
|
55
|
+
className={cn(buttonVariants({ variant, size, className }))}
|
|
56
|
+
{...props}
|
|
57
|
+
/>
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export { buttonVariants };
|