@workflow/web-shared 5.0.0-beta.0 → 5.0.0-beta.10
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 +1 -1
- package/dist/components/event-list-view.d.ts +18 -1
- package/dist/components/event-list-view.d.ts.map +1 -1
- package/dist/components/event-list-view.js +242 -142
- package/dist/components/hook-actions.js +1 -1
- package/dist/components/index.d.ts +4 -1
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +5 -2
- 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 +39 -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/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 +99 -0
- package/dist/components/new-trace-viewer/components/timeline.d.ts +34 -0
- package/dist/components/new-trace-viewer/components/timeline.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/components/timeline.js +223 -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/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 +13 -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 +8 -0
- package/dist/components/new-trace-viewer/trace-viewer.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/trace-viewer.js +387 -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/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/utils.d.ts +46 -0
- package/dist/components/new-trace-viewer/utils.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/utils.js +330 -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 +3 -3
- 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 +131 -70
- 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 +3 -1
- package/dist/components/sidebar/entity-detail-panel.d.ts.map +1 -1
- package/dist/components/sidebar/entity-detail-panel.js +20 -37
- package/dist/components/sidebar/events-list.d.ts +1 -1
- package/dist/components/sidebar/events-list.d.ts.map +1 -1
- package/dist/components/sidebar/events-list.js +46 -32
- 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/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.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.d.ts +1 -1
- package/dist/components/trace-viewer/util/timing.d.ts.map +1 -1
- package/dist/components/trace-viewer/util/timing.js +6 -9
- 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 +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/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 +39 -1
- package/dist/components/ui/data-inspector.d.ts.map +1 -1
- package/dist/components/ui/data-inspector.js +207 -22
- 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 +27 -19
- 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.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/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.d.ts +3 -1
- package/dist/components/workflow-trace-view.d.ts.map +1 -1
- package/dist/components/workflow-trace-view.js +10 -5
- 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.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 -6
- package/dist/components/workflow-traces/trace-time-utils.js +1 -1
- package/dist/hooks/use-dark-mode.js +1 -1
- package/dist/hooks/use-reduced-motion.d.ts +10 -0
- package/dist/hooks/use-reduced-motion.d.ts.map +1 -0
- package/dist/hooks/use-reduced-motion.js +29 -0
- package/dist/index.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 +15 -2
- package/dist/lib/hydration.d.ts.map +1 -1
- package/dist/lib/hydration.js +168 -16
- 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.map +1 -1
- package/dist/lib/trace-builder.js +3 -2
- package/dist/lib/utils.d.ts +9 -9
- package/dist/lib/utils.d.ts.map +1 -1
- package/dist/lib/utils.js +27 -32
- package/dist/styles.css +475 -1
- package/package.json +6 -4
- package/src/components/event-list-view.tsx +447 -282
- package/src/components/index.ts +12 -1
- package/src/components/new-trace-viewer/components/copy-button.tsx +68 -0
- package/src/components/new-trace-viewer/components/event-list.tsx +127 -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/split-pane.tsx +185 -0
- package/src/components/new-trace-viewer/components/timeline.tsx +552 -0
- package/src/components/new-trace-viewer/context.tsx +92 -0
- package/src/components/new-trace-viewer/detail-panel.tsx +55 -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 +694 -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 +482 -0
- package/src/components/run-trace-view.tsx +3 -0
- package/src/components/sidebar/attribute-panel.tsx +240 -196
- 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 +92 -148
- package/src/components/sidebar/events-list.tsx +93 -108
- package/src/components/sidebar/sidebar-data-context.tsx +62 -0
- package/src/components/stream-viewer.tsx +18 -40
- package/src/components/trace-viewer/util/timing.ts +5 -9
- package/src/components/trace-viewer-new.tsx +49 -0
- package/src/components/ui/button.tsx +68 -0
- package/src/components/ui/data-inspector.tsx +427 -31
- package/src/components/ui/error-stack-block.tsx +39 -30
- package/src/components/ui/icon-button.tsx +57 -0
- 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 +24 -6
- 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 +182 -14
- package/src/lib/stream-display.ts +48 -0
- package/src/lib/trace-builder.ts +2 -1
- package/src/lib/utils.ts +27 -32
- package/src/styles.css +475 -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
|
@@ -3,13 +3,24 @@
|
|
|
3
3
|
import { parseStepName, parseWorkflowName } from '@workflow/utils/parse-name';
|
|
4
4
|
import type { Event, WorkflowRun } from '@workflow/world';
|
|
5
5
|
import { Check, ChevronRight, Copy } from 'lucide-react';
|
|
6
|
-
import type {
|
|
6
|
+
import type {
|
|
7
|
+
KeyboardEvent as ReactKeyboardEvent,
|
|
8
|
+
MouseEvent as ReactMouseEvent,
|
|
9
|
+
ReactNode,
|
|
10
|
+
} from 'react';
|
|
7
11
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
8
12
|
import { Virtuoso, type VirtuosoHandle } from 'react-virtuoso';
|
|
9
13
|
import { isEncryptedMarker } from '../lib/hydration';
|
|
14
|
+
import {
|
|
15
|
+
parseExactWorkflowSearchId,
|
|
16
|
+
looksLikeWorkflowIdSearchInput,
|
|
17
|
+
type ExactIdSearchResult,
|
|
18
|
+
type ExactWorkflowSearchIdKind,
|
|
19
|
+
} from '../lib/exact-event-search-id';
|
|
10
20
|
import { DecryptButton } from './ui/decrypt-button';
|
|
11
21
|
import { formatDuration } from '../lib/utils';
|
|
12
|
-
import {
|
|
22
|
+
import { useToast } from '../lib/toast';
|
|
23
|
+
import { DataInspector, DecryptClickContext } from './ui/data-inspector';
|
|
13
24
|
import {
|
|
14
25
|
ErrorStackBlock,
|
|
15
26
|
isStructuredErrorWithStack,
|
|
@@ -142,7 +153,7 @@ function buildNameMaps(
|
|
|
142
153
|
return { correlationNameMap, workflowName };
|
|
143
154
|
}
|
|
144
155
|
|
|
145
|
-
interface DurationInfo {
|
|
156
|
+
export interface DurationInfo {
|
|
146
157
|
/** Time from created → started (ms) */
|
|
147
158
|
queued?: number;
|
|
148
159
|
/** Time from started → completed/failed/cancelled (ms) */
|
|
@@ -154,19 +165,30 @@ interface DurationInfo {
|
|
|
154
165
|
* created ↔ started (queued) and started ↔ completed/failed/cancelled (ran).
|
|
155
166
|
* Also computes run-level durations under the key '__run__'.
|
|
156
167
|
*/
|
|
157
|
-
function buildDurationMap(events: Event[]): Map<string, DurationInfo> {
|
|
168
|
+
export function buildDurationMap(events: Event[]): Map<string, DurationInfo> {
|
|
169
|
+
// Process events in chronological order so the result doesn't depend on
|
|
170
|
+
// the caller's sort direction. Retried steps emit multiple `step_started`
|
|
171
|
+
// events for the same correlationId; the queued duration must be measured
|
|
172
|
+
// against the first one, not the last.
|
|
173
|
+
const chronological = [...events].sort(
|
|
174
|
+
(a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime()
|
|
175
|
+
);
|
|
176
|
+
|
|
158
177
|
const createdTimes = new Map<string, number>();
|
|
178
|
+
const firstStartedTimes = new Map<string, number>();
|
|
159
179
|
const startedTimes = new Map<string, number>();
|
|
160
180
|
const durations = new Map<string, DurationInfo>();
|
|
161
181
|
|
|
162
|
-
for (const event of
|
|
182
|
+
for (const event of chronological) {
|
|
163
183
|
const ts = new Date(event.createdAt).getTime();
|
|
164
184
|
const key = event.correlationId ?? '__run__';
|
|
165
185
|
const type: string = event.eventType;
|
|
166
186
|
|
|
167
187
|
// Track created times (first event for each correlation)
|
|
168
188
|
if (type === 'step_created' || type === 'run_created') {
|
|
169
|
-
createdTimes.
|
|
189
|
+
if (!createdTimes.has(key)) {
|
|
190
|
+
createdTimes.set(key, ts);
|
|
191
|
+
}
|
|
170
192
|
}
|
|
171
193
|
|
|
172
194
|
// Track started times & compute queued duration
|
|
@@ -176,16 +198,21 @@ function buildDurationMap(events: Event[]): Map<string, DurationInfo> {
|
|
|
176
198
|
type === 'workflow_started'
|
|
177
199
|
) {
|
|
178
200
|
startedTimes.set(key, ts);
|
|
179
|
-
//
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
201
|
+
// The queued duration is anchored on the first start event only —
|
|
202
|
+
// subsequent step_started events come from retries.
|
|
203
|
+
if (!firstStartedTimes.has(key)) {
|
|
204
|
+
firstStartedTimes.set(key, ts);
|
|
205
|
+
// If no explicit created event was seen, use the started time as created
|
|
206
|
+
if (!createdTimes.has(key)) {
|
|
207
|
+
createdTimes.set(key, ts);
|
|
208
|
+
}
|
|
209
|
+
const createdAt = createdTimes.get(key);
|
|
210
|
+
const info = durations.get(key) ?? {};
|
|
211
|
+
if (createdAt !== undefined) {
|
|
212
|
+
info.queued = ts - createdAt;
|
|
213
|
+
}
|
|
214
|
+
durations.set(key, info);
|
|
187
215
|
}
|
|
188
|
-
durations.set(key, info);
|
|
189
216
|
}
|
|
190
217
|
|
|
191
218
|
// Compute ran duration on terminal events
|
|
@@ -703,6 +730,14 @@ interface EventsListProps {
|
|
|
703
730
|
onDecrypt?: () => void;
|
|
704
731
|
/** Whether the encryption key is currently being fetched. */
|
|
705
732
|
isDecrypting?: boolean;
|
|
733
|
+
/** Run-level hint: the run contains encrypted data (from probe). */
|
|
734
|
+
hasEncryptedData?: boolean;
|
|
735
|
+
/** Fetch events for an exact correlation or event ID. */
|
|
736
|
+
onExactIdSearch?: (
|
|
737
|
+
id: string,
|
|
738
|
+
kind: ExactWorkflowSearchIdKind,
|
|
739
|
+
signal?: AbortSignal
|
|
740
|
+
) => Promise<ExactIdSearchResult>;
|
|
706
741
|
}
|
|
707
742
|
|
|
708
743
|
function EventRow({
|
|
@@ -725,6 +760,7 @@ function EventRow({
|
|
|
725
760
|
onCacheEventData,
|
|
726
761
|
encryptionKey,
|
|
727
762
|
onEncryptedDataDetected,
|
|
763
|
+
suppressGroupDimming = false,
|
|
728
764
|
}: {
|
|
729
765
|
event: Event;
|
|
730
766
|
index: number;
|
|
@@ -745,6 +781,8 @@ function EventRow({
|
|
|
745
781
|
onCacheEventData: (eventId: string, data: unknown) => void;
|
|
746
782
|
encryptionKey?: Uint8Array;
|
|
747
783
|
onEncryptedDataDetected?: () => void;
|
|
784
|
+
/** Exact-ID search results should not dim unrelated rows. */
|
|
785
|
+
suppressGroupDimming?: boolean;
|
|
748
786
|
}) {
|
|
749
787
|
const [isLoading, setIsLoading] = useState(false);
|
|
750
788
|
const [loadedEventData, setLoadedEventData] = useState<unknown | null>(
|
|
@@ -786,7 +824,7 @@ function EventRow({
|
|
|
786
824
|
|
|
787
825
|
const hasActive = activeGroupKey !== undefined;
|
|
788
826
|
const isRelated = rowGroupKey !== undefined && rowGroupKey === activeGroupKey;
|
|
789
|
-
const isDimmed = hasActive && !isRelated;
|
|
827
|
+
const isDimmed = hasActive && !isRelated && !suppressGroupDimming;
|
|
790
828
|
const isPulsing = hasActive && isRelated;
|
|
791
829
|
|
|
792
830
|
// Gutter state derived from selectedGroupRange
|
|
@@ -801,7 +839,15 @@ function EventRow({
|
|
|
801
839
|
selectedGroupRange !== null && index === selectedGroupRange.last;
|
|
802
840
|
|
|
803
841
|
const loadEventDetails = useCallback(async () => {
|
|
804
|
-
if (loadedEventData !== null
|
|
842
|
+
if (loadedEventData !== null) {
|
|
843
|
+
return;
|
|
844
|
+
}
|
|
845
|
+
if (cachedEventData !== null) {
|
|
846
|
+
setLoadedEventData(cachedEventData);
|
|
847
|
+
setHasAttemptedLoad(true);
|
|
848
|
+
return;
|
|
849
|
+
}
|
|
850
|
+
if (isLoading) {
|
|
805
851
|
return;
|
|
806
852
|
}
|
|
807
853
|
setIsLoading(true);
|
|
@@ -830,24 +876,20 @@ function EventRow({
|
|
|
830
876
|
}, [
|
|
831
877
|
event,
|
|
832
878
|
loadedEventData,
|
|
833
|
-
|
|
879
|
+
isLoading,
|
|
834
880
|
onLoadEventData,
|
|
835
881
|
onCacheEventData,
|
|
836
882
|
encryptionKey,
|
|
837
883
|
onEncryptedDataDetected,
|
|
884
|
+
cachedEventData,
|
|
838
885
|
]);
|
|
839
886
|
|
|
840
887
|
// Auto-load event data when remounting in expanded state without cached data
|
|
841
888
|
useEffect(() => {
|
|
842
|
-
if (
|
|
843
|
-
|
|
844
|
-
loadedEventData === null &&
|
|
845
|
-
!hasExistingEventData &&
|
|
846
|
-
!isLoading &&
|
|
847
|
-
!hasAttemptedLoad
|
|
848
|
-
) {
|
|
849
|
-
loadEventDetails();
|
|
889
|
+
if (!isExpanded || isLoading) {
|
|
890
|
+
return;
|
|
850
891
|
}
|
|
892
|
+
void loadEventDetails();
|
|
851
893
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
852
894
|
}, []);
|
|
853
895
|
|
|
@@ -875,8 +917,8 @@ function EventRow({
|
|
|
875
917
|
const handleRowClick = useCallback(() => {
|
|
876
918
|
onSelectGroup(rowGroupKey === selectedGroupKey ? undefined : rowGroupKey);
|
|
877
919
|
onToggleExpand(event.eventId);
|
|
878
|
-
if (!isExpanded
|
|
879
|
-
loadEventDetails();
|
|
920
|
+
if (!isExpanded) {
|
|
921
|
+
void loadEventDetails();
|
|
880
922
|
}
|
|
881
923
|
}, [
|
|
882
924
|
selectedGroupKey,
|
|
@@ -885,14 +927,16 @@ function EventRow({
|
|
|
885
927
|
onToggleExpand,
|
|
886
928
|
event.eventId,
|
|
887
929
|
isExpanded,
|
|
888
|
-
loadedEventData,
|
|
889
|
-
hasExistingEventData,
|
|
890
930
|
loadEventDetails,
|
|
891
931
|
]);
|
|
892
932
|
|
|
893
|
-
const
|
|
894
|
-
|
|
895
|
-
|
|
933
|
+
const mergedEventData =
|
|
934
|
+
loadedEventData ??
|
|
935
|
+
(hasExistingEventData
|
|
936
|
+
? (event as Event & { eventData: unknown }).eventData
|
|
937
|
+
: null);
|
|
938
|
+
|
|
939
|
+
const displayPayload = isLoading ? loadedEventData : mergedEventData;
|
|
896
940
|
|
|
897
941
|
const contentOpacity = isDimmed ? 0.3 : 1;
|
|
898
942
|
|
|
@@ -1076,8 +1120,8 @@ function EventRow({
|
|
|
1076
1120
|
)}
|
|
1077
1121
|
|
|
1078
1122
|
{/* Payload */}
|
|
1079
|
-
{
|
|
1080
|
-
<PayloadBlock data={
|
|
1123
|
+
{displayPayload != null ? (
|
|
1124
|
+
<PayloadBlock data={displayPayload} eventType={event.eventType} />
|
|
1081
1125
|
) : loadError ? (
|
|
1082
1126
|
<div
|
|
1083
1127
|
className="rounded-md border p-3 text-xs"
|
|
@@ -1090,7 +1134,7 @@ function EventRow({
|
|
|
1090
1134
|
{loadError}
|
|
1091
1135
|
</div>
|
|
1092
1136
|
) : isLoading ||
|
|
1093
|
-
(
|
|
1137
|
+
(loadedEventData === null &&
|
|
1094
1138
|
!hasAttemptedLoad &&
|
|
1095
1139
|
event.correlationId) ? (
|
|
1096
1140
|
<div className="flex flex-col gap-2 p-3">
|
|
@@ -1130,7 +1174,10 @@ export function EventListView({
|
|
|
1130
1174
|
onSortOrderChange,
|
|
1131
1175
|
onDecrypt,
|
|
1132
1176
|
isDecrypting = false,
|
|
1177
|
+
hasEncryptedData: hasEncryptedDataProp = false,
|
|
1178
|
+
onExactIdSearch,
|
|
1133
1179
|
}: EventsListProps) {
|
|
1180
|
+
const toast = useToast();
|
|
1134
1181
|
const [internalSortOrder, setInternalSortOrder] = useState<'asc' | 'desc'>(
|
|
1135
1182
|
'asc'
|
|
1136
1183
|
);
|
|
@@ -1146,25 +1193,42 @@ export function EventListView({
|
|
|
1146
1193
|
[onSortOrderChange]
|
|
1147
1194
|
);
|
|
1148
1195
|
|
|
1196
|
+
const [searchQuery, setSearchQuery] = useState('');
|
|
1197
|
+
const [searchResults, setSearchResults] = useState<Event[] | null>(null);
|
|
1198
|
+
const [searchResultsTruncated, setSearchResultsTruncated] = useState(false);
|
|
1199
|
+
const [searchError, setSearchError] = useState<string | null>(null);
|
|
1200
|
+
const [searchLoading, setSearchLoading] = useState(false);
|
|
1201
|
+
const [searchNotFound, setSearchNotFound] = useState(false);
|
|
1202
|
+
const searchRequestRef = useRef(0);
|
|
1203
|
+
const virtuosoRef = useRef<VirtuosoHandle>(null);
|
|
1204
|
+
|
|
1205
|
+
const parsedSearchId = useMemo(
|
|
1206
|
+
() => parseExactWorkflowSearchId(searchQuery),
|
|
1207
|
+
[searchQuery]
|
|
1208
|
+
);
|
|
1209
|
+
const isExactSearchActive = searchResults !== null;
|
|
1210
|
+
|
|
1149
1211
|
const sortedEvents = useMemo(() => {
|
|
1150
|
-
|
|
1212
|
+
const sourceEvents = isExactSearchActive ? searchResults : (events ?? []);
|
|
1213
|
+
if (sourceEvents.length === 0) return [];
|
|
1151
1214
|
const dir = effectiveSortOrder === 'desc' ? -1 : 1;
|
|
1152
|
-
return [...
|
|
1215
|
+
return [...sourceEvents].sort(
|
|
1153
1216
|
(a, b) =>
|
|
1154
1217
|
dir *
|
|
1155
1218
|
(new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime())
|
|
1156
1219
|
);
|
|
1157
|
-
}, [events, effectiveSortOrder]);
|
|
1220
|
+
}, [events, effectiveSortOrder, isExactSearchActive, searchResults]);
|
|
1158
1221
|
|
|
1159
1222
|
// Detect encrypted fields across all loaded events (inline eventData).
|
|
1160
1223
|
const hasEncryptedInlineData = useMemo(() => {
|
|
1161
|
-
|
|
1162
|
-
|
|
1224
|
+
const sourceEvents = isExactSearchActive ? searchResults : events;
|
|
1225
|
+
if (!sourceEvents) return false;
|
|
1226
|
+
for (const event of sourceEvents) {
|
|
1163
1227
|
const ed = (event as Record<string, unknown>).eventData;
|
|
1164
1228
|
if (hasEncryptedValues(ed)) return true;
|
|
1165
1229
|
}
|
|
1166
1230
|
return false;
|
|
1167
|
-
}, [events]);
|
|
1231
|
+
}, [events, isExactSearchActive, searchResults]);
|
|
1168
1232
|
|
|
1169
1233
|
// Tracks whether any expanded row's lazy-loaded data contained encrypted markers.
|
|
1170
1234
|
// Set to true by EventRow via onEncryptedDataDetected; never reset (sticky).
|
|
@@ -1174,11 +1238,16 @@ export function EventListView({
|
|
|
1174
1238
|
setFoundEncryptedInLazyData(true);
|
|
1175
1239
|
}, []);
|
|
1176
1240
|
|
|
1177
|
-
const hasEncryptedData =
|
|
1241
|
+
const hasEncryptedData =
|
|
1242
|
+
hasEncryptedDataProp || hasEncryptedInlineData || foundEncryptedInLazyData;
|
|
1178
1243
|
|
|
1179
1244
|
const { correlationNameMap, workflowName } = useMemo(
|
|
1180
|
-
() =>
|
|
1181
|
-
|
|
1245
|
+
() =>
|
|
1246
|
+
buildNameMaps(
|
|
1247
|
+
isExactSearchActive ? searchResults : (events ?? null),
|
|
1248
|
+
run ?? null
|
|
1249
|
+
),
|
|
1250
|
+
[events, isExactSearchActive, run, searchResults]
|
|
1182
1251
|
);
|
|
1183
1252
|
|
|
1184
1253
|
const durationMap = useMemo(
|
|
@@ -1268,68 +1337,139 @@ export function EventListView({
|
|
|
1268
1337
|
return first >= 0 ? { first, last } : null;
|
|
1269
1338
|
}, [activeGroupKey, sortedEvents]);
|
|
1270
1339
|
|
|
1271
|
-
const [searchQuery, setSearchQuery] = useState('');
|
|
1272
|
-
const virtuosoRef = useRef<VirtuosoHandle>(null);
|
|
1273
|
-
|
|
1274
|
-
const searchIndex = useMemo(() => {
|
|
1275
|
-
const entries: {
|
|
1276
|
-
fields: string[];
|
|
1277
|
-
groupKey?: string;
|
|
1278
|
-
eventId: string;
|
|
1279
|
-
index: number;
|
|
1280
|
-
}[] = [];
|
|
1281
|
-
for (let i = 0; i < sortedEvents.length; i++) {
|
|
1282
|
-
const ev = sortedEvents[i];
|
|
1283
|
-
const isRun = isRunLevel(ev.eventType);
|
|
1284
|
-
const name = isRun
|
|
1285
|
-
? (workflowName ?? '')
|
|
1286
|
-
: ev.correlationId
|
|
1287
|
-
? (correlationNameMap.get(ev.correlationId) ?? '')
|
|
1288
|
-
: '';
|
|
1289
|
-
entries.push({
|
|
1290
|
-
fields: [
|
|
1291
|
-
ev.eventId,
|
|
1292
|
-
ev.correlationId ?? '',
|
|
1293
|
-
ev.eventType,
|
|
1294
|
-
formatEventType(ev.eventType),
|
|
1295
|
-
name,
|
|
1296
|
-
].map((f) => f.toLowerCase()),
|
|
1297
|
-
groupKey: ev.correlationId ?? (isRun ? '__run__' : undefined),
|
|
1298
|
-
eventId: ev.eventId,
|
|
1299
|
-
index: i,
|
|
1300
|
-
});
|
|
1301
|
-
}
|
|
1302
|
-
return entries;
|
|
1303
|
-
}, [sortedEvents, correlationNameMap, workflowName]);
|
|
1304
|
-
|
|
1305
1340
|
useEffect(() => {
|
|
1306
|
-
const
|
|
1307
|
-
if (!
|
|
1341
|
+
const trimmed = searchQuery.trim();
|
|
1342
|
+
if (!trimmed) {
|
|
1343
|
+
searchRequestRef.current += 1;
|
|
1344
|
+
setSearchResults(null);
|
|
1345
|
+
setSearchResultsTruncated(false);
|
|
1346
|
+
setSearchError(null);
|
|
1347
|
+
setSearchLoading(false);
|
|
1348
|
+
setSearchNotFound(false);
|
|
1308
1349
|
setSelectedGroupKey(undefined);
|
|
1309
1350
|
return;
|
|
1310
1351
|
}
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1352
|
+
|
|
1353
|
+
const parsed = parseExactWorkflowSearchId(trimmed);
|
|
1354
|
+
if (!parsed || !onExactIdSearch) {
|
|
1355
|
+
setSearchResults(null);
|
|
1356
|
+
setSearchLoading(false);
|
|
1357
|
+
setSearchNotFound(false);
|
|
1358
|
+
return;
|
|
1359
|
+
}
|
|
1360
|
+
|
|
1361
|
+
const requestId = ++searchRequestRef.current;
|
|
1362
|
+
setSearchLoading(true);
|
|
1363
|
+
setSearchNotFound(false);
|
|
1364
|
+
setSearchError(null);
|
|
1365
|
+
|
|
1366
|
+
const abortController = new AbortController();
|
|
1367
|
+
|
|
1368
|
+
const timer = setTimeout(() => {
|
|
1369
|
+
void (async () => {
|
|
1370
|
+
try {
|
|
1371
|
+
const results = await onExactIdSearch(
|
|
1372
|
+
parsed.id,
|
|
1373
|
+
parsed.kind,
|
|
1374
|
+
abortController.signal
|
|
1375
|
+
);
|
|
1376
|
+
if (
|
|
1377
|
+
abortController.signal.aborted ||
|
|
1378
|
+
searchRequestRef.current !== requestId
|
|
1379
|
+
) {
|
|
1380
|
+
return;
|
|
1381
|
+
}
|
|
1382
|
+
|
|
1383
|
+
if (results.status === 'error') {
|
|
1384
|
+
setSearchResults([]);
|
|
1385
|
+
setSearchResultsTruncated(false);
|
|
1386
|
+
setSearchNotFound(false);
|
|
1387
|
+
setSearchError(results.message);
|
|
1388
|
+
setSelectedGroupKey(undefined);
|
|
1389
|
+
return;
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
if (
|
|
1393
|
+
results.status === 'not_found' ||
|
|
1394
|
+
(results.status === 'ok' && results.events.length === 0)
|
|
1395
|
+
) {
|
|
1396
|
+
setSearchResults([]);
|
|
1397
|
+
setSearchResultsTruncated(false);
|
|
1398
|
+
setSearchNotFound(true);
|
|
1399
|
+
setSearchError(null);
|
|
1400
|
+
setSelectedGroupKey(undefined);
|
|
1401
|
+
return;
|
|
1402
|
+
}
|
|
1403
|
+
|
|
1404
|
+
setSearchResults(results.events);
|
|
1405
|
+
setSearchResultsTruncated(Boolean(results.truncated));
|
|
1406
|
+
setSearchNotFound(false);
|
|
1407
|
+
setSearchError(null);
|
|
1408
|
+
setSelectedGroupKey(
|
|
1409
|
+
parsed.kind === 'event'
|
|
1410
|
+
? (() => {
|
|
1411
|
+
const first = results.events[0];
|
|
1412
|
+
if (!first) return undefined;
|
|
1413
|
+
return isRunLevel(first.eventType)
|
|
1414
|
+
? '__run__'
|
|
1415
|
+
: (first.correlationId ?? undefined);
|
|
1416
|
+
})()
|
|
1417
|
+
: parsed.id
|
|
1418
|
+
);
|
|
1419
|
+
virtuosoRef.current?.scrollToIndex({
|
|
1420
|
+
index: 0,
|
|
1421
|
+
align: 'start',
|
|
1422
|
+
behavior: 'smooth',
|
|
1423
|
+
});
|
|
1424
|
+
} catch {
|
|
1425
|
+
if (
|
|
1426
|
+
abortController.signal.aborted ||
|
|
1427
|
+
searchRequestRef.current !== requestId
|
|
1428
|
+
) {
|
|
1429
|
+
return;
|
|
1430
|
+
}
|
|
1431
|
+
setSearchResults([]);
|
|
1432
|
+
setSearchResultsTruncated(false);
|
|
1433
|
+
setSearchNotFound(false);
|
|
1434
|
+
setSearchError('Failed to search events. Try again.');
|
|
1435
|
+
setSelectedGroupKey(undefined);
|
|
1436
|
+
} finally {
|
|
1437
|
+
if (
|
|
1438
|
+
searchRequestRef.current === requestId &&
|
|
1439
|
+
!abortController.signal.aborted
|
|
1440
|
+
) {
|
|
1441
|
+
setSearchLoading(false);
|
|
1320
1442
|
}
|
|
1321
1443
|
}
|
|
1444
|
+
})();
|
|
1445
|
+
}, 300);
|
|
1446
|
+
|
|
1447
|
+
return () => {
|
|
1448
|
+
clearTimeout(timer);
|
|
1449
|
+
abortController.abort();
|
|
1450
|
+
};
|
|
1451
|
+
}, [searchQuery, onExactIdSearch]);
|
|
1452
|
+
|
|
1453
|
+
const handleSearchKeyDown = useCallback(
|
|
1454
|
+
(event: ReactKeyboardEvent<HTMLInputElement>) => {
|
|
1455
|
+
if (event.key !== 'Enter') {
|
|
1456
|
+
return;
|
|
1322
1457
|
}
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1458
|
+
|
|
1459
|
+
const trimmed = searchQuery.trim();
|
|
1460
|
+
if (
|
|
1461
|
+
!trimmed ||
|
|
1462
|
+
parseExactWorkflowSearchId(trimmed) ||
|
|
1463
|
+
!onExactIdSearch ||
|
|
1464
|
+
!looksLikeWorkflowIdSearchInput(trimmed)
|
|
1465
|
+
) {
|
|
1466
|
+
return;
|
|
1467
|
+
}
|
|
1468
|
+
|
|
1469
|
+
toast.info('Enter a full step ID, wait ID, hook ID, or event ID');
|
|
1470
|
+
},
|
|
1471
|
+
[searchQuery, onExactIdSearch, toast]
|
|
1472
|
+
);
|
|
1333
1473
|
|
|
1334
1474
|
// Track whether we've ever had events to distinguish initial load from refetch
|
|
1335
1475
|
const hasHadEventsRef = useRef(false);
|
|
@@ -1375,207 +1515,232 @@ export function EventListView({
|
|
|
1375
1515
|
);
|
|
1376
1516
|
}
|
|
1377
1517
|
|
|
1378
|
-
if (!isLoading && (!events || events.length === 0)) {
|
|
1379
|
-
return (
|
|
1380
|
-
<div
|
|
1381
|
-
className="flex items-center justify-center h-full text-sm"
|
|
1382
|
-
style={{ color: 'var(--ds-gray-700)' }}
|
|
1383
|
-
>
|
|
1384
|
-
No events found
|
|
1385
|
-
</div>
|
|
1386
|
-
);
|
|
1387
|
-
}
|
|
1388
|
-
|
|
1389
1518
|
return (
|
|
1390
|
-
<
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
<div
|
|
1394
|
-
style
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
display: 'flex',
|
|
1398
|
-
gap: 6,
|
|
1399
|
-
}}
|
|
1400
|
-
>
|
|
1401
|
-
<label
|
|
1519
|
+
<DecryptClickContext.Provider
|
|
1520
|
+
value={onDecrypt ? { onDecrypt, isDecrypting } : undefined}
|
|
1521
|
+
>
|
|
1522
|
+
<div className="h-full flex flex-col overflow-hidden">
|
|
1523
|
+
<style>{`@keyframes workflow-dot-pulse{0%{transform:scale(1);opacity:.7}70%,100%{transform:scale(2.2);opacity:0}}`}</style>
|
|
1524
|
+
{/* Search bar + sort */}
|
|
1525
|
+
<div
|
|
1402
1526
|
style={{
|
|
1527
|
+
padding: 6,
|
|
1528
|
+
backgroundColor: 'var(--ds-background-100)',
|
|
1403
1529
|
display: 'flex',
|
|
1404
|
-
|
|
1405
|
-
justifyContent: 'center',
|
|
1406
|
-
borderRadius: 6,
|
|
1407
|
-
boxShadow: '0 0 0 1px var(--ds-gray-alpha-400)',
|
|
1408
|
-
background: 'var(--ds-background-100)',
|
|
1409
|
-
height: 40,
|
|
1410
|
-
flex: 1,
|
|
1411
|
-
minWidth: 0,
|
|
1530
|
+
gap: 6,
|
|
1412
1531
|
}}
|
|
1413
1532
|
>
|
|
1414
|
-
<
|
|
1533
|
+
<label
|
|
1415
1534
|
style={{
|
|
1416
|
-
width: 40,
|
|
1417
|
-
height: 40,
|
|
1418
1535
|
display: 'flex',
|
|
1419
1536
|
alignItems: 'center',
|
|
1420
1537
|
justifyContent: 'center',
|
|
1421
|
-
|
|
1422
|
-
|
|
1538
|
+
borderRadius: 6,
|
|
1539
|
+
boxShadow: '0 0 0 1px var(--ds-gray-alpha-400)',
|
|
1540
|
+
background: 'var(--ds-background-100)',
|
|
1541
|
+
height: 40,
|
|
1542
|
+
flex: 1,
|
|
1543
|
+
minWidth: 0,
|
|
1423
1544
|
}}
|
|
1424
1545
|
>
|
|
1425
|
-
<
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1546
|
+
<div
|
|
1547
|
+
style={{
|
|
1548
|
+
width: 40,
|
|
1549
|
+
height: 40,
|
|
1550
|
+
display: 'flex',
|
|
1551
|
+
alignItems: 'center',
|
|
1552
|
+
justifyContent: 'center',
|
|
1553
|
+
color: 'var(--ds-gray-800)',
|
|
1554
|
+
flexShrink: 0,
|
|
1555
|
+
}}
|
|
1432
1556
|
>
|
|
1433
|
-
<
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1557
|
+
<svg
|
|
1558
|
+
width={16}
|
|
1559
|
+
height={16}
|
|
1560
|
+
viewBox="0 0 16 16"
|
|
1561
|
+
fill="none"
|
|
1562
|
+
aria-hidden="true"
|
|
1563
|
+
focusable="false"
|
|
1564
|
+
>
|
|
1565
|
+
<circle
|
|
1566
|
+
cx="7"
|
|
1567
|
+
cy="7"
|
|
1568
|
+
r="4.5"
|
|
1569
|
+
stroke="currentColor"
|
|
1570
|
+
strokeWidth="1.5"
|
|
1571
|
+
/>
|
|
1572
|
+
<path
|
|
1573
|
+
d="M11.5 11.5L14 14"
|
|
1574
|
+
stroke="currentColor"
|
|
1575
|
+
strokeWidth="1.5"
|
|
1576
|
+
strokeLinecap="round"
|
|
1577
|
+
/>
|
|
1578
|
+
</svg>
|
|
1579
|
+
</div>
|
|
1580
|
+
<input
|
|
1581
|
+
type="search"
|
|
1582
|
+
placeholder="Search by step ID, wait ID, hook ID, or event ID…"
|
|
1583
|
+
value={searchQuery}
|
|
1584
|
+
onChange={(e) => setSearchQuery(e.target.value)}
|
|
1585
|
+
onKeyDown={handleSearchKeyDown}
|
|
1586
|
+
disabled={!onExactIdSearch}
|
|
1587
|
+
title={
|
|
1588
|
+
onExactIdSearch
|
|
1589
|
+
? undefined
|
|
1590
|
+
: 'Exact ID search is unavailable in this view.'
|
|
1591
|
+
}
|
|
1592
|
+
style={{
|
|
1593
|
+
marginLeft: -16,
|
|
1594
|
+
paddingInline: 12,
|
|
1595
|
+
fontFamily: 'inherit',
|
|
1596
|
+
fontSize: 14,
|
|
1597
|
+
background: 'transparent',
|
|
1598
|
+
border: 'none',
|
|
1599
|
+
outline: 'none',
|
|
1600
|
+
height: 40,
|
|
1601
|
+
width: '100%',
|
|
1602
|
+
opacity: onExactIdSearch ? 1 : 0.5,
|
|
1603
|
+
cursor: onExactIdSearch ? 'text' : 'not-allowed',
|
|
1604
|
+
}}
|
|
1605
|
+
/>
|
|
1606
|
+
</label>
|
|
1607
|
+
<MenuDropdown
|
|
1608
|
+
options={SORT_OPTIONS}
|
|
1609
|
+
value={effectiveSortOrder}
|
|
1610
|
+
onChange={handleSortOrderChange}
|
|
1476
1611
|
/>
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
borderColor: 'var(--ds-gray-alpha-200)',
|
|
1485
|
-
color: 'var(--ds-gray-900)',
|
|
1486
|
-
backgroundColor: 'var(--ds-background-100)',
|
|
1487
|
-
}}
|
|
1488
|
-
>
|
|
1489
|
-
<div className="flex-shrink-0" style={{ width: GUTTER_WIDTH }} />
|
|
1490
|
-
<div className="w-5 flex-shrink-0" />
|
|
1491
|
-
<div className="min-w-0 px-4" style={{ flex: '2 1 0%' }}>
|
|
1492
|
-
Time
|
|
1493
|
-
</div>
|
|
1494
|
-
<div className="min-w-0 px-4" style={{ flex: '2 1 0%' }}>
|
|
1495
|
-
Event Type
|
|
1496
|
-
</div>
|
|
1497
|
-
<div className="min-w-0 px-4" style={{ flex: '2 1 0%' }}>
|
|
1498
|
-
Name
|
|
1499
|
-
</div>
|
|
1500
|
-
<div className="min-w-0 px-4" style={{ flex: '3 1 0%' }}>
|
|
1501
|
-
Correlation ID
|
|
1502
|
-
</div>
|
|
1503
|
-
<div className="min-w-0 px-4" style={{ flex: '3 1 0%' }}>
|
|
1504
|
-
Event ID
|
|
1612
|
+
{(hasEncryptedData || encryptionKey) && onDecrypt && (
|
|
1613
|
+
<DecryptButton
|
|
1614
|
+
decrypted={!!encryptionKey}
|
|
1615
|
+
loading={isDecrypting}
|
|
1616
|
+
onClick={onDecrypt}
|
|
1617
|
+
/>
|
|
1618
|
+
)}
|
|
1505
1619
|
</div>
|
|
1506
|
-
</div>
|
|
1507
1620
|
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
overscan={20}
|
|
1516
|
-
defaultItemHeight={40}
|
|
1517
|
-
endReached={() => {
|
|
1518
|
-
if (!hasMoreEvents || isLoadingMoreEvents) {
|
|
1519
|
-
return;
|
|
1520
|
-
}
|
|
1521
|
-
void onLoadMoreEvents?.();
|
|
1522
|
-
}}
|
|
1523
|
-
itemContent={(index: number) => {
|
|
1524
|
-
const ev = sortedEvents[index];
|
|
1525
|
-
return (
|
|
1526
|
-
<EventRow
|
|
1527
|
-
event={ev}
|
|
1528
|
-
index={index}
|
|
1529
|
-
isFirst={index === 0}
|
|
1530
|
-
isLast={index === sortedEvents.length - 1}
|
|
1531
|
-
isExpanded={expandedEventIds.has(ev.eventId)}
|
|
1532
|
-
onToggleExpand={toggleEventExpanded}
|
|
1533
|
-
activeGroupKey={activeGroupKey}
|
|
1534
|
-
selectedGroupKey={selectedGroupKey}
|
|
1535
|
-
selectedGroupRange={selectedGroupRange}
|
|
1536
|
-
correlationNameMap={correlationNameMap}
|
|
1537
|
-
workflowName={workflowName}
|
|
1538
|
-
durationMap={durationMap}
|
|
1539
|
-
onSelectGroup={onSelectGroup}
|
|
1540
|
-
onHoverGroup={onHoverGroup}
|
|
1541
|
-
onLoadEventData={onLoadEventData}
|
|
1542
|
-
cachedEventData={
|
|
1543
|
-
eventDataCacheRef.current.get(ev.eventId) ?? null
|
|
1544
|
-
}
|
|
1545
|
-
onCacheEventData={cacheEventData}
|
|
1546
|
-
encryptionKey={encryptionKey}
|
|
1547
|
-
onEncryptedDataDetected={handleEncryptedDataDetected}
|
|
1548
|
-
/>
|
|
1549
|
-
);
|
|
1621
|
+
{/* Header */}
|
|
1622
|
+
<div
|
|
1623
|
+
className="flex items-center gap-0 text-[13px] font-medium h-10 border-b flex-shrink-0"
|
|
1624
|
+
style={{
|
|
1625
|
+
borderColor: 'var(--ds-gray-alpha-200)',
|
|
1626
|
+
color: 'var(--ds-gray-900)',
|
|
1627
|
+
backgroundColor: 'var(--ds-background-100)',
|
|
1550
1628
|
}}
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1629
|
+
>
|
|
1630
|
+
<div className="flex-shrink-0" style={{ width: GUTTER_WIDTH }} />
|
|
1631
|
+
<div className="w-5 flex-shrink-0" />
|
|
1632
|
+
<div className="min-w-0 px-4" style={{ flex: '2 1 0%' }}>
|
|
1633
|
+
Time
|
|
1634
|
+
</div>
|
|
1635
|
+
<div className="min-w-0 px-4" style={{ flex: '2 1 0%' }}>
|
|
1636
|
+
Event Type
|
|
1637
|
+
</div>
|
|
1638
|
+
<div className="min-w-0 px-4" style={{ flex: '2 1 0%' }}>
|
|
1639
|
+
Name
|
|
1640
|
+
</div>
|
|
1641
|
+
<div className="min-w-0 px-4" style={{ flex: '3 1 0%' }}>
|
|
1642
|
+
Correlation ID
|
|
1643
|
+
</div>
|
|
1644
|
+
<div className="min-w-0 px-4" style={{ flex: '3 1 0%' }}>
|
|
1645
|
+
Event ID
|
|
1646
|
+
</div>
|
|
1647
|
+
</div>
|
|
1554
1648
|
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
<div className="pointer-events-auto">
|
|
1571
|
-
<LoadMoreButton
|
|
1572
|
-
loading={isLoadingMoreEvents}
|
|
1573
|
-
onClick={() => void onLoadMoreEvents?.()}
|
|
1574
|
-
/>
|
|
1575
|
-
</div>
|
|
1649
|
+
{/* Virtualized event rows or refetching skeleton */}
|
|
1650
|
+
{isRefetching || searchLoading ? (
|
|
1651
|
+
<RowsSkeleton />
|
|
1652
|
+
) : sortedEvents.length === 0 ? (
|
|
1653
|
+
<div
|
|
1654
|
+
className="flex flex-1 items-center justify-center px-6 text-center text-sm"
|
|
1655
|
+
style={{ color: 'var(--ds-gray-700)' }}
|
|
1656
|
+
>
|
|
1657
|
+
{searchNotFound && searchQuery.trim()
|
|
1658
|
+
? `No events found for ${searchQuery.trim()}`
|
|
1659
|
+
: searchError
|
|
1660
|
+
? searchError
|
|
1661
|
+
: parsedSearchId && searchQuery.trim() && !onExactIdSearch
|
|
1662
|
+
? 'Exact ID search is unavailable in this view.'
|
|
1663
|
+
: 'No events found'}
|
|
1576
1664
|
</div>
|
|
1665
|
+
) : (
|
|
1666
|
+
<Virtuoso
|
|
1667
|
+
ref={virtuosoRef}
|
|
1668
|
+
totalCount={sortedEvents.length}
|
|
1669
|
+
overscan={20}
|
|
1670
|
+
defaultItemHeight={40}
|
|
1671
|
+
endReached={() => {
|
|
1672
|
+
if (
|
|
1673
|
+
isExactSearchActive ||
|
|
1674
|
+
!hasMoreEvents ||
|
|
1675
|
+
isLoadingMoreEvents
|
|
1676
|
+
) {
|
|
1677
|
+
return;
|
|
1678
|
+
}
|
|
1679
|
+
void onLoadMoreEvents?.();
|
|
1680
|
+
}}
|
|
1681
|
+
itemContent={(index: number) => {
|
|
1682
|
+
const ev = sortedEvents[index];
|
|
1683
|
+
return (
|
|
1684
|
+
<EventRow
|
|
1685
|
+
event={ev}
|
|
1686
|
+
index={index}
|
|
1687
|
+
isFirst={index === 0}
|
|
1688
|
+
isLast={index === sortedEvents.length - 1}
|
|
1689
|
+
isExpanded={expandedEventIds.has(ev.eventId)}
|
|
1690
|
+
onToggleExpand={toggleEventExpanded}
|
|
1691
|
+
activeGroupKey={activeGroupKey}
|
|
1692
|
+
selectedGroupKey={selectedGroupKey}
|
|
1693
|
+
selectedGroupRange={selectedGroupRange}
|
|
1694
|
+
correlationNameMap={correlationNameMap}
|
|
1695
|
+
workflowName={workflowName}
|
|
1696
|
+
durationMap={durationMap}
|
|
1697
|
+
onSelectGroup={onSelectGroup}
|
|
1698
|
+
onHoverGroup={onHoverGroup}
|
|
1699
|
+
onLoadEventData={onLoadEventData}
|
|
1700
|
+
cachedEventData={
|
|
1701
|
+
eventDataCacheRef.current.get(ev.eventId) ?? null
|
|
1702
|
+
}
|
|
1703
|
+
onCacheEventData={cacheEventData}
|
|
1704
|
+
encryptionKey={encryptionKey}
|
|
1705
|
+
onEncryptedDataDetected={handleEncryptedDataDetected}
|
|
1706
|
+
suppressGroupDimming={isExactSearchActive}
|
|
1707
|
+
/>
|
|
1708
|
+
);
|
|
1709
|
+
}}
|
|
1710
|
+
style={{ flex: 1, minHeight: 0 }}
|
|
1711
|
+
/>
|
|
1577
1712
|
)}
|
|
1713
|
+
|
|
1714
|
+
{/* Fixed footer — count + load more */}
|
|
1715
|
+
<div
|
|
1716
|
+
className="relative flex-shrink-0 flex items-center h-10 border-t px-4 text-xs"
|
|
1717
|
+
style={{
|
|
1718
|
+
borderColor: 'var(--ds-gray-alpha-200)',
|
|
1719
|
+
color: 'var(--ds-gray-900)',
|
|
1720
|
+
backgroundColor: 'var(--ds-background-100)',
|
|
1721
|
+
}}
|
|
1722
|
+
>
|
|
1723
|
+
<span>
|
|
1724
|
+
{isExactSearchActive
|
|
1725
|
+
? searchError
|
|
1726
|
+
? searchError
|
|
1727
|
+
: searchNotFound
|
|
1728
|
+
? `No events found for ${searchQuery.trim()}`
|
|
1729
|
+
: `${sortedEvents.length} event${sortedEvents.length !== 1 ? 's' : ''} for ${searchQuery.trim()}${searchResultsTruncated ? ' (results may be truncated)' : ''}`
|
|
1730
|
+
: `${sortedEvents.length} event${sortedEvents.length !== 1 ? 's' : ''} loaded`}
|
|
1731
|
+
</span>
|
|
1732
|
+
{!isExactSearchActive && hasMoreEvents && (
|
|
1733
|
+
<div className="absolute inset-0 flex items-center justify-center pointer-events-none">
|
|
1734
|
+
<div className="pointer-events-auto">
|
|
1735
|
+
<LoadMoreButton
|
|
1736
|
+
loading={isLoadingMoreEvents}
|
|
1737
|
+
onClick={() => void onLoadMoreEvents?.()}
|
|
1738
|
+
/>
|
|
1739
|
+
</div>
|
|
1740
|
+
</div>
|
|
1741
|
+
)}
|
|
1742
|
+
</div>
|
|
1578
1743
|
</div>
|
|
1579
|
-
</
|
|
1744
|
+
</DecryptClickContext.Provider>
|
|
1580
1745
|
);
|
|
1581
1746
|
}
|