diff --git a/TASKS.md b/TASKS.md index 0d8c5de..ab42975 100644 --- a/TASKS.md +++ b/TASKS.md @@ -31,8 +31,10 @@ Implementation slices: Progress: - done: shared capability payload exists in `crank-core` and `admin-api`; - done: authenticated `/api/admin/capabilities` exposes Community defaults to UI; -- in_progress: first UI consumer uses capability payload in `Settings`; -- pending: gate premium protocols and security levels in wizard and agents flows. +- done: first UI consumer uses capability payload in `Settings`; +- done: `protocol-capabilities` is edition-aware and Community wizard hides premium protocol cards; +- in_progress: surface Community-only security guidance inside wizard flow; +- pending: add server-side validation so unsupported protocol and security-level drafts are rejected, not only hidden in UI. DoD: - UI знает, какие функции входят в текущую редакцию; diff --git a/apps/admin-api/src/app.rs b/apps/admin-api/src/app.rs index eb0f263..b7d986f 100644 --- a/apps/admin-api/src/app.rs +++ b/apps/admin-api/src/app.rs @@ -1038,6 +1038,35 @@ mod tests { assert_eq!(response["limits"]["max_agents_per_workspace"], 1); } + #[tokio::test(flavor = "multi_thread")] + #[serial] + async fn returns_community_protocol_capabilities_only_for_supported_protocols() { + let registry = test_registry().await; + let storage_root = test_storage_root("community_protocol_capabilities"); + let base_url = spawn_admin_api(build_test_app(registry, storage_root)).await; + let client = authorized_client(&base_url).await; + + let response = assert_success_json( + client + .get(format!("{base_url}/protocol-capabilities")) + .send() + .await + .unwrap(), + ) + .await; + + assert_eq!(response["items"].as_array().unwrap().len(), 3); + assert_eq!( + response["items"] + .as_array() + .unwrap() + .iter() + .map(|item| item["protocol"].as_str().unwrap()) + .collect::>(), + vec!["rest", "graphql", "grpc"] + ); + } + #[tokio::test(flavor = "multi_thread")] #[serial] async fn manages_workspace_access_lifecycle() { diff --git a/apps/admin-api/src/service.rs b/apps/admin-api/src/service.rs index 2cf15f7..8306c80 100644 --- a/apps/admin-api/src/service.rs +++ b/apps/admin-api/src/service.rs @@ -1556,16 +1556,12 @@ impl AdminService { } pub async fn list_protocol_capabilities(&self) -> Vec { - [ - Protocol::Rest, - Protocol::Graphql, - Protocol::Grpc, - Protocol::Websocket, - Protocol::Soap, - ] - .into_iter() - .map(protocol_capability_view) - .collect() + self.get_capabilities() + .await + .supported_protocols + .into_iter() + .map(protocol_capability_view) + .collect() } pub async fn get_capabilities(&self) -> EditionCapabilities { diff --git a/apps/ui/css/wizard.css b/apps/ui/css/wizard.css index 4657ac4..d3ceb66 100644 --- a/apps/ui/css/wizard.css +++ b/apps/ui/css/wizard.css @@ -1,10 +1,29 @@ /* ══════════════════════════════════════════════════ WIZARD — shell ══════════════════════════════════════════════════ */ +.wizard-page { + padding-top: 60px; +} + +.wizard-page .navbar { + position: fixed; + top: 0; + left: 0; + right: 0; +} + +.wizard-page .progress-strip { + position: fixed; + top: 60px; + left: 0; + right: 0; +} + .wizard-shell { min-height: calc(100vh - 60px); display: flex; flex-direction: column; + padding-top: 56px; } /* ══════════════════════════════════════════════════ @@ -18,8 +37,6 @@ align-items: center; height: 56px; gap: 20px; - position: sticky; - top: 60px; z-index: 30; box-shadow: 0 1px 0 var(--border-subtle), 0 4px 16px rgba(0, 0, 0, 0.4); } @@ -244,9 +261,9 @@ .steps-list::before { content: ''; position: absolute; - left: 17px; + left: 27px; top: 32px; - bottom: 32px; + bottom: 40px; width: 1px; background: var(--border); z-index: 0; diff --git a/apps/ui/html/wizard/index.html b/apps/ui/html/wizard/index.html index bfc84b0..a69d71c 100644 --- a/apps/ui/html/wizard/index.html +++ b/apps/ui/html/wizard/index.html @@ -11,7 +11,7 @@ - +