@qaick/runner 0.32.16 → 0.32.19
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/package-dist/package.json +4 -4
- package/package-dist/src/runner/RunnerModule.d.ts.map +1 -1
- package/package-dist/src/runner/RunnerModule.js +21 -15
- package/package-dist/src/runner/RunnerModule.js.map +1 -1
- package/package-dist/src/runner/history.d.ts +2 -0
- package/package-dist/src/runner/history.d.ts.map +1 -1
- package/package-dist/src/runner/history.js +26 -0
- package/package-dist/src/runner/history.js.map +1 -1
- package/package-dist/src/runner/redaction.d.ts +7 -4
- package/package-dist/src/runner/redaction.d.ts.map +1 -1
- package/package-dist/src/runner/redaction.js +96 -20
- package/package-dist/src/runner/redaction.js.map +1 -1
- package/package-dist/src/runner/runtime-client-adapter.d.ts +2 -2
- package/package-dist/src/runner/runtime-client-adapter.d.ts.map +1 -1
- package/package-dist/src/runner/runtime-client-adapter.js +78 -27
- package/package-dist/src/runner/runtime-client-adapter.js.map +1 -1
- package/package.json +4 -4
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qaick/runner",
|
|
3
3
|
"description": "Reusable QAick Runner module and standalone execution application.",
|
|
4
|
-
"version": "0.32.
|
|
4
|
+
"version": "0.32.19",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
7
7
|
"package-dist",
|
|
@@ -63,9 +63,9 @@
|
|
|
63
63
|
},
|
|
64
64
|
"dependencies": {
|
|
65
65
|
"@qaick/contract": "0.7.3",
|
|
66
|
-
"@qaick/executor": "0.4.
|
|
67
|
-
"@qaick/http-executor": "0.2.
|
|
68
|
-
"@qaick/runtime": "0.4.
|
|
66
|
+
"@qaick/executor": "0.4.9",
|
|
67
|
+
"@qaick/http-executor": "0.2.19",
|
|
68
|
+
"@qaick/runtime": "0.4.10",
|
|
69
69
|
"zustand": "^5.0.15"
|
|
70
70
|
},
|
|
71
71
|
"peerDependencies": {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RunnerModule.d.ts","sourceRoot":"","sources":["../../../src/runner/RunnerModule.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA6B,KAAK,SAAS,EAAE,MAAM,+BAA4B,CAAC;AAUvF,OAAO,KAAK,EAAqB,cAAc,EAAe,gBAAgB,EAAC,MAAM,iBAAiB,CAAC;AAQvG,OAAO,KAAK,EAAkB,gBAAgB,EAAmB,eAAe,EAAE,UAAU,EAAE,MAAM,YAAS,CAAC;AAC9G,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAkB,CAAC;AA6B5D,MAAM,WAAW,iBAAiB;IAChC,OAAO,CAAC,EAAE,EAAE,SAAS,GAAG,OAAO,CAAC;IAChC,WAAW,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACjE,KAAK,IAAI,IAAI,CAAC;IACd,IAAI,IAAI,IAAI,CAAC;CACd;AACD,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,OAAO,EAAE,iBAAiB,GAAG,MAAM,IAAI,CAAC;CAClD;AACD,MAAM,WAAW,iBAAiB;IAChC,eAAe,CAAC,EAAE,qBAAqB,CAAC;IACxC,MAAM,EAAE,mBAAmB,CAAC;IAC5B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;CACrB;AASD,wBAAgB,YAAY,CAAC,EAAE,MAAM,EAAE,QAAoC,EAAE,MAAM,EAAE,eAAe,EAAE,EAAE,iBAAiB,+BAExH;
|
|
1
|
+
{"version":3,"file":"RunnerModule.d.ts","sourceRoot":"","sources":["../../../src/runner/RunnerModule.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA6B,KAAK,SAAS,EAAE,MAAM,+BAA4B,CAAC;AAUvF,OAAO,KAAK,EAAqB,cAAc,EAAe,gBAAgB,EAAC,MAAM,iBAAiB,CAAC;AAQvG,OAAO,KAAK,EAAkB,gBAAgB,EAAmB,eAAe,EAAE,UAAU,EAAE,MAAM,YAAS,CAAC;AAC9G,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAkB,CAAC;AA6B5D,MAAM,WAAW,iBAAiB;IAChC,OAAO,CAAC,EAAE,EAAE,SAAS,GAAG,OAAO,CAAC;IAChC,WAAW,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACjE,KAAK,IAAI,IAAI,CAAC;IACd,IAAI,IAAI,IAAI,CAAC;CACd;AACD,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,OAAO,EAAE,iBAAiB,GAAG,MAAM,IAAI,CAAC;CAClD;AACD,MAAM,WAAW,iBAAiB;IAChC,eAAe,CAAC,EAAE,qBAAqB,CAAC;IACxC,MAAM,EAAE,mBAAmB,CAAC;IAC5B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;CACrB;AASD,wBAAgB,YAAY,CAAC,EAAE,MAAM,EAAE,QAAoC,EAAE,MAAM,EAAE,eAAe,EAAE,EAAE,iBAAiB,+BAExH;AA6YD,KAAK,WAAW,GAAG;IAAE,cAAc,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAC,MAAM,CAAC;IAAA,iBAAiB,CAAC,EAAC,gBAAgB,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,WAAW,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,GAAC,MAAM,GAAC,MAAM,GAAC,QAAQ,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAC,OAAO,CAAC;IAAC,YAAY,CAAC,EAAC,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,OAAO,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,CAAC;IAAC,WAAW,CAAC,EAAC,gBAAgB,CAAC;IAAC,cAAc,CAAC,EAAC,MAAM,CAAA;CAAE,CAAC;AAkB1a,wBAAgB,yBAAyB,CAAC,KAAK,EAAC,WAAW,EAAE,EAAC,QAAQ,EAAC,UAAU,EAAE,GAAE,WAAW,EAAE,CAAe;AACjH,eAAO,MAAM,aAAa,GAAE,UAAS,gBAAgB,WAA8D,CAAC;AACpH,wBAAgB,oBAAoB,CAAC,OAAO,EAAC,UAAU,EAAE,EAAC,OAAO,CAAC,EAAC,gBAAgB,EAAC,UAAU,CAAC,EAAC,MAAM,GAAE,UAAU,EAAE,CAAuI;AAC3P,wBAAgB,mBAAmB,CAAC,OAAO,EAAC,UAAU,EAAE,EAAC,OAAO,CAAC,EAAC,gBAAgB,EAAC,UAAU,CAAC,EAAC,MAAM,GAAE,UAAU,GAAC,SAAS,CAAiH;AAC5O,wBAAgB,kBAAkB,CAAC,OAAO,EAAC,UAAU,EAAE,EAAC,OAAO,CAAC,EAAC,gBAAgB,GAAE,eAAe,GAAC,SAAS,CAS3G;AAID,wBAAgB,mBAAmB,CAAC,EAAC,OAAO,EAAC,UAAU,EAAC,EAAC;IAAC,OAAO,EAAC,UAAU,EAAE,CAAC;IAAA,UAAU,CAAC,EAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAA;CAAC,+BAK5H;AAcD,kGAAkG;AAClG,wBAAgB,uBAAuB,CAAC,IAAI,EAAC,WAAW,EAAE,EAAC,MAAM,EAAC;IAAC,MAAM,CAAC,EAAC,MAAM,CAAC;IAAA,UAAU,CAAC,EAAC,MAAM,CAAC;IAAA,OAAO,CAAC,EAAC,gBAAgB,CAAA;CAAC,EAAC,OAAO,CAAC,EAAC,cAAc,GAAE;IAAC,IAAI,CAAC,EAAC,WAAW,CAAC;IAAA,MAAM,CAAC,EAAC,MAAM,CAAA;CAAC,CAa1L"}
|
|
@@ -17,10 +17,10 @@ import { PackageCatalog } from "./catalog.js";
|
|
|
17
17
|
import { RUNNER_CONTRACT_VERSION } from "./types.js";
|
|
18
18
|
import { RunnerWalkthrough } from "../demo/RunnerWalkthrough.js";
|
|
19
19
|
import { RUNNER_BUILD_LABEL, RUNNER_UI_VERSION } from "../build-info.js";
|
|
20
|
-
import { collectSecretValues, redactExecutionEvent, redactExecutionResult, redactKeyValuePairs } from "./redaction.js";
|
|
20
|
+
import { collectSecretValues, redactExecutionEvent, redactExecutionResult, redactKeyValuePairs, redactValue, redactText, isSensitiveKey } from "./redaction.js";
|
|
21
21
|
import { createResultExport } from "./result-export.js";
|
|
22
22
|
import { inspectDeclaredInputs, inputDrafts, resolvedArguments } from "./invocation-inputs.js";
|
|
23
|
-
import { persistRunHistory, redactHistoryEntry, captureHistoryStructure, assertHistoryIdentity, recoverRunHistoryEntry } from "./history.js";
|
|
23
|
+
import { persistRunHistory, redactHistoryEntry, captureHistoryStructure, assertHistoryIdentity, recoverRunHistoryEntry, historyPresentationEntry } from "./history.js";
|
|
24
24
|
import { prepareStudioDocument } from "./studio-execution-document.js";
|
|
25
25
|
const statusGlyph = { pending: '', 'not executed': '', running: '', finished: '✓', failed: '✕', waiting: '◷', skipped: '–', cancelled: '⊘' };
|
|
26
26
|
const HISTORY_KEY = 'qaick-runner.history.v1';
|
|
@@ -231,7 +231,11 @@ function RunnerApp({ client, onExit, applicationMenu }) {
|
|
|
231
231
|
const legacyDisplaySteps = orderDisplayStepsByResult(flattenDisplaySteps(packageSteps, 0, undefined, undefined, collapsedSteps), result?.children?.flatMap(child => flattenResultSteps(child.steps)) ?? flattenResultSteps(result?.steps ?? []));
|
|
232
232
|
const liveDisplaySteps = preparedDocument ? contextDisplaySteps(preparedDocument.context, collapsedSteps, preparedDocument) : authoringSource ? [] : legacyDisplaySteps;
|
|
233
233
|
const historyPackage = undefined;
|
|
234
|
-
const
|
|
234
|
+
const presentedHistory = historicalEntry ? historyPresentationEntry(historicalEntry) : undefined;
|
|
235
|
+
const historicalEvents = presentedHistory?.events ?? [];
|
|
236
|
+
const invocationSecrets = collectSecretValues(inputs, runtimeValues, inputContract, (preparedDocument ?? executionPackage));
|
|
237
|
+
const shownSecrets = readOnly ? collectSecretValues(historicalEntry?.result) : invocationSecrets;
|
|
238
|
+
const shownResult = readOnly ? presentedHistory?.result && redactExecutionResult(presentedHistory.result, shownSecrets) : result;
|
|
235
239
|
const shownPackage = readOnly ? historyPackage : authoringSource ? undefined : executionPackage;
|
|
236
240
|
const shownPackageSteps = shownPackage ? packageStepsFor(shownPackage) : [];
|
|
237
241
|
const shownSelectedStep = readOnly ? historySelectedStep : selectedStep;
|
|
@@ -239,12 +243,12 @@ function RunnerApp({ client, onExit, applicationMenu }) {
|
|
|
239
243
|
const shownRunState = readOnly ? historicalEntry?.state ?? 'ready' : runState;
|
|
240
244
|
const allResults = shownResult?.children?.flatMap(child => flattenResultSteps(child.steps)) ?? flattenResultSteps(shownResult?.steps ?? []);
|
|
241
245
|
const displaySteps = readOnly ? historicalEntry?.structure ? contextDisplaySteps(historicalEntry.structure.context, historyCollapsedSteps) : recordedDisplaySteps(allResults) : liveDisplaySteps;
|
|
242
|
-
const selectedStart = selectedStepStartedAt(displaySteps[shownSelectedStep], { results: allResults, result: shownResult, context: readOnly ? historicalEntry?.structure?.context : preparedDocument?.context, scope: readOnly ? historicalEntry?.structure?.scope : preparedDocument?.selection.root, events: readOnly ?
|
|
246
|
+
const selectedStart = selectedStepStartedAt(displaySteps[shownSelectedStep], { results: allResults, result: shownResult, context: readOnly ? historicalEntry?.structure?.context : preparedDocument?.context, scope: readOnly ? historicalEntry?.structure?.scope : preparedDocument?.selection.root, events: readOnly ? historicalEvents.map(event => redactExecutionEvent(event, shownSecrets)) : events, requestId: shownRequestId });
|
|
243
247
|
const guides = hierarchyGuides(displaySteps);
|
|
244
248
|
const hasNestedSteps = displaySteps.some(step => step.depth > 0 || step.hasChildren);
|
|
245
249
|
const displayResults = displaySteps.map(step => resultForOccurrence(allResults, step.structuralAddress, step.occurrence));
|
|
246
250
|
const selectedInvocations = resultsForOccurrence(allResults, displaySteps[shownSelectedStep]?.structuralAddress, displaySteps[shownSelectedStep]?.occurrence);
|
|
247
|
-
const selectedPaths = readableInvocationPaths(displaySteps[shownSelectedStep], { context: readOnly ? historicalEntry?.structure?.context : preparedDocument?.context, invocations: selectedInvocations, allResults, result: shownResult, events: readOnly ?
|
|
251
|
+
const selectedPaths = readableInvocationPaths(displaySteps[shownSelectedStep], { context: readOnly ? historicalEntry?.structure?.context : preparedDocument?.context, invocations: selectedInvocations, allResults, result: shownResult, events: readOnly ? historicalEvents.map(event => redactExecutionEvent(event, shownSecrets)) : events, requestId: shownRequestId });
|
|
248
252
|
const selectedError = displayResults[shownSelectedStep]?.error;
|
|
249
253
|
const errorCode = selectedError?.code ?? shownResult?.error?.code;
|
|
250
254
|
const errorMessage = selectedError?.message ?? shownResult?.error?.message;
|
|
@@ -263,7 +267,7 @@ function RunnerApp({ client, onExit, applicationMenu }) {
|
|
|
263
267
|
switchWorkspace(next);
|
|
264
268
|
document.getElementById(`runner-tab-${next}`)?.focus();
|
|
265
269
|
}
|
|
266
|
-
const executionEvents = (readOnly ?
|
|
270
|
+
const executionEvents = (readOnly ? historicalEvents.map(event => redactExecutionEvent(event, shownSecrets)) : events).filter(event => event.requestId === shownRequestId);
|
|
267
271
|
const visibleEvents = executionEvents.filter(event => { const categoryMatches = eventFilter === 'all' || eventFilter === 'parallel' && event.parallel || eventFilter === 'steps' && event.stepId || eventFilter === 'lifecycle' && !event.stepId && !event.parallel || eventFilter === 'failures' && (event.state === 'failed' || event.type.includes('error')); const searchMatches = !eventSearch.trim() || `${event.type} ${event.state} ${event.message} ${event.stepName ?? ''}`.toLowerCase().includes(eventSearch.trim().toLowerCase()); return categoryMatches && searchMatches; });
|
|
268
272
|
function selectRoot(key) { if (activeInputRequest.current)
|
|
269
273
|
return; setSelectedRoot(key); setSelectedStep(0); stepStateCache.current = {}; setStepStates(liveDisplaySteps.map(() => 'pending')); setResult(undefined); setEvents([]); setRequestId(undefined); setRunState('ready'); setControlState('idle'); setLoadError(undefined); }
|
|
@@ -291,7 +295,7 @@ function RunnerApp({ client, onExit, applicationMenu }) {
|
|
|
291
295
|
setControlState('running');
|
|
292
296
|
let structure;
|
|
293
297
|
let admission;
|
|
294
|
-
const secretValues =
|
|
298
|
+
const secretValues = invocationSecrets;
|
|
295
299
|
try {
|
|
296
300
|
structure = await captureHistoryStructure(currentPackage);
|
|
297
301
|
admission = { historyVersion: 2, structure, requestId: id, admittedAt: new Date().toISOString(), target: currentPackage.target.name, packageId: currentPackage.packageId, executionSchemaVersion: currentPackage.schemaVersion, state: 'admitted', events: [], eventCollectionIncomplete: true,
|
|
@@ -361,7 +365,9 @@ function RunnerApp({ client, onExit, applicationMenu }) {
|
|
|
361
365
|
})();
|
|
362
366
|
let executionResult;
|
|
363
367
|
try {
|
|
364
|
-
|
|
368
|
+
const actualResult = await client.result(id);
|
|
369
|
+
secretValues.push(...collectSecretValues(actualResult));
|
|
370
|
+
executionResult = redactExecutionResult(actualResult, secretValues);
|
|
365
371
|
}
|
|
366
372
|
catch {
|
|
367
373
|
completed = true;
|
|
@@ -424,13 +430,13 @@ function RunnerApp({ client, onExit, applicationMenu }) {
|
|
|
424
430
|
next.add(stepId); breakpointsRef.current = next; return next; }); }
|
|
425
431
|
function toggleStopAfter(stepId) { setStopAfterStepId(previous => previous === stepId ? undefined : stepId); }
|
|
426
432
|
function exportResult(value, packageId, schemaVersion, provenance, executionVersion) { if (!value)
|
|
427
|
-
return; const storedEntry = runHistory.find(entry => entry.requestId === value.requestId); const exportPayload = storedEntry?.historyVersion === 2 ? { runnerResultVersion: 2, entry: storedEntry } : createResultExport(value, packageId ?? 'unknown', schemaVersion, collectSecretValues(
|
|
433
|
+
return; const storedEntry = runHistory.find(entry => entry.requestId === value.requestId); const exportPayload = storedEntry?.historyVersion === 2 ? { runnerResultVersion: 2, entry: redactHistoryEntry(storedEntry, collectSecretValues(storedEntry.result)) } : createResultExport(value, packageId ?? 'unknown', schemaVersion, storedEntry ? collectSecretValues(storedEntry.result) : invocationSecrets, provenance, executionVersion); const blob = new Blob([JSON.stringify(exportPayload, null, 2)], { type: 'application/json' }); const url = URL.createObjectURL(blob); const link = document.createElement('a'); link.href = url; link.download = `${value.target.name.replace(/[^a-z0-9]+/gi, '-').toLowerCase()}-${value.requestId}.result.json`; link.click(); URL.revokeObjectURL(url); }
|
|
428
434
|
function exportHistoryEntry(entry) {
|
|
429
435
|
if (entry.result && entry.historyVersion !== 2) {
|
|
430
436
|
exportResult(entry.result, entry.packageId, entry.artifactSchemaVersion, entry.artifactProvenance, entry.executionSchemaVersion);
|
|
431
437
|
return;
|
|
432
438
|
}
|
|
433
|
-
const blob = new Blob([JSON.stringify({ runnerResultVersion: 2, entry }, null, 2)], { type: 'application/json' });
|
|
439
|
+
const blob = new Blob([JSON.stringify({ runnerResultVersion: 2, entry: redactHistoryEntry(entry, collectSecretValues(entry.result)) }, null, 2)], { type: 'application/json' });
|
|
434
440
|
const url = URL.createObjectURL(blob), link = document.createElement('a');
|
|
435
441
|
link.href = url;
|
|
436
442
|
link.download = `${entry.target.replace(/[^a-z0-9]+/gi, '-').toLowerCase()}-${entry.requestId}.result.json`;
|
|
@@ -637,8 +643,8 @@ function RunnerApp({ client, onExit, applicationMenu }) {
|
|
|
637
643
|
about: () => menuActions.current.about(),
|
|
638
644
|
demo: () => menuActions.current.demo(),
|
|
639
645
|
}), [registerMenu]);
|
|
640
|
-
return _jsxs("div", { className: "runner-shell", children: [_jsxs("header", { className: "runner-header", children: [_jsxs("div", { className: "runner-brand", children: [_jsx("span", { className: "runner-brand-mark", children: "QAICK" }), _jsx("span", { className: "runner-brand-product", children: "Runner" }), _jsx("span", { className: "alpha-label", children: RUNNER_UI_VERSION }), onExit && _jsx("button", { className: "about-button", onClick: onExit, children: "Studio" })] }), !applicationMenu?.native && _jsx(HeaderHelp, { enabled: id => menuActions.current.enabled(id), onAbout: () => menuActions.current.about(), onOpenProject: () => projectFileInput.current?.click() }), _jsx("span", { className: "header-spacer" }), _jsx(ScreenshotButton, { className: "about-button" }), _jsx("a", { className: "demo-entry", href: "./examples/qaick-local-http-regression.qaick.json", download: true, title: "Download QAick Local HTTP Regression. Start the local fixture on port 5197, then load this file. Runner executes both Flows. Editing is restricted in Studio.", children: "HTTP example" }), _jsx(ThemeToggle, { theme: theme, onChange: setTheme, className: "runner-theme-toggle" })] }), _jsx("input", { ref: projectFileInput, type: "file", accept: "application/json,.json", hidden: true, "aria-label": "Open Project\u2026", onChange: event => { const file = event.target.files?.[0]; event.target.value = ''; void loadPackage(file); } }), _jsx("div", { className: "runner-tabs", role: "tablist", "aria-label": "Runner workspace", children: ['execution', 'history'].map(tab => _jsx("button", { id: `runner-tab-${tab}`, role: "tab", "aria-selected": workspace === tab, "aria-controls": `runner-panel-${tab}`, tabIndex: workspace === tab ? 0 : -1, onKeyDown: tabKey, onClick: () => switchWorkspace(tab), children: tab === 'execution' ? 'Execution' : 'History' }, tab)) }), _jsx("div", { className: "runner-pane-scroll", role: "region", "aria-label": "Runner workspace and Inspector", tabIndex: 0, children: _jsxs("main", { style: { gridTemplateColumns: `minmax(560px, 1fr) 8px ${inspectorWidth}px`, minWidth: `${568 + inspectorWidth}px` }, className: "runner-main runner-tabbed-main", id: `runner-panel-${workspace}`, role: "tabpanel", "aria-labelledby": `runner-tab-${workspace}`, children: [_jsxs(_Fragment, { children: [_jsxs("section", { className: "runner-workspace", children: [diagnosticNotice && _jsx("p", { className: "notice", role: "status", children: diagnosticNotice }), historySaveError && _jsx("p", { className: "load-error", role: "alert", children: historySaveError }), readOnly && loadError && _jsx("p", { className: "load-error", role: "alert", children: loadError }), readOnly && loadIssues.length > 0 && _jsx(PreRunValidation, { issues: loadIssues, title: "Artifact validation" }), readOnly && historicalEntry && !historicalEntry.structure && _jsx("p", { className: "notice", children: "Original Project structure was not recorded for this run. Only recorded execution evidence is available." }), readOnly && _jsx(HistoryPanel, { entries: runHistory, onReload: reloadHistoryEntry, retention: historyRetention, onRetentionChange: changeHistoryRetention, onClear: clearHistory, onDelete: deleteHistoryEntry, onExport: exportHistoryEntry }), _jsxs("div", { hidden: readOnly, children: [_jsx("h1", { children: contextTarget.name }), _jsxs("p", { className: "description", children: ["Execute the selected QAick ", contextTarget.kind === 'project' ? 'Project' : 'Flow', " and capture structured evidence."] }), _jsxs("div", { className: "run-controls", children: [_jsxs("div", { className: "run-settings", role: "group", "aria-label": "Execution setup", children: [_jsxs("label", { children: ["Run only", _jsxs("select", { disabled: inputsLocked || preparing, value: selectedRoot, onChange: event => selectRoot(event.target.value), children: [_jsx("option", { value: "", children: "Entire project" }), preparedDocument && contextDisplaySteps(preparedDocument.context, new Set(), preparedDocument).filter(n => n.kind !== 'body' && n.kind !== 'branch').map(n => _jsxs("option", { value: n.id, children: [' '.repeat(n.depth), n.name] }, n.id))] })] }), _jsxs("label", { children: ["Timeout", _jsxs("select", { disabled: inputsLocked, value: timeoutMs, onChange: event => setTimeoutMs(event.target.value), children: [_jsx("option", { value: "none", children: "None" }), _jsx("option", { value: "1000", children: "1 second" }), _jsx("option", { value: "3000", children: "3 seconds" }), _jsx("option", { value: "10000", children: "10 seconds" })] })] })] }), _jsxs("div", { className: "run-actions", role: "group", "aria-label": "Execution actions", children: [_jsx("button", { className: "button", disabled: inputsLocked, onClick: () => { if (!activeInputRequest.current)
|
|
641
|
-
setEditingInputs(value => !value); }, children: editingInputs ? 'Done inputs' : 'Edit inputs' }), _jsx("button", { className: "button primary", onClick: () => void run(), disabled: !!inputBlocker || preparing || !!preparationError || runState === 'preflighting' || runState === 'running', children: "\u25B6\u00A0 Run" }), _jsx("button", { className: "button dry-run", onClick: () => void run(true), disabled: !!inputBlocker || preparing || !!preparationError || runState === "preflighting" || runState === "running", children: "\u25CE\u00A0 Pre-run validation" }), _jsx("button", { className: "button stop", onClick: () => void stop(), disabled: runState !== 'preflighting' && runState !== 'running', children: "\u25A0\u00A0 Stop" }), _jsx("button", { className: "button", onClick: () => void pause(), disabled: controlState !== 'running', children: "\u2161\u00A0 Pause" }), _jsx("button", { className: `button ${controlState === 'paused' ? 'resume-highlight' : ''}`, onClick: () => void resume(), disabled: controlState !== 'paused', children: "\u25B6\u00A0 Resume" }), _jsx("button", { className: "button", onClick: () => void stepExecution(), disabled: controlState !== 'paused', children: "\u21A6\u00A0 Step" }), breakpoints.size > 0 && _jsxs("span", { className: "debug-session-badge", children: [breakpoints.size, " breakpoint", breakpoints.size === 1 ? "" : "s", " armed"] })] })] }), preparing && _jsx("p", { role: "status", children: "Preparing Project\u2026" }), preparationError && _jsx("p", { role: "alert", children: preparationError }), preparedDocument && !preparedDocument.selection.executable && _jsx("section", { role: "alert", children: preparedDocument.selection.issues.map((i, index) => _jsxs("p", { children: [preparedDocument.context.nodes.find(n => n.key === i.at)?.name, ": ", i.message] }, index)) }), conflict && _jsxs("section", { role: "alert", children: [_jsx("p", { children: conflict.message }), _jsx("ul", { children: conflict.entries.map((entry, index) => _jsxs("li", { children: [entry.owner, " \u00B7 ", entry.declaration.name, " \u00B7 ", entry.declaration.type, " \u00B7 ", entry.declaration.required ? 'required' : 'optional', " \u00B7 default: ", Object.hasOwn(entry.declaration, 'defaultValue') ? JSON.stringify(entry.declaration.defaultValue) : 'none'] }, index)) }), _jsx("p", { children: "Retained input drafts:" }), _jsx("ul", { children: Object.entries(inputEdits).map(([name, draft]) => _jsxs("li", { children: [name, " \u00B7 ", draft.supplied ? 'supplied' : 'omitted'] }, name)) })] }), unresolved && _jsxs("section", { role: "alert", children: [_jsx("p", { children: unresolved.message }), _jsx("ul", { children: unresolved.entries.map((entry, index) => _jsxs("li", { children: [entry.owner, " \u00B7 ", entry.name, " \u00B7 required \u00B7 type unresolved"] }, index)) }), _jsx("p", { children: "Retained input drafts:" }), _jsx("ul", { children: Object.entries(inputEdits).map(([name, draft]) => _jsxs("li", { children: [name, " \u00B7 ", draft.supplied ? 'supplied' : 'omitted'] }, name)) })] }), inputError && _jsx("p", { role: "alert", children: inputError }), loadError && _jsx("p", { className: "load-error", children: loadError }), loadIssues.length > 0 && _jsx(PreRunValidation, { issues: loadIssues, title: "Artifact validation" }), result?.issues !== undefined && _jsx(PreRunValidation, { issues: result.issues }), result?.warnings !== undefined && result.warnings.length > 0 && _jsx(PreRunValidation, { issues: result.warnings, title: "Browser execution warnings" }), editingInputs && _jsxs("section", { className: "inputs-panel panel", children: [_jsxs("div", { className: "panel-heading", children: [_jsx("h2", { children: "Invocation Inputs" }), _jsx("span", { className: "panel-spacer" }), _jsx("span", { className: "input-hint", children: inputsLocked ? 'Inputs are locked while execution is active.' : 'Values are sent with the next run' })] }), _jsxs("fieldset", { className: "input-grid input-lock-fields", "aria-label": "Invocation input values", disabled: inputsLocked, children: [inputBlocker ? _jsx("p", { children: "Invocation input editing is unavailable until requirements are resolved." }) : declarations.map(declaration => { const draft = inputEdits[declaration.name] ?? { supplied: false, text: '' }; const change = (text) => { if (!activeInputRequest.current)
|
|
646
|
+
return _jsxs("div", { className: "runner-shell", children: [_jsxs("header", { className: "runner-header", children: [_jsxs("div", { className: "runner-brand", children: [_jsx("span", { className: "runner-brand-mark", children: "QAICK" }), _jsx("span", { className: "runner-brand-product", children: "Runner" }), _jsx("span", { className: "alpha-label", children: RUNNER_UI_VERSION }), onExit && _jsx("button", { className: "about-button", onClick: onExit, children: "Studio" })] }), !applicationMenu?.native && _jsx(HeaderHelp, { enabled: id => menuActions.current.enabled(id), onAbout: () => menuActions.current.about(), onOpenProject: () => projectFileInput.current?.click() }), _jsx("span", { className: "header-spacer" }), _jsx(ScreenshotButton, { className: "about-button" }), _jsx("a", { className: "demo-entry", href: "./examples/qaick-local-http-regression.qaick.json", download: true, title: "Download QAick Local HTTP Regression. Start the local fixture on port 5197, then load this file. Runner executes both Flows. Editing is restricted in Studio.", children: "HTTP example" }), _jsx(ThemeToggle, { theme: theme, onChange: setTheme, className: "runner-theme-toggle" })] }), _jsx("input", { ref: projectFileInput, type: "file", accept: "application/json,.json", hidden: true, "aria-label": "Open Project\u2026", onChange: event => { const file = event.target.files?.[0]; event.target.value = ''; void loadPackage(file); } }), _jsx("div", { className: "runner-tabs", role: "tablist", "aria-label": "Runner workspace", children: ['execution', 'history'].map(tab => _jsx("button", { id: `runner-tab-${tab}`, role: "tab", "aria-selected": workspace === tab, "aria-controls": `runner-panel-${tab}`, tabIndex: workspace === tab ? 0 : -1, onKeyDown: tabKey, onClick: () => switchWorkspace(tab), children: tab === 'execution' ? 'Execution' : 'History' }, tab)) }), _jsx("div", { className: "runner-pane-scroll", role: "region", "aria-label": "Runner workspace and Inspector", tabIndex: 0, children: _jsxs("main", { style: { gridTemplateColumns: `minmax(560px, 1fr) 8px ${inspectorWidth}px`, minWidth: `${568 + inspectorWidth}px` }, className: "runner-main runner-tabbed-main", id: `runner-panel-${workspace}`, role: "tabpanel", "aria-labelledby": `runner-tab-${workspace}`, children: [_jsxs(_Fragment, { children: [_jsxs("section", { className: "runner-workspace", children: [diagnosticNotice && _jsx("p", { className: "notice", role: "status", children: diagnosticNotice }), historySaveError && _jsx("p", { className: "load-error", role: "alert", children: historySaveError }), readOnly && loadError && _jsx("p", { className: "load-error", role: "alert", children: loadError }), readOnly && loadIssues.length > 0 && _jsx(PreRunValidation, { issues: loadIssues.map(issue => ({ ...issue, message: redactText(issue.message, invocationSecrets) })), title: "Artifact validation" }), readOnly && historicalEntry && !historicalEntry.structure && _jsx("p", { className: "notice", children: "Original Project structure was not recorded for this run. Only recorded execution evidence is available." }), readOnly && _jsx(HistoryPanel, { entries: runHistory, onReload: reloadHistoryEntry, retention: historyRetention, onRetentionChange: changeHistoryRetention, onClear: clearHistory, onDelete: deleteHistoryEntry, onExport: exportHistoryEntry }), _jsxs("div", { hidden: readOnly, children: [_jsx("h1", { children: contextTarget.name }), _jsxs("p", { className: "description", children: ["Execute the selected QAick ", contextTarget.kind === 'project' ? 'Project' : 'Flow', " and capture structured evidence."] }), _jsxs("div", { className: "run-controls", children: [_jsxs("div", { className: "run-settings", role: "group", "aria-label": "Execution setup", children: [_jsxs("label", { children: ["Run only", _jsxs("select", { disabled: inputsLocked || preparing, value: selectedRoot, onChange: event => selectRoot(event.target.value), children: [_jsx("option", { value: "", children: "Entire project" }), preparedDocument && contextDisplaySteps(preparedDocument.context, new Set(), preparedDocument).filter(n => n.kind !== 'body' && n.kind !== 'branch').map(n => _jsxs("option", { value: n.id, children: [' '.repeat(n.depth), n.name] }, n.id))] })] }), _jsxs("label", { children: ["Timeout", _jsxs("select", { disabled: inputsLocked, value: timeoutMs, onChange: event => setTimeoutMs(event.target.value), children: [_jsx("option", { value: "none", children: "None" }), _jsx("option", { value: "1000", children: "1 second" }), _jsx("option", { value: "3000", children: "3 seconds" }), _jsx("option", { value: "10000", children: "10 seconds" })] })] })] }), _jsxs("div", { className: "run-actions", role: "group", "aria-label": "Execution actions", children: [_jsx("button", { className: "button", disabled: inputsLocked, onClick: () => { if (!activeInputRequest.current)
|
|
647
|
+
setEditingInputs(value => !value); }, children: editingInputs ? 'Done inputs' : 'Edit inputs' }), _jsx("button", { className: "button primary", onClick: () => void run(), disabled: !!inputBlocker || preparing || !!preparationError || runState === 'preflighting' || runState === 'running', children: "\u25B6\u00A0 Run" }), _jsx("button", { className: "button dry-run", onClick: () => void run(true), disabled: !!inputBlocker || preparing || !!preparationError || runState === "preflighting" || runState === "running", children: "\u25CE\u00A0 Pre-run validation" }), _jsx("button", { className: "button stop", onClick: () => void stop(), disabled: runState !== 'preflighting' && runState !== 'running', children: "\u25A0\u00A0 Stop" }), _jsx("button", { className: "button", onClick: () => void pause(), disabled: controlState !== 'running', children: "\u2161\u00A0 Pause" }), _jsx("button", { className: `button ${controlState === 'paused' ? 'resume-highlight' : ''}`, onClick: () => void resume(), disabled: controlState !== 'paused', children: "\u25B6\u00A0 Resume" }), _jsx("button", { className: "button", onClick: () => void stepExecution(), disabled: controlState !== 'paused', children: "\u21A6\u00A0 Step" }), breakpoints.size > 0 && _jsxs("span", { className: "debug-session-badge", children: [breakpoints.size, " breakpoint", breakpoints.size === 1 ? "" : "s", " armed"] })] })] }), preparing && _jsx("p", { role: "status", children: "Preparing Project\u2026" }), preparationError && _jsx("p", { role: "alert", children: redactText(preparationError, invocationSecrets) }), preparedDocument && !preparedDocument.selection.executable && _jsx("section", { role: "alert", children: preparedDocument.selection.issues.map((i, index) => _jsxs("p", { children: [preparedDocument.context.nodes.find(n => n.key === i.at)?.name, ": ", i.message] }, index)) }), conflict && _jsxs("section", { role: "alert", children: [_jsx("p", { children: conflict.message }), _jsx("ul", { children: conflict.entries.map((entry, index) => _jsxs("li", { children: [entry.owner, " \u00B7 ", entry.declaration.name, " \u00B7 ", entry.declaration.type, " \u00B7 ", entry.declaration.required ? 'required' : 'optional', " \u00B7 default: ", Object.hasOwn(entry.declaration, 'defaultValue') ? JSON.stringify(redactValue(entry.declaration.defaultValue, invocationSecrets, entry.declaration.name)) : 'none'] }, index)) }), _jsx("p", { children: "Retained input drafts:" }), _jsx("ul", { children: Object.entries(inputEdits).map(([name, draft]) => _jsxs("li", { children: [name, " \u00B7 ", draft.supplied ? 'supplied' : 'omitted'] }, name)) })] }), unresolved && _jsxs("section", { role: "alert", children: [_jsx("p", { children: unresolved.message }), _jsx("ul", { children: unresolved.entries.map((entry, index) => _jsxs("li", { children: [entry.owner, " \u00B7 ", entry.name, " \u00B7 required \u00B7 type unresolved"] }, index)) }), _jsx("p", { children: "Retained input drafts:" }), _jsx("ul", { children: Object.entries(inputEdits).map(([name, draft]) => _jsxs("li", { children: [name, " \u00B7 ", draft.supplied ? 'supplied' : 'omitted'] }, name)) })] }), inputError && _jsx("p", { role: "alert", children: redactText(inputError, invocationSecrets) }), loadError && _jsx("p", { className: "load-error", children: redactText(loadError, invocationSecrets) }), loadIssues.length > 0 && _jsx(PreRunValidation, { issues: loadIssues.map(issue => ({ ...issue, message: redactText(issue.message, invocationSecrets) })), title: "Artifact validation" }), result?.issues !== undefined && _jsx(PreRunValidation, { issues: result.issues }), result?.warnings !== undefined && result.warnings.length > 0 && _jsx(PreRunValidation, { issues: result.warnings, title: "Browser execution warnings" }), editingInputs && _jsxs("section", { className: "inputs-panel panel", children: [_jsxs("div", { className: "panel-heading", children: [_jsx("h2", { children: "Invocation Inputs" }), _jsx("span", { className: "panel-spacer" }), _jsx("span", { className: "input-hint", children: inputsLocked ? 'Inputs are locked while execution is active.' : 'Values are sent with the next run' })] }), _jsxs("fieldset", { className: "input-grid input-lock-fields", "aria-label": "Invocation input values", disabled: inputsLocked, children: [inputBlocker ? _jsx("p", { children: "Invocation input editing is unavailable until requirements are resolved." }) : declarations.map(declaration => { const draft = inputEdits[declaration.name] ?? { supplied: false, text: '' }; const change = (text) => { if (!activeInputRequest.current)
|
|
642
648
|
setInputEdits(previous => ({ ...previous, [declaration.name]: { supplied: true, text } })); }; return _jsxs("div", { children: [_jsxs("label", { children: [_jsx("input", { type: "checkbox", "aria-label": `Supply ${declaration.name}`, checked: draft.supplied, onChange: event => { if (!activeInputRequest.current)
|
|
643
649
|
setInputEdits(previous => ({ ...previous, [declaration.name]: { ...draft, supplied: event.target.checked } })); } }), "Supply ", declaration.name] }), declaration.type === 'boolean' ? _jsxs("label", { className: "input-field", children: [declaration.name, _jsxs("select", { value: draft.text, onChange: event => change(event.target.value), children: [_jsx("option", { value: "false", children: "false" }), _jsx("option", { value: "true", children: "true" })] })] }) : _jsx(InputField, { label: declaration.name, value: draft.text, onChange: change }), _jsxs("small", { children: [declaration.type, " \u00B7 ", draft.supplied ? 'supplied' : Object.hasOwn(declaration, 'defaultValue') ? 'omitted — declared default applies' : 'omitted', declaration.required ? ' · required' : ''] })] }, declaration.name); }), (executionPackage.runtimeRequirements ?? []).map(name => _jsx(InputField, { label: `Runtime · ${name}`, value: runtimeValues[name] ?? '', onChange: value => { if (!activeInputRequest.current)
|
|
644
650
|
setRuntimeValues(previous => ({ ...previous, [name]: value })); } }, name))] })] })] }), readOnly && historicalEntry && _jsxs("div", { className: "history-view-banner", children: ["Viewing stored results: ", historyRecordName(historicalEntry), " \u00B7 ", historyOutcome(historicalEntry), " \u00B7 ", historicalEntry.startedAt ? new Date(historicalEntry.startedAt).toLocaleString() : 'Start time not recorded'] }), _jsxs("section", { className: "panel", hidden: readOnly && !historicalEntry, children: [_jsxs("div", { className: "panel-heading", children: [_jsx("h2", { children: readOnly ? 'Recorded execution' : 'Live Execution' }), _jsx("span", { className: "panel-spacer" }), _jsxs("span", { className: "execution-menu-label", hidden: readOnly, children: ["Right-click a row to manage its breakpoint \u00B7 Selected: ", displaySteps[shownSelectedStep]?.name ?? 'None'] }), _jsxs("span", { className: shownRunState === 'running' ? 'running' : shownRunState === 'failed' ? 'stopped' : 'run-status', children: ["\u25CF ", statusLabel] })] }), hasNestedSteps && _jsxs("div", { className: "hierarchy-hint", children: [_jsx("strong", { children: "Nested execution" }), _jsx("span", { children: "Use \u2212 / + to collapse or expand nested Operations, Control Blocks, and loops." }), _jsx("button", { className: "hierarchy-action", onClick: () => setAllCollapsed(true), children: "Collapse all" }), _jsx("button", { className: "hierarchy-action", onClick: () => setAllCollapsed(false), children: "Expand all" })] }), _jsx("div", { className: "table-scroll", role: "region", "aria-label": "Execution steps", tabIndex: 0, children: _jsxs("table", { children: [_jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { children: "#" }), _jsx("th", { children: "Step hierarchy" }), _jsx("th", { children: "Status" }), _jsx("th", { children: "Start time" }), _jsx("th", { children: "Duration" })] }) }), _jsx("tbody", { children: displaySteps.map((step, index) => { const isLoop = step.loopRepeat; const loopContexts = isLoop ? loopPresentation(step.structuralAddress, step.loopTotal, step.loopDuration, shownResult ? allResults : eventPresentationEvidence(executionEvents, shownRequestId), Boolean(shownResult), step.occurrence) : []; const rowEvidence = shownResult ? allResults : eventPresentationEvidence(executionEvents, shownRequestId); const repeatedMatches = rowEvidence.filter(r => step.occurrence ? r.occurrence === step.occurrence : occurrenceKey(r.structuralAddress) === occurrenceKey(step.structuralAddress)); const latestQualifier = step.branchRow ? rowEvidence.filter(r => occurrenceKey(r.structuralAddress) === occurrenceKey(step.branchOwner)).length > 1 : repeatedMatches.length > 1; const scope = readOnly ? historicalEntry?.structure?.scope : preparedDocument?.selection.root; const context = readOnly ? historicalEntry?.structure?.context : preparedDocument?.context; const outside = Boolean(step.occurrence && scope && context && !scopeIncludes(context, scope, step.occurrence)); const presentation = rowPresentation(step, rowEvidence, Boolean(shownResult), step.branchRow ? 'pending' : readOnly ? 'pending' : stepStates[index] ?? 'pending', { context, scope, result: shownResult }); const rowStart = selectedStepStartedAt(step, { results: allResults, result: shownResult, context, scope, events: executionEvents, requestId: shownRequestId }); const displayState = presentation.state; const isLoopContent = Boolean(step.loopId); const isLoopEnd = isLoopContent && displaySteps[index + 1]?.loopId !== step.loopId; return _jsxs("tr", { className: `${outside ? 'outside-scope ' : ''}${shownSelectedStep === index ? 'selected ' : ''}${isLoop ? 'loop-row ' : ''}${isLoopContent ? 'loop-content ' : ''}${isLoopEnd ? 'loop-end ' : ''}${step.depth > 0 ? 'nested-row' : 'parent-row'}`, tabIndex: 0, onKeyDown: event => { if (event.key === "ArrowDown") {
|
|
@@ -648,7 +654,7 @@ function RunnerApp({ client, onExit, applicationMenu }) {
|
|
|
648
654
|
event.preventDefault();
|
|
649
655
|
selectDisplayedStep(Math.max(0, index - 1));
|
|
650
656
|
} }, onClick: () => selectDisplayedStep(index), onContextMenu: event => { event.preventDefault(); if (readOnly)
|
|
651
|
-
return; selectDisplayedStep(index); setContextMenu({ x: event.clientX, y: event.clientY, stepId: step.id }); }, children: [_jsx("td", { children: index + 1 }), _jsxs("td", { className: "hierarchy-cell", children: [_jsx(HierarchyGuides, { segments: guides.get(step.id) ?? [] }), _jsxs("span", { className: "hierarchy-name", style: { paddingLeft: `${step.depth * 18}px` }, children: [step.hasChildren && _jsx("button", { className: "collapse-toggle", "aria-label": `${(readOnly ? historyCollapsedSteps : collapsedSteps).has(step.id) ? 'Expand' : 'Collapse'} ${step.name}`, onClick: event => { event.stopPropagation(); toggleStep(step.id); }, children: (readOnly ? historyCollapsedSteps : collapsedSteps).has(step.id) ? '+' : '−' }), !step.hasChildren && _jsx("span", { className: "collapse-spacer", "aria-hidden": "true" }), _jsx(StructuralIcon, { kind: step.structuralKind }), !readOnly && breakpoints.has(step.id) && _jsx("span", { className: "breakpoint-marker", role: "img", "aria-label": "Breakpoint armed", title: "Breakpoint armed" }), _jsx("span", { children: step.name }), isLoop && _jsx("small", { className: "kind-label loop-label", children: "\u21BB LOOP" }), step.structuralKind === 'branch' && _jsx("small", { className: "kind-label", children: "BRANCH" }), (!step.structuralKind || step.structuralKind === 'unknown') && _jsx("small", { className: "kind-label", children: "TYPE NOT RECORDED" })] }), shownSelectedStep === index && _jsx("small", { className: "selected-label", children: "SELECTED" })] }), _jsxs("td", { children: [!outside && loopContexts.map(context => _jsxs("div", { className: "loop-progress", children: [context.context.length > 0 && _jsxs("small", { children: ["Enclosing iterations: ", context.context.map(s => s.iteration).join(' / ')] }), _jsx("strong", { children: context.label })] }, JSON.stringify(context.context))), _jsxs("span", { className: "execution-status", children: [_jsx("span", { className: `step-icon execution-status-icon ${displayState.replaceAll(' ', '-')}`, "aria-hidden": "true", children: statusGlyph[displayState] }), _jsx("span", { className: `status ${displayState.replaceAll(' ', '-')}`, children: presentation.label })] }), latestQualifier && _jsx("small", { className: "latest-invocation", children: "Latest invocation" })] }), _jsx("td", { children: rowStart ? new Date(rowStart).toLocaleTimeString() : '—' }), _jsx("td", { children: displayResults[index] ? `${displayResults[index].durationMs} ms` : '—' })] }, `${step.id}-${index}`); }) })] }) }), !readOnly && contextMenu && _jsxs("div", { className: "runner-context-menu", style: { left: contextMenu.x, top: contextMenu.y }, onClick: event => event.stopPropagation(), onContextMenu: event => event.preventDefault(), children: [_jsx("strong", { children: "Breakpoint" }), breakpoints.has(contextMenu.stepId) ? _jsx("button", { onClick: () => { toggleBreakpoint(contextMenu.stepId); setContextMenu(undefined); }, children: "Remove breakpoint" }) : _jsx("button", { onClick: () => { toggleBreakpoint(contextMenu.stepId); setContextMenu(undefined); }, children: "Add breakpoint" })] })] }), !readOnly && _jsxs("details", { className: "panel runner-event-log execution-event-log", children: [_jsx("summary", { children: "Event Log" }), _jsxs("div", { className: "event-log-content", children: [_jsxs("div", { className: "event-log-tools", children: [_jsx("input", { className: "event-search", "aria-label": "Search event log", placeholder: "Search events", value: eventSearch, onChange: event => setEventSearch(event.target.value) }), _jsxs("select", { "aria-label": "Filter execution events", className: "event-filter", value: eventFilter, onChange: event => setEventFilter(event.target.value), children: [_jsx("option", { value: "all", children: "All events" }), _jsx("option", { value: "steps", children: "Step events" }), _jsx("option", { value: "parallel", children: "Parallel groups" }), _jsx("option", { value: "lifecycle", children: "Lifecycle" }), _jsx("option", { value: "failures", children: "Failures" })] })] }), _jsx("div", { className: "event-log-scroll", role: "region", "aria-label": "Execution events", tabIndex: 0, children: _jsx(ExecutionEventRows, { events: visibleEvents }) }), executionEvents.length > 0 && visibleEvents.length === 0 && _jsx("p", { className: "empty-state", children: "No events match the current filter." }), executionEvents.length === 0 && _jsx("p", { className: "empty-state", children: "No execution events yet." })] })] }, JSON.stringify(['execution', requestId ?? 'ready', selectedTargetId]))] }), _jsx("div", { className: "inspector-divider", role: "separator", "aria-label": "Resize Inspector", "aria-orientation": "vertical", "aria-controls": "runner-inspector", "aria-valuemin": INSPECTOR_MIN_WIDTH, "aria-valuemax": INSPECTOR_MAX_WIDTH, "aria-valuenow": inspectorWidth, "aria-valuetext": `${inspectorWidth} pixels`, tabIndex: 0, hidden: readOnly && !historicalEntry, onPointerDown: startInspectorResize, onPointerMove: moveInspectorResize, onPointerUp: finishInspectorResize, onPointerCancel: finishInspectorResize, onLostPointerCapture: finishInspectorResize, onKeyDown: inspectorResizeKey }), _jsxs("aside", { id: "runner-inspector", className: "inspector", hidden: readOnly && !historicalEntry, children: [_jsx("h2", { children: "SELECTED STEP" }), _jsx("p", { className: "selected-detail-name", children: _jsx("strong", { children: displaySteps[shownSelectedStep] ? `${shownSelectedStep + 1}. ${displaySteps[shownSelectedStep].name}` : 'No step selected' }) }), _jsx("p", { className: "selected-step-start", children: selectedStart ? `Started: ${new Date(selectedStart).toLocaleTimeString()}` : 'Not started' }), _jsx(InspectorSection, { title: "Artifact summary", children: _jsx(KeyValues, { values: ["Target", (readOnly ? historicalEntry?.result?.target.name ?? historicalEntry?.target : contextTarget.name) ?? 'Unknown', "Type", (readOnly ? historicalEntry?.result?.target.kind : contextTarget.kind) ?? 'Unknown', "Project reference", (readOnly ? historicalEntry?.packageId : selectedTargetId) ?? 'Not recorded', "Execution format", `Execution v${readOnly ? historicalEntry?.executionSchemaVersion ?? 'unknown' : authoringSource ? 8 : executionPackage.schemaVersion}`, "Definitions", shownPackage ? String(shownPackage.definitions.length) : 'Not recorded', "Required inputs", shownPackage ? shownPackage.requiredInputs?.join(', ') || 'None' : !readOnly && preparedDocument ? preparedDocument.selection.requiredInputs?.join(', ') || 'None' : 'Not recorded', "Runtime values", shownPackage ? shownPackage.runtimeRequirements?.join(', ') || 'None' : !readOnly && preparedDocument ? preparedDocument.selection.runtimeRequirements?.join(', ') || 'None' : 'Not recorded'] }) }), _jsx(InspectorSection, { title: "Run outcome", children: _jsxs("div", { className: "notice", children: [_jsx("strong", { children: shownResult?.state.toUpperCase() ?? (readOnly && historicalEntry?.admittedAt ? historyOutcome(historicalEntry) : 'NOT STARTED') }), _jsx("br", {}), shownResult ? shownResult.state : readOnly && historicalEntry?.admittedAt ? `Last recorded state: ${historicalEntry.lastObservedState ?? 'Admission recorded'}. No terminal result is available.` : 'Run the Project to inspect its terminal outcome.'] }) }), _jsx(InspectorSection, { title: "Selected step inputs", children: _jsx(KeyValues, { values: Object.entries(displayResults[shownSelectedStep]?.inputs ?? (selectedInvocations.length > 1 ? {} : readOnly ? {} : inputs)).flatMap(([key, value]) => [key, String(value)]) }) }), _jsx(InspectorSection, { title: "Selected step outputs", children: _jsx(KeyValues, { values: displayResults[shownSelectedStep]?.outputs ? Object.entries(displayResults[shownSelectedStep]?.outputs ?? {}).flatMap(([key, value]) => [key, String(value)]) : ['—', selectedInvocations.length > 1 ? `${selectedInvocations.length} recorded invocations; see iteration history` : 'Available after execution'] }) }), (shownResult?.error || displayResults[shownSelectedStep]?.error) && _jsx(InspectorSection, { title: "Error", children: _jsxs("div", { className: "error-notice", children: [errorCode && _jsxs(_Fragment, { children: [_jsx("strong", { children: errorCode }), _jsx("br", {})] }), errorMessage, hasErrorDetails && _jsx("pre", { children: JSON.stringify(errorDetails, null, 2) }), !errorCode && !errorMessage && !hasErrorDetails && 'Error details were not recorded.'] }) }), shownResult?.issues !== undefined && _jsx(InspectorSection, { title: "Pre-run validation", children: _jsx(PreRunValidation, { issues: shownResult.issues }) }), _jsx(InspectorSection, { title: "Invocation path", children: selectedPaths.length ? selectedPaths.map(path => _jsxs("div", { className: "notice", children: [selectedInvocations.length > 1 && _jsx("small", { children: "Latest recorded invocation" }), path.names.map((name, index) => _jsx("div", { children: name }, index))] }, path.key)) : _jsx("div", { className: "notice", children: "No invocation path available." }) }), _jsx(InspectorSection, { title: "Iteration history", children: _jsx(RecordedInvocations, { results: selectedInvocations, definition: findInspectionDefinition(shownPackageSteps, displaySteps[shownSelectedStep]?.structuralAddress) }, JSON.stringify([shownRequestId, displaySteps[shownSelectedStep]?.structuralAddress])) }), _jsx(InspectorSection, { title: "Execution timing", children: _jsxs("div", { className: "timing-details", children: [_jsxs("span", { children: ["Wall ", shownResult?.executionTiming?.wallDurationMs ?? "—", " ms"] }), _jsxs("span", { children: ["Active ", shownResult?.executionTiming?.activeDurationMs ?? "—", " ms"] }), _jsxs("span", { children: ["Paused ", shownResult?.executionTiming?.pausedDurationMs ?? "—", " ms"] })] }) }), _jsx(InspectorSection, { title: "Selected step attempts", children: _jsx("div", { className: "attempt-history", children: displayResults[shownSelectedStep]?.attempts?.map(attempt => _jsxs("div", { className: "iteration-entry", children: [_jsxs("strong", { children: ["Attempt ", attempt.attempt] }), _jsxs("span", { children: [(attempt.kind ?? 'automatic').toUpperCase(), " \u00B7 ", attempt.state.toUpperCase(), " \u00B7 ", attempt.durationMs, " ms"] })] }, `${attempt.attempt}-${attempt.kind}`)) ?? _jsx("div", { className: "notice", children: "No retry attempts recorded." }) }) }), readOnly && _jsxs("details", { className: "inspector-section inspector-event-log runner-event-log", children: [_jsx("summary", { children: "Event Log" }), _jsxs("div", { className: "event-log-content", children: [_jsx("p", { className: "empty-state", children: historicalEntry?.events === undefined ? 'Events were not recorded for this run.' : historicalEntry.eventCollectionIncomplete ? 'Event collection was incomplete. Only captured events are shown.' : executionEvents.length === 0 ? 'No execution events were recorded.' : '' }), _jsx("div", { className: "event-log-scroll", role: "region", "aria-label": "Recorded execution events", tabIndex: 0, children: _jsx(ExecutionEventRows, { events: executionEvents }) })] })] }, JSON.stringify(['history', shownRequestId ?? 'ready', historicalEntry?.packageId])), _jsxs(InspectorSection, { title: "Selected step", children: [_jsxs("div", { className: "notice", children: [_jsx("strong", { children: displaySteps[shownSelectedStep]?.name ?? 'No step selected' }), _jsx("br", {}), displayResults[shownSelectedStep] ? displayResults[shownSelectedStep].error ? 'This step failed. See the error details above.' : `Completed in ${displayResults[shownSelectedStep].durationMs} ms.` : selectedInvocations.length > 1 ? `${selectedInvocations.length} invocations recorded. No single invocation selected.` : 'Run the Project to inspect execution details.', _jsxs("div", { className: "inspector-actions", children: [_jsx("button", { className: "button", onClick: () => void retrySelected(), disabled: readOnly || !!preparedDocument || !displayResults[shownSelectedStep] || (!displayResults[shownSelectedStep]?.error && runState !== "completed"), children: "Retry Action" }), _jsx("button", { className: `button ${stopAfterStepId === displaySteps[shownSelectedStep]?.id ? "active" : ""}`, onClick: () => displaySteps[shownSelectedStep] && toggleStopAfter(displaySteps[shownSelectedStep].id), disabled: readOnly || !displaySteps[shownSelectedStep], children: "Stop After" }), _jsx("button", { className: "button", onClick: () => void runFromSelected(), disabled: readOnly || !!preparedDocument || !displayResults[shownSelectedStep] || runState === "running", children: "Run From Here" })] })] }), _jsxs("div", { className: "selection-nav", children: [_jsx("button", { className: "button", disabled: shownSelectedStep <= 0, onClick: () => selectDisplayedStep(index => Math.max(0, index - 1)), children: "\u2039 Previous" }), _jsx("span", { children: displaySteps.length ? `${shownSelectedStep + 1} / ${displaySteps.length}` : '0 / 0' }), _jsx("button", { className: "button", disabled: shownSelectedStep >= displaySteps.length - 1, onClick: () => selectDisplayedStep(index => Math.min(displaySteps.length - 1, index + 1)), children: "Next \u203A" })] })] })] })] }), " "] }) }), showAbout && _jsx("div", { className: "about-backdrop", onClick: () => setShowAbout(false), children: _jsxs("section", { className: "about-dialog", role: "dialog", "aria-modal": "true", "aria-labelledby": "about-title", onClick: event => event.stopPropagation(), children: [_jsx("button", { className: "about-close", onClick: () => setShowAbout(false), "aria-label": "Close About", children: "\u00D7" }), _jsx("div", { className: "runner-logo", children: "\u25B6" }), _jsx("h2", { id: "about-title", children: "QAick Runner" }), _jsx("p", { children: "Standalone execution and evidence viewer for QAICK Projects." }), _jsxs("small", { children: [RUNNER_UI_VERSION, " \u00B7 ", RUNNER_BUILD_LABEL, " \u00B7 QAick contract"] }), _jsx("footer", { children: "\u00A9 2006\u20132026 QAick. All rights reserved." })] }) })] });
|
|
657
|
+
return; selectDisplayedStep(index); setContextMenu({ x: event.clientX, y: event.clientY, stepId: step.id }); }, children: [_jsx("td", { children: index + 1 }), _jsxs("td", { className: "hierarchy-cell", children: [_jsx(HierarchyGuides, { segments: guides.get(step.id) ?? [] }), _jsxs("span", { className: "hierarchy-name", style: { paddingLeft: `${step.depth * 18}px` }, children: [step.hasChildren && _jsx("button", { className: "collapse-toggle", "aria-label": `${(readOnly ? historyCollapsedSteps : collapsedSteps).has(step.id) ? 'Expand' : 'Collapse'} ${step.name}`, onClick: event => { event.stopPropagation(); toggleStep(step.id); }, children: (readOnly ? historyCollapsedSteps : collapsedSteps).has(step.id) ? '+' : '−' }), !step.hasChildren && _jsx("span", { className: "collapse-spacer", "aria-hidden": "true" }), _jsx(StructuralIcon, { kind: step.structuralKind }), !readOnly && breakpoints.has(step.id) && _jsx("span", { className: "breakpoint-marker", role: "img", "aria-label": "Breakpoint armed", title: "Breakpoint armed" }), _jsx("span", { children: step.name }), isLoop && _jsx("small", { className: "kind-label loop-label", children: "\u21BB LOOP" }), step.structuralKind === 'branch' && _jsx("small", { className: "kind-label", children: "BRANCH" }), (!step.structuralKind || step.structuralKind === 'unknown') && _jsx("small", { className: "kind-label", children: "TYPE NOT RECORDED" })] }), shownSelectedStep === index && _jsx("small", { className: "selected-label", children: "SELECTED" })] }), _jsxs("td", { children: [!outside && loopContexts.map(context => _jsxs("div", { className: "loop-progress", children: [context.context.length > 0 && _jsxs("small", { children: ["Enclosing iterations: ", context.context.map(s => s.iteration).join(' / ')] }), _jsx("strong", { children: context.label })] }, JSON.stringify(context.context))), _jsxs("span", { className: "execution-status", children: [_jsx("span", { className: `step-icon execution-status-icon ${displayState.replaceAll(' ', '-')}`, "aria-hidden": "true", children: statusGlyph[displayState] }), _jsx("span", { className: `status ${displayState.replaceAll(' ', '-')}`, children: presentation.label })] }), latestQualifier && _jsx("small", { className: "latest-invocation", children: "Latest invocation" })] }), _jsx("td", { children: rowStart ? new Date(rowStart).toLocaleTimeString() : '—' }), _jsx("td", { children: displayResults[index] ? `${displayResults[index].durationMs} ms` : '—' })] }, `${step.id}-${index}`); }) })] }) }), !readOnly && contextMenu && _jsxs("div", { className: "runner-context-menu", style: { left: contextMenu.x, top: contextMenu.y }, onClick: event => event.stopPropagation(), onContextMenu: event => event.preventDefault(), children: [_jsx("strong", { children: "Breakpoint" }), breakpoints.has(contextMenu.stepId) ? _jsx("button", { onClick: () => { toggleBreakpoint(contextMenu.stepId); setContextMenu(undefined); }, children: "Remove breakpoint" }) : _jsx("button", { onClick: () => { toggleBreakpoint(contextMenu.stepId); setContextMenu(undefined); }, children: "Add breakpoint" })] })] }), !readOnly && _jsxs("details", { className: "panel runner-event-log execution-event-log", children: [_jsx("summary", { children: "Event Log" }), _jsxs("div", { className: "event-log-content", children: [_jsxs("div", { className: "event-log-tools", children: [_jsx("input", { className: "event-search", "aria-label": "Search event log", placeholder: "Search events", value: eventSearch, onChange: event => setEventSearch(event.target.value) }), _jsxs("select", { "aria-label": "Filter execution events", className: "event-filter", value: eventFilter, onChange: event => setEventFilter(event.target.value), children: [_jsx("option", { value: "all", children: "All events" }), _jsx("option", { value: "steps", children: "Step events" }), _jsx("option", { value: "parallel", children: "Parallel groups" }), _jsx("option", { value: "lifecycle", children: "Lifecycle" }), _jsx("option", { value: "failures", children: "Failures" })] })] }), _jsx("div", { className: "event-log-scroll", role: "region", "aria-label": "Execution events", tabIndex: 0, children: _jsx(ExecutionEventRows, { events: visibleEvents }) }), executionEvents.length > 0 && visibleEvents.length === 0 && _jsx("p", { className: "empty-state", children: "No events match the current filter." }), executionEvents.length === 0 && _jsx("p", { className: "empty-state", children: "No execution events yet." })] })] }, JSON.stringify(['execution', requestId ?? 'ready', selectedTargetId]))] }), _jsx("div", { className: "inspector-divider", role: "separator", "aria-label": "Resize Inspector", "aria-orientation": "vertical", "aria-controls": "runner-inspector", "aria-valuemin": INSPECTOR_MIN_WIDTH, "aria-valuemax": INSPECTOR_MAX_WIDTH, "aria-valuenow": inspectorWidth, "aria-valuetext": `${inspectorWidth} pixels`, tabIndex: 0, hidden: readOnly && !historicalEntry, onPointerDown: startInspectorResize, onPointerMove: moveInspectorResize, onPointerUp: finishInspectorResize, onPointerCancel: finishInspectorResize, onLostPointerCapture: finishInspectorResize, onKeyDown: inspectorResizeKey }), _jsxs("aside", { id: "runner-inspector", className: "inspector", hidden: readOnly && !historicalEntry, children: [_jsx("h2", { children: "SELECTED STEP" }), _jsx("p", { className: "selected-detail-name", children: _jsx("strong", { children: displaySteps[shownSelectedStep] ? `${shownSelectedStep + 1}. ${displaySteps[shownSelectedStep].name}` : 'No step selected' }) }), _jsx("p", { className: "selected-step-start", children: selectedStart ? `Started: ${new Date(selectedStart).toLocaleTimeString()}` : 'Not started' }), _jsx(InspectorSection, { title: "Artifact summary", children: _jsx(KeyValues, { secretValues: shownSecrets, values: ["Target", (readOnly ? historicalEntry?.result?.target.name ?? historicalEntry?.target : contextTarget.name) ?? 'Unknown', "Type", (readOnly ? historicalEntry?.result?.target.kind : contextTarget.kind) ?? 'Unknown', "Project reference", (readOnly ? historicalEntry?.packageId : selectedTargetId) ?? 'Not recorded', "Execution format", `Execution v${readOnly ? historicalEntry?.executionSchemaVersion ?? 'unknown' : authoringSource ? 8 : executionPackage.schemaVersion}`, "Definitions", shownPackage ? String(shownPackage.definitions.length) : 'Not recorded', "Required inputs", shownPackage ? shownPackage.requiredInputs?.join(', ') || 'None' : !readOnly && preparedDocument ? preparedDocument.selection.requiredInputs?.join(', ') || 'None' : 'Not recorded', "Runtime values", shownPackage ? shownPackage.runtimeRequirements?.join(', ') || 'None' : !readOnly && preparedDocument ? preparedDocument.selection.runtimeRequirements?.join(', ') || 'None' : 'Not recorded'] }) }), _jsx(InspectorSection, { title: "Run outcome", children: _jsxs("div", { className: "notice", children: [_jsx("strong", { children: shownResult?.state.toUpperCase() ?? (readOnly && historicalEntry?.admittedAt ? historyOutcome(historicalEntry) : 'NOT STARTED') }), _jsx("br", {}), shownResult ? shownResult.state : readOnly && historicalEntry?.admittedAt ? `Last recorded state: ${historicalEntry.lastObservedState ?? 'Admission recorded'}. No terminal result is available.` : 'Run the Project to inspect its terminal outcome.'] }) }), _jsx(InspectorSection, { title: "Selected step inputs", children: _jsx(KeyValues, { secretValues: shownSecrets, values: Object.entries(displayResults[shownSelectedStep]?.inputs ?? (selectedInvocations.length > 1 ? {} : readOnly ? {} : inputs)).flatMap(([key, value]) => [key, String(value)]) }) }), _jsx(InspectorSection, { title: "Selected step outputs", children: _jsx(KeyValues, { secretValues: shownSecrets, values: displayResults[shownSelectedStep]?.outputs ? Object.entries(displayResults[shownSelectedStep]?.outputs ?? {}).flatMap(([key, value]) => [key, String(value)]) : ['—', selectedInvocations.length > 1 ? `${selectedInvocations.length} recorded invocations; see iteration history` : 'Available after execution'] }) }), (shownResult?.error || displayResults[shownSelectedStep]?.error) && _jsx(InspectorSection, { title: "Error", children: _jsxs("div", { className: "error-notice", children: [errorCode && _jsxs(_Fragment, { children: [_jsx("strong", { children: errorCode }), _jsx("br", {})] }), errorMessage, hasErrorDetails && _jsx("pre", { children: JSON.stringify(errorDetails, null, 2) }), !errorCode && !errorMessage && !hasErrorDetails && 'Error details were not recorded.'] }) }), shownResult?.issues !== undefined && _jsx(InspectorSection, { title: "Pre-run validation", children: _jsx(PreRunValidation, { issues: shownResult.issues }) }), _jsx(InspectorSection, { title: "Invocation path", children: selectedPaths.length ? selectedPaths.map(path => _jsxs("div", { className: "notice", children: [selectedInvocations.length > 1 && _jsx("small", { children: "Latest recorded invocation" }), path.names.map((name, index) => _jsx("div", { children: name }, index))] }, path.key)) : _jsx("div", { className: "notice", children: "No invocation path available." }) }), _jsx(InspectorSection, { title: "Iteration history", children: _jsx(RecordedInvocations, { results: selectedInvocations, definition: findInspectionDefinition(shownPackageSteps, displaySteps[shownSelectedStep]?.structuralAddress) }, JSON.stringify([shownRequestId, displaySteps[shownSelectedStep]?.structuralAddress])) }), _jsx(InspectorSection, { title: "Execution timing", children: _jsxs("div", { className: "timing-details", children: [_jsxs("span", { children: ["Wall ", shownResult?.executionTiming?.wallDurationMs ?? "—", " ms"] }), _jsxs("span", { children: ["Active ", shownResult?.executionTiming?.activeDurationMs ?? "—", " ms"] }), _jsxs("span", { children: ["Paused ", shownResult?.executionTiming?.pausedDurationMs ?? "—", " ms"] })] }) }), _jsx(InspectorSection, { title: "Selected step attempts", children: _jsx("div", { className: "attempt-history", children: displayResults[shownSelectedStep]?.attempts?.map(attempt => _jsxs("div", { className: "iteration-entry", children: [_jsxs("strong", { children: ["Attempt ", attempt.attempt] }), _jsxs("span", { children: [(attempt.kind ?? 'automatic').toUpperCase(), " \u00B7 ", attempt.state.toUpperCase(), " \u00B7 ", attempt.durationMs, " ms"] })] }, `${attempt.attempt}-${attempt.kind}`)) ?? _jsx("div", { className: "notice", children: "No retry attempts recorded." }) }) }), readOnly && _jsxs("details", { className: "inspector-section inspector-event-log runner-event-log", children: [_jsx("summary", { children: "Event Log" }), _jsxs("div", { className: "event-log-content", children: [_jsx("p", { className: "empty-state", children: historicalEntry?.events === undefined ? 'Events were not recorded for this run.' : historicalEntry.eventCollectionIncomplete ? 'Event collection was incomplete. Only captured events are shown.' : executionEvents.length === 0 ? 'No execution events were recorded.' : '' }), _jsx("div", { className: "event-log-scroll", role: "region", "aria-label": "Recorded execution events", tabIndex: 0, children: _jsx(ExecutionEventRows, { events: executionEvents }) })] })] }, JSON.stringify(['history', shownRequestId ?? 'ready', historicalEntry?.packageId])), _jsxs(InspectorSection, { title: "Selected step", children: [_jsxs("div", { className: "notice", children: [_jsx("strong", { children: displaySteps[shownSelectedStep]?.name ?? 'No step selected' }), _jsx("br", {}), displayResults[shownSelectedStep] ? displayResults[shownSelectedStep].error ? 'This step failed. See the error details above.' : `Completed in ${displayResults[shownSelectedStep].durationMs} ms.` : selectedInvocations.length > 1 ? `${selectedInvocations.length} invocations recorded. No single invocation selected.` : 'Run the Project to inspect execution details.', _jsxs("div", { className: "inspector-actions", children: [_jsx("button", { className: "button", onClick: () => void retrySelected(), disabled: readOnly || !!preparedDocument || !displayResults[shownSelectedStep] || (!displayResults[shownSelectedStep]?.error && runState !== "completed"), children: "Retry Action" }), _jsx("button", { className: `button ${stopAfterStepId === displaySteps[shownSelectedStep]?.id ? "active" : ""}`, onClick: () => displaySteps[shownSelectedStep] && toggleStopAfter(displaySteps[shownSelectedStep].id), disabled: readOnly || !displaySteps[shownSelectedStep], children: "Stop After" }), _jsx("button", { className: "button", onClick: () => void runFromSelected(), disabled: readOnly || !!preparedDocument || !displayResults[shownSelectedStep] || runState === "running", children: "Run From Here" })] })] }), _jsxs("div", { className: "selection-nav", children: [_jsx("button", { className: "button", disabled: shownSelectedStep <= 0, onClick: () => selectDisplayedStep(index => Math.max(0, index - 1)), children: "\u2039 Previous" }), _jsx("span", { children: displaySteps.length ? `${shownSelectedStep + 1} / ${displaySteps.length}` : '0 / 0' }), _jsx("button", { className: "button", disabled: shownSelectedStep >= displaySteps.length - 1, onClick: () => selectDisplayedStep(index => Math.min(displaySteps.length - 1, index + 1)), children: "Next \u203A" })] })] })] })] }), " "] }) }), showAbout && _jsx("div", { className: "about-backdrop", onClick: () => setShowAbout(false), children: _jsxs("section", { className: "about-dialog", role: "dialog", "aria-modal": "true", "aria-labelledby": "about-title", onClick: event => event.stopPropagation(), children: [_jsx("button", { className: "about-close", onClick: () => setShowAbout(false), "aria-label": "Close About", children: "\u00D7" }), _jsx("div", { className: "runner-logo", children: "\u25B6" }), _jsx("h2", { id: "about-title", children: "QAick Runner" }), _jsx("p", { children: "Standalone execution and evidence viewer for QAICK Projects." }), _jsxs("small", { children: [RUNNER_UI_VERSION, " \u00B7 ", RUNNER_BUILD_LABEL, " \u00B7 QAick contract"] }), _jsx("footer", { children: "\u00A9 2006\u20132026 QAick. All rights reserved." })] }) })] });
|
|
652
658
|
}
|
|
653
659
|
function recordedDisplaySteps(results) {
|
|
654
660
|
const unique = new Map();
|
|
@@ -672,7 +678,7 @@ function HistoryPanel({ entries, retention, onRetentionChange, onClear, onDelete
|
|
|
672
678
|
}) })] }) }) : _jsx("p", { className: "empty-state", children: "Completed and failed runs will be kept here in this browser." })] });
|
|
673
679
|
}
|
|
674
680
|
function InspectorSection({ title, children }) { return _jsxs("section", { className: "inspector-section", children: [_jsx("h3", { children: title }), children] }); }
|
|
675
|
-
function KeyValues({ values }) { return _jsx("div", { className: "key-values", children: redactKeyValuePairs(values).map((value, index) => _jsx("span", { children: value }, `${value}-${index}`)) }); }
|
|
681
|
+
function KeyValues({ values, secretValues = [] }) { return _jsx("div", { className: "key-values", children: redactKeyValuePairs(values, secretValues).map((value, index) => _jsx("span", { children: value }, `${value}-${index}`)) }); }
|
|
676
682
|
function IterationHistory({ result }) { return _jsxs(_Fragment, { children: [_jsx("div", { className: "iteration-history", children: result?.children?.length ? result.children.map((iteration, index) => _jsxs("div", { className: "iteration-entry", children: [_jsx("strong", { children: iteration.name }), _jsxs("span", { children: [iteration.state.toUpperCase(), " \u00B7 ", iteration.durationMs, " ms"] }), _jsx("small", { children: iteration.children?.map(child => `${child.name}: ${Object.entries(child.outputs).map(([key, value]) => `${key}=${String(value)}`).join(', ') || 'no outputs'}`).join(' · ') || 'No nested output.' })] }, `${iteration.id}-${index}`)) : _jsx("div", { className: "notice", children: "No iteration history available." }) }), result?.terminalReason && _jsxs("div", { className: "timing-details", children: [_jsx("strong", { children: "Terminal reason" }), _jsx("span", { children: result.terminalReason })] }), _jsx(TransportTiming, { timing: result?.transportTiming }), _jsx(BranchExecutionPath, { result: result }), _jsx(ParallelGroupDetails, { result: result }), _jsx(ResultSummary, { result: result })] }); }
|
|
677
683
|
function TransportTiming({ timing }) { return _jsxs("div", { className: "timing-details", children: [_jsx("strong", { children: timing ? 'Request timing' : 'Contract version' }), timing ? _jsxs(_Fragment, { children: [_jsxs("span", { children: ["Started ", new Date(timing.requestStartedAt).toLocaleTimeString()] }), _jsxs("span", { children: ["Response ", new Date(timing.responseReceivedAt).toLocaleTimeString()] }), _jsxs("span", { children: ["Transport duration ", timing.durationMs, " ms"] })] }) : _jsxs("span", { children: ["@qaick/contract ", RUNNER_CONTRACT_VERSION] })] }); }
|
|
678
684
|
function BranchExecutionPath({ result }) { const branches = result?.children?.filter(child => child.kind === 'control-block' && child.children?.length); if (!branches?.length)
|
|
@@ -687,7 +693,7 @@ function diagnosticCategory(code) { if (code === 'CONTRACT_INVALID' || code ===
|
|
|
687
693
|
return 'contract-invalid'; if (code === 'INVALID_BINDING' || code === 'MISSING_INPUT_BINDING' || code === 'MISSING_STEP_BINDING' || code === 'MISSING_STEP_OUTPUT' || code === 'BINDING_FAILED')
|
|
688
694
|
return 'binding-unresolved'; if (code.startsWith('HTTP_') || code === 'ACTION_FAILED' || code === 'MISSING_ACTION_ADAPTER')
|
|
689
695
|
return 'runtime-action-failure'; return 'preflight-invalid'; }
|
|
690
|
-
function InputField({ label, value, onChange }) { return _jsxs("label", { className: "input-field", children: [label, _jsx("input", { value: value, onChange: event => onChange(event.target.value) })] }); }
|
|
696
|
+
function InputField({ label, value, onChange }) { return _jsxs("label", { className: "input-field", children: [label, _jsx("input", { type: isSensitiveKey(label) ? 'password' : 'text', autoComplete: "off", value: value, onChange: event => onChange(event.target.value) })] }); }
|
|
691
697
|
function packageStepsFor(pack) { return pack.target.kind === 'project' ? pack.flows?.flatMap(flow => flow.steps) ?? [] : pack.steps; }
|
|
692
698
|
function flattenDisplaySteps(steps, depth = 0, loopId, parentId, collapsed = new Set()) {
|
|
693
699
|
return steps.flatMap(step => {
|