@workflow/web-shared 5.0.0-beta.1 → 5.0.0-beta.3
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/README.md +1 -1
- package/dist/components/error-boundary.js.map +1 -1
- package/dist/components/event-list-view.d.ts +3 -1
- package/dist/components/event-list-view.d.ts.map +1 -1
- package/dist/components/event-list-view.js +53 -53
- package/dist/components/event-list-view.js.map +1 -1
- package/dist/components/hook-actions.js.map +1 -1
- package/dist/components/index.d.ts +3 -1
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +3 -1
- package/dist/components/index.js.map +1 -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/copy-button.js.map +1 -0
- package/dist/components/new-trace-viewer/components/event-list.d.ts +8 -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 +35 -0
- package/dist/components/new-trace-viewer/components/event-list.js.map +1 -0
- package/dist/components/new-trace-viewer/components/split-pane.d.ts +14 -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 +100 -0
- package/dist/components/new-trace-viewer/components/split-pane.js.map +1 -0
- package/dist/components/new-trace-viewer/components/timeline.d.ts +32 -0
- package/dist/components/new-trace-viewer/components/timeline.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/components/timeline.js +134 -0
- package/dist/components/new-trace-viewer/components/timeline.js.map +1 -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 +49 -0
- package/dist/components/new-trace-viewer/context.js.map +1 -0
- package/dist/components/new-trace-viewer/detail-panel.d.ts +10 -0
- package/dist/components/new-trace-viewer/detail-panel.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/detail-panel.js +11 -0
- package/dist/components/new-trace-viewer/detail-panel.js.map +1 -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/icons.js.map +1 -0
- package/dist/components/new-trace-viewer/trace-viewer.d.ts +8 -0
- package/dist/components/new-trace-viewer/trace-viewer.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/trace-viewer.js +329 -0
- package/dist/components/new-trace-viewer/trace-viewer.js.map +1 -0
- package/dist/components/new-trace-viewer/types.d.ts +1 -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/types.js.map +1 -0
- package/dist/components/new-trace-viewer/util/constants.d.ts +1 -0
- package/dist/components/new-trace-viewer/util/constants.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/util/constants.js +2 -0
- package/dist/components/new-trace-viewer/util/constants.js.map +1 -0
- package/dist/components/new-trace-viewer/utils.d.ts +47 -0
- package/dist/components/new-trace-viewer/utils.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/utils.js +358 -0
- package/dist/components/new-trace-viewer/utils.js.map +1 -0
- package/dist/components/run-trace-view.d.ts +2 -1
- package/dist/components/run-trace-view.d.ts.map +1 -1
- package/dist/components/run-trace-view.js +2 -2
- package/dist/components/run-trace-view.js.map +1 -1
- package/dist/components/sidebar/attribute-panel.d.ts +7 -1
- package/dist/components/sidebar/attribute-panel.d.ts.map +1 -1
- package/dist/components/sidebar/attribute-panel.js +76 -47
- package/dist/components/sidebar/attribute-panel.js.map +1 -1
- package/dist/components/sidebar/conversation-view.js.map +1 -1
- package/dist/components/sidebar/copyable-data-block.js +1 -1
- package/dist/components/sidebar/copyable-data-block.js.map +1 -1
- package/dist/components/sidebar/detail-card.d.ts.map +1 -1
- package/dist/components/sidebar/detail-card.js +1 -1
- package/dist/components/sidebar/detail-card.js.map +1 -1
- package/dist/components/sidebar/entity-detail-panel.d.ts +3 -1
- package/dist/components/sidebar/entity-detail-panel.d.ts.map +1 -1
- package/dist/components/sidebar/entity-detail-panel.js +16 -36
- package/dist/components/sidebar/entity-detail-panel.js.map +1 -1
- package/dist/components/sidebar/events-list.d.ts.map +1 -1
- package/dist/components/sidebar/events-list.js +2 -2
- package/dist/components/sidebar/events-list.js.map +1 -1
- package/dist/components/sidebar/resolve-hook-modal.js.map +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/sidebar-data-context.js.map +1 -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 +2 -26
- package/dist/components/stream-viewer.js.map +1 -1
- package/dist/components/trace-viewer/components/map.js.map +1 -1
- package/dist/components/trace-viewer/components/markers.js.map +1 -1
- package/dist/components/trace-viewer/components/node.js.map +1 -1
- package/dist/components/trace-viewer/components/search-input.js.map +1 -1
- package/dist/components/trace-viewer/components/search.js.map +1 -1
- package/dist/components/trace-viewer/components/span-content.js.map +1 -1
- package/dist/components/trace-viewer/components/span-detail-panel.js.map +1 -1
- package/dist/components/trace-viewer/components/span-segments.js.map +1 -1
- package/dist/components/trace-viewer/components/span-strategies.js.map +1 -1
- package/dist/components/trace-viewer/components/ui.js.map +1 -1
- package/dist/components/trace-viewer/components/zoom-button.js.map +1 -1
- package/dist/components/trace-viewer/components/zoom-icons.js.map +1 -1
- package/dist/components/trace-viewer/context.js.map +1 -1
- package/dist/components/trace-viewer/index.js.map +1 -1
- package/dist/components/trace-viewer/trace-viewer.js.map +1 -1
- package/dist/components/trace-viewer/types.js.map +1 -1
- package/dist/components/trace-viewer/util/constants.js.map +1 -1
- package/dist/components/trace-viewer/util/scrollbar-width.js.map +1 -1
- package/dist/components/trace-viewer/util/timing.js.map +1 -1
- package/dist/components/trace-viewer/util/tree.js.map +1 -1
- package/dist/components/trace-viewer/util/use-immediate-style.js.map +1 -1
- package/dist/components/trace-viewer/util/use-streaming-spans.js.map +1 -1
- package/dist/components/trace-viewer/util/use-trackpad-zoom.js.map +1 -1
- package/dist/components/trace-viewer/worker.js.map +1 -1
- package/dist/components/trace-viewer-new.d.ts +10 -0
- package/dist/components/trace-viewer-new.d.ts.map +1 -0
- package/dist/components/trace-viewer-new.js +23 -0
- package/dist/components/trace-viewer-new.js.map +1 -0
- package/dist/components/ui/alert.js.map +1 -1
- package/dist/components/ui/card.js.map +1 -1
- package/dist/components/ui/data-inspector.d.ts +38 -1
- package/dist/components/ui/data-inspector.d.ts.map +1 -1
- package/dist/components/ui/data-inspector.js +211 -21
- package/dist/components/ui/data-inspector.js.map +1 -1
- package/dist/components/ui/decrypt-button.js.map +1 -1
- package/dist/components/ui/error-card.js.map +1 -1
- package/dist/components/ui/error-stack-block.js.map +1 -1
- 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 +38 -71
- package/dist/components/ui/inspector-theme.js.map +1 -1
- package/dist/components/ui/load-more-button.js.map +1 -1
- package/dist/components/ui/menu-dropdown.js.map +1 -1
- package/dist/components/ui/skeleton.js.map +1 -1
- package/dist/components/ui/spinner.js.map +1 -1
- package/dist/components/ui/timestamp-tooltip.js.map +1 -1
- package/dist/components/workflow-trace-view.d.ts +3 -1
- package/dist/components/workflow-trace-view.d.ts.map +1 -1
- package/dist/components/workflow-trace-view.js +9 -4
- package/dist/components/workflow-trace-view.js.map +1 -1
- package/dist/components/workflow-traces/event-colors.js.map +1 -1
- package/dist/components/workflow-traces/trace-colors.js.map +1 -1
- package/dist/components/workflow-traces/trace-span-construction.js +1 -1
- package/dist/components/workflow-traces/trace-span-construction.js.map +1 -1
- package/dist/components/workflow-traces/trace-time-utils.js.map +1 -1
- package/dist/hooks/use-dark-mode.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/event-analysis.js.map +1 -1
- package/dist/lib/event-materialization.js.map +1 -1
- package/dist/lib/hydration.d.ts +8 -1
- package/dist/lib/hydration.d.ts.map +1 -1
- package/dist/lib/hydration.js +32 -2
- package/dist/lib/hydration.js.map +1 -1
- 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/stream-display.js.map +1 -0
- package/dist/lib/toast.js.map +1 -1
- package/dist/lib/trace-builder.js.map +1 -1
- package/dist/lib/utils.d.ts +7 -9
- package/dist/lib/utils.d.ts.map +1 -1
- package/dist/lib/utils.js +17 -22
- package/dist/lib/utils.js.map +1 -1
- package/dist/styles.css +470 -1
- package/package.json +4 -3
- package/src/components/event-list-view.tsx +181 -173
- package/src/components/index.ts +11 -1
- package/src/components/new-trace-viewer/components/copy-button.tsx +68 -0
- package/src/components/new-trace-viewer/components/event-list.tsx +109 -0
- package/src/components/new-trace-viewer/components/split-pane.tsx +186 -0
- package/src/components/new-trace-viewer/components/timeline.tsx +378 -0
- package/src/components/new-trace-viewer/context.tsx +94 -0
- package/src/components/new-trace-viewer/detail-panel.tsx +57 -0
- package/src/components/new-trace-viewer/icons.tsx +79 -0
- package/src/components/new-trace-viewer/trace-viewer.tsx +585 -0
- package/src/components/new-trace-viewer/types.ts +0 -0
- package/src/components/new-trace-viewer/util/constants.ts +0 -0
- package/src/components/new-trace-viewer/utils.ts +524 -0
- package/src/components/run-trace-view.tsx +3 -0
- package/src/components/sidebar/attribute-panel.tsx +200 -138
- package/src/components/sidebar/copyable-data-block.tsx +1 -1
- package/src/components/sidebar/detail-card.tsx +1 -19
- package/src/components/sidebar/entity-detail-panel.tsx +91 -147
- package/src/components/sidebar/events-list.tsx +9 -6
- package/src/components/sidebar/sidebar-data-context.tsx +62 -0
- package/src/components/stream-viewer.tsx +18 -40
- package/src/components/trace-viewer-new.tsx +49 -0
- package/src/components/ui/data-inspector.tsx +436 -31
- package/src/components/ui/inspector-theme.ts +39 -81
- package/src/components/workflow-trace-view.tsx +12 -2
- package/src/components/workflow-traces/trace-span-construction.ts +1 -1
- package/src/index.ts +2 -0
- package/src/lib/hydration.ts +37 -0
- package/src/lib/stream-display.ts +48 -0
- package/src/lib/utils.ts +18 -23
- package/src/styles.css +470 -1
|
@@ -5,8 +5,7 @@ import clsx from 'clsx';
|
|
|
5
5
|
import { Send, Zap } from 'lucide-react';
|
|
6
6
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
7
7
|
import { useToast } from '../../lib/toast';
|
|
8
|
-
import {
|
|
9
|
-
import { DecryptButton } from '../ui/decrypt-button';
|
|
8
|
+
import { DecryptClickContext } from '../ui/data-inspector';
|
|
10
9
|
import { AttributePanel } from './attribute-panel';
|
|
11
10
|
import { EventsList } from './events-list';
|
|
12
11
|
import { ResolveHookModal } from './resolve-hook-modal';
|
|
@@ -56,6 +55,7 @@ export interface SelectedSpanInfo {
|
|
|
56
55
|
export function EntityDetailPanel({
|
|
57
56
|
run,
|
|
58
57
|
onStreamClick,
|
|
58
|
+
onRunClick,
|
|
59
59
|
spanDetailData,
|
|
60
60
|
spanDetailError,
|
|
61
61
|
spanDetailLoading,
|
|
@@ -71,6 +71,8 @@ export function EntityDetailPanel({
|
|
|
71
71
|
run: WorkflowRun;
|
|
72
72
|
/** Callback when a stream reference is clicked */
|
|
73
73
|
onStreamClick?: (streamId: string) => void;
|
|
74
|
+
/** Callback when a run reference is clicked */
|
|
75
|
+
onRunClick?: (runId: string) => void;
|
|
74
76
|
/** Pre-fetched span detail data for the selected span. */
|
|
75
77
|
spanDetailData: WorkflowRun | Step | Hook | Event | null;
|
|
76
78
|
/** Error from external span detail fetch. */
|
|
@@ -209,17 +211,6 @@ export function EntityDetailPanel({
|
|
|
209
211
|
const error = spanDetailError ?? undefined;
|
|
210
212
|
const loading = spanDetailLoading ?? false;
|
|
211
213
|
|
|
212
|
-
const hasEncryptedFields = useMemo(() => {
|
|
213
|
-
if (!spanDetailData) return false;
|
|
214
|
-
const d = spanDetailData as Record<string, unknown>;
|
|
215
|
-
return (
|
|
216
|
-
isEncryptedMarker(d.input) ||
|
|
217
|
-
isEncryptedMarker(d.output) ||
|
|
218
|
-
isEncryptedMarker(d.error) ||
|
|
219
|
-
isEncryptedMarker(d.metadata)
|
|
220
|
-
);
|
|
221
|
-
}, [spanDetailData]);
|
|
222
|
-
|
|
223
214
|
// Get the hook token for resolving (prefer fetched data, then hooks array fallback)
|
|
224
215
|
const hookToken = useMemo(() => {
|
|
225
216
|
if (resource !== 'hook' || !resourceId) return undefined;
|
|
@@ -347,155 +338,108 @@ export function EntityDetailPanel({
|
|
|
347
338
|
return null;
|
|
348
339
|
}
|
|
349
340
|
|
|
350
|
-
const resourceLabel = resource.charAt(0).toUpperCase() + resource.slice(1);
|
|
351
341
|
const hasPendingActions =
|
|
352
342
|
(resource === 'sleep' && canWakeUp) ||
|
|
353
343
|
(resource === 'hook' && canResolveHook);
|
|
354
|
-
const runStateLabel = run.completedAt ? 'Completed' : 'Live';
|
|
355
344
|
|
|
356
345
|
return (
|
|
357
346
|
<div className="flex h-full flex-col">
|
|
358
|
-
<
|
|
359
|
-
|
|
360
|
-
style={{ borderColor: 'var(--ds-gray-200)' }}
|
|
347
|
+
<DecryptClickContext.Provider
|
|
348
|
+
value={onDecrypt ? { onDecrypt, isDecrypting } : undefined}
|
|
361
349
|
>
|
|
362
|
-
<div className="flex
|
|
363
|
-
|
|
364
|
-
<div
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
{
|
|
374
|
-
</span>
|
|
375
|
-
<span
|
|
376
|
-
className="text-[13px]"
|
|
377
|
-
style={{
|
|
378
|
-
color: run.completedAt
|
|
379
|
-
? 'var(--ds-gray-700)'
|
|
380
|
-
: 'var(--ds-green-800)',
|
|
381
|
-
}}
|
|
350
|
+
<div className="flex-1 overflow-y-auto px-3 pt-3 pb-8">
|
|
351
|
+
{hasPendingActions && (
|
|
352
|
+
<div
|
|
353
|
+
className="mb-4 rounded-lg border p-2"
|
|
354
|
+
style={{
|
|
355
|
+
borderColor: 'var(--ds-gray-300)',
|
|
356
|
+
backgroundColor: 'var(--ds-gray-100)',
|
|
357
|
+
}}
|
|
358
|
+
>
|
|
359
|
+
<p
|
|
360
|
+
className="mb-2 px-1 text-[13px] font-medium uppercase tracking-wide"
|
|
361
|
+
style={{ color: 'var(--ds-gray-700)' }}
|
|
382
362
|
>
|
|
383
|
-
|
|
384
|
-
</
|
|
363
|
+
Actions
|
|
364
|
+
</p>
|
|
365
|
+
<div className="flex flex-col gap-2">
|
|
366
|
+
{/* Wake up button for pending sleep calls */}
|
|
367
|
+
{resource === 'sleep' && canWakeUp && (
|
|
368
|
+
<button
|
|
369
|
+
type="button"
|
|
370
|
+
onClick={handleWakeUp}
|
|
371
|
+
disabled={stoppingSleep}
|
|
372
|
+
className={clsx(
|
|
373
|
+
'flex items-center justify-center gap-2 rounded-md px-3 py-2 text-sm font-medium',
|
|
374
|
+
'disabled:opacity-50 disabled:cursor-not-allowed transition-colors',
|
|
375
|
+
stoppingSleep
|
|
376
|
+
? 'opacity-50 cursor-not-allowed'
|
|
377
|
+
: 'cursor-pointer'
|
|
378
|
+
)}
|
|
379
|
+
style={{
|
|
380
|
+
background: 'var(--ds-amber-200)',
|
|
381
|
+
color: 'var(--ds-amber-900)',
|
|
382
|
+
}}
|
|
383
|
+
>
|
|
384
|
+
<Zap className="h-4 w-4" />
|
|
385
|
+
{stoppingSleep ? 'Waking up...' : 'Wake Up Sleep'}
|
|
386
|
+
</button>
|
|
387
|
+
)}
|
|
388
|
+
|
|
389
|
+
{/* Resolve hook button for pending hooks */}
|
|
390
|
+
{resource === 'hook' && canResolveHook && (
|
|
391
|
+
<button
|
|
392
|
+
type="button"
|
|
393
|
+
onClick={() => setShowResolveHookModal(true)}
|
|
394
|
+
disabled={resolvingHook}
|
|
395
|
+
className={clsx(
|
|
396
|
+
'flex items-center justify-center gap-2 rounded-md px-3 py-2 text-sm font-medium',
|
|
397
|
+
'disabled:opacity-50 disabled:cursor-not-allowed transition-colors',
|
|
398
|
+
resolvingHook
|
|
399
|
+
? 'opacity-50 cursor-not-allowed'
|
|
400
|
+
: 'cursor-pointer'
|
|
401
|
+
)}
|
|
402
|
+
style={{
|
|
403
|
+
background: 'var(--ds-gray-1000)',
|
|
404
|
+
color: 'var(--ds-background-100)',
|
|
405
|
+
}}
|
|
406
|
+
>
|
|
407
|
+
<Send className="h-4 w-4" />
|
|
408
|
+
Resolve Hook
|
|
409
|
+
</button>
|
|
410
|
+
)}
|
|
411
|
+
</div>
|
|
385
412
|
</div>
|
|
386
|
-
<p
|
|
387
|
-
className="mt-1 truncate font-mono text-[13px]"
|
|
388
|
-
style={{ color: 'var(--ds-gray-700)' }}
|
|
389
|
-
title={resourceId}
|
|
390
|
-
>
|
|
391
|
-
{resourceId}
|
|
392
|
-
</p>
|
|
393
|
-
</div>
|
|
394
|
-
{(hasEncryptedFields || encryptionKey) && onDecrypt && (
|
|
395
|
-
<DecryptButton
|
|
396
|
-
decrypted={!!encryptionKey}
|
|
397
|
-
loading={isDecrypting}
|
|
398
|
-
onClick={onDecrypt}
|
|
399
|
-
/>
|
|
400
413
|
)}
|
|
401
|
-
</div>
|
|
402
|
-
</div>
|
|
403
|
-
|
|
404
|
-
<div className="flex-1 overflow-y-auto px-3 pt-3 pb-8">
|
|
405
|
-
{hasPendingActions && (
|
|
406
|
-
<div
|
|
407
|
-
className="mb-4 rounded-lg border p-2"
|
|
408
|
-
style={{
|
|
409
|
-
borderColor: 'var(--ds-gray-300)',
|
|
410
|
-
backgroundColor: 'var(--ds-gray-100)',
|
|
411
|
-
}}
|
|
412
|
-
>
|
|
413
|
-
<p
|
|
414
|
-
className="mb-2 px-1 text-[13px] font-medium uppercase tracking-wide"
|
|
415
|
-
style={{ color: 'var(--ds-gray-700)' }}
|
|
416
|
-
>
|
|
417
|
-
Actions
|
|
418
|
-
</p>
|
|
419
|
-
<div className="flex flex-col gap-2">
|
|
420
|
-
{/* Wake up button for pending sleep calls */}
|
|
421
|
-
{resource === 'sleep' && canWakeUp && (
|
|
422
|
-
<button
|
|
423
|
-
type="button"
|
|
424
|
-
onClick={handleWakeUp}
|
|
425
|
-
disabled={stoppingSleep}
|
|
426
|
-
className={clsx(
|
|
427
|
-
'flex items-center justify-center gap-2 rounded-md px-3 py-2 text-sm font-medium',
|
|
428
|
-
'disabled:opacity-50 disabled:cursor-not-allowed transition-colors',
|
|
429
|
-
stoppingSleep
|
|
430
|
-
? 'opacity-50 cursor-not-allowed'
|
|
431
|
-
: 'cursor-pointer'
|
|
432
|
-
)}
|
|
433
|
-
style={{
|
|
434
|
-
background: 'var(--ds-amber-200)',
|
|
435
|
-
color: 'var(--ds-amber-900)',
|
|
436
|
-
}}
|
|
437
|
-
>
|
|
438
|
-
<Zap className="h-4 w-4" />
|
|
439
|
-
{stoppingSleep ? 'Waking up...' : 'Wake Up Sleep'}
|
|
440
|
-
</button>
|
|
441
|
-
)}
|
|
442
|
-
|
|
443
|
-
{/* Resolve hook button for pending hooks */}
|
|
444
|
-
{resource === 'hook' && canResolveHook && (
|
|
445
|
-
<button
|
|
446
|
-
type="button"
|
|
447
|
-
onClick={() => setShowResolveHookModal(true)}
|
|
448
|
-
disabled={resolvingHook}
|
|
449
|
-
className={clsx(
|
|
450
|
-
'flex items-center justify-center gap-2 rounded-md px-3 py-2 text-sm font-medium',
|
|
451
|
-
'disabled:opacity-50 disabled:cursor-not-allowed transition-colors',
|
|
452
|
-
resolvingHook
|
|
453
|
-
? 'opacity-50 cursor-not-allowed'
|
|
454
|
-
: 'cursor-pointer'
|
|
455
|
-
)}
|
|
456
|
-
style={{
|
|
457
|
-
background: 'var(--ds-gray-1000)',
|
|
458
|
-
color: 'var(--ds-background-100)',
|
|
459
|
-
}}
|
|
460
|
-
>
|
|
461
|
-
<Send className="h-4 w-4" />
|
|
462
|
-
Resolve Hook
|
|
463
|
-
</button>
|
|
464
|
-
)}
|
|
465
|
-
</div>
|
|
466
|
-
</div>
|
|
467
|
-
)}
|
|
468
414
|
|
|
469
|
-
|
|
470
|
-
<section>
|
|
471
|
-
<h3
|
|
472
|
-
className="mb-2 text-[13px] font-medium uppercase tracking-wide"
|
|
473
|
-
style={{ color: 'var(--ds-gray-700)' }}
|
|
474
|
-
>
|
|
475
|
-
Details
|
|
476
|
-
</h3>
|
|
477
|
-
<AttributePanel
|
|
478
|
-
data={displayData}
|
|
479
|
-
moduleSpecifier={moduleSpecifier}
|
|
480
|
-
expiredAt={run.expiredAt}
|
|
481
|
-
isLoading={loading}
|
|
482
|
-
error={error ?? undefined}
|
|
483
|
-
onStreamClick={onStreamClick}
|
|
484
|
-
resource={resource}
|
|
485
|
-
/>
|
|
486
|
-
</section>
|
|
487
|
-
|
|
488
|
-
{resource !== 'run' && rawEvents && (
|
|
415
|
+
<div className="space-y-4">
|
|
489
416
|
<section>
|
|
490
|
-
<
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
417
|
+
<AttributePanel
|
|
418
|
+
data={displayData}
|
|
419
|
+
moduleSpecifier={moduleSpecifier}
|
|
420
|
+
expiredAt={run.expiredAt}
|
|
421
|
+
isLoading={loading}
|
|
422
|
+
error={error ?? undefined}
|
|
423
|
+
onStreamClick={onStreamClick}
|
|
424
|
+
onRunClick={onRunClick}
|
|
425
|
+
onDecrypt={onDecrypt}
|
|
426
|
+
isDecrypting={isDecrypting}
|
|
427
|
+
resource={resource}
|
|
494
428
|
/>
|
|
495
429
|
</section>
|
|
496
|
-
|
|
430
|
+
|
|
431
|
+
{resource !== 'run' && rawEvents && (
|
|
432
|
+
<section>
|
|
433
|
+
<EventsList
|
|
434
|
+
events={rawEvents}
|
|
435
|
+
onLoadEventData={onLoadEventData}
|
|
436
|
+
encryptionKey={encryptionKey}
|
|
437
|
+
/>
|
|
438
|
+
</section>
|
|
439
|
+
)}
|
|
440
|
+
</div>
|
|
497
441
|
</div>
|
|
498
|
-
</
|
|
442
|
+
</DecryptClickContext.Provider>
|
|
499
443
|
|
|
500
444
|
{/* Resolve Hook Modal */}
|
|
501
445
|
<ResolveHookModal
|
|
@@ -142,8 +142,11 @@ function EventItem({
|
|
|
142
142
|
className="flex min-h-[32px] items-center justify-between gap-4 px-2.5 py-1.5"
|
|
143
143
|
style={{ borderColor: 'var(--ds-gray-300)' }}
|
|
144
144
|
>
|
|
145
|
-
<span
|
|
146
|
-
|
|
145
|
+
<span
|
|
146
|
+
className="text-[13px] font-medium"
|
|
147
|
+
style={{ color: 'var(--ds-gray-700)' }}
|
|
148
|
+
>
|
|
149
|
+
Event ID
|
|
147
150
|
</span>
|
|
148
151
|
<span
|
|
149
152
|
className="max-w-[70%] truncate text-right text-[13px] font-mono"
|
|
@@ -159,10 +162,10 @@ function EventItem({
|
|
|
159
162
|
style={{ borderColor: 'var(--ds-gray-300)' }}
|
|
160
163
|
>
|
|
161
164
|
<span
|
|
162
|
-
className="text-[
|
|
165
|
+
className="text-[13px] font-medium"
|
|
163
166
|
style={{ color: 'var(--ds-gray-700)' }}
|
|
164
167
|
>
|
|
165
|
-
|
|
168
|
+
Correlation ID
|
|
166
169
|
</span>
|
|
167
170
|
<span
|
|
168
171
|
className="max-w-[70%] truncate text-right text-[13px] font-mono"
|
|
@@ -311,10 +314,10 @@ export function EventsList({
|
|
|
311
314
|
return (
|
|
312
315
|
<div className="mt-2" style={{ color: 'var(--ds-gray-1000)' }}>
|
|
313
316
|
<h3
|
|
314
|
-
className="text-
|
|
317
|
+
className="text-label-14 font-medium mt-4 mb-2"
|
|
315
318
|
style={{ color: 'var(--ds-gray-1000)' }}
|
|
316
319
|
>
|
|
317
|
-
Events
|
|
320
|
+
Events
|
|
318
321
|
</h3>
|
|
319
322
|
{isLoading ? (
|
|
320
323
|
<div className="flex flex-col gap-4">
|
|
@@ -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
|
+
}
|
|
@@ -5,37 +5,13 @@ import { Virtuoso, type VirtuosoHandle } from 'react-virtuoso';
|
|
|
5
5
|
import { DataInspector } from './ui/data-inspector';
|
|
6
6
|
import { Skeleton } from './ui/skeleton';
|
|
7
7
|
|
|
8
|
-
// ──────────────────────────────────────────────────────────────────────────
|
|
9
|
-
// Helpers
|
|
10
|
-
// ──────────────────────────────────────────────────────────────────────────
|
|
11
|
-
|
|
12
|
-
function deserializeChunkText(text: string): string {
|
|
13
|
-
try {
|
|
14
|
-
const parsed = JSON.parse(text);
|
|
15
|
-
if (typeof parsed === 'string') {
|
|
16
|
-
return parsed;
|
|
17
|
-
}
|
|
18
|
-
return JSON.stringify(parsed, null, 2);
|
|
19
|
-
} catch {
|
|
20
|
-
return text;
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function parseChunkData(text: string): unknown {
|
|
25
|
-
try {
|
|
26
|
-
return JSON.parse(text);
|
|
27
|
-
} catch {
|
|
28
|
-
return text;
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
8
|
// ──────────────────────────────────────────────────────────────────────────
|
|
33
9
|
// Types
|
|
34
10
|
// ──────────────────────────────────────────────────────────────────────────
|
|
35
11
|
|
|
36
12
|
export interface StreamChunk {
|
|
37
13
|
id: number;
|
|
38
|
-
|
|
14
|
+
value: unknown;
|
|
39
15
|
}
|
|
40
16
|
|
|
41
17
|
type Chunk = StreamChunk;
|
|
@@ -62,8 +38,6 @@ const ChunkRow = React.memo(function ChunkRow({
|
|
|
62
38
|
chunk: Chunk;
|
|
63
39
|
index: number;
|
|
64
40
|
}) {
|
|
65
|
-
const parsed = parseChunkData(chunk.text);
|
|
66
|
-
|
|
67
41
|
return (
|
|
68
42
|
<div
|
|
69
43
|
className="text-[11px] rounded-md border p-3"
|
|
@@ -72,22 +46,26 @@ const ChunkRow = React.memo(function ChunkRow({
|
|
|
72
46
|
backgroundColor: 'var(--ds-gray-100)',
|
|
73
47
|
}}
|
|
74
48
|
>
|
|
75
|
-
<
|
|
76
|
-
className="select-none mr-2"
|
|
77
|
-
style={{ color: 'var(--ds-gray-500)' }}
|
|
78
|
-
>
|
|
79
|
-
[{index}]
|
|
80
|
-
</span>
|
|
81
|
-
{typeof parsed === 'string' ? (
|
|
49
|
+
<div className="flex items-start gap-2">
|
|
82
50
|
<span
|
|
83
|
-
className="
|
|
84
|
-
style={{ color: 'var(--ds-gray-
|
|
51
|
+
className="select-none pt-px"
|
|
52
|
+
style={{ color: 'var(--ds-gray-500)' }}
|
|
85
53
|
>
|
|
86
|
-
{
|
|
54
|
+
[{index}]
|
|
87
55
|
</span>
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
56
|
+
<div className="min-w-0 flex-1">
|
|
57
|
+
{typeof chunk.value === 'string' ? (
|
|
58
|
+
<span
|
|
59
|
+
className="whitespace-pre-wrap break-words"
|
|
60
|
+
style={{ color: 'var(--ds-gray-1000)' }}
|
|
61
|
+
>
|
|
62
|
+
{chunk.value}
|
|
63
|
+
</span>
|
|
64
|
+
) : (
|
|
65
|
+
<DataInspector data={chunk.value} expandLevel={1} />
|
|
66
|
+
)}
|
|
67
|
+
</div>
|
|
68
|
+
</div>
|
|
91
69
|
</div>
|
|
92
70
|
);
|
|
93
71
|
});
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { useMemo } from 'react';
|
|
2
|
+
import type { WorkflowRun } from '@workflow/core/runtime';
|
|
3
|
+
import type { Event } from '@workflow/world';
|
|
4
|
+
import { buildTrace, type TraceWithMeta } from '../lib/trace-builder';
|
|
5
|
+
import { NewTraceViewer as NewTraceViewerComponent } from './new-trace-viewer/trace-viewer';
|
|
6
|
+
import {
|
|
7
|
+
SidebarDataProvider,
|
|
8
|
+
type SidebarDataContextValue,
|
|
9
|
+
} from './sidebar/sidebar-data-context';
|
|
10
|
+
import type { Trace } from './trace-viewer/types';
|
|
11
|
+
|
|
12
|
+
const NewTraceViewer = ({
|
|
13
|
+
run,
|
|
14
|
+
events,
|
|
15
|
+
sidebarData,
|
|
16
|
+
}: {
|
|
17
|
+
run: WorkflowRun;
|
|
18
|
+
events: Event[];
|
|
19
|
+
sidebarData: SidebarDataContextValue;
|
|
20
|
+
}) => {
|
|
21
|
+
// Build trace only when actual data changes — no timer-driven rebuilds.
|
|
22
|
+
// Active span widths are animated imperatively by useLiveTick at 60fps.
|
|
23
|
+
const traceWithMeta: TraceWithMeta | undefined = useMemo(() => {
|
|
24
|
+
if (!run?.runId) {
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
27
|
+
return buildTrace(run, events, new Date());
|
|
28
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps -- `new Date()` is intentionally not a dep; useLiveTick handles live growth
|
|
29
|
+
}, [run, events]);
|
|
30
|
+
const trace = traceWithMeta;
|
|
31
|
+
|
|
32
|
+
if (!trace) {
|
|
33
|
+
return (
|
|
34
|
+
<div className="relative w-full h-full flex items-center justify-center">
|
|
35
|
+
<div className="text-gray-500 text-sm">Loading trace…</div>
|
|
36
|
+
</div>
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<SidebarDataProvider value={sidebarData}>
|
|
42
|
+
<div className="relative w-full h-full flex">
|
|
43
|
+
<NewTraceViewerComponent trace={trace as Trace} />
|
|
44
|
+
</div>
|
|
45
|
+
</SidebarDataProvider>
|
|
46
|
+
);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export { NewTraceViewer };
|