From 489acfe8c614f59f79be0cf997c6faaf019b3248 Mon Sep 17 00:00:00 2001
From: Alessandro <155005371+3clyp50@users.noreply.github.com>
Date: Tue, 23 Jun 2026 02:21:44 +0200
Subject: [PATCH] Refine welcome screen setup surfaces
Fold the blocking onboarding state into the welcome composer, refresh the account and channel tiles, and keep system resources aligned with the renewed Welcome Screen layout.
Update model-config, OAuth, and welcome static tests to pin the new CTA, dismissal, copy, and layout contracts.
---
.../python/banners/10_discovery_cards.py | 2 +-
.../discovery-cards.html | 8 +-
.../welcome-actions-end/discovery-cards.html | 215 ++++------
plugins/_discovery/webui/discovery-store.js | 19 +
.../python/banners/_20_missing_api_key.py | 20 +-
tests/test_model_config_api_keys.py | 5 +
tests/test_oauth_static.py | 5 +
tests/test_welcome_composer_static.py | 53 +++
webui/components/welcome/welcome-screen.html | 375 ++++++++++++++++--
webui/components/welcome/welcome-store.js | 38 ++
10 files changed, 555 insertions(+), 185 deletions(-)
diff --git a/plugins/_discovery/extensions/python/banners/10_discovery_cards.py b/plugins/_discovery/extensions/python/banners/10_discovery_cards.py
index bba6c1c85..460f52ee8 100644
--- a/plugins/_discovery/extensions/python/banners/10_discovery_cards.py
+++ b/plugins/_discovery/extensions/python/banners/10_discovery_cards.py
@@ -138,7 +138,7 @@ class DiscoveryCardsExtension(Extension):
"type": "hero",
"placement": "after-features",
"title": "Your AI accounts",
- "description": "Link account-backed providers such as ChatGPT/Codex, GitHub Copilot, Gemini API, and xAI Grok."
+ "description": "Use your subscription-backed logins for model access."
if not connected_count
else "",
"cta_text": "Connect accounts" if not connected_count else "Manage accounts",
diff --git a/plugins/_discovery/extensions/webui/onboarding-success-end/discovery-cards.html b/plugins/_discovery/extensions/webui/onboarding-success-end/discovery-cards.html
index cf54f176b..c7ca47b30 100644
--- a/plugins/_discovery/extensions/webui/onboarding-success-end/discovery-cards.html
+++ b/plugins/_discovery/extensions/webui/onboarding-success-end/discovery-cards.html
@@ -276,8 +276,8 @@
.discovery-feature-thumb {
flex: 0 0 auto;
- width: 44px;
- height: 44px;
+ width: 32px;
+ height: 32px;
display: flex;
align-items: center;
justify-content: center;
@@ -570,8 +570,8 @@
}
.discovery-feature-thumb {
- width: 46px;
- height: 46px;
+ width: 32px;
+ height: 32px;
}
.discovery-feature-desc {
diff --git a/plugins/_discovery/extensions/webui/welcome-actions-end/discovery-cards.html b/plugins/_discovery/extensions/webui/welcome-actions-end/discovery-cards.html
index c0c9b6810..1d6ad7ca9 100644
--- a/plugins/_discovery/extensions/webui/welcome-actions-end/discovery-cards.html
+++ b/plugins/_discovery/extensions/webui/welcome-actions-end/discovery-cards.html
@@ -11,37 +11,35 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
@@ -58,11 +56,16 @@
@@ -95,12 +98,6 @@
-
@@ -135,15 +132,23 @@
.discovery-features-panel {
min-height: 100%;
- padding: 1.7rem 1.55rem 1.55rem;
+ padding: 1.25rem 1.45rem;
}
.discovery-panel-header {
display: grid;
- gap: 0.42rem;
+ grid-template-columns: minmax(0, 1fr) auto;
+ gap: 0.7rem;
+ align-items: start;
margin-bottom: 1.28rem;
}
+ .discovery-panel-copy {
+ display: grid;
+ gap: 0.42rem;
+ min-width: 0;
+ }
+
.discovery-panel-header h2 {
margin: 0;
color: var(--color-text);
@@ -162,31 +167,32 @@
.discovery-features {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
- gap: 0.7rem;
+ gap: 0.65rem;
}
.discovery-feature-card {
- position: relative;
- display: flex;
- flex-direction: column;
- align-items: flex-start;
- text-align: left;
- }
-
- .discovery-feature-head {
- display: flex;
- flex-direction: row;
+ display: inline-flex;
align-items: center;
- gap: 0.75rem;
- width: 100%;
+ gap: 0.5rem;
min-width: 0;
- margin-bottom: 1rem;
+ min-height: 3.1rem;
+ border: 1px solid color-mix(in srgb, var(--color-border) 52%, transparent);
+ border-radius: 8px;
+ padding: 0.56rem 0.58rem;
+ background: color-mix(in srgb, var(--color-background) 50%, transparent);
+ color: inherit;
+ cursor: pointer;
+ font-family: var(--font-family-main, "Rubik", Arial, Helvetica, sans-serif);
+ text-align: left;
+ transition:
+ border-color 0.18s ease,
+ background-color 0.18s ease;
}
.discovery-feature-thumb {
flex: 0 0 auto;
- width: 52px;
- height: 52px;
+ width: 32px;
+ height: 32px;
display: flex;
align-items: center;
justify-content: center;
@@ -212,34 +218,15 @@
flex: 1 1 auto;
min-width: 0;
color: var(--color-text);
- font-size: 0.96rem;
+ font-size: 0.84rem;
font-weight: 520;
line-height: 1.25;
}
- .discovery-feature-desc {
- margin: 1.12rem 0 0;
- padding-bottom: var(--spacing-md);
- color: color-mix(in srgb, var(--color-text) 72%, transparent);
- font-size: 0.86rem;
- line-height: 1.48;
- }
-
- .discovery-feature-card > .btn {
- margin-top: auto;
- min-width: 6.1rem;
- min-height: 2.35rem;
- border: 0;
- border-radius: 8px;
- color: #fff;
- font-family: var(--font-family-main, "Rubik", Arial, Helvetica, sans-serif);
- font-size: 0.88rem;
- font-weight: 460;
- }
-
- .discovery-feature-card > .btn:hover,
- .discovery-feature-card > .btn:focus-visible {
- filter: brightness(1.06);
+ .discovery-feature-card:hover,
+ .discovery-feature-card:focus-visible {
+ border-color: color-mix(in srgb, var(--color-border) 88%, var(--color-text) 12%);
+ background: color-mix(in srgb, var(--color-panel) 86%, var(--color-background) 14%);
outline: none;
}
@@ -272,10 +259,12 @@
height: 26px;
}
- .discovery-feature-card:hover .discovery-dismiss,
- .discovery-feature-card:focus-visible .discovery-dismiss,
- .discovery-account-card:hover .discovery-dismiss,
- .discovery-account-card:focus-within .discovery-dismiss {
+ .discovery-panel-dismiss {
+ position: static;
+ opacity: 0.68;
+ }
+
+ .discovery-account-card > .discovery-dismiss {
opacity: 0.68;
}
@@ -294,32 +283,19 @@
.discovery-account-card {
position: relative;
display: grid;
- gap: 1.1rem;
- padding: 1.35rem 1.45rem 1.4rem;
+ gap: 1rem;
+ padding: 1.25rem 1.45rem 1.25rem;
}
.discovery-account-header {
display: grid;
- grid-template-columns: auto minmax(0, 1fr);
+ grid-template-columns: minmax(0, 1fr) auto;
gap: 0.95rem;
align-items: center;
min-width: 0;
padding-right: 2.1rem;
}
- .discovery-account-icon {
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: 3rem;
- height: 3rem;
- border-radius: 10px;
- color: #2f6bff;
- background: color-mix(in srgb, var(--color-primary) 10%, transparent);
- box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--color-primary) 12%, transparent);
- font-size: 1.7rem;
- }
-
.discovery-account-copy {
display: grid;
gap: 0.3rem;
@@ -357,7 +333,7 @@
min-height: 2rem;
padding: 0.32rem 0.58rem;
border: 1px solid color-mix(in srgb, var(--color-border) 52%, transparent);
- border-radius: 999px;
+ border-radius: 8px;
background: color-mix(in srgb, var(--color-background) 50%, transparent);
color: color-mix(in srgb, var(--color-text) 74%, transparent);
font-size: 0.8rem;
@@ -464,7 +440,7 @@
}
.discovery-account-cta {
- justify-self: start;
+ justify-self: end;
display: inline-flex;
align-items: center;
justify-content: center;
@@ -479,6 +455,7 @@
font-family: var(--font-family-main, "Rubik", Arial, Helvetica, sans-serif);
font-size: 0.88rem;
font-weight: 460;
+ white-space: nowrap;
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2);
}
@@ -536,33 +513,14 @@
}
.discovery-feature-card {
- display: grid;
- grid-template-columns: minmax(0, 1fr) auto;
- gap: 0.75rem;
+ display: inline-flex;
min-height: 0;
- align-items: center;
- }
-
- .discovery-feature-head {
- grid-column: 1;
- min-width: 0;
- margin-bottom: 0;
+ padding: 0.62rem 0.7rem;
}
.discovery-feature-thumb {
- width: 46px;
- height: 46px;
- }
-
- .discovery-feature-desc {
- display: none;
- }
-
- .discovery-feature-card > .btn {
- grid-column: 2;
- grid-row: 1;
- align-self: center;
- margin-top: 0;
+ width: 32px;
+ height: 32px;
}
.discovery-account-usage-row {
@@ -577,12 +535,7 @@
}
.discovery-feature-card {
- grid-template-columns: minmax(0, 1fr) auto;
- padding-right: 3rem;
- }
-
- .discovery-feature-card > .btn {
- justify-self: end;
+ padding-right: 0.7rem;
}
.discovery-account-card {
@@ -594,11 +547,11 @@
padding-right: 2.2rem;
}
- .discovery-account-icon {
- width: 2.55rem;
- height: 2.55rem;
- font-size: 1.45rem;
+ .discovery-account-cta {
+ grid-column: 1 / -1;
+ justify-self: start;
}
+
}
diff --git a/plugins/_discovery/webui/discovery-store.js b/plugins/_discovery/webui/discovery-store.js
index 8dbb52919..2feb1756f 100644
--- a/plugins/_discovery/webui/discovery-store.js
+++ b/plugins/_discovery/webui/discovery-store.js
@@ -64,6 +64,25 @@ const model = {
this.hasDismissedCards = true;
},
+ dismissFeatureCards() {
+ const featureIds = this.featureCards
+ .filter((card) => card.dismissible !== false)
+ .map((card) => card.id)
+ .filter(Boolean);
+
+ if (!featureIds.length) return;
+
+ const dismissed = this._getDismissedIds();
+ const dismissSet = new Set(featureIds);
+ for (const id of dismissSet) {
+ dismissed.add(id);
+ }
+ this._persistDismissedIds(dismissed);
+
+ this.cards = this.cards.filter((card) => !dismissSet.has(card.id));
+ this.hasDismissedCards = true;
+ },
+
undismissCards() {
localStorage.removeItem(STORAGE_KEY);
this.refreshCards();
diff --git a/plugins/_model_config/extensions/python/banners/_20_missing_api_key.py b/plugins/_model_config/extensions/python/banners/_20_missing_api_key.py
index c5722435c..1d58b3d8e 100644
--- a/plugins/_model_config/extensions/python/banners/_20_missing_api_key.py
+++ b/plugins/_model_config/extensions/python/banners/_20_missing_api_key.py
@@ -7,12 +7,8 @@ class MissingApiKeyCheck(Extension):
"""Check if API keys are configured for selected model providers."""
LOCAL_PROVIDERS = {"ollama", "lm_studio", "llama_cpp", "omlx", "vllm"}
- CONFIGURE_MODEL_SETTINGS_LINK = (
- """"""
- """"""
- """
"""
- )
+ ONBOARDING_MODAL_PATH = "/plugins/_onboarding/webui/onboarding.html"
+ ONBOARDING_CTA_TEXT = "Start Onboarding"
async def execute(self, banners: list = [], frontend_context: dict = {}, **kwargs):
cfg = plugins.get_plugin_config("_model_config") or {}
@@ -25,11 +21,12 @@ class MissingApiKeyCheck(Extension):
"priority": 100,
"title": "Welcome to Agent Zero!",
"html": f"""You're almost ready to chat. Please configure your models to continue.
- Insert your API key in the onboarding wizard.
- {self.CONFIGURE_MODEL_SETTINGS_LINK}""",
+ Insert your API key in the onboarding wizard.""",
+ "cta_text": self.ONBOARDING_CTA_TEXT,
+ "cta_action": f"open-modal:{self.ONBOARDING_MODAL_PATH}",
"dismissible": False,
"source": "backend",
- "auto_modal_path": "/plugins/_onboarding/webui/onboarding.html",
+ "auto_modal_path": self.ONBOARDING_MODAL_PATH,
"auto_modal_reason": "missing-api-key",
"auto_modal_priority": 100,
"auto_modal_surfaces": ["welcome", "chat-created"],
@@ -69,8 +66,9 @@ class MissingApiKeyCheck(Extension):
"priority": 90,
"title": "Missing API Key for model presets",
"html": f"""No API key configured for preset models: {preset_list}.
- These presets will not work until you provide the required API keys.
- {self.CONFIGURE_MODEL_SETTINGS_LINK}""",
+ These presets will not work until you provide the required API keys.""",
+ "cta_text": self.ONBOARDING_CTA_TEXT,
+ "cta_action": f"open-modal:{self.ONBOARDING_MODAL_PATH}",
"dismissible": True,
"source": "backend"
})
diff --git a/tests/test_model_config_api_keys.py b/tests/test_model_config_api_keys.py
index 1153630fd..1b592c555 100644
--- a/tests/test_model_config_api_keys.py
+++ b/tests/test_model_config_api_keys.py
@@ -82,6 +82,9 @@ async def test_missing_api_key_banner_exposes_missing_providers(monkeypatch):
)
row = next(b for b in banners if b.get("id") == "missing-api-key")
assert row.get("missing_providers") == fake
+ assert row["cta_text"] == "Start Onboarding"
+ assert row["cta_action"] == "open-modal:/plugins/_onboarding/webui/onboarding.html"
+ assert "onboarding-banner-btn-container" not in row["html"]
def test_model_config_frontend_tracks_inline_api_key_edits():
@@ -267,6 +270,8 @@ def test_missing_api_key_banner_includes_auto_modal_metadata(monkeypatch):
assert row["type"] == "warning"
assert row["dismissible"] is False
assert row["missing_providers"] == fake
+ assert row["cta_text"] == "Start Onboarding"
+ assert row["cta_action"] == "open-modal:/plugins/_onboarding/webui/onboarding.html"
def test_provider_key_modes_for_local_and_ollama_cloud():
diff --git a/tests/test_oauth_static.py b/tests/test_oauth_static.py
index 4b7b165bd..419a93178 100644
--- a/tests/test_oauth_static.py
+++ b/tests/test_oauth_static.py
@@ -179,6 +179,8 @@ def test_oauth_discovery_card_renders_in_welcome_account_panel():
assert "discovery-oauth-accounts" in discovery_cards
assert "Your AI accounts" in discovery_cards
+ assert "Use your subscription-backed logins for model access." in discovery_cards
+ assert "Link account-backed providers such as" not in discovery_cards
assert "Connected OAuth accounts" not in discovery_cards
assert "discovery-codex-oauth" not in discovery_cards
assert "5h and weekly limits are ready." not in discovery_cards
@@ -188,6 +190,9 @@ def test_oauth_discovery_card_renders_in_welcome_account_panel():
assert "account_chips" in discovery_cards
assert "discovery-account-card" in welcome_cards
assert "discovery-account-chip" in welcome_cards
+ assert "discovery-account-icon" not in welcome_cards
+ assert ".discovery-account-chip {\n display: inline-grid;" in welcome_cards
+ assert " border-radius: 8px;" in welcome_cards
assert "discovery-account-usage" in welcome_cards
assert "formatRemainingPercent(window)" in welcome_cards
assert "formatRemainingPercent(window)" in discovery_store
diff --git a/tests/test_welcome_composer_static.py b/tests/test_welcome_composer_static.py
index 11ab62311..0738fb8a9 100644
--- a/tests/test_welcome_composer_static.py
+++ b/tests/test_welcome_composer_static.py
@@ -10,17 +10,70 @@ def _read(relative_path: str) -> str:
def test_welcome_screen_embeds_shared_new_chat_composer() -> None:
welcome = _read("webui/components/welcome/welcome-screen.html")
+ welcome_store = _read("webui/components/welcome/welcome-store.js")
index = _read("webui/index.html")
discovery_cards = _read(
"plugins/_discovery/extensions/webui/welcome-actions-end/discovery-cards.html"
)
+ discovery_store = _read("plugins/_discovery/webui/discovery-store.js")
assert 'class="welcome-composer"' in welcome
assert 'path="chat/attachments/inputPreview.html"' in welcome
assert 'path="chat/input/chat-bar-input.html"' in welcome
+ assert "x-text=\"$store.welcomeStore.heroSubtitle\"" in welcome
+ assert "Hello! I'm Agent Zero" in welcome
+ assert "'is-setup-required': $store.welcomeStore.hasBlockingSetupBanner" in welcome
+ assert 'class="welcome-setup-composer"' in welcome
+ assert "Configure your models to start chatting" in welcome
+ assert "Start Onboarding" in welcome
+ assert "openBlockingSetup()" in welcome
+ assert '.filter((b) => b.id !== "missing-api-key")' in welcome_store
+ assert "get blockingSetupBanner()" in welcome_store
+ assert "get heroSubtitle()" in welcome_store
+ assert 'return "One setup step before chatting.";' in welcome_store
+ assert 'return "How can I help you today?";' in welcome_store
+ assert "openBlockingSetup()" in welcome_store
assert 'Quick Actions
' in welcome
assert 'class="welcome-lower-grid"' in welcome
assert 'x-extension id="welcome-actions-end"' in welcome
+ assert "grid-template-columns: repeat(4, minmax(0, 1fr));" in welcome
+ assert '"accounts accounts channels channels"' in welcome
+ assert '"system system system system"' in welcome
+ assert "align-items: stretch;" in welcome
+ assert ".welcome-lower-grid .discovery-slot {\n display: contents;" in welcome
+ assert ".welcome-lower-grid .discovery-account-card {\n grid-area: accounts;" in welcome
+ assert "grid-area: system;" in welcome
+ assert ".welcome-composer .input-row {\n min-height: 4.9rem;" in welcome
+ assert "border-radius: 8px;" in welcome
+ assert 'aria-label="Refresh System Resources"' in welcome
+ assert "refreshBanners(true)" in welcome
+ assert 'aria-label="Dismiss System Resources"' in welcome
+ assert "dismissBanner($store.welcomeStore.systemResourceBanner?.id || 'system-resources')" in welcome
+ assert "welcome-panel-status-icon" not in welcome
+ assert "monitoring" not in welcome
+ assert ".welcome-banner {\n --welcome-banner-accent: #2f6bff;" in welcome
+ assert "grid-template-columns: auto minmax(0, 1fr) auto auto;" in welcome
+ assert ".welcome-banner.banner-warning {\n --welcome-banner-accent: #f59e0b;" in welcome
+ assert "border-left: 4px" not in welcome
+ assert 'class="welcome-banner-cta"' in welcome
+ assert "executeBannerAction(banner.cta_action)" in welcome
+ assert "executeBannerAction(action)" in welcome_store
+ assert 'action.startsWith("open-modal:")' in welcome_store
+ assert ".welcome-banner-html .onboarding-banner-btn-container" in welcome
+ assert "justify-content: flex-end;" in welcome
+ assert "justify-content: flex-start;" in welcome
+ assert ".welcome-banner-html .btn,\n .welcome-banner-html button" in welcome
+ assert "background-color: #4248f1;" in welcome
+ assert 'aria-label="Dismiss Connect Channels"' in discovery_cards
+ assert "dismissFeatureCards()" in discovery_cards
+ assert "dismissFeatureCards() {" in discovery_store
+ assert 'class="discovery-feature-card"\n type="button"' in discovery_cards
+ assert "`${card.cta_text || 'Connect'} ${card.title}`" in discovery_cards
+ assert "discovery-feature-card > .btn" not in discovery_cards
+ assert "discovery-feature-head" not in discovery_cards
+ assert "discovery-account-header" in discovery_cards
+ assert "discovery-account-cta" in discovery_cards
+ assert "discovery-account-icon" not in discovery_cards
assert "x-if=\"$store.welcomeStore && $store.welcomeStore.isVisible\"" in index
assert "x-if=\"!$store.welcomeStore || !$store.welcomeStore.isVisible\"" in index
diff --git a/webui/components/welcome/welcome-screen.html b/webui/components/welcome/welcome-screen.html
index d27472373..15a29fc29 100644
--- a/webui/components/welcome/welcome-screen.html
+++ b/webui/components/welcome/welcome-screen.html
@@ -15,11 +15,31 @@
-
+
+
+
+
@@ -37,6 +57,14 @@
+