ui: gate community wizard capabilities

This commit is contained in:
a.tolmachev
2026-05-03 17:11:30 +00:00
parent 10433d5193
commit 49c46c0d0b
14 changed files with 221 additions and 225 deletions
+12
View File
@@ -575,6 +575,8 @@ var TRANSLATIONS = {
'wizard.step1.unary': 'Unary',
'wizard.step1.tip_title': 'You can change this later',
'wizard.step1.tip_body': 'Switching protocol after configuring subsequent steps will clear schema and mapping data. Save your operation as a draft before experimenting. See protocol migration guide for details.',
'wizard.step1.community_protocol_title': 'Community protocol scope',
'wizard.step1.community_protocol_note': 'This Community build hides {protocols}. Commercial editions unlock those protocol surfaces.',
'wizard.step2.title': 'Select upstream & endpoint',
'wizard.step2.subtitle': 'Choose an existing upstream or register a new one. Then define the specific endpoint path this operation will call.',
'wizard.required': 'Required',
@@ -762,6 +764,8 @@ var TRANSLATIONS = {
'wizard.step5.execution': 'Execution',
'wizard.step5.exec_title': 'Execution config',
'wizard.step5.exec_subtitle': 'Timeouts, retry policy and auth profile reference',
'wizard.step5.security_level_title': 'Operation security in Community',
'wizard.step5.community_security_note': 'Community supports only the standard operation security level with static AI-agent keys. Short-lived and one-time token flows require a commercial edition.',
'wizard.step5.live_title': 'Live validation and publishing',
'wizard.step5.draft_actions': 'Draft actions',
'wizard.step5.live_save_title': 'Live actions save the draft first',
@@ -931,6 +935,8 @@ var TRANSLATIONS = {
'agents.title': 'Agents',
'agents.subtitle': 'Named MCP endpoints that expose a curated subset of operations to an LLM',
'agents.new': 'New agent',
'agents.limit.title': 'Agent limit reached',
'agents.limit.message': 'This Community build allows up to {limit} AI agent. Upgrade the edition or remove an existing agent to add another one.',
'agents.stats.total': 'Total agents',
'agents.stats.total_sub': 'across this workspace',
'agents.stats.published': 'Published',
@@ -1623,6 +1629,8 @@ var TRANSLATIONS = {
'wizard.step1.unary': 'Unary',
'wizard.step1.tip_title': 'Это можно изменить позже',
'wizard.step1.tip_body': 'Смена протокола после настройки следующих шагов очистит схемы и mapping. Сохраните операцию как черновик перед экспериментами. См. гайд по миграции протоколов.',
'wizard.step1.community_protocol_title': 'Граница протоколов Community',
'wizard.step1.community_protocol_note': 'В этой Community-сборке скрыты {protocols}. Эти протокольные поверхности открываются в коммерческих редакциях.',
'wizard.step2.title': 'Выберите upstream и endpoint',
'wizard.step2.subtitle': 'Выберите существующий upstream или зарегистрируйте новый. Затем задайте конкретный путь endpoint-а для этой операции.',
'wizard.required': 'Обязательно',
@@ -1812,6 +1820,8 @@ var TRANSLATIONS = {
'wizard.step5.execution': 'Исполнение',
'wizard.step5.exec_title': 'Execution config',
'wizard.step5.exec_subtitle': 'Таймауты, retry policy и ссылка на auth profile',
'wizard.step5.security_level_title': 'Защита операций в Community',
'wizard.step5.community_security_note': 'Community поддерживает только стандартный уровень защиты операций со статическими ключами AI-агента. Короткоживущие и одноразовые токены требуют коммерческую редакцию.',
'wizard.step5.live_title': 'Live-проверка и публикация',
'wizard.step5.draft_actions': 'Действия черновика',
'wizard.step5.live_save_title': 'Live-действия сначала сохраняют черновик',
@@ -1985,6 +1995,8 @@ var TRANSLATIONS = {
'agents.title': 'Агенты',
'agents.subtitle': 'Именованные MCP endpoint-ы, открывающие LLM ограниченный набор операций',
'agents.new': 'Новый агент',
'agents.limit.title': 'Достигнут лимит агентов',
'agents.limit.message': 'В этой Community-сборке доступно не более {limit} AI-агента. Чтобы добавить еще одного, удалите существующего агента или перейдите на другую редакцию.',
'agents.stats.total': 'Всего агентов',
'agents.stats.total_sub': 'в этом воркспейсе',
'agents.stats.published': 'Опубликованы',
+54
View File
@@ -175,6 +175,9 @@
function bindProtocolCards() {
document.querySelectorAll('.protocol-card').forEach(function(card) {
card.addEventListener('click', function() {
if (card.hidden || card.getAttribute('aria-disabled') === 'true') {
return;
}
document.querySelectorAll('.protocol-card').forEach(function(item) {
item.classList.remove('selected');
item.setAttribute('aria-checked', 'false');
@@ -214,6 +217,56 @@
});
}
function applyEditionProtocolVisibility(capabilities) {
var supported = capabilities && Array.isArray(capabilities.supported_protocols)
? capabilities.supported_protocols.slice()
: ['rest', 'graphql', 'grpc'];
var hiddenProtocols = [];
document.querySelectorAll('.protocol-card').forEach(function(card) {
var protocol = card.dataset.protocol || 'rest';
var isSupported = supported.indexOf(protocol) >= 0;
card.hidden = !isSupported;
card.setAttribute('aria-disabled', isSupported ? 'false' : 'true');
if (!isSupported) {
card.classList.remove('selected');
card.setAttribute('aria-checked', 'false');
hiddenProtocols.push(protocol);
}
});
if (supported.indexOf(window.wizardProtocol) === -1) {
window.wizardProtocol = supported[0] || 'rest';
}
var selectedCard = document.querySelector('.protocol-card[data-protocol="' + window.wizardProtocol + '"]');
if (selectedCard) {
selectedCard.classList.add('selected');
selectedCard.setAttribute('aria-checked', 'true');
}
var step3Name = document.getElementById('sidebar-step-3-name');
var labels = window.CrankWizardState.step3Labels();
if (step3Name) {
step3Name.textContent = labels[window.wizardProtocol] || tKey('wizard.step3.rest.label');
}
var note = document.getElementById('wizard-edition-protocol-note');
var noteText = document.getElementById('wizard-edition-protocol-note-text');
if (note && noteText) {
if (hiddenProtocols.length) {
note.hidden = false;
noteText.textContent = tfKey('wizard.step1.community_protocol_note', {
protocols: hiddenProtocols.map(function(protocol) {
return tKey('settings.capability.' + protocol);
}).join(', ')
});
} else {
note.hidden = true;
}
}
}
window.CrankWizardShell = {
TOTAL_STEPS: TOTAL_STEPS,
step3PanelId: step3PanelId,
@@ -222,5 +275,6 @@
goToStep: goToStep,
loadWizardPanels: loadWizardPanels,
bindProtocolCards: bindProtocolCards,
applyEditionProtocolVisibility: applyEditionProtocolVisibility,
};
}());
+37
View File
@@ -19,6 +19,7 @@
grpcDescriptorServices: [],
soapServiceCatalog: [],
wizardProtocolCapabilities: null,
wizardEditionCapabilities: null,
wizardSecrets: [],
wizardAuthProfiles: [],
selectedUpstreamId: null,
@@ -68,11 +69,29 @@
};
}
function defaultEditionCapabilities() {
return {
edition: 'community',
supported_protocols: ['rest', 'graphql', 'grpc'],
supported_security_levels: ['standard'],
machine_access_modes: ['static_agent_key'],
limits: {
max_workspaces: 1,
max_users_per_workspace: 1,
max_agents_per_workspace: 1,
},
};
}
function currentProtocolCapabilities() {
var capabilities = window.wizardProtocolCapabilities || defaultProtocolCapabilities();
return capabilities[window.wizardProtocol] || capabilities.rest;
}
function currentEditionCapabilities() {
return window.wizardEditionCapabilities || defaultEditionCapabilities();
}
async function loadProtocolCapabilities() {
if (!window.wizardWorkspaceId || !window.CrankApi || typeof window.CrankApi.getProtocolCapabilities !== 'function') {
window.wizardProtocolCapabilities = defaultProtocolCapabilities();
@@ -93,6 +112,21 @@
return window.wizardProtocolCapabilities;
}
async function loadEditionCapabilities() {
if (!window.CrankApi || typeof window.CrankApi.getCapabilities !== 'function') {
window.wizardEditionCapabilities = defaultEditionCapabilities();
return window.wizardEditionCapabilities;
}
try {
window.wizardEditionCapabilities = await window.CrankApi.getCapabilities();
} catch (_error) {
window.wizardEditionCapabilities = defaultEditionCapabilities();
}
return window.wizardEditionCapabilities;
}
function step3Labels() {
return {
rest: tKey('wizard.step3.rest.label'),
@@ -106,8 +140,11 @@
window.CrankWizardState = {
state: window,
defaultProtocolCapabilities: defaultProtocolCapabilities,
defaultEditionCapabilities: defaultEditionCapabilities,
currentProtocolCapabilities: currentProtocolCapabilities,
currentEditionCapabilities: currentEditionCapabilities,
loadProtocolCapabilities: loadProtocolCapabilities,
loadEditionCapabilities: loadEditionCapabilities,
step3Labels: step3Labels,
};
}());
+18
View File
@@ -6,12 +6,14 @@ function tfKey(key, vars) {
}
var TOTAL_STEPS = window.CrankWizardShell.TOTAL_STEPS;
var loadProtocolCapabilities = window.CrankWizardState.loadProtocolCapabilities;
var loadEditionCapabilities = window.CrankWizardState.loadEditionCapabilities;
var currentProtocolCapabilities = window.CrankWizardState.currentProtocolCapabilities;
var loadStep = window.CrankWizardShell.loadStep;
var goToStep = window.CrankWizardShell.goToStep;
var _doGoToStep = window.CrankWizardShell.doGoToStep;
var loadWizardPanels = window.CrankWizardShell.loadWizardPanels;
var bindProtocolCards = window.CrankWizardShell.bindProtocolCards;
var applyEditionProtocolVisibility = window.CrankWizardShell.applyEditionProtocolVisibility;
var step3PanelId = window.CrankWizardShell.step3PanelId;
var bindStreamingConfigControls = window.CrankStreamingForm.bindStreamingConfigControls;
var collectStreamingConfig = window.CrankStreamingForm.collectStreamingConfig;
@@ -85,14 +87,17 @@ async function initWizardPage() {
var workspace = window.getCurrentWorkspace ? window.getCurrentWorkspace() : null;
wizardWorkspaceId = workspace ? workspace.id : null;
window.wizardWorkspaceId = wizardWorkspaceId;
var editionCapabilities = await loadEditionCapabilities();
await loadProtocolCapabilities();
await loadWizardPanels([1, 2, 3, 4, 5]);
applyEditionProtocolVisibility(editionCapabilities);
await loadWizardAuthResources();
bindProtocolCards();
bindWizardLiveActions();
bindStreamingConfigControls();
updateUpstreamAuthUi();
renderEditionCapabilityHints(editionCapabilities);
var quickSecretModal = document.getElementById('quick-secret-modal');
var quickSecretClose = document.getElementById('quick-secret-close-btn');
@@ -141,6 +146,19 @@ async function initWizardPage() {
_doGoToStep(1);
}
function renderEditionCapabilityHints(capabilities) {
var securityNote = document.getElementById('wizard-security-level-note');
var securityText = securityNote ? securityNote.querySelector('.info-callout-text') : null;
if (!securityText) return;
var levels = capabilities && Array.isArray(capabilities.supported_security_levels)
? capabilities.supported_security_levels
: ['standard'];
securityNote.hidden = !(levels.length === 1 && levels[0] === 'standard');
if (!securityNote.hidden) {
securityText.textContent = tKey('wizard.step5.community_security_note');
}
}
if (window.CrankDiagnostics && typeof window.CrankDiagnostics.bootstrap === 'function') {
window.CrankDiagnostics.bootstrap('wizard', initWizardPage);
} else {