@workflow/web-shared 4.1.0-beta.47 → 4.1.0-beta.49
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 +26 -52
- package/dist/components/error-boundary.d.ts.map +1 -0
- package/dist/{error-boundary.js → components/error-boundary.js} +1 -1
- package/dist/components/error-boundary.js.map +1 -0
- package/dist/{event-list-view.d.ts → components/event-list-view.d.ts} +2 -3
- package/dist/components/event-list-view.d.ts.map +1 -0
- package/dist/{event-list-view.js → components/event-list-view.js} +9 -17
- package/dist/components/event-list-view.js.map +1 -0
- package/dist/{hook-actions.d.ts → components/hook-actions.d.ts} +2 -3
- package/dist/components/hook-actions.d.ts.map +1 -0
- package/dist/{hook-actions.js → components/hook-actions.js} +3 -4
- package/dist/components/hook-actions.js.map +1 -0
- package/dist/components/index.d.ts +10 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/index.js +8 -0
- package/dist/components/index.js.map +1 -0
- package/dist/components/run-trace-view.d.ts +22 -0
- package/dist/components/run-trace-view.d.ts.map +1 -0
- package/dist/components/run-trace-view.js +11 -0
- package/dist/components/run-trace-view.js.map +1 -0
- package/dist/components/sidebar/attribute-panel.d.ts.map +1 -0
- package/dist/{sidebar → components/sidebar}/attribute-panel.js +3 -3
- package/dist/components/sidebar/attribute-panel.js.map +1 -0
- package/dist/components/sidebar/conversation-view.d.ts.map +1 -0
- package/dist/components/sidebar/conversation-view.js.map +1 -0
- package/dist/components/sidebar/detail-card.d.ts.map +1 -0
- package/dist/components/sidebar/detail-card.js.map +1 -0
- package/dist/components/sidebar/entity-detail-panel.d.ts +32 -0
- package/dist/components/sidebar/entity-detail-panel.d.ts.map +1 -0
- package/dist/{sidebar → components/sidebar}/entity-detail-panel.js +61 -49
- package/dist/components/sidebar/entity-detail-panel.js.map +1 -0
- package/dist/components/sidebar/events-list.d.ts +8 -0
- package/dist/components/sidebar/events-list.d.ts.map +1 -0
- package/dist/components/sidebar/events-list.js +16 -0
- package/dist/components/sidebar/events-list.js.map +1 -0
- package/dist/components/sidebar/resolve-hook-modal.d.ts.map +1 -0
- package/dist/components/sidebar/resolve-hook-modal.js.map +1 -0
- package/dist/components/stream-viewer.d.ts +18 -0
- package/dist/components/stream-viewer.d.ts.map +1 -0
- package/dist/{stream-viewer.js → components/stream-viewer.js} +1 -59
- package/dist/components/stream-viewer.js.map +1 -0
- package/dist/components/trace-viewer/components/map.d.ts.map +1 -0
- package/dist/components/trace-viewer/components/map.js.map +1 -0
- package/dist/components/trace-viewer/components/markers.d.ts.map +1 -0
- package/dist/components/trace-viewer/components/markers.js.map +1 -0
- package/dist/components/trace-viewer/components/node.d.ts.map +1 -0
- package/dist/components/trace-viewer/components/node.js.map +1 -0
- package/dist/components/trace-viewer/components/search-input.d.ts.map +1 -0
- package/dist/components/trace-viewer/components/search-input.js.map +1 -0
- package/dist/components/trace-viewer/components/search.d.ts.map +1 -0
- package/dist/components/trace-viewer/components/search.js.map +1 -0
- package/dist/components/trace-viewer/components/span-detail-panel.d.ts.map +1 -0
- package/dist/components/trace-viewer/components/span-detail-panel.js.map +1 -0
- package/dist/components/trace-viewer/components/ui.d.ts.map +1 -0
- package/dist/components/trace-viewer/components/ui.js.map +1 -0
- package/dist/components/trace-viewer/components/zoom-button.d.ts.map +1 -0
- package/dist/components/trace-viewer/components/zoom-button.js.map +1 -0
- package/dist/components/trace-viewer/components/zoom-icons.d.ts.map +1 -0
- package/dist/components/trace-viewer/components/zoom-icons.js.map +1 -0
- package/dist/components/trace-viewer/context.d.ts.map +1 -0
- package/dist/components/trace-viewer/context.js.map +1 -0
- package/dist/components/trace-viewer/index.d.ts.map +1 -0
- package/dist/components/trace-viewer/index.js.map +1 -0
- package/dist/components/trace-viewer/trace-viewer.d.ts.map +1 -0
- package/dist/components/trace-viewer/trace-viewer.js.map +1 -0
- package/dist/components/trace-viewer/types.d.ts.map +1 -0
- package/dist/components/trace-viewer/types.js.map +1 -0
- package/dist/components/trace-viewer/util/constants.d.ts.map +1 -0
- package/dist/components/trace-viewer/util/constants.js.map +1 -0
- package/dist/components/trace-viewer/util/scrollbar-width.d.ts.map +1 -0
- package/dist/components/trace-viewer/util/scrollbar-width.js.map +1 -0
- package/dist/{trace-viewer → components/trace-viewer}/util/timing.d.ts +1 -1
- package/dist/components/trace-viewer/util/timing.d.ts.map +1 -0
- package/dist/{trace-viewer → components/trace-viewer}/util/timing.js +1 -1
- package/dist/components/trace-viewer/util/timing.js.map +1 -0
- package/dist/components/trace-viewer/util/tree.d.ts.map +1 -0
- package/dist/components/trace-viewer/util/tree.js.map +1 -0
- package/dist/components/trace-viewer/util/use-immediate-style.d.ts.map +1 -0
- package/dist/components/trace-viewer/util/use-immediate-style.js.map +1 -0
- package/dist/components/trace-viewer/util/use-streaming-spans.d.ts.map +1 -0
- package/dist/components/trace-viewer/util/use-streaming-spans.js.map +1 -0
- package/dist/components/trace-viewer/util/use-trackpad-zoom.d.ts.map +1 -0
- package/dist/components/trace-viewer/util/use-trackpad-zoom.js.map +1 -0
- package/dist/components/trace-viewer/worker.d.ts.map +1 -0
- package/dist/components/trace-viewer/worker.js.map +1 -0
- package/dist/components/workflow-trace-view.d.ts +24 -0
- package/dist/components/workflow-trace-view.d.ts.map +1 -0
- package/dist/components/workflow-trace-view.js +152 -0
- package/dist/components/workflow-trace-view.js.map +1 -0
- package/dist/components/workflow-traces/event-colors.d.ts.map +1 -0
- package/dist/components/workflow-traces/event-colors.js.map +1 -0
- package/dist/components/workflow-traces/trace-colors.d.ts.map +1 -0
- package/dist/components/workflow-traces/trace-colors.js.map +1 -0
- package/dist/components/workflow-traces/trace-span-construction.d.ts.map +1 -0
- package/dist/components/workflow-traces/trace-span-construction.js.map +1 -0
- package/dist/components/workflow-traces/trace-time-utils.d.ts.map +1 -0
- package/dist/components/workflow-traces/trace-time-utils.js.map +1 -0
- package/dist/index.d.ts +3 -13
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -9
- package/dist/index.js.map +1 -1
- package/package.json +15 -11
- package/src/components/error-boundary.tsx +79 -0
- package/src/components/event-list-view.tsx +429 -0
- package/src/components/hook-actions.tsx +167 -0
- package/src/components/index.d.ts +1 -0
- package/src/components/index.ts +23 -0
- package/src/components/run-trace-view.tsx +75 -0
- package/src/components/sidebar/attribute-panel.tsx +938 -0
- package/src/components/sidebar/conversation-view.tsx +235 -0
- package/src/components/sidebar/detail-card.tsx +43 -0
- package/src/components/sidebar/entity-detail-panel.tsx +338 -0
- package/src/components/sidebar/events-list.tsx +119 -0
- package/src/components/sidebar/resolve-hook-modal.tsx +219 -0
- package/src/components/stream-viewer.tsx +143 -0
- package/src/components/trace-viewer/components/map.tsx +226 -0
- package/src/components/trace-viewer/components/markers.tsx +564 -0
- package/src/components/trace-viewer/components/node.tsx +259 -0
- package/src/components/trace-viewer/components/search-input.tsx +52 -0
- package/src/components/trace-viewer/components/search.tsx +47 -0
- package/src/components/trace-viewer/components/span-detail-panel.tsx +650 -0
- package/src/components/trace-viewer/components/ui.tsx +156 -0
- package/src/components/trace-viewer/components/zoom-button.tsx +61 -0
- package/src/components/trace-viewer/components/zoom-icons.tsx +65 -0
- package/src/components/trace-viewer/context.tsx +633 -0
- package/src/components/trace-viewer/index.tsx +4 -0
- package/src/components/trace-viewer/modules.d.ts +16 -0
- package/src/components/trace-viewer/trace-viewer.module.css +1292 -0
- package/src/components/trace-viewer/trace-viewer.tsx +448 -0
- package/src/components/trace-viewer/types.ts +234 -0
- package/src/components/trace-viewer/util/constants.ts +8 -0
- package/src/components/trace-viewer/util/scrollbar-width.ts +13 -0
- package/src/components/trace-viewer/util/timing.ts +33 -0
- package/src/components/trace-viewer/util/tree.ts +277 -0
- package/src/components/trace-viewer/util/use-immediate-style.ts +38 -0
- package/src/components/trace-viewer/util/use-streaming-spans.ts +415 -0
- package/src/components/trace-viewer/util/use-trackpad-zoom.tsx +51 -0
- package/src/components/trace-viewer/worker.ts +128 -0
- package/src/components/ui/alert.tsx +59 -0
- package/src/components/ui/card.tsx +88 -0
- package/src/components/ui/error-card.tsx +65 -0
- package/src/components/ui/skeleton.tsx +15 -0
- package/src/components/workflow-trace-view.tsx +306 -0
- package/src/components/workflow-traces/event-colors.ts +94 -0
- package/src/components/workflow-traces/trace-colors.ts +112 -0
- package/src/components/workflow-traces/trace-span-construction.ts +299 -0
- package/src/components/workflow-traces/trace-time-utils.ts +50 -0
- package/src/hooks/use-dark-mode.ts +34 -0
- package/src/index.d.ts +1 -0
- package/src/index.ts +29 -0
- package/src/lib/event-analysis.ts +231 -0
- package/src/lib/utils.ts +166 -0
- package/dist/api/workflow-api-client.d.ts +0 -543
- package/dist/api/workflow-api-client.d.ts.map +0 -1
- package/dist/api/workflow-api-client.js +0 -953
- package/dist/api/workflow-api-client.js.map +0 -1
- package/dist/api/workflow-server-actions.d.ts +0 -230
- package/dist/api/workflow-server-actions.d.ts.map +0 -1
- package/dist/api/workflow-server-actions.js +0 -861
- package/dist/api/workflow-server-actions.js.map +0 -1
- package/dist/error-boundary.d.ts.map +0 -1
- package/dist/error-boundary.js.map +0 -1
- package/dist/event-list-view.d.ts.map +0 -1
- package/dist/event-list-view.js.map +0 -1
- package/dist/hook-actions.d.ts.map +0 -1
- package/dist/hook-actions.js.map +0 -1
- package/dist/run-trace-view.d.ts +0 -8
- package/dist/run-trace-view.d.ts.map +0 -1
- package/dist/run-trace-view.js +0 -15
- package/dist/run-trace-view.js.map +0 -1
- package/dist/sidebar/attribute-panel.d.ts.map +0 -1
- package/dist/sidebar/attribute-panel.js.map +0 -1
- package/dist/sidebar/conversation-view.d.ts.map +0 -1
- package/dist/sidebar/conversation-view.js.map +0 -1
- package/dist/sidebar/detail-card.d.ts.map +0 -1
- package/dist/sidebar/detail-card.js.map +0 -1
- package/dist/sidebar/entity-detail-panel.d.ts +0 -12
- package/dist/sidebar/entity-detail-panel.d.ts.map +0 -1
- package/dist/sidebar/entity-detail-panel.js.map +0 -1
- package/dist/sidebar/events-list.d.ts +0 -9
- package/dist/sidebar/events-list.d.ts.map +0 -1
- package/dist/sidebar/events-list.js +0 -36
- package/dist/sidebar/events-list.js.map +0 -1
- package/dist/sidebar/resolve-hook-modal.d.ts.map +0 -1
- package/dist/sidebar/resolve-hook-modal.js.map +0 -1
- package/dist/stream-viewer.d.ts +0 -13
- package/dist/stream-viewer.d.ts.map +0 -1
- package/dist/stream-viewer.js.map +0 -1
- package/dist/trace-viewer/components/map.d.ts.map +0 -1
- package/dist/trace-viewer/components/map.js.map +0 -1
- package/dist/trace-viewer/components/markers.d.ts.map +0 -1
- package/dist/trace-viewer/components/markers.js.map +0 -1
- package/dist/trace-viewer/components/node.d.ts.map +0 -1
- package/dist/trace-viewer/components/node.js.map +0 -1
- package/dist/trace-viewer/components/search-input.d.ts.map +0 -1
- package/dist/trace-viewer/components/search-input.js.map +0 -1
- package/dist/trace-viewer/components/search.d.ts.map +0 -1
- package/dist/trace-viewer/components/search.js.map +0 -1
- package/dist/trace-viewer/components/span-detail-panel.d.ts.map +0 -1
- package/dist/trace-viewer/components/span-detail-panel.js.map +0 -1
- package/dist/trace-viewer/components/ui.d.ts.map +0 -1
- package/dist/trace-viewer/components/ui.js.map +0 -1
- package/dist/trace-viewer/components/zoom-button.d.ts.map +0 -1
- package/dist/trace-viewer/components/zoom-button.js.map +0 -1
- package/dist/trace-viewer/components/zoom-icons.d.ts.map +0 -1
- package/dist/trace-viewer/components/zoom-icons.js.map +0 -1
- package/dist/trace-viewer/context.d.ts.map +0 -1
- package/dist/trace-viewer/context.js.map +0 -1
- package/dist/trace-viewer/index.d.ts.map +0 -1
- package/dist/trace-viewer/index.js.map +0 -1
- package/dist/trace-viewer/trace-viewer.d.ts.map +0 -1
- package/dist/trace-viewer/trace-viewer.js.map +0 -1
- package/dist/trace-viewer/types.d.ts.map +0 -1
- package/dist/trace-viewer/types.js.map +0 -1
- package/dist/trace-viewer/util/constants.d.ts.map +0 -1
- package/dist/trace-viewer/util/constants.js.map +0 -1
- package/dist/trace-viewer/util/scrollbar-width.d.ts.map +0 -1
- package/dist/trace-viewer/util/scrollbar-width.js.map +0 -1
- package/dist/trace-viewer/util/timing.d.ts.map +0 -1
- package/dist/trace-viewer/util/timing.js.map +0 -1
- package/dist/trace-viewer/util/tree.d.ts.map +0 -1
- package/dist/trace-viewer/util/tree.js.map +0 -1
- package/dist/trace-viewer/util/use-immediate-style.d.ts.map +0 -1
- package/dist/trace-viewer/util/use-immediate-style.js.map +0 -1
- package/dist/trace-viewer/util/use-streaming-spans.d.ts.map +0 -1
- package/dist/trace-viewer/util/use-streaming-spans.js.map +0 -1
- package/dist/trace-viewer/util/use-trackpad-zoom.d.ts.map +0 -1
- package/dist/trace-viewer/util/use-trackpad-zoom.js.map +0 -1
- package/dist/trace-viewer/worker.d.ts.map +0 -1
- package/dist/trace-viewer/worker.js.map +0 -1
- package/dist/workflow-trace-view.d.ts +0 -14
- package/dist/workflow-trace-view.d.ts.map +0 -1
- package/dist/workflow-trace-view.js +0 -135
- package/dist/workflow-trace-view.js.map +0 -1
- package/dist/workflow-traces/event-colors.d.ts.map +0 -1
- package/dist/workflow-traces/event-colors.js.map +0 -1
- package/dist/workflow-traces/trace-colors.d.ts.map +0 -1
- package/dist/workflow-traces/trace-colors.js.map +0 -1
- package/dist/workflow-traces/trace-span-construction.d.ts.map +0 -1
- package/dist/workflow-traces/trace-span-construction.js.map +0 -1
- package/dist/workflow-traces/trace-time-utils.d.ts.map +0 -1
- package/dist/workflow-traces/trace-time-utils.js.map +0 -1
- package/server/README.md +0 -1
- package/server/package.json +0 -4
- /package/dist/{error-boundary.d.ts → components/error-boundary.d.ts} +0 -0
- /package/dist/{sidebar → components/sidebar}/attribute-panel.d.ts +0 -0
- /package/dist/{sidebar → components/sidebar}/conversation-view.d.ts +0 -0
- /package/dist/{sidebar → components/sidebar}/conversation-view.js +0 -0
- /package/dist/{sidebar → components/sidebar}/detail-card.d.ts +0 -0
- /package/dist/{sidebar → components/sidebar}/detail-card.js +0 -0
- /package/dist/{sidebar → components/sidebar}/resolve-hook-modal.d.ts +0 -0
- /package/dist/{sidebar → components/sidebar}/resolve-hook-modal.js +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/components/map.d.ts +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/components/map.js +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/components/markers.d.ts +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/components/markers.js +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/components/node.d.ts +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/components/node.js +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/components/search-input.d.ts +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/components/search-input.js +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/components/search.d.ts +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/components/search.js +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/components/span-detail-panel.d.ts +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/components/span-detail-panel.js +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/components/ui.d.ts +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/components/ui.js +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/components/zoom-button.d.ts +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/components/zoom-button.js +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/components/zoom-icons.d.ts +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/components/zoom-icons.js +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/context.d.ts +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/context.js +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/index.d.ts +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/index.js +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/trace-viewer.d.ts +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/trace-viewer.js +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/trace-viewer.module.css +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/types.d.ts +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/types.js +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/util/constants.d.ts +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/util/constants.js +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/util/scrollbar-width.d.ts +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/util/scrollbar-width.js +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/util/tree.d.ts +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/util/tree.js +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/util/use-immediate-style.d.ts +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/util/use-immediate-style.js +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/util/use-streaming-spans.d.ts +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/util/use-streaming-spans.js +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/util/use-trackpad-zoom.d.ts +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/util/use-trackpad-zoom.js +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/worker.d.ts +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/worker.js +0 -0
- /package/dist/{workflow-traces → components/workflow-traces}/event-colors.d.ts +0 -0
- /package/dist/{workflow-traces → components/workflow-traces}/event-colors.js +0 -0
- /package/dist/{workflow-traces → components/workflow-traces}/trace-colors.d.ts +0 -0
- /package/dist/{workflow-traces → components/workflow-traces}/trace-colors.js +0 -0
- /package/dist/{workflow-traces → components/workflow-traces}/trace-span-construction.d.ts +0 -0
- /package/dist/{workflow-traces → components/workflow-traces}/trace-span-construction.js +0 -0
- /package/dist/{workflow-traces → components/workflow-traces}/trace-time-utils.d.ts +0 -0
- /package/dist/{workflow-traces → components/workflow-traces}/trace-time-utils.js +0 -0
|
@@ -1,953 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
import { VERCEL_403_ERROR_MESSAGE } from '@workflow/errors';
|
|
3
|
-
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
4
|
-
import { getPaginationDisplay } from '../lib/utils';
|
|
5
|
-
import { hookEventsToHookEntity, waitEventsToWaitEntity, } from '../workflow-traces/trace-span-construction';
|
|
6
|
-
import { cancelRun as cancelRunServerAction, fetchEvents, fetchEventsByCorrelationId, fetchHook, fetchHooks, fetchRun, fetchRuns, fetchStep, fetchSteps, fetchStreams, readStreamServerAction, recreateRun as recreateRunServerAction, reenqueueRun as reenqueueRunServerAction, resumeHook as resumeHookServerAction, wakeUpRun as wakeUpRunServerAction, } from './workflow-server-actions';
|
|
7
|
-
const MAX_ITEMS = 1000;
|
|
8
|
-
const LIVE_POLL_LIMIT = 10;
|
|
9
|
-
const LIVE_STEP_UPDATE_INTERVAL_MS = 2000;
|
|
10
|
-
const LIVE_UPDATE_INTERVAL_MS = 5000;
|
|
11
|
-
/**
|
|
12
|
-
* Helper to convert ServerActionError to WorkflowWebAPIError
|
|
13
|
-
*/
|
|
14
|
-
function createWorkflowAPIError(serverError) {
|
|
15
|
-
return new WorkflowWebAPIError(serverError.message, {
|
|
16
|
-
cause: serverError.cause,
|
|
17
|
-
request: serverError.request,
|
|
18
|
-
layer: serverError.layer,
|
|
19
|
-
});
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* Gets a user-facing error message from an error object.
|
|
23
|
-
* Handles both WorkflowWebAPIError and regular Error instances.
|
|
24
|
-
*/
|
|
25
|
-
export const getErrorMessage = (error) => {
|
|
26
|
-
if ('layer' in error && error.layer) {
|
|
27
|
-
if (error instanceof WorkflowWebAPIError) {
|
|
28
|
-
if (error.request?.status === 403) {
|
|
29
|
-
return VERCEL_403_ERROR_MESSAGE;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
// WorkflowWebAPIError already has user-facing messages
|
|
33
|
-
return error.message;
|
|
34
|
-
}
|
|
35
|
-
return error instanceof Error ? error.message : 'An error occurred';
|
|
36
|
-
};
|
|
37
|
-
/**
|
|
38
|
-
* Helper to handle server action results and throw WorkflowWebAPIError on failure
|
|
39
|
-
*/
|
|
40
|
-
export async function unwrapServerActionResult(promise) {
|
|
41
|
-
let result;
|
|
42
|
-
try {
|
|
43
|
-
result = await promise;
|
|
44
|
-
}
|
|
45
|
-
catch (error) {
|
|
46
|
-
result = {
|
|
47
|
-
success: false,
|
|
48
|
-
error: error,
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
if (!result.success) {
|
|
52
|
-
console.error('[web-api-client] error', result.error);
|
|
53
|
-
if (!result.error) {
|
|
54
|
-
return {
|
|
55
|
-
error: new WorkflowWebAPIError('Unknown error occurred', {
|
|
56
|
-
layer: 'client',
|
|
57
|
-
}),
|
|
58
|
-
result: null,
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
return {
|
|
62
|
-
error: createWorkflowAPIError(result.error),
|
|
63
|
-
result: null,
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
return { error: null, result: result.data };
|
|
67
|
-
}
|
|
68
|
-
/**
|
|
69
|
-
* Error instance for API and server-side errors.
|
|
70
|
-
* `error.message` will be a user-facing error message, to be displayed in UI.
|
|
71
|
-
* `error.cause` will be a developer-facing error message, to be displayed in logs.
|
|
72
|
-
*
|
|
73
|
-
* If the error originates from an HTTP request made from a server action,
|
|
74
|
-
* these fields will be populated:
|
|
75
|
-
* - `error.request` will be a JSON-serializable object representing the request made.
|
|
76
|
-
* - `error.layer` will be 'API'
|
|
77
|
-
*
|
|
78
|
-
* If the error originates from inside the server action, or there's an error with
|
|
79
|
-
* calling the server action, these fields will be populated:
|
|
80
|
-
* - `error.layer` will be 'server'
|
|
81
|
-
*/
|
|
82
|
-
export class WorkflowWebAPIError extends Error {
|
|
83
|
-
request;
|
|
84
|
-
layer;
|
|
85
|
-
constructor(message, options) {
|
|
86
|
-
super(message, { cause: options?.cause });
|
|
87
|
-
this.name = 'WorkflowWebAPIError';
|
|
88
|
-
this.request = options?.request;
|
|
89
|
-
this.layer = options?.layer;
|
|
90
|
-
if (options?.cause instanceof Error) {
|
|
91
|
-
this.stack = `${this.stack}\nCaused by: ${options.cause.stack}`;
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
/**
|
|
96
|
-
* Returns a list of runs with pagination control
|
|
97
|
-
*/
|
|
98
|
-
export function useWorkflowRuns(env, params) {
|
|
99
|
-
const { workflowName, status, limit = 10, sortOrder = 'desc' } = params;
|
|
100
|
-
const [cursor, setCursor] = useState(undefined);
|
|
101
|
-
const [hasMore, setHasMore] = useState(false);
|
|
102
|
-
const [currentPage, setCurrentPage] = useState(0);
|
|
103
|
-
const [pageHistory, setPageHistory] = useState([
|
|
104
|
-
undefined,
|
|
105
|
-
]);
|
|
106
|
-
const [maxPagesVisited, setMaxPagesVisited] = useState(1);
|
|
107
|
-
// Store PageResult for each page
|
|
108
|
-
const [allPageResults, setAllPageResults] = useState(new Map([[0, { data: null, isLoading: true, error: null }]]));
|
|
109
|
-
// Cache for fetched pages - key is cursor (or 'initial' for first page)
|
|
110
|
-
const pageCache = useRef(new Map());
|
|
111
|
-
const fetchPage = useCallback(async (pageIndex, pageCursor, force = false) => {
|
|
112
|
-
const cacheKey = pageCursor ?? 'initial';
|
|
113
|
-
// Set loading state for this page
|
|
114
|
-
setAllPageResults((prev) => {
|
|
115
|
-
const newMap = new Map(prev);
|
|
116
|
-
newMap.set(pageIndex, {
|
|
117
|
-
data: prev.get(pageIndex)?.data ?? null,
|
|
118
|
-
isLoading: true,
|
|
119
|
-
error: null,
|
|
120
|
-
});
|
|
121
|
-
return newMap;
|
|
122
|
-
});
|
|
123
|
-
// Check cache first unless force reload
|
|
124
|
-
if (!force && pageCache.current.has(cacheKey)) {
|
|
125
|
-
const cached = pageCache.current.get(cacheKey);
|
|
126
|
-
if (cached) {
|
|
127
|
-
setAllPageResults((prev) => {
|
|
128
|
-
const newMap = new Map(prev);
|
|
129
|
-
newMap.set(pageIndex, {
|
|
130
|
-
data: cached.data,
|
|
131
|
-
isLoading: false,
|
|
132
|
-
error: null,
|
|
133
|
-
});
|
|
134
|
-
return newMap;
|
|
135
|
-
});
|
|
136
|
-
setCursor(cached.cursor);
|
|
137
|
-
setHasMore(cached.hasMore);
|
|
138
|
-
return;
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
const { error, result } = await unwrapServerActionResult(fetchRuns(env, {
|
|
142
|
-
cursor: pageCursor,
|
|
143
|
-
sortOrder,
|
|
144
|
-
limit: limit,
|
|
145
|
-
workflowName,
|
|
146
|
-
status,
|
|
147
|
-
}));
|
|
148
|
-
if (error) {
|
|
149
|
-
setAllPageResults((prev) => {
|
|
150
|
-
const newMap = new Map(prev);
|
|
151
|
-
newMap.set(pageIndex, {
|
|
152
|
-
data: prev.get(pageIndex)?.data ?? null,
|
|
153
|
-
isLoading: false,
|
|
154
|
-
error,
|
|
155
|
-
});
|
|
156
|
-
return newMap;
|
|
157
|
-
});
|
|
158
|
-
return;
|
|
159
|
-
}
|
|
160
|
-
// Cache the result
|
|
161
|
-
pageCache.current.set(cacheKey, {
|
|
162
|
-
data: result.data,
|
|
163
|
-
cursor: result.cursor,
|
|
164
|
-
hasMore: result.hasMore,
|
|
165
|
-
});
|
|
166
|
-
setAllPageResults((prev) => {
|
|
167
|
-
const newMap = new Map(prev);
|
|
168
|
-
newMap.set(pageIndex, {
|
|
169
|
-
data: result.data,
|
|
170
|
-
isLoading: false,
|
|
171
|
-
error: null,
|
|
172
|
-
});
|
|
173
|
-
return newMap;
|
|
174
|
-
});
|
|
175
|
-
setCursor(result.cursor);
|
|
176
|
-
setHasMore(result.hasMore);
|
|
177
|
-
}, [env, workflowName, limit, sortOrder, status]);
|
|
178
|
-
// Initial load
|
|
179
|
-
// biome-ignore lint/correctness/useExhaustiveDependencies: Want to refetch first page on param change
|
|
180
|
-
useEffect(() => {
|
|
181
|
-
fetchPage(0, undefined, true);
|
|
182
|
-
}, [fetchPage, sortOrder, env, limit, workflowName, status]);
|
|
183
|
-
const nextPage = useCallback(() => {
|
|
184
|
-
if (hasMore && cursor) {
|
|
185
|
-
const newPage = currentPage + 1;
|
|
186
|
-
setPageHistory((prev) => [...prev, cursor]);
|
|
187
|
-
setCurrentPage(newPage);
|
|
188
|
-
setMaxPagesVisited((prev) => Math.max(prev, newPage + 1));
|
|
189
|
-
// Initialize next page if not already loaded
|
|
190
|
-
if (!allPageResults.has(newPage)) {
|
|
191
|
-
setAllPageResults((prev) => {
|
|
192
|
-
const newMap = new Map(prev);
|
|
193
|
-
newMap.set(newPage, { data: null, isLoading: true, error: null });
|
|
194
|
-
return newMap;
|
|
195
|
-
});
|
|
196
|
-
}
|
|
197
|
-
fetchPage(newPage, cursor);
|
|
198
|
-
}
|
|
199
|
-
}, [hasMore, cursor, fetchPage, currentPage, allPageResults]);
|
|
200
|
-
const previousPage = useCallback(() => {
|
|
201
|
-
if (currentPage > 0) {
|
|
202
|
-
const newPage = currentPage - 1;
|
|
203
|
-
const prevCursor = pageHistory[newPage];
|
|
204
|
-
setCurrentPage(newPage);
|
|
205
|
-
fetchPage(newPage, prevCursor);
|
|
206
|
-
}
|
|
207
|
-
}, [currentPage, pageHistory, fetchPage]);
|
|
208
|
-
const reload = useCallback(() => {
|
|
209
|
-
// Clear cache and results
|
|
210
|
-
pageCache.current.clear();
|
|
211
|
-
setAllPageResults(new Map([[0, { data: null, isLoading: true, error: null }]]));
|
|
212
|
-
// Reset to first page
|
|
213
|
-
setCurrentPage(0);
|
|
214
|
-
setPageHistory([undefined]);
|
|
215
|
-
setMaxPagesVisited(1);
|
|
216
|
-
// Force fetch first page
|
|
217
|
-
fetchPage(0, undefined, true);
|
|
218
|
-
}, [fetchPage]);
|
|
219
|
-
const refresh = useCallback(() => {
|
|
220
|
-
// Refetch current page without resetting state
|
|
221
|
-
// This preserves the existing data while loading, preventing flicker
|
|
222
|
-
const currentCursor = pageHistory[currentPage];
|
|
223
|
-
// Clear cache for current page to ensure fresh data
|
|
224
|
-
const cacheKey = currentCursor ?? 'initial';
|
|
225
|
-
pageCache.current.delete(cacheKey);
|
|
226
|
-
// Force fetch current page
|
|
227
|
-
fetchPage(currentPage, currentCursor, true);
|
|
228
|
-
}, [fetchPage, currentPage, pageHistory]);
|
|
229
|
-
const currentPageResult = allPageResults.get(currentPage) ?? {
|
|
230
|
-
data: null,
|
|
231
|
-
isLoading: true,
|
|
232
|
-
error: null,
|
|
233
|
-
};
|
|
234
|
-
// Compute global error (any page has error)
|
|
235
|
-
const globalError = Array.from(allPageResults.values()).find((p) => p.error)?.error ?? null;
|
|
236
|
-
// Compute global loading (any page is loading)
|
|
237
|
-
const globalLoading = Array.from(allPageResults.values()).some((p) => p.isLoading);
|
|
238
|
-
const totalPages = hasMore ? currentPage + 2 : currentPage + 1;
|
|
239
|
-
const currentPageNumber = currentPage + 1;
|
|
240
|
-
// Only show "+" if we're on the last visited page AND there are more pages
|
|
241
|
-
const isOnLastVisitedPage = currentPageNumber === maxPagesVisited;
|
|
242
|
-
const showPlus = isOnLastVisitedPage && hasMore;
|
|
243
|
-
const pageInfo = getPaginationDisplay(currentPageNumber, maxPagesVisited, showPlus);
|
|
244
|
-
const result = {
|
|
245
|
-
data: currentPageResult,
|
|
246
|
-
allData: Array.from(allPageResults.values()),
|
|
247
|
-
error: globalError,
|
|
248
|
-
isLoading: globalLoading,
|
|
249
|
-
currentPage,
|
|
250
|
-
totalPages,
|
|
251
|
-
nextPage,
|
|
252
|
-
previousPage,
|
|
253
|
-
hasNextPage: hasMore,
|
|
254
|
-
hasPreviousPage: currentPage > 0,
|
|
255
|
-
reload,
|
|
256
|
-
refresh,
|
|
257
|
-
pageInfo,
|
|
258
|
-
};
|
|
259
|
-
return result;
|
|
260
|
-
}
|
|
261
|
-
/**
|
|
262
|
-
* Returns a list of hooks with pagination control
|
|
263
|
-
*/
|
|
264
|
-
export function useWorkflowHooks(env, params) {
|
|
265
|
-
const { runId, limit = 10, sortOrder = 'desc' } = params;
|
|
266
|
-
const [cursor, setCursor] = useState(undefined);
|
|
267
|
-
const [hasMore, setHasMore] = useState(false);
|
|
268
|
-
const [currentPage, setCurrentPage] = useState(0);
|
|
269
|
-
const [pageHistory, setPageHistory] = useState([
|
|
270
|
-
undefined,
|
|
271
|
-
]);
|
|
272
|
-
const [maxPagesVisited, setMaxPagesVisited] = useState(1);
|
|
273
|
-
// Store PageResult for each page
|
|
274
|
-
const [allPageResults, setAllPageResults] = useState(new Map([[0, { data: null, isLoading: true, error: null }]]));
|
|
275
|
-
// Cache for fetched pages - key is cursor (or 'initial' for first page)
|
|
276
|
-
const pageCache = useRef(new Map());
|
|
277
|
-
const fetchPage = useCallback(async (pageIndex, pageCursor, force = false) => {
|
|
278
|
-
const cacheKey = pageCursor ?? 'initial';
|
|
279
|
-
// Set loading state for this page
|
|
280
|
-
setAllPageResults((prev) => {
|
|
281
|
-
const newMap = new Map(prev);
|
|
282
|
-
newMap.set(pageIndex, {
|
|
283
|
-
data: prev.get(pageIndex)?.data ?? null,
|
|
284
|
-
isLoading: true,
|
|
285
|
-
error: null,
|
|
286
|
-
});
|
|
287
|
-
return newMap;
|
|
288
|
-
});
|
|
289
|
-
// Check cache first unless force reload
|
|
290
|
-
if (!force && pageCache.current.has(cacheKey)) {
|
|
291
|
-
const cached = pageCache.current.get(cacheKey);
|
|
292
|
-
if (cached) {
|
|
293
|
-
setAllPageResults((prev) => {
|
|
294
|
-
const newMap = new Map(prev);
|
|
295
|
-
newMap.set(pageIndex, {
|
|
296
|
-
data: cached.data,
|
|
297
|
-
isLoading: false,
|
|
298
|
-
error: null,
|
|
299
|
-
});
|
|
300
|
-
return newMap;
|
|
301
|
-
});
|
|
302
|
-
setCursor(cached.cursor);
|
|
303
|
-
setHasMore(cached.hasMore);
|
|
304
|
-
return;
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
const { error, result } = await unwrapServerActionResult(fetchHooks(env, {
|
|
308
|
-
runId,
|
|
309
|
-
cursor: pageCursor,
|
|
310
|
-
sortOrder,
|
|
311
|
-
limit: limit,
|
|
312
|
-
}));
|
|
313
|
-
if (error) {
|
|
314
|
-
setAllPageResults((prev) => {
|
|
315
|
-
const newMap = new Map(prev);
|
|
316
|
-
newMap.set(pageIndex, {
|
|
317
|
-
data: prev.get(pageIndex)?.data ?? null,
|
|
318
|
-
isLoading: false,
|
|
319
|
-
error,
|
|
320
|
-
});
|
|
321
|
-
return newMap;
|
|
322
|
-
});
|
|
323
|
-
return;
|
|
324
|
-
}
|
|
325
|
-
// Cache the result
|
|
326
|
-
pageCache.current.set(cacheKey, {
|
|
327
|
-
data: result.data,
|
|
328
|
-
cursor: result.cursor,
|
|
329
|
-
hasMore: result.hasMore,
|
|
330
|
-
});
|
|
331
|
-
setAllPageResults((prev) => {
|
|
332
|
-
const newMap = new Map(prev);
|
|
333
|
-
newMap.set(pageIndex, {
|
|
334
|
-
data: result.data,
|
|
335
|
-
isLoading: false,
|
|
336
|
-
error: null,
|
|
337
|
-
});
|
|
338
|
-
return newMap;
|
|
339
|
-
});
|
|
340
|
-
setCursor(result.cursor);
|
|
341
|
-
setHasMore(result.hasMore);
|
|
342
|
-
}, [env, runId, limit, sortOrder]);
|
|
343
|
-
// Initial load
|
|
344
|
-
useEffect(() => {
|
|
345
|
-
fetchPage(0, undefined);
|
|
346
|
-
}, [fetchPage]);
|
|
347
|
-
const nextPage = useCallback(() => {
|
|
348
|
-
if (hasMore && cursor) {
|
|
349
|
-
const newPage = currentPage + 1;
|
|
350
|
-
setPageHistory((prev) => [...prev, cursor]);
|
|
351
|
-
setCurrentPage(newPage);
|
|
352
|
-
setMaxPagesVisited((prev) => Math.max(prev, newPage + 1));
|
|
353
|
-
// Initialize next page if not already loaded
|
|
354
|
-
if (!allPageResults.has(newPage)) {
|
|
355
|
-
setAllPageResults((prev) => {
|
|
356
|
-
const newMap = new Map(prev);
|
|
357
|
-
newMap.set(newPage, { data: null, isLoading: true, error: null });
|
|
358
|
-
return newMap;
|
|
359
|
-
});
|
|
360
|
-
}
|
|
361
|
-
fetchPage(newPage, cursor);
|
|
362
|
-
}
|
|
363
|
-
}, [hasMore, cursor, fetchPage, currentPage, allPageResults]);
|
|
364
|
-
const previousPage = useCallback(() => {
|
|
365
|
-
if (currentPage > 0) {
|
|
366
|
-
const newPage = currentPage - 1;
|
|
367
|
-
const prevCursor = pageHistory[newPage];
|
|
368
|
-
setCurrentPage(newPage);
|
|
369
|
-
fetchPage(newPage, prevCursor);
|
|
370
|
-
}
|
|
371
|
-
}, [currentPage, pageHistory, fetchPage]);
|
|
372
|
-
const reload = useCallback(() => {
|
|
373
|
-
// Clear cache and results
|
|
374
|
-
pageCache.current.clear();
|
|
375
|
-
setAllPageResults(new Map([[0, { data: null, isLoading: true, error: null }]]));
|
|
376
|
-
// Reset to first page
|
|
377
|
-
setCurrentPage(0);
|
|
378
|
-
setPageHistory([undefined]);
|
|
379
|
-
setMaxPagesVisited(1);
|
|
380
|
-
// Force fetch first page
|
|
381
|
-
fetchPage(0, undefined, true);
|
|
382
|
-
}, [fetchPage]);
|
|
383
|
-
const refresh = useCallback(() => {
|
|
384
|
-
// Refetch current page without resetting state
|
|
385
|
-
// This preserves the existing data while loading, preventing flicker
|
|
386
|
-
const currentCursor = pageHistory[currentPage];
|
|
387
|
-
// Clear cache for current page to ensure fresh data
|
|
388
|
-
const cacheKey = currentCursor ?? 'initial';
|
|
389
|
-
pageCache.current.delete(cacheKey);
|
|
390
|
-
// Force fetch current page
|
|
391
|
-
fetchPage(currentPage, currentCursor, true);
|
|
392
|
-
}, [fetchPage, currentPage, pageHistory]);
|
|
393
|
-
const currentPageResult = allPageResults.get(currentPage) ?? {
|
|
394
|
-
data: null,
|
|
395
|
-
isLoading: true,
|
|
396
|
-
error: null,
|
|
397
|
-
};
|
|
398
|
-
// Compute global error (any page has error)
|
|
399
|
-
const globalError = Array.from(allPageResults.values()).find((p) => p.error)?.error ?? null;
|
|
400
|
-
// Compute global loading (any page is loading)
|
|
401
|
-
const globalLoading = Array.from(allPageResults.values()).some((p) => p.isLoading);
|
|
402
|
-
const totalPages = hasMore ? currentPage + 2 : currentPage + 1;
|
|
403
|
-
const currentPageNumber = currentPage + 1;
|
|
404
|
-
// Only show "+" if we're on the last visited page AND there are more pages
|
|
405
|
-
const isOnLastVisitedPage = currentPageNumber === maxPagesVisited;
|
|
406
|
-
const showPlus = isOnLastVisitedPage && hasMore;
|
|
407
|
-
const pageInfo = getPaginationDisplay(currentPageNumber, maxPagesVisited, showPlus);
|
|
408
|
-
return {
|
|
409
|
-
data: currentPageResult,
|
|
410
|
-
allData: Array.from(allPageResults.values()),
|
|
411
|
-
error: globalError,
|
|
412
|
-
isLoading: globalLoading,
|
|
413
|
-
currentPage,
|
|
414
|
-
totalPages,
|
|
415
|
-
nextPage,
|
|
416
|
-
previousPage,
|
|
417
|
-
hasNextPage: hasMore,
|
|
418
|
-
hasPreviousPage: currentPage > 0,
|
|
419
|
-
reload,
|
|
420
|
-
refresh,
|
|
421
|
-
pageInfo,
|
|
422
|
-
};
|
|
423
|
-
}
|
|
424
|
-
// Helper function to exhaustively fetch steps
|
|
425
|
-
async function fetchAllSteps(env, runId) {
|
|
426
|
-
let stepsData = [];
|
|
427
|
-
let stepsCursor;
|
|
428
|
-
while (true) {
|
|
429
|
-
const { error, result } = await unwrapServerActionResult(fetchSteps(env, runId, {
|
|
430
|
-
cursor: stepsCursor,
|
|
431
|
-
sortOrder: 'asc',
|
|
432
|
-
limit: 100,
|
|
433
|
-
}));
|
|
434
|
-
// TODO: We're not handling errors well for infinite fetches
|
|
435
|
-
if (error) {
|
|
436
|
-
break;
|
|
437
|
-
}
|
|
438
|
-
stepsData = [...stepsData, ...result.data];
|
|
439
|
-
if (!result.hasMore || !result.cursor || stepsData.length >= MAX_ITEMS) {
|
|
440
|
-
break;
|
|
441
|
-
}
|
|
442
|
-
stepsCursor = result.cursor;
|
|
443
|
-
}
|
|
444
|
-
return { data: stepsData, cursor: stepsCursor };
|
|
445
|
-
}
|
|
446
|
-
// Helper function to exhaustively fetch hooks
|
|
447
|
-
async function fetchAllHooks(env, runId) {
|
|
448
|
-
let hooksData = [];
|
|
449
|
-
let hooksCursor;
|
|
450
|
-
while (true) {
|
|
451
|
-
const { error, result } = await unwrapServerActionResult(fetchHooks(env, {
|
|
452
|
-
runId,
|
|
453
|
-
cursor: hooksCursor,
|
|
454
|
-
sortOrder: 'asc',
|
|
455
|
-
limit: 100,
|
|
456
|
-
}));
|
|
457
|
-
if (error) {
|
|
458
|
-
break;
|
|
459
|
-
}
|
|
460
|
-
hooksData = [...hooksData, ...result.data];
|
|
461
|
-
if (!result.hasMore || !result.cursor || hooksData.length >= MAX_ITEMS) {
|
|
462
|
-
break;
|
|
463
|
-
}
|
|
464
|
-
hooksCursor = result.cursor;
|
|
465
|
-
}
|
|
466
|
-
return { data: hooksData, cursor: hooksCursor };
|
|
467
|
-
}
|
|
468
|
-
// Helper function to exhaustively fetch events
|
|
469
|
-
async function fetchAllEvents(env, runId) {
|
|
470
|
-
let eventsData = [];
|
|
471
|
-
let eventsCursor;
|
|
472
|
-
while (true) {
|
|
473
|
-
const { error, result } = await unwrapServerActionResult(fetchEvents(env, runId, {
|
|
474
|
-
cursor: eventsCursor,
|
|
475
|
-
sortOrder: 'asc',
|
|
476
|
-
limit: 1000,
|
|
477
|
-
}));
|
|
478
|
-
if (error) {
|
|
479
|
-
break;
|
|
480
|
-
}
|
|
481
|
-
eventsData = [...eventsData, ...result.data];
|
|
482
|
-
if (!result.hasMore || !result.cursor || eventsData.length >= MAX_ITEMS) {
|
|
483
|
-
break;
|
|
484
|
-
}
|
|
485
|
-
eventsCursor = result.cursor;
|
|
486
|
-
}
|
|
487
|
-
return { data: eventsData, cursor: eventsCursor };
|
|
488
|
-
}
|
|
489
|
-
/**
|
|
490
|
-
* Returns (and keeps up-to-date) all data related to a run.
|
|
491
|
-
* Items returned will _not_ have resolved data (like input/output values).
|
|
492
|
-
*/
|
|
493
|
-
export function useWorkflowTraceViewerData(env, runId, options = {}) {
|
|
494
|
-
const { live = false } = options;
|
|
495
|
-
const [run, setRun] = useState(null);
|
|
496
|
-
const [steps, setSteps] = useState([]);
|
|
497
|
-
const [hooks, setHooks] = useState([]);
|
|
498
|
-
const [events, setEvents] = useState([]);
|
|
499
|
-
const [loading, setLoading] = useState(true);
|
|
500
|
-
const [auxiliaryDataLoading, setAuxiliaryDataLoading] = useState(false);
|
|
501
|
-
const [error, setError] = useState(null);
|
|
502
|
-
const [stepsCursor, setStepsCursor] = useState();
|
|
503
|
-
const [hooksCursor, setHooksCursor] = useState();
|
|
504
|
-
const [eventsCursor, setEventsCursor] = useState();
|
|
505
|
-
const isFetchingRef = useRef(false);
|
|
506
|
-
const [initialLoadCompleted, setInitialLoadCompleted] = useState(false);
|
|
507
|
-
// Fetch all data for a run
|
|
508
|
-
const fetchAllData = useCallback(async () => {
|
|
509
|
-
if (isFetchingRef.current) {
|
|
510
|
-
return;
|
|
511
|
-
}
|
|
512
|
-
isFetchingRef.current = true;
|
|
513
|
-
setLoading(true);
|
|
514
|
-
setAuxiliaryDataLoading(true);
|
|
515
|
-
setError(null);
|
|
516
|
-
const promises = [
|
|
517
|
-
unwrapServerActionResult(fetchRun(env, runId)).then(({ error, result }) => {
|
|
518
|
-
if (error) {
|
|
519
|
-
setError(error);
|
|
520
|
-
return;
|
|
521
|
-
}
|
|
522
|
-
setRun(result);
|
|
523
|
-
return result;
|
|
524
|
-
}),
|
|
525
|
-
fetchAllSteps(env, runId).then((result) => {
|
|
526
|
-
setSteps(result.data);
|
|
527
|
-
setStepsCursor(result.cursor);
|
|
528
|
-
}),
|
|
529
|
-
fetchAllHooks(env, runId).then((result) => {
|
|
530
|
-
setHooks(result.data);
|
|
531
|
-
setHooksCursor(result.cursor);
|
|
532
|
-
}),
|
|
533
|
-
fetchAllEvents(env, runId).then((result) => {
|
|
534
|
-
setEvents(result.data);
|
|
535
|
-
setEventsCursor(result.cursor);
|
|
536
|
-
}),
|
|
537
|
-
];
|
|
538
|
-
const results = await Promise.allSettled(promises);
|
|
539
|
-
setLoading(false);
|
|
540
|
-
setAuxiliaryDataLoading(false);
|
|
541
|
-
setInitialLoadCompleted(true);
|
|
542
|
-
isFetchingRef.current = false;
|
|
543
|
-
// Just doing the first error, but would be nice to show multiple
|
|
544
|
-
const error = results.find((result) => result.status === 'rejected')
|
|
545
|
-
?.reason;
|
|
546
|
-
if (error) {
|
|
547
|
-
setError(error);
|
|
548
|
-
return;
|
|
549
|
-
}
|
|
550
|
-
}, [env, runId]);
|
|
551
|
-
// Helper to merge steps by ID
|
|
552
|
-
const mergeSteps = useCallback((prev, newData) => {
|
|
553
|
-
const combined = [...prev, ...newData];
|
|
554
|
-
const uniqueById = new Map(combined.map((s) => [s.stepId, s]));
|
|
555
|
-
return Array.from(uniqueById.values());
|
|
556
|
-
}, []);
|
|
557
|
-
// Helper to merge hooks by ID
|
|
558
|
-
const mergeHooks = useCallback((prev, newData) => {
|
|
559
|
-
const combined = [...prev, ...newData];
|
|
560
|
-
const uniqueById = new Map(combined.map((h) => [h.hookId, h]));
|
|
561
|
-
return Array.from(uniqueById.values());
|
|
562
|
-
}, []);
|
|
563
|
-
// Helper to merge events by ID
|
|
564
|
-
const mergeEvents = useCallback((prev, newData) => {
|
|
565
|
-
const combined = [...prev, ...newData];
|
|
566
|
-
const uniqueById = new Map(combined.map((e) => [e.eventId, e]));
|
|
567
|
-
return Array.from(uniqueById.values());
|
|
568
|
-
}, []);
|
|
569
|
-
const pollRun = useCallback(async () => {
|
|
570
|
-
if (run?.completedAt) {
|
|
571
|
-
return false;
|
|
572
|
-
}
|
|
573
|
-
const { error, result } = await unwrapServerActionResult(fetchRun(env, runId));
|
|
574
|
-
if (error) {
|
|
575
|
-
setError(error);
|
|
576
|
-
return false;
|
|
577
|
-
}
|
|
578
|
-
setRun(result);
|
|
579
|
-
return true;
|
|
580
|
-
}, [env, runId, run?.completedAt]);
|
|
581
|
-
// Poll for new steps
|
|
582
|
-
const pollSteps = useCallback(async () => {
|
|
583
|
-
const { error, result } = await unwrapServerActionResult(fetchSteps(env, runId, {
|
|
584
|
-
cursor: stepsCursor,
|
|
585
|
-
sortOrder: 'asc',
|
|
586
|
-
limit: LIVE_POLL_LIMIT,
|
|
587
|
-
}));
|
|
588
|
-
if (error) {
|
|
589
|
-
setError(error);
|
|
590
|
-
return false;
|
|
591
|
-
}
|
|
592
|
-
if (result.data.length > 0) {
|
|
593
|
-
setSteps((prev) => mergeSteps(prev, result.data));
|
|
594
|
-
// We intentionally leave the cursor where it is, unless we're at the end of the page
|
|
595
|
-
// in which case we roll over. This is so that we re-fetch existing steps, to ensure
|
|
596
|
-
// their status gets updated.
|
|
597
|
-
if (result.cursor && result.hasMore) {
|
|
598
|
-
setStepsCursor(result.cursor);
|
|
599
|
-
}
|
|
600
|
-
return true;
|
|
601
|
-
}
|
|
602
|
-
return false;
|
|
603
|
-
}, [env, runId, stepsCursor, mergeSteps]);
|
|
604
|
-
// Poll for new hooks
|
|
605
|
-
const pollHooks = useCallback(async () => {
|
|
606
|
-
const { error, result } = await unwrapServerActionResult(fetchHooks(env, {
|
|
607
|
-
runId,
|
|
608
|
-
cursor: hooksCursor,
|
|
609
|
-
sortOrder: 'asc',
|
|
610
|
-
limit: LIVE_POLL_LIMIT,
|
|
611
|
-
}));
|
|
612
|
-
if (error) {
|
|
613
|
-
setError(error);
|
|
614
|
-
return false;
|
|
615
|
-
}
|
|
616
|
-
if (result.data.length > 0) {
|
|
617
|
-
setHooks((prev) => mergeHooks(prev, result.data));
|
|
618
|
-
if (result.cursor) {
|
|
619
|
-
setHooksCursor(result.cursor);
|
|
620
|
-
}
|
|
621
|
-
return true;
|
|
622
|
-
}
|
|
623
|
-
return false;
|
|
624
|
-
}, [env, runId, hooksCursor, mergeHooks]);
|
|
625
|
-
// Poll for new events
|
|
626
|
-
const pollEvents = useCallback(async () => {
|
|
627
|
-
const { error, result } = await unwrapServerActionResult(fetchEvents(env, runId, {
|
|
628
|
-
cursor: eventsCursor,
|
|
629
|
-
sortOrder: 'asc',
|
|
630
|
-
limit: LIVE_POLL_LIMIT,
|
|
631
|
-
}));
|
|
632
|
-
if (error) {
|
|
633
|
-
setError(error);
|
|
634
|
-
return false;
|
|
635
|
-
}
|
|
636
|
-
if (result.data.length > 0) {
|
|
637
|
-
setEvents((prev) => mergeEvents(prev, result.data));
|
|
638
|
-
if (result.cursor) {
|
|
639
|
-
setEventsCursor(result.cursor);
|
|
640
|
-
}
|
|
641
|
-
return true;
|
|
642
|
-
}
|
|
643
|
-
return false;
|
|
644
|
-
}, [env, runId, eventsCursor, mergeEvents]);
|
|
645
|
-
// Update function for live polling
|
|
646
|
-
const update = useCallback(async (stepsOnly = false) => {
|
|
647
|
-
if (isFetchingRef.current || !initialLoadCompleted) {
|
|
648
|
-
return { foundNewItems: false };
|
|
649
|
-
}
|
|
650
|
-
let foundNewItems = false;
|
|
651
|
-
try {
|
|
652
|
-
const [_, stepsUpdated, hooksUpdated, eventsUpdated] = await Promise.all([
|
|
653
|
-
stepsOnly ? Promise.resolve(false) : pollRun(),
|
|
654
|
-
pollSteps(),
|
|
655
|
-
stepsOnly ? Promise.resolve(false) : pollHooks(),
|
|
656
|
-
stepsOnly ? Promise.resolve(false) : pollEvents(),
|
|
657
|
-
]);
|
|
658
|
-
foundNewItems = stepsUpdated || hooksUpdated || eventsUpdated;
|
|
659
|
-
}
|
|
660
|
-
catch (err) {
|
|
661
|
-
console.error('Update error:', err);
|
|
662
|
-
}
|
|
663
|
-
return { foundNewItems };
|
|
664
|
-
}, [pollSteps, pollHooks, pollEvents, initialLoadCompleted, pollRun]);
|
|
665
|
-
// Initial load
|
|
666
|
-
useEffect(() => {
|
|
667
|
-
fetchAllData();
|
|
668
|
-
}, [fetchAllData]);
|
|
669
|
-
// Live polling
|
|
670
|
-
useEffect(() => {
|
|
671
|
-
if (!live || !initialLoadCompleted || run?.completedAt) {
|
|
672
|
-
return;
|
|
673
|
-
}
|
|
674
|
-
const interval = setInterval(() => {
|
|
675
|
-
update();
|
|
676
|
-
}, LIVE_UPDATE_INTERVAL_MS);
|
|
677
|
-
const stepInterval = setInterval(() => {
|
|
678
|
-
update(true);
|
|
679
|
-
}, LIVE_STEP_UPDATE_INTERVAL_MS);
|
|
680
|
-
return () => {
|
|
681
|
-
clearInterval(interval);
|
|
682
|
-
clearInterval(stepInterval);
|
|
683
|
-
};
|
|
684
|
-
}, [live, initialLoadCompleted, update, run?.completedAt]);
|
|
685
|
-
return {
|
|
686
|
-
run: run ?? {},
|
|
687
|
-
steps,
|
|
688
|
-
hooks,
|
|
689
|
-
events,
|
|
690
|
-
loading,
|
|
691
|
-
auxiliaryDataLoading,
|
|
692
|
-
error,
|
|
693
|
-
update,
|
|
694
|
-
};
|
|
695
|
-
}
|
|
696
|
-
// Helper function to fetch resource and get correlation ID
|
|
697
|
-
async function fetchResourceWithCorrelationId(env, resource, resourceId, options = {}) {
|
|
698
|
-
let resourceData;
|
|
699
|
-
let correlationId;
|
|
700
|
-
const resolveData = options.resolveData ?? 'all';
|
|
701
|
-
if (resource === 'run') {
|
|
702
|
-
const { error, result } = await unwrapServerActionResult(fetchRun(env, resourceId, resolveData));
|
|
703
|
-
if (error) {
|
|
704
|
-
throw error;
|
|
705
|
-
}
|
|
706
|
-
resourceData = result;
|
|
707
|
-
correlationId = resourceData.runId;
|
|
708
|
-
}
|
|
709
|
-
else if (resource === 'step') {
|
|
710
|
-
const { runId } = options;
|
|
711
|
-
if (!runId) {
|
|
712
|
-
throw new WorkflowWebAPIError('runId is required for step resource', {
|
|
713
|
-
layer: 'client',
|
|
714
|
-
});
|
|
715
|
-
}
|
|
716
|
-
const { error, result } = await unwrapServerActionResult(fetchStep(env, runId, resourceId, resolveData));
|
|
717
|
-
if (error) {
|
|
718
|
-
throw error;
|
|
719
|
-
}
|
|
720
|
-
resourceData = result;
|
|
721
|
-
correlationId = resourceData.stepId;
|
|
722
|
-
}
|
|
723
|
-
else if (resource === 'hook') {
|
|
724
|
-
const { error, result } = await unwrapServerActionResult(fetchHook(env, resourceId, resolveData));
|
|
725
|
-
if (error) {
|
|
726
|
-
throw error;
|
|
727
|
-
}
|
|
728
|
-
resourceData = result;
|
|
729
|
-
correlationId = resourceData.hookId;
|
|
730
|
-
}
|
|
731
|
-
else {
|
|
732
|
-
throw new WorkflowWebAPIError(`Unknown resource type: ${resource}`, {
|
|
733
|
-
layer: 'client',
|
|
734
|
-
});
|
|
735
|
-
}
|
|
736
|
-
return { data: resourceData, correlationId };
|
|
737
|
-
}
|
|
738
|
-
/**
|
|
739
|
-
* Returns (and keeps up-to-date) data inherent to a specific run/step/hook,
|
|
740
|
-
* resolving input/output/metadata, AND loading all related events with full event data.
|
|
741
|
-
*/
|
|
742
|
-
export function useWorkflowResourceData(env, resource, resourceId, options = {}) {
|
|
743
|
-
const { refreshInterval = 0, runId } = options;
|
|
744
|
-
const [data, setData] = useState(null);
|
|
745
|
-
// const [events, setEvents] = useState<Event[]>([]);
|
|
746
|
-
const [loading, setLoading] = useState(true);
|
|
747
|
-
const [error, setError] = useState(null);
|
|
748
|
-
const fetchData = useCallback(async () => {
|
|
749
|
-
setData(null);
|
|
750
|
-
setError(null);
|
|
751
|
-
if (resource === 'hook' || resource === 'sleep') {
|
|
752
|
-
const { error, result } = await unwrapServerActionResult(fetchEventsByCorrelationId(env, resourceId, {
|
|
753
|
-
sortOrder: 'asc',
|
|
754
|
-
limit: 100,
|
|
755
|
-
withData: true,
|
|
756
|
-
}));
|
|
757
|
-
if (error) {
|
|
758
|
-
setError(error);
|
|
759
|
-
return;
|
|
760
|
-
}
|
|
761
|
-
const events = result.data;
|
|
762
|
-
const data = resource === 'hook'
|
|
763
|
-
? hookEventsToHookEntity(events)
|
|
764
|
-
: waitEventsToWaitEntity(events);
|
|
765
|
-
if (data === null) {
|
|
766
|
-
setError(new Error(`Failed to load ${resource} details: missing required event data`));
|
|
767
|
-
return;
|
|
768
|
-
}
|
|
769
|
-
setData(data);
|
|
770
|
-
return;
|
|
771
|
-
}
|
|
772
|
-
setLoading(true);
|
|
773
|
-
// Fetch resource with full data
|
|
774
|
-
try {
|
|
775
|
-
const { data: resourceData } = await fetchResourceWithCorrelationId(env, resource, resourceId, {
|
|
776
|
-
runId,
|
|
777
|
-
});
|
|
778
|
-
setData(resourceData);
|
|
779
|
-
}
|
|
780
|
-
catch (error) {
|
|
781
|
-
if (error instanceof Error) {
|
|
782
|
-
setError(error);
|
|
783
|
-
}
|
|
784
|
-
else {
|
|
785
|
-
setError(new Error(String(error)));
|
|
786
|
-
}
|
|
787
|
-
return;
|
|
788
|
-
}
|
|
789
|
-
finally {
|
|
790
|
-
setLoading(false);
|
|
791
|
-
}
|
|
792
|
-
// // Fetch events by correlation ID
|
|
793
|
-
// const eventsData = await fetchAllEventsByCorrelationId(
|
|
794
|
-
// env,
|
|
795
|
-
// correlationId
|
|
796
|
-
// );
|
|
797
|
-
// setEvents(eventsData);
|
|
798
|
-
}, [env, resource, resourceId, runId]);
|
|
799
|
-
// Initial load
|
|
800
|
-
useEffect(() => {
|
|
801
|
-
fetchData();
|
|
802
|
-
}, [fetchData]);
|
|
803
|
-
// Refresh interval
|
|
804
|
-
useEffect(() => {
|
|
805
|
-
if (!refreshInterval || refreshInterval <= 0) {
|
|
806
|
-
return;
|
|
807
|
-
}
|
|
808
|
-
const interval = setInterval(fetchData, refreshInterval);
|
|
809
|
-
return () => clearInterval(interval);
|
|
810
|
-
}, [refreshInterval, fetchData]);
|
|
811
|
-
return {
|
|
812
|
-
data,
|
|
813
|
-
// events,
|
|
814
|
-
loading,
|
|
815
|
-
error,
|
|
816
|
-
refresh: fetchData,
|
|
817
|
-
};
|
|
818
|
-
}
|
|
819
|
-
/**
|
|
820
|
-
* Cancel a workflow run
|
|
821
|
-
*/
|
|
822
|
-
export async function cancelRun(env, runId) {
|
|
823
|
-
const { error } = await unwrapServerActionResult(cancelRunServerAction(env, runId));
|
|
824
|
-
if (error) {
|
|
825
|
-
throw error;
|
|
826
|
-
}
|
|
827
|
-
}
|
|
828
|
-
/**
|
|
829
|
-
* Start a new workflow run
|
|
830
|
-
*/
|
|
831
|
-
export async function recreateRun(env, runId) {
|
|
832
|
-
const { error, result: resultData } = await unwrapServerActionResult(recreateRunServerAction(env, runId));
|
|
833
|
-
if (error) {
|
|
834
|
-
throw error;
|
|
835
|
-
}
|
|
836
|
-
return resultData;
|
|
837
|
-
}
|
|
838
|
-
/**
|
|
839
|
-
* Wake up a workflow run by re-enqueuing it
|
|
840
|
-
*/
|
|
841
|
-
export async function reenqueueRun(env, runId) {
|
|
842
|
-
const { error } = await unwrapServerActionResult(reenqueueRunServerAction(env, runId));
|
|
843
|
-
if (error) {
|
|
844
|
-
throw error;
|
|
845
|
-
}
|
|
846
|
-
}
|
|
847
|
-
/**
|
|
848
|
-
* Wake up a workflow run by interrupting any pending sleep() calls
|
|
849
|
-
*/
|
|
850
|
-
export async function wakeUpRun(env, runId, options) {
|
|
851
|
-
const { error, result: resultData } = await unwrapServerActionResult(wakeUpRunServerAction(env, runId, options));
|
|
852
|
-
if (error) {
|
|
853
|
-
throw error;
|
|
854
|
-
}
|
|
855
|
-
return resultData;
|
|
856
|
-
}
|
|
857
|
-
/**
|
|
858
|
-
* Resume a hook by sending a JSON payload
|
|
859
|
-
*/
|
|
860
|
-
export async function resumeHook(env, token, payload) {
|
|
861
|
-
const { error, result: resultData } = await unwrapServerActionResult(resumeHookServerAction(env, token, payload));
|
|
862
|
-
if (error) {
|
|
863
|
-
throw error;
|
|
864
|
-
}
|
|
865
|
-
return resultData;
|
|
866
|
-
}
|
|
867
|
-
function isServerActionError(value) {
|
|
868
|
-
return (typeof value === 'object' &&
|
|
869
|
-
value !== null &&
|
|
870
|
-
'message' in value &&
|
|
871
|
-
'layer' in value &&
|
|
872
|
-
'cause' in value &&
|
|
873
|
-
'request' in value);
|
|
874
|
-
}
|
|
875
|
-
export async function readStream(env, streamId, startIndex) {
|
|
876
|
-
try {
|
|
877
|
-
const stream = await readStreamServerAction(env, streamId, startIndex);
|
|
878
|
-
if (!stream) {
|
|
879
|
-
throw new WorkflowWebAPIError('Failed to read stream', {
|
|
880
|
-
layer: 'client',
|
|
881
|
-
});
|
|
882
|
-
}
|
|
883
|
-
if (isServerActionError(stream)) {
|
|
884
|
-
throw new WorkflowWebAPIError(stream.message, {
|
|
885
|
-
layer: 'client',
|
|
886
|
-
cause: stream.cause,
|
|
887
|
-
request: stream.request,
|
|
888
|
-
});
|
|
889
|
-
}
|
|
890
|
-
return stream;
|
|
891
|
-
}
|
|
892
|
-
catch (error) {
|
|
893
|
-
if (error instanceof WorkflowWebAPIError) {
|
|
894
|
-
throw error;
|
|
895
|
-
}
|
|
896
|
-
throw new WorkflowWebAPIError('Failed to read stream', {
|
|
897
|
-
layer: 'client',
|
|
898
|
-
cause: error,
|
|
899
|
-
});
|
|
900
|
-
}
|
|
901
|
-
}
|
|
902
|
-
/**
|
|
903
|
-
* List all stream IDs for a run
|
|
904
|
-
*/
|
|
905
|
-
export async function listStreams(env, runId) {
|
|
906
|
-
const { error, result } = await unwrapServerActionResult(fetchStreams(env, runId));
|
|
907
|
-
if (error) {
|
|
908
|
-
throw error;
|
|
909
|
-
}
|
|
910
|
-
return result;
|
|
911
|
-
}
|
|
912
|
-
const STREAMS_REFRESH_INTERVAL_MS = 10000;
|
|
913
|
-
/**
|
|
914
|
-
* Hook to fetch and manage stream list for a run
|
|
915
|
-
*/
|
|
916
|
-
export function useWorkflowStreams(env, runId, refreshInterval = STREAMS_REFRESH_INTERVAL_MS) {
|
|
917
|
-
const [streams, setStreams] = useState([]);
|
|
918
|
-
const [loading, setLoading] = useState(true);
|
|
919
|
-
const [error, setError] = useState(null);
|
|
920
|
-
const fetchData = useCallback(async () => {
|
|
921
|
-
setLoading(true);
|
|
922
|
-
setError(null);
|
|
923
|
-
try {
|
|
924
|
-
const result = await listStreams(env, runId);
|
|
925
|
-
setStreams(result);
|
|
926
|
-
}
|
|
927
|
-
catch (err) {
|
|
928
|
-
setError(err instanceof Error ? err : new Error(String(err)));
|
|
929
|
-
}
|
|
930
|
-
finally {
|
|
931
|
-
setLoading(false);
|
|
932
|
-
}
|
|
933
|
-
}, [env, runId]);
|
|
934
|
-
// Initial load
|
|
935
|
-
useEffect(() => {
|
|
936
|
-
fetchData();
|
|
937
|
-
}, [fetchData]);
|
|
938
|
-
// Auto-refresh interval
|
|
939
|
-
useEffect(() => {
|
|
940
|
-
if (!refreshInterval || refreshInterval <= 0) {
|
|
941
|
-
return;
|
|
942
|
-
}
|
|
943
|
-
const interval = setInterval(fetchData, refreshInterval);
|
|
944
|
-
return () => clearInterval(interval);
|
|
945
|
-
}, [refreshInterval, fetchData]);
|
|
946
|
-
return {
|
|
947
|
-
streams,
|
|
948
|
-
loading,
|
|
949
|
-
error,
|
|
950
|
-
refresh: fetchData,
|
|
951
|
-
};
|
|
952
|
-
}
|
|
953
|
-
//# sourceMappingURL=workflow-api-client.js.map
|