@workflow/web-shared 5.0.0-beta.7 → 5.0.0-beta.9
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.d.ts +1 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +2 -1
- package/dist/components/new-trace-viewer/components/copy-button.js +2 -2
- package/dist/components/new-trace-viewer/components/event-list.d.ts +3 -1
- package/dist/components/new-trace-viewer/components/event-list.d.ts.map +1 -1
- package/dist/components/new-trace-viewer/components/event-list.js +8 -7
- 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 +4 -1
- package/dist/components/new-trace-viewer/components/timeline.d.ts.map +1 -1
- package/dist/components/new-trace-viewer/components/timeline.js +6 -5
- package/dist/components/new-trace-viewer/context.js +1 -1
- package/dist/components/new-trace-viewer/detail-panel.d.ts.map +1 -1
- package/dist/components/new-trace-viewer/detail-panel.js +3 -2
- package/dist/components/new-trace-viewer/icons.js +1 -1
- 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.map +1 -1
- package/dist/components/new-trace-viewer/trace-viewer.js +62 -35
- 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.js +1 -1
- 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 +46 -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/icon-button.d.ts +13 -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.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.js +1 -1
- 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/dist/styles.css +5 -0
- package/package.json +5 -5
- package/src/components/event-list-view.tsx +29 -13
- package/src/components/index.ts +1 -0
- package/src/components/new-trace-viewer/components/copy-button.tsx +1 -1
- package/src/components/new-trace-viewer/components/event-list.tsx +17 -6
- package/src/components/new-trace-viewer/components/timeline.tsx +11 -2
- package/src/components/new-trace-viewer/detail-panel.tsx +3 -6
- package/src/components/new-trace-viewer/search.ts +178 -0
- package/src/components/new-trace-viewer/trace-viewer.tsx +123 -89
- 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 +68 -0
- package/src/components/ui/data-inspector.tsx +9 -18
- package/src/components/ui/error-stack-block.tsx +7 -26
- package/src/components/ui/icon-button.tsx +57 -0
- package/src/styles.css +5 -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/hooks/use-reduced-motion.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
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
import { parseStepName, parseWorkflowName } from '@workflow/utils/parse-name';
|
|
4
4
|
import type { Event, Hook, Step, WorkflowRun } from '@workflow/world';
|
|
5
5
|
import type { ModelMessage } from 'ai';
|
|
6
|
-
import { Lock } from 'lucide-react';
|
|
7
6
|
import type { KeyboardEvent, ReactNode } from 'react';
|
|
8
7
|
import { useCallback, useContext, useMemo, useState } from 'react';
|
|
9
8
|
import { isEncryptedMarker, isExpiredMarker } from '../../lib/hydration';
|
|
@@ -20,10 +19,11 @@ import {
|
|
|
20
19
|
isStructuredErrorWithStack,
|
|
21
20
|
} from '../ui/error-stack-block';
|
|
22
21
|
import { Skeleton } from '../ui/skeleton';
|
|
23
|
-
import { Spinner } from '../ui/spinner';
|
|
24
22
|
import { TimestampTooltip } from '../ui/timestamp-tooltip';
|
|
23
|
+
import { CopyButton } from '../new-trace-viewer/components/copy-button';
|
|
24
|
+
import { MiddleTruncate } from '../new-trace-viewer/components/middle-truncate/middle-truncate';
|
|
25
25
|
import { ConversationView } from './conversation-view';
|
|
26
|
-
import { CopyableDataBlock } from './copyable-data-block';
|
|
26
|
+
import { CopyableDataBlock, EncryptedDataBlock } from './copyable-data-block';
|
|
27
27
|
import { DetailCard } from './detail-card';
|
|
28
28
|
|
|
29
29
|
/**
|
|
@@ -151,7 +151,7 @@ function ConversationWithTabs({
|
|
|
151
151
|
);
|
|
152
152
|
|
|
153
153
|
return (
|
|
154
|
-
<DetailCard summary=
|
|
154
|
+
<DetailCard summary="Input">
|
|
155
155
|
<TabbedContainer
|
|
156
156
|
tabs={conversationTabs}
|
|
157
157
|
activeTab={activeTab}
|
|
@@ -180,51 +180,8 @@ function ConversationWithTabs({
|
|
|
180
180
|
* Render a value with the shared DataInspector (ObjectInspector with
|
|
181
181
|
* custom theming, nodeRenderer for StreamRef/ClassInstanceRef, etc.)
|
|
182
182
|
*/
|
|
183
|
-
/**
|
|
184
|
-
* Inline display for an encrypted field — no expand, just a flat label
|
|
185
|
-
* with the lucide Lock icon matching the title bar Decrypt button.
|
|
186
|
-
*/
|
|
187
183
|
function EncryptedFieldBlock() {
|
|
188
|
-
|
|
189
|
-
if (ctx) {
|
|
190
|
-
return (
|
|
191
|
-
<button
|
|
192
|
-
type="button"
|
|
193
|
-
onClick={ctx.onDecrypt}
|
|
194
|
-
disabled={ctx.isDecrypting}
|
|
195
|
-
className="flex w-full items-center justify-center gap-1.5 rounded-md border px-3 py-2 text-xs cursor-pointer transition-colors"
|
|
196
|
-
style={{
|
|
197
|
-
borderColor: 'var(--ds-gray-400)',
|
|
198
|
-
backgroundColor: 'var(--ds-gray-100)',
|
|
199
|
-
color: 'var(--ds-gray-700)',
|
|
200
|
-
opacity: ctx.isDecrypting ? 0.6 : 1,
|
|
201
|
-
}}
|
|
202
|
-
title="Click to decrypt"
|
|
203
|
-
>
|
|
204
|
-
{ctx.isDecrypting ? (
|
|
205
|
-
<Spinner size={12} />
|
|
206
|
-
) : (
|
|
207
|
-
<Lock className="h-3 w-3" />
|
|
208
|
-
)}
|
|
209
|
-
<span className="font-medium">
|
|
210
|
-
{ctx.isDecrypting ? 'Decrypting…' : 'Decrypt'}
|
|
211
|
-
</span>
|
|
212
|
-
</button>
|
|
213
|
-
);
|
|
214
|
-
}
|
|
215
|
-
return (
|
|
216
|
-
<div
|
|
217
|
-
className="flex w-full items-center justify-center gap-1.5 rounded-md border px-3 py-2 text-xs"
|
|
218
|
-
style={{
|
|
219
|
-
borderColor: 'var(--ds-gray-300)',
|
|
220
|
-
backgroundColor: 'var(--ds-gray-100)',
|
|
221
|
-
color: 'var(--ds-gray-700)',
|
|
222
|
-
}}
|
|
223
|
-
>
|
|
224
|
-
<Lock className="h-3 w-3" />
|
|
225
|
-
<span className="font-medium">Encrypted</span>
|
|
226
|
-
</div>
|
|
227
|
-
);
|
|
184
|
+
return <EncryptedDataBlock />;
|
|
228
185
|
}
|
|
229
186
|
|
|
230
187
|
/**
|
|
@@ -269,7 +226,9 @@ type AttributeKey =
|
|
|
269
226
|
| 'workflowCoreVersion'
|
|
270
227
|
| 'receivedCount'
|
|
271
228
|
| 'lastReceivedAt'
|
|
272
|
-
| 'disposedAt'
|
|
229
|
+
| 'disposedAt'
|
|
230
|
+
| 'isSystem'
|
|
231
|
+
| 'errorCode';
|
|
273
232
|
|
|
274
233
|
const attributeOrder: AttributeKey[] = [
|
|
275
234
|
'workflowName',
|
|
@@ -326,6 +285,7 @@ const attributeDisplayNames: Partial<Record<AttributeKey, string>> = {
|
|
|
326
285
|
attempt: 'Attempts',
|
|
327
286
|
eventId: 'Event ID',
|
|
328
287
|
runId: 'Run ID',
|
|
288
|
+
token: 'Token',
|
|
329
289
|
eventType: 'Event Type',
|
|
330
290
|
correlationId: 'Correlation ID',
|
|
331
291
|
deploymentId: 'Deployment ID',
|
|
@@ -432,7 +392,7 @@ const attributeToDisplayFn: Record<
|
|
|
432
392
|
stepName: (_value: unknown) => null,
|
|
433
393
|
// IDs
|
|
434
394
|
runId: (_value: unknown) => null,
|
|
435
|
-
stepId: (
|
|
395
|
+
stepId: (value: unknown) => String(value),
|
|
436
396
|
hookId: (value: unknown) => String(value),
|
|
437
397
|
eventId: (value: unknown) => String(value),
|
|
438
398
|
// Run/step details
|
|
@@ -457,6 +417,13 @@ const attributeToDisplayFn: Record<
|
|
|
457
417
|
projectId: (_value: unknown) => null,
|
|
458
418
|
environment: (_value: unknown) => null,
|
|
459
419
|
executionContext: (_value: unknown) => null,
|
|
420
|
+
// Attributes MVP — string-string metadata attached to the run.
|
|
421
|
+
// Rendered as a JSON block; if empty/missing, hidden by the
|
|
422
|
+
// hasDisplayContent gate above.
|
|
423
|
+
attributes: (value: unknown) => {
|
|
424
|
+
if (!hasDisplayContent(value)) return null;
|
|
425
|
+
return JsonBlock(value);
|
|
426
|
+
},
|
|
460
427
|
// Dates — wrapped with TimestampTooltip showing UTC/local + relative time
|
|
461
428
|
createdAt: timestampWithTooltipOrNull,
|
|
462
429
|
startedAt: timestampWithTooltipOrNull,
|
|
@@ -468,12 +435,18 @@ const attributeToDisplayFn: Record<
|
|
|
468
435
|
// Resolved attributes, won't actually use this function
|
|
469
436
|
metadata: (value: unknown) => {
|
|
470
437
|
if (!hasDisplayContent(value)) return null;
|
|
471
|
-
if (isEncryptedMarker(value)) return <
|
|
438
|
+
if (isEncryptedMarker(value)) return <EncryptedDataBlock />;
|
|
472
439
|
if (isExpiredMarker(value)) return <ExpiredFieldBlock />;
|
|
473
440
|
return JsonBlock(value);
|
|
474
441
|
},
|
|
475
442
|
input: (value: unknown, context?: DisplayContext) => {
|
|
476
|
-
if (isEncryptedMarker(value))
|
|
443
|
+
if (isEncryptedMarker(value)) {
|
|
444
|
+
return (
|
|
445
|
+
<DetailCard summary="Input">
|
|
446
|
+
<EncryptedFieldBlock />
|
|
447
|
+
</DetailCard>
|
|
448
|
+
);
|
|
449
|
+
}
|
|
477
450
|
if (isExpiredMarker(value)) return <ExpiredFieldBlock />;
|
|
478
451
|
// Check if input has args + closure vars structure
|
|
479
452
|
if (value && typeof value === 'object' && 'args' in value) {
|
|
@@ -482,8 +455,6 @@ const attributeToDisplayFn: Record<
|
|
|
482
455
|
closureVars?: Record<string, unknown>;
|
|
483
456
|
thisVal?: unknown;
|
|
484
457
|
};
|
|
485
|
-
const argCount = Array.isArray(args) ? args.length : 0;
|
|
486
|
-
const argLabel = argCount === 1 ? 'argument' : 'arguments';
|
|
487
458
|
const hasClosureVars = hasDisplayContent(closureVars);
|
|
488
459
|
const hasThisVal = hasDisplayContent(thisVal);
|
|
489
460
|
const hasArgs = hasDisplayContent(args);
|
|
@@ -512,22 +483,12 @@ const attributeToDisplayFn: Record<
|
|
|
512
483
|
|
|
513
484
|
// Don't render an empty "Input (0 arguments)" card when no input exists.
|
|
514
485
|
if (!hasArgs && !hasClosureVars && !hasThisVal) {
|
|
515
|
-
return (
|
|
516
|
-
<DetailCard
|
|
517
|
-
summary="Input (no data)"
|
|
518
|
-
disabled
|
|
519
|
-
summaryClassName="text-label-14 font-medium py-2"
|
|
520
|
-
/>
|
|
521
|
-
);
|
|
486
|
+
return <DetailCard summary="Input (no data)" disabled />;
|
|
522
487
|
}
|
|
523
488
|
|
|
524
489
|
return (
|
|
525
490
|
<>
|
|
526
|
-
<DetailCard
|
|
527
|
-
summary={`Input (${argCount} ${argLabel})`}
|
|
528
|
-
summaryClassName="text-label-14 font-medium py-2"
|
|
529
|
-
contentClassName="mt-0"
|
|
530
|
-
>
|
|
491
|
+
<DetailCard summary="Input">
|
|
531
492
|
{Array.isArray(args)
|
|
532
493
|
? args.map((v, i) => (
|
|
533
494
|
<div className="mt-2 first:mt-0" key={i}>
|
|
@@ -542,30 +503,18 @@ const attributeToDisplayFn: Record<
|
|
|
542
503
|
</DetailCard>
|
|
543
504
|
)}
|
|
544
505
|
{hasThisVal && (
|
|
545
|
-
<DetailCard summary="
|
|
506
|
+
<DetailCard summary="Context">{JsonBlock(thisVal)}</DetailCard>
|
|
546
507
|
)}
|
|
547
508
|
</>
|
|
548
509
|
);
|
|
549
510
|
}
|
|
550
511
|
|
|
551
512
|
// Fallback: treat as plain array or object
|
|
552
|
-
const argCount = Array.isArray(value) ? value.length : 0;
|
|
553
|
-
const argLabel = argCount === 1 ? 'argument' : 'arguments';
|
|
554
513
|
if (!hasDisplayContent(value)) {
|
|
555
|
-
return (
|
|
556
|
-
<DetailCard
|
|
557
|
-
summary="Input (no data)"
|
|
558
|
-
disabled
|
|
559
|
-
summaryClassName="text-label-14 font-medium py-2"
|
|
560
|
-
/>
|
|
561
|
-
);
|
|
514
|
+
return <DetailCard summary="Input (no data)" disabled />;
|
|
562
515
|
}
|
|
563
516
|
return (
|
|
564
|
-
<DetailCard
|
|
565
|
-
summary={`Input (${argCount} ${argLabel})`}
|
|
566
|
-
summaryClassName="text-label-14 font-medium py-2"
|
|
567
|
-
contentClassName="mt-0"
|
|
568
|
-
>
|
|
517
|
+
<DetailCard summary="Input">
|
|
569
518
|
{Array.isArray(value)
|
|
570
519
|
? value.map((v, i) => (
|
|
571
520
|
<div className="mt-2 first:mt-0" key={i}>
|
|
@@ -577,21 +526,25 @@ const attributeToDisplayFn: Record<
|
|
|
577
526
|
);
|
|
578
527
|
},
|
|
579
528
|
output: (value: unknown) => {
|
|
529
|
+
if (isEncryptedMarker(value)) {
|
|
530
|
+
return (
|
|
531
|
+
<DetailCard summary="Output">
|
|
532
|
+
<EncryptedFieldBlock />
|
|
533
|
+
</DetailCard>
|
|
534
|
+
);
|
|
535
|
+
}
|
|
580
536
|
if (!hasDisplayContent(value)) return null;
|
|
581
|
-
if (isEncryptedMarker(value)) return <EncryptedFieldBlock />;
|
|
582
537
|
if (isExpiredMarker(value)) return <ExpiredFieldBlock />;
|
|
583
|
-
return (
|
|
584
|
-
<DetailCard
|
|
585
|
-
summary="Output"
|
|
586
|
-
summaryClassName="text-label-14 font-medium py-2"
|
|
587
|
-
contentClassName="mt-0"
|
|
588
|
-
>
|
|
589
|
-
{JsonBlock(value)}
|
|
590
|
-
</DetailCard>
|
|
591
|
-
);
|
|
538
|
+
return <DetailCard summary="Output">{JsonBlock(value)}</DetailCard>;
|
|
592
539
|
},
|
|
593
540
|
error: (value: unknown) => {
|
|
594
|
-
if (isEncryptedMarker(value))
|
|
541
|
+
if (isEncryptedMarker(value)) {
|
|
542
|
+
return (
|
|
543
|
+
<DetailCard summary="Error" defaultOpen>
|
|
544
|
+
<EncryptedFieldBlock />
|
|
545
|
+
</DetailCard>
|
|
546
|
+
);
|
|
547
|
+
}
|
|
595
548
|
if (isExpiredMarker(value)) return <ExpiredFieldBlock />;
|
|
596
549
|
if (!hasDisplayContent(value)) return null;
|
|
597
550
|
|
|
@@ -599,31 +552,33 @@ const attributeToDisplayFn: Record<
|
|
|
599
552
|
// pre-formatted text. Otherwise fall back to the raw JSON viewer.
|
|
600
553
|
if (isStructuredErrorWithStack(value)) {
|
|
601
554
|
return (
|
|
602
|
-
<DetailCard
|
|
603
|
-
summary="Error"
|
|
604
|
-
summaryClassName="text-label-14 font-medium py-2"
|
|
605
|
-
contentClassName="mt-0"
|
|
606
|
-
>
|
|
555
|
+
<DetailCard summary="Error" defaultOpen>
|
|
607
556
|
<ErrorStackBlock value={value} />
|
|
608
557
|
</DetailCard>
|
|
609
558
|
);
|
|
610
559
|
}
|
|
611
560
|
|
|
612
561
|
return (
|
|
613
|
-
<DetailCard
|
|
614
|
-
summary="Error"
|
|
615
|
-
summaryClassName="text-label-14 font-medium py-2"
|
|
616
|
-
contentClassName="mt-0"
|
|
617
|
-
>
|
|
562
|
+
<DetailCard summary="Error" defaultOpen>
|
|
618
563
|
{JsonBlock(value)}
|
|
619
564
|
</DetailCard>
|
|
620
565
|
);
|
|
621
566
|
},
|
|
622
567
|
eventData: (value: unknown) => {
|
|
623
|
-
if (isEncryptedMarker(value))
|
|
568
|
+
if (isEncryptedMarker(value)) {
|
|
569
|
+
return (
|
|
570
|
+
<DetailCard summary="Event Data" defaultOpen>
|
|
571
|
+
<EncryptedFieldBlock />
|
|
572
|
+
</DetailCard>
|
|
573
|
+
);
|
|
574
|
+
}
|
|
624
575
|
if (isExpiredMarker(value)) return <ExpiredFieldBlock />;
|
|
625
576
|
if (!hasDisplayContent(value)) return null;
|
|
626
|
-
return
|
|
577
|
+
return (
|
|
578
|
+
<DetailCard summary="Event Data" defaultOpen>
|
|
579
|
+
{JsonBlock(value)}
|
|
580
|
+
</DetailCard>
|
|
581
|
+
);
|
|
627
582
|
},
|
|
628
583
|
errorCode: (value: unknown) => {
|
|
629
584
|
if (typeof value !== 'string' || value.length === 0) return null;
|
|
@@ -639,6 +594,15 @@ const resolvableAttributes = [
|
|
|
639
594
|
'eventData',
|
|
640
595
|
];
|
|
641
596
|
|
|
597
|
+
// Attributes whose displayFn renders its own section header via DetailCard,
|
|
598
|
+
// so the outer AttributeBlock should not duplicate the label.
|
|
599
|
+
const selfHeaderedAttributes = new Set([
|
|
600
|
+
'input',
|
|
601
|
+
'output',
|
|
602
|
+
'error',
|
|
603
|
+
'eventData',
|
|
604
|
+
]);
|
|
605
|
+
|
|
642
606
|
const ExpiredDataMessage = () => (
|
|
643
607
|
<div
|
|
644
608
|
className="text-copy-12 rounded-md border p-4 my-2"
|
|
@@ -652,6 +616,13 @@ const ExpiredDataMessage = () => (
|
|
|
652
616
|
</div>
|
|
653
617
|
);
|
|
654
618
|
|
|
619
|
+
const copyableBasicAttributes = new Set<AttributeKey>([
|
|
620
|
+
'stepId',
|
|
621
|
+
'hookId',
|
|
622
|
+
'eventId',
|
|
623
|
+
'deploymentId',
|
|
624
|
+
]);
|
|
625
|
+
|
|
655
626
|
export const AttributeBlock = ({
|
|
656
627
|
attribute,
|
|
657
628
|
value,
|
|
@@ -665,19 +636,26 @@ export const AttributeBlock = ({
|
|
|
665
636
|
inline?: boolean;
|
|
666
637
|
context?: DisplayContext;
|
|
667
638
|
}) => {
|
|
639
|
+
const decryptCtx = useContext(DecryptClickContext);
|
|
668
640
|
const isExpandableLoadingTarget =
|
|
669
|
-
attribute === 'input' ||
|
|
641
|
+
attribute === 'input' ||
|
|
642
|
+
attribute === 'output' ||
|
|
643
|
+
attribute === 'eventData';
|
|
670
644
|
if (isLoading && isExpandableLoadingTarget && !hasDisplayContent(value)) {
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
645
|
+
const label =
|
|
646
|
+
attribute === 'eventData'
|
|
647
|
+
? 'Event Data'
|
|
648
|
+
: attribute === 'output'
|
|
649
|
+
? 'Output'
|
|
650
|
+
: 'Input';
|
|
651
|
+
if (decryptCtx?.hasEncryptedData) {
|
|
652
|
+
return (
|
|
653
|
+
<DetailCard summary={label} defaultOpen={attribute === 'eventData'}>
|
|
654
|
+
<EncryptedFieldBlock />
|
|
655
|
+
</DetailCard>
|
|
656
|
+
);
|
|
657
|
+
}
|
|
658
|
+
return <DetailCard summary={label} />;
|
|
681
659
|
}
|
|
682
660
|
|
|
683
661
|
const displayFn =
|
|
@@ -706,6 +684,10 @@ export const AttributeBlock = ({
|
|
|
706
684
|
);
|
|
707
685
|
}
|
|
708
686
|
|
|
687
|
+
if (selfHeaderedAttributes.has(attribute)) {
|
|
688
|
+
return <>{displayValue}</>;
|
|
689
|
+
}
|
|
690
|
+
|
|
709
691
|
return (
|
|
710
692
|
<div className="relative">
|
|
711
693
|
{typeof isLoading === 'boolean' && isLoading && (
|
|
@@ -716,10 +698,7 @@ export const AttributeBlock = ({
|
|
|
716
698
|
/>
|
|
717
699
|
</div>
|
|
718
700
|
)}
|
|
719
|
-
<div
|
|
720
|
-
key={attribute}
|
|
721
|
-
className={`my-2 flex flex-col ${attribute === 'input' || attribute === 'output' || attribute === 'error' ? 'gap-2 my-3.5' : 'gap-0'}`}
|
|
722
|
-
>
|
|
701
|
+
<div key={attribute} className="my-2 flex flex-col gap-0">
|
|
723
702
|
<span className="text-label-14 text-gray-1000 font-medium first-letter:uppercase">
|
|
724
703
|
{attribute}
|
|
725
704
|
</span>
|
|
@@ -789,16 +768,18 @@ export const AttributePanel = ({
|
|
|
789
768
|
|
|
790
769
|
if (!isLoading) return present;
|
|
791
770
|
|
|
792
|
-
|
|
771
|
+
if (resource === 'sleep') return present;
|
|
772
|
+
|
|
773
|
+
// During loading, ensure sections appear so their skeletons render
|
|
793
774
|
// in the correct position (above the events section).
|
|
794
|
-
const loadingDefaults = ['input'];
|
|
775
|
+
const loadingDefaults = ['input', 'output'];
|
|
795
776
|
for (const key of loadingDefaults) {
|
|
796
777
|
if (!present.includes(key)) {
|
|
797
778
|
present.push(key);
|
|
798
779
|
}
|
|
799
780
|
}
|
|
800
781
|
return present.sort(sortByAttributeOrder);
|
|
801
|
-
}, [displayData, isLoading]);
|
|
782
|
+
}, [displayData, isLoading, resource]);
|
|
802
783
|
|
|
803
784
|
// Filter out attributes that return null
|
|
804
785
|
const visibleBasicAttributes = basicAttributes.filter((attribute) => {
|
|
@@ -854,125 +835,121 @@ export const AttributePanel = ({
|
|
|
854
835
|
});
|
|
855
836
|
}, []);
|
|
856
837
|
|
|
838
|
+
const outerDecryptCtx = useContext(DecryptClickContext);
|
|
839
|
+
const decryptValue = onDecrypt
|
|
840
|
+
? {
|
|
841
|
+
onDecrypt,
|
|
842
|
+
isDecrypting,
|
|
843
|
+
hasEncryptedData: outerDecryptCtx?.hasEncryptedData,
|
|
844
|
+
}
|
|
845
|
+
: outerDecryptCtx;
|
|
846
|
+
|
|
857
847
|
return (
|
|
858
848
|
<RunClickContext.Provider value={onRunClick}>
|
|
859
849
|
<StreamClickContext.Provider value={onStreamClick}>
|
|
860
|
-
<DecryptClickContext.Provider
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
: 'text-[14px]'
|
|
899
|
-
}
|
|
900
|
-
style={{ color: 'var(--ds-gray-700)' }}
|
|
901
|
-
>
|
|
902
|
-
{getAttributeDisplayName(attribute)}
|
|
903
|
-
</span>
|
|
904
|
-
{isModuleSpecifier ? (
|
|
905
|
-
<button
|
|
906
|
-
type="button"
|
|
907
|
-
className="min-w-0 max-w-[70%] truncate text-right text-[13px] font-mono"
|
|
908
|
-
style={{
|
|
909
|
-
color: 'var(--ds-gray-1000)',
|
|
910
|
-
background: 'transparent',
|
|
911
|
-
border: 'none',
|
|
912
|
-
padding: 0,
|
|
913
|
-
}}
|
|
914
|
-
title={moduleSpecifierValue}
|
|
915
|
-
onClick={() =>
|
|
916
|
-
handleCopyModuleSpecifier(moduleSpecifierValue)
|
|
917
|
-
}
|
|
918
|
-
>
|
|
919
|
-
{moduleSpecifierValue}
|
|
920
|
-
</button>
|
|
921
|
-
) : (
|
|
922
|
-
<span
|
|
923
|
-
className="min-w-0 max-w-[70%] truncate text-right text-[13px] font-mono"
|
|
924
|
-
style={{ color: 'var(--ds-gray-1000)' }}
|
|
925
|
-
>
|
|
926
|
-
{displayValue}
|
|
927
|
-
</span>
|
|
928
|
-
)}
|
|
929
|
-
</div>
|
|
930
|
-
{showDivider ? (
|
|
931
|
-
<div
|
|
932
|
-
className="mx-2.5 border-b"
|
|
933
|
-
style={{ borderColor: 'var(--ds-gray-300)' }}
|
|
934
|
-
/>
|
|
935
|
-
) : null}
|
|
936
|
-
</div>
|
|
937
|
-
);
|
|
938
|
-
})}
|
|
939
|
-
{isLoading && resource === 'sleep' && !displayData.resumeAt && (
|
|
940
|
-
<div className="py-1">
|
|
941
|
-
<div className="flex min-h-[32px] items-center justify-between gap-4 rounded-sm px-2.5 py-1">
|
|
942
|
-
<span
|
|
943
|
-
className="text-[14px] first-letter:uppercase"
|
|
944
|
-
style={{ color: 'var(--ds-gray-700)' }}
|
|
850
|
+
<DecryptClickContext.Provider value={decryptValue}>
|
|
851
|
+
{visibleBasicAttributes.length > 0 && (
|
|
852
|
+
<div className="flex flex-col overflow-hidden divide-y divide-gray-alpha-400 mb-3">
|
|
853
|
+
{orderedBasicAttributes.map((attribute) => {
|
|
854
|
+
const displayValue = attributeToDisplayFn[
|
|
855
|
+
attribute as keyof typeof attributeToDisplayFn
|
|
856
|
+
]?.(displayData[attribute as keyof typeof displayData]);
|
|
857
|
+
const isModuleSpecifier = attribute === 'moduleSpecifier';
|
|
858
|
+
const isCopyableBasicAttribute =
|
|
859
|
+
copyableBasicAttributes.has(attribute as AttributeKey) &&
|
|
860
|
+
typeof displayValue === 'string';
|
|
861
|
+
const moduleSpecifierValue =
|
|
862
|
+
typeof displayValue === 'string'
|
|
863
|
+
? displayValue
|
|
864
|
+
: String(displayValue ?? displayData.moduleSpecifier ?? '');
|
|
865
|
+
|
|
866
|
+
return (
|
|
867
|
+
<div
|
|
868
|
+
className="flex items-center justify-between py-2"
|
|
869
|
+
key={attribute}
|
|
870
|
+
>
|
|
871
|
+
<span className="text-label-14 text-gray-900">
|
|
872
|
+
{getAttributeDisplayName(attribute)}
|
|
873
|
+
</span>
|
|
874
|
+
{isModuleSpecifier ? (
|
|
875
|
+
<button
|
|
876
|
+
type="button"
|
|
877
|
+
className="min-w-0 max-w-[70%] truncate text-right text-label-13 font-mono"
|
|
878
|
+
style={{
|
|
879
|
+
color: 'var(--ds-gray-1000)',
|
|
880
|
+
background: 'transparent',
|
|
881
|
+
border: 'none',
|
|
882
|
+
padding: 0,
|
|
883
|
+
}}
|
|
884
|
+
title={moduleSpecifierValue}
|
|
885
|
+
onClick={() =>
|
|
886
|
+
handleCopyModuleSpecifier(moduleSpecifierValue)
|
|
887
|
+
}
|
|
945
888
|
>
|
|
946
|
-
|
|
889
|
+
{moduleSpecifierValue}
|
|
890
|
+
</button>
|
|
891
|
+
) : isCopyableBasicAttribute ? (
|
|
892
|
+
<div
|
|
893
|
+
className="flex min-w-0 max-w-[70%] items-center justify-end gap-1 text-right text-[13px] font-mono"
|
|
894
|
+
style={{
|
|
895
|
+
color: 'var(--ds-gray-1000)',
|
|
896
|
+
}}
|
|
897
|
+
title={displayValue}
|
|
898
|
+
>
|
|
899
|
+
<MiddleTruncate
|
|
900
|
+
value={displayValue}
|
|
901
|
+
className="flex-1"
|
|
902
|
+
/>
|
|
903
|
+
<CopyButton
|
|
904
|
+
copyText={displayValue}
|
|
905
|
+
ariaLabel={`Copy ${getAttributeDisplayName(attribute)}`}
|
|
906
|
+
className="shrink-0 -mr-1"
|
|
907
|
+
/>
|
|
908
|
+
</div>
|
|
909
|
+
) : (
|
|
910
|
+
<span className="text-right text-label-13 font-mono">
|
|
911
|
+
{displayValue}
|
|
947
912
|
</span>
|
|
948
|
-
|
|
949
|
-
</div>
|
|
913
|
+
)}
|
|
950
914
|
</div>
|
|
951
|
-
)
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
915
|
+
);
|
|
916
|
+
})}
|
|
917
|
+
{isLoading && resource === 'sleep' && !displayData.resumeAt && (
|
|
918
|
+
<div className="py-1">
|
|
919
|
+
<div className="flex min-h-[32px] items-center justify-between gap-4 rounded-sm px-2.5 py-1">
|
|
920
|
+
<span
|
|
921
|
+
className="text-[14px] first-letter:uppercase"
|
|
922
|
+
style={{ color: 'var(--ds-gray-700)' }}
|
|
923
|
+
>
|
|
924
|
+
resumeAt
|
|
925
|
+
</span>
|
|
926
|
+
<Skeleton className="h-4 w-[55%]" />
|
|
927
|
+
</div>
|
|
928
|
+
</div>
|
|
929
|
+
)}
|
|
930
|
+
</div>
|
|
931
|
+
)}
|
|
932
|
+
{error ? (
|
|
933
|
+
<ErrorCard
|
|
934
|
+
title="Failed to load resource details"
|
|
935
|
+
details={error.message}
|
|
936
|
+
className="my-4"
|
|
937
|
+
/>
|
|
938
|
+
) : hasExpired ? (
|
|
939
|
+
<ExpiredDataMessage />
|
|
940
|
+
) : resolvedAttributes.length > 0 ? (
|
|
941
|
+
<>
|
|
942
|
+
{resolvedAttributes.map((attribute) => (
|
|
943
|
+
<AttributeBlock
|
|
944
|
+
isLoading={isLoading}
|
|
945
|
+
key={attribute}
|
|
946
|
+
attribute={attribute}
|
|
947
|
+
value={displayData[attribute as keyof typeof displayData]}
|
|
948
|
+
context={displayContext}
|
|
949
|
+
/>
|
|
950
|
+
))}
|
|
951
|
+
</>
|
|
952
|
+
) : null}
|
|
976
953
|
</DecryptClickContext.Provider>
|
|
977
954
|
</StreamClickContext.Provider>
|
|
978
955
|
</RunClickContext.Provider>
|