feat: add streaming ui configuration
This commit is contained in:
@@ -10,6 +10,7 @@ var wizardProtoUpload = null;
|
||||
var wizardDescriptorSetUpload = null;
|
||||
var wizardTestResponsePreview = null;
|
||||
var grpcDescriptorServices = [];
|
||||
var wizardProtocolCapabilities = null;
|
||||
function tKey(key) {
|
||||
return typeof t === 'function' ? t(key) : key;
|
||||
}
|
||||
@@ -17,6 +18,48 @@ function tfKey(key, vars) {
|
||||
return typeof tf === 'function' ? tf(key, vars) : key;
|
||||
}
|
||||
|
||||
function defaultProtocolCapabilities() {
|
||||
return {
|
||||
rest: {
|
||||
supports_execution_modes: ['unary', 'window', 'session', 'async_job'],
|
||||
supports_transport_behaviors: ['request_response', 'server_stream', 'deferred_result'],
|
||||
},
|
||||
graphql: {
|
||||
supports_execution_modes: ['unary'],
|
||||
supports_transport_behaviors: ['request_response'],
|
||||
},
|
||||
grpc: {
|
||||
supports_execution_modes: ['unary', 'window', 'session', 'async_job'],
|
||||
supports_transport_behaviors: ['request_response', 'server_stream'],
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function currentProtocolCapabilities() {
|
||||
var capabilities = wizardProtocolCapabilities || defaultProtocolCapabilities();
|
||||
return capabilities[wizardProtocol] || capabilities.rest;
|
||||
}
|
||||
|
||||
async function loadProtocolCapabilities() {
|
||||
if (!wizardWorkspaceId || !window.CrankApi || typeof window.CrankApi.getProtocolCapabilities !== 'function') {
|
||||
wizardProtocolCapabilities = defaultProtocolCapabilities();
|
||||
return wizardProtocolCapabilities;
|
||||
}
|
||||
|
||||
try {
|
||||
var response = await window.CrankApi.getProtocolCapabilities(wizardWorkspaceId);
|
||||
var mapped = {};
|
||||
(response.items || []).forEach(function(item) {
|
||||
mapped[item.protocol] = item;
|
||||
});
|
||||
wizardProtocolCapabilities = mapped;
|
||||
} catch (_error) {
|
||||
wizardProtocolCapabilities = defaultProtocolCapabilities();
|
||||
}
|
||||
|
||||
return wizardProtocolCapabilities;
|
||||
}
|
||||
|
||||
/* ── Dynamic step loading ── */
|
||||
function _stepFile(n) {
|
||||
return (n === 3) ? 'step3-' + wizardProtocol + '.html' : 'step' + n + '.html';
|
||||
@@ -222,10 +265,12 @@ document.addEventListener('DOMContentLoaded', async function() {
|
||||
await (window.whenWorkspacesReady ? window.whenWorkspacesReady() : Promise.resolve());
|
||||
var workspace = window.getCurrentWorkspace ? window.getCurrentWorkspace() : null;
|
||||
wizardWorkspaceId = workspace ? workspace.id : null;
|
||||
await loadProtocolCapabilities();
|
||||
|
||||
await loadWizardPanels([1, 2, 3, 4, 5]);
|
||||
bindProtocolCards();
|
||||
bindWizardLiveActions();
|
||||
bindStreamingConfigControls();
|
||||
|
||||
var params = new URLSearchParams(window.location.search);
|
||||
if (params.get('mode') === 'edit' && params.get('operationId')) {
|
||||
@@ -1092,6 +1137,12 @@ function buildMappingSet(rawValue, mode) {
|
||||
}
|
||||
|
||||
function parseExecutionConfig(text) {
|
||||
if (window.CrankStreamingForm && typeof window.CrankStreamingForm.validateStreamingConfig === 'function') {
|
||||
var validation = window.CrankStreamingForm.validateStreamingConfig([currentProtocolCapabilities()]);
|
||||
if (!validation.valid) {
|
||||
throw new Error(validation.errors[0]);
|
||||
}
|
||||
}
|
||||
var value = parseStructuredText(text);
|
||||
var retry = value.retry || value.retry_policy || null;
|
||||
var headers = value.headers && typeof value.headers === 'object' ? value.headers : {};
|
||||
@@ -1113,6 +1164,8 @@ function parseExecutionConfig(text) {
|
||||
config.protocol_options = { grpc: { use_tls: useTls } };
|
||||
}
|
||||
|
||||
config.streaming = collectStreamingConfig();
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
@@ -1236,6 +1289,264 @@ function parseHeaderMap(text) {
|
||||
return value && typeof value === 'object' ? value : {};
|
||||
}
|
||||
|
||||
function numericValueOrNull(id) {
|
||||
var value = textValue(id);
|
||||
if (!value) return null;
|
||||
var parsed = Number(value);
|
||||
return Number.isFinite(parsed) && parsed > 0 ? parsed : null;
|
||||
}
|
||||
|
||||
function stringValueOrNull(id) {
|
||||
var value = textValue(id);
|
||||
return value ? value : null;
|
||||
}
|
||||
|
||||
function textareaLines(id) {
|
||||
var value = textValue(id);
|
||||
if (!value) return [];
|
||||
return value
|
||||
.split(/\r?\n/)
|
||||
.map(function(line) { return line.trim(); })
|
||||
.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.style.display = isUnary ? 'none' : '';
|
||||
}
|
||||
});
|
||||
|
||||
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.style.display = (isSession || isAsyncJob) ? '' : 'none';
|
||||
if (asyncRow) asyncRow.style.display = isAsyncJob ? '' : 'none';
|
||||
|
||||
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'),
|
||||
@@ -1439,6 +1750,7 @@ function prefillWizardFromEdit(detail, versionDocument) {
|
||||
setValue('tool-input-mapping', mappingSetToEditorValue(versionDocument.input_mapping, 'input', detail.protocol));
|
||||
setValue('tool-output-mapping', mappingSetToEditorValue(versionDocument.output_mapping, 'output', detail.protocol));
|
||||
setValue('tool-exec-config', executionConfigToEditorValue(versionDocument.execution_config));
|
||||
applyStreamingConfig(versionDocument.execution_config ? versionDocument.execution_config.streaming : null);
|
||||
|
||||
var toolNameInput = document.getElementById('tool-name');
|
||||
if (toolNameInput) toolNameInput.disabled = true;
|
||||
@@ -1525,6 +1837,8 @@ async function runWizardLiveAction(button, busyLabel, handler) {
|
||||
function updateWizardProtocolVisibility() {
|
||||
var grpcTools = document.getElementById('wizard-grpc-live-tools');
|
||||
if (grpcTools) grpcTools.style.display = wizardProtocol === 'grpc' ? '' : 'none';
|
||||
updateStreamingModeOptions();
|
||||
updateStreamingConfigVisibility();
|
||||
}
|
||||
|
||||
function showWizardLiveStatus(title, text, isError) {
|
||||
|
||||
Reference in New Issue
Block a user