function downloadTextFile(fileName, content, mimeType) { var blob = new Blob([content], { type: mimeType || 'text/plain;charset=utf-8' }); var url = URL.createObjectURL(blob); var link = document.createElement('a'); link.href = url; link.download = fileName; link.click(); URL.revokeObjectURL(url); } async function exportWizardYaml() { await persistCurrentDraft(true); var yaml = await window.CrankApi.exportOperation(wizardWorkspaceId, wizardEditId, { mode: 'portable', version: currentDraftVersion(), }); downloadTextFile((textValue('tool-name') || 'operation') + '.yaml', yaml, 'application/yaml'); showWizardLiveStatus(tKey('wizard.yaml.exported'), tKey('wizard.yaml.exported_body')); } async function importWizardYaml() { if (!wizardWorkspaceId) { throw new Error(tKey('wizard.error.no_workspace')); } var yamlDocument = textValue('wizard-import-yaml-text'); if (!yamlDocument) { showWizardLiveStatus(tKey('wizard.yaml.none'), tKey('wizard.yaml.none_body'), true); return; } var imported = await window.CrankApi.importOperation(wizardWorkspaceId, yamlDocument, 'upsert'); showWizardLiveStatus(tKey('wizard.yaml.imported'), tKey('wizard.yaml.imported_body')); window.location.href = window.location.pathname + '?mode=edit&operationId=' + encodeURIComponent(imported.operation_id); } async function publishWizardOperation() { await persistCurrentDraft(true); var published = await window.CrankApi.publishOperation( wizardWorkspaceId, wizardEditId, currentDraftVersion() ); await refreshCurrentOperationState(); showWizardLiveStatus( tKey('wizard.publish.done'), tfKey('wizard.publish.done_body', { version: published.published_version }) ); } function handleImportYamlFileSelection(event) { var file = event.target.files && event.target.files[0]; if (!file) return; var reader = new FileReader(); reader.onload = function(loadEvent) { setValue('wizard-import-yaml-text', loadEvent.target.result || ''); showWizardLiveStatus(tKey('wizard.yaml.loaded'), tKey('wizard.yaml.loaded_body')); }; reader.readAsText(file); } function handleDescriptorSetSelection(event) { var file = event.target.files && event.target.files[0]; if (!file) return; var reader = new FileReader(); reader.onload = function(loadEvent) { wizardDescriptorSetUpload = { fileName: file.name, bytes: new Uint8Array(loadEvent.target.result), }; var fileNameEl = document.getElementById('wizard-descriptor-set-name'); if (fileNameEl) fileNameEl.textContent = file.name; showWizardLiveStatus(tKey('wizard.descriptor.selected'), tKey('wizard.descriptor.selected_body')); }; reader.readAsArrayBuffer(file); } function handleSoapWsdlSelection(event) { var file = event.target.files && event.target.files[0]; if (!file) return; var reader = new FileReader(); reader.onload = function(loadEvent) { wizardSoapWsdlUpload = { fileName: file.name, bytes: new Uint8Array(loadEvent.target.result), }; var fileNameEl = document.getElementById('wizard-soap-wsdl-name'); if (fileNameEl) fileNameEl.textContent = file.name; showWizardLiveStatus(tKey('wizard.step3.soap.wsdl_selected'), tKey('wizard.step3.soap.wsdl_selected_body')); }; reader.readAsArrayBuffer(file); } function handleSoapXsdSelection(event) { var file = event.target.files && event.target.files[0]; if (!file) return; var reader = new FileReader(); reader.onload = function(loadEvent) { wizardSoapXsdUpload = { fileName: file.name, bytes: new Uint8Array(loadEvent.target.result), }; var fileNameEl = document.getElementById('wizard-soap-xsd-name'); if (fileNameEl) fileNameEl.textContent = file.name; showWizardLiveStatus(tKey('wizard.step3.soap.xsd_selected'), tKey('wizard.step3.soap.xsd_selected_body')); }; reader.readAsArrayBuffer(file); } function renderDescriptorServiceList(services) { grpcDescriptorServices = services || []; var summaryEl = document.getElementById('wizard-descriptor-services-summary'); var listEl = document.getElementById('wizard-descriptor-services-list'); if (!summaryEl || !listEl) return; var methodCount = grpcDescriptorServices.reduce(function(total, service) { return total + ((service.methods || []).length); }, 0); summaryEl.textContent = grpcDescriptorServices.length ? tfKey('wizard.grpc.services_discovered', { services: grpcDescriptorServices.length, methods: methodCount }) : tKey('wizard.grpc.services_none'); listEl.innerHTML = ''; grpcDescriptorServices.forEach(function(service, serviceIndex) { var group = document.createElement('div'); group.className = 'config-card'; group.style.marginBottom = '0'; var body = document.createElement('div'); body.className = 'config-card-body'; body.style.padding = '16px'; body.style.gap = '10px'; var title = document.createElement('div'); title.className = 'config-card-title'; title.textContent = (service.package ? service.package + '.' : '') + service.service; body.appendChild(title); (service.methods || []).forEach(function(method, methodIndex) { var button = document.createElement('button'); button.type = 'button'; button.className = 'btn-ghost-sm'; button.style.width = '100%'; button.style.justifyContent = 'space-between'; button.textContent = method.name; button.addEventListener('click', function() { applyDiscoveredGrpcMethod(serviceIndex, methodIndex); }); body.appendChild(button); }); group.appendChild(body); listEl.appendChild(group); }); } function applyDiscoveredGrpcMethod(serviceIndex, methodIndex) { var service = grpcDescriptorServices[serviceIndex]; var method = service && service.methods ? service.methods[methodIndex] : null; if (!service || !method) return; var route = '/' + (service.package ? service.package + '.' : '') + service.service + '/' + method.name; selectGrpcSource('manual'); setValue('grpc-manual-route', route); setValue('grpc-manual-req-type', method.name + 'Request'); setValue('grpc-manual-res-type', method.name + 'Response'); grpcManualRouteInput(route); grpcManualTypeInput(); setValue('tool-input-schema', JSON.stringify(crankSchemaToJsonSchema(method.input_schema), null, 2)); setValue('tool-output-schema', JSON.stringify(crankSchemaToJsonSchema(method.output_schema), null, 2)); showWizardLiveStatus(tKey('wizard.descriptor.applied'), tKey('wizard.descriptor.applied_body')); } async function uploadDescriptorSetAndDiscover() { var hasSavedDescriptor = !!( wizardCurrentVersion && wizardCurrentVersion.target && wizardCurrentVersion.target.kind === 'grpc' && wizardCurrentVersion.target.descriptor_ref ); if (!wizardDescriptorSetUpload && !hasSavedDescriptor) { showWizardLiveStatus(tKey('wizard.descriptor.no_file'), tKey('wizard.descriptor.no_file_body'), true); return; } await persistCurrentDraft(true); var services = await window.CrankApi.listGrpcServices( wizardWorkspaceId, wizardEditId, currentDraftVersion() ); renderDescriptorServiceList(services.services || []); showWizardLiveStatus(tKey('wizard.descriptor.discovered'), tKey('wizard.descriptor.discovered_body')); } function renderSoapServiceCatalog(services) { soapServiceCatalog = services || []; var summaryEl = document.getElementById('wizard-soap-services-summary'); var listEl = document.getElementById('wizard-soap-services-list'); if (!summaryEl || !listEl) return; var portCount = 0; var operationCount = 0; soapServiceCatalog.forEach(function(service) { portCount += (service.ports || []).length; (service.ports || []).forEach(function(port) { operationCount += (port.operations || []).length; }); }); summaryEl.textContent = soapServiceCatalog.length ? tfKey('wizard.step3.soap.services_discovered', { services: soapServiceCatalog.length, ports: portCount, operations: operationCount }) : tKey('wizard.step3.soap.services_none'); listEl.innerHTML = ''; soapServiceCatalog.forEach(function(service, serviceIndex) { var group = document.createElement('div'); group.className = 'config-card'; group.style.marginBottom = '0'; var body = document.createElement('div'); body.className = 'config-card-body'; body.style.padding = '16px'; body.style.gap = '10px'; var title = document.createElement('div'); title.className = 'config-card-title'; title.textContent = service.service_name; body.appendChild(title); (service.ports || []).forEach(function(port, portIndex) { var portLabel = document.createElement('div'); portLabel.className = 'form-hint'; portLabel.textContent = port.port_name + ' ยท ' + port.soap_version; body.appendChild(portLabel); (port.operations || []).forEach(function(operation, operationIndex) { var button = document.createElement('button'); button.type = 'button'; button.className = 'btn-ghost-sm'; button.style.width = '100%'; button.style.justifyContent = 'space-between'; button.textContent = operation.operation_name; button.addEventListener('click', function() { applyDiscoveredSoapOperation(serviceIndex, portIndex, operationIndex); }); body.appendChild(button); }); }); group.appendChild(body); listEl.appendChild(group); }); } function applyDiscoveredSoapOperation(serviceIndex, portIndex, operationIndex) { var service = soapServiceCatalog[serviceIndex]; var port = service && service.ports ? service.ports[portIndex] : null; var operation = port && port.operations ? port.operations[operationIndex] : null; if (!service || !port || !operation) return; setValue('soap-service-name', service.service_name); setValue('soap-port-name', port.port_name); setValue('soap-operation-name', operation.operation_name); setValue('soap-version', port.soap_version || 'soap_11'); setValue('soap-action', operation.soap_action || ''); setValue('soap-binding-style', operation.binding_style || 'document_literal'); if (!textValue('soap-endpoint-override') && port.endpoint) { setValue('soap-endpoint-override', port.endpoint); } showWizardLiveStatus(tKey('wizard.step3.soap.applied'), tKey('wizard.step3.soap.applied_body')); } async function uploadSoapArtifactsAndInspect() { var hasSavedWsdl = !!( wizardCurrentVersion && wizardCurrentVersion.target && wizardCurrentVersion.target.kind === 'soap' && wizardCurrentVersion.target.wsdl_ref && wizardCurrentVersion.target.wsdl_ref !== 'sample_wsdl_pending' ); if (!wizardSoapWsdlUpload && !hasSavedWsdl) { showWizardLiveStatus(tKey('wizard.step3.soap.no_wsdl_error'), tKey('wizard.step3.soap.no_wsdl_error_body'), true); return; } await persistCurrentDraft(true); var services = await window.CrankApi.listSoapServices( wizardWorkspaceId, wizardEditId, currentDraftVersion() ); renderSoapServiceCatalog(services.services || []); showWizardLiveStatus(tKey('wizard.step3.soap.discovered'), tKey('wizard.step3.soap.discovered_body')); }