diff --git a/apps/ui/js/wizard-artifacts.js b/apps/ui/js/wizard-artifacts.js new file mode 100644 index 0000000..03f1d16 --- /dev/null +++ b/apps/ui/js/wizard-artifacts.js @@ -0,0 +1,302 @@ +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')); +} diff --git a/apps/ui/js/wizard.js b/apps/ui/js/wizard.js index 9855951..8ce62d1 100644 --- a/apps/ui/js/wizard.js +++ b/apps/ui/js/wizard.js @@ -1299,306 +1299,3 @@ function copyTestResponseToOutputSample() { setTextareaValue('wizard-output-sample', wizardTestResponsePreview); showWizardLiveStatus(tKey('wizard.test.response_copied'), tKey('wizard.test.response_copied_body')); } - -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')); -} diff --git a/apps/ui/scripts/build.js b/apps/ui/scripts/build.js index 08f3426..96b1bad 100644 --- a/apps/ui/scripts/build.js +++ b/apps/ui/scripts/build.js @@ -103,6 +103,7 @@ const BUNDLES = { 'js/streaming-form.js', 'js/stream-test-run.js', 'js/wizard-grpc.js', + 'js/wizard-artifacts.js', 'js/wizard-upstreams.js', 'js/wizard.js', 'js/nav.js',