diff --git a/apps/ui/js/streaming-form.js b/apps/ui/js/streaming-form.js index 17da8c8..9063178 100644 --- a/apps/ui/js/streaming-form.js +++ b/apps/ui/js/streaming-form.js @@ -1,9 +1,24 @@ (function() { + function tKey(key) { + return typeof t === 'function' ? t(key) : key; + } + + function currentProtocolCapabilities() { + return window.CrankWizardState.currentProtocolCapabilities(); + } + function text(id) { var element = document.getElementById(id); return element ? String(element.value || '').trim() : ''; } + function set(id, value) { + var element = document.getElementById(id); + if (element) { + element.value = value || ''; + } + } + function number(id) { var value = text(id); if (!value) return null; @@ -27,6 +42,149 @@ return text('streaming-mode') || 'unary'; } + function transportOptionsForMode(mode) { + var capabilities = currentProtocolCapabilities(); + var behaviors = (capabilities.supports_transport_behaviors || []).slice(); + if (mode === 'unary') return behaviors.filter(function(value) { return value === 'request_response'; }); + if (mode === 'window') return behaviors.filter(function(value) { + return value === 'request_response' || value === 'server_stream'; + }); + if (mode === 'session') return behaviors.filter(function(value) { + return value === 'server_stream' || value === 'stateful_session'; + }); + if (mode === 'async_job') return behaviors.filter(function(value) { + return value === 'deferred_result'; + }); + return behaviors; + } + + function modeOptionsForProtocol() { + var capabilities = currentProtocolCapabilities(); + return (capabilities.supports_execution_modes || ['unary']).filter(function(mode) { + return transportOptionsForMode(mode).length > 0 || mode === 'unary'; + }); + } + + function updateStreamingTransportOptions(preferredValue) { + var element = document.getElementById('streaming-transport-behavior'); + if (!element) return; + var options = transportOptionsForMode(selectedMode()); + element.innerHTML = ''; + options.forEach(function(value) { + var option = document.createElement('option'); + option.value = value; + option.textContent = tKey('wizard.streaming.transport.' + value); + element.appendChild(option); + }); + if (preferredValue && options.indexOf(preferredValue) >= 0) { + element.value = preferredValue; + } else if (options.length) { + element.value = options[0]; + } + } + + function updateStreamingModeOptions(preferredValue) { + var element = document.getElementById('streaming-mode'); + if (!element) return; + var options = modeOptionsForProtocol(); + element.innerHTML = ''; + options.forEach(function(value) { + var option = document.createElement('option'); + option.value = value; + option.textContent = tKey('wizard.streaming.mode.' + value); + element.appendChild(option); + }); + if (preferredValue && options.indexOf(preferredValue) >= 0) { + element.value = preferredValue; + } else { + element.value = options.indexOf('unary') >= 0 ? 'unary' : (options[0] || 'unary'); + } + updateStreamingTransportOptions(); + } + + function ensureStreamingToolFamilyDefaults(mode) { + var base = text('tool-name') || 'stream_tool'; + if (mode === 'session') { + if (!text('streaming-start-tool-name')) set('streaming-start-tool-name', base + '_start'); + if (!text('streaming-poll-tool-name')) set('streaming-poll-tool-name', base + '_poll'); + if (!text('streaming-stop-tool-name')) set('streaming-stop-tool-name', base + '_stop'); + } + if (mode === 'async_job') { + if (!text('streaming-start-tool-name')) set('streaming-start-tool-name', base + '_start'); + if (!text('streaming-status-tool-name')) set('streaming-status-tool-name', base + '_status'); + if (!text('streaming-result-tool-name')) set('streaming-result-tool-name', base + '_result'); + if (!text('streaming-cancel-tool-name')) set('streaming-cancel-tool-name', base + '_cancel'); + } + } + + function updateStreamingConfigVisibility() { + var mode = selectedMode(); + var card = document.getElementById('wizard-streaming-config-card'); + var help = document.getElementById('streaming-mode-help'); + var toolFamily = document.getElementById('streaming-tool-family-block'); + var asyncRow = document.getElementById('streaming-async-tool-family-row'); + if (!card) return; + + var isUnary = mode === 'unary'; + var isSession = mode === 'session'; + var isAsyncJob = mode === 'async_job'; + + [ + 'streaming-window-duration-ms', + 'streaming-poll-interval-ms', + 'streaming-upstream-timeout-ms', + 'streaming-idle-timeout-ms', + 'streaming-session-lifetime-ms', + 'streaming-max-items', + 'streaming-max-bytes', + 'streaming-max-field-length', + 'streaming-sampling-rate', + 'streaming-items-path', + 'streaming-summary-path', + 'streaming-done-path', + 'streaming-cursor-path', + 'streaming-status-path', + 'streaming-redacted-paths', + 'streaming-truncate-item-fields', + 'streaming-drop-duplicates' + ].forEach(function(id) { + var node = document.getElementById(id); + if (!node) return; + var group = node.closest('.form-group') || node.closest('.checkbox-pill'); + if (group) { + group.hidden = isUnary; + } + }); + + if (help) { + help.textContent = isUnary + ? tKey('wizard.streaming.help.unary') + : (isSession + ? tKey('wizard.streaming.help.session') + : (isAsyncJob + ? tKey('wizard.streaming.help.async_job') + : tKey('wizard.streaming.help.window'))); + } + + if (toolFamily) toolFamily.hidden = !(isSession || isAsyncJob); + if (asyncRow) asyncRow.hidden = !isAsyncJob; + + ensureStreamingToolFamilyDefaults(mode); + } + + function bindStreamingConfigControls() { + updateStreamingModeOptions(); + updateStreamingConfigVisibility(); + + var mode = document.getElementById('streaming-mode'); + if (mode) { + mode.addEventListener('change', function() { + updateStreamingTransportOptions(); + updateStreamingConfigVisibility(); + }); + } + } + function serializeStreamingConfig() { if (selectedMode() === 'unary') { return null; @@ -116,6 +274,49 @@ } window.CrankStreamingForm = { + selectedStreamingMode: selectedMode, + bindStreamingConfigControls: bindStreamingConfigControls, + collectStreamingConfig: serializeStreamingConfig, + applyStreamingConfig: function(streaming) { + updateStreamingModeOptions(streaming && streaming.mode ? streaming.mode : 'unary'); + if (!streaming) { + updateStreamingConfigVisibility(); + return; + } + + if (streaming.window_duration_ms != null) set('streaming-window-duration-ms', String(streaming.window_duration_ms)); + if (streaming.poll_interval_ms != null) set('streaming-poll-interval-ms', String(streaming.poll_interval_ms)); + if (streaming.upstream_timeout_ms != null) set('streaming-upstream-timeout-ms', String(streaming.upstream_timeout_ms)); + if (streaming.idle_timeout_ms != null) set('streaming-idle-timeout-ms', String(streaming.idle_timeout_ms)); + if (streaming.max_session_lifetime_ms != null) set('streaming-session-lifetime-ms', String(streaming.max_session_lifetime_ms)); + if (streaming.max_items != null) set('streaming-max-items', String(streaming.max_items)); + if (streaming.max_bytes != null) set('streaming-max-bytes', String(streaming.max_bytes)); + if (streaming.max_field_length != null) set('streaming-max-field-length', String(streaming.max_field_length)); + if (streaming.sampling_rate != null) set('streaming-sampling-rate', String(streaming.sampling_rate)); + set('streaming-items-path', streaming.items_path || ''); + set('streaming-summary-path', streaming.summary_path || ''); + set('streaming-done-path', streaming.done_path || ''); + set('streaming-cursor-path', streaming.cursor_path || ''); + set('streaming-status-path', streaming.status_path || ''); + set('streaming-redacted-paths', (streaming.redacted_paths || []).join('\n')); + var truncate = document.getElementById('streaming-truncate-item-fields'); + if (truncate) truncate.checked = !!streaming.truncate_item_fields; + var dedupe = document.getElementById('streaming-drop-duplicates'); + if (dedupe) dedupe.checked = !!streaming.drop_duplicates; + set('streaming-aggregation-mode', streaming.aggregation_mode || 'summary_plus_samples'); + + updateStreamingTransportOptions(streaming.transport_behavior); + + var toolFamily = streaming.tool_family || {}; + set('streaming-start-tool-name', toolFamily.start_tool_name || ''); + set('streaming-poll-tool-name', toolFamily.poll_tool_name || ''); + set('streaming-stop-tool-name', toolFamily.stop_tool_name || ''); + set('streaming-status-tool-name', toolFamily.status_tool_name || ''); + set('streaming-result-tool-name', toolFamily.result_tool_name || ''); + set('streaming-cancel-tool-name', toolFamily.cancel_tool_name || ''); + + updateStreamingConfigVisibility(); + }, serializeStreamingConfig: serializeStreamingConfig, deserializeStreamingConfig: function(streaming) { if (typeof window.applyStreamingConfig === 'function') { diff --git a/apps/ui/js/wizard.js b/apps/ui/js/wizard.js index 22ceede..9855951 100644 --- a/apps/ui/js/wizard.js +++ b/apps/ui/js/wizard.js @@ -13,6 +13,9 @@ var _doGoToStep = window.CrankWizardShell.doGoToStep; var loadWizardPanels = window.CrankWizardShell.loadWizardPanels; var bindProtocolCards = window.CrankWizardShell.bindProtocolCards; var step3PanelId = window.CrankWizardShell.step3PanelId; +var bindStreamingConfigControls = window.CrankStreamingForm.bindStreamingConfigControls; +var collectStreamingConfig = window.CrankStreamingForm.collectStreamingConfig; +var applyStreamingConfig = window.CrankStreamingForm.applyStreamingConfig; var currentStep = window.currentStep; var wizardProtocol = window.wizardProtocol; var wizardMode = window.wizardMode; @@ -612,243 +615,6 @@ function textareaLines(id) { .filter(Boolean); } -function selectedStreamingMode() { - var element = document.getElementById('streaming-mode'); - return element ? element.value : 'unary'; -} - -function transportOptionsForMode(mode) { - var capabilities = currentProtocolCapabilities(); - var behaviors = (capabilities.supports_transport_behaviors || []).slice(); - if (mode === 'unary') return behaviors.filter(function(value) { return value === 'request_response'; }); - if (mode === 'window') return behaviors.filter(function(value) { - return value === 'request_response' || value === 'server_stream'; - }); - if (mode === 'session') return behaviors.filter(function(value) { - return value === 'server_stream' || value === 'stateful_session'; - }); - if (mode === 'async_job') return behaviors.filter(function(value) { - return value === 'deferred_result'; - }); - return behaviors; -} - -function modeOptionsForProtocol() { - var capabilities = currentProtocolCapabilities(); - return (capabilities.supports_execution_modes || ['unary']).filter(function(mode) { - return transportOptionsForMode(mode).length > 0 || mode === 'unary'; - }); -} - -function updateStreamingTransportOptions(preferredValue) { - var element = document.getElementById('streaming-transport-behavior'); - if (!element) return; - var options = transportOptionsForMode(selectedStreamingMode()); - element.innerHTML = ''; - options.forEach(function(value) { - var option = document.createElement('option'); - option.value = value; - option.textContent = tKey('wizard.streaming.transport.' + value); - element.appendChild(option); - }); - if (preferredValue && options.indexOf(preferredValue) >= 0) { - element.value = preferredValue; - } else if (options.length) { - element.value = options[0]; - } -} - -function updateStreamingModeOptions(preferredValue) { - var element = document.getElementById('streaming-mode'); - if (!element) return; - var options = modeOptionsForProtocol(); - element.innerHTML = ''; - options.forEach(function(value) { - var option = document.createElement('option'); - option.value = value; - option.textContent = tKey('wizard.streaming.mode.' + value); - element.appendChild(option); - }); - if (preferredValue && options.indexOf(preferredValue) >= 0) { - element.value = preferredValue; - } else { - element.value = options.indexOf('unary') >= 0 ? 'unary' : (options[0] || 'unary'); - } - updateStreamingTransportOptions(); -} - -function ensureStreamingToolFamilyDefaults(mode) { - var base = textValue('tool-name') || 'stream_tool'; - if (mode === 'session') { - if (!textValue('streaming-start-tool-name')) setValue('streaming-start-tool-name', base + '_start'); - if (!textValue('streaming-poll-tool-name')) setValue('streaming-poll-tool-name', base + '_poll'); - if (!textValue('streaming-stop-tool-name')) setValue('streaming-stop-tool-name', base + '_stop'); - } - if (mode === 'async_job') { - if (!textValue('streaming-start-tool-name')) setValue('streaming-start-tool-name', base + '_start'); - if (!textValue('streaming-status-tool-name')) setValue('streaming-status-tool-name', base + '_status'); - if (!textValue('streaming-result-tool-name')) setValue('streaming-result-tool-name', base + '_result'); - if (!textValue('streaming-cancel-tool-name')) setValue('streaming-cancel-tool-name', base + '_cancel'); - } -} - -function updateStreamingConfigVisibility() { - var mode = selectedStreamingMode(); - var card = document.getElementById('wizard-streaming-config-card'); - var help = document.getElementById('streaming-mode-help'); - var toolFamily = document.getElementById('streaming-tool-family-block'); - var asyncRow = document.getElementById('streaming-async-tool-family-row'); - if (!card) return; - - var isUnary = mode === 'unary'; - var isWindow = mode === 'window'; - var isSession = mode === 'session'; - var isAsyncJob = mode === 'async_job'; - - [ - 'streaming-window-duration-ms', - 'streaming-poll-interval-ms', - 'streaming-upstream-timeout-ms', - 'streaming-idle-timeout-ms', - 'streaming-session-lifetime-ms', - 'streaming-max-items', - 'streaming-max-bytes', - 'streaming-max-field-length', - 'streaming-sampling-rate', - 'streaming-items-path', - 'streaming-summary-path', - 'streaming-done-path', - 'streaming-cursor-path', - 'streaming-status-path', - 'streaming-redacted-paths', - 'streaming-truncate-item-fields', - 'streaming-drop-duplicates' - ].forEach(function(id) { - var node = document.getElementById(id); - if (!node) return; - var group = node.closest('.form-group') || node.closest('.checkbox-pill'); - if (group) { - group.hidden = isUnary; - } - }); - - if (help) { - help.textContent = isUnary - ? tKey('wizard.streaming.help.unary') - : (isSession - ? tKey('wizard.streaming.help.session') - : (isAsyncJob - ? tKey('wizard.streaming.help.async_job') - : tKey('wizard.streaming.help.window'))); - } - - if (toolFamily) toolFamily.hidden = !(isSession || isAsyncJob); - if (asyncRow) asyncRow.hidden = !isAsyncJob; - - ensureStreamingToolFamilyDefaults(mode); -} - -function bindStreamingConfigControls() { - updateStreamingModeOptions(); - updateStreamingConfigVisibility(); - - var mode = document.getElementById('streaming-mode'); - if (mode) { - mode.addEventListener('change', function() { - updateStreamingTransportOptions(); - updateStreamingConfigVisibility(); - }); - } -} - -function collectStreamingConfig() { - var mode = selectedStreamingMode(); - if (mode === 'unary') return null; - - var config = { - mode: mode, - transport_behavior: stringValueOrNull('streaming-transport-behavior') || 'request_response', - window_duration_ms: numericValueOrNull('streaming-window-duration-ms'), - poll_interval_ms: numericValueOrNull('streaming-poll-interval-ms'), - upstream_timeout_ms: numericValueOrNull('streaming-upstream-timeout-ms'), - idle_timeout_ms: numericValueOrNull('streaming-idle-timeout-ms'), - max_session_lifetime_ms: numericValueOrNull('streaming-session-lifetime-ms'), - max_items: numericValueOrNull('streaming-max-items'), - max_bytes: numericValueOrNull('streaming-max-bytes'), - aggregation_mode: stringValueOrNull('streaming-aggregation-mode') || 'summary_plus_samples', - summary_path: stringValueOrNull('streaming-summary-path'), - items_path: stringValueOrNull('streaming-items-path'), - cursor_path: stringValueOrNull('streaming-cursor-path'), - status_path: stringValueOrNull('streaming-status-path'), - done_path: stringValueOrNull('streaming-done-path'), - redacted_paths: textareaLines('streaming-redacted-paths'), - truncate_item_fields: !!document.getElementById('streaming-truncate-item-fields').checked, - max_field_length: numericValueOrNull('streaming-max-field-length'), - drop_duplicates: !!document.getElementById('streaming-drop-duplicates').checked, - sampling_rate: (function() { - var value = textValue('streaming-sampling-rate'); - if (!value) return null; - var parsed = Number(value); - return Number.isFinite(parsed) ? parsed : null; - }()), - tool_family: {}, - }; - - if (mode === 'session') { - config.tool_family.start_tool_name = stringValueOrNull('streaming-start-tool-name'); - config.tool_family.poll_tool_name = stringValueOrNull('streaming-poll-tool-name'); - config.tool_family.stop_tool_name = stringValueOrNull('streaming-stop-tool-name'); - } else if (mode === 'async_job') { - config.tool_family.start_tool_name = stringValueOrNull('streaming-start-tool-name'); - config.tool_family.status_tool_name = stringValueOrNull('streaming-status-tool-name'); - config.tool_family.result_tool_name = stringValueOrNull('streaming-result-tool-name'); - config.tool_family.cancel_tool_name = stringValueOrNull('streaming-cancel-tool-name'); - } - - Object.keys(config).forEach(function(key) { - if (config[key] === null) delete config[key]; - }); - if (!config.redacted_paths.length) delete config.redacted_paths; - - return config; -} - -function applyStreamingConfig(streaming) { - updateStreamingModeOptions(streaming && streaming.mode ? streaming.mode : 'unary'); - if (!streaming) { - updateStreamingConfigVisibility(); - return; - } - - setValue('streaming-window-duration-ms', streaming.window_duration_ms || ''); - setValue('streaming-poll-interval-ms', streaming.poll_interval_ms || ''); - setValue('streaming-upstream-timeout-ms', streaming.upstream_timeout_ms || ''); - setValue('streaming-idle-timeout-ms', streaming.idle_timeout_ms || ''); - setValue('streaming-session-lifetime-ms', streaming.max_session_lifetime_ms || ''); - setValue('streaming-max-items', streaming.max_items || ''); - setValue('streaming-max-bytes', streaming.max_bytes || ''); - setValue('streaming-max-field-length', streaming.max_field_length || ''); - setValue('streaming-sampling-rate', streaming.sampling_rate || ''); - setValue('streaming-items-path', streaming.items_path || ''); - setValue('streaming-summary-path', streaming.summary_path || ''); - setValue('streaming-done-path', streaming.done_path || ''); - setValue('streaming-cursor-path', streaming.cursor_path || ''); - setValue('streaming-status-path', streaming.status_path || ''); - setValue('streaming-redacted-paths', (streaming.redacted_paths || []).join('\n')); - document.getElementById('streaming-truncate-item-fields').checked = !!streaming.truncate_item_fields; - document.getElementById('streaming-drop-duplicates').checked = !!streaming.drop_duplicates; - updateStreamingTransportOptions(streaming.transport_behavior); - setValue('streaming-start-tool-name', streaming.tool_family && streaming.tool_family.start_tool_name ? streaming.tool_family.start_tool_name : ''); - setValue('streaming-poll-tool-name', streaming.tool_family && streaming.tool_family.poll_tool_name ? streaming.tool_family.poll_tool_name : ''); - setValue('streaming-stop-tool-name', streaming.tool_family && streaming.tool_family.stop_tool_name ? streaming.tool_family.stop_tool_name : ''); - setValue('streaming-status-tool-name', streaming.tool_family && streaming.tool_family.status_tool_name ? streaming.tool_family.status_tool_name : ''); - setValue('streaming-result-tool-name', streaming.tool_family && streaming.tool_family.result_tool_name ? streaming.tool_family.result_tool_name : ''); - setValue('streaming-cancel-tool-name', streaming.tool_family && streaming.tool_family.cancel_tool_name ? streaming.tool_family.cancel_tool_name : ''); - var aggregation = document.getElementById('streaming-aggregation-mode'); - if (aggregation && streaming.aggregation_mode) aggregation.value = streaming.aggregation_mode; - updateStreamingConfigVisibility(); -} - function buildToolDescription() { return { title: textValue('tool-title') || textValue('tool-display-name') || textValue('tool-name'),