ui: finalize wizard modularization

This commit is contained in:
a.tolmachev
2026-05-02 20:17:17 +00:00
parent 95d9006d70
commit fa2a98765d
6 changed files with 30 additions and 40 deletions
+10 -32
View File
@@ -2,42 +2,20 @@
## Current ## Current
### `feat/frontend-wizard-modularization` ### `feat/websocket-test-run-polish`
Status: in_progress Status: ready
DoD: DoD:
- `wizard.js` is split by responsibility into smaller files with stable ownership boundaries - websocket test-run flow clearly reports bounded results, reconnect/error states, and final status
- extracted modules keep existing wizard behavior and asset build flow - operator-facing UI reflects websocket-specific runtime semantics instead of generic streaming copy
- modularization changes pass UI build and targeted wizard smoke checks - targeted UI checks cover websocket wizard/test-run behavior
## Next ## 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` - `feat/live-authenticated-staging-entry`
## Completed
- `feat/frontend-wizard-modularization`
- `feat/distributed-mcp-session-store`
+2
View File
@@ -318,6 +318,8 @@
updateStreamingConfigVisibility(); updateStreamingConfigVisibility();
}, },
serializeStreamingConfig: serializeStreamingConfig, serializeStreamingConfig: serializeStreamingConfig,
updateStreamingModeOptions: updateStreamingModeOptions,
updateStreamingConfigVisibility: updateStreamingConfigVisibility,
deserializeStreamingConfig: function(streaming) { deserializeStreamingConfig: function(streaming) {
if (typeof window.applyStreamingConfig === 'function') { if (typeof window.applyStreamingConfig === 'function') {
window.applyStreamingConfig(streaming); window.applyStreamingConfig(streaming);
+3
View File
@@ -1,3 +1,6 @@
var updateStreamingModeOptions = window.CrankStreamingForm.updateStreamingModeOptions;
var updateStreamingConfigVisibility = window.CrankStreamingForm.updateStreamingConfigVisibility;
function buildToolDescription() { function buildToolDescription() {
return { return {
title: textValue('tool-title') || textValue('tool-display-name') || textValue('tool-name'), title: textValue('tool-title') || textValue('tool-display-name') || textValue('tool-name'),
+5 -4
View File
@@ -53,10 +53,11 @@ function mappingRootForProtocol(protocol) {
} }
function normalizeInputSource(path) { function normalizeInputSource(path) {
if (!path) return '$.input'; if (!path) return '$.mcp';
if (path === '$') return '$.input'; if (path === '$') return '$.mcp';
if (path.indexOf('$.input') === 0) return path; if (path.indexOf('$.mcp') === 0) return path;
return '$.input.' + path.replace(/^\$\./, ''); if (path.indexOf('$.input') === 0) return '$.mcp' + path.slice('$.input'.length);
return '$.mcp.' + path.replace(/^\$\./, '');
} }
function normalizeOutputSource(path) { function normalizeOutputSource(path) {
+3
View File
@@ -84,6 +84,7 @@ async function initWizardPage() {
await (window.whenWorkspacesReady ? window.whenWorkspacesReady() : Promise.resolve()); await (window.whenWorkspacesReady ? window.whenWorkspacesReady() : Promise.resolve());
var workspace = window.getCurrentWorkspace ? window.getCurrentWorkspace() : null; var workspace = window.getCurrentWorkspace ? window.getCurrentWorkspace() : null;
wizardWorkspaceId = workspace ? workspace.id : null; wizardWorkspaceId = workspace ? workspace.id : null;
window.wizardWorkspaceId = wizardWorkspaceId;
await loadProtocolCapabilities(); await loadProtocolCapabilities();
await loadWizardPanels([1, 2, 3, 4, 5]); await loadWizardPanels([1, 2, 3, 4, 5]);
@@ -130,6 +131,8 @@ async function initWizardPage() {
if (params.get('mode') === 'edit' && params.get('operationId')) { if (params.get('mode') === 'edit' && params.get('operationId')) {
wizardMode = 'edit'; wizardMode = 'edit';
wizardEditId = params.get('operationId'); wizardEditId = params.get('operationId');
window.wizardMode = wizardMode;
window.wizardEditId = wizardEditId;
document.title = 'Crank — ' + tKey('wizard.progress.edit'); document.title = 'Crank — ' + tKey('wizard.progress.edit');
await loadOperationForEdit(); await loadOperationForEdit();
} }
+7 -4
View File
@@ -12,11 +12,10 @@ const {
test('wizard loads and protocol selection updates flow', async ({ page }) => { test('wizard loads and protocol selection updates flow', async ({ page }) => {
await login(page); await login(page);
await page.goto('/wizard/'); 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 expect(page.locator('#step-panel-1 .step-panel-title')).toContainText(localized('Choose a protocol', 'Выберите протокол'));
await page.getByText(/graphql/i).first().click(); await page.getByText(/graphql/i).first().click();
await page.locator('#btn-continue').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')); 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)); }, null, 2));
await page.locator('#btn-continue').click(); await page.locator('#btn-continue').click();
await expect(page.locator('[data-i18n="wizard.step5.test_title"]')).toContainText(localized('Test run', 'Тестовый запуск')); 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-input-mapping').fill(JSON.stringify({
await page.locator('#tool-output-mapping').fill('id: "$.response.body.id"'); 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('#tool-exec-config').fill('timeout_ms: 1000');
await page.locator('#wizard-test-input').fill(JSON.stringify({ email: 'user@example.com' }, null, 2)); await page.locator('#wizard-test-input').fill(JSON.stringify({ email: 'user@example.com' }, null, 2));