@workflow/web-shared 5.0.0-beta.2 → 5.0.0-beta.20
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 +16 -1
- package/dist/components/event-list-view.d.ts.map +1 -1
- package/dist/components/event-list-view.js +196 -85
- package/dist/components/hook-actions.js +1 -1
- package/dist/components/index.d.ts +4 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +5 -1
- package/dist/components/new-trace-viewer/components/copy-button.d.ts +9 -0
- package/dist/components/new-trace-viewer/components/copy-button.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/components/copy-button.js +27 -0
- package/dist/components/new-trace-viewer/components/event-list.d.ts +10 -0
- package/dist/components/new-trace-viewer/components/event-list.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/components/event-list.js +46 -0
- package/dist/components/new-trace-viewer/components/middle-truncate/copy-selection.d.ts +18 -0
- package/dist/components/new-trace-viewer/components/middle-truncate/copy-selection.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/components/middle-truncate/copy-selection.js +54 -0
- package/dist/components/new-trace-viewer/components/middle-truncate/middle-truncate.d.ts +20 -0
- package/dist/components/new-trace-viewer/components/middle-truncate/middle-truncate.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/components/middle-truncate/middle-truncate.js +81 -0
- package/dist/components/new-trace-viewer/components/middle-truncate/truncate.d.ts +25 -0
- package/dist/components/new-trace-viewer/components/middle-truncate/truncate.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/components/middle-truncate/truncate.js +101 -0
- package/dist/components/new-trace-viewer/components/middle-truncate/use-middle-truncate.d.ts +20 -0
- package/dist/components/new-trace-viewer/components/middle-truncate/use-middle-truncate.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/components/middle-truncate/use-middle-truncate.js +114 -0
- package/dist/components/new-trace-viewer/components/span-markers.d.ts +46 -0
- package/dist/components/new-trace-viewer/components/span-markers.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/components/span-markers.js +85 -0
- package/dist/components/new-trace-viewer/components/split-pane.d.ts +15 -0
- package/dist/components/new-trace-viewer/components/split-pane.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/components/split-pane.js +105 -0
- package/dist/components/new-trace-viewer/components/timeline.d.ts +36 -0
- package/dist/components/new-trace-viewer/components/timeline.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/components/timeline.js +254 -0
- package/dist/components/new-trace-viewer/components/timeline.module.css +46 -0
- package/dist/components/new-trace-viewer/components/trace-viewer-skeleton.d.ts +2 -0
- package/dist/components/new-trace-viewer/components/trace-viewer-skeleton.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/components/trace-viewer-skeleton.js +19 -0
- package/dist/components/new-trace-viewer/components/use-row-window.d.ts +34 -0
- package/dist/components/new-trace-viewer/components/use-row-window.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/components/use-row-window.js +107 -0
- package/dist/components/new-trace-viewer/context.d.ts +15 -0
- package/dist/components/new-trace-viewer/context.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/context.js +47 -0
- package/dist/components/new-trace-viewer/icons.d.ts +6 -0
- package/dist/components/new-trace-viewer/icons.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/icons.js +15 -0
- package/dist/components/new-trace-viewer/search.d.ts +19 -0
- package/dist/components/new-trace-viewer/search.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/search.js +134 -0
- package/dist/components/new-trace-viewer/trace-viewer.d.ts +11 -0
- package/dist/components/new-trace-viewer/trace-viewer.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/trace-viewer.js +462 -0
- package/dist/components/new-trace-viewer/types.d.ts +3 -0
- package/dist/components/new-trace-viewer/types.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/types.js +2 -0
- package/dist/components/new-trace-viewer/utils.d.ts +61 -0
- package/dist/components/new-trace-viewer/utils.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/utils.js +345 -0
- 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 +129 -102
- package/dist/components/sidebar/attributes-block.d.ts +28 -0
- package/dist/components/sidebar/attributes-block.d.ts.map +1 -0
- package/dist/components/sidebar/attributes-block.js +81 -0
- 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 +1 -3
- package/dist/components/sidebar/entity-detail-panel.d.ts.map +1 -1
- package/dist/components/sidebar/entity-detail-panel.js +17 -35
- package/dist/components/sidebar/events-list.d.ts +3 -1
- package/dist/components/sidebar/events-list.d.ts.map +1 -1
- package/dist/components/sidebar/events-list.js +36 -22
- package/dist/components/sidebar/resolve-hook-modal.js +1 -1
- package/dist/components/sidebar/sidebar-data-context.d.ts +29 -0
- package/dist/components/sidebar/sidebar-data-context.d.ts.map +1 -0
- package/dist/components/sidebar/sidebar-data-context.js +19 -0
- package/dist/components/sidebar/span-detail-merge.d.ts +16 -0
- package/dist/components/sidebar/span-detail-merge.d.ts.map +1 -0
- package/dist/components/sidebar/span-detail-merge.js +53 -0
- package/dist/components/stream-viewer.d.ts +1 -1
- package/dist/components/stream-viewer.d.ts.map +1 -1
- package/dist/components/stream-viewer.js +3 -27
- 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.d.ts.map +1 -1
- package/dist/components/trace-viewer/components/node.js +2 -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/trace-viewer.module.css +4 -4
- 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.d.ts +3 -3
- package/dist/components/trace-viewer/util/timing.d.ts.map +1 -1
- package/dist/components/trace-viewer/util/timing.js +8 -11
- 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.d.ts +14 -0
- package/dist/components/trace-viewer-new.d.ts.map +1 -0
- package/dist/components/trace-viewer-new.js +21 -0
- 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 +46 -0
- package/dist/components/ui/card.js +1 -1
- package/dist/components/ui/context-card.d.ts +47 -0
- package/dist/components/ui/context-card.d.ts.map +1 -0
- package/dist/components/ui/context-card.js +471 -0
- package/dist/components/ui/data-inspector.d.ts +22 -0
- package/dist/components/ui/data-inspector.d.ts.map +1 -1
- package/dist/components/ui/data-inspector.js +103 -13
- 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 +17 -10
- package/dist/components/ui/error-stack-block.d.ts.map +1 -1
- package/dist/components/ui/error-stack-block.js +49 -30
- package/dist/components/ui/icon-button.d.ts +19 -0
- package/dist/components/ui/icon-button.d.ts.map +1 -0
- package/dist/components/ui/icon-button.js +29 -0
- package/dist/components/ui/inspector-theme.d.ts +9 -10
- package/dist/components/ui/inspector-theme.d.ts.map +1 -1
- package/dist/components/ui/inspector-theme.js +39 -72
- package/dist/components/ui/kbd.d.ts +6 -0
- package/dist/components/ui/kbd.d.ts.map +1 -0
- package/dist/components/ui/kbd.js +6 -0
- 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.d.ts +34 -1
- package/dist/components/ui/timestamp-tooltip.d.ts.map +1 -1
- package/dist/components/ui/timestamp-tooltip.js +80 -132
- package/dist/components/ui/tooltip.d.ts +10 -0
- package/dist/components/ui/tooltip.d.ts.map +1 -0
- package/dist/components/ui/tooltip.js +12 -0
- package/dist/components/workflow-trace-view.d.ts +1 -3
- package/dist/components/workflow-trace-view.d.ts.map +1 -1
- package/dist/components/workflow-trace-view.js +11 -13
- package/dist/components/workflow-traces/event-colors.d.ts +1 -0
- package/dist/components/workflow-traces/event-colors.d.ts.map +1 -1
- package/dist/components/workflow-traces/event-colors.js +12 -1
- package/dist/components/workflow-traces/trace-colors.js +1 -1
- package/dist/components/workflow-traces/trace-span-construction.d.ts +2 -2
- package/dist/components/workflow-traces/trace-span-construction.d.ts.map +1 -1
- package/dist/components/workflow-traces/trace-span-construction.js +19 -5
- package/dist/components/workflow-traces/trace-time-utils.js +1 -1
- package/dist/hooks/use-dark-mode.js +1 -1
- package/dist/hooks/use-intersection-observer.d.ts +17 -0
- package/dist/hooks/use-intersection-observer.d.ts.map +1 -0
- package/dist/hooks/use-intersection-observer.js +29 -0
- package/dist/hooks/use-load-more-on-scroll.d.ts +21 -0
- package/dist/hooks/use-load-more-on-scroll.d.ts.map +1 -0
- package/dist/hooks/use-load-more-on-scroll.js +28 -0
- 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.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/lib/event-analysis.js +1 -1
- package/dist/lib/event-materialization.js +1 -1
- package/dist/lib/exact-event-search-id.d.ts +25 -0
- package/dist/lib/exact-event-search-id.d.ts.map +1 -0
- package/dist/lib/exact-event-search-id.js +39 -0
- package/dist/lib/hydration.d.ts +6 -0
- package/dist/lib/hydration.d.ts.map +1 -1
- package/dist/lib/hydration.js +154 -2
- package/dist/lib/stream-display.d.ts +18 -0
- package/dist/lib/stream-display.d.ts.map +1 -0
- package/dist/lib/stream-display.js +30 -0
- package/dist/lib/toast.js +1 -1
- package/dist/lib/trace-builder.d.ts +15 -0
- package/dist/lib/trace-builder.d.ts.map +1 -1
- package/dist/lib/trace-builder.js +29 -3
- package/dist/lib/utils.d.ts +20 -9
- package/dist/lib/utils.d.ts.map +1 -1
- package/dist/lib/utils.js +74 -31
- package/dist/lib/zstd-browser-decoder.d.ts +7 -0
- package/dist/lib/zstd-browser-decoder.d.ts.map +1 -0
- package/dist/lib/zstd-browser-decoder.js +41 -0
- package/dist/styles.css +484 -1
- package/package.json +10 -5
- package/src/components/event-list-view.tsx +279 -104
- package/src/components/index.ts +7 -0
- package/src/components/new-trace-viewer/components/copy-button.tsx +68 -0
- package/src/components/new-trace-viewer/components/event-list.tsx +136 -0
- package/src/components/new-trace-viewer/components/middle-truncate/copy-selection.ts +114 -0
- package/src/components/new-trace-viewer/components/middle-truncate/middle-truncate.tsx +157 -0
- package/src/components/new-trace-viewer/components/middle-truncate/truncate.ts +132 -0
- package/src/components/new-trace-viewer/components/middle-truncate/use-middle-truncate.ts +167 -0
- package/src/components/new-trace-viewer/components/span-markers.tsx +173 -0
- package/src/components/new-trace-viewer/components/split-pane.tsx +198 -0
- package/src/components/new-trace-viewer/components/timeline.module.css +46 -0
- package/src/components/new-trace-viewer/components/timeline.tsx +744 -0
- package/src/components/new-trace-viewer/components/trace-viewer-skeleton.tsx +94 -0
- package/src/components/new-trace-viewer/components/use-row-window.ts +140 -0
- package/src/components/new-trace-viewer/context.tsx +90 -0
- package/src/components/new-trace-viewer/icons.tsx +79 -0
- package/src/components/new-trace-viewer/search.ts +178 -0
- package/src/components/new-trace-viewer/trace-viewer.tsx +843 -0
- package/src/components/new-trace-viewer/types.ts +2 -0
- package/src/components/new-trace-viewer/utils.test.ts +182 -0
- package/src/components/new-trace-viewer/utils.ts +519 -0
- package/src/components/sidebar/attribute-panel.tsx +194 -240
- package/src/components/sidebar/attributes-block.tsx +173 -0
- package/src/components/sidebar/copyable-data-block.tsx +49 -27
- package/src/components/sidebar/detail-card.tsx +119 -59
- package/src/components/sidebar/entity-detail-panel.tsx +55 -111
- package/src/components/sidebar/events-list.tsx +85 -96
- package/src/components/sidebar/sidebar-data-context.tsx +62 -0
- package/src/components/sidebar/span-detail-merge.ts +65 -0
- package/src/components/stream-viewer.tsx +18 -40
- package/src/components/trace-viewer/components/node.tsx +3 -2
- package/src/components/trace-viewer/trace-viewer.module.css +4 -4
- package/src/components/trace-viewer/util/timing.ts +7 -11
- package/src/components/trace-viewer-new.tsx +55 -0
- package/src/components/ui/button.tsx +68 -0
- package/src/components/ui/context-card.tsx +784 -0
- package/src/components/ui/data-inspector.tsx +244 -22
- package/src/components/ui/error-stack-block.tsx +84 -55
- package/src/components/ui/icon-button.tsx +53 -0
- package/src/components/ui/inspector-theme.ts +39 -81
- package/src/components/ui/kbd.tsx +21 -0
- package/src/components/ui/timestamp-tooltip.tsx +132 -194
- package/src/components/ui/tooltip.tsx +47 -0
- package/src/components/workflow-trace-view.tsx +19 -15
- package/src/components/workflow-traces/event-colors.ts +12 -0
- package/src/components/workflow-traces/trace-span-construction.ts +24 -5
- package/src/hooks/use-intersection-observer.ts +57 -0
- package/src/hooks/use-load-more-on-scroll.ts +49 -0
- package/src/hooks/use-reduced-motion.ts +34 -0
- package/src/index.ts +9 -0
- package/src/lib/exact-event-search-id.ts +67 -0
- package/src/lib/hydration.ts +166 -1
- package/src/lib/stream-display.ts +48 -0
- package/src/lib/trace-builder.ts +34 -2
- package/src/lib/utils.ts +83 -31
- package/src/lib/zstd-browser-decoder.ts +42 -0
- package/src/styles.css +484 -1
- 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/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/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/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/toast.js.map +0 -1
- package/dist/lib/trace-builder.js.map +0 -1
- package/dist/lib/utils.js.map +0 -1
|
@@ -4,13 +4,16 @@ import type { Event, Hook, Step, WorkflowRun } from '@workflow/world';
|
|
|
4
4
|
import clsx from 'clsx';
|
|
5
5
|
import { Send, Zap } from 'lucide-react';
|
|
6
6
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
7
|
-
import { isEncryptedMarker } from '../../lib/hydration';
|
|
8
7
|
import { useToast } from '../../lib/toast';
|
|
9
8
|
import { DecryptClickContext } from '../ui/data-inspector';
|
|
10
|
-
import { DecryptButton } from '../ui/decrypt-button';
|
|
11
9
|
import { AttributePanel } from './attribute-panel';
|
|
12
10
|
import { EventsList } from './events-list';
|
|
13
11
|
import { ResolveHookModal } from './resolve-hook-modal';
|
|
12
|
+
import { useSidebarDataOptional } from './sidebar-data-context';
|
|
13
|
+
import {
|
|
14
|
+
mergeSpanDetail,
|
|
15
|
+
spanDetailMatchesSelection,
|
|
16
|
+
} from './span-detail-merge';
|
|
14
17
|
|
|
15
18
|
// Type guards for runtime validation of span attribute data
|
|
16
19
|
function isStep(data: unknown): data is Step {
|
|
@@ -69,7 +72,6 @@ export function EntityDetailPanel({
|
|
|
69
72
|
onDecrypt,
|
|
70
73
|
isDecrypting = false,
|
|
71
74
|
selectedSpan,
|
|
72
|
-
hasEncryptedData = false,
|
|
73
75
|
}: {
|
|
74
76
|
run: WorkflowRun;
|
|
75
77
|
/** Callback when a stream reference is clicked */
|
|
@@ -108,8 +110,6 @@ export function EntityDetailPanel({
|
|
|
108
110
|
isDecrypting?: boolean;
|
|
109
111
|
/** Info about the currently selected span from the trace viewer */
|
|
110
112
|
selectedSpan: SelectedSpanInfo | null;
|
|
111
|
-
/** Run-level hint: the run contains encrypted data (from probe). */
|
|
112
|
-
hasEncryptedData?: boolean;
|
|
113
113
|
}): React.JSX.Element | null {
|
|
114
114
|
const toast = useToast();
|
|
115
115
|
const [stoppingSleep, setStoppingSleep] = useState(false);
|
|
@@ -121,6 +121,9 @@ export function EntityDetailPanel({
|
|
|
121
121
|
new Set()
|
|
122
122
|
);
|
|
123
123
|
|
|
124
|
+
const sidebar = useSidebarDataOptional();
|
|
125
|
+
const hasEncryptedData = Boolean(sidebar?.hasEncryptedData && !encryptionKey);
|
|
126
|
+
|
|
124
127
|
const data = selectedSpan?.data;
|
|
125
128
|
const rawEvents = selectedSpan?.rawEvents;
|
|
126
129
|
const rawEventsLength = rawEvents?.length ?? 0;
|
|
@@ -216,30 +219,27 @@ export function EntityDetailPanel({
|
|
|
216
219
|
const error = spanDetailError ?? undefined;
|
|
217
220
|
const loading = spanDetailLoading ?? false;
|
|
218
221
|
|
|
219
|
-
const
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
isEncryptedMarker(d.metadata)
|
|
227
|
-
);
|
|
228
|
-
}, [spanDetailData]);
|
|
222
|
+
const matchedSpanDetailData = useMemo(
|
|
223
|
+
() =>
|
|
224
|
+
spanDetailMatchesSelection(spanDetailData, resource, resourceId)
|
|
225
|
+
? spanDetailData
|
|
226
|
+
: null,
|
|
227
|
+
[spanDetailData, resource, resourceId]
|
|
228
|
+
);
|
|
229
229
|
|
|
230
230
|
// Get the hook token for resolving (prefer fetched data, then hooks array fallback)
|
|
231
231
|
const hookToken = useMemo(() => {
|
|
232
232
|
if (resource !== 'hook' || !resourceId) return undefined;
|
|
233
233
|
// 1. Try the externally-fetched detail data first
|
|
234
|
-
if (isHook(
|
|
235
|
-
return
|
|
234
|
+
if (isHook(matchedSpanDetailData) && matchedSpanDetailData.token) {
|
|
235
|
+
return matchedSpanDetailData.token;
|
|
236
236
|
}
|
|
237
237
|
// 2. Try the span's inline data (reconstructed from hook_created event)
|
|
238
238
|
if (isHook(data) && (data as Hook).token) {
|
|
239
239
|
return (data as Hook).token;
|
|
240
240
|
}
|
|
241
241
|
return undefined;
|
|
242
|
-
}, [resource, resourceId,
|
|
242
|
+
}, [resource, resourceId, matchedSpanDetailData, data]);
|
|
243
243
|
|
|
244
244
|
useEffect(() => {
|
|
245
245
|
if (error && selectedSpan && resource) {
|
|
@@ -301,7 +301,7 @@ export function EntityDetailPanel({
|
|
|
301
301
|
|
|
302
302
|
try {
|
|
303
303
|
setResolvingHook(true);
|
|
304
|
-
const candidate =
|
|
304
|
+
const candidate = matchedSpanDetailData ?? data;
|
|
305
305
|
const hook = isHook(candidate) ? candidate : undefined;
|
|
306
306
|
await onResolveHook(hookToken, payload, hook);
|
|
307
307
|
toast.success('Hook resolved', {
|
|
@@ -322,17 +322,18 @@ export function EntityDetailPanel({
|
|
|
322
322
|
setResolvingHook(false);
|
|
323
323
|
}
|
|
324
324
|
},
|
|
325
|
-
[onResolveHook, hookToken, resolvingHook,
|
|
325
|
+
[onResolveHook, hookToken, resolvingHook, matchedSpanDetailData, data]
|
|
326
326
|
);
|
|
327
327
|
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
328
|
+
const displayData = useMemo(
|
|
329
|
+
() =>
|
|
330
|
+
mergeSpanDetail(data, matchedSpanDetailData) as
|
|
331
|
+
| WorkflowRun
|
|
332
|
+
| Step
|
|
333
|
+
| Hook
|
|
334
|
+
| Event,
|
|
335
|
+
[data, matchedSpanDetailData]
|
|
336
|
+
);
|
|
336
337
|
|
|
337
338
|
const moduleSpecifier = useMemo(() => {
|
|
338
339
|
const displayRecord = displayData as Record<string, unknown>;
|
|
@@ -354,65 +355,18 @@ export function EntityDetailPanel({
|
|
|
354
355
|
return null;
|
|
355
356
|
}
|
|
356
357
|
|
|
357
|
-
const resourceLabel = resource.charAt(0).toUpperCase() + resource.slice(1);
|
|
358
358
|
const hasPendingActions =
|
|
359
359
|
(resource === 'sleep' && canWakeUp) ||
|
|
360
360
|
(resource === 'hook' && canResolveHook);
|
|
361
|
-
const runStateLabel = run.completedAt ? 'Completed' : 'Live';
|
|
362
361
|
|
|
363
362
|
return (
|
|
364
363
|
<div className="flex h-full flex-col">
|
|
365
|
-
<div
|
|
366
|
-
className="border-b px-3 py-3"
|
|
367
|
-
style={{ borderColor: 'var(--ds-gray-200)' }}
|
|
368
|
-
>
|
|
369
|
-
<div className="flex items-start justify-between gap-2">
|
|
370
|
-
<div className="min-w-0">
|
|
371
|
-
<div className="flex items-center gap-2">
|
|
372
|
-
<span
|
|
373
|
-
className="inline-flex items-center rounded-full border px-2 py-0.5 text-[13px] font-medium"
|
|
374
|
-
style={{
|
|
375
|
-
borderColor: 'var(--ds-gray-300)',
|
|
376
|
-
color: 'var(--ds-gray-900)',
|
|
377
|
-
backgroundColor: 'var(--ds-background-100)',
|
|
378
|
-
}}
|
|
379
|
-
>
|
|
380
|
-
{resourceLabel}
|
|
381
|
-
</span>
|
|
382
|
-
<span
|
|
383
|
-
className="text-[13px]"
|
|
384
|
-
style={{
|
|
385
|
-
color: run.completedAt
|
|
386
|
-
? 'var(--ds-gray-700)'
|
|
387
|
-
: 'var(--ds-green-800)',
|
|
388
|
-
}}
|
|
389
|
-
>
|
|
390
|
-
{runStateLabel}
|
|
391
|
-
</span>
|
|
392
|
-
</div>
|
|
393
|
-
<p
|
|
394
|
-
className="mt-1 truncate font-mono text-[13px]"
|
|
395
|
-
style={{ color: 'var(--ds-gray-700)' }}
|
|
396
|
-
title={resourceId}
|
|
397
|
-
>
|
|
398
|
-
{resourceId}
|
|
399
|
-
</p>
|
|
400
|
-
</div>
|
|
401
|
-
{(hasEncryptedFields || hasEncryptedData || encryptionKey) &&
|
|
402
|
-
onDecrypt && (
|
|
403
|
-
<DecryptButton
|
|
404
|
-
decrypted={!!encryptionKey}
|
|
405
|
-
loading={isDecrypting}
|
|
406
|
-
onClick={onDecrypt}
|
|
407
|
-
/>
|
|
408
|
-
)}
|
|
409
|
-
</div>
|
|
410
|
-
</div>
|
|
411
|
-
|
|
412
364
|
<DecryptClickContext.Provider
|
|
413
|
-
value={
|
|
365
|
+
value={
|
|
366
|
+
onDecrypt ? { onDecrypt, isDecrypting, hasEncryptedData } : undefined
|
|
367
|
+
}
|
|
414
368
|
>
|
|
415
|
-
<div className="flex-1 overflow-y-auto px-
|
|
369
|
+
<div className="flex-1 overflow-y-auto px-4 pb-8">
|
|
416
370
|
{hasPendingActions && (
|
|
417
371
|
<div
|
|
418
372
|
className="mb-4 rounded-lg border p-2"
|
|
@@ -477,38 +431,28 @@ export function EntityDetailPanel({
|
|
|
477
431
|
</div>
|
|
478
432
|
)}
|
|
479
433
|
|
|
480
|
-
<
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
{resource !== 'run' && rawEvents && (
|
|
503
|
-
<section>
|
|
504
|
-
<EventsList
|
|
505
|
-
events={rawEvents}
|
|
506
|
-
onLoadEventData={onLoadEventData}
|
|
507
|
-
encryptionKey={encryptionKey}
|
|
508
|
-
/>
|
|
509
|
-
</section>
|
|
510
|
-
)}
|
|
511
|
-
</div>
|
|
434
|
+
<AttributePanel
|
|
435
|
+
data={displayData}
|
|
436
|
+
moduleSpecifier={moduleSpecifier}
|
|
437
|
+
expiredAt={run.expiredAt}
|
|
438
|
+
isLoading={loading}
|
|
439
|
+
error={error ?? undefined}
|
|
440
|
+
onStreamClick={onStreamClick}
|
|
441
|
+
onRunClick={onRunClick}
|
|
442
|
+
onDecrypt={onDecrypt}
|
|
443
|
+
isDecrypting={isDecrypting}
|
|
444
|
+
resource={resource}
|
|
445
|
+
/>
|
|
446
|
+
|
|
447
|
+
{rawEvents && (
|
|
448
|
+
<EventsList
|
|
449
|
+
events={rawEvents}
|
|
450
|
+
onLoadEventData={onLoadEventData}
|
|
451
|
+
onStreamClick={onStreamClick}
|
|
452
|
+
onRunClick={onRunClick}
|
|
453
|
+
encryptionKey={encryptionKey}
|
|
454
|
+
/>
|
|
455
|
+
)}
|
|
512
456
|
</div>
|
|
513
457
|
</DecryptClickContext.Provider>
|
|
514
458
|
|
|
@@ -1,16 +1,14 @@
|
|
|
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
|
+
import { RunClickContext, StreamClickContext } from '../ui/data-inspector';
|
|
6
7
|
import { ErrorCard } from '../ui/error-card';
|
|
7
|
-
import {
|
|
8
|
-
ErrorStackBlock,
|
|
9
|
-
isStructuredErrorWithStack,
|
|
10
|
-
} from '../ui/error-stack-block';
|
|
8
|
+
import { ErrorStackBlock, isStructuredError } from '../ui/error-stack-block';
|
|
11
9
|
import { Skeleton } from '../ui/skeleton';
|
|
12
|
-
import {
|
|
13
|
-
import { CopyableDataBlock } from './copyable-data-block';
|
|
10
|
+
import { AttrSetEventBlock } from './attributes-block';
|
|
11
|
+
import { CopyableDataBlock, EncryptedDataBlock } from './copyable-data-block';
|
|
14
12
|
import { DetailCard } from './detail-card';
|
|
15
13
|
|
|
16
14
|
/**
|
|
@@ -33,6 +31,7 @@ const DATA_EVENT_TYPES = new Set([
|
|
|
33
31
|
'run_failed',
|
|
34
32
|
'wait_created',
|
|
35
33
|
'wait_completed',
|
|
34
|
+
'attr_set',
|
|
36
35
|
]);
|
|
37
36
|
|
|
38
37
|
/**
|
|
@@ -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,44 +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 className="text-[14px]" style={{ color: 'var(--ds-gray-700)' }}>
|
|
146
|
-
eventId
|
|
147
|
-
</span>
|
|
148
|
-
<span
|
|
149
|
-
className="max-w-[70%] truncate text-right text-[13px] font-mono"
|
|
150
|
-
style={{ color: 'var(--ds-gray-1000)' }}
|
|
151
|
-
title={event.eventId}
|
|
152
|
-
>
|
|
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">
|
|
153
139
|
{event.eventId}
|
|
154
140
|
</span>
|
|
155
141
|
</div>
|
|
156
142
|
{event.correlationId && (
|
|
157
|
-
<div
|
|
158
|
-
className="
|
|
159
|
-
|
|
160
|
-
>
|
|
161
|
-
<span
|
|
162
|
-
className="text-[14px]"
|
|
163
|
-
style={{ color: 'var(--ds-gray-700)' }}
|
|
164
|
-
>
|
|
165
|
-
correlationId
|
|
166
|
-
</span>
|
|
167
|
-
<span
|
|
168
|
-
className="max-w-[70%] truncate text-right text-[13px] font-mono"
|
|
169
|
-
style={{ color: 'var(--ds-gray-1000)' }}
|
|
170
|
-
title={event.correlationId}
|
|
171
|
-
>
|
|
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">
|
|
172
146
|
{event.correlationId}
|
|
173
147
|
</span>
|
|
174
148
|
</div>
|
|
@@ -177,12 +151,7 @@ function EventItem({
|
|
|
177
151
|
|
|
178
152
|
{/* Loading state */}
|
|
179
153
|
{isLoading && (
|
|
180
|
-
<div
|
|
181
|
-
className="mt-2 rounded-md border p-3"
|
|
182
|
-
style={{
|
|
183
|
-
borderColor: 'var(--ds-gray-300)',
|
|
184
|
-
}}
|
|
185
|
-
>
|
|
154
|
+
<div className="p-3">
|
|
186
155
|
<Skeleton className="h-4 w-[35%]" />
|
|
187
156
|
<Skeleton className="mt-2 h-4 w-[90%]" />
|
|
188
157
|
<Skeleton className="mt-2 h-4 w-[75%]" />
|
|
@@ -200,7 +169,7 @@ function EventItem({
|
|
|
200
169
|
|
|
201
170
|
{/* Event data */}
|
|
202
171
|
{displayPayload != null && (
|
|
203
|
-
<div className="
|
|
172
|
+
<div className="[&>div]:border-none [&>div]:rounded-none">
|
|
204
173
|
<EventDataBlock eventType={event.eventType} data={displayPayload} />
|
|
205
174
|
</div>
|
|
206
175
|
)}
|
|
@@ -227,8 +196,8 @@ function hasOnlyExpiredFields(data: unknown, eventType: string): boolean {
|
|
|
227
196
|
}
|
|
228
197
|
|
|
229
198
|
/**
|
|
230
|
-
* Renders event data, using ErrorStackBlock for error events that contain
|
|
231
|
-
*
|
|
199
|
+
* Renders event data, using ErrorStackBlock for error events that contain a
|
|
200
|
+
* structured error, and CopyableDataBlock otherwise.
|
|
232
201
|
*/
|
|
233
202
|
function EventDataBlock({
|
|
234
203
|
eventType,
|
|
@@ -255,6 +224,16 @@ function EventDataBlock({
|
|
|
255
224
|
);
|
|
256
225
|
}
|
|
257
226
|
|
|
227
|
+
if (hasEncryptedFields({ eventType, eventData: data })) {
|
|
228
|
+
return <EncryptedDataBlock />;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// Attribute changes — render the changed keys and the writer instead of
|
|
232
|
+
// the raw JSON payload.
|
|
233
|
+
if (eventType === 'attr_set') {
|
|
234
|
+
return <AttrSetEventBlock data={data} />;
|
|
235
|
+
}
|
|
236
|
+
|
|
258
237
|
// For error events (step_failed, step_retrying), the eventData has the shape
|
|
259
238
|
// { error: StructuredError, stack?: string, ... }. Check both the top-level
|
|
260
239
|
// value and the nested `error` field for a stack trace.
|
|
@@ -266,12 +245,12 @@ function EventDataBlock({
|
|
|
266
245
|
const record = data as Record<string, unknown>;
|
|
267
246
|
|
|
268
247
|
// Check the nested `error` field first (the StructuredError)
|
|
269
|
-
if (
|
|
248
|
+
if (isStructuredError(record.error)) {
|
|
270
249
|
return <ErrorStackBlock value={record.error} />;
|
|
271
250
|
}
|
|
272
251
|
|
|
273
|
-
// Some error formats put the stack at the top level of eventData
|
|
274
|
-
if (
|
|
252
|
+
// Some error formats put the message/stack at the top level of eventData.
|
|
253
|
+
if (isStructuredError(record)) {
|
|
275
254
|
return <ErrorStackBlock value={record} />;
|
|
276
255
|
}
|
|
277
256
|
}
|
|
@@ -286,6 +265,8 @@ export function EventsList({
|
|
|
286
265
|
isLoading = false,
|
|
287
266
|
error,
|
|
288
267
|
onLoadEventData,
|
|
268
|
+
onStreamClick,
|
|
269
|
+
onRunClick,
|
|
289
270
|
encryptionKey,
|
|
290
271
|
}: {
|
|
291
272
|
events: Event[];
|
|
@@ -295,6 +276,8 @@ export function EventsList({
|
|
|
295
276
|
correlationId: string,
|
|
296
277
|
eventId: string
|
|
297
278
|
) => Promise<unknown | null>;
|
|
279
|
+
onStreamClick?: (streamId: string) => void;
|
|
280
|
+
onRunClick?: (runId: string) => void;
|
|
298
281
|
/** When provided, signals that decryption is active (triggers re-load of expanded events) */
|
|
299
282
|
encryptionKey?: Uint8Array;
|
|
300
283
|
}) {
|
|
@@ -308,36 +291,42 @@ export function EventsList({
|
|
|
308
291
|
[events]
|
|
309
292
|
);
|
|
310
293
|
|
|
294
|
+
const hasEvents = sortedEvents.length > 0 && !error;
|
|
295
|
+
|
|
296
|
+
if (!hasEvents && !isLoading) {
|
|
297
|
+
return <DetailCard summary="Events" disabled />;
|
|
298
|
+
}
|
|
299
|
+
|
|
311
300
|
return (
|
|
312
|
-
<
|
|
313
|
-
<
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
)
|
|
339
|
-
</
|
|
340
|
-
|
|
341
|
-
</
|
|
301
|
+
<RunClickContext.Provider value={onRunClick}>
|
|
302
|
+
<StreamClickContext.Provider value={onStreamClick}>
|
|
303
|
+
<DetailCard summary="Events" contentClassName="mb-0" defaultOpen>
|
|
304
|
+
{isLoading ? (
|
|
305
|
+
<div className="flex flex-col -mx-4">
|
|
306
|
+
{[0, 1, 2].map((i) => (
|
|
307
|
+
<div
|
|
308
|
+
key={i}
|
|
309
|
+
className="flex items-center justify-between gap-3 bg-background-200 px-4 py-2"
|
|
310
|
+
>
|
|
311
|
+
<Skeleton className="h-4 w-32 rounded" />
|
|
312
|
+
<Skeleton className="h-3 w-16 rounded" />
|
|
313
|
+
</div>
|
|
314
|
+
))}
|
|
315
|
+
</div>
|
|
316
|
+
) : (
|
|
317
|
+
<div className="flex flex-col -mx-4">
|
|
318
|
+
{sortedEvents.map((event) => (
|
|
319
|
+
<EventItem
|
|
320
|
+
key={event.eventId}
|
|
321
|
+
event={event}
|
|
322
|
+
onLoadEventData={onLoadEventData}
|
|
323
|
+
encryptionKey={encryptionKey}
|
|
324
|
+
/>
|
|
325
|
+
))}
|
|
326
|
+
</div>
|
|
327
|
+
)}
|
|
328
|
+
</DetailCard>
|
|
329
|
+
</StreamClickContext.Provider>
|
|
330
|
+
</RunClickContext.Provider>
|
|
342
331
|
);
|
|
343
332
|
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { createContext, useContext, type ReactNode } from 'react';
|
|
4
|
+
import type { Event, Hook, Step, WorkflowRun } from '@workflow/world';
|
|
5
|
+
import type { SpanSelectionInfo } from './entity-detail-panel';
|
|
6
|
+
|
|
7
|
+
export interface SidebarDataContextValue {
|
|
8
|
+
run: WorkflowRun;
|
|
9
|
+
events: Event[];
|
|
10
|
+
spanDetailData: WorkflowRun | Step | Hook | Event | null;
|
|
11
|
+
spanDetailError?: Error | null;
|
|
12
|
+
spanDetailLoading?: boolean;
|
|
13
|
+
onSpanSelect: (info: SpanSelectionInfo) => void;
|
|
14
|
+
onStreamClick?: (streamId: string) => void;
|
|
15
|
+
onRunClick?: (runId: string) => void;
|
|
16
|
+
onWakeUpSleep?: (
|
|
17
|
+
runId: string,
|
|
18
|
+
correlationId: string
|
|
19
|
+
) => Promise<{ stoppedCount: number }>;
|
|
20
|
+
onLoadEventData?: (
|
|
21
|
+
correlationId: string,
|
|
22
|
+
eventId: string
|
|
23
|
+
) => Promise<unknown | null>;
|
|
24
|
+
onResolveHook?: (
|
|
25
|
+
hookToken: string,
|
|
26
|
+
payload: unknown,
|
|
27
|
+
hook?: Hook
|
|
28
|
+
) => Promise<void>;
|
|
29
|
+
encryptionKey?: Uint8Array;
|
|
30
|
+
onDecrypt?: () => void;
|
|
31
|
+
isDecrypting?: boolean;
|
|
32
|
+
hasEncryptedData?: boolean;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const SidebarDataContext = createContext<SidebarDataContextValue | null>(null);
|
|
36
|
+
SidebarDataContext.displayName = 'SidebarDataContext';
|
|
37
|
+
|
|
38
|
+
export function SidebarDataProvider({
|
|
39
|
+
value,
|
|
40
|
+
children,
|
|
41
|
+
}: {
|
|
42
|
+
value: SidebarDataContextValue;
|
|
43
|
+
children: ReactNode;
|
|
44
|
+
}) {
|
|
45
|
+
return (
|
|
46
|
+
<SidebarDataContext.Provider value={value}>
|
|
47
|
+
{children}
|
|
48
|
+
</SidebarDataContext.Provider>
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function useSidebarData(): SidebarDataContextValue {
|
|
53
|
+
const ctx = useContext(SidebarDataContext);
|
|
54
|
+
if (!ctx) {
|
|
55
|
+
throw new Error('useSidebarData must be used within a SidebarDataProvider');
|
|
56
|
+
}
|
|
57
|
+
return ctx;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function useSidebarDataOptional(): SidebarDataContextValue | null {
|
|
61
|
+
return useContext(SidebarDataContext);
|
|
62
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
const hasField = (
|
|
2
|
+
value: object,
|
|
3
|
+
key: string
|
|
4
|
+
): value is Record<string, unknown> => key in value;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Returns true when the fetched `detail` belongs to the current selection.
|
|
8
|
+
* The fetch lags selection, so it can briefly hold a previously selected span
|
|
9
|
+
* (even a different resource type); reject it before merging or its fields
|
|
10
|
+
* union into the wrong panel. Steps/hooks/waits carry their parent `runId`, so
|
|
11
|
+
* a `run` selection excludes objects identifiable as a child resource.
|
|
12
|
+
*/
|
|
13
|
+
export function spanDetailMatchesSelection(
|
|
14
|
+
detail: unknown,
|
|
15
|
+
resource: string | undefined,
|
|
16
|
+
resourceId: string | undefined
|
|
17
|
+
): boolean {
|
|
18
|
+
if (!detail || typeof detail !== 'object' || !resource || !resourceId) {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
switch (resource) {
|
|
22
|
+
case 'step':
|
|
23
|
+
return hasField(detail, 'stepId') && detail.stepId === resourceId;
|
|
24
|
+
case 'hook':
|
|
25
|
+
return hasField(detail, 'hookId') && detail.hookId === resourceId;
|
|
26
|
+
case 'sleep':
|
|
27
|
+
return hasField(detail, 'waitId') && detail.waitId === resourceId;
|
|
28
|
+
case 'run':
|
|
29
|
+
return (
|
|
30
|
+
hasField(detail, 'runId') &&
|
|
31
|
+
!('stepId' in detail) &&
|
|
32
|
+
!('hookId' in detail) &&
|
|
33
|
+
!('waitId' in detail) &&
|
|
34
|
+
detail.runId === resourceId
|
|
35
|
+
);
|
|
36
|
+
default:
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Merges fetched `detail` over the span's own data. The detail supplies the
|
|
43
|
+
* heavy fields the trace strips (input/output/error/metadata, sleep resumeAt);
|
|
44
|
+
* the span's identity, status, and event-derived timestamps stay authoritative
|
|
45
|
+
* so they don't flicker to the backend row's millisecond-different values.
|
|
46
|
+
*/
|
|
47
|
+
export function mergeSpanDetail(spanData: unknown, detail: unknown): unknown {
|
|
48
|
+
if (!detail || typeof detail !== 'object') {
|
|
49
|
+
return spanData;
|
|
50
|
+
}
|
|
51
|
+
if (!spanData || typeof spanData !== 'object') {
|
|
52
|
+
return detail;
|
|
53
|
+
}
|
|
54
|
+
// Skip `undefined` span fields so they don't clobber a value the detail
|
|
55
|
+
// legitimately provides (e.g. a step's optional startedAt).
|
|
56
|
+
const merged: Record<string, unknown> = { ...detail };
|
|
57
|
+
for (const [key, value] of Object.entries(
|
|
58
|
+
spanData as Record<string, unknown>
|
|
59
|
+
)) {
|
|
60
|
+
if (value !== undefined) {
|
|
61
|
+
merged[key] = value;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return merged;
|
|
65
|
+
}
|