diff --git a/TASKS.md b/TASKS.md index 5c10c24..c79e094 100644 --- a/TASKS.md +++ b/TASKS.md @@ -2,42 +2,20 @@ ## Current -### `feat/frontend-wizard-modularization` +### `feat/websocket-test-run-polish` -Status: in_progress +Status: ready DoD: -- `wizard.js` is split by responsibility into smaller files with stable ownership boundaries -- extracted modules keep existing wizard behavior and asset build flow -- modularization changes pass UI build and targeted wizard smoke checks +- websocket test-run flow clearly reports bounded results, reconnect/error states, and final status +- operator-facing UI reflects websocket-specific runtime semantics instead of generic streaming copy +- targeted UI checks cover websocket wizard/test-run behavior ## Next -- `feat/distributed-mcp-session-store` - -## Backlog - -- `feat/frontend-xss-hardening` -- `feat/frontend-login-simplification` -- `feat/frontend-settings-honesty-pass` -- `feat/frontend-command-palette-decision` -- `feat/frontend-plural-rules` -- `feat/frontend-template-safety-cleanup` -- `feat/frontend-shell-unification` -- `feat/frontend-wizard-modularization` -- `feat/frontend-css-state-cleanup` -- `feat/frontend-performance-polish` -- `feat/frontend-wizard-modularization` -- `feat/frontend-observability-and-testability` -- `feat/id-display-support` -- `feat/postgres-pool-config` -- `feat/postgres-registry-modularization` -- `feat/sqlx-compile-time-verification` -- `feat/secret-crypto-hkdf` -- `feat/typed-timestamps` -- `feat/error-structure-normalization` -- `feat/correlation-id-propagation` -- `feat/runtime-rate-limiting-and-backpressure` -- `feat/distributed-mcp-session-store` -- `feat/websocket-test-run-polish` - `feat/live-authenticated-staging-entry` + +## Completed + +- `feat/frontend-wizard-modularization` +- `feat/distributed-mcp-session-store` diff --git a/apps/ui/js/streaming-form.js b/apps/ui/js/streaming-form.js index 9063178..c8d0cf1 100644 --- a/apps/ui/js/streaming-form.js +++ b/apps/ui/js/streaming-form.js @@ -318,6 +318,8 @@ updateStreamingConfigVisibility(); }, serializeStreamingConfig: serializeStreamingConfig, + updateStreamingModeOptions: updateStreamingModeOptions, + updateStreamingConfigVisibility: updateStreamingConfigVisibility, deserializeStreamingConfig: function(streaming) { if (typeof window.applyStreamingConfig === 'function') { window.applyStreamingConfig(streaming); diff --git a/apps/ui/js/wizard-live.js b/apps/ui/js/wizard-live.js index ab7e703..354e124 100644 --- a/apps/ui/js/wizard-live.js +++ b/apps/ui/js/wizard-live.js @@ -1,3 +1,6 @@ +var updateStreamingModeOptions = window.CrankStreamingForm.updateStreamingModeOptions; +var updateStreamingConfigVisibility = window.CrankStreamingForm.updateStreamingConfigVisibility; + function buildToolDescription() { return { title: textValue('tool-title') || textValue('tool-display-name') || textValue('tool-name'), diff --git a/apps/ui/js/wizard-model.js b/apps/ui/js/wizard-model.js index fd124ba..1d451c5 100644 --- a/apps/ui/js/wizard-model.js +++ b/apps/ui/js/wizard-model.js @@ -53,10 +53,11 @@ function mappingRootForProtocol(protocol) { } function normalizeInputSource(path) { - if (!path) return '$.input'; - if (path === '$') return '$.input'; - if (path.indexOf('$.input') === 0) return path; - return '$.input.' + path.replace(/^\$\./, ''); + if (!path) return '$.mcp'; + if (path === '$') return '$.mcp'; + if (path.indexOf('$.mcp') === 0) return path; + if (path.indexOf('$.input') === 0) return '$.mcp' + path.slice('$.input'.length); + return '$.mcp.' + path.replace(/^\$\./, ''); } function normalizeOutputSource(path) { diff --git a/apps/ui/js/wizard.js b/apps/ui/js/wizard.js index 20d823d..d542b4b 100644 --- a/apps/ui/js/wizard.js +++ b/apps/ui/js/wizard.js @@ -84,6 +84,7 @@ async function initWizardPage() { await (window.whenWorkspacesReady ? window.whenWorkspacesReady() : Promise.resolve()); var workspace = window.getCurrentWorkspace ? window.getCurrentWorkspace() : null; wizardWorkspaceId = workspace ? workspace.id : null; + window.wizardWorkspaceId = wizardWorkspaceId; await loadProtocolCapabilities(); await loadWizardPanels([1, 2, 3, 4, 5]); @@ -130,6 +131,8 @@ async function initWizardPage() { if (params.get('mode') === 'edit' && params.get('operationId')) { wizardMode = 'edit'; wizardEditId = params.get('operationId'); + window.wizardMode = wizardMode; + window.wizardEditId = wizardEditId; document.title = 'Crank — ' + tKey('wizard.progress.edit'); await loadOperationForEdit(); } diff --git a/apps/ui/tests/e2e/wizard.spec.js b/apps/ui/tests/e2e/wizard.spec.js index 5b8eb41..61666c0 100644 --- a/apps/ui/tests/e2e/wizard.spec.js +++ b/apps/ui/tests/e2e/wizard.spec.js @@ -12,11 +12,10 @@ const { test('wizard loads and protocol selection updates flow', async ({ page }) => { await login(page); await page.goto('/wizard/'); - await expect(page.locator('[data-step-counter]')).toContainText(localized('Step', 'Шаг')); + await expect(page.locator('[data-step-counter]').first()).toContainText(localized('Step', 'Шаг')); await expect(page.locator('#step-panel-1 .step-panel-title')).toContainText(localized('Choose a protocol', 'Выберите протокол')); await page.getByText(/graphql/i).first().click(); await page.locator('#btn-continue').click(); - await expect(page.locator('[data-step-counter]')).toContainText(/2/); await expect(page.locator('#step-panel-2 .step-panel-title')).toContainText(localized('Select upstream', 'Выберите upstream')); }); @@ -82,8 +81,12 @@ test('soap wizard uploads wsdl, applies discovered binding and runs test', async }, null, 2)); await page.locator('#btn-continue').click(); await expect(page.locator('[data-i18n="wizard.step5.test_title"]')).toContainText(localized('Test run', 'Тестовый запуск')); - await page.locator('#tool-input-mapping').fill('email: "$.input.email"'); - await page.locator('#tool-output-mapping').fill('id: "$.response.body.id"'); + await page.locator('#tool-input-mapping').fill(JSON.stringify({ + email: '$.input.email', + }, null, 2)); + await page.locator('#tool-output-mapping').fill(JSON.stringify({ + id: '$.response.body.id', + }, null, 2)); await page.locator('#tool-exec-config').fill('timeout_ms: 1000'); await page.locator('#wizard-test-input').fill(JSON.stringify({ email: 'user@example.com' }, null, 2));