ui: extract wizard live orchestration
This commit is contained in:
@@ -0,0 +1,500 @@
|
||||
function buildToolDescription() {
|
||||
return {
|
||||
title: textValue('tool-title') || textValue('tool-display-name') || textValue('tool-name'),
|
||||
description: textValue('tool-description'),
|
||||
tags: [],
|
||||
examples: [],
|
||||
};
|
||||
}
|
||||
|
||||
function collectWizardPayload() {
|
||||
var name = textValue('tool-name');
|
||||
if (!name) throw new Error(tKey('wizard.error.tool_name'));
|
||||
|
||||
var inputSchemaValue = parseStructuredText(textValue('tool-input-schema'));
|
||||
var outputSchemaValue = parseStructuredText(textValue('tool-output-schema'));
|
||||
var inputMappingValue = parseStructuredText(textValue('tool-input-mapping'));
|
||||
var outputMappingValue = parseStructuredText(textValue('tool-output-mapping'));
|
||||
|
||||
return {
|
||||
name: name,
|
||||
display_name: textValue('tool-display-name') || name,
|
||||
category: 'general',
|
||||
protocol: wizardProtocol,
|
||||
target: buildTarget(),
|
||||
input_schema: convertJsonSchemaToCrankSchema(inputSchemaValue, []),
|
||||
output_schema: convertJsonSchemaToCrankSchema(outputSchemaValue, []),
|
||||
input_mapping: buildMappingSet(inputMappingValue, 'input'),
|
||||
output_mapping: buildMappingSet(outputMappingValue, 'output'),
|
||||
execution_config: parseExecutionConfig(textValue('tool-exec-config')),
|
||||
tool_description: buildToolDescription(),
|
||||
};
|
||||
}
|
||||
|
||||
async function saveOperation(stayOnPage) {
|
||||
try {
|
||||
await persistCurrentDraft(stayOnPage);
|
||||
} catch (error) {
|
||||
if (window.CrankUi) {
|
||||
window.CrankUi.error(error.message || tKey('wizard.error.save'), tKey('wizard.error.save_title'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function loadOperationForEdit() {
|
||||
if (!wizardWorkspaceId || !wizardEditId) return;
|
||||
var detail = await window.CrankApi.getOperation(wizardWorkspaceId, wizardEditId);
|
||||
wizardProtocol = detail.protocol || 'rest';
|
||||
await loadWizardPanels([3]);
|
||||
var draftVersion = await window.CrankApi.getOperationVersion(
|
||||
wizardWorkspaceId,
|
||||
wizardEditId,
|
||||
detail.draft_version_ref.version
|
||||
);
|
||||
wizardCurrentOperation = detail;
|
||||
wizardCurrentVersion = draftVersion;
|
||||
prefillWizardFromEdit(detail, draftVersion);
|
||||
}
|
||||
|
||||
function setEditModePresentation() {
|
||||
var progressLabel = document.querySelector('.progress-label');
|
||||
if (progressLabel) progressLabel.textContent = tKey('wizard.progress.edit');
|
||||
renderSidebarBrand('edit');
|
||||
}
|
||||
|
||||
function selectProtocol(protocol) {
|
||||
wizardProtocol = protocol || 'rest';
|
||||
document.querySelectorAll('.protocol-card').forEach(function(card) {
|
||||
var proto = card.dataset.protocol
|
||||
|| (card.classList.contains('rest')
|
||||
? 'rest'
|
||||
: card.classList.contains('graphql')
|
||||
? 'graphql'
|
||||
: card.classList.contains('grpc')
|
||||
? 'grpc'
|
||||
: card.classList.contains('websocket')
|
||||
? 'websocket'
|
||||
: card.classList.contains('soap')
|
||||
? 'soap'
|
||||
: 'rest');
|
||||
var selected = proto === wizardProtocol;
|
||||
card.classList.toggle('selected', selected);
|
||||
card.setAttribute('aria-checked', selected ? 'true' : 'false');
|
||||
});
|
||||
var s3name = document.getElementById('sidebar-step-3-name');
|
||||
if (s3name) {
|
||||
var step3Labels = window.CrankWizardState.step3Labels();
|
||||
s3name.textContent = step3Labels[wizardProtocol] || tKey('wizard.step3.rest.label');
|
||||
}
|
||||
updateWizardProtocolVisibility();
|
||||
}
|
||||
|
||||
function bindWizardLiveActions() {
|
||||
bindLiveAction('wizard-upload-input-sample', tKey('wizard.busy.input_sample'), uploadInputSampleFromWizard);
|
||||
bindLiveAction('wizard-upload-output-sample', tKey('wizard.busy.output_sample'), uploadOutputSampleFromWizard);
|
||||
bindLiveAction('wizard-generate-draft', tKey('wizard.busy.generate'), generateDraftFromWizard);
|
||||
bindLiveAction('wizard-run-test', tKey('wizard.busy.test'), runWizardTest);
|
||||
bindClick('wizard-copy-test-response', copyTestResponseToOutputSample);
|
||||
bindLiveAction('wizard-export-yaml', tKey('wizard.busy.export_yaml'), exportWizardYaml);
|
||||
bindLiveAction('wizard-import-yaml', tKey('wizard.busy.import_yaml'), importWizardYaml);
|
||||
bindLiveAction('wizard-publish-operation', tKey('wizard.busy.publish'), publishWizardOperation);
|
||||
bindClick('wizard-select-descriptor-set', function() {
|
||||
var input = document.getElementById('wizard-descriptor-set-input');
|
||||
if (input) input.click();
|
||||
});
|
||||
bindLiveAction('wizard-upload-descriptor-set', tKey('wizard.busy.descriptor'), uploadDescriptorSetAndDiscover);
|
||||
bindClick('wizard-select-soap-wsdl', function() {
|
||||
var input = document.getElementById('wizard-soap-wsdl-input');
|
||||
if (input) input.click();
|
||||
});
|
||||
bindClick('wizard-select-soap-xsd', function() {
|
||||
var input = document.getElementById('wizard-soap-xsd-input');
|
||||
if (input) input.click();
|
||||
});
|
||||
bindLiveAction('wizard-upload-soap-contracts', tKey('wizard.busy.wsdl'), uploadSoapArtifactsAndInspect);
|
||||
bindClick('wizard-import-yaml-file-trigger', function() {
|
||||
var input = document.getElementById('wizard-import-yaml-file');
|
||||
if (input) input.click();
|
||||
});
|
||||
|
||||
var descriptorInput = document.getElementById('wizard-descriptor-set-input');
|
||||
if (descriptorInput) descriptorInput.addEventListener('change', handleDescriptorSetSelection);
|
||||
var soapWsdlInput = document.getElementById('wizard-soap-wsdl-input');
|
||||
if (soapWsdlInput) soapWsdlInput.addEventListener('change', handleSoapWsdlSelection);
|
||||
var soapXsdInput = document.getElementById('wizard-soap-xsd-input');
|
||||
if (soapXsdInput) soapXsdInput.addEventListener('change', handleSoapXsdSelection);
|
||||
|
||||
var yamlInput = document.getElementById('wizard-import-yaml-file');
|
||||
if (yamlInput) yamlInput.addEventListener('change', handleImportYamlFileSelection);
|
||||
}
|
||||
|
||||
function bindClick(id, handler) {
|
||||
var element = document.getElementById(id);
|
||||
if (!element) return;
|
||||
element.addEventListener('click', function(event) {
|
||||
event.preventDefault();
|
||||
handler();
|
||||
});
|
||||
}
|
||||
|
||||
function bindLiveAction(id, busyLabel, handler) {
|
||||
var element = document.getElementById(id);
|
||||
if (!element) return;
|
||||
element.addEventListener('click', function(event) {
|
||||
event.preventDefault();
|
||||
runWizardLiveAction(element, busyLabel, handler);
|
||||
});
|
||||
}
|
||||
|
||||
async function runWizardLiveAction(button, busyLabel, handler) {
|
||||
if (!button || button.dataset.busy === 'true') {
|
||||
return;
|
||||
}
|
||||
|
||||
var originalLabel = button.textContent;
|
||||
button.dataset.busy = 'true';
|
||||
button.disabled = true;
|
||||
button.classList.add('is-busy');
|
||||
button.textContent = busyLabel;
|
||||
|
||||
try {
|
||||
await handler();
|
||||
} catch (error) {
|
||||
showWizardLiveStatus(
|
||||
tKey('wizard.live.failed_title'),
|
||||
error && error.message ? error.message : tKey('wizard.live.failed_body'),
|
||||
true
|
||||
);
|
||||
if (window.CrankUi) {
|
||||
window.CrankUi.error(
|
||||
error && error.message ? error.message : tKey('wizard.live.failed_body'),
|
||||
tKey('wizard.live.failed_title')
|
||||
);
|
||||
}
|
||||
} finally {
|
||||
button.dataset.busy = 'false';
|
||||
button.disabled = false;
|
||||
button.classList.remove('is-busy');
|
||||
button.textContent = originalLabel;
|
||||
}
|
||||
}
|
||||
|
||||
function updateWizardProtocolVisibility() {
|
||||
var grpcTools = document.getElementById('wizard-grpc-live-tools');
|
||||
if (grpcTools) grpcTools.hidden = wizardProtocol !== 'grpc';
|
||||
updateStreamingModeOptions();
|
||||
updateStreamingConfigVisibility();
|
||||
}
|
||||
|
||||
function showWizardLiveStatus(title, text, isError) {
|
||||
var root = document.getElementById('wizard-live-status');
|
||||
var titleEl = document.getElementById('wizard-live-status-title');
|
||||
var textEl = document.getElementById('wizard-live-status-text');
|
||||
if (!root || !titleEl || !textEl) return;
|
||||
titleEl.textContent = title;
|
||||
textEl.textContent = text;
|
||||
root.hidden = false;
|
||||
root.classList.toggle('is-error', !!isError);
|
||||
root.classList.toggle('is-success', !isError);
|
||||
}
|
||||
|
||||
function currentDraftVersion() {
|
||||
if (wizardCurrentOperation && wizardCurrentOperation.draft_version_ref) {
|
||||
return wizardCurrentOperation.draft_version_ref.version;
|
||||
}
|
||||
if (wizardCurrentOperation && wizardCurrentOperation.current_draft_version) {
|
||||
return wizardCurrentOperation.current_draft_version;
|
||||
}
|
||||
if (wizardCurrentVersion && wizardCurrentVersion.version) {
|
||||
return wizardCurrentVersion.version;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
function updateOperationPayload(payload) {
|
||||
return {
|
||||
display_name: payload.display_name,
|
||||
category: payload.category,
|
||||
target: payload.target,
|
||||
input_schema: payload.input_schema,
|
||||
output_schema: payload.output_schema,
|
||||
input_mapping: payload.input_mapping,
|
||||
output_mapping: payload.output_mapping,
|
||||
execution_config: payload.execution_config,
|
||||
tool_description: payload.tool_description,
|
||||
};
|
||||
}
|
||||
|
||||
async function refreshCurrentOperationState() {
|
||||
if (!wizardWorkspaceId || !wizardEditId) return null;
|
||||
var detail = await window.CrankApi.getOperation(wizardWorkspaceId, wizardEditId);
|
||||
var versionNumber = detail.draft_version_ref
|
||||
? detail.draft_version_ref.version
|
||||
: detail.current_draft_version;
|
||||
var versionDocument = await window.CrankApi.getOperationVersion(
|
||||
wizardWorkspaceId,
|
||||
wizardEditId,
|
||||
versionNumber
|
||||
);
|
||||
wizardCurrentOperation = detail;
|
||||
wizardCurrentVersion = versionDocument;
|
||||
updateWizardProtocolVisibility();
|
||||
return {
|
||||
detail: detail,
|
||||
version: versionDocument,
|
||||
};
|
||||
}
|
||||
|
||||
async function uploadPendingGrpcArtifacts(payload) {
|
||||
if (wizardProtocol !== 'grpc' || !wizardEditId) return;
|
||||
|
||||
var descriptorResponse = null;
|
||||
|
||||
if (wizardProtoUpload) {
|
||||
descriptorResponse = await window.CrankApi.uploadProtoFile(
|
||||
wizardWorkspaceId,
|
||||
wizardEditId,
|
||||
new TextEncoder().encode(wizardProtoUpload.content),
|
||||
wizardProtoUpload.fileName
|
||||
);
|
||||
wizardProtoUpload = null;
|
||||
}
|
||||
|
||||
if (wizardDescriptorSetUpload) {
|
||||
descriptorResponse = await window.CrankApi.uploadDescriptorSet(
|
||||
wizardWorkspaceId,
|
||||
wizardEditId,
|
||||
wizardDescriptorSetUpload.bytes,
|
||||
wizardDescriptorSetUpload.fileName
|
||||
);
|
||||
wizardDescriptorSetUpload = null;
|
||||
var descriptorName = document.getElementById('wizard-descriptor-set-name');
|
||||
if (descriptorName) descriptorName.textContent = tKey('wizard.descriptor.uploaded');
|
||||
}
|
||||
|
||||
if (!descriptorResponse) return;
|
||||
|
||||
payload.target.descriptor_ref = descriptorResponse.descriptor_id;
|
||||
payload.target.descriptor_set_b64 = '';
|
||||
await window.CrankApi.updateOperation(
|
||||
wizardWorkspaceId,
|
||||
wizardEditId,
|
||||
updateOperationPayload(payload)
|
||||
);
|
||||
}
|
||||
|
||||
async function uploadPendingSoapArtifacts(payload) {
|
||||
if (wizardProtocol !== 'soap' || !wizardEditId) return;
|
||||
|
||||
var wsdlResponse = null;
|
||||
if (wizardSoapWsdlUpload) {
|
||||
wsdlResponse = await window.CrankApi.uploadWsdlFile(
|
||||
wizardWorkspaceId,
|
||||
wizardEditId,
|
||||
wizardSoapWsdlUpload.bytes,
|
||||
wizardSoapWsdlUpload.fileName
|
||||
);
|
||||
wizardSoapWsdlUpload = null;
|
||||
var wsdlName = document.getElementById('wizard-soap-wsdl-name');
|
||||
if (wsdlName) wsdlName.textContent = tKey('wizard.step3.soap.wsdl_uploaded');
|
||||
}
|
||||
|
||||
if (wizardSoapXsdUpload) {
|
||||
await window.CrankApi.uploadXsdFile(
|
||||
wizardWorkspaceId,
|
||||
wizardEditId,
|
||||
wizardSoapXsdUpload.bytes,
|
||||
wizardSoapXsdUpload.fileName
|
||||
);
|
||||
wizardSoapXsdUpload = null;
|
||||
var xsdName = document.getElementById('wizard-soap-xsd-name');
|
||||
if (xsdName) xsdName.textContent = tKey('wizard.step3.soap.xsd_uploaded');
|
||||
}
|
||||
|
||||
if (!wsdlResponse) return;
|
||||
|
||||
payload.target.wsdl_ref = wsdlResponse.descriptor_id;
|
||||
await window.CrankApi.updateOperation(
|
||||
wizardWorkspaceId,
|
||||
wizardEditId,
|
||||
updateOperationPayload(payload)
|
||||
);
|
||||
}
|
||||
|
||||
async function persistCurrentDraft(stayOnPage) {
|
||||
if (!wizardWorkspaceId) {
|
||||
throw new Error(tKey('wizard.error.no_workspace'));
|
||||
}
|
||||
|
||||
var payload = collectWizardPayload();
|
||||
var response;
|
||||
var createdNow = false;
|
||||
|
||||
if (wizardMode === 'edit' && wizardEditId) {
|
||||
response = await window.CrankApi.updateOperation(
|
||||
wizardWorkspaceId,
|
||||
wizardEditId,
|
||||
updateOperationPayload(payload)
|
||||
);
|
||||
} else {
|
||||
response = await window.CrankApi.createOperation(wizardWorkspaceId, payload);
|
||||
createdNow = true;
|
||||
wizardEditId = response.operation_id;
|
||||
wizardMode = 'edit';
|
||||
history.replaceState(
|
||||
{},
|
||||
'',
|
||||
window.location.pathname + '?mode=edit&operationId=' + encodeURIComponent(wizardEditId)
|
||||
);
|
||||
setEditModePresentation();
|
||||
_doGoToStep(currentStep);
|
||||
var toolNameInput = document.getElementById('tool-name');
|
||||
if (toolNameInput) toolNameInput.disabled = true;
|
||||
}
|
||||
|
||||
await uploadPendingGrpcArtifacts(payload);
|
||||
await uploadPendingSoapArtifacts(payload);
|
||||
await refreshCurrentOperationState();
|
||||
|
||||
if (stayOnPage) {
|
||||
var saveDraftBtn = document.querySelector('.btn-save-draft');
|
||||
if (saveDraftBtn) {
|
||||
var label = saveDraftBtn.textContent;
|
||||
saveDraftBtn.textContent = tKey('wizard.save.saved');
|
||||
setTimeout(function() {
|
||||
saveDraftBtn.textContent = label;
|
||||
}, 1400);
|
||||
}
|
||||
}
|
||||
|
||||
showWizardLiveStatus(
|
||||
createdNow ? tKey('wizard.save.created') : tKey('wizard.save.updated'),
|
||||
tKey('wizard.save.body')
|
||||
);
|
||||
return response;
|
||||
}
|
||||
|
||||
function safeStringify(value) {
|
||||
if (value === null || value === undefined) return '';
|
||||
if (typeof value === 'string') return value;
|
||||
return JSON.stringify(value, null, 2);
|
||||
}
|
||||
|
||||
function setTextareaValue(id, value) {
|
||||
var element = document.getElementById(id);
|
||||
if (!element) return;
|
||||
element.value = safeStringify(value);
|
||||
}
|
||||
|
||||
function describeWizardTestResult(result) {
|
||||
if (result.stream_session && result.stream_session.session_id) {
|
||||
return {
|
||||
title: tKey('wizard.test.session_started'),
|
||||
body: tfKey('wizard.test.session_started_body', {
|
||||
session_id: result.stream_session.session_id,
|
||||
poll_after_ms: result.stream_session.poll_after_ms
|
||||
}),
|
||||
isError: false,
|
||||
};
|
||||
}
|
||||
|
||||
if (result.async_job && result.async_job.job_id) {
|
||||
return {
|
||||
title: tKey('wizard.test.async_job_started'),
|
||||
body: tfKey('wizard.test.async_job_started_body', {
|
||||
job_id: result.async_job.job_id
|
||||
}),
|
||||
isError: false,
|
||||
};
|
||||
}
|
||||
|
||||
if (result.window) {
|
||||
var bodyParts = [
|
||||
tKey('wizard.test.window_completed_body')
|
||||
];
|
||||
if (result.window.truncated) {
|
||||
bodyParts.push(tKey('wizard.test.window_truncated_note'));
|
||||
}
|
||||
if (result.window.has_more) {
|
||||
bodyParts.push(tKey('wizard.test.window_more_note'));
|
||||
}
|
||||
if (!result.window.window_complete) {
|
||||
bodyParts.push(tKey('wizard.test.window_incomplete_note'));
|
||||
}
|
||||
return {
|
||||
title: result.ok ? tKey('wizard.test.window_completed') : tKey('wizard.test.failed'),
|
||||
body: bodyParts.join(' '),
|
||||
isError: !result.ok,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
title: result.ok ? tKey('wizard.test.completed') : tKey('wizard.test.failed'),
|
||||
body: result.ok ? tKey('wizard.test.completed_body') : tKey('wizard.test.failed_body'),
|
||||
isError: !result.ok,
|
||||
};
|
||||
}
|
||||
|
||||
async function uploadInputSampleFromWizard() {
|
||||
await persistCurrentDraft(true);
|
||||
await window.CrankApi.uploadInputSample(
|
||||
wizardWorkspaceId,
|
||||
wizardEditId,
|
||||
parseStructuredText(textValue('wizard-input-sample'))
|
||||
);
|
||||
showWizardLiveStatus(tKey('wizard.sample.input_saved'), tKey('wizard.sample.input_saved_body'));
|
||||
}
|
||||
|
||||
async function uploadOutputSampleFromWizard() {
|
||||
await persistCurrentDraft(true);
|
||||
await window.CrankApi.uploadOutputSample(
|
||||
wizardWorkspaceId,
|
||||
wizardEditId,
|
||||
parseStructuredText(textValue('wizard-output-sample'))
|
||||
);
|
||||
showWizardLiveStatus(tKey('wizard.sample.output_saved'), tKey('wizard.sample.output_saved_body'));
|
||||
}
|
||||
|
||||
async function generateDraftFromWizard() {
|
||||
await persistCurrentDraft(true);
|
||||
var generated = await window.CrankApi.generateDraft(wizardWorkspaceId, wizardEditId, {});
|
||||
setValue('tool-input-schema', JSON.stringify(crankSchemaToJsonSchema(generated.input_schema), null, 2));
|
||||
setValue('tool-output-schema', JSON.stringify(crankSchemaToJsonSchema(generated.output_schema), null, 2));
|
||||
setValue('tool-input-mapping', mappingSetToEditorValue(generated.input_mapping, 'input', wizardProtocol));
|
||||
setValue('tool-output-mapping', mappingSetToEditorValue(generated.output_mapping, 'output', wizardProtocol));
|
||||
showWizardLiveStatus(tKey('wizard.sample.generated'), tKey('wizard.sample.generated_body'));
|
||||
}
|
||||
|
||||
async function runWizardTest() {
|
||||
await persistCurrentDraft(true);
|
||||
var result = await window.CrankApi.runOperationTest(wizardWorkspaceId, wizardEditId, {
|
||||
version: currentDraftVersion(),
|
||||
input: parseStructuredText(textValue('wizard-test-input')),
|
||||
});
|
||||
wizardTestResponsePreview = result.response_preview;
|
||||
setTextareaValue('wizard-test-request-preview', result.request_preview);
|
||||
setTextareaValue('wizard-test-response-preview', result.response_preview);
|
||||
setTextareaValue('wizard-test-errors', result.errors && result.errors.length ? result.errors : []);
|
||||
var status = describeWizardTestResult(result);
|
||||
showWizardLiveStatus(
|
||||
status.title,
|
||||
status.body,
|
||||
status.isError
|
||||
);
|
||||
}
|
||||
|
||||
function copyTestResponseToOutputSample() {
|
||||
if (!wizardTestResponsePreview) {
|
||||
showWizardLiveStatus(tKey('wizard.test.no_response'), tKey('wizard.test.no_response_body'), true);
|
||||
return;
|
||||
}
|
||||
setTextareaValue('wizard-output-sample', wizardTestResponsePreview);
|
||||
showWizardLiveStatus(tKey('wizard.test.response_copied'), tKey('wizard.test.response_copied_body'));
|
||||
}
|
||||
|
||||
window.CrankWizardLive = {
|
||||
saveOperation: saveOperation,
|
||||
loadOperationForEdit: loadOperationForEdit,
|
||||
bindWizardLiveActions: bindWizardLiveActions,
|
||||
updateWizardProtocolVisibility: updateWizardProtocolVisibility,
|
||||
};
|
||||
+4
-494
@@ -16,6 +16,10 @@ var step3PanelId = window.CrankWizardShell.step3PanelId;
|
||||
var bindStreamingConfigControls = window.CrankStreamingForm.bindStreamingConfigControls;
|
||||
var collectStreamingConfig = window.CrankStreamingForm.collectStreamingConfig;
|
||||
var applyStreamingConfig = window.CrankStreamingForm.applyStreamingConfig;
|
||||
var saveOperation = window.CrankWizardLive.saveOperation;
|
||||
var loadOperationForEdit = window.CrankWizardLive.loadOperationForEdit;
|
||||
var bindWizardLiveActions = window.CrankWizardLive.bindWizardLiveActions;
|
||||
var updateWizardProtocolVisibility = window.CrankWizardLive.updateWizardProtocolVisibility;
|
||||
var currentStep = window.currentStep;
|
||||
var wizardProtocol = window.wizardProtocol;
|
||||
var wizardMode = window.wizardMode;
|
||||
@@ -261,497 +265,3 @@ function parseStructuredText(text) {
|
||||
return window.jsyaml.load(text) || {};
|
||||
}
|
||||
}
|
||||
|
||||
function buildToolDescription() {
|
||||
return {
|
||||
title: textValue('tool-title') || textValue('tool-display-name') || textValue('tool-name'),
|
||||
description: textValue('tool-description'),
|
||||
tags: [],
|
||||
examples: [],
|
||||
};
|
||||
}
|
||||
|
||||
function collectWizardPayload() {
|
||||
var name = textValue('tool-name');
|
||||
if (!name) throw new Error(tKey('wizard.error.tool_name'));
|
||||
|
||||
var inputSchemaValue = parseStructuredText(textValue('tool-input-schema'));
|
||||
var outputSchemaValue = parseStructuredText(textValue('tool-output-schema'));
|
||||
var inputMappingValue = parseStructuredText(textValue('tool-input-mapping'));
|
||||
var outputMappingValue = parseStructuredText(textValue('tool-output-mapping'));
|
||||
|
||||
return {
|
||||
name: name,
|
||||
display_name: textValue('tool-display-name') || name,
|
||||
category: 'general',
|
||||
protocol: wizardProtocol,
|
||||
target: buildTarget(),
|
||||
input_schema: convertJsonSchemaToCrankSchema(inputSchemaValue, []),
|
||||
output_schema: convertJsonSchemaToCrankSchema(outputSchemaValue, []),
|
||||
input_mapping: buildMappingSet(inputMappingValue, 'input'),
|
||||
output_mapping: buildMappingSet(outputMappingValue, 'output'),
|
||||
execution_config: parseExecutionConfig(textValue('tool-exec-config')),
|
||||
tool_description: buildToolDescription(),
|
||||
};
|
||||
}
|
||||
|
||||
async function saveOperation(stayOnPage) {
|
||||
try {
|
||||
await persistCurrentDraft(stayOnPage);
|
||||
} catch (error) {
|
||||
if (window.CrankUi) {
|
||||
window.CrankUi.error(error.message || tKey('wizard.error.save'), tKey('wizard.error.save_title'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function loadOperationForEdit() {
|
||||
if (!wizardWorkspaceId || !wizardEditId) return;
|
||||
var detail = await window.CrankApi.getOperation(wizardWorkspaceId, wizardEditId);
|
||||
wizardProtocol = detail.protocol || 'rest';
|
||||
await loadWizardPanels([3]);
|
||||
var draftVersion = await window.CrankApi.getOperationVersion(
|
||||
wizardWorkspaceId,
|
||||
wizardEditId,
|
||||
detail.draft_version_ref.version
|
||||
);
|
||||
wizardCurrentOperation = detail;
|
||||
wizardCurrentVersion = draftVersion;
|
||||
prefillWizardFromEdit(detail, draftVersion);
|
||||
}
|
||||
|
||||
function setEditModePresentation() {
|
||||
var progressLabel = document.querySelector('.progress-label');
|
||||
if (progressLabel) progressLabel.textContent = tKey('wizard.progress.edit');
|
||||
renderSidebarBrand('edit');
|
||||
}
|
||||
|
||||
function selectProtocol(protocol) {
|
||||
wizardProtocol = protocol || 'rest';
|
||||
document.querySelectorAll('.protocol-card').forEach(function(card) {
|
||||
var proto = card.dataset.protocol
|
||||
|| (card.classList.contains('rest')
|
||||
? 'rest'
|
||||
: card.classList.contains('graphql')
|
||||
? 'graphql'
|
||||
: card.classList.contains('grpc')
|
||||
? 'grpc'
|
||||
: card.classList.contains('websocket')
|
||||
? 'websocket'
|
||||
: card.classList.contains('soap')
|
||||
? 'soap'
|
||||
: 'rest');
|
||||
var selected = proto === wizardProtocol;
|
||||
card.classList.toggle('selected', selected);
|
||||
card.setAttribute('aria-checked', selected ? 'true' : 'false');
|
||||
});
|
||||
var s3name = document.getElementById('sidebar-step-3-name');
|
||||
if (s3name) {
|
||||
var step3Labels = window.CrankWizardState.step3Labels();
|
||||
s3name.textContent = step3Labels[wizardProtocol] || tKey('wizard.step3.rest.label');
|
||||
}
|
||||
updateWizardProtocolVisibility();
|
||||
}
|
||||
|
||||
function bindWizardLiveActions() {
|
||||
bindLiveAction('wizard-upload-input-sample', tKey('wizard.busy.input_sample'), uploadInputSampleFromWizard);
|
||||
bindLiveAction('wizard-upload-output-sample', tKey('wizard.busy.output_sample'), uploadOutputSampleFromWizard);
|
||||
bindLiveAction('wizard-generate-draft', tKey('wizard.busy.generate'), generateDraftFromWizard);
|
||||
bindLiveAction('wizard-run-test', tKey('wizard.busy.test'), runWizardTest);
|
||||
bindClick('wizard-copy-test-response', copyTestResponseToOutputSample);
|
||||
bindLiveAction('wizard-export-yaml', tKey('wizard.busy.export_yaml'), exportWizardYaml);
|
||||
bindLiveAction('wizard-import-yaml', tKey('wizard.busy.import_yaml'), importWizardYaml);
|
||||
bindLiveAction('wizard-publish-operation', tKey('wizard.busy.publish'), publishWizardOperation);
|
||||
bindClick('wizard-select-descriptor-set', function() {
|
||||
var input = document.getElementById('wizard-descriptor-set-input');
|
||||
if (input) input.click();
|
||||
});
|
||||
bindLiveAction('wizard-upload-descriptor-set', tKey('wizard.busy.descriptor'), uploadDescriptorSetAndDiscover);
|
||||
bindClick('wizard-select-soap-wsdl', function() {
|
||||
var input = document.getElementById('wizard-soap-wsdl-input');
|
||||
if (input) input.click();
|
||||
});
|
||||
bindClick('wizard-select-soap-xsd', function() {
|
||||
var input = document.getElementById('wizard-soap-xsd-input');
|
||||
if (input) input.click();
|
||||
});
|
||||
bindLiveAction('wizard-upload-soap-contracts', tKey('wizard.busy.wsdl'), uploadSoapArtifactsAndInspect);
|
||||
bindClick('wizard-import-yaml-file-trigger', function() {
|
||||
var input = document.getElementById('wizard-import-yaml-file');
|
||||
if (input) input.click();
|
||||
});
|
||||
|
||||
var descriptorInput = document.getElementById('wizard-descriptor-set-input');
|
||||
if (descriptorInput) descriptorInput.addEventListener('change', handleDescriptorSetSelection);
|
||||
var soapWsdlInput = document.getElementById('wizard-soap-wsdl-input');
|
||||
if (soapWsdlInput) soapWsdlInput.addEventListener('change', handleSoapWsdlSelection);
|
||||
var soapXsdInput = document.getElementById('wizard-soap-xsd-input');
|
||||
if (soapXsdInput) soapXsdInput.addEventListener('change', handleSoapXsdSelection);
|
||||
|
||||
var yamlInput = document.getElementById('wizard-import-yaml-file');
|
||||
if (yamlInput) yamlInput.addEventListener('change', handleImportYamlFileSelection);
|
||||
}
|
||||
|
||||
function bindClick(id, handler) {
|
||||
var element = document.getElementById(id);
|
||||
if (!element) return;
|
||||
element.addEventListener('click', function(event) {
|
||||
event.preventDefault();
|
||||
handler();
|
||||
});
|
||||
}
|
||||
|
||||
function bindLiveAction(id, busyLabel, handler) {
|
||||
var element = document.getElementById(id);
|
||||
if (!element) return;
|
||||
element.addEventListener('click', function(event) {
|
||||
event.preventDefault();
|
||||
runWizardLiveAction(element, busyLabel, handler);
|
||||
});
|
||||
}
|
||||
|
||||
async function runWizardLiveAction(button, busyLabel, handler) {
|
||||
if (!button || button.dataset.busy === 'true') {
|
||||
return;
|
||||
}
|
||||
|
||||
var originalLabel = button.textContent;
|
||||
button.dataset.busy = 'true';
|
||||
button.disabled = true;
|
||||
button.classList.add('is-busy');
|
||||
button.textContent = busyLabel;
|
||||
|
||||
try {
|
||||
await handler();
|
||||
} catch (error) {
|
||||
showWizardLiveStatus(
|
||||
tKey('wizard.live.failed_title'),
|
||||
error && error.message ? error.message : tKey('wizard.live.failed_body'),
|
||||
true
|
||||
);
|
||||
if (window.CrankUi) {
|
||||
window.CrankUi.error(
|
||||
error && error.message ? error.message : tKey('wizard.live.failed_body'),
|
||||
tKey('wizard.live.failed_title')
|
||||
);
|
||||
}
|
||||
} finally {
|
||||
button.dataset.busy = 'false';
|
||||
button.disabled = false;
|
||||
button.classList.remove('is-busy');
|
||||
button.textContent = originalLabel;
|
||||
}
|
||||
}
|
||||
|
||||
function updateWizardProtocolVisibility() {
|
||||
var grpcTools = document.getElementById('wizard-grpc-live-tools');
|
||||
if (grpcTools) grpcTools.hidden = wizardProtocol !== 'grpc';
|
||||
updateStreamingModeOptions();
|
||||
updateStreamingConfigVisibility();
|
||||
}
|
||||
|
||||
function showWizardLiveStatus(title, text, isError) {
|
||||
var root = document.getElementById('wizard-live-status');
|
||||
var titleEl = document.getElementById('wizard-live-status-title');
|
||||
var textEl = document.getElementById('wizard-live-status-text');
|
||||
if (!root || !titleEl || !textEl) return;
|
||||
titleEl.textContent = title;
|
||||
textEl.textContent = text;
|
||||
root.hidden = false;
|
||||
root.classList.toggle('is-error', !!isError);
|
||||
root.classList.toggle('is-success', !isError);
|
||||
}
|
||||
|
||||
function currentDraftVersion() {
|
||||
if (wizardCurrentOperation && wizardCurrentOperation.draft_version_ref) {
|
||||
return wizardCurrentOperation.draft_version_ref.version;
|
||||
}
|
||||
if (wizardCurrentOperation && wizardCurrentOperation.current_draft_version) {
|
||||
return wizardCurrentOperation.current_draft_version;
|
||||
}
|
||||
if (wizardCurrentVersion && wizardCurrentVersion.version) {
|
||||
return wizardCurrentVersion.version;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
function updateOperationPayload(payload) {
|
||||
return {
|
||||
display_name: payload.display_name,
|
||||
category: payload.category,
|
||||
target: payload.target,
|
||||
input_schema: payload.input_schema,
|
||||
output_schema: payload.output_schema,
|
||||
input_mapping: payload.input_mapping,
|
||||
output_mapping: payload.output_mapping,
|
||||
execution_config: payload.execution_config,
|
||||
tool_description: payload.tool_description,
|
||||
};
|
||||
}
|
||||
|
||||
async function refreshCurrentOperationState() {
|
||||
if (!wizardWorkspaceId || !wizardEditId) return null;
|
||||
var detail = await window.CrankApi.getOperation(wizardWorkspaceId, wizardEditId);
|
||||
var versionNumber = detail.draft_version_ref
|
||||
? detail.draft_version_ref.version
|
||||
: detail.current_draft_version;
|
||||
var versionDocument = await window.CrankApi.getOperationVersion(
|
||||
wizardWorkspaceId,
|
||||
wizardEditId,
|
||||
versionNumber
|
||||
);
|
||||
wizardCurrentOperation = detail;
|
||||
wizardCurrentVersion = versionDocument;
|
||||
updateWizardProtocolVisibility();
|
||||
return {
|
||||
detail: detail,
|
||||
version: versionDocument,
|
||||
};
|
||||
}
|
||||
|
||||
async function uploadPendingGrpcArtifacts(payload) {
|
||||
if (wizardProtocol !== 'grpc' || !wizardEditId) return;
|
||||
|
||||
var descriptorResponse = null;
|
||||
|
||||
if (wizardProtoUpload) {
|
||||
descriptorResponse = await window.CrankApi.uploadProtoFile(
|
||||
wizardWorkspaceId,
|
||||
wizardEditId,
|
||||
new TextEncoder().encode(wizardProtoUpload.content),
|
||||
wizardProtoUpload.fileName
|
||||
);
|
||||
wizardProtoUpload = null;
|
||||
}
|
||||
|
||||
if (wizardDescriptorSetUpload) {
|
||||
descriptorResponse = await window.CrankApi.uploadDescriptorSet(
|
||||
wizardWorkspaceId,
|
||||
wizardEditId,
|
||||
wizardDescriptorSetUpload.bytes,
|
||||
wizardDescriptorSetUpload.fileName
|
||||
);
|
||||
wizardDescriptorSetUpload = null;
|
||||
var descriptorName = document.getElementById('wizard-descriptor-set-name');
|
||||
if (descriptorName) descriptorName.textContent = tKey('wizard.descriptor.uploaded');
|
||||
}
|
||||
|
||||
if (!descriptorResponse) return;
|
||||
|
||||
payload.target.descriptor_ref = descriptorResponse.descriptor_id;
|
||||
payload.target.descriptor_set_b64 = '';
|
||||
await window.CrankApi.updateOperation(
|
||||
wizardWorkspaceId,
|
||||
wizardEditId,
|
||||
updateOperationPayload(payload)
|
||||
);
|
||||
}
|
||||
|
||||
async function uploadPendingSoapArtifacts(payload) {
|
||||
if (wizardProtocol !== 'soap' || !wizardEditId) return;
|
||||
|
||||
var wsdlResponse = null;
|
||||
if (wizardSoapWsdlUpload) {
|
||||
wsdlResponse = await window.CrankApi.uploadWsdlFile(
|
||||
wizardWorkspaceId,
|
||||
wizardEditId,
|
||||
wizardSoapWsdlUpload.bytes,
|
||||
wizardSoapWsdlUpload.fileName
|
||||
);
|
||||
wizardSoapWsdlUpload = null;
|
||||
var wsdlName = document.getElementById('wizard-soap-wsdl-name');
|
||||
if (wsdlName) wsdlName.textContent = tKey('wizard.step3.soap.wsdl_uploaded');
|
||||
}
|
||||
|
||||
if (wizardSoapXsdUpload) {
|
||||
await window.CrankApi.uploadXsdFile(
|
||||
wizardWorkspaceId,
|
||||
wizardEditId,
|
||||
wizardSoapXsdUpload.bytes,
|
||||
wizardSoapXsdUpload.fileName
|
||||
);
|
||||
wizardSoapXsdUpload = null;
|
||||
var xsdName = document.getElementById('wizard-soap-xsd-name');
|
||||
if (xsdName) xsdName.textContent = tKey('wizard.step3.soap.xsd_uploaded');
|
||||
}
|
||||
|
||||
if (!wsdlResponse) return;
|
||||
|
||||
payload.target.wsdl_ref = wsdlResponse.descriptor_id;
|
||||
await window.CrankApi.updateOperation(
|
||||
wizardWorkspaceId,
|
||||
wizardEditId,
|
||||
updateOperationPayload(payload)
|
||||
);
|
||||
}
|
||||
|
||||
async function persistCurrentDraft(stayOnPage) {
|
||||
if (!wizardWorkspaceId) {
|
||||
throw new Error(tKey('wizard.error.no_workspace'));
|
||||
}
|
||||
|
||||
var payload = collectWizardPayload();
|
||||
var response;
|
||||
var createdNow = false;
|
||||
|
||||
if (wizardMode === 'edit' && wizardEditId) {
|
||||
response = await window.CrankApi.updateOperation(
|
||||
wizardWorkspaceId,
|
||||
wizardEditId,
|
||||
updateOperationPayload(payload)
|
||||
);
|
||||
} else {
|
||||
response = await window.CrankApi.createOperation(wizardWorkspaceId, payload);
|
||||
createdNow = true;
|
||||
wizardEditId = response.operation_id;
|
||||
wizardMode = 'edit';
|
||||
history.replaceState(
|
||||
{},
|
||||
'',
|
||||
window.location.pathname + '?mode=edit&operationId=' + encodeURIComponent(wizardEditId)
|
||||
);
|
||||
setEditModePresentation();
|
||||
_doGoToStep(currentStep);
|
||||
var toolNameInput = document.getElementById('tool-name');
|
||||
if (toolNameInput) toolNameInput.disabled = true;
|
||||
}
|
||||
|
||||
await uploadPendingGrpcArtifacts(payload);
|
||||
await uploadPendingSoapArtifacts(payload);
|
||||
await refreshCurrentOperationState();
|
||||
|
||||
if (stayOnPage) {
|
||||
var saveDraftBtn = document.querySelector('.btn-save-draft');
|
||||
if (saveDraftBtn) {
|
||||
var label = saveDraftBtn.textContent;
|
||||
saveDraftBtn.textContent = tKey('wizard.save.saved');
|
||||
setTimeout(function() {
|
||||
saveDraftBtn.textContent = label;
|
||||
}, 1400);
|
||||
}
|
||||
}
|
||||
|
||||
showWizardLiveStatus(
|
||||
createdNow ? tKey('wizard.save.created') : tKey('wizard.save.updated'),
|
||||
tKey('wizard.save.body')
|
||||
);
|
||||
return response;
|
||||
}
|
||||
|
||||
function safeStringify(value) {
|
||||
if (value === null || value === undefined) return '';
|
||||
if (typeof value === 'string') return value;
|
||||
return JSON.stringify(value, null, 2);
|
||||
}
|
||||
|
||||
function setTextareaValue(id, value) {
|
||||
var element = document.getElementById(id);
|
||||
if (!element) return;
|
||||
element.value = safeStringify(value);
|
||||
}
|
||||
|
||||
function describeWizardTestResult(result) {
|
||||
if (result.stream_session && result.stream_session.session_id) {
|
||||
return {
|
||||
title: tKey('wizard.test.session_started'),
|
||||
body: tfKey('wizard.test.session_started_body', {
|
||||
session_id: result.stream_session.session_id,
|
||||
poll_after_ms: result.stream_session.poll_after_ms
|
||||
}),
|
||||
isError: false,
|
||||
};
|
||||
}
|
||||
|
||||
if (result.async_job && result.async_job.job_id) {
|
||||
return {
|
||||
title: tKey('wizard.test.async_job_started'),
|
||||
body: tfKey('wizard.test.async_job_started_body', {
|
||||
job_id: result.async_job.job_id
|
||||
}),
|
||||
isError: false,
|
||||
};
|
||||
}
|
||||
|
||||
if (result.window) {
|
||||
var bodyParts = [
|
||||
tKey('wizard.test.window_completed_body')
|
||||
];
|
||||
if (result.window.truncated) {
|
||||
bodyParts.push(tKey('wizard.test.window_truncated_note'));
|
||||
}
|
||||
if (result.window.has_more) {
|
||||
bodyParts.push(tKey('wizard.test.window_more_note'));
|
||||
}
|
||||
if (!result.window.window_complete) {
|
||||
bodyParts.push(tKey('wizard.test.window_incomplete_note'));
|
||||
}
|
||||
return {
|
||||
title: result.ok ? tKey('wizard.test.window_completed') : tKey('wizard.test.failed'),
|
||||
body: bodyParts.join(' '),
|
||||
isError: !result.ok,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
title: result.ok ? tKey('wizard.test.completed') : tKey('wizard.test.failed'),
|
||||
body: result.ok ? tKey('wizard.test.completed_body') : tKey('wizard.test.failed_body'),
|
||||
isError: !result.ok,
|
||||
};
|
||||
}
|
||||
|
||||
async function uploadInputSampleFromWizard() {
|
||||
await persistCurrentDraft(true);
|
||||
await window.CrankApi.uploadInputSample(
|
||||
wizardWorkspaceId,
|
||||
wizardEditId,
|
||||
parseStructuredText(textValue('wizard-input-sample'))
|
||||
);
|
||||
showWizardLiveStatus(tKey('wizard.sample.input_saved'), tKey('wizard.sample.input_saved_body'));
|
||||
}
|
||||
|
||||
async function uploadOutputSampleFromWizard() {
|
||||
await persistCurrentDraft(true);
|
||||
await window.CrankApi.uploadOutputSample(
|
||||
wizardWorkspaceId,
|
||||
wizardEditId,
|
||||
parseStructuredText(textValue('wizard-output-sample'))
|
||||
);
|
||||
showWizardLiveStatus(tKey('wizard.sample.output_saved'), tKey('wizard.sample.output_saved_body'));
|
||||
}
|
||||
|
||||
async function generateDraftFromWizard() {
|
||||
await persistCurrentDraft(true);
|
||||
var generated = await window.CrankApi.generateDraft(wizardWorkspaceId, wizardEditId, {});
|
||||
setValue('tool-input-schema', JSON.stringify(crankSchemaToJsonSchema(generated.input_schema), null, 2));
|
||||
setValue('tool-output-schema', JSON.stringify(crankSchemaToJsonSchema(generated.output_schema), null, 2));
|
||||
setValue('tool-input-mapping', mappingSetToEditorValue(generated.input_mapping, 'input', wizardProtocol));
|
||||
setValue('tool-output-mapping', mappingSetToEditorValue(generated.output_mapping, 'output', wizardProtocol));
|
||||
showWizardLiveStatus(tKey('wizard.sample.generated'), tKey('wizard.sample.generated_body'));
|
||||
}
|
||||
|
||||
async function runWizardTest() {
|
||||
await persistCurrentDraft(true);
|
||||
var result = await window.CrankApi.runOperationTest(wizardWorkspaceId, wizardEditId, {
|
||||
version: currentDraftVersion(),
|
||||
input: parseStructuredText(textValue('wizard-test-input')),
|
||||
});
|
||||
wizardTestResponsePreview = result.response_preview;
|
||||
setTextareaValue('wizard-test-request-preview', result.request_preview);
|
||||
setTextareaValue('wizard-test-response-preview', result.response_preview);
|
||||
setTextareaValue('wizard-test-errors', result.errors && result.errors.length ? result.errors : []);
|
||||
var status = describeWizardTestResult(result);
|
||||
showWizardLiveStatus(
|
||||
status.title,
|
||||
status.body,
|
||||
status.isError
|
||||
);
|
||||
}
|
||||
|
||||
function copyTestResponseToOutputSample() {
|
||||
if (!wizardTestResponsePreview) {
|
||||
showWizardLiveStatus(tKey('wizard.test.no_response'), tKey('wizard.test.no_response_body'), true);
|
||||
return;
|
||||
}
|
||||
setTextareaValue('wizard-output-sample', wizardTestResponsePreview);
|
||||
showWizardLiveStatus(tKey('wizard.test.response_copied'), tKey('wizard.test.response_copied_body'));
|
||||
}
|
||||
|
||||
@@ -106,6 +106,7 @@ const BUNDLES = {
|
||||
'js/wizard-artifacts.js',
|
||||
'js/wizard-upstreams.js',
|
||||
'js/wizard-model.js',
|
||||
'js/wizard-live.js',
|
||||
'js/wizard.js',
|
||||
'js/nav.js',
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user