@ryanfw/prompt-orchestration-pipeline 0.6.0 → 0.8.0
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 -2
- package/package.json +1 -2
- package/src/api/validators/json.js +39 -0
- package/src/components/DAGGrid.jsx +392 -303
- package/src/components/JobCard.jsx +13 -11
- package/src/components/JobDetail.jsx +41 -71
- package/src/components/JobTable.jsx +32 -22
- package/src/components/Layout.jsx +0 -21
- package/src/components/LiveText.jsx +47 -0
- package/src/components/TaskDetailSidebar.jsx +216 -0
- package/src/components/TimerText.jsx +82 -0
- package/src/components/ui/RestartJobModal.jsx +140 -0
- package/src/components/ui/toast.jsx +138 -0
- package/src/config/models.js +322 -0
- package/src/config/statuses.js +119 -0
- package/src/core/config.js +2 -164
- package/src/core/file-io.js +1 -1
- package/src/core/module-loader.js +54 -40
- package/src/core/pipeline-runner.js +52 -26
- package/src/core/status-writer.js +147 -3
- package/src/core/symlink-bridge.js +55 -0
- package/src/core/symlink-utils.js +94 -0
- package/src/core/task-runner.js +267 -443
- package/src/llm/index.js +167 -52
- package/src/pages/Code.jsx +57 -3
- package/src/pages/PipelineDetail.jsx +92 -22
- package/src/pages/PromptPipelineDashboard.jsx +15 -36
- package/src/providers/anthropic.js +83 -69
- package/src/providers/base.js +52 -0
- package/src/providers/deepseek.js +17 -34
- package/src/providers/gemini.js +226 -0
- package/src/providers/openai.js +36 -106
- package/src/providers/zhipu.js +136 -0
- package/src/ui/client/adapters/job-adapter.js +16 -26
- package/src/ui/client/api.js +134 -0
- package/src/ui/client/hooks/useJobDetailWithUpdates.js +65 -178
- package/src/ui/client/index.css +9 -0
- package/src/ui/client/index.html +1 -0
- package/src/ui/client/main.jsx +18 -15
- package/src/ui/client/time-store.js +161 -0
- package/src/ui/config-bridge.js +15 -24
- package/src/ui/config-bridge.node.js +15 -24
- package/src/ui/dist/assets/{index-WgJUlSmE.js → index-DqkbzXZ1.js} +1408 -771
- package/src/ui/dist/assets/style-DBF9NQGk.css +62 -0
- package/src/ui/dist/index.html +3 -2
- package/src/ui/public/favicon.svg +12 -0
- package/src/ui/server.js +231 -38
- package/src/ui/transformers/status-transformer.js +18 -31
- package/src/ui/watcher.js +5 -1
- package/src/utils/dag.js +8 -4
- package/src/utils/duration.js +13 -19
- package/src/utils/formatters.js +27 -0
- package/src/utils/geometry-equality.js +83 -0
- package/src/utils/pipelines.js +5 -1
- package/src/utils/time-utils.js +40 -0
- package/src/utils/token-cost-calculator.js +4 -7
- package/src/utils/ui.jsx +14 -16
- package/src/components/ui/select.jsx +0 -27
- package/src/lib/utils.js +0 -6
- package/src/ui/client/hooks/useTicker.js +0 -26
- package/src/ui/config-bridge.browser.js +0 -149
- package/src/ui/dist/assets/style-x0V-5m8e.css +0 -62
|
@@ -520,11 +520,11 @@ function requireReact_production() {
|
|
|
520
520
|
react_production.useState = function(initialState) {
|
|
521
521
|
return ReactSharedInternals.H.useState(initialState);
|
|
522
522
|
};
|
|
523
|
-
react_production.useSyncExternalStore = function(
|
|
523
|
+
react_production.useSyncExternalStore = function(subscribe2, getSnapshot2, getServerSnapshot2) {
|
|
524
524
|
return ReactSharedInternals.H.useSyncExternalStore(
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
525
|
+
subscribe2,
|
|
526
|
+
getSnapshot2,
|
|
527
|
+
getServerSnapshot2
|
|
528
528
|
);
|
|
529
529
|
};
|
|
530
530
|
react_production.useTransition = function() {
|
|
@@ -3180,15 +3180,15 @@ function requireReactDomClient_production() {
|
|
|
3180
3180
|
return value;
|
|
3181
3181
|
}
|
|
3182
3182
|
var AbortControllerLocal = "undefined" !== typeof AbortController ? AbortController : function() {
|
|
3183
|
-
var
|
|
3183
|
+
var listeners2 = [], signal = this.signal = {
|
|
3184
3184
|
aborted: false,
|
|
3185
3185
|
addEventListener: function(type, listener) {
|
|
3186
|
-
|
|
3186
|
+
listeners2.push(listener);
|
|
3187
3187
|
}
|
|
3188
3188
|
};
|
|
3189
3189
|
this.abort = function() {
|
|
3190
3190
|
signal.aborted = true;
|
|
3191
|
-
|
|
3191
|
+
listeners2.forEach(function(listener) {
|
|
3192
3192
|
return listener();
|
|
3193
3193
|
});
|
|
3194
3194
|
};
|
|
@@ -3234,33 +3234,33 @@ function requireReactDomClient_production() {
|
|
|
3234
3234
|
function pingEngtangledActionScope() {
|
|
3235
3235
|
if (0 === --currentEntangledPendingCount && null !== currentEntangledListeners) {
|
|
3236
3236
|
null !== currentEntangledActionThenable && (currentEntangledActionThenable.status = "fulfilled");
|
|
3237
|
-
var
|
|
3237
|
+
var listeners2 = currentEntangledListeners;
|
|
3238
3238
|
currentEntangledListeners = null;
|
|
3239
3239
|
currentEntangledLane = 0;
|
|
3240
3240
|
currentEntangledActionThenable = null;
|
|
3241
|
-
for (var i2 = 0; i2 <
|
|
3241
|
+
for (var i2 = 0; i2 < listeners2.length; i2++) (0, listeners2[i2])();
|
|
3242
3242
|
}
|
|
3243
3243
|
}
|
|
3244
3244
|
function chainThenableValue(thenable, result) {
|
|
3245
|
-
var
|
|
3245
|
+
var listeners2 = [], thenableWithOverride = {
|
|
3246
3246
|
status: "pending",
|
|
3247
3247
|
value: null,
|
|
3248
3248
|
reason: null,
|
|
3249
3249
|
then: function(resolve) {
|
|
3250
|
-
|
|
3250
|
+
listeners2.push(resolve);
|
|
3251
3251
|
}
|
|
3252
3252
|
};
|
|
3253
3253
|
thenable.then(
|
|
3254
3254
|
function() {
|
|
3255
3255
|
thenableWithOverride.status = "fulfilled";
|
|
3256
3256
|
thenableWithOverride.value = result;
|
|
3257
|
-
for (var i2 = 0; i2 <
|
|
3257
|
+
for (var i2 = 0; i2 < listeners2.length; i2++) (0, listeners2[i2])(result);
|
|
3258
3258
|
},
|
|
3259
3259
|
function(error) {
|
|
3260
3260
|
thenableWithOverride.status = "rejected";
|
|
3261
3261
|
thenableWithOverride.reason = error;
|
|
3262
|
-
for (error = 0; error <
|
|
3263
|
-
(0,
|
|
3262
|
+
for (error = 0; error < listeners2.length; error++)
|
|
3263
|
+
(0, listeners2[error])(void 0);
|
|
3264
3264
|
}
|
|
3265
3265
|
);
|
|
3266
3266
|
return thenableWithOverride;
|
|
@@ -4327,22 +4327,22 @@ function requireReactDomClient_production() {
|
|
|
4327
4327
|
}
|
|
4328
4328
|
return [newState, dispatch];
|
|
4329
4329
|
}
|
|
4330
|
-
function updateSyncExternalStore(
|
|
4330
|
+
function updateSyncExternalStore(subscribe2, getSnapshot2, getServerSnapshot2) {
|
|
4331
4331
|
var fiber = currentlyRenderingFiber, hook = updateWorkInProgressHook(), isHydrating$jscomp$0 = isHydrating;
|
|
4332
4332
|
if (isHydrating$jscomp$0) {
|
|
4333
|
-
if (void 0 ===
|
|
4334
|
-
|
|
4335
|
-
} else
|
|
4333
|
+
if (void 0 === getServerSnapshot2) throw Error(formatProdErrorMessage(407));
|
|
4334
|
+
getServerSnapshot2 = getServerSnapshot2();
|
|
4335
|
+
} else getServerSnapshot2 = getSnapshot2();
|
|
4336
4336
|
var snapshotChanged = !objectIs(
|
|
4337
4337
|
(currentHook || hook).memoizedState,
|
|
4338
|
-
|
|
4338
|
+
getServerSnapshot2
|
|
4339
4339
|
);
|
|
4340
|
-
snapshotChanged && (hook.memoizedState =
|
|
4340
|
+
snapshotChanged && (hook.memoizedState = getServerSnapshot2, didReceiveUpdate = true);
|
|
4341
4341
|
hook = hook.queue;
|
|
4342
|
-
updateEffect(subscribeToStore.bind(null, fiber, hook,
|
|
4343
|
-
|
|
4342
|
+
updateEffect(subscribeToStore.bind(null, fiber, hook, subscribe2), [
|
|
4343
|
+
subscribe2
|
|
4344
4344
|
]);
|
|
4345
|
-
if (hook.getSnapshot !==
|
|
4345
|
+
if (hook.getSnapshot !== getSnapshot2 || snapshotChanged || null !== workInProgressHook && workInProgressHook.memoizedState.tag & 1) {
|
|
4346
4346
|
fiber.flags |= 2048;
|
|
4347
4347
|
pushSimpleEffect(
|
|
4348
4348
|
9,
|
|
@@ -4351,29 +4351,29 @@ function requireReactDomClient_production() {
|
|
|
4351
4351
|
null,
|
|
4352
4352
|
fiber,
|
|
4353
4353
|
hook,
|
|
4354
|
-
|
|
4355
|
-
|
|
4354
|
+
getServerSnapshot2,
|
|
4355
|
+
getSnapshot2
|
|
4356
4356
|
),
|
|
4357
4357
|
null
|
|
4358
4358
|
);
|
|
4359
4359
|
if (null === workInProgressRoot) throw Error(formatProdErrorMessage(349));
|
|
4360
|
-
isHydrating$jscomp$0 || 0 !== (renderLanes & 127) || pushStoreConsistencyCheck(fiber,
|
|
4360
|
+
isHydrating$jscomp$0 || 0 !== (renderLanes & 127) || pushStoreConsistencyCheck(fiber, getSnapshot2, getServerSnapshot2);
|
|
4361
4361
|
}
|
|
4362
|
-
return
|
|
4362
|
+
return getServerSnapshot2;
|
|
4363
4363
|
}
|
|
4364
|
-
function pushStoreConsistencyCheck(fiber,
|
|
4364
|
+
function pushStoreConsistencyCheck(fiber, getSnapshot2, renderedSnapshot) {
|
|
4365
4365
|
fiber.flags |= 16384;
|
|
4366
|
-
fiber = { getSnapshot, value: renderedSnapshot };
|
|
4367
|
-
|
|
4368
|
-
null ===
|
|
4366
|
+
fiber = { getSnapshot: getSnapshot2, value: renderedSnapshot };
|
|
4367
|
+
getSnapshot2 = currentlyRenderingFiber.updateQueue;
|
|
4368
|
+
null === getSnapshot2 ? (getSnapshot2 = createFunctionComponentUpdateQueue(), currentlyRenderingFiber.updateQueue = getSnapshot2, getSnapshot2.stores = [fiber]) : (renderedSnapshot = getSnapshot2.stores, null === renderedSnapshot ? getSnapshot2.stores = [fiber] : renderedSnapshot.push(fiber));
|
|
4369
4369
|
}
|
|
4370
|
-
function updateStoreInstance(fiber, inst, nextSnapshot,
|
|
4370
|
+
function updateStoreInstance(fiber, inst, nextSnapshot, getSnapshot2) {
|
|
4371
4371
|
inst.value = nextSnapshot;
|
|
4372
|
-
inst.getSnapshot =
|
|
4372
|
+
inst.getSnapshot = getSnapshot2;
|
|
4373
4373
|
checkIfSnapshotChanged(inst) && forceStoreRerender(fiber);
|
|
4374
4374
|
}
|
|
4375
|
-
function subscribeToStore(fiber, inst,
|
|
4376
|
-
return
|
|
4375
|
+
function subscribeToStore(fiber, inst, subscribe2) {
|
|
4376
|
+
return subscribe2(function() {
|
|
4377
4377
|
checkIfSnapshotChanged(inst) && forceStoreRerender(fiber);
|
|
4378
4378
|
});
|
|
4379
4379
|
}
|
|
@@ -5092,23 +5092,23 @@ function requireReactDomClient_production() {
|
|
|
5092
5092
|
mountWorkInProgressHook().memoizedState = stateHook;
|
|
5093
5093
|
return [false, stateHook];
|
|
5094
5094
|
},
|
|
5095
|
-
useSyncExternalStore: function(
|
|
5095
|
+
useSyncExternalStore: function(subscribe2, getSnapshot2, getServerSnapshot2) {
|
|
5096
5096
|
var fiber = currentlyRenderingFiber, hook = mountWorkInProgressHook();
|
|
5097
5097
|
if (isHydrating) {
|
|
5098
|
-
if (void 0 ===
|
|
5098
|
+
if (void 0 === getServerSnapshot2)
|
|
5099
5099
|
throw Error(formatProdErrorMessage(407));
|
|
5100
|
-
|
|
5100
|
+
getServerSnapshot2 = getServerSnapshot2();
|
|
5101
5101
|
} else {
|
|
5102
|
-
|
|
5102
|
+
getServerSnapshot2 = getSnapshot2();
|
|
5103
5103
|
if (null === workInProgressRoot)
|
|
5104
5104
|
throw Error(formatProdErrorMessage(349));
|
|
5105
|
-
0 !== (workInProgressRootRenderLanes & 127) || pushStoreConsistencyCheck(fiber,
|
|
5105
|
+
0 !== (workInProgressRootRenderLanes & 127) || pushStoreConsistencyCheck(fiber, getSnapshot2, getServerSnapshot2);
|
|
5106
5106
|
}
|
|
5107
|
-
hook.memoizedState =
|
|
5108
|
-
var inst = { value:
|
|
5107
|
+
hook.memoizedState = getServerSnapshot2;
|
|
5108
|
+
var inst = { value: getServerSnapshot2, getSnapshot: getSnapshot2 };
|
|
5109
5109
|
hook.queue = inst;
|
|
5110
|
-
mountEffect(subscribeToStore.bind(null, fiber, inst,
|
|
5111
|
-
|
|
5110
|
+
mountEffect(subscribeToStore.bind(null, fiber, inst, subscribe2), [
|
|
5111
|
+
subscribe2
|
|
5112
5112
|
]);
|
|
5113
5113
|
fiber.flags |= 2048;
|
|
5114
5114
|
pushSimpleEffect(
|
|
@@ -5118,12 +5118,12 @@ function requireReactDomClient_production() {
|
|
|
5118
5118
|
null,
|
|
5119
5119
|
fiber,
|
|
5120
5120
|
inst,
|
|
5121
|
-
|
|
5122
|
-
|
|
5121
|
+
getServerSnapshot2,
|
|
5122
|
+
getSnapshot2
|
|
5123
5123
|
),
|
|
5124
5124
|
null
|
|
5125
5125
|
);
|
|
5126
|
-
return
|
|
5126
|
+
return getServerSnapshot2;
|
|
5127
5127
|
},
|
|
5128
5128
|
useId: function() {
|
|
5129
5129
|
var hook = mountWorkInProgressHook(), identifierPrefix = workInProgressRoot.identifierPrefix;
|
|
@@ -8813,10 +8813,10 @@ function requireReactDomClient_production() {
|
|
|
8813
8813
|
var tag = node.tag;
|
|
8814
8814
|
if ((0 === tag || 11 === tag || 15 === tag) && node.flags & 16384 && (tag = node.updateQueue, null !== tag && (tag = tag.stores, null !== tag)))
|
|
8815
8815
|
for (var i2 = 0; i2 < tag.length; i2++) {
|
|
8816
|
-
var check = tag[i2],
|
|
8816
|
+
var check = tag[i2], getSnapshot2 = check.getSnapshot;
|
|
8817
8817
|
check = check.value;
|
|
8818
8818
|
try {
|
|
8819
|
-
if (!objectIs(
|
|
8819
|
+
if (!objectIs(getSnapshot2(), check)) return false;
|
|
8820
8820
|
} catch (error) {
|
|
8821
8821
|
return false;
|
|
8822
8822
|
}
|
|
@@ -10201,15 +10201,15 @@ function requireReactDomClient_production() {
|
|
|
10201
10201
|
};
|
|
10202
10202
|
}
|
|
10203
10203
|
function accumulateTwoPhaseListeners(targetFiber, reactName) {
|
|
10204
|
-
for (var captureName = reactName + "Capture",
|
|
10204
|
+
for (var captureName = reactName + "Capture", listeners2 = []; null !== targetFiber; ) {
|
|
10205
10205
|
var _instance2 = targetFiber, stateNode = _instance2.stateNode;
|
|
10206
10206
|
_instance2 = _instance2.tag;
|
|
10207
|
-
5 !== _instance2 && 26 !== _instance2 && 27 !== _instance2 || null === stateNode || (_instance2 = getListener(targetFiber, captureName), null != _instance2 &&
|
|
10207
|
+
5 !== _instance2 && 26 !== _instance2 && 27 !== _instance2 || null === stateNode || (_instance2 = getListener(targetFiber, captureName), null != _instance2 && listeners2.unshift(
|
|
10208
10208
|
createDispatchListener(targetFiber, _instance2, stateNode)
|
|
10209
|
-
), _instance2 = getListener(targetFiber, reactName), null != _instance2 &&
|
|
10209
|
+
), _instance2 = getListener(targetFiber, reactName), null != _instance2 && listeners2.push(
|
|
10210
10210
|
createDispatchListener(targetFiber, _instance2, stateNode)
|
|
10211
10211
|
));
|
|
10212
|
-
if (3 === targetFiber.tag) return
|
|
10212
|
+
if (3 === targetFiber.tag) return listeners2;
|
|
10213
10213
|
targetFiber = targetFiber.return;
|
|
10214
10214
|
}
|
|
10215
10215
|
return [];
|
|
@@ -10222,18 +10222,18 @@ function requireReactDomClient_production() {
|
|
|
10222
10222
|
return inst ? inst : null;
|
|
10223
10223
|
}
|
|
10224
10224
|
function accumulateEnterLeaveListenersForEvent(dispatchQueue, event, target, common, inCapturePhase) {
|
|
10225
|
-
for (var registrationName = event._reactName,
|
|
10225
|
+
for (var registrationName = event._reactName, listeners2 = []; null !== target && target !== common; ) {
|
|
10226
10226
|
var _instance3 = target, alternate = _instance3.alternate, stateNode = _instance3.stateNode;
|
|
10227
10227
|
_instance3 = _instance3.tag;
|
|
10228
10228
|
if (null !== alternate && alternate === common) break;
|
|
10229
|
-
5 !== _instance3 && 26 !== _instance3 && 27 !== _instance3 || null === stateNode || (alternate = stateNode, inCapturePhase ? (stateNode = getListener(target, registrationName), null != stateNode &&
|
|
10229
|
+
5 !== _instance3 && 26 !== _instance3 && 27 !== _instance3 || null === stateNode || (alternate = stateNode, inCapturePhase ? (stateNode = getListener(target, registrationName), null != stateNode && listeners2.unshift(
|
|
10230
10230
|
createDispatchListener(target, stateNode, alternate)
|
|
10231
|
-
)) : inCapturePhase || (stateNode = getListener(target, registrationName), null != stateNode &&
|
|
10231
|
+
)) : inCapturePhase || (stateNode = getListener(target, registrationName), null != stateNode && listeners2.push(
|
|
10232
10232
|
createDispatchListener(target, stateNode, alternate)
|
|
10233
10233
|
)));
|
|
10234
10234
|
target = target.return;
|
|
10235
10235
|
}
|
|
10236
|
-
0 !==
|
|
10236
|
+
0 !== listeners2.length && dispatchQueue.push({ event, listeners: listeners2 });
|
|
10237
10237
|
}
|
|
10238
10238
|
var NORMALIZE_NEWLINES_REGEX = /\r\n?/g, NORMALIZE_NULL_AND_REPLACEMENT_REGEX = /\u0000|\uFFFD/g;
|
|
10239
10239
|
function normalizeMarkupForTextOrAttribute(markup) {
|
|
@@ -12550,7 +12550,7 @@ function requireClient() {
|
|
|
12550
12550
|
return client.exports;
|
|
12551
12551
|
}
|
|
12552
12552
|
var clientExports = requireClient();
|
|
12553
|
-
const ReactDOM = /* @__PURE__ */ getDefaultExportFromCjs(clientExports);
|
|
12553
|
+
const ReactDOM$1 = /* @__PURE__ */ getDefaultExportFromCjs(clientExports);
|
|
12554
12554
|
/**
|
|
12555
12555
|
* react-router v7.9.4
|
|
12556
12556
|
*
|
|
@@ -14637,6 +14637,7 @@ function useViewTransitionState(to, { relative } = {}) {
|
|
|
14637
14637
|
return matchPath(path.pathname, nextPath) != null || matchPath(path.pathname, currentPath) != null;
|
|
14638
14638
|
}
|
|
14639
14639
|
var reactDomExports = requireReactDom();
|
|
14640
|
+
const ReactDOM = /* @__PURE__ */ getDefaultExportFromCjs(reactDomExports);
|
|
14640
14641
|
function setRef(ref, value) {
|
|
14641
14642
|
if (typeof ref === "function") {
|
|
14642
14643
|
return ref(value);
|
|
@@ -15332,11 +15333,11 @@ function usePointerDownOutside(onPointerDownOutside, ownerDocument = globalThis?
|
|
|
15332
15333
|
}
|
|
15333
15334
|
isPointerInsideReactTreeRef.current = false;
|
|
15334
15335
|
};
|
|
15335
|
-
const
|
|
15336
|
+
const timerId2 = window.setTimeout(() => {
|
|
15336
15337
|
ownerDocument.addEventListener("pointerdown", handlePointerDown);
|
|
15337
15338
|
}, 0);
|
|
15338
15339
|
return () => {
|
|
15339
|
-
window.clearTimeout(
|
|
15340
|
+
window.clearTimeout(timerId2);
|
|
15340
15341
|
ownerDocument.removeEventListener("pointerdown", handlePointerDown);
|
|
15341
15342
|
ownerDocument.removeEventListener("click", handleClickRef.current);
|
|
15342
15343
|
};
|
|
@@ -15380,6 +15381,15 @@ function handleAndDispatchCustomEvent(name, handler, detail, { discrete }) {
|
|
|
15380
15381
|
target.dispatchEvent(event);
|
|
15381
15382
|
}
|
|
15382
15383
|
}
|
|
15384
|
+
var PORTAL_NAME$1 = "Portal";
|
|
15385
|
+
var Portal$1 = reactExports.forwardRef((props, forwardedRef) => {
|
|
15386
|
+
const { container: containerProp, ...portalProps } = props;
|
|
15387
|
+
const [mounted, setMounted] = reactExports.useState(false);
|
|
15388
|
+
useLayoutEffect2(() => setMounted(true), []);
|
|
15389
|
+
const container = containerProp || mounted && globalThis?.document?.body;
|
|
15390
|
+
return container ? ReactDOM.createPortal(/* @__PURE__ */ jsxRuntimeExports.jsx(Primitive.div, { ...portalProps, ref: forwardedRef }), container) : null;
|
|
15391
|
+
});
|
|
15392
|
+
Portal$1.displayName = PORTAL_NAME$1;
|
|
15383
15393
|
function useSize(element) {
|
|
15384
15394
|
const [size2, setSize] = reactExports.useState(void 0);
|
|
15385
15395
|
useLayoutEffect2(() => {
|
|
@@ -16007,7 +16017,7 @@ async function convertValueToCoords(state, options) {
|
|
|
16007
16017
|
y: crossAxis * crossAxisMulti
|
|
16008
16018
|
};
|
|
16009
16019
|
}
|
|
16010
|
-
const offset$
|
|
16020
|
+
const offset$3 = function(options) {
|
|
16011
16021
|
if (options === void 0) {
|
|
16012
16022
|
options = 0;
|
|
16013
16023
|
}
|
|
@@ -16990,7 +17000,7 @@ function autoUpdate(reference, floating, update, options) {
|
|
|
16990
17000
|
}
|
|
16991
17001
|
};
|
|
16992
17002
|
}
|
|
16993
|
-
const offset$
|
|
17003
|
+
const offset$2 = offset$3;
|
|
16994
17004
|
const shift$1 = shift$2;
|
|
16995
17005
|
const flip$1 = flip$2;
|
|
16996
17006
|
const size$1 = size$2;
|
|
@@ -17263,8 +17273,8 @@ const arrow$1 = (options) => {
|
|
|
17263
17273
|
}
|
|
17264
17274
|
};
|
|
17265
17275
|
};
|
|
17266
|
-
const offset = (options, deps) => ({
|
|
17267
|
-
...offset$
|
|
17276
|
+
const offset$1 = (options, deps) => ({
|
|
17277
|
+
...offset$2(options),
|
|
17268
17278
|
options: [options, deps]
|
|
17269
17279
|
});
|
|
17270
17280
|
const shift = (options, deps) => ({
|
|
@@ -17388,7 +17398,7 @@ var PopperContent = reactExports.forwardRef(
|
|
|
17388
17398
|
reference: context.anchor
|
|
17389
17399
|
},
|
|
17390
17400
|
middleware: [
|
|
17391
|
-
offset({ mainAxis: sideOffset + arrowHeight, alignmentAxis: alignOffset }),
|
|
17401
|
+
offset$1({ mainAxis: sideOffset + arrowHeight, alignmentAxis: alignOffset }),
|
|
17392
17402
|
avoidCollisions && shift({
|
|
17393
17403
|
mainAxis: true,
|
|
17394
17404
|
crossAxis: false,
|
|
@@ -18867,6 +18877,12 @@ var PORTAL_NAME = "TooltipPortal";
|
|
|
18867
18877
|
var [PortalProvider, usePortalContext] = createTooltipContext(PORTAL_NAME, {
|
|
18868
18878
|
forceMount: void 0
|
|
18869
18879
|
});
|
|
18880
|
+
var TooltipPortal = (props) => {
|
|
18881
|
+
const { __scopeTooltip, forceMount, children, container } = props;
|
|
18882
|
+
const context = useTooltipContext(PORTAL_NAME, __scopeTooltip);
|
|
18883
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(PortalProvider, { scope: __scopeTooltip, forceMount, children: /* @__PURE__ */ jsxRuntimeExports.jsx(Presence, { present: forceMount || context.open, children: /* @__PURE__ */ jsxRuntimeExports.jsx(Portal$1, { asChild: true, container, children }) }) });
|
|
18884
|
+
};
|
|
18885
|
+
TooltipPortal.displayName = PORTAL_NAME;
|
|
18870
18886
|
var CONTENT_NAME = "TooltipContent";
|
|
18871
18887
|
var TooltipContent = reactExports.forwardRef(
|
|
18872
18888
|
(props, forwardedRef) => {
|
|
@@ -19135,7 +19151,9 @@ function getHullPresorted(points) {
|
|
|
19135
19151
|
var Provider = TooltipProvider;
|
|
19136
19152
|
var Root3 = Tooltip;
|
|
19137
19153
|
var Trigger = TooltipTrigger;
|
|
19154
|
+
var Portal = TooltipPortal;
|
|
19138
19155
|
var Content2 = TooltipContent;
|
|
19156
|
+
var Arrow2 = TooltipArrow;
|
|
19139
19157
|
var classnames = { exports: {} };
|
|
19140
19158
|
/*!
|
|
19141
19159
|
Copyright (c) 2018 Jed Watson.
|
|
@@ -19610,8 +19628,9 @@ function derivePipelineMetadata(source = {}) {
|
|
|
19610
19628
|
const pipelineLabel = source?.pipelineLabel ?? (typeof pipelineSlugFromSource === "string" ? humanizePipelineSlug(pipelineSlugFromSource) : null);
|
|
19611
19629
|
const pipelineObject = pipelineValue && typeof pipelineValue === "object" && !Array.isArray(pipelineValue) ? pipelineValue : null;
|
|
19612
19630
|
const pipeline = pipelineObject ?? (typeof pipelineSlugFromSource === "string" ? pipelineSlugFromSource : null);
|
|
19631
|
+
const stringPipeline = typeof pipelineValue === "string" ? pipelineValue : null;
|
|
19613
19632
|
return {
|
|
19614
|
-
pipeline,
|
|
19633
|
+
pipeline: pipeline || stringPipeline,
|
|
19615
19634
|
pipelineSlug: typeof pipelineSlugFromSource === "string" ? pipelineSlugFromSource : null,
|
|
19616
19635
|
pipelineLabel: pipelineLabel || null
|
|
19617
19636
|
};
|
|
@@ -19909,13 +19928,70 @@ function useJobListWithUpdates() {
|
|
|
19909
19928
|
connectionStatus
|
|
19910
19929
|
};
|
|
19911
19930
|
}
|
|
19912
|
-
const
|
|
19913
|
-
|
|
19931
|
+
const TaskState = Object.freeze({
|
|
19932
|
+
PENDING: "pending",
|
|
19933
|
+
RUNNING: "running",
|
|
19934
|
+
DONE: "done",
|
|
19935
|
+
FAILED: "failed"
|
|
19936
|
+
});
|
|
19937
|
+
const JobStatus = Object.freeze({
|
|
19938
|
+
PENDING: "pending",
|
|
19939
|
+
RUNNING: "running",
|
|
19940
|
+
FAILED: "failed",
|
|
19941
|
+
COMPLETE: "complete"
|
|
19942
|
+
});
|
|
19943
|
+
const JobLocation = Object.freeze({
|
|
19944
|
+
PENDING: "pending",
|
|
19945
|
+
CURRENT: "current",
|
|
19946
|
+
COMPLETE: "complete",
|
|
19947
|
+
REJECTED: "rejected"
|
|
19948
|
+
});
|
|
19949
|
+
new Set(Object.values(TaskState));
|
|
19950
|
+
new Set(Object.values(JobStatus));
|
|
19951
|
+
new Set(Object.values(JobLocation));
|
|
19952
|
+
function normalizeTaskState(state) {
|
|
19953
|
+
if (typeof state !== "string") {
|
|
19954
|
+
return TaskState.PENDING;
|
|
19955
|
+
}
|
|
19956
|
+
const normalized = state.toLowerCase().trim();
|
|
19957
|
+
switch (normalized) {
|
|
19958
|
+
case "error":
|
|
19959
|
+
return TaskState.FAILED;
|
|
19960
|
+
case "succeeded":
|
|
19961
|
+
return TaskState.DONE;
|
|
19962
|
+
case TaskState.PENDING:
|
|
19963
|
+
case TaskState.RUNNING:
|
|
19964
|
+
case TaskState.DONE:
|
|
19965
|
+
case TaskState.FAILED:
|
|
19966
|
+
return normalized;
|
|
19967
|
+
default:
|
|
19968
|
+
return TaskState.PENDING;
|
|
19969
|
+
}
|
|
19970
|
+
}
|
|
19971
|
+
function deriveJobStatusFromTasks(tasks) {
|
|
19972
|
+
if (!Array.isArray(tasks) || tasks.length === 0) {
|
|
19973
|
+
return JobStatus.PENDING;
|
|
19974
|
+
}
|
|
19975
|
+
const normalizedStates = tasks.map((task) => normalizeTaskState(task.state));
|
|
19976
|
+
if (normalizedStates.some((state) => state === TaskState.FAILED)) {
|
|
19977
|
+
return JobStatus.FAILED;
|
|
19978
|
+
}
|
|
19979
|
+
if (normalizedStates.some((state) => state === TaskState.RUNNING)) {
|
|
19980
|
+
return JobStatus.RUNNING;
|
|
19981
|
+
}
|
|
19982
|
+
if (normalizedStates.every((state) => state === TaskState.DONE)) {
|
|
19983
|
+
return JobStatus.COMPLETE;
|
|
19984
|
+
}
|
|
19985
|
+
return JobStatus.PENDING;
|
|
19986
|
+
}
|
|
19987
|
+
function normalizeTaskStateWithWarning(raw) {
|
|
19914
19988
|
if (!raw || typeof raw !== "string")
|
|
19915
19989
|
return { state: "pending", warning: "missing_state" };
|
|
19916
|
-
const
|
|
19917
|
-
if (
|
|
19918
|
-
|
|
19990
|
+
const normalizedState = normalizeTaskState(raw);
|
|
19991
|
+
if (raw !== normalizedState) {
|
|
19992
|
+
return { state: normalizedState, warning: `unknown_state:${raw}` };
|
|
19993
|
+
}
|
|
19994
|
+
return { state: normalizedState };
|
|
19919
19995
|
}
|
|
19920
19996
|
function normalizeTasks(rawTasks) {
|
|
19921
19997
|
if (!rawTasks) return { tasks: {}, warnings: [] };
|
|
@@ -19923,7 +19999,7 @@ function normalizeTasks(rawTasks) {
|
|
|
19923
19999
|
if (typeof rawTasks === "object" && !Array.isArray(rawTasks)) {
|
|
19924
20000
|
const tasks = {};
|
|
19925
20001
|
Object.entries(rawTasks).forEach(([name, t2]) => {
|
|
19926
|
-
const ns =
|
|
20002
|
+
const ns = normalizeTaskStateWithWarning(t2 && t2.state);
|
|
19927
20003
|
if (ns.warning) warnings.push(`${name}:${ns.warning}`);
|
|
19928
20004
|
const taskObj = {
|
|
19929
20005
|
name,
|
|
@@ -19957,7 +20033,7 @@ function normalizeTasks(rawTasks) {
|
|
|
19957
20033
|
const tasks = {};
|
|
19958
20034
|
rawTasks.forEach((t2, idx) => {
|
|
19959
20035
|
const name = t2 && t2.name ? String(t2.name) : `task-${idx}`;
|
|
19960
|
-
const ns =
|
|
20036
|
+
const ns = normalizeTaskStateWithWarning(t2 && t2.state);
|
|
19961
20037
|
if (ns.warning) warnings.push(`${name}:${ns.warning}`);
|
|
19962
20038
|
tasks[name] = {
|
|
19963
20039
|
name,
|
|
@@ -19978,14 +20054,6 @@ function normalizeTasks(rawTasks) {
|
|
|
19978
20054
|
}
|
|
19979
20055
|
return { tasks: {}, warnings: ["invalid_tasks_shape"] };
|
|
19980
20056
|
}
|
|
19981
|
-
function deriveStatusFromTasks(tasks) {
|
|
19982
|
-
const taskList = Object.values(tasks);
|
|
19983
|
-
if (!Array.isArray(taskList) || taskList.length === 0) return "pending";
|
|
19984
|
-
if (taskList.some((t2) => t2.state === "failed")) return "failed";
|
|
19985
|
-
if (taskList.some((t2) => t2.state === "running")) return "running";
|
|
19986
|
-
if (taskList.every((t2) => t2.state === "done")) return "complete";
|
|
19987
|
-
return "pending";
|
|
19988
|
-
}
|
|
19989
20057
|
function computeJobSummaryStats(tasks) {
|
|
19990
20058
|
const taskList = Object.values(tasks);
|
|
19991
20059
|
const taskCount = taskList.length;
|
|
@@ -19993,7 +20061,7 @@ function computeJobSummaryStats(tasks) {
|
|
|
19993
20061
|
(acc, t2) => acc + (t2.state === "done" ? 1 : 0),
|
|
19994
20062
|
0
|
|
19995
20063
|
);
|
|
19996
|
-
const status =
|
|
20064
|
+
const status = deriveJobStatusFromTasks(Object.values(tasks));
|
|
19997
20065
|
const progress = taskCount > 0 ? Math.round(doneCount / taskCount * 100) : 0;
|
|
19998
20066
|
return { status, progress, doneCount, taskCount };
|
|
19999
20067
|
}
|
|
@@ -20076,101 +20144,6 @@ function adaptJobDetail(apiDetail) {
|
|
|
20076
20144
|
if (warnings.length > 0) detail.__warnings = warnings;
|
|
20077
20145
|
return detail;
|
|
20078
20146
|
}
|
|
20079
|
-
function normalizeState(state) {
|
|
20080
|
-
switch (state) {
|
|
20081
|
-
case "done":
|
|
20082
|
-
return "completed";
|
|
20083
|
-
case "failed":
|
|
20084
|
-
case "error":
|
|
20085
|
-
return "error";
|
|
20086
|
-
case "pending":
|
|
20087
|
-
case "running":
|
|
20088
|
-
case "current":
|
|
20089
|
-
case "completed":
|
|
20090
|
-
case "rejected":
|
|
20091
|
-
return state;
|
|
20092
|
-
default:
|
|
20093
|
-
return state;
|
|
20094
|
-
}
|
|
20095
|
-
}
|
|
20096
|
-
function taskDisplayDurationMs(task, now = Date.now()) {
|
|
20097
|
-
const { state, startedAt, endedAt, executionTime, executionTimeMs } = task;
|
|
20098
|
-
const normalizedState = normalizeState(state);
|
|
20099
|
-
switch (normalizedState) {
|
|
20100
|
-
case "pending":
|
|
20101
|
-
return 0;
|
|
20102
|
-
case "running":
|
|
20103
|
-
case "current":
|
|
20104
|
-
if (!startedAt) {
|
|
20105
|
-
return 0;
|
|
20106
|
-
}
|
|
20107
|
-
const startTime = Date.parse(startedAt);
|
|
20108
|
-
return Math.max(0, now - startTime);
|
|
20109
|
-
case "completed":
|
|
20110
|
-
const execTime = executionTimeMs != null ? executionTimeMs : executionTime;
|
|
20111
|
-
if (typeof execTime === "number" && execTime >= 0) {
|
|
20112
|
-
return execTime;
|
|
20113
|
-
}
|
|
20114
|
-
if (!startedAt) {
|
|
20115
|
-
return 0;
|
|
20116
|
-
}
|
|
20117
|
-
const completedStartTime = Date.parse(startedAt);
|
|
20118
|
-
const endTime = endedAt ? Date.parse(endedAt) : now;
|
|
20119
|
-
return Math.max(0, endTime - completedStartTime);
|
|
20120
|
-
case "rejected":
|
|
20121
|
-
return 0;
|
|
20122
|
-
default:
|
|
20123
|
-
return 0;
|
|
20124
|
-
}
|
|
20125
|
-
}
|
|
20126
|
-
function jobCumulativeDurationMs(job, now = Date.now()) {
|
|
20127
|
-
const { tasks } = job;
|
|
20128
|
-
if (!tasks) {
|
|
20129
|
-
return 0;
|
|
20130
|
-
}
|
|
20131
|
-
let taskList;
|
|
20132
|
-
if (Array.isArray(tasks)) {
|
|
20133
|
-
taskList = tasks;
|
|
20134
|
-
} else if (typeof tasks === "object") {
|
|
20135
|
-
taskList = Object.values(tasks);
|
|
20136
|
-
} else {
|
|
20137
|
-
return 0;
|
|
20138
|
-
}
|
|
20139
|
-
return taskList.reduce((total, task) => {
|
|
20140
|
-
return total + taskDisplayDurationMs(task, now);
|
|
20141
|
-
}, 0);
|
|
20142
|
-
}
|
|
20143
|
-
function fmtDuration(ms) {
|
|
20144
|
-
if (ms <= 0) return "0s";
|
|
20145
|
-
const seconds = Math.floor(ms / 1e3);
|
|
20146
|
-
const minutes = Math.floor(seconds / 60);
|
|
20147
|
-
const hours = Math.floor(minutes / 60);
|
|
20148
|
-
if (hours > 0) {
|
|
20149
|
-
const remainingMinutes = minutes % 60;
|
|
20150
|
-
const remainingSeconds = seconds % 60;
|
|
20151
|
-
if (remainingSeconds > 0) {
|
|
20152
|
-
return `${hours}h ${remainingMinutes}m ${remainingSeconds}s`;
|
|
20153
|
-
} else {
|
|
20154
|
-
return `${hours}h ${remainingMinutes}m`;
|
|
20155
|
-
}
|
|
20156
|
-
} else if (minutes > 0) {
|
|
20157
|
-
return `${minutes}m ${seconds % 60}s`;
|
|
20158
|
-
} else {
|
|
20159
|
-
return `${seconds}s`;
|
|
20160
|
-
}
|
|
20161
|
-
}
|
|
20162
|
-
function useTicker(intervalMs = 1e3) {
|
|
20163
|
-
const [now, setNow] = reactExports.useState(() => Date.now());
|
|
20164
|
-
reactExports.useEffect(() => {
|
|
20165
|
-
const intervalId = setInterval(() => {
|
|
20166
|
-
setNow(Date.now());
|
|
20167
|
-
}, intervalMs);
|
|
20168
|
-
return () => {
|
|
20169
|
-
clearInterval(intervalId);
|
|
20170
|
-
};
|
|
20171
|
-
}, [intervalMs]);
|
|
20172
|
-
return now;
|
|
20173
|
-
}
|
|
20174
20147
|
/**
|
|
20175
20148
|
* @license lucide-react v0.544.0 - ISC
|
|
20176
20149
|
*
|
|
@@ -20270,17 +20243,6 @@ const createLucideIcon = (iconName, iconNode) => {
|
|
|
20270
20243
|
Component.displayName = toPascalCase(iconName);
|
|
20271
20244
|
return Component;
|
|
20272
20245
|
};
|
|
20273
|
-
/**
|
|
20274
|
-
* @license lucide-react v0.544.0 - ISC
|
|
20275
|
-
*
|
|
20276
|
-
* This source code is licensed under the ISC license.
|
|
20277
|
-
* See the LICENSE file in the root directory of this source tree.
|
|
20278
|
-
*/
|
|
20279
|
-
const __iconNode$4 = [
|
|
20280
|
-
["path", { d: "m12 19-7-7 7-7", key: "1l729n" }],
|
|
20281
|
-
["path", { d: "M19 12H5", key: "x3x0zl" }]
|
|
20282
|
-
];
|
|
20283
|
-
const ArrowLeft = createLucideIcon("arrow-left", __iconNode$4);
|
|
20284
20246
|
/**
|
|
20285
20247
|
* @license lucide-react v0.544.0 - ISC
|
|
20286
20248
|
*
|
|
@@ -20326,6 +20288,78 @@ const __iconNode = [
|
|
|
20326
20288
|
["path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4", key: "ih7n3h" }]
|
|
20327
20289
|
];
|
|
20328
20290
|
const Upload = createLucideIcon("upload", __iconNode);
|
|
20291
|
+
function normalizeState(state) {
|
|
20292
|
+
const canonicalState = normalizeTaskState(state);
|
|
20293
|
+
if (canonicalState === TaskState.DONE) {
|
|
20294
|
+
return "completed";
|
|
20295
|
+
}
|
|
20296
|
+
return canonicalState;
|
|
20297
|
+
}
|
|
20298
|
+
function taskDisplayDurationMs(task, now = Date.now()) {
|
|
20299
|
+
const { state, startedAt, endedAt, executionTime, executionTimeMs } = task;
|
|
20300
|
+
const normalizedState = normalizeState(state);
|
|
20301
|
+
switch (normalizedState) {
|
|
20302
|
+
case TaskState.PENDING:
|
|
20303
|
+
return 0;
|
|
20304
|
+
case TaskState.RUNNING:
|
|
20305
|
+
if (!startedAt) {
|
|
20306
|
+
return 0;
|
|
20307
|
+
}
|
|
20308
|
+
const startTime = Date.parse(startedAt);
|
|
20309
|
+
return Math.max(0, now - startTime);
|
|
20310
|
+
case "completed":
|
|
20311
|
+
const execTime = executionTimeMs != null ? executionTimeMs : executionTime;
|
|
20312
|
+
if (typeof execTime === "number" && execTime >= 0) {
|
|
20313
|
+
return execTime;
|
|
20314
|
+
}
|
|
20315
|
+
if (!startedAt) {
|
|
20316
|
+
return 0;
|
|
20317
|
+
}
|
|
20318
|
+
const completedStartTime = Date.parse(startedAt);
|
|
20319
|
+
const endTime = endedAt ? Date.parse(endedAt) : now;
|
|
20320
|
+
return Math.max(0, endTime - completedStartTime);
|
|
20321
|
+
case TaskState.FAILED:
|
|
20322
|
+
return 0;
|
|
20323
|
+
default:
|
|
20324
|
+
return 0;
|
|
20325
|
+
}
|
|
20326
|
+
}
|
|
20327
|
+
function jobCumulativeDurationMs(job, now = Date.now()) {
|
|
20328
|
+
const { tasks } = job;
|
|
20329
|
+
if (!tasks) {
|
|
20330
|
+
return 0;
|
|
20331
|
+
}
|
|
20332
|
+
let taskList;
|
|
20333
|
+
if (Array.isArray(tasks)) {
|
|
20334
|
+
taskList = tasks;
|
|
20335
|
+
} else if (typeof tasks === "object") {
|
|
20336
|
+
taskList = Object.values(tasks);
|
|
20337
|
+
} else {
|
|
20338
|
+
return 0;
|
|
20339
|
+
}
|
|
20340
|
+
return taskList.reduce((total, task) => {
|
|
20341
|
+
return total + taskDisplayDurationMs(task, now);
|
|
20342
|
+
}, 0);
|
|
20343
|
+
}
|
|
20344
|
+
function fmtDuration(ms) {
|
|
20345
|
+
if (ms <= 0) return "0s";
|
|
20346
|
+
const seconds = Math.floor(ms / 1e3);
|
|
20347
|
+
const minutes = Math.floor(seconds / 60);
|
|
20348
|
+
const hours = Math.floor(minutes / 60);
|
|
20349
|
+
if (hours > 0) {
|
|
20350
|
+
const remainingMinutes = minutes % 60;
|
|
20351
|
+
const remainingSeconds = seconds % 60;
|
|
20352
|
+
if (remainingSeconds > 0) {
|
|
20353
|
+
return `${hours}h ${remainingMinutes}m ${remainingSeconds}s`;
|
|
20354
|
+
} else {
|
|
20355
|
+
return `${hours}h ${remainingMinutes}m`;
|
|
20356
|
+
}
|
|
20357
|
+
} else if (minutes > 0) {
|
|
20358
|
+
return `${minutes}m ${seconds % 60}s`;
|
|
20359
|
+
} else {
|
|
20360
|
+
return `${seconds}s`;
|
|
20361
|
+
}
|
|
20362
|
+
}
|
|
20329
20363
|
const countCompleted = (job) => {
|
|
20330
20364
|
const list = Array.isArray(job?.tasks) ? job.tasks : Object.values(job?.tasks || {});
|
|
20331
20365
|
return list.filter((t2) => t2?.state === "done" || t2?.state === "completed").length;
|
|
@@ -20347,14 +20381,13 @@ function Badge({ children, intent = "gray", className = "", ...props }) {
|
|
|
20347
20381
|
}
|
|
20348
20382
|
const statusBadge = (status) => {
|
|
20349
20383
|
switch (status) {
|
|
20350
|
-
case
|
|
20384
|
+
case TaskState.RUNNING:
|
|
20351
20385
|
return /* @__PURE__ */ jsxRuntimeExports.jsx(Badge, { intent: "blue", "aria-label": "Running", children: "Running" });
|
|
20352
|
-
case
|
|
20386
|
+
case TaskState.FAILED:
|
|
20353
20387
|
return /* @__PURE__ */ jsxRuntimeExports.jsx(Badge, { intent: "red", "aria-label": "Failed", children: "Failed" });
|
|
20354
|
-
case
|
|
20355
|
-
case "complete":
|
|
20388
|
+
case TaskState.DONE:
|
|
20356
20389
|
return /* @__PURE__ */ jsxRuntimeExports.jsx(Badge, { intent: "green", "aria-label": "Completed", children: "Completed" });
|
|
20357
|
-
case
|
|
20390
|
+
case TaskState.PENDING:
|
|
20358
20391
|
return /* @__PURE__ */ jsxRuntimeExports.jsx(Badge, { intent: "gray", "aria-label": "Pending", children: "Pending" });
|
|
20359
20392
|
default:
|
|
20360
20393
|
return null;
|
|
@@ -20362,16 +20395,176 @@ const statusBadge = (status) => {
|
|
|
20362
20395
|
};
|
|
20363
20396
|
const progressClasses = (status) => {
|
|
20364
20397
|
switch (status) {
|
|
20365
|
-
case
|
|
20398
|
+
case TaskState.RUNNING:
|
|
20366
20399
|
return "bg-info/20 [&>div]:bg-info";
|
|
20367
|
-
case
|
|
20400
|
+
case TaskState.FAILED:
|
|
20368
20401
|
return "bg-destructive/20 [&>div]:bg-destructive";
|
|
20369
|
-
case
|
|
20402
|
+
case TaskState.DONE:
|
|
20370
20403
|
return "bg-success/20 [&>div]:bg-success";
|
|
20371
20404
|
default:
|
|
20372
20405
|
return "bg-muted [&>div]:bg-muted-foreground";
|
|
20373
20406
|
}
|
|
20374
20407
|
};
|
|
20408
|
+
const offset = Date.now() - performance.now();
|
|
20409
|
+
let currentNow = Math.floor(performance.now() + offset);
|
|
20410
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
20411
|
+
const cadenceHints = /* @__PURE__ */ new Map();
|
|
20412
|
+
let timerId = null;
|
|
20413
|
+
let activeIntervalMs = 1e3;
|
|
20414
|
+
let isBackground = false;
|
|
20415
|
+
function subscribe(listener) {
|
|
20416
|
+
listeners.add(listener);
|
|
20417
|
+
if (listeners.size === 1) {
|
|
20418
|
+
startTimer();
|
|
20419
|
+
}
|
|
20420
|
+
return () => {
|
|
20421
|
+
listeners.delete(listener);
|
|
20422
|
+
if (listeners.size === 0) {
|
|
20423
|
+
stopTimer();
|
|
20424
|
+
}
|
|
20425
|
+
};
|
|
20426
|
+
}
|
|
20427
|
+
function getSnapshot() {
|
|
20428
|
+
return currentNow;
|
|
20429
|
+
}
|
|
20430
|
+
function getServerSnapshot() {
|
|
20431
|
+
return Date.now();
|
|
20432
|
+
}
|
|
20433
|
+
function addCadenceHint(id, ms) {
|
|
20434
|
+
cadenceHints.set(id, ms);
|
|
20435
|
+
recalculateInterval();
|
|
20436
|
+
}
|
|
20437
|
+
function removeCadenceHint(id) {
|
|
20438
|
+
cadenceHints.delete(id);
|
|
20439
|
+
recalculateInterval();
|
|
20440
|
+
}
|
|
20441
|
+
function recalculateInterval() {
|
|
20442
|
+
const minCadence = Math.min(...cadenceHints.values(), 1e3);
|
|
20443
|
+
const newIntervalMs = isBackground ? Math.max(minCadence, 6e4) : minCadence;
|
|
20444
|
+
if (newIntervalMs !== activeIntervalMs) {
|
|
20445
|
+
activeIntervalMs = newIntervalMs;
|
|
20446
|
+
if (listeners.size > 0) {
|
|
20447
|
+
stopTimer();
|
|
20448
|
+
startTimer();
|
|
20449
|
+
}
|
|
20450
|
+
}
|
|
20451
|
+
}
|
|
20452
|
+
function startTimer() {
|
|
20453
|
+
if (timerId !== null) return;
|
|
20454
|
+
const tick = () => {
|
|
20455
|
+
currentNow = Math.floor(performance.now() + offset);
|
|
20456
|
+
listeners.forEach((listener) => {
|
|
20457
|
+
try {
|
|
20458
|
+
listener();
|
|
20459
|
+
} catch (error) {
|
|
20460
|
+
console.error("Error in time store listener:", error);
|
|
20461
|
+
}
|
|
20462
|
+
});
|
|
20463
|
+
};
|
|
20464
|
+
if (activeIntervalMs >= 6e4) {
|
|
20465
|
+
const now = Date.now();
|
|
20466
|
+
const nextMinuteBoundary = Math.ceil(now / 6e4) * 6e4;
|
|
20467
|
+
const initialDelay = nextMinuteBoundary - now;
|
|
20468
|
+
timerId = setTimeout(() => {
|
|
20469
|
+
tick();
|
|
20470
|
+
timerId = setInterval(tick, 6e4);
|
|
20471
|
+
}, initialDelay);
|
|
20472
|
+
} else {
|
|
20473
|
+
timerId = setInterval(tick, activeIntervalMs);
|
|
20474
|
+
}
|
|
20475
|
+
}
|
|
20476
|
+
function stopTimer() {
|
|
20477
|
+
if (timerId !== null) {
|
|
20478
|
+
clearTimeout(timerId);
|
|
20479
|
+
clearInterval(timerId);
|
|
20480
|
+
timerId = null;
|
|
20481
|
+
}
|
|
20482
|
+
}
|
|
20483
|
+
function handleVisibilityChange() {
|
|
20484
|
+
const wasBackground = isBackground;
|
|
20485
|
+
isBackground = document.visibilityState === "hidden";
|
|
20486
|
+
if (wasBackground !== isBackground) {
|
|
20487
|
+
recalculateInterval();
|
|
20488
|
+
}
|
|
20489
|
+
}
|
|
20490
|
+
if (typeof document !== "undefined") {
|
|
20491
|
+
document.addEventListener("visibilitychange", handleVisibilityChange);
|
|
20492
|
+
}
|
|
20493
|
+
function TimerText({
|
|
20494
|
+
startMs,
|
|
20495
|
+
endMs = null,
|
|
20496
|
+
granularity = "second",
|
|
20497
|
+
format = fmtDuration,
|
|
20498
|
+
className
|
|
20499
|
+
}) {
|
|
20500
|
+
const id = reactExports.useId();
|
|
20501
|
+
const now = reactExports.useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
|
|
20502
|
+
const [displayText, setDisplayText] = reactExports.useState(() => {
|
|
20503
|
+
if (!startMs) return "—";
|
|
20504
|
+
const initialEnd = endMs ?? Date.now();
|
|
20505
|
+
const elapsed = Math.max(0, initialEnd - startMs);
|
|
20506
|
+
return format(elapsed);
|
|
20507
|
+
});
|
|
20508
|
+
reactExports.useEffect(() => {
|
|
20509
|
+
if (!startMs) return;
|
|
20510
|
+
const cadenceMs = granularity === "second" ? 1e3 : 6e4;
|
|
20511
|
+
addCadenceHint(id, cadenceMs);
|
|
20512
|
+
return () => {
|
|
20513
|
+
removeCadenceHint(id);
|
|
20514
|
+
};
|
|
20515
|
+
}, [id, granularity, startMs]);
|
|
20516
|
+
reactExports.useEffect(() => {
|
|
20517
|
+
if (!startMs) return;
|
|
20518
|
+
if (endMs !== null) return;
|
|
20519
|
+
const elapsed = Math.max(0, now - startMs);
|
|
20520
|
+
setDisplayText(format(elapsed));
|
|
20521
|
+
}, [now, startMs, endMs, format]);
|
|
20522
|
+
reactExports.useEffect(() => {
|
|
20523
|
+
if (!startMs || endMs === null) return;
|
|
20524
|
+
const elapsed = Math.max(0, endMs - startMs);
|
|
20525
|
+
setDisplayText(format(elapsed));
|
|
20526
|
+
}, [startMs, endMs, format]);
|
|
20527
|
+
if (!startMs) {
|
|
20528
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className, children: "—" });
|
|
20529
|
+
}
|
|
20530
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className, children: displayText });
|
|
20531
|
+
}
|
|
20532
|
+
function LiveText({ compute, cadenceMs = 1e4, className }) {
|
|
20533
|
+
const id = reactExports.useId();
|
|
20534
|
+
const now = reactExports.useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
|
|
20535
|
+
const [displayText, setDisplayText] = reactExports.useState(() => {
|
|
20536
|
+
return compute(Date.now());
|
|
20537
|
+
});
|
|
20538
|
+
reactExports.useEffect(() => {
|
|
20539
|
+
addCadenceHint(id, cadenceMs);
|
|
20540
|
+
return () => {
|
|
20541
|
+
removeCadenceHint(id);
|
|
20542
|
+
};
|
|
20543
|
+
}, [id, cadenceMs]);
|
|
20544
|
+
reactExports.useEffect(() => {
|
|
20545
|
+
setDisplayText(compute(now));
|
|
20546
|
+
}, [now, compute]);
|
|
20547
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className, children: displayText });
|
|
20548
|
+
}
|
|
20549
|
+
function toMilliseconds(timestamp) {
|
|
20550
|
+
if (timestamp === null || timestamp === void 0) {
|
|
20551
|
+
return null;
|
|
20552
|
+
}
|
|
20553
|
+
if (typeof timestamp === "number") {
|
|
20554
|
+
return isNaN(timestamp) ? null : timestamp;
|
|
20555
|
+
}
|
|
20556
|
+
if (typeof timestamp === "string") {
|
|
20557
|
+
const parsed = Date.parse(timestamp);
|
|
20558
|
+
return isNaN(parsed) ? null : parsed;
|
|
20559
|
+
}
|
|
20560
|
+
return null;
|
|
20561
|
+
}
|
|
20562
|
+
function taskToTimerProps(task) {
|
|
20563
|
+
return {
|
|
20564
|
+
startMs: toMilliseconds(task?.startedAt),
|
|
20565
|
+
endMs: toMilliseconds(task?.endedAt)
|
|
20566
|
+
};
|
|
20567
|
+
}
|
|
20375
20568
|
function formatCurrency4$1(x) {
|
|
20376
20569
|
if (typeof x !== "number" || x === 0) return "$0.0000";
|
|
20377
20570
|
const formatted = x.toFixed(4);
|
|
@@ -20386,13 +20579,7 @@ function formatTokensCompact$1(n2) {
|
|
|
20386
20579
|
}
|
|
20387
20580
|
return `${n2} tok`;
|
|
20388
20581
|
}
|
|
20389
|
-
function JobTable({
|
|
20390
|
-
jobs,
|
|
20391
|
-
pipeline,
|
|
20392
|
-
onOpenJob,
|
|
20393
|
-
overallElapsed,
|
|
20394
|
-
now
|
|
20395
|
-
}) {
|
|
20582
|
+
function JobTable({ jobs, pipeline, onOpenJob }) {
|
|
20396
20583
|
if (jobs.length === 0) {
|
|
20397
20584
|
return /* @__PURE__ */ jsxRuntimeExports.jsx(p$7, { className: "p-6", children: /* @__PURE__ */ jsxRuntimeExports.jsx(p$b, { size: "2", className: "text-slate-600", children: "No jobs to show here yet." }) });
|
|
20398
20585
|
}
|
|
@@ -20417,11 +20604,9 @@ function JobTable({
|
|
|
20417
20604
|
})
|
|
20418
20605
|
) : job.tasks || {};
|
|
20419
20606
|
const currentTask = job.current ? taskById[job.current] : void 0;
|
|
20420
|
-
const currentElapsedMs = currentTask ? taskDisplayDurationMs(currentTask, now) : 0;
|
|
20421
20607
|
const totalCompleted = countCompleted(job);
|
|
20422
20608
|
const totalTasks = pipeline?.tasks?.length ?? (Array.isArray(job.tasks) ? job.tasks.length : Object.keys(job.tasks || {}).length);
|
|
20423
20609
|
const progress = Number.isFinite(job.progress) ? Math.round(job.progress) : 0;
|
|
20424
|
-
const duration = overallElapsed(job);
|
|
20425
20610
|
const currentTaskName = currentTask ? currentTask.name ?? currentTask.id ?? job.current : void 0;
|
|
20426
20611
|
const currentTaskConfig = job.current && (currentTask?.config || pipeline?.taskConfig?.[job.current]) || {};
|
|
20427
20612
|
const costsSummary = job.costsSummary || {};
|
|
@@ -20448,12 +20633,26 @@ function JobTable({
|
|
|
20448
20633
|
] }) }),
|
|
20449
20634
|
/* @__PURE__ */ jsxRuntimeExports.jsx(T, { children: statusBadge(job.status) }),
|
|
20450
20635
|
/* @__PURE__ */ jsxRuntimeExports.jsx(T, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(p$4, { direction: "column", gap: "1", children: [
|
|
20451
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(p$b, { size: "2", className: "text-slate-700", children: currentTaskName ? currentTaskName : job.status === "
|
|
20636
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(p$b, { size: "2", className: "text-slate-700", children: currentTaskName ? currentTaskName : job.status === "done" ? "—" : job.current ?? "—" }),
|
|
20452
20637
|
currentTask && /* @__PURE__ */ jsxRuntimeExports.jsx(p$b, { size: "1", className: "text-slate-500", children: [
|
|
20453
20638
|
currentTaskConfig?.model || currentTask?.model,
|
|
20454
20639
|
currentTaskConfig?.temperature != null || currentTask?.temperature != null ? `temp ${currentTaskConfig?.temperature ?? currentTask?.temperature}` : null,
|
|
20455
|
-
|
|
20456
|
-
|
|
20640
|
+
(() => {
|
|
20641
|
+
const { startMs, endMs } = taskToTimerProps(currentTask);
|
|
20642
|
+
return startMs ? /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
20643
|
+
TimerText,
|
|
20644
|
+
{
|
|
20645
|
+
startMs,
|
|
20646
|
+
endMs,
|
|
20647
|
+
granularity: "second",
|
|
20648
|
+
className: "text-slate-500"
|
|
20649
|
+
}
|
|
20650
|
+
) : null;
|
|
20651
|
+
})()
|
|
20652
|
+
].filter(Boolean).map((item, index2) => /* @__PURE__ */ jsxRuntimeExports.jsxs(React.Fragment, { children: [
|
|
20653
|
+
typeof item === "string" ? item : item,
|
|
20654
|
+
index2 < 2 && " · "
|
|
20655
|
+
] }, index2)) })
|
|
20457
20656
|
] }) }),
|
|
20458
20657
|
/* @__PURE__ */ jsxRuntimeExports.jsx(T, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(p$4, { direction: "column", gap: "2", className: "w-32", children: [
|
|
20459
20658
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
@@ -20480,7 +20679,14 @@ function JobTable({
|
|
|
20480
20679
|
] }) }),
|
|
20481
20680
|
/* @__PURE__ */ jsxRuntimeExports.jsx(T, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(p$4, { align: "center", gap: "1", children: [
|
|
20482
20681
|
/* @__PURE__ */ jsxRuntimeExports.jsx(TimerReset, { className: "h-3 w-3 text-slate-500" }),
|
|
20483
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
20682
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
20683
|
+
LiveText,
|
|
20684
|
+
{
|
|
20685
|
+
cadenceMs: 1e4,
|
|
20686
|
+
compute: (now) => fmtDuration(jobCumulativeDurationMs(job, now)),
|
|
20687
|
+
className: "text-slate-700"
|
|
20688
|
+
}
|
|
20689
|
+
)
|
|
20484
20690
|
] }) }),
|
|
20485
20691
|
/* @__PURE__ */ jsxRuntimeExports.jsx(T, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
20486
20692
|
o$2,
|
|
@@ -20747,7 +20953,6 @@ function Layout({
|
|
|
20747
20953
|
pageTitle,
|
|
20748
20954
|
breadcrumbs,
|
|
20749
20955
|
actions,
|
|
20750
|
-
showBackButton = false,
|
|
20751
20956
|
backTo = "/",
|
|
20752
20957
|
maxWidth = "max-w-7xl"
|
|
20753
20958
|
}) {
|
|
@@ -20761,9 +20966,6 @@ function Layout({
|
|
|
20761
20966
|
if (location.pathname.startsWith(path)) return true;
|
|
20762
20967
|
return false;
|
|
20763
20968
|
};
|
|
20764
|
-
const handleBack = () => {
|
|
20765
|
-
navigate(backTo);
|
|
20766
|
-
};
|
|
20767
20969
|
const toggleUploadPanel = () => {
|
|
20768
20970
|
setIsUploadOpen(!isUploadOpen);
|
|
20769
20971
|
};
|
|
@@ -20819,20 +21021,6 @@ function Layout({
|
|
|
20819
21021
|
gap: "4",
|
|
20820
21022
|
children: [
|
|
20821
21023
|
/* @__PURE__ */ jsxRuntimeExports.jsxs(p$4, { align: "center", className: "min-w-0 flex-1", children: [
|
|
20822
|
-
showBackButton && /* @__PURE__ */ jsxRuntimeExports.jsxs(Root3, { delayDuration: 200, children: [
|
|
20823
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(Trigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
20824
|
-
Button,
|
|
20825
|
-
{
|
|
20826
|
-
variant: "ghost",
|
|
20827
|
-
size: "sm",
|
|
20828
|
-
onClick: handleBack,
|
|
20829
|
-
className: "shrink-0",
|
|
20830
|
-
"aria-label": "Go back",
|
|
20831
|
-
children: /* @__PURE__ */ jsxRuntimeExports.jsx(ArrowLeft, { className: "h-4 w-4" })
|
|
20832
|
-
}
|
|
20833
|
-
) }),
|
|
20834
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(Content2, { side: "bottom", sideOffset: 5, children: /* @__PURE__ */ jsxRuntimeExports.jsx(p$b, { size: "2", children: "Go back" }) })
|
|
20835
|
-
] }),
|
|
20836
21024
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
20837
21025
|
p$7,
|
|
20838
21026
|
{
|
|
@@ -20966,34 +21154,32 @@ function PromptPipelineDashboard({ isConnected }) {
|
|
|
20966
21154
|
return src.map(adaptJobSummary);
|
|
20967
21155
|
}, [apiJobs, error]);
|
|
20968
21156
|
const [activeTab, setActiveTab] = reactExports.useState("current");
|
|
20969
|
-
const now = useTicker(1e4);
|
|
20970
21157
|
const errorCount = reactExports.useMemo(
|
|
20971
|
-
() => jobs.filter((j) => j.status ===
|
|
21158
|
+
() => jobs.filter((j) => j.status === TaskState.FAILED).length,
|
|
20972
21159
|
[jobs]
|
|
20973
21160
|
);
|
|
20974
21161
|
const currentCount = reactExports.useMemo(
|
|
20975
|
-
() => jobs.filter((j) => j.status ===
|
|
21162
|
+
() => jobs.filter((j) => j.status === TaskState.RUNNING).length,
|
|
20976
21163
|
[jobs]
|
|
20977
21164
|
);
|
|
20978
21165
|
const completedCount = reactExports.useMemo(
|
|
20979
|
-
() => jobs.filter((j) => j.status ===
|
|
21166
|
+
() => jobs.filter((j) => j.status === JobStatus.COMPLETE).length,
|
|
20980
21167
|
[jobs]
|
|
20981
21168
|
);
|
|
20982
21169
|
const filteredJobs = reactExports.useMemo(() => {
|
|
20983
21170
|
switch (activeTab) {
|
|
20984
21171
|
case "current":
|
|
20985
|
-
return jobs.filter((j) => j.status ===
|
|
21172
|
+
return jobs.filter((j) => j.status === TaskState.RUNNING);
|
|
20986
21173
|
case "errors":
|
|
20987
|
-
return jobs.filter((j) => j.status ===
|
|
21174
|
+
return jobs.filter((j) => j.status === TaskState.FAILED);
|
|
20988
21175
|
case "complete":
|
|
20989
|
-
return jobs.filter((j) => j.status ===
|
|
21176
|
+
return jobs.filter((j) => j.status === JobStatus.COMPLETE);
|
|
20990
21177
|
default:
|
|
20991
21178
|
return [];
|
|
20992
21179
|
}
|
|
20993
21180
|
}, [jobs, activeTab]);
|
|
20994
|
-
const overallElapsed = (job) => jobCumulativeDurationMs(job, now);
|
|
20995
21181
|
const runningJobs = reactExports.useMemo(
|
|
20996
|
-
() => jobs.filter((j) => j.status ===
|
|
21182
|
+
() => jobs.filter((j) => j.status === TaskState.RUNNING),
|
|
20997
21183
|
[jobs]
|
|
20998
21184
|
);
|
|
20999
21185
|
const aggregateProgress = reactExports.useMemo(() => {
|
|
@@ -21042,41 +21228,42 @@ function PromptPipelineDashboard({ isConnected }) {
|
|
|
21042
21228
|
")"
|
|
21043
21229
|
] })
|
|
21044
21230
|
] }),
|
|
21045
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(f, { value: "current", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
21046
|
-
|
|
21047
|
-
|
|
21048
|
-
jobs: filteredJobs,
|
|
21049
|
-
pipeline: null,
|
|
21050
|
-
onOpenJob: openJob,
|
|
21051
|
-
overallElapsed,
|
|
21052
|
-
now
|
|
21053
|
-
}
|
|
21054
|
-
) }),
|
|
21055
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(f, { value: "errors", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
21056
|
-
JobTable,
|
|
21057
|
-
{
|
|
21058
|
-
jobs: filteredJobs,
|
|
21059
|
-
pipeline: null,
|
|
21060
|
-
onOpenJob: openJob,
|
|
21061
|
-
overallElapsed,
|
|
21062
|
-
now
|
|
21063
|
-
}
|
|
21064
|
-
) }),
|
|
21065
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(f, { value: "complete", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
21066
|
-
JobTable,
|
|
21067
|
-
{
|
|
21068
|
-
jobs: filteredJobs,
|
|
21069
|
-
pipeline: null,
|
|
21070
|
-
onOpenJob: openJob,
|
|
21071
|
-
overallElapsed,
|
|
21072
|
-
now
|
|
21073
|
-
}
|
|
21074
|
-
) })
|
|
21231
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(f, { value: "current", children: /* @__PURE__ */ jsxRuntimeExports.jsx(JobTable, { jobs: filteredJobs, pipeline: null, onOpenJob: openJob }) }),
|
|
21232
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(f, { value: "errors", children: /* @__PURE__ */ jsxRuntimeExports.jsx(JobTable, { jobs: filteredJobs, pipeline: null, onOpenJob: openJob }) }),
|
|
21233
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(f, { value: "complete", children: /* @__PURE__ */ jsxRuntimeExports.jsx(JobTable, { jobs: filteredJobs, pipeline: null, onOpenJob: openJob }) })
|
|
21075
21234
|
]
|
|
21076
21235
|
}
|
|
21077
21236
|
)
|
|
21078
21237
|
] });
|
|
21079
21238
|
}
|
|
21239
|
+
function areGeometriesEqual(prev, next, epsilon = 0.5) {
|
|
21240
|
+
if (prev === next) return true;
|
|
21241
|
+
if (!prev || !next) return false;
|
|
21242
|
+
if (prev.itemsLength !== next.itemsLength) return false;
|
|
21243
|
+
if (prev.effectiveCols !== next.effectiveCols) return false;
|
|
21244
|
+
if (!areOverlayBoxesEqual(prev.overlayBox, next.overlayBox, epsilon)) {
|
|
21245
|
+
return false;
|
|
21246
|
+
}
|
|
21247
|
+
const prevBoxes = prev.boxes;
|
|
21248
|
+
const nextBoxes = next.boxes;
|
|
21249
|
+
if (prevBoxes.length !== nextBoxes.length) return false;
|
|
21250
|
+
for (let i2 = 0; i2 < prevBoxes.length; i2++) {
|
|
21251
|
+
if (!areBoxesEqual(prevBoxes[i2], nextBoxes[i2], epsilon)) {
|
|
21252
|
+
return false;
|
|
21253
|
+
}
|
|
21254
|
+
}
|
|
21255
|
+
return true;
|
|
21256
|
+
}
|
|
21257
|
+
function areOverlayBoxesEqual(a2, b2, epsilon) {
|
|
21258
|
+
return areNumbersClose(a2.left, b2.left, epsilon) && areNumbersClose(a2.top, b2.top, epsilon) && areNumbersClose(a2.width, b2.width, epsilon) && areNumbersClose(a2.height, b2.height, epsilon) && areNumbersClose(a2.right, b2.right, epsilon) && areNumbersClose(a2.bottom, b2.bottom, epsilon);
|
|
21259
|
+
}
|
|
21260
|
+
function areBoxesEqual(a2, b2, epsilon) {
|
|
21261
|
+
if (!a2 || !b2) return a2 === b2;
|
|
21262
|
+
return areNumbersClose(a2.left, b2.left, epsilon) && areNumbersClose(a2.top, b2.top, epsilon) && areNumbersClose(a2.width, b2.width, epsilon) && areNumbersClose(a2.height, b2.height, epsilon) && areNumbersClose(a2.right, b2.right, epsilon) && areNumbersClose(a2.bottom, b2.bottom, epsilon) && areNumbersClose(a2.headerMidY, b2.headerMidY, epsilon);
|
|
21263
|
+
}
|
|
21264
|
+
function areNumbersClose(a2, b2, epsilon) {
|
|
21265
|
+
return Math.abs(a2 - b2) <= epsilon;
|
|
21266
|
+
}
|
|
21080
21267
|
function TaskFilePane({
|
|
21081
21268
|
isOpen,
|
|
21082
21269
|
jobId,
|
|
@@ -21512,11 +21699,357 @@ function TaskFilePane({
|
|
|
21512
21699
|
] })
|
|
21513
21700
|
] });
|
|
21514
21701
|
}
|
|
21515
|
-
|
|
21516
|
-
|
|
21517
|
-
|
|
21518
|
-
|
|
21519
|
-
|
|
21702
|
+
function TaskDetailSidebar({
|
|
21703
|
+
open,
|
|
21704
|
+
title,
|
|
21705
|
+
status,
|
|
21706
|
+
jobId,
|
|
21707
|
+
taskId,
|
|
21708
|
+
taskBody,
|
|
21709
|
+
filesByTypeForItem = () => ({ artifacts: [], logs: [], tmp: [] }),
|
|
21710
|
+
task,
|
|
21711
|
+
onClose,
|
|
21712
|
+
taskIndex
|
|
21713
|
+
// Add taskIndex for ID compatibility
|
|
21714
|
+
}) {
|
|
21715
|
+
const [filePaneType, setFilePaneType] = reactExports.useState("artifacts");
|
|
21716
|
+
const [filePaneOpen, setFilePaneOpen] = reactExports.useState(false);
|
|
21717
|
+
const [filePaneFilename, setFilePaneFilename] = reactExports.useState(null);
|
|
21718
|
+
const closeButtonRef = reactExports.useRef(null);
|
|
21719
|
+
const getHeaderClasses2 = (status2) => {
|
|
21720
|
+
switch (status2) {
|
|
21721
|
+
case TaskState.DONE:
|
|
21722
|
+
return "bg-green-50 border-green-200 text-green-700";
|
|
21723
|
+
case TaskState.RUNNING:
|
|
21724
|
+
return "bg-amber-50 border-amber-200 text-amber-700";
|
|
21725
|
+
case TaskState.FAILED:
|
|
21726
|
+
return "bg-pink-50 border-pink-200 text-pink-700";
|
|
21727
|
+
default:
|
|
21728
|
+
return "bg-gray-100 border-gray-200 text-gray-700";
|
|
21729
|
+
}
|
|
21730
|
+
};
|
|
21731
|
+
reactExports.useEffect(() => {
|
|
21732
|
+
if (open && closeButtonRef.current) {
|
|
21733
|
+
closeButtonRef.current.focus();
|
|
21734
|
+
}
|
|
21735
|
+
}, [open]);
|
|
21736
|
+
reactExports.useEffect(() => {
|
|
21737
|
+
if (open) {
|
|
21738
|
+
setFilePaneType("artifacts");
|
|
21739
|
+
setFilePaneOpen(false);
|
|
21740
|
+
setFilePaneFilename(null);
|
|
21741
|
+
}
|
|
21742
|
+
}, [open]);
|
|
21743
|
+
reactExports.useEffect(() => {
|
|
21744
|
+
setFilePaneFilename(null);
|
|
21745
|
+
setFilePaneOpen(false);
|
|
21746
|
+
}, [filePaneType]);
|
|
21747
|
+
const handleFileClick = (filename) => {
|
|
21748
|
+
setFilePaneFilename(filename);
|
|
21749
|
+
setFilePaneOpen(true);
|
|
21750
|
+
};
|
|
21751
|
+
const handleFilePaneClose = () => {
|
|
21752
|
+
setFilePaneOpen(false);
|
|
21753
|
+
setFilePaneFilename(null);
|
|
21754
|
+
};
|
|
21755
|
+
if (!open) {
|
|
21756
|
+
return null;
|
|
21757
|
+
}
|
|
21758
|
+
const filesForStep = filesByTypeForItem(task);
|
|
21759
|
+
const filesForTab = filesForStep[filePaneType] ?? [];
|
|
21760
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
21761
|
+
"aside",
|
|
21762
|
+
{
|
|
21763
|
+
role: "dialog",
|
|
21764
|
+
"aria-modal": "true",
|
|
21765
|
+
"aria-labelledby": `slide-over-title-${taskIndex}`,
|
|
21766
|
+
"aria-hidden": false,
|
|
21767
|
+
className: `fixed inset-y-0 right-0 z-[2000] w-full max-w-4xl bg-white border-l border-gray-200 transform transition-transform duration-300 ease-out translate-x-0`,
|
|
21768
|
+
children: [
|
|
21769
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
21770
|
+
"div",
|
|
21771
|
+
{
|
|
21772
|
+
className: `px-6 py-4 border-b flex items-center justify-between ${getHeaderClasses2(status)}`,
|
|
21773
|
+
children: [
|
|
21774
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
21775
|
+
"div",
|
|
21776
|
+
{
|
|
21777
|
+
id: `slide-over-title-${taskIndex}`,
|
|
21778
|
+
className: "text-lg font-semibold truncate",
|
|
21779
|
+
children: title
|
|
21780
|
+
}
|
|
21781
|
+
),
|
|
21782
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
21783
|
+
"button",
|
|
21784
|
+
{
|
|
21785
|
+
ref: closeButtonRef,
|
|
21786
|
+
type: "button",
|
|
21787
|
+
"aria-label": "Close details",
|
|
21788
|
+
onClick: onClose,
|
|
21789
|
+
className: "rounded-md border border-gray-300 text-gray-700 hover:bg-gray-50 px-3 py-1.5 text-base",
|
|
21790
|
+
children: "×"
|
|
21791
|
+
}
|
|
21792
|
+
)
|
|
21793
|
+
]
|
|
21794
|
+
}
|
|
21795
|
+
),
|
|
21796
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-6 space-y-8 overflow-y-auto h-full", children: [
|
|
21797
|
+
status === TaskState.FAILED && taskBody && /* @__PURE__ */ jsxRuntimeExports.jsx("section", { "aria-label": "Error", children: /* @__PURE__ */ jsxRuntimeExports.jsx(n$2, { role: "alert", "aria-live": "assertive", children: /* @__PURE__ */ jsxRuntimeExports.jsx(u$1, { className: "whitespace-pre-wrap break-words", children: taskBody }) }) }),
|
|
21798
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("section", { className: "mt-6", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between mb-4", children: [
|
|
21799
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-base font-semibold text-gray-900", children: "Files" }),
|
|
21800
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center space-x-2", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex rounded-lg border border-gray-200 bg-gray-50 p-1", children: [
|
|
21801
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
21802
|
+
"button",
|
|
21803
|
+
{
|
|
21804
|
+
onClick: () => setFilePaneType("artifacts"),
|
|
21805
|
+
className: `px-3 py-1.5 text-sm font-medium rounded-md transition-colors ${filePaneType === "artifacts" ? "bg-white text-gray-900 shadow-sm" : "text-gray-600 hover:text-gray-900"}`,
|
|
21806
|
+
children: "Artifacts"
|
|
21807
|
+
}
|
|
21808
|
+
),
|
|
21809
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
21810
|
+
"button",
|
|
21811
|
+
{
|
|
21812
|
+
onClick: () => setFilePaneType("logs"),
|
|
21813
|
+
className: `px-3 py-1.5 text-sm font-medium rounded-md transition-colors ${filePaneType === "logs" ? "bg-white text-gray-900 shadow-sm" : "text-gray-600 hover:text-gray-900"}`,
|
|
21814
|
+
children: "Logs"
|
|
21815
|
+
}
|
|
21816
|
+
),
|
|
21817
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
21818
|
+
"button",
|
|
21819
|
+
{
|
|
21820
|
+
onClick: () => setFilePaneType("tmp"),
|
|
21821
|
+
className: `px-3 py-1.5 text-sm font-medium rounded-md transition-colors ${filePaneType === "tmp" ? "bg-white text-gray-900 shadow-sm" : "text-gray-600 hover:text-gray-900"}`,
|
|
21822
|
+
children: "Temp"
|
|
21823
|
+
}
|
|
21824
|
+
)
|
|
21825
|
+
] }) })
|
|
21826
|
+
] }) }),
|
|
21827
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-2", children: [
|
|
21828
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-sm text-gray-600", children: [
|
|
21829
|
+
filePaneType.charAt(0).toUpperCase() + filePaneType.slice(1),
|
|
21830
|
+
" files for ",
|
|
21831
|
+
taskId
|
|
21832
|
+
] }),
|
|
21833
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-1", children: filesForTab.length === 0 ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-sm text-gray-500 italic py-4 text-center", children: [
|
|
21834
|
+
"No ",
|
|
21835
|
+
filePaneType,
|
|
21836
|
+
" files available for this task"
|
|
21837
|
+
] }) : filesForTab.map((name) => /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
21838
|
+
"div",
|
|
21839
|
+
{
|
|
21840
|
+
className: "flex items-center justify-between p-2 rounded border border-gray-200 hover:border-gray-300 hover:bg-gray-50 cursor-pointer transition-colors",
|
|
21841
|
+
onClick: () => handleFileClick(name),
|
|
21842
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center space-x-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm text-gray-700", children: name }) })
|
|
21843
|
+
},
|
|
21844
|
+
`${filePaneType}-${name}`
|
|
21845
|
+
)) })
|
|
21846
|
+
] }),
|
|
21847
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
21848
|
+
TaskFilePane,
|
|
21849
|
+
{
|
|
21850
|
+
isOpen: filePaneOpen,
|
|
21851
|
+
jobId,
|
|
21852
|
+
taskId,
|
|
21853
|
+
type: filePaneType,
|
|
21854
|
+
filename: filePaneFilename,
|
|
21855
|
+
onClose: handleFilePaneClose
|
|
21856
|
+
}
|
|
21857
|
+
)
|
|
21858
|
+
] })
|
|
21859
|
+
]
|
|
21860
|
+
}
|
|
21861
|
+
);
|
|
21862
|
+
}
|
|
21863
|
+
React.memo(TaskDetailSidebar);
|
|
21864
|
+
function RestartJobModal({
|
|
21865
|
+
open,
|
|
21866
|
+
onClose,
|
|
21867
|
+
onConfirm,
|
|
21868
|
+
jobId,
|
|
21869
|
+
taskId,
|
|
21870
|
+
isSubmitting = false
|
|
21871
|
+
}) {
|
|
21872
|
+
const modalRef = reactExports.useRef(null);
|
|
21873
|
+
reactExports.useEffect(() => {
|
|
21874
|
+
const handleKeyDown2 = (e2) => {
|
|
21875
|
+
if (e2.key === "Escape" && open) {
|
|
21876
|
+
e2.preventDefault();
|
|
21877
|
+
onClose();
|
|
21878
|
+
}
|
|
21879
|
+
};
|
|
21880
|
+
if (open) {
|
|
21881
|
+
document.addEventListener("keydown", handleKeyDown2);
|
|
21882
|
+
if (modalRef.current) {
|
|
21883
|
+
modalRef.current.focus();
|
|
21884
|
+
}
|
|
21885
|
+
return () => {
|
|
21886
|
+
document.removeEventListener("keydown", handleKeyDown2);
|
|
21887
|
+
};
|
|
21888
|
+
}
|
|
21889
|
+
}, [open, onClose]);
|
|
21890
|
+
const handleKeyDown = (e2) => {
|
|
21891
|
+
if (e2.key === "Enter" && !isSubmitting && open) {
|
|
21892
|
+
e2.preventDefault();
|
|
21893
|
+
onConfirm();
|
|
21894
|
+
}
|
|
21895
|
+
};
|
|
21896
|
+
if (!open) return null;
|
|
21897
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
21898
|
+
"div",
|
|
21899
|
+
{
|
|
21900
|
+
className: "fixed inset-0 z-50 flex items-center justify-center",
|
|
21901
|
+
"aria-hidden": !open,
|
|
21902
|
+
children: [
|
|
21903
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
21904
|
+
"div",
|
|
21905
|
+
{
|
|
21906
|
+
className: "absolute inset-0 bg-black/50",
|
|
21907
|
+
onClick: onClose,
|
|
21908
|
+
"aria-hidden": "true"
|
|
21909
|
+
}
|
|
21910
|
+
),
|
|
21911
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
21912
|
+
"div",
|
|
21913
|
+
{
|
|
21914
|
+
ref: modalRef,
|
|
21915
|
+
role: "dialog",
|
|
21916
|
+
"aria-modal": "true",
|
|
21917
|
+
"aria-labelledby": "restart-modal-title",
|
|
21918
|
+
"aria-describedby": "restart-modal-description",
|
|
21919
|
+
className: "relative bg-white rounded-lg shadow-2xl border border-gray-200 max-w-lg w-full mx-4 outline-none",
|
|
21920
|
+
style: { minWidth: "320px", maxWidth: "560px" },
|
|
21921
|
+
tabIndex: -1,
|
|
21922
|
+
onKeyDown: handleKeyDown,
|
|
21923
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-6", children: [
|
|
21924
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
21925
|
+
r$8,
|
|
21926
|
+
{
|
|
21927
|
+
id: "restart-modal-title",
|
|
21928
|
+
as: "h2",
|
|
21929
|
+
size: "5",
|
|
21930
|
+
className: "mb-4 text-gray-900",
|
|
21931
|
+
children: taskId ? `Restart from ${taskId}` : "Restart job (reset progress)"
|
|
21932
|
+
}
|
|
21933
|
+
),
|
|
21934
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(p$7, { id: "restart-modal-description", className: "mb-6", children: [
|
|
21935
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(p$b, { as: "p", className: "text-gray-700 mb-4", children: taskId ? `This will restart the job from the "${taskId}" task. Tasks before ${taskId} will remain completed, while ${taskId} and all subsequent tasks will be reset to pending. Files and artifacts are preserved. A new background run will start automatically. This cannot be undone.` : "This will clear the job's progress and active stage and reset all tasks to pending. Files and artifacts are preserved. A new background run will start automatically. This cannot be undone." }),
|
|
21936
|
+
taskId && /* @__PURE__ */ jsxRuntimeExports.jsxs(p$b, { as: "p", className: "text-sm text-gray-600 mb-3", children: [
|
|
21937
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: "Triggered from task:" }),
|
|
21938
|
+
" ",
|
|
21939
|
+
taskId
|
|
21940
|
+
] }),
|
|
21941
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(p$b, { as: "p", className: "text-sm text-gray-500 italic", children: "Note: Job must be in current lifecycle and not running." })
|
|
21942
|
+
] }),
|
|
21943
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(p$4, { gap: "3", justify: "end", children: [
|
|
21944
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
21945
|
+
Button,
|
|
21946
|
+
{
|
|
21947
|
+
variant: "outline",
|
|
21948
|
+
onClick: onClose,
|
|
21949
|
+
disabled: isSubmitting,
|
|
21950
|
+
className: "min-w-[80px]",
|
|
21951
|
+
children: "Cancel"
|
|
21952
|
+
}
|
|
21953
|
+
),
|
|
21954
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
21955
|
+
Button,
|
|
21956
|
+
{
|
|
21957
|
+
variant: "destructive",
|
|
21958
|
+
onClick: onConfirm,
|
|
21959
|
+
disabled: isSubmitting,
|
|
21960
|
+
className: "min-w-[80px]",
|
|
21961
|
+
children: isSubmitting ? "Restarting..." : "Restart"
|
|
21962
|
+
}
|
|
21963
|
+
)
|
|
21964
|
+
] })
|
|
21965
|
+
] })
|
|
21966
|
+
}
|
|
21967
|
+
)
|
|
21968
|
+
]
|
|
21969
|
+
}
|
|
21970
|
+
) });
|
|
21971
|
+
}
|
|
21972
|
+
async function restartJob(jobId, opts = {}) {
|
|
21973
|
+
const options = {
|
|
21974
|
+
clearTokenUsage: true,
|
|
21975
|
+
...opts.options
|
|
21976
|
+
};
|
|
21977
|
+
const requestBody = opts.fromTask ? { fromTask: opts.fromTask, options } : { mode: "clean-slate", options };
|
|
21978
|
+
try {
|
|
21979
|
+
const response = await fetch(
|
|
21980
|
+
`/api/jobs/${encodeURIComponent(jobId)}/restart`,
|
|
21981
|
+
{
|
|
21982
|
+
method: "POST",
|
|
21983
|
+
headers: {
|
|
21984
|
+
"Content-Type": "application/json"
|
|
21985
|
+
},
|
|
21986
|
+
body: JSON.stringify(requestBody)
|
|
21987
|
+
}
|
|
21988
|
+
);
|
|
21989
|
+
if (!response.ok) {
|
|
21990
|
+
let errorData;
|
|
21991
|
+
try {
|
|
21992
|
+
errorData = await response.json();
|
|
21993
|
+
} catch {
|
|
21994
|
+
errorData = { message: response.statusText };
|
|
21995
|
+
}
|
|
21996
|
+
throw {
|
|
21997
|
+
code: errorData.code || getErrorCodeFromStatus(response.status),
|
|
21998
|
+
message: getRestartErrorMessage(errorData, response.status),
|
|
21999
|
+
status: response.status
|
|
22000
|
+
};
|
|
22001
|
+
}
|
|
22002
|
+
return await response.json();
|
|
22003
|
+
} catch (error) {
|
|
22004
|
+
if (error.code && error.message) {
|
|
22005
|
+
throw error;
|
|
22006
|
+
}
|
|
22007
|
+
throw {
|
|
22008
|
+
code: "network_error",
|
|
22009
|
+
message: error.message || "Failed to connect to server"
|
|
22010
|
+
};
|
|
22011
|
+
}
|
|
22012
|
+
}
|
|
22013
|
+
function getErrorCodeFromStatus(status) {
|
|
22014
|
+
switch (status) {
|
|
22015
|
+
case 404:
|
|
22016
|
+
return "job_not_found";
|
|
22017
|
+
case 409:
|
|
22018
|
+
return "conflict";
|
|
22019
|
+
case 500:
|
|
22020
|
+
return "spawn_failed";
|
|
22021
|
+
default:
|
|
22022
|
+
return "unknown_error";
|
|
22023
|
+
}
|
|
22024
|
+
}
|
|
22025
|
+
function getRestartErrorMessage(errorData, status) {
|
|
22026
|
+
if (status === 409) {
|
|
22027
|
+
if (errorData.code === "job_running") {
|
|
22028
|
+
return "Job is currently running; restart is unavailable.";
|
|
22029
|
+
}
|
|
22030
|
+
if (errorData.code === "unsupported_lifecycle") {
|
|
22031
|
+
return "Job must be in current to restart.";
|
|
22032
|
+
}
|
|
22033
|
+
if (errorData.message?.includes("job_running")) {
|
|
22034
|
+
return "Job is currently running; restart is unavailable.";
|
|
22035
|
+
}
|
|
22036
|
+
if (errorData.message?.includes("unsupported_lifecycle")) {
|
|
22037
|
+
return "Job must be in current to restart.";
|
|
22038
|
+
}
|
|
22039
|
+
}
|
|
22040
|
+
if (status === 404) {
|
|
22041
|
+
return "Job not found.";
|
|
22042
|
+
}
|
|
22043
|
+
if (status === 500) {
|
|
22044
|
+
return "Failed to start restart. Try again.";
|
|
22045
|
+
}
|
|
22046
|
+
return errorData.message || "Failed to restart job.";
|
|
22047
|
+
}
|
|
22048
|
+
const CATEGORY_KEYS = ["artifacts", "logs", "tmp"];
|
|
22049
|
+
const LEGACY_KEY_SET = /* @__PURE__ */ new Set([
|
|
22050
|
+
"input",
|
|
22051
|
+
"inputs",
|
|
22052
|
+
"output",
|
|
21520
22053
|
"outputs",
|
|
21521
22054
|
"legacyInput",
|
|
21522
22055
|
"legacyOutput",
|
|
@@ -21613,6 +22146,10 @@ function getTaskFilesForTask(job, taskId) {
|
|
|
21613
22146
|
console.debug("[getTaskFilesForTask] Task files result:", { taskId, result });
|
|
21614
22147
|
return result;
|
|
21615
22148
|
}
|
|
22149
|
+
const prefersReducedMotion = () => {
|
|
22150
|
+
if (typeof window === "undefined") return false;
|
|
22151
|
+
return window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
22152
|
+
};
|
|
21616
22153
|
function upperFirst(s2) {
|
|
21617
22154
|
return typeof s2 === "string" && s2.length > 0 ? s2.charAt(0).toUpperCase() + s2.slice(1) : s2;
|
|
21618
22155
|
}
|
|
@@ -21635,26 +22172,136 @@ function formatStepName(item, idx) {
|
|
|
21635
22172
|
const raw = item.title ?? item.id ?? `Step ${idx + 1}`;
|
|
21636
22173
|
return upperFirst(item.title ? item.title : raw);
|
|
21637
22174
|
}
|
|
21638
|
-
const
|
|
21639
|
-
|
|
21640
|
-
|
|
21641
|
-
|
|
21642
|
-
|
|
21643
|
-
|
|
21644
|
-
|
|
21645
|
-
|
|
21646
|
-
|
|
21647
|
-
|
|
21648
|
-
|
|
21649
|
-
},
|
|
21650
|
-
group: (label) => console.group(`${prefix} ${label}`),
|
|
21651
|
-
groupEnd: () => console.groupEnd(),
|
|
21652
|
-
table: (data, title) => {
|
|
21653
|
-
console.log(`${prefix} ${title}:`);
|
|
21654
|
-
console.table(data);
|
|
21655
|
-
}
|
|
21656
|
-
};
|
|
22175
|
+
const getHeaderClasses = (status) => {
|
|
22176
|
+
switch (status) {
|
|
22177
|
+
case TaskState.DONE:
|
|
22178
|
+
return "bg-green-50 border-green-200 text-green-700";
|
|
22179
|
+
case TaskState.RUNNING:
|
|
22180
|
+
return "bg-amber-50 border-amber-200 text-amber-700";
|
|
22181
|
+
case TaskState.FAILED:
|
|
22182
|
+
return "bg-pink-50 border-pink-200 text-pink-700";
|
|
22183
|
+
default:
|
|
22184
|
+
return "bg-gray-100 border-gray-200 text-gray-700";
|
|
22185
|
+
}
|
|
21657
22186
|
};
|
|
22187
|
+
const canShowRestart = (status) => {
|
|
22188
|
+
return status === TaskState.FAILED || status === TaskState.DONE;
|
|
22189
|
+
};
|
|
22190
|
+
const TaskCard = reactExports.memo(function TaskCard2({
|
|
22191
|
+
item,
|
|
22192
|
+
idx,
|
|
22193
|
+
nodeRef,
|
|
22194
|
+
status,
|
|
22195
|
+
isActive,
|
|
22196
|
+
canRestart,
|
|
22197
|
+
isSubmitting,
|
|
22198
|
+
getRestartDisabledReason,
|
|
22199
|
+
onClick,
|
|
22200
|
+
onKeyDown,
|
|
22201
|
+
handleRestartClick
|
|
22202
|
+
}) {
|
|
22203
|
+
const { startMs, endMs } = taskToTimerProps(item);
|
|
22204
|
+
const reducedMotion = prefersReducedMotion();
|
|
22205
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
22206
|
+
"div",
|
|
22207
|
+
{
|
|
22208
|
+
ref: nodeRef,
|
|
22209
|
+
role: "listitem",
|
|
22210
|
+
"aria-current": isActive ? "step" : void 0,
|
|
22211
|
+
tabIndex: 0,
|
|
22212
|
+
onClick,
|
|
22213
|
+
onKeyDown,
|
|
22214
|
+
className: `cursor-pointer rounded-lg border border-gray-400 ${status === TaskState.PENDING ? "bg-gray-50" : "bg-white"} overflow-hidden flex flex-col ${reducedMotion ? "" : "transition-all duration-200 ease-in-out"} outline outline-2 outline-transparent hover:outline-gray-400/70 focus-visible:outline-blue-500/60`,
|
|
22215
|
+
children: [
|
|
22216
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
22217
|
+
"div",
|
|
22218
|
+
{
|
|
22219
|
+
"data-role": "card-header",
|
|
22220
|
+
className: `rounded-t-lg px-4 py-2 border-b flex items-center justify-between gap-3 ${reducedMotion ? "" : "transition-opacity duration-300 ease-in-out"} ${getHeaderClasses(status)}`,
|
|
22221
|
+
children: [
|
|
22222
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "font-medium truncate", children: formatStepName(item, idx) }),
|
|
22223
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center gap-2", children: status === TaskState.RUNNING ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
22224
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "relative h-4 w-4", "aria-label": "Active", children: [
|
|
22225
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "sr-only", children: "Active" }),
|
|
22226
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "absolute inset-0 rounded-full border-2 border-amber-200" }),
|
|
22227
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
22228
|
+
"span",
|
|
22229
|
+
{
|
|
22230
|
+
className: `absolute inset-0 rounded-full border-2 border-transparent border-t-amber-600 ${reducedMotion ? "" : "animate-spin"}`
|
|
22231
|
+
}
|
|
22232
|
+
)
|
|
22233
|
+
] }),
|
|
22234
|
+
item.stage && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
22235
|
+
"span",
|
|
22236
|
+
{
|
|
22237
|
+
className: "text-[11px] font-medium opacity-80 truncate uppercase tracking-wide",
|
|
22238
|
+
title: item.stage,
|
|
22239
|
+
children: formatStageLabel(item.stage)
|
|
22240
|
+
}
|
|
22241
|
+
),
|
|
22242
|
+
startMs && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
22243
|
+
TimerText,
|
|
22244
|
+
{
|
|
22245
|
+
startMs,
|
|
22246
|
+
granularity: "second",
|
|
22247
|
+
className: "text-[11px] opacity-80"
|
|
22248
|
+
}
|
|
22249
|
+
)
|
|
22250
|
+
] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
22251
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
22252
|
+
"span",
|
|
22253
|
+
{
|
|
22254
|
+
className: `text-[11px] uppercase tracking-wide opacity-80${reducedMotion ? "" : " transition-opacity duration-200"}`,
|
|
22255
|
+
children: [
|
|
22256
|
+
status,
|
|
22257
|
+
status === TaskState.FAILED && item.stage && /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
22258
|
+
"span",
|
|
22259
|
+
{
|
|
22260
|
+
className: "text-[11px] font-medium opacity-80 truncate ml-2 uppercase tracking-wide",
|
|
22261
|
+
title: item.stage,
|
|
22262
|
+
children: [
|
|
22263
|
+
"(",
|
|
22264
|
+
formatStageLabel(item.stage),
|
|
22265
|
+
")"
|
|
22266
|
+
]
|
|
22267
|
+
}
|
|
22268
|
+
)
|
|
22269
|
+
]
|
|
22270
|
+
}
|
|
22271
|
+
),
|
|
22272
|
+
status === TaskState.DONE && startMs && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
22273
|
+
TimerText,
|
|
22274
|
+
{
|
|
22275
|
+
startMs,
|
|
22276
|
+
endMs: endMs || item.finishedAt,
|
|
22277
|
+
granularity: "minute",
|
|
22278
|
+
className: "text-[11px] opacity-80"
|
|
22279
|
+
}
|
|
22280
|
+
)
|
|
22281
|
+
] }) })
|
|
22282
|
+
]
|
|
22283
|
+
}
|
|
22284
|
+
),
|
|
22285
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-4", children: [
|
|
22286
|
+
item.subtitle && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-sm text-gray-600", children: item.subtitle }),
|
|
22287
|
+
item.body && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-2 text-sm text-gray-700", children: item.body }),
|
|
22288
|
+
canShowRestart(status) && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-3 pt-3 border-t border-gray-100", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
22289
|
+
Button,
|
|
22290
|
+
{
|
|
22291
|
+
variant: "outline",
|
|
22292
|
+
size: "sm",
|
|
22293
|
+
onClick: (e2) => handleRestartClick(e2, item.id),
|
|
22294
|
+
disabled: !canRestart || isSubmitting,
|
|
22295
|
+
className: "text-xs cursor-pointer disabled:cursor-not-allowed",
|
|
22296
|
+
title: !canRestart ? getRestartDisabledReason() : `Restart job from ${item.id}`,
|
|
22297
|
+
children: "Restart"
|
|
22298
|
+
}
|
|
22299
|
+
) })
|
|
22300
|
+
] })
|
|
22301
|
+
]
|
|
22302
|
+
}
|
|
22303
|
+
);
|
|
22304
|
+
});
|
|
21658
22305
|
function DAGGrid({
|
|
21659
22306
|
items,
|
|
21660
22307
|
cols = 3,
|
|
@@ -21663,28 +22310,19 @@ function DAGGrid({
|
|
|
21663
22310
|
jobId,
|
|
21664
22311
|
filesByTypeForItem = () => createEmptyTaskFiles()
|
|
21665
22312
|
}) {
|
|
21666
|
-
const logger = React.useMemo(() => createDAGGridLogger(jobId), [jobId]);
|
|
21667
22313
|
const overlayRef = reactExports.useRef(null);
|
|
21668
22314
|
const gridRef = reactExports.useRef(null);
|
|
21669
22315
|
const nodeRefs = reactExports.useRef([]);
|
|
21670
22316
|
const [lines, setLines] = reactExports.useState([]);
|
|
21671
22317
|
const [effectiveCols, setEffectiveCols] = reactExports.useState(cols);
|
|
21672
|
-
const [openIdx, setOpenIdx] = reactExports.useState(
|
|
21673
|
-
const [
|
|
21674
|
-
const [
|
|
21675
|
-
const [
|
|
21676
|
-
const [
|
|
21677
|
-
|
|
21678
|
-
|
|
21679
|
-
|
|
21680
|
-
itemCount: items?.length,
|
|
21681
|
-
cols,
|
|
21682
|
-
activeIndex,
|
|
21683
|
-
jobId
|
|
21684
|
-
});
|
|
21685
|
-
logger.log("Items data:", items);
|
|
21686
|
-
logger.groupEnd();
|
|
21687
|
-
}, [items, cols, activeIndex, jobId, logger]);
|
|
22318
|
+
const [openIdx, setOpenIdx] = reactExports.useState(-1);
|
|
22319
|
+
const [restartModalOpen, setRestartModalOpen] = reactExports.useState(false);
|
|
22320
|
+
const [restartTaskId, setRestartTaskId] = reactExports.useState(null);
|
|
22321
|
+
const [isSubmitting, setIsSubmitting] = reactExports.useState(false);
|
|
22322
|
+
const [alertMessage, setAlertMessage] = reactExports.useState(null);
|
|
22323
|
+
const [alertType, setAlertType] = reactExports.useState("info");
|
|
22324
|
+
const prevGeometryRef = reactExports.useRef(null);
|
|
22325
|
+
const rafRef = reactExports.useRef(null);
|
|
21688
22326
|
nodeRefs.current = reactExports.useMemo(
|
|
21689
22327
|
() => items.map((_, i2) => nodeRefs.current[i2] ?? reactExports.createRef()),
|
|
21690
22328
|
[items.length]
|
|
@@ -21710,9 +22348,10 @@ function DAGGrid({
|
|
|
21710
22348
|
const end = Math.min(start + effectiveCols, items.length);
|
|
21711
22349
|
const slice = Array.from({ length: end - start }, (_, k) => start + k);
|
|
21712
22350
|
const rowLen = slice.length;
|
|
21713
|
-
const
|
|
21714
|
-
if (
|
|
22351
|
+
const isReversedRow = r2 % 2 === 1;
|
|
22352
|
+
if (isReversedRow) {
|
|
21715
22353
|
const reversed = slice.reverse();
|
|
22354
|
+
const pad = effectiveCols - rowLen;
|
|
21716
22355
|
order.push(...Array(pad).fill(-1), ...reversed);
|
|
21717
22356
|
} else {
|
|
21718
22357
|
order.push(...slice);
|
|
@@ -21724,11 +22363,11 @@ function DAGGrid({
|
|
|
21724
22363
|
if (typeof window === "undefined" || !overlayRef.current || items.length === 0) {
|
|
21725
22364
|
return;
|
|
21726
22365
|
}
|
|
21727
|
-
let isComputing = false;
|
|
21728
22366
|
const compute = () => {
|
|
21729
|
-
if (
|
|
21730
|
-
|
|
21731
|
-
|
|
22367
|
+
if (rafRef.current) {
|
|
22368
|
+
cancelAnimationFrame(rafRef.current);
|
|
22369
|
+
}
|
|
22370
|
+
rafRef.current = requestAnimationFrame(() => {
|
|
21732
22371
|
if (!overlayRef.current) return;
|
|
21733
22372
|
const overlayBox = overlayRef.current.getBoundingClientRect();
|
|
21734
22373
|
const boxes = nodeRefs.current.map((r2) => {
|
|
@@ -21750,6 +22389,17 @@ function DAGGrid({
|
|
|
21750
22389
|
headerMidY
|
|
21751
22390
|
};
|
|
21752
22391
|
});
|
|
22392
|
+
const currentGeometry = {
|
|
22393
|
+
overlayBox,
|
|
22394
|
+
boxes: boxes.filter(Boolean),
|
|
22395
|
+
effectiveCols,
|
|
22396
|
+
itemsLength: items.length
|
|
22397
|
+
};
|
|
22398
|
+
const geometryChanged = !prevGeometryRef.current || !areGeometriesEqual(prevGeometryRef.current, currentGeometry);
|
|
22399
|
+
if (!geometryChanged) {
|
|
22400
|
+
rafRef.current = null;
|
|
22401
|
+
return;
|
|
22402
|
+
}
|
|
21753
22403
|
const newLines = [];
|
|
21754
22404
|
for (let i2 = 0; i2 < items.length - 1; i2++) {
|
|
21755
22405
|
const a2 = boxes[i2];
|
|
@@ -21784,10 +22434,10 @@ function DAGGrid({
|
|
|
21784
22434
|
});
|
|
21785
22435
|
}
|
|
21786
22436
|
}
|
|
22437
|
+
prevGeometryRef.current = currentGeometry;
|
|
21787
22438
|
setLines(newLines);
|
|
21788
|
-
|
|
21789
|
-
|
|
21790
|
-
}
|
|
22439
|
+
rafRef.current = null;
|
|
22440
|
+
});
|
|
21791
22441
|
};
|
|
21792
22442
|
compute();
|
|
21793
22443
|
let ro = null;
|
|
@@ -21804,66 +22454,147 @@ function DAGGrid({
|
|
|
21804
22454
|
if (ro) ro.disconnect();
|
|
21805
22455
|
window.removeEventListener("resize", handleResize);
|
|
21806
22456
|
window.removeEventListener("scroll", handleScroll, true);
|
|
22457
|
+
if (rafRef.current) {
|
|
22458
|
+
cancelAnimationFrame(rafRef.current);
|
|
22459
|
+
}
|
|
21807
22460
|
};
|
|
21808
22461
|
}, [items, effectiveCols, visualOrder]);
|
|
21809
22462
|
const getStatus = (index2) => {
|
|
21810
22463
|
const item = items[index2];
|
|
21811
22464
|
const s2 = item?.status;
|
|
21812
|
-
if (s2 ===
|
|
21813
|
-
if (s2 ===
|
|
21814
|
-
if (s2 ===
|
|
22465
|
+
if (s2 === TaskState.FAILED) return TaskState.FAILED;
|
|
22466
|
+
if (s2 === TaskState.DONE) return TaskState.DONE;
|
|
22467
|
+
if (s2 === TaskState.RUNNING) return TaskState.RUNNING;
|
|
21815
22468
|
if (typeof activeIndex === "number") {
|
|
21816
|
-
if (index2 < activeIndex) return
|
|
21817
|
-
if (index2 === activeIndex) return
|
|
21818
|
-
return
|
|
21819
|
-
}
|
|
21820
|
-
return "pending";
|
|
21821
|
-
};
|
|
21822
|
-
const getHeaderClasses = (status) => {
|
|
21823
|
-
switch (status) {
|
|
21824
|
-
case "done":
|
|
21825
|
-
return "bg-green-50 border-green-200 text-green-700";
|
|
21826
|
-
case "running":
|
|
21827
|
-
return "bg-amber-50 border-amber-200 text-amber-700";
|
|
21828
|
-
case "failed":
|
|
21829
|
-
return "bg-pink-50 border-pink-200 text-pink-700";
|
|
21830
|
-
default:
|
|
21831
|
-
return "bg-gray-100 border-gray-200 text-gray-700";
|
|
22469
|
+
if (index2 < activeIndex) return TaskState.DONE;
|
|
22470
|
+
if (index2 === activeIndex) return TaskState.RUNNING;
|
|
22471
|
+
return TaskState.PENDING;
|
|
21832
22472
|
}
|
|
22473
|
+
return TaskState.PENDING;
|
|
21833
22474
|
};
|
|
21834
22475
|
React.useEffect(() => {
|
|
21835
22476
|
const handleKeyDown = (e2) => {
|
|
21836
|
-
if (e2.key === "Escape" && openIdx !==
|
|
21837
|
-
setOpenIdx(
|
|
21838
|
-
setSelectedFile(null);
|
|
22477
|
+
if (e2.key === "Escape" && openIdx !== -1) {
|
|
22478
|
+
setOpenIdx(-1);
|
|
21839
22479
|
}
|
|
21840
22480
|
};
|
|
21841
|
-
if (openIdx !==
|
|
22481
|
+
if (openIdx !== -1) {
|
|
21842
22482
|
document.addEventListener("keydown", handleKeyDown);
|
|
21843
22483
|
return () => document.removeEventListener("keydown", handleKeyDown);
|
|
21844
22484
|
}
|
|
21845
22485
|
}, [openIdx]);
|
|
21846
|
-
const
|
|
21847
|
-
|
|
21848
|
-
|
|
21849
|
-
|
|
22486
|
+
const handleRestartClick = (e2, taskId) => {
|
|
22487
|
+
e2.stopPropagation();
|
|
22488
|
+
setRestartTaskId(taskId);
|
|
22489
|
+
setRestartModalOpen(true);
|
|
22490
|
+
};
|
|
22491
|
+
const handleRestartConfirm = async () => {
|
|
22492
|
+
if (!jobId || isSubmitting) return;
|
|
22493
|
+
setIsSubmitting(true);
|
|
22494
|
+
setAlertMessage(null);
|
|
22495
|
+
try {
|
|
22496
|
+
const restartOptions = {};
|
|
22497
|
+
if (restartTaskId) {
|
|
22498
|
+
restartOptions.fromTask = restartTaskId;
|
|
22499
|
+
}
|
|
22500
|
+
await restartJob(jobId, restartOptions);
|
|
22501
|
+
const successMessage = restartTaskId ? `Restart requested from ${restartTaskId}. The job will start from that task in the background.` : "Restart requested. The job will reset to pending and start in the background.";
|
|
22502
|
+
setAlertMessage(successMessage);
|
|
22503
|
+
setAlertType("success");
|
|
22504
|
+
setRestartModalOpen(false);
|
|
22505
|
+
setRestartTaskId(null);
|
|
22506
|
+
} catch (error) {
|
|
22507
|
+
let message = "Failed to start restart. Try again.";
|
|
22508
|
+
let type = "error";
|
|
22509
|
+
switch (error.code) {
|
|
22510
|
+
case "job_running":
|
|
22511
|
+
message = "Job is currently running; restart is unavailable.";
|
|
22512
|
+
type = "warning";
|
|
22513
|
+
break;
|
|
22514
|
+
case "unsupported_lifecycle":
|
|
22515
|
+
message = "Job must be in current lifecycle to restart.";
|
|
22516
|
+
type = "warning";
|
|
22517
|
+
break;
|
|
22518
|
+
case "job_not_found":
|
|
22519
|
+
message = "Job not found.";
|
|
22520
|
+
type = "error";
|
|
22521
|
+
break;
|
|
22522
|
+
case "spawn_failed":
|
|
22523
|
+
message = "Failed to start restart. Try again.";
|
|
22524
|
+
type = "error";
|
|
22525
|
+
break;
|
|
22526
|
+
default:
|
|
22527
|
+
message = error.message || "An unexpected error occurred.";
|
|
22528
|
+
type = "error";
|
|
22529
|
+
}
|
|
22530
|
+
setAlertMessage(message);
|
|
22531
|
+
setAlertType(type);
|
|
22532
|
+
} finally {
|
|
22533
|
+
setIsSubmitting(false);
|
|
21850
22534
|
}
|
|
21851
|
-
}
|
|
21852
|
-
|
|
21853
|
-
|
|
21854
|
-
|
|
21855
|
-
}
|
|
22535
|
+
};
|
|
22536
|
+
const handleRestartCancel = () => {
|
|
22537
|
+
setRestartModalOpen(false);
|
|
22538
|
+
setRestartTaskId(null);
|
|
22539
|
+
};
|
|
21856
22540
|
React.useEffect(() => {
|
|
21857
|
-
if (
|
|
21858
|
-
|
|
21859
|
-
|
|
21860
|
-
|
|
21861
|
-
|
|
21862
|
-
|
|
21863
|
-
|
|
21864
|
-
|
|
21865
|
-
|
|
22541
|
+
if (alertMessage) {
|
|
22542
|
+
const timer = setTimeout(() => {
|
|
22543
|
+
setAlertMessage(null);
|
|
22544
|
+
}, 5e3);
|
|
22545
|
+
return () => clearTimeout(timer);
|
|
22546
|
+
}
|
|
22547
|
+
}, [alertMessage]);
|
|
22548
|
+
const isRestartEnabled = React.useCallback(() => {
|
|
22549
|
+
const isJobRunning = items.some(
|
|
22550
|
+
(item) => item?.state === TaskState.RUNNING
|
|
22551
|
+
);
|
|
22552
|
+
const hasRunningTask = items.some(
|
|
22553
|
+
(item) => item?.status === TaskState.RUNNING
|
|
22554
|
+
);
|
|
22555
|
+
const jobLifecycle = items[0]?.lifecycle || "current";
|
|
22556
|
+
return jobLifecycle === "current" && !isJobRunning && !hasRunningTask;
|
|
22557
|
+
}, [items]);
|
|
22558
|
+
const getRestartDisabledReason = React.useCallback(() => {
|
|
22559
|
+
const isJobRunning = items.some(
|
|
22560
|
+
(item) => item?.state === TaskState.RUNNING
|
|
22561
|
+
);
|
|
22562
|
+
const hasRunningTask = items.some(
|
|
22563
|
+
(item) => item?.status === TaskState.RUNNING
|
|
22564
|
+
);
|
|
22565
|
+
const jobLifecycle = items[0]?.lifecycle || "current";
|
|
22566
|
+
if (isJobRunning || hasRunningTask) return "Job is currently running";
|
|
22567
|
+
if (jobLifecycle !== "current") return "Job must be in current lifecycle";
|
|
22568
|
+
return "";
|
|
22569
|
+
}, [items]);
|
|
21866
22570
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "relative w-full", role: "list", children: [
|
|
22571
|
+
alertMessage && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
22572
|
+
"div",
|
|
22573
|
+
{
|
|
22574
|
+
className: `fixed top-4 right-4 z-[3000] max-w-sm p-4 rounded-lg shadow-lg border ${alertType === "success" ? "bg-green-50 border-green-200 text-green-800" : alertType === "error" ? "bg-red-50 border-red-200 text-red-800" : alertType === "warning" ? "bg-yellow-50 border-yellow-200 text-yellow-800" : "bg-blue-50 border-blue-200 text-blue-800"}`,
|
|
22575
|
+
role: "alert",
|
|
22576
|
+
"aria-live": "polite",
|
|
22577
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-start", children: [
|
|
22578
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm font-medium", children: alertMessage }) }),
|
|
22579
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
22580
|
+
"button",
|
|
22581
|
+
{
|
|
22582
|
+
onClick: () => setAlertMessage(null),
|
|
22583
|
+
className: "ml-3 flex-shrink-0 inline-flex text-gray-400 hover:text-gray-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500",
|
|
22584
|
+
"aria-label": "Dismiss notification",
|
|
22585
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx("svg", { className: "h-4 w-4", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
22586
|
+
"path",
|
|
22587
|
+
{
|
|
22588
|
+
fillRule: "evenodd",
|
|
22589
|
+
d: "M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z",
|
|
22590
|
+
clipRule: "evenodd"
|
|
22591
|
+
}
|
|
22592
|
+
) })
|
|
22593
|
+
}
|
|
22594
|
+
)
|
|
22595
|
+
] })
|
|
22596
|
+
}
|
|
22597
|
+
),
|
|
21867
22598
|
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
21868
22599
|
"svg",
|
|
21869
22600
|
{
|
|
@@ -21882,7 +22613,8 @@ function DAGGrid({
|
|
|
21882
22613
|
markerHeight: "8",
|
|
21883
22614
|
orient: "auto",
|
|
21884
22615
|
markerUnits: "userSpaceOnUse",
|
|
21885
|
-
|
|
22616
|
+
className: "text-gray-400",
|
|
22617
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M 0 0 L 10 5 L 0 10 z" })
|
|
21886
22618
|
}
|
|
21887
22619
|
) }),
|
|
21888
22620
|
lines.map((line, idx) => /* @__PURE__ */ jsxRuntimeExports.jsx("g", { children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
@@ -21891,9 +22623,9 @@ function DAGGrid({
|
|
|
21891
22623
|
d: line.d,
|
|
21892
22624
|
fill: "none",
|
|
21893
22625
|
stroke: "currentColor",
|
|
21894
|
-
strokeWidth: "
|
|
21895
|
-
strokeLinecap: "
|
|
21896
|
-
className: "text-gray-
|
|
22626
|
+
strokeWidth: "1",
|
|
22627
|
+
strokeLinecap: "square",
|
|
22628
|
+
className: "text-gray-400",
|
|
21897
22629
|
strokeLinejoin: "round",
|
|
21898
22630
|
markerEnd: "url(#arrow)"
|
|
21899
22631
|
}
|
|
@@ -21920,195 +22652,58 @@ function DAGGrid({
|
|
|
21920
22652
|
const item = items[idx];
|
|
21921
22653
|
const status = getStatus(idx);
|
|
21922
22654
|
const isActive = idx === activeIndex;
|
|
21923
|
-
|
|
21924
|
-
|
|
22655
|
+
const canRestart = isRestartEnabled();
|
|
22656
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
22657
|
+
TaskCard,
|
|
21925
22658
|
{
|
|
21926
|
-
|
|
21927
|
-
|
|
21928
|
-
|
|
21929
|
-
|
|
22659
|
+
idx,
|
|
22660
|
+
nodeRef: nodeRefs.current[idx],
|
|
22661
|
+
status,
|
|
22662
|
+
isActive,
|
|
22663
|
+
canRestart,
|
|
22664
|
+
isSubmitting,
|
|
22665
|
+
getRestartDisabledReason,
|
|
21930
22666
|
onClick: () => {
|
|
21931
22667
|
setOpenIdx(idx);
|
|
21932
|
-
setSelectedFile(null);
|
|
21933
22668
|
},
|
|
21934
22669
|
onKeyDown: (e2) => {
|
|
21935
22670
|
if (e2.key === "Enter" || e2.key === " ") {
|
|
21936
22671
|
e2.preventDefault();
|
|
21937
22672
|
setOpenIdx(idx);
|
|
21938
|
-
setSelectedFile(null);
|
|
21939
22673
|
}
|
|
21940
22674
|
},
|
|
21941
|
-
|
|
21942
|
-
|
|
21943
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
21944
|
-
"div",
|
|
21945
|
-
{
|
|
21946
|
-
"data-role": "card-header",
|
|
21947
|
-
className: `rounded-t-lg px-4 py-2 border-b flex items-center justify-between gap-3 ${getHeaderClasses(status)}`,
|
|
21948
|
-
children: [
|
|
21949
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "font-medium truncate", children: formatStepName(item, idx) }),
|
|
21950
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center gap-2", children: status === "running" ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
21951
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "relative h-4 w-4", "aria-label": "Running", children: [
|
|
21952
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "sr-only", children: "Running" }),
|
|
21953
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "absolute inset-0 rounded-full border-2 border-amber-200" }),
|
|
21954
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "absolute inset-0 rounded-full border-2 border-transparent border-t-amber-600 animate-spin" })
|
|
21955
|
-
] }),
|
|
21956
|
-
item.stage && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
21957
|
-
"span",
|
|
21958
|
-
{
|
|
21959
|
-
className: "text-[11px] font-medium opacity-80 truncate",
|
|
21960
|
-
title: item.stage,
|
|
21961
|
-
children: formatStageLabel(item.stage)
|
|
21962
|
-
}
|
|
21963
|
-
)
|
|
21964
|
-
] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-[11px] uppercase tracking-wide opacity-80", children: [
|
|
21965
|
-
status,
|
|
21966
|
-
status === "failed" && item.stage && /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
21967
|
-
"span",
|
|
21968
|
-
{
|
|
21969
|
-
className: "text-[11px] font-medium opacity-80 truncate ml-2",
|
|
21970
|
-
title: item.stage,
|
|
21971
|
-
children: [
|
|
21972
|
-
"(",
|
|
21973
|
-
formatStageLabel(item.stage),
|
|
21974
|
-
")"
|
|
21975
|
-
]
|
|
21976
|
-
}
|
|
21977
|
-
)
|
|
21978
|
-
] }) })
|
|
21979
|
-
]
|
|
21980
|
-
}
|
|
21981
|
-
),
|
|
21982
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-4", children: [
|
|
21983
|
-
item.subtitle && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-sm text-gray-600", children: item.subtitle }),
|
|
21984
|
-
item.body && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-2 text-sm text-gray-700", children: item.body })
|
|
21985
|
-
] })
|
|
21986
|
-
]
|
|
22675
|
+
handleRestartClick,
|
|
22676
|
+
item
|
|
21987
22677
|
},
|
|
21988
22678
|
item.id ?? idx
|
|
21989
22679
|
);
|
|
21990
22680
|
})
|
|
21991
22681
|
}
|
|
21992
22682
|
),
|
|
22683
|
+
openIdx !== -1 && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
22684
|
+
TaskDetailSidebar,
|
|
22685
|
+
{
|
|
22686
|
+
open: openIdx !== -1,
|
|
22687
|
+
title: formatStepName(items[openIdx], openIdx),
|
|
22688
|
+
status: getStatus(openIdx),
|
|
22689
|
+
jobId,
|
|
22690
|
+
taskId: items[openIdx]?.id || `task-${openIdx}`,
|
|
22691
|
+
taskBody: items[openIdx]?.body || null,
|
|
22692
|
+
filesByTypeForItem,
|
|
22693
|
+
task: items[openIdx],
|
|
22694
|
+
taskIndex: openIdx,
|
|
22695
|
+
onClose: () => setOpenIdx(-1)
|
|
22696
|
+
}
|
|
22697
|
+
),
|
|
21993
22698
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
21994
|
-
|
|
22699
|
+
RestartJobModal,
|
|
21995
22700
|
{
|
|
21996
|
-
|
|
21997
|
-
|
|
21998
|
-
|
|
21999
|
-
|
|
22000
|
-
|
|
22001
|
-
|
|
22002
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
22003
|
-
"div",
|
|
22004
|
-
{
|
|
22005
|
-
className: `px-6 py-4 border-b flex items-center justify-between ${getHeaderClasses(getStatus(openIdx))}`,
|
|
22006
|
-
children: [
|
|
22007
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
22008
|
-
"div",
|
|
22009
|
-
{
|
|
22010
|
-
id: `slide-over-title-${openIdx}`,
|
|
22011
|
-
className: "text-lg font-semibold truncate",
|
|
22012
|
-
children: formatStepName(items[openIdx], openIdx)
|
|
22013
|
-
}
|
|
22014
|
-
),
|
|
22015
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
22016
|
-
"button",
|
|
22017
|
-
{
|
|
22018
|
-
ref: closeButtonRef,
|
|
22019
|
-
type: "button",
|
|
22020
|
-
"aria-label": "Close details",
|
|
22021
|
-
onClick: () => {
|
|
22022
|
-
setOpenIdx(null);
|
|
22023
|
-
setSelectedFile(null);
|
|
22024
|
-
},
|
|
22025
|
-
className: "rounded-md border border-gray-300 text-gray-700 hover:bg-gray-50 px-3 py-1.5 text-base",
|
|
22026
|
-
children: "×"
|
|
22027
|
-
}
|
|
22028
|
-
)
|
|
22029
|
-
]
|
|
22030
|
-
}
|
|
22031
|
-
),
|
|
22032
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-6 space-y-8 overflow-y-auto h-full", children: [
|
|
22033
|
-
items[openIdx]?.status === "failed" && items[openIdx]?.body && /* @__PURE__ */ jsxRuntimeExports.jsx("section", { "aria-label": "Error", children: /* @__PURE__ */ jsxRuntimeExports.jsx(n$2, { role: "alert", "aria-live": "assertive", children: /* @__PURE__ */ jsxRuntimeExports.jsx(u$1, { className: "whitespace-pre-wrap break-words", children: items[openIdx].body }) }) }),
|
|
22034
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("section", { className: "mt-6", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between mb-4", children: [
|
|
22035
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-base font-semibold text-gray-900", children: "Files" }),
|
|
22036
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center space-x-2", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex rounded-lg border border-gray-200 bg-gray-50 p-1", children: [
|
|
22037
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
22038
|
-
"button",
|
|
22039
|
-
{
|
|
22040
|
-
onClick: () => setFilePaneType("artifacts"),
|
|
22041
|
-
className: `px-3 py-1.5 text-sm font-medium rounded-md transition-colors ${filePaneType === "artifacts" ? "bg-white text-gray-900 shadow-sm" : "text-gray-600 hover:text-gray-900"}`,
|
|
22042
|
-
children: "Artifacts"
|
|
22043
|
-
}
|
|
22044
|
-
),
|
|
22045
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
22046
|
-
"button",
|
|
22047
|
-
{
|
|
22048
|
-
onClick: () => setFilePaneType("logs"),
|
|
22049
|
-
className: `px-3 py-1.5 text-sm font-medium rounded-md transition-colors ${filePaneType === "logs" ? "bg-white text-gray-900 shadow-sm" : "text-gray-600 hover:text-gray-900"}`,
|
|
22050
|
-
children: "Logs"
|
|
22051
|
-
}
|
|
22052
|
-
),
|
|
22053
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
22054
|
-
"button",
|
|
22055
|
-
{
|
|
22056
|
-
onClick: () => setFilePaneType("tmp"),
|
|
22057
|
-
className: `px-3 py-1.5 text-sm font-medium rounded-md transition-colors ${filePaneType === "tmp" ? "bg-white text-gray-900 shadow-sm" : "text-gray-600 hover:text-gray-900"}`,
|
|
22058
|
-
children: "Temp"
|
|
22059
|
-
}
|
|
22060
|
-
)
|
|
22061
|
-
] }) })
|
|
22062
|
-
] }) }),
|
|
22063
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-2", children: [
|
|
22064
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-sm text-gray-600", children: [
|
|
22065
|
-
filePaneType.charAt(0).toUpperCase() + filePaneType.slice(1),
|
|
22066
|
-
" ",
|
|
22067
|
-
"files for ",
|
|
22068
|
-
items[openIdx]?.id || `Task ${openIdx + 1}`
|
|
22069
|
-
] }),
|
|
22070
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-1", children: (() => {
|
|
22071
|
-
const filesForStep = filesByTypeForItem(items[openIdx]);
|
|
22072
|
-
const filesForTab = filesForStep[filePaneType] ?? [];
|
|
22073
|
-
if (filesForTab.length === 0) {
|
|
22074
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-sm text-gray-500 italic py-4 text-center", children: [
|
|
22075
|
-
"No ",
|
|
22076
|
-
filePaneType,
|
|
22077
|
-
" files available for this task"
|
|
22078
|
-
] });
|
|
22079
|
-
}
|
|
22080
|
-
return filesForTab.map((name) => {
|
|
22081
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
22082
|
-
"div",
|
|
22083
|
-
{
|
|
22084
|
-
className: "flex items-center justify-between p-2 rounded border border-gray-200 hover:border-gray-300 hover:bg-gray-50 cursor-pointer transition-colors",
|
|
22085
|
-
onClick: () => {
|
|
22086
|
-
setFilePaneFilename(name);
|
|
22087
|
-
setFilePaneOpen(true);
|
|
22088
|
-
},
|
|
22089
|
-
children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center space-x-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm text-gray-700", children: name }) })
|
|
22090
|
-
},
|
|
22091
|
-
`${filePaneType}-${name}`
|
|
22092
|
-
);
|
|
22093
|
-
});
|
|
22094
|
-
})() })
|
|
22095
|
-
] }),
|
|
22096
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
22097
|
-
TaskFilePane,
|
|
22098
|
-
{
|
|
22099
|
-
isOpen: filePaneOpen,
|
|
22100
|
-
jobId,
|
|
22101
|
-
taskId: items[openIdx]?.id || `task-${openIdx}`,
|
|
22102
|
-
type: filePaneType,
|
|
22103
|
-
filename: filePaneFilename,
|
|
22104
|
-
onClose: () => {
|
|
22105
|
-
setFilePaneOpen(false);
|
|
22106
|
-
setFilePaneFilename(null);
|
|
22107
|
-
}
|
|
22108
|
-
}
|
|
22109
|
-
)
|
|
22110
|
-
] })
|
|
22111
|
-
] })
|
|
22701
|
+
open: restartModalOpen,
|
|
22702
|
+
onClose: handleRestartCancel,
|
|
22703
|
+
onConfirm: handleRestartConfirm,
|
|
22704
|
+
jobId,
|
|
22705
|
+
taskId: restartTaskId,
|
|
22706
|
+
isSubmitting
|
|
22112
22707
|
}
|
|
22113
22708
|
)
|
|
22114
22709
|
] });
|
|
@@ -22149,7 +22744,7 @@ function computeDagItems(job, pipeline) {
|
|
|
22149
22744
|
const jobTask = jobTasks[taskId];
|
|
22150
22745
|
return {
|
|
22151
22746
|
id: taskId,
|
|
22152
|
-
status: jobTask ? jobTask.state :
|
|
22747
|
+
status: jobTask ? jobTask.state : TaskState.PENDING,
|
|
22153
22748
|
source: "pipeline",
|
|
22154
22749
|
stage: computeTaskStage(job, taskId)
|
|
22155
22750
|
};
|
|
@@ -22172,14 +22767,16 @@ function computeDagItems(job, pipeline) {
|
|
|
22172
22767
|
function computeActiveIndex(items) {
|
|
22173
22768
|
if (!items || items.length === 0) return 0;
|
|
22174
22769
|
const firstRunningIndex = items.findIndex(
|
|
22175
|
-
(item) => item.status ===
|
|
22770
|
+
(item) => item.status === TaskState.RUNNING
|
|
22176
22771
|
);
|
|
22177
22772
|
if (firstRunningIndex !== -1) return firstRunningIndex;
|
|
22178
|
-
const firstFailedIndex = items.findIndex(
|
|
22773
|
+
const firstFailedIndex = items.findIndex(
|
|
22774
|
+
(item) => item.status === TaskState.FAILED
|
|
22775
|
+
);
|
|
22179
22776
|
if (firstFailedIndex !== -1) return firstFailedIndex;
|
|
22180
22777
|
let lastDoneIndex = -1;
|
|
22181
22778
|
items.forEach((item, index2) => {
|
|
22182
|
-
if (item.status ===
|
|
22779
|
+
if (item.status === TaskState.DONE) lastDoneIndex = index2;
|
|
22183
22780
|
});
|
|
22184
22781
|
if (lastDoneIndex !== -1) return lastDoneIndex;
|
|
22185
22782
|
return 0;
|
|
@@ -22198,11 +22795,7 @@ function formatTokensCompact(n2) {
|
|
|
22198
22795
|
}
|
|
22199
22796
|
return `${n2} tokens`;
|
|
22200
22797
|
}
|
|
22201
|
-
function JobDetail({ job, pipeline
|
|
22202
|
-
const now = useTicker(1e3);
|
|
22203
|
-
const [resumeFrom, setResumeFrom] = reactExports.useState(
|
|
22204
|
-
pipeline?.tasks?.[0] ? typeof pipeline.tasks[0] === "string" ? pipeline.tasks[0] : pipeline.tasks[0].id ?? pipeline.tasks[0].name ?? "" : ""
|
|
22205
|
-
);
|
|
22798
|
+
function JobDetail({ job, pipeline }) {
|
|
22206
22799
|
const taskById = React.useMemo(() => {
|
|
22207
22800
|
const tasks = job?.tasks;
|
|
22208
22801
|
let result;
|
|
@@ -22222,11 +22815,6 @@ function JobDetail({ job, pipeline, onClose, onResume }) {
|
|
|
22222
22815
|
}
|
|
22223
22816
|
return result;
|
|
22224
22817
|
}, [job?.tasks]);
|
|
22225
|
-
reactExports.useEffect(() => {
|
|
22226
|
-
setResumeFrom(
|
|
22227
|
-
pipeline?.tasks?.[0] ? typeof pipeline.tasks[0] === "string" ? pipeline.tasks[0] : pipeline.tasks[0].id ?? pipeline.tasks[0].name ?? "" : ""
|
|
22228
|
-
);
|
|
22229
|
-
}, [job.id, pipeline?.tasks?.length]);
|
|
22230
22818
|
const computedPipeline = React.useMemo(() => {
|
|
22231
22819
|
let result;
|
|
22232
22820
|
if (pipeline?.tasks) {
|
|
@@ -22242,18 +22830,9 @@ function JobDetail({ job, pipeline, onClose, onResume }) {
|
|
|
22242
22830
|
}
|
|
22243
22831
|
return result;
|
|
22244
22832
|
}, [pipeline, job?.tasks]);
|
|
22245
|
-
const
|
|
22833
|
+
const stableDagItems = React.useMemo(() => {
|
|
22246
22834
|
const rawDagItems = computeDagItems(job, computedPipeline);
|
|
22247
|
-
|
|
22248
|
-
{
|
|
22249
|
-
console.debug("[JobDetail] computed DAG item", {
|
|
22250
|
-
id: item.id,
|
|
22251
|
-
status: item.status,
|
|
22252
|
-
stage: item.stage,
|
|
22253
|
-
jobHasTasks: !!job?.tasks,
|
|
22254
|
-
taskKeys: job?.tasks ? Object.keys(job.tasks) : null
|
|
22255
|
-
});
|
|
22256
|
-
}
|
|
22835
|
+
return rawDagItems.map((item, index2) => {
|
|
22257
22836
|
const task = taskById[item.id];
|
|
22258
22837
|
const taskConfig = task?.config || {};
|
|
22259
22838
|
const subtitleParts = [];
|
|
@@ -22263,18 +22842,9 @@ function JobDetail({ job, pipeline, onClose, onResume }) {
|
|
|
22263
22842
|
if (taskConfig?.temperature != null) {
|
|
22264
22843
|
subtitleParts.push(`temp ${taskConfig.temperature}`);
|
|
22265
22844
|
}
|
|
22266
|
-
if (task?.attempts != null) {
|
|
22267
|
-
subtitleParts.push(`${task.attempts} attempts`);
|
|
22268
|
-
}
|
|
22269
22845
|
if (task?.refinementAttempts != null) {
|
|
22270
22846
|
subtitleParts.push(`${task.refinementAttempts} refinements`);
|
|
22271
22847
|
}
|
|
22272
|
-
if (task?.startedAt) {
|
|
22273
|
-
const durationMs = taskDisplayDurationMs(task, now);
|
|
22274
|
-
if (durationMs > 0) {
|
|
22275
|
-
subtitleParts.push(fmtDuration(durationMs));
|
|
22276
|
-
}
|
|
22277
|
-
}
|
|
22278
22848
|
const taskBreakdown = job?.costs?.taskBreakdown?.[item.id]?.summary || {};
|
|
22279
22849
|
if (taskBreakdown.totalTokens > 0) {
|
|
22280
22850
|
subtitleParts.push(formatTokensCompact(taskBreakdown.totalTokens));
|
|
@@ -22284,16 +22854,29 @@ function JobDetail({ job, pipeline, onClose, onResume }) {
|
|
|
22284
22854
|
}
|
|
22285
22855
|
const errorMsg = task?.error?.message;
|
|
22286
22856
|
const body = (item.status === "failed" || item.status === "error") && errorMsg ? errorMsg : null;
|
|
22287
|
-
|
|
22857
|
+
return {
|
|
22288
22858
|
...item,
|
|
22289
22859
|
title: typeof item.id === "string" ? item.id : item.id?.name || item.id?.id || `Task ${item.id}`,
|
|
22290
22860
|
subtitle: subtitleParts.length > 0 ? subtitleParts.join(" · ") : null,
|
|
22291
|
-
body
|
|
22861
|
+
body,
|
|
22862
|
+
startedAt: task?.startedAt,
|
|
22863
|
+
endedAt: task?.endedAt
|
|
22292
22864
|
};
|
|
22293
|
-
return resultItem;
|
|
22294
22865
|
});
|
|
22295
|
-
|
|
22296
|
-
|
|
22866
|
+
}, [job, computedPipeline, taskById]);
|
|
22867
|
+
const prevDagItemsRef = React.useRef([]);
|
|
22868
|
+
const dagItems = React.useMemo(() => {
|
|
22869
|
+
const prevItems = prevDagItemsRef.current;
|
|
22870
|
+
const newItems = stableDagItems.map((item, index2) => {
|
|
22871
|
+
const prevItem = prevItems[index2];
|
|
22872
|
+
if (prevItem && prevItem.id === item.id && prevItem.status === item.status && prevItem.stage === item.stage && prevItem.title === item.title && prevItem.subtitle === item.subtitle && prevItem.body === item.body) {
|
|
22873
|
+
return prevItem;
|
|
22874
|
+
}
|
|
22875
|
+
return item;
|
|
22876
|
+
});
|
|
22877
|
+
prevDagItemsRef.current = newItems;
|
|
22878
|
+
return newItems;
|
|
22879
|
+
}, [stableDagItems]);
|
|
22297
22880
|
const activeIndex = React.useMemo(() => {
|
|
22298
22881
|
const index2 = computeActiveIndex(dagItems);
|
|
22299
22882
|
return index2;
|
|
@@ -22305,7 +22888,6 @@ function JobDetail({ job, pipeline, onClose, onResume }) {
|
|
|
22305
22888
|
},
|
|
22306
22889
|
[job]
|
|
22307
22890
|
);
|
|
22308
|
-
console.log("dagItems", dagItems);
|
|
22309
22891
|
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex h-full flex-col", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
22310
22892
|
DAGGrid,
|
|
22311
22893
|
{
|
|
@@ -22317,40 +22899,6 @@ function JobDetail({ job, pipeline, onClose, onResume }) {
|
|
|
22317
22899
|
) });
|
|
22318
22900
|
}
|
|
22319
22901
|
const REFRESH_DEBOUNCE_MS = 200;
|
|
22320
|
-
const createHookLogger = (jobId) => {
|
|
22321
|
-
const prefix = `[useJobDetailWithUpdates:${jobId || "unknown"}]`;
|
|
22322
|
-
return {
|
|
22323
|
-
log: (message, data = null) => {
|
|
22324
|
-
console.log(`${prefix} ${message}`, data ? data : "");
|
|
22325
|
-
},
|
|
22326
|
-
warn: (message, data = null) => {
|
|
22327
|
-
console.warn(`${prefix} ${message}`, data ? data : "");
|
|
22328
|
-
},
|
|
22329
|
-
error: (message, data = null) => {
|
|
22330
|
-
console.error(`${prefix} ${message}`, data ? data : "");
|
|
22331
|
-
},
|
|
22332
|
-
group: (label) => console.group(`${prefix} ${label}`),
|
|
22333
|
-
groupEnd: () => console.groupEnd(),
|
|
22334
|
-
table: (data, title) => {
|
|
22335
|
-
console.log(`${prefix} ${title}:`);
|
|
22336
|
-
console.table(data);
|
|
22337
|
-
},
|
|
22338
|
-
sse: (eventType, eventData) => {
|
|
22339
|
-
console.log(
|
|
22340
|
-
`%c${prefix} SSE Event: ${eventType}`,
|
|
22341
|
-
"color: #0066cc; font-weight: bold;",
|
|
22342
|
-
eventData
|
|
22343
|
-
);
|
|
22344
|
-
},
|
|
22345
|
-
state: (stateName, value) => {
|
|
22346
|
-
console.log(
|
|
22347
|
-
`%c${prefix} State Change: ${stateName}`,
|
|
22348
|
-
"color: #006600; font-weight: bold;",
|
|
22349
|
-
value
|
|
22350
|
-
);
|
|
22351
|
-
}
|
|
22352
|
-
};
|
|
22353
|
-
};
|
|
22354
22902
|
async function fetchJobDetail(jobId, { signal } = {}) {
|
|
22355
22903
|
const response = await fetch(`/api/jobs/${jobId}`, { signal });
|
|
22356
22904
|
if (!response.ok) {
|
|
@@ -22435,89 +22983,63 @@ function matchesJobTasksStatusPath(path, jobId) {
|
|
|
22435
22983
|
}
|
|
22436
22984
|
}
|
|
22437
22985
|
function useJobDetailWithUpdates(jobId) {
|
|
22438
|
-
const logger = reactExports.useMemo(() => createHookLogger(jobId), [jobId]);
|
|
22439
22986
|
const [data, setData] = reactExports.useState(null);
|
|
22440
22987
|
const [loading, setLoading] = reactExports.useState(true);
|
|
22441
22988
|
const [error, setError] = reactExports.useState(null);
|
|
22442
22989
|
const [connectionStatus, setConnectionStatus] = reactExports.useState("disconnected");
|
|
22990
|
+
const [isRefreshing, setIsRefreshing] = reactExports.useState(false);
|
|
22991
|
+
const [isPending, startTransition] = reactExports.useTransition();
|
|
22992
|
+
const [isHydrated, setIsHydrated] = reactExports.useState(false);
|
|
22443
22993
|
const esRef = reactExports.useRef(null);
|
|
22444
22994
|
const reconnectTimer = reactExports.useRef(null);
|
|
22445
22995
|
const hydratedRef = reactExports.useRef(false);
|
|
22446
22996
|
const eventQueue = reactExports.useRef([]);
|
|
22447
22997
|
const mountedRef = reactExports.useRef(true);
|
|
22448
22998
|
const refetchTimerRef = reactExports.useRef(null);
|
|
22449
|
-
reactExports.useEffect(() => {
|
|
22450
|
-
logger.group("Hook Initialization");
|
|
22451
|
-
logger.log("Job ID:", jobId);
|
|
22452
|
-
logger.log("Initial state:", { data, loading, error, connectionStatus });
|
|
22453
|
-
logger.groupEnd();
|
|
22454
|
-
}, [jobId, logger]);
|
|
22455
|
-
reactExports.useEffect(() => {
|
|
22456
|
-
logger.state("data", data);
|
|
22457
|
-
}, [data, logger]);
|
|
22458
|
-
reactExports.useEffect(() => {
|
|
22459
|
-
logger.state("loading", loading);
|
|
22460
|
-
}, [loading, logger]);
|
|
22461
|
-
reactExports.useEffect(() => {
|
|
22462
|
-
logger.state("error", error);
|
|
22463
|
-
}, [error, logger]);
|
|
22464
|
-
reactExports.useEffect(() => {
|
|
22465
|
-
logger.state("connectionStatus", connectionStatus);
|
|
22466
|
-
}, [connectionStatus, logger]);
|
|
22467
22999
|
const scheduleDebouncedRefetch = reactExports.useCallback(
|
|
22468
23000
|
(context = {}) => {
|
|
22469
|
-
logger.group("Debounced Refetch Request");
|
|
22470
|
-
logger.log("Request context:", context);
|
|
22471
|
-
logger.log("Scheduling debounced refetch");
|
|
22472
23001
|
if (refetchTimerRef.current) {
|
|
22473
|
-
logger.log("Clearing existing refetch timer");
|
|
22474
23002
|
clearTimeout(refetchTimerRef.current);
|
|
22475
23003
|
}
|
|
22476
23004
|
refetchTimerRef.current = setTimeout(async () => {
|
|
22477
23005
|
if (!mountedRef.current || !hydratedRef.current) {
|
|
22478
|
-
logger.warn(
|
|
22479
|
-
"Refetch aborted - component not mounted or not hydrated",
|
|
22480
|
-
{ mounted: mountedRef.current, hydrated: hydratedRef.current }
|
|
22481
|
-
);
|
|
22482
|
-
logger.groupEnd();
|
|
22483
23006
|
return;
|
|
22484
23007
|
}
|
|
22485
|
-
logger.log("Executing debounced refetch");
|
|
22486
|
-
logger.log("Refetch jobId:", jobId);
|
|
22487
23008
|
const abortController = new AbortController();
|
|
22488
23009
|
try {
|
|
23010
|
+
startTransition(() => {
|
|
23011
|
+
setIsRefreshing(true);
|
|
23012
|
+
});
|
|
22489
23013
|
const jobData = await fetchJobDetail(jobId, {
|
|
22490
23014
|
signal: abortController.signal
|
|
22491
23015
|
});
|
|
22492
|
-
logger.log("Refetch response received");
|
|
22493
|
-
logger.log("Refetch job data preview:", {
|
|
22494
|
-
status: jobData?.status,
|
|
22495
|
-
hasTasks: !!jobData?.tasks,
|
|
22496
|
-
taskKeys: jobData?.tasks ? Object.keys(jobData.tasks) : []
|
|
22497
|
-
});
|
|
22498
23016
|
if (mountedRef.current) {
|
|
22499
|
-
|
|
22500
|
-
|
|
22501
|
-
|
|
22502
|
-
|
|
22503
|
-
|
|
23017
|
+
startTransition(() => {
|
|
23018
|
+
setData(jobData);
|
|
23019
|
+
setError(null);
|
|
23020
|
+
setIsRefreshing(false);
|
|
23021
|
+
});
|
|
22504
23022
|
}
|
|
22505
23023
|
} catch (err) {
|
|
22506
|
-
|
|
22507
|
-
|
|
23024
|
+
if (mountedRef.current) {
|
|
23025
|
+
startTransition(() => {
|
|
23026
|
+
setError(err.message);
|
|
23027
|
+
setIsRefreshing(false);
|
|
23028
|
+
});
|
|
23029
|
+
}
|
|
22508
23030
|
} finally {
|
|
22509
23031
|
refetchTimerRef.current = null;
|
|
22510
|
-
logger.groupEnd();
|
|
22511
23032
|
}
|
|
22512
23033
|
}, REFRESH_DEBOUNCE_MS);
|
|
22513
23034
|
},
|
|
22514
|
-
[jobId
|
|
23035
|
+
[jobId]
|
|
22515
23036
|
);
|
|
22516
23037
|
reactExports.useEffect(() => {
|
|
22517
23038
|
setData(null);
|
|
22518
23039
|
setLoading(true);
|
|
22519
23040
|
setError(null);
|
|
22520
23041
|
setConnectionStatus("disconnected");
|
|
23042
|
+
setIsHydrated(false);
|
|
22521
23043
|
hydratedRef.current = false;
|
|
22522
23044
|
eventQueue.current = [];
|
|
22523
23045
|
if (refetchTimerRef.current) {
|
|
@@ -22528,92 +23050,80 @@ function useJobDetailWithUpdates(jobId) {
|
|
|
22528
23050
|
reactExports.useEffect(() => {
|
|
22529
23051
|
if (!jobId || !mountedRef.current) return;
|
|
22530
23052
|
const doFetch = async () => {
|
|
22531
|
-
logger.group("Initial Data Fetch");
|
|
22532
23053
|
try {
|
|
22533
|
-
|
|
23054
|
+
if (!hydratedRef.current) {
|
|
23055
|
+
setLoading(true);
|
|
23056
|
+
}
|
|
22534
23057
|
setError(null);
|
|
22535
|
-
logger.log("Starting initial job data fetch");
|
|
22536
23058
|
const jobData = await fetchJobDetail(jobId);
|
|
22537
|
-
logger.log("Initial fetch successful", jobData);
|
|
22538
23059
|
let finalData = jobData;
|
|
22539
23060
|
let queuedNeedsRefetch = false;
|
|
22540
23061
|
if (eventQueue.current.length > 0) {
|
|
22541
|
-
logger.log(`Processing ${eventQueue.current.length} queued events`);
|
|
22542
23062
|
for (const ev of eventQueue.current) {
|
|
22543
|
-
logger.log("Processing queued event:", ev);
|
|
22544
23063
|
if (ev.type === "state:change") {
|
|
22545
23064
|
const d2 = ev.payload && (ev.payload.data || ev.payload) || {};
|
|
22546
23065
|
if (typeof d2.path === "string" && matchesJobTasksStatusPath(d2.path, jobId)) {
|
|
22547
|
-
logger.log(
|
|
22548
|
-
"Queued state:change matches tasks-status path, scheduling refetch"
|
|
22549
|
-
);
|
|
22550
23066
|
queuedNeedsRefetch = true;
|
|
22551
23067
|
continue;
|
|
22552
23068
|
}
|
|
22553
23069
|
}
|
|
22554
23070
|
finalData = applyJobEvent(finalData, ev, jobId);
|
|
22555
|
-
logger.log("Applied queued event, result:", finalData);
|
|
22556
23071
|
}
|
|
22557
23072
|
eventQueue.current = [];
|
|
22558
23073
|
}
|
|
22559
23074
|
if (mountedRef.current) {
|
|
22560
|
-
|
|
22561
|
-
|
|
22562
|
-
|
|
22563
|
-
|
|
22564
|
-
|
|
23075
|
+
startTransition(() => {
|
|
23076
|
+
setData(finalData);
|
|
23077
|
+
setError(null);
|
|
23078
|
+
const wasHydrated = hydratedRef.current;
|
|
23079
|
+
hydratedRef.current = true;
|
|
23080
|
+
if (!wasHydrated) {
|
|
23081
|
+
setIsHydrated(true);
|
|
23082
|
+
setLoading(false);
|
|
23083
|
+
}
|
|
23084
|
+
});
|
|
22565
23085
|
if (queuedNeedsRefetch) {
|
|
22566
|
-
logger.log("Scheduling refetch for queued path changes");
|
|
22567
23086
|
scheduleDebouncedRefetch();
|
|
22568
23087
|
}
|
|
22569
23088
|
}
|
|
22570
23089
|
} catch (err) {
|
|
22571
|
-
logger.error("Failed to fetch job detail:", err);
|
|
22572
23090
|
if (mountedRef.current) {
|
|
22573
|
-
|
|
22574
|
-
|
|
23091
|
+
startTransition(() => {
|
|
23092
|
+
setError(err.message);
|
|
23093
|
+
setData(null);
|
|
23094
|
+
if (!hydratedRef.current) {
|
|
23095
|
+
setLoading(false);
|
|
23096
|
+
}
|
|
23097
|
+
});
|
|
22575
23098
|
}
|
|
22576
23099
|
} finally {
|
|
22577
|
-
if (mountedRef.current) {
|
|
23100
|
+
if (mountedRef.current && !hydratedRef.current) {
|
|
22578
23101
|
setLoading(false);
|
|
22579
23102
|
}
|
|
22580
|
-
logger.groupEnd();
|
|
22581
23103
|
}
|
|
22582
23104
|
};
|
|
22583
23105
|
doFetch();
|
|
22584
|
-
}, [jobId, scheduleDebouncedRefetch
|
|
23106
|
+
}, [jobId, scheduleDebouncedRefetch]);
|
|
22585
23107
|
reactExports.useEffect(() => {
|
|
22586
23108
|
if (!jobId) {
|
|
22587
|
-
logger.log("SSE setup skipped - no jobId available", {
|
|
22588
|
-
hasJobId: !!jobId,
|
|
22589
|
-
hasExistingEs: !!esRef.current,
|
|
22590
|
-
isMounted: mountedRef.current
|
|
22591
|
-
});
|
|
22592
23109
|
return void 0;
|
|
22593
23110
|
}
|
|
22594
23111
|
if (esRef.current) {
|
|
22595
|
-
logger.log("Closing existing EventSource before reinitializing");
|
|
22596
23112
|
try {
|
|
22597
23113
|
esRef.current.close();
|
|
22598
23114
|
} catch (err) {
|
|
22599
|
-
logger.warn("Error closing existing EventSource during reinit", err);
|
|
22600
23115
|
}
|
|
22601
23116
|
esRef.current = null;
|
|
22602
23117
|
}
|
|
22603
|
-
logger.group("SSE Connection Setup");
|
|
22604
|
-
logger.log("Setting up SSE connection for job:", jobId);
|
|
22605
23118
|
const attachListeners = (es) => {
|
|
22606
23119
|
const onOpen = () => {
|
|
22607
|
-
logger.log("SSE connection opened");
|
|
22608
23120
|
if (mountedRef.current) {
|
|
22609
23121
|
setConnectionStatus("connected");
|
|
22610
23122
|
}
|
|
22611
23123
|
};
|
|
22612
23124
|
const onError = () => {
|
|
22613
|
-
logger.warn("SSE connection error");
|
|
22614
23125
|
try {
|
|
22615
23126
|
const rs = esRef.current?.readyState;
|
|
22616
|
-
logger.log("SSE readyState:", rs);
|
|
22617
23127
|
if (rs === 0) {
|
|
22618
23128
|
if (mountedRef.current) setConnectionStatus("disconnected");
|
|
22619
23129
|
} else if (rs === 1) {
|
|
@@ -22624,11 +23134,9 @@ function useJobDetailWithUpdates(jobId) {
|
|
|
22624
23134
|
if (mountedRef.current) setConnectionStatus("disconnected");
|
|
22625
23135
|
}
|
|
22626
23136
|
} catch (err) {
|
|
22627
|
-
logger.error("Error getting readyState:", err);
|
|
22628
23137
|
if (mountedRef.current) setConnectionStatus("disconnected");
|
|
22629
23138
|
}
|
|
22630
23139
|
if (esRef.current && esRef.current.readyState === 2 && mountedRef.current) {
|
|
22631
|
-
logger.log("Scheduling SSE reconnection");
|
|
22632
23140
|
if (reconnectTimer.current) clearTimeout(reconnectTimer.current);
|
|
22633
23141
|
reconnectTimer.current = setTimeout(() => {
|
|
22634
23142
|
if (!mountedRef.current) return;
|
|
@@ -22638,7 +23146,6 @@ function useJobDetailWithUpdates(jobId) {
|
|
|
22638
23146
|
} catch (e2) {
|
|
22639
23147
|
}
|
|
22640
23148
|
const eventsUrl = jobId ? `/api/events?jobId=${encodeURIComponent(jobId)}` : "/api/events";
|
|
22641
|
-
logger.log("Creating new EventSource for reconnection");
|
|
22642
23149
|
const newEs = new EventSource(eventsUrl);
|
|
22643
23150
|
newEs.addEventListener("open", onOpen);
|
|
22644
23151
|
newEs.addEventListener("job:updated", onJobUpdated);
|
|
@@ -22649,7 +23156,7 @@ function useJobDetailWithUpdates(jobId) {
|
|
|
22649
23156
|
newEs.addEventListener("error", onError);
|
|
22650
23157
|
esRef.current = newEs;
|
|
22651
23158
|
} catch (err) {
|
|
22652
|
-
|
|
23159
|
+
console.error("Failed to reconnect SSE:", err);
|
|
22653
23160
|
}
|
|
22654
23161
|
}, 2e3);
|
|
22655
23162
|
}
|
|
@@ -22658,64 +23165,37 @@ function useJobDetailWithUpdates(jobId) {
|
|
|
22658
23165
|
try {
|
|
22659
23166
|
const payload = evt && evt.data ? JSON.parse(evt.data) : null;
|
|
22660
23167
|
const eventObj = { type, payload };
|
|
22661
|
-
logger.sse(type, payload);
|
|
22662
23168
|
if (payload && payload.jobId && payload.jobId !== jobId) {
|
|
22663
|
-
logger.log(
|
|
22664
|
-
`Ignoring event for different job: ${payload.jobId} (current: ${jobId})`
|
|
22665
|
-
);
|
|
22666
23169
|
return;
|
|
22667
23170
|
}
|
|
22668
23171
|
if (!hydratedRef.current) {
|
|
22669
|
-
logger.log(`Queueing event until hydration: ${type}`);
|
|
22670
23172
|
eventQueue.current = (eventQueue.current || []).concat(eventObj);
|
|
22671
23173
|
return;
|
|
22672
23174
|
}
|
|
22673
23175
|
if (type === "state:change") {
|
|
22674
23176
|
const d2 = payload && (payload.data || payload) || {};
|
|
22675
|
-
logger.log("Processing state:change event:", d2);
|
|
22676
23177
|
if (typeof d2.path === "string" && matchesJobTasksStatusPath(d2.path, jobId)) {
|
|
22677
|
-
logger.log(
|
|
22678
|
-
`state:change matches tasks-status path: ${d2.path}, scheduling refetch`
|
|
22679
|
-
);
|
|
22680
23178
|
scheduleDebouncedRefetch({
|
|
22681
23179
|
reason: "state:change",
|
|
22682
23180
|
path: d2.path
|
|
22683
23181
|
});
|
|
22684
23182
|
return;
|
|
22685
|
-
} else {
|
|
22686
|
-
logger.log(
|
|
22687
|
-
`state:change does not match tasks-status path: ${d2.path}`
|
|
22688
|
-
);
|
|
22689
23183
|
}
|
|
22690
23184
|
}
|
|
22691
|
-
|
|
22692
|
-
|
|
22693
|
-
|
|
22694
|
-
|
|
22695
|
-
|
|
22696
|
-
|
|
22697
|
-
|
|
22698
|
-
|
|
22699
|
-
|
|
22700
|
-
try {
|
|
22701
|
-
if (JSON.stringify(prev) === JSON.stringify(next)) {
|
|
22702
|
-
logger.log("Event application resulted in no state change");
|
|
22703
|
-
logger.groupEnd();
|
|
22704
|
-
return prev;
|
|
23185
|
+
startTransition(() => {
|
|
23186
|
+
setData((prev) => {
|
|
23187
|
+
const next = applyJobEvent(prev, eventObj, jobId);
|
|
23188
|
+
try {
|
|
23189
|
+
if (JSON.stringify(prev) === JSON.stringify(next)) {
|
|
23190
|
+
return prev;
|
|
23191
|
+
}
|
|
23192
|
+
} catch (e2) {
|
|
23193
|
+
console.error("Error comparing states:", e2);
|
|
22705
23194
|
}
|
|
22706
|
-
|
|
22707
|
-
logger.error("Error comparing states:", e2);
|
|
22708
|
-
}
|
|
22709
|
-
logger.log("Event applied, state updated", {
|
|
22710
|
-
hasTasks: !!next?.tasks,
|
|
22711
|
-
taskKeys: next?.tasks ? Object.keys(next.tasks) : [],
|
|
22712
|
-
status: next?.status
|
|
23195
|
+
return next;
|
|
22713
23196
|
});
|
|
22714
|
-
logger.groupEnd();
|
|
22715
|
-
return next;
|
|
22716
23197
|
});
|
|
22717
23198
|
} catch (err) {
|
|
22718
|
-
logger.error("Failed to handle SSE event:", err);
|
|
22719
23199
|
console.error("Failed to handle SSE event:", err);
|
|
22720
23200
|
}
|
|
22721
23201
|
};
|
|
@@ -22724,7 +23204,6 @@ function useJobDetailWithUpdates(jobId) {
|
|
|
22724
23204
|
const onJobRemoved = (evt) => handleIncomingEvent("job:removed", evt);
|
|
22725
23205
|
const onStatusChanged = (evt) => handleIncomingEvent("status:changed", evt);
|
|
22726
23206
|
const onStateChange = (evt) => handleIncomingEvent("state:change", evt);
|
|
22727
|
-
logger.log("Attaching SSE event listeners");
|
|
22728
23207
|
es.addEventListener("open", onOpen);
|
|
22729
23208
|
es.addEventListener("job:updated", onJobUpdated);
|
|
22730
23209
|
es.addEventListener("job:created", onJobCreated);
|
|
@@ -22733,14 +23212,11 @@ function useJobDetailWithUpdates(jobId) {
|
|
|
22733
23212
|
es.addEventListener("state:change", onStateChange);
|
|
22734
23213
|
es.addEventListener("error", onError);
|
|
22735
23214
|
if (es.readyState === 1 && mountedRef.current) {
|
|
22736
|
-
logger.log("SSE already open, setting connected");
|
|
22737
23215
|
setConnectionStatus("connected");
|
|
22738
23216
|
} else if (es.readyState === 0 && mountedRef.current) {
|
|
22739
|
-
logger.log("SSE connecting, setting disconnected");
|
|
22740
23217
|
setConnectionStatus("disconnected");
|
|
22741
23218
|
}
|
|
22742
23219
|
return () => {
|
|
22743
|
-
logger.log("Cleaning up SSE connection");
|
|
22744
23220
|
try {
|
|
22745
23221
|
es.removeEventListener("open", onOpen);
|
|
22746
23222
|
es.removeEventListener("job:updated", onJobUpdated);
|
|
@@ -22750,9 +23226,8 @@ function useJobDetailWithUpdates(jobId) {
|
|
|
22750
23226
|
es.removeEventListener("state:change", onStateChange);
|
|
22751
23227
|
es.removeEventListener("error", onError);
|
|
22752
23228
|
es.close();
|
|
22753
|
-
logger.log("SSE connection closed");
|
|
22754
23229
|
} catch (err) {
|
|
22755
|
-
|
|
23230
|
+
console.error("Error during SSE cleanup:", err);
|
|
22756
23231
|
}
|
|
22757
23232
|
if (reconnectTimer.current) {
|
|
22758
23233
|
clearTimeout(reconnectTimer.current);
|
|
@@ -22763,21 +23238,18 @@ function useJobDetailWithUpdates(jobId) {
|
|
|
22763
23238
|
};
|
|
22764
23239
|
try {
|
|
22765
23240
|
const eventsUrl = jobId ? `/api/events?jobId=${encodeURIComponent(jobId)}` : "/api/events";
|
|
22766
|
-
logger.log(`Creating EventSource with URL: ${eventsUrl}`);
|
|
22767
23241
|
const es = new EventSource(eventsUrl);
|
|
22768
23242
|
esRef.current = es;
|
|
22769
23243
|
const cleanup = attachListeners(es);
|
|
22770
|
-
logger.groupEnd();
|
|
22771
23244
|
return cleanup;
|
|
22772
23245
|
} catch (err) {
|
|
22773
|
-
|
|
23246
|
+
console.error("Failed to create SSE connection:", err);
|
|
22774
23247
|
if (mountedRef.current) {
|
|
22775
23248
|
setConnectionStatus("error");
|
|
22776
23249
|
}
|
|
22777
|
-
logger.groupEnd();
|
|
22778
23250
|
return void 0;
|
|
22779
23251
|
}
|
|
22780
|
-
}, [jobId, scheduleDebouncedRefetch
|
|
23252
|
+
}, [jobId, scheduleDebouncedRefetch]);
|
|
22781
23253
|
reactExports.useEffect(() => {
|
|
22782
23254
|
mountedRef.current = true;
|
|
22783
23255
|
return () => {
|
|
@@ -22803,7 +23275,10 @@ function useJobDetailWithUpdates(jobId) {
|
|
|
22803
23275
|
data,
|
|
22804
23276
|
loading,
|
|
22805
23277
|
error,
|
|
22806
|
-
connectionStatus
|
|
23278
|
+
connectionStatus,
|
|
23279
|
+
isRefreshing,
|
|
23280
|
+
isTransitioning: isPending,
|
|
23281
|
+
isHydrated
|
|
22807
23282
|
};
|
|
22808
23283
|
}
|
|
22809
23284
|
function PipelineDetail() {
|
|
@@ -22813,26 +23288,30 @@ function PipelineDetail() {
|
|
|
22813
23288
|
Layout,
|
|
22814
23289
|
{
|
|
22815
23290
|
pageTitle: "Pipeline Details",
|
|
22816
|
-
breadcrumbs: [
|
|
22817
|
-
{ label: "Home", href: "/" },
|
|
22818
|
-
{ label: "Pipeline Details" }
|
|
22819
|
-
],
|
|
22820
|
-
showBackButton: true,
|
|
23291
|
+
breadcrumbs: [{ label: "Home", href: "/" }],
|
|
22821
23292
|
children: /* @__PURE__ */ jsxRuntimeExports.jsx(p$4, { align: "center", justify: "center", className: "min-h-64", children: /* @__PURE__ */ jsxRuntimeExports.jsx(p$7, { className: "text-center", children: /* @__PURE__ */ jsxRuntimeExports.jsx(p$b, { size: "5", weight: "medium", color: "red", className: "mb-2", children: "No job ID provided" }) }) })
|
|
22822
23293
|
}
|
|
22823
23294
|
);
|
|
22824
23295
|
}
|
|
22825
|
-
const {
|
|
22826
|
-
|
|
23296
|
+
const {
|
|
23297
|
+
data: job,
|
|
23298
|
+
loading,
|
|
23299
|
+
error,
|
|
23300
|
+
isRefreshing,
|
|
23301
|
+
isHydrated
|
|
23302
|
+
} = useJobDetailWithUpdates(jobId);
|
|
23303
|
+
const showLoadingScreen = loading && !isHydrated;
|
|
23304
|
+
if (showLoadingScreen) {
|
|
22827
23305
|
return /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
22828
23306
|
Layout,
|
|
22829
23307
|
{
|
|
22830
23308
|
pageTitle: "Pipeline Details",
|
|
22831
23309
|
breadcrumbs: [
|
|
22832
23310
|
{ label: "Home", href: "/" },
|
|
22833
|
-
{
|
|
23311
|
+
{
|
|
23312
|
+
label: job && job?.pipelineLabel ? job.pipelineLabel : "Pipeline Details"
|
|
23313
|
+
}
|
|
22834
23314
|
],
|
|
22835
|
-
showBackButton: true,
|
|
22836
23315
|
children: /* @__PURE__ */ jsxRuntimeExports.jsx(p$4, { align: "center", justify: "center", className: "min-h-64", children: /* @__PURE__ */ jsxRuntimeExports.jsx(p$7, { className: "text-center", children: /* @__PURE__ */ jsxRuntimeExports.jsx(p$b, { size: "5", weight: "medium", className: "mb-2", children: "Loading job details..." }) }) })
|
|
22837
23316
|
}
|
|
22838
23317
|
);
|
|
@@ -22844,9 +23323,10 @@ function PipelineDetail() {
|
|
|
22844
23323
|
pageTitle: "Pipeline Details",
|
|
22845
23324
|
breadcrumbs: [
|
|
22846
23325
|
{ label: "Home", href: "/" },
|
|
22847
|
-
{
|
|
23326
|
+
{
|
|
23327
|
+
label: job && job?.pipelineLabel ? job.pipelineLabel : "Pipeline Details"
|
|
23328
|
+
}
|
|
22848
23329
|
],
|
|
22849
|
-
showBackButton: true,
|
|
22850
23330
|
children: /* @__PURE__ */ jsxRuntimeExports.jsx(p$4, { align: "center", justify: "center", className: "min-h-64", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(p$7, { className: "text-center", children: [
|
|
22851
23331
|
/* @__PURE__ */ jsxRuntimeExports.jsx(p$b, { size: "5", weight: "medium", color: "red", className: "mb-2", children: "Failed to load job details" }),
|
|
22852
23332
|
/* @__PURE__ */ jsxRuntimeExports.jsx(p$b, { size: "2", color: "gray", className: "mt-2", children: error })
|
|
@@ -22861,9 +23341,8 @@ function PipelineDetail() {
|
|
|
22861
23341
|
pageTitle: "Pipeline Details",
|
|
22862
23342
|
breadcrumbs: [
|
|
22863
23343
|
{ label: "Home", href: "/" },
|
|
22864
|
-
{ label: "Pipeline Details" }
|
|
23344
|
+
{ label: job.pipelineLabel || "Pipeline Details" }
|
|
22865
23345
|
],
|
|
22866
|
-
showBackButton: true,
|
|
22867
23346
|
children: /* @__PURE__ */ jsxRuntimeExports.jsx(p$4, { align: "center", justify: "center", className: "min-h-64", children: /* @__PURE__ */ jsxRuntimeExports.jsx(p$7, { className: "text-center", children: /* @__PURE__ */ jsxRuntimeExports.jsx(p$b, { size: "5", weight: "medium", className: "mb-2", children: "Job not found" }) }) })
|
|
22868
23347
|
}
|
|
22869
23348
|
);
|
|
@@ -22881,28 +23360,64 @@ function PipelineDetail() {
|
|
|
22881
23360
|
const pageTitle = job.name || "Pipeline Details";
|
|
22882
23361
|
const breadcrumbs = [
|
|
22883
23362
|
{ label: "Home", href: "/" },
|
|
22884
|
-
{
|
|
23363
|
+
{
|
|
23364
|
+
label: job && job?.pipelineLabel ? job.pipelineLabel : "Pipeline Details"
|
|
23365
|
+
},
|
|
22885
23366
|
...job.name ? [{ label: job.name }] : []
|
|
22886
23367
|
];
|
|
22887
|
-
const
|
|
23368
|
+
const totalCost = job?.totalCost || job?.costs?.summary?.totalCost || 0;
|
|
23369
|
+
const totalTokens = job?.totalTokens || job?.costs?.summary?.totalTokens || 0;
|
|
23370
|
+
const totalInputTokens = job?.costs?.summary?.totalInputTokens || 0;
|
|
23371
|
+
const totalOutputTokens = job?.costs?.summary?.totalOutputTokens || 0;
|
|
23372
|
+
const costIndicator = /* @__PURE__ */ jsxRuntimeExports.jsxs(p$b, { size: "2", color: "gray", children: [
|
|
23373
|
+
"Cost: ",
|
|
23374
|
+
totalCost > 0 ? formatCurrency4(totalCost) : "—"
|
|
23375
|
+
] });
|
|
23376
|
+
const costIndicatorWithTooltip = totalCost > 0 && totalTokens > 0 ? /* @__PURE__ */ jsxRuntimeExports.jsx(Provider, { delayDuration: 100, children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Root3, { children: [
|
|
23377
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Trigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
23378
|
+
p$7,
|
|
23379
|
+
{
|
|
23380
|
+
className: "cursor-help border-b border-dotted border-gray-400 hover:border-gray-600 transition-colors",
|
|
23381
|
+
"aria-label": `Total cost: ${formatCurrency4(totalCost)}, ${formatTokensCompact(totalTokens)}`,
|
|
23382
|
+
children: costIndicator
|
|
23383
|
+
}
|
|
23384
|
+
) }),
|
|
23385
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Portal, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
23386
|
+
Content2,
|
|
23387
|
+
{
|
|
23388
|
+
className: "bg-gray-900 text-white px-2 py-1 rounded text-xs max-w-xs",
|
|
23389
|
+
sideOffset: 5,
|
|
23390
|
+
children: [
|
|
23391
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1", children: [
|
|
23392
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "font-semibold", children: formatTokensCompact(totalTokens) }),
|
|
23393
|
+
totalInputTokens > 0 && totalOutputTokens > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-gray-300", children: [
|
|
23394
|
+
"Input: ",
|
|
23395
|
+
formatTokensCompact(totalInputTokens),
|
|
23396
|
+
" • Output:",
|
|
23397
|
+
" ",
|
|
23398
|
+
formatTokensCompact(totalOutputTokens)
|
|
23399
|
+
] })
|
|
23400
|
+
] }),
|
|
23401
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Arrow2, { className: "fill-gray-900" })
|
|
23402
|
+
]
|
|
23403
|
+
}
|
|
23404
|
+
) })
|
|
23405
|
+
] }) }) : costIndicator;
|
|
23406
|
+
const subheaderRightContent = /* @__PURE__ */ jsxRuntimeExports.jsxs(p$4, { align: "center", gap: "3", className: "shrink-0 flex-wrap", children: [
|
|
22888
23407
|
/* @__PURE__ */ jsxRuntimeExports.jsxs(p$b, { size: "2", color: "gray", children: [
|
|
22889
23408
|
"ID: ",
|
|
22890
23409
|
job.id || jobId
|
|
22891
23410
|
] }),
|
|
23411
|
+
costIndicatorWithTooltip,
|
|
22892
23412
|
statusBadge(job.status)
|
|
22893
23413
|
] });
|
|
22894
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
22895
|
-
|
|
22896
|
-
|
|
22897
|
-
|
|
22898
|
-
|
|
22899
|
-
|
|
22900
|
-
|
|
22901
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(PageSubheader, { breadcrumbs, maxWidth: "max-w-7xl", children: subheaderRightContent }),
|
|
22902
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(JobDetail, { job, pipeline })
|
|
22903
|
-
]
|
|
22904
|
-
}
|
|
22905
|
-
);
|
|
23414
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs(Layout, { pageTitle, breadcrumbs, children: [
|
|
23415
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(PageSubheader, { breadcrumbs, maxWidth: "max-w-7xl", children: [
|
|
23416
|
+
subheaderRightContent,
|
|
23417
|
+
isRefreshing && /* @__PURE__ */ jsxRuntimeExports.jsx(p$b, { size: "2", color: "blue", className: "ml-3 animate-pulse", children: "Refreshing..." })
|
|
23418
|
+
] }),
|
|
23419
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(JobDetail, { job, pipeline })
|
|
23420
|
+
] });
|
|
22906
23421
|
}
|
|
22907
23422
|
const ioFunctions = [
|
|
22908
23423
|
{
|
|
@@ -23052,8 +23567,6 @@ function CodePage() {
|
|
|
23052
23567
|
topP?: number,
|
|
23053
23568
|
frequencyPenalty?: number,
|
|
23054
23569
|
presencePenalty?: number,
|
|
23055
|
-
tools?: Array<{type: "function", function: object}>,
|
|
23056
|
-
toolChoice?: "auto" | "required" | { type: "function", function: { name: string } },
|
|
23057
23570
|
seed?: number,
|
|
23058
23571
|
provider?: string,
|
|
23059
23572
|
model?: string,
|
|
@@ -23075,6 +23588,43 @@ function CodePage() {
|
|
|
23075
23588
|
] }, fn.fullPath))
|
|
23076
23589
|
) })
|
|
23077
23590
|
] }) }),
|
|
23591
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(r$8, { size: "6", mt: "8", mb: "4", children: "Validation API" }),
|
|
23592
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(p$b, { as: "p", mb: "3", size: "2", children: "Schema validation helper available to task stages via validators." }),
|
|
23593
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(p$7, { mb: "4", children: [
|
|
23594
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(r$8, { size: "4", mb: "2", children: "Function Signature" }),
|
|
23595
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(p$2, { size: "3", children: `validateWithSchema(schema: object, data: object | string): { valid: true } | { valid: false, errors: AjvError[] }` }),
|
|
23596
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(r$8, { size: "4", mb: "2", mt: "4", children: "Behavior" }),
|
|
23597
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("ul", { className: "list-disc list-inside mb-4 space-y-1", children: [
|
|
23598
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("li", { className: "text-sm text-gray-700", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(p$b, { as: "span", children: [
|
|
23599
|
+
"Parses string data to JSON; on parse failure returns",
|
|
23600
|
+
" ",
|
|
23601
|
+
`{ valid:false, errors:[{ keyword:"type", message:"must be a valid JSON object (string parsing failed)"} ]`
|
|
23602
|
+
] }) }),
|
|
23603
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("li", { className: "text-sm text-gray-700", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(p$b, { as: "span", children: [
|
|
23604
|
+
"Uses Ajv(",
|
|
23605
|
+
`{ allErrors: true, strict: false }`,
|
|
23606
|
+
"); compiles provided schema"
|
|
23607
|
+
] }) }),
|
|
23608
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("li", { className: "text-sm text-gray-700", children: /* @__PURE__ */ jsxRuntimeExports.jsx(p$b, { as: "span", children: "Returns AJV errors array when invalid" }) })
|
|
23609
|
+
] }),
|
|
23610
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(r$8, { size: "4", mb: "2", children: "Source" }),
|
|
23611
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(p$2, { size: "3", children: "src/api/validators/json.js" }),
|
|
23612
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(r$8, { size: "4", mb: "2", mt: "4", children: "Usage Example" }),
|
|
23613
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(p$2, { size: "3", children: `export const validateStructure = async ({
|
|
23614
|
+
io,
|
|
23615
|
+
flags,
|
|
23616
|
+
validators: { validateWithSchema },
|
|
23617
|
+
}) => {
|
|
23618
|
+
const content = await io.readArtifact("research-output.json");
|
|
23619
|
+
const result = validateWithSchema(researchJsonSchema, content);
|
|
23620
|
+
|
|
23621
|
+
if (!result.valid) {
|
|
23622
|
+
console.warn("[Research:validateStructure] Validation failed", result.errors);
|
|
23623
|
+
return { output: {}, flags: { ...flags, validationFailed: true } };
|
|
23624
|
+
}
|
|
23625
|
+
return { output: {}, flags };
|
|
23626
|
+
};` })
|
|
23627
|
+
] }),
|
|
23078
23628
|
/* @__PURE__ */ jsxRuntimeExports.jsx(r$8, { size: "6", mt: "8", mb: "4", children: "Environment Configuration" }),
|
|
23079
23629
|
/* @__PURE__ */ jsxRuntimeExports.jsxs(p$7, { mb: "4", children: [
|
|
23080
23630
|
/* @__PURE__ */ jsxRuntimeExports.jsx(r$8, { size: "4", mb: "2", children: "Example .env Configuration" }),
|
|
@@ -23085,15 +23635,102 @@ function CodePage() {
|
|
|
23085
23635
|
/* @__PURE__ */ jsxRuntimeExports.jsx(P$1, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(R, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(p$2, { size: "3", children: "DEEPSEEK_API_KEY=" }) }) }),
|
|
23086
23636
|
/* @__PURE__ */ jsxRuntimeExports.jsx(P$1, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(R, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(p$2, { size: "3", children: "GEMINI_API_KEY=" }) }) }),
|
|
23087
23637
|
/* @__PURE__ */ jsxRuntimeExports.jsx(P$1, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(R, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(p$2, { size: "3", children: "ANTHROPIC_API_KEY=" }) }) }),
|
|
23088
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(P$1, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(R, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(p$2, { size: "3", children: "
|
|
23638
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(P$1, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(R, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(p$2, { size: "3", children: "ZHIPU_API_KEY=" }) }) })
|
|
23089
23639
|
] })
|
|
23090
23640
|
] }) })
|
|
23091
23641
|
] })
|
|
23092
23642
|
] })
|
|
23093
23643
|
] });
|
|
23094
23644
|
}
|
|
23095
|
-
|
|
23096
|
-
|
|
23645
|
+
const ToastContext = reactExports.createContext();
|
|
23646
|
+
function ToastProvider({ children }) {
|
|
23647
|
+
const [toasts, setToasts] = reactExports.useState([]);
|
|
23648
|
+
const addToast = reactExports.useCallback((message, options = {}) => {
|
|
23649
|
+
const toast = {
|
|
23650
|
+
id: Date.now() + Math.random(),
|
|
23651
|
+
message,
|
|
23652
|
+
type: options.type || "info",
|
|
23653
|
+
duration: options.duration || 5e3
|
|
23654
|
+
};
|
|
23655
|
+
setToasts((prev) => [...prev, toast]);
|
|
23656
|
+
if (toast.duration > 0) {
|
|
23657
|
+
setTimeout(() => {
|
|
23658
|
+
removeToast(toast.id);
|
|
23659
|
+
}, toast.duration);
|
|
23660
|
+
}
|
|
23661
|
+
return toast.id;
|
|
23662
|
+
}, []);
|
|
23663
|
+
const removeToast = reactExports.useCallback((id) => {
|
|
23664
|
+
setToasts((prev) => prev.filter((toast) => toast.id !== id));
|
|
23665
|
+
}, []);
|
|
23666
|
+
const value = {
|
|
23667
|
+
addToast,
|
|
23668
|
+
removeToast,
|
|
23669
|
+
success: (message, options) => addToast(message, { ...options, type: "success" }),
|
|
23670
|
+
error: (message, options) => addToast(message, { ...options, type: "error" }),
|
|
23671
|
+
warning: (message, options) => addToast(message, { ...options, type: "warning" }),
|
|
23672
|
+
info: (message, options) => addToast(message, { ...options, type: "info" })
|
|
23673
|
+
};
|
|
23674
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs(ToastContext.Provider, { value, children: [
|
|
23675
|
+
children,
|
|
23676
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(ToastContainer, { toasts, onRemove: removeToast })
|
|
23677
|
+
] });
|
|
23678
|
+
}
|
|
23679
|
+
function ToastContainer({ toasts, onRemove }) {
|
|
23680
|
+
if (toasts.length === 0) return null;
|
|
23681
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "fixed top-4 right-4 z-50 space-y-2", children: toasts.map((toast) => /* @__PURE__ */ jsxRuntimeExports.jsx(ToastItem, { toast, onRemove }, toast.id)) });
|
|
23682
|
+
}
|
|
23683
|
+
function ToastItem({ toast, onRemove }) {
|
|
23684
|
+
const getToastStyles = (type) => {
|
|
23685
|
+
switch (type) {
|
|
23686
|
+
case "success":
|
|
23687
|
+
return "bg-green-50 border-green-200 text-green-800";
|
|
23688
|
+
case "error":
|
|
23689
|
+
return "bg-red-50 border-red-200 text-red-800";
|
|
23690
|
+
case "warning":
|
|
23691
|
+
return "bg-yellow-50 border-yellow-200 text-yellow-800";
|
|
23692
|
+
default:
|
|
23693
|
+
return "bg-blue-50 border-blue-200 text-blue-800";
|
|
23694
|
+
}
|
|
23695
|
+
};
|
|
23696
|
+
const getIcon = (type) => {
|
|
23697
|
+
switch (type) {
|
|
23698
|
+
case "success":
|
|
23699
|
+
return "✓";
|
|
23700
|
+
case "error":
|
|
23701
|
+
return "✕";
|
|
23702
|
+
case "warning":
|
|
23703
|
+
return "⚠";
|
|
23704
|
+
default:
|
|
23705
|
+
return "ℹ";
|
|
23706
|
+
}
|
|
23707
|
+
};
|
|
23708
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
23709
|
+
p$7,
|
|
23710
|
+
{
|
|
23711
|
+
className: `relative flex items-start p-4 border rounded-lg shadow-lg max-w-sm ${getToastStyles(
|
|
23712
|
+
toast.type
|
|
23713
|
+
)}`,
|
|
23714
|
+
role: "alert",
|
|
23715
|
+
"aria-live": "polite",
|
|
23716
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsxs(p$4, { gap: "3", align: "start", children: [
|
|
23717
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(p$b, { className: "flex-shrink-0 text-lg font-semibold", children: getIcon(toast.type) }),
|
|
23718
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(p$b, { className: "text-sm font-medium flex-1", children: toast.message }),
|
|
23719
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
23720
|
+
"button",
|
|
23721
|
+
{
|
|
23722
|
+
onClick: () => onRemove(toast.id),
|
|
23723
|
+
className: "flex-shrink-0 ml-4 text-sm opacity-60 hover:opacity-100 focus:outline-none focus:opacity-100",
|
|
23724
|
+
"aria-label": "Dismiss notification",
|
|
23725
|
+
children: "✕"
|
|
23726
|
+
}
|
|
23727
|
+
)
|
|
23728
|
+
] })
|
|
23729
|
+
}
|
|
23730
|
+
);
|
|
23731
|
+
}
|
|
23732
|
+
ReactDOM$1.createRoot(document.getElementById("root")).render(
|
|
23733
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(React.StrictMode, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(ToastProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
23097
23734
|
R$1,
|
|
23098
23735
|
{
|
|
23099
23736
|
accentColor: "iris",
|
|
@@ -23107,5 +23744,5 @@ ReactDOM.createRoot(document.getElementById("root")).render(
|
|
|
23107
23744
|
/* @__PURE__ */ jsxRuntimeExports.jsx(Route, { path: "/code", element: /* @__PURE__ */ jsxRuntimeExports.jsx(CodePage, {}) })
|
|
23108
23745
|
] }) })
|
|
23109
23746
|
}
|
|
23110
|
-
) })
|
|
23747
|
+
) }) })
|
|
23111
23748
|
);
|