From d63f1473ab7286245c5efed1ab389482ce98d443 Mon Sep 17 00:00:00 2001 From: Vojtech <119944107+cvrysanek@users.noreply.github.com> Date: Thu, 14 May 2026 20:31:24 +0400 Subject: [PATCH] =?UTF-8?q?feat(home):=20drop=20/home=20connectors=20block?= =?UTF-8?q?=20=E2=80=94=20onboarding=20covers=20it=20(#305)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The dedicated `
` section on /home duplicated content that the install hero's Step 4 clipboard payload already inlines. Both surfaces sourced the same prompt strings from `app/web/connector_prompts.py` (home tiles via ``, setup script via `app/web/setup_instructions.py::_connectors_block`), so users walking the install script visited each connector inline and then had no reason to scroll back up. Removed the full block (3 tiles + summary + section-label). Lead paragraph in the install hero now mentions the connector families briefly so the benefit is visible before kick-off: "... your team's curated data, plugins, third-party tools (Asana, Google Workspace, Atlassian), and shared knowledge ... the install script also connects your tools for you, so there's no extra page to visit." The "Email admin" mailto CTA, previously gated inside the GWS tile when admin_email was set + GWS unconfigured, moves implicitly to the install script's GWS step (Claude prompts the user when the OAuth gating wall lands). Tests updated: - test_connectors_section_removed_from_home (renamed from test_connectors_render_flat_when_onboarded_by_default) — asserts `class="connector-tiles"` and `data-section="connectors"` are absent in BOTH onboarded states, and that the lead paragraph still mentions the three connector families so the benefit isn't lost. - test_home_renders_connector_prompts_from_shared_module — DROPPED. Was a parity check between the home tiles and the setup script's connector_prompts.py source. One surface now → no drift risk → test redundant. Replaced with an inline comment pointing future readers at where the strings flow (setup_instructions.py::_connectors_block). - test_home_no_longer_shows_email_admin_button (renamed from test_home_shows_email_admin_button_when_admin_email_set_and_gws_unconfigured) — asserts the mailto CTA is gone from /home regardless of admin_email / GWS-configured state; documents the path-move. CSS for `.connector-tile*` left in place as dead bytes — small footprint, no behavior, easy follow-up if/when someone audits. --- app/web/templates/home_not_onboarded.html | 106 ++-------------- tests/test_web_home_page.py | 140 +++++++++------------- 2 files changed, 70 insertions(+), 176 deletions(-) diff --git a/app/web/templates/home_not_onboarded.html b/app/web/templates/home_not_onboarded.html index 8009f54..034d1f1 100644 --- a/app/web/templates/home_not_onboarded.html +++ b/app/web/templates/home_not_onboarded.html @@ -1453,7 +1453,7 @@
Welcome, {{ display_name }} — let's get you set up

Connect Claude Code on your machine to your team's data

- {{ instance_brand }} gives Claude Code on your computer access to your team's curated data, plugins, and shared knowledge — so you can ask questions and get answers in plain language, right from your terminal. This page walks you through the one-time setup (~10 minutes). Everything it installs lives in your home folder (~/{{ workspace_dir }}) and can be removed in one command. + {{ instance_brand }} gives Claude Code on your computer access to your team's curated data, plugins, third-party tools (Asana, Google Workspace, Atlassian), and shared knowledge — so you can ask questions and get answers in plain language, right from your terminal. This page walks you through the one-time setup (~10 minutes); the install script also connects your tools for you, so there's no extra page to visit. Everything it installs lives in your home folder (~/{{ workspace_dir }}) and can be removed in one command.

@@ -1662,99 +1662,17 @@ Set-Location "$HOME\{{ workspace_dir }}"

For the deepest integration, create every project under ~/{{ workspace_dir }}/Projects/ — existing or new. The bundled plugin keeps each project in sync with the central catalog automatically, and the session-analysis loop is scoped to that root.

-
- - - Connect your tools (Asana / Google Workspace / Atlassian) - - - - -
-
- - {# P0-3 — title row + time-badge + post-copy hint. The hint - container is rendered hidden; the JS reveals it after the - copy succeeds, then auto-hides after 8 s. #} -
- Asana - ~5 min · self-serve -
-
Read tasks and projects, comment, create updates — Claude works alongside your project boards without leaving the terminal.
-
- -
- ✅ Copied. Now paste into Claude Code — run claude in your terminal, then paste & press Enter. -
-
- Show prompt - {# Asana prompt body sourced from app/web/connector_prompts.py - (`asana_prompt()`). Same string the main setup script - inlines in step 9, so the two surfaces stay in lockstep. #} -
{{ connector_prompts.asana }}
-
-
-
- -
- 📚 - {# P0-3 + P1-8 — Google Workspace tile. Time badge warns when - the operator hasn't provisioned a shared OAuth app (forces - the user to set up GCP themselves, which is a ~20-min - clickops detour). The gating-note + email-admin button - appear in that same un-configured branch so the user has - a way out before copying. #} -
- Google Workspace - {% if gws_oauth.configured %} - ~5 min · self-serve - {% else %} - ~20 min · admin help likely - {% endif %} -
-
Drive, Calendar, Gmail, Docs, Sheets, Chat — Claude reads and acts across your work account via the official gws CLI.
- {% if not gws_oauth.configured %} -
- Heads up: your {{ instance_brand }} admin hasn't provisioned a shared Google Cloud OAuth app yet, so this connector needs GCP project setup (creating an OAuth client, enabling APIs). It's fastest to ask your admin first — the button below pre-fills the email. -
- {% endif %} -
- - {% if not gws_oauth.configured and instance_admin_email %} - - {% endif %} -
- ✅ Copied. Now paste into Claude Code — run claude in your terminal, then paste & press Enter. -
-
- Show prompt -
{{ connector_prompts.gws }}
-
-
-
- -
- 🎟️ -
- Atlassian (Jira / Confluence) - ~7 min · self-serve -
-
Read and write Jira issues, search Confluence pages — Claude pulls ticket context and posts updates without leaving the workspace.
-
- -
- ✅ Copied. Now paste into Claude Code — run claude in your terminal, then paste & press Enter. -
-
- Show prompt -
{{ connector_prompts.atlassian }}
-
-
-
-
-
+ {# Connectors `
` block removed — + the install-hero's Step 4 clipboard payload (rendered via + `_claude_setup_instructions.jinja` inside the "Or paste manually" + fallback) already inlines the same Asana / GWS / Atlassian + prompts from app/web/connector_prompts.py via + app/web/setup_instructions.py::_connectors_block. Showing them + a second time as standalone cards duplicated UX without adding + reach — the install script visits them all in sequence. Brief + mention in the install-hero lead paragraph above covers the + benefits ("third-party tools (Asana, Google Workspace, + Atlassian)"); deep ops live in /setup-advanced. #}

You don't need {{ instance_brand }} installed locally to browse what's available. Anything you bookmark or subscribe to will be there waiting after you set {{ instance_brand }} up.

diff --git a/tests/test_web_home_page.py b/tests/test_web_home_page.py index ec46b05..6a79cdb 100644 --- a/tests/test_web_home_page.py +++ b/tests/test_web_home_page.py @@ -109,20 +109,20 @@ def test_home_onboarded_user_sees_nav_hub(fresh_db): assert "Step 4 — install" not in body -def test_connectors_render_flat_when_onboarded_by_default(fresh_db): - """Connect-your-tools section must NOT auto-collapse on the - server-side `users.onboarded=TRUE` flip. It renders flat (in
) by default; only an explicit user click on the in-hero - "Minimize setup view" toggle (persisted in localStorage, not server) - activates the collapsed bar layout. +def test_connectors_section_removed_from_home(fresh_db): + """The dedicated `
` block was + dropped from `/home` — the install-hero's Step 4 clipboard payload + (rendered via `_claude_setup_instructions.jinja` inside the manual + fallback) already inlines the same Asana / GWS / Atlassian prompts + from `app/web/connector_prompts.py` via + `app/web/setup_instructions.py::_connectors_block`. Showing them + twice on the same page was duplicate UX. The lead paragraph in the + install-hero now mentions the connectors briefly so users still see + the benefit before they hit the install. - Auto-mode used to be a peer `setup-collapsible` section - (`data-section="step3"`) outside the install-hero. It moved into the - install-hero as Step 2 of the install flow (so users enable it - BEFORE Step 3's ~20-command install runs), and the standalone - outside-hero copy was dropped to avoid duplicating reference - content. Onboarded users no longer see the auto-mode block at all — - consistent with Step 1 + Step 3 also hiding post-onboarding.""" + Co-asserts the auto-mode block removal that this test originally + pinned — onboarded users still see neither the connectors block + nor the legacy auto-mode peer section.""" from src.db import get_system_db, close_system_db conn = get_system_db() @@ -136,22 +136,37 @@ def test_connectors_render_flat_when_onboarded_by_default(fresh_db): resp = c.get("/home", cookies={"access_token": sess}) assert resp.status_code == 200 body = resp.text - # Auto-mode no longer renders for onboarded users — both the - # in-hero install-block and the legacy outside-hero `
` - # reference card are gated `{% if not onboarded %}` / removed. + # Auto-mode peer section still gone (legacy guard, not regressed). assert 'class="automode-card"' not in body assert 'data-section="step3"' not in body assert "Step 2 — turn on auto-mode" not in body - # Connect-your-tools section is still flat-open by default. - assert 'class="connector-tiles"' in body - assert 'class="setup-collapsible" data-section="connectors" open' in body + # Dedicated connectors block is gone from /home in BOTH states. + assert 'class="connector-tiles"' not in body + assert 'data-section="connectors"' not in body # Server-rendered HTML never carries the data-setup-minimized # attribute on the .home-mock root — that's a client-side - # localStorage decision applied via JS on load. The token still - # appears in inline CSS selectors and the JS body, which is fine. + # localStorage decision applied via JS on load. assert '
' in body + # Not-onboarded path: same — the section disappears regardless of + # state. Lead-paragraph still surfaces the connector names so users + # know the benefit exists before they kick off the install. + conn = get_system_db() + try: + _, sess2 = _make_user_and_session( + conn, email="not-onboarded@example.com", onboarded=False + ) + finally: + conn.close() + close_system_db() + body2 = _client().get("/home", cookies={"access_token": sess2}).text + assert 'class="connector-tiles"' not in body2 + assert 'data-section="connectors"' not in body2 + # Lead-paragraph mentions the three connector families so the + # benefit isn't lost when the dedicated section disappears. + assert "Asana, Google Workspace, Atlassian" in body2 + def test_minimize_toggle_no_longer_rendered(fresh_db): """The "Minimize setup view" toggle used to live inside the @@ -237,12 +252,15 @@ def test_home_hides_email_admin_button_when_admin_email_unset(fresh_db, monkeypa assert "mailto:?" not in body # specifically, no broken empty mailto -def test_home_shows_email_admin_button_when_admin_email_set_and_gws_unconfigured( - fresh_db, monkeypatch, -): - """When admin_email is set AND gws_oauth is unconfigured, the mailto - link renders. (Both conditions required — see template guard - ``{% if not gws_oauth.configured and instance_admin_email %}``.)""" +def test_home_no_longer_shows_email_admin_button(fresh_db, monkeypatch): + """The Email-admin mailto CTA used to live inside the /home GWS + connector tile. With the dedicated `
` + block removed (see test_connectors_section_removed_from_home above), + the button has no rendering site even when admin_email is set + GWS + is unconfigured. The escalation path lives inside the install + script's GWS step now — Claude prompts the user with the admin + email when the connector setup hits an OAuth gating wall, so the + affordance moves to the surface where it's actually useful.""" monkeypatch.setenv("AGNES_INSTANCE_ADMIN_EMAIL", "ops@example.com") monkeypatch.delenv("AGNES_GWS_CLIENT_ID", raising=False) monkeypatch.delenv("AGNES_GWS_CLIENT_SECRET", raising=False) @@ -254,8 +272,8 @@ def test_home_shows_email_admin_button_when_admin_email_set_and_gws_unconfigured conn.close() close_system_db() body = _client().get("/home", cookies={"access_token": sess}).text - assert "Email admin" in body - assert "mailto:ops@example.com" in body + assert "Email admin" not in body + assert 'mailto:ops@example.com' not in body def test_home_hides_email_admin_button_when_gws_configured(fresh_db, monkeypatch): @@ -276,59 +294,17 @@ def test_home_hides_email_admin_button_when_gws_configured(fresh_db, monkeypatch assert "Email admin" not in body -def test_home_renders_connector_prompts_from_shared_module(fresh_db): - """Single source of truth check: the prompt text the /home tiles - paste must equal the strings ``app/web/connector_prompts.py`` returns. - The same strings are also inlined into the setup script's step 9, so - if they ever drift the two surfaces would tell users to do different - things — this test catches that early.""" - import html as _html - import re - - from src.db import get_system_db, close_system_db - from app.web.connector_prompts import ( - asana_prompt, gws_prompt, atlassian_prompt, - ) - from app.instance_config import ( - get_gws_oauth_credentials, get_instance_admin_email, - ) - - conn = get_system_db() - try: - _, sess = _make_user_and_session(conn) - finally: - conn.close() - close_system_db() - - c = _client() - body = c.get("/home", cookies={"access_token": sess}).text - - # Resolve the same gws_oauth dict the route uses so the parity check - # exercises whichever branch (configured / manual) is active in the - # current test environment. - gws = get_gws_oauth_credentials() - expected_gws = gws_prompt( - gws_oauth_configured=bool(gws.get("configured")), - gws_client_id=str(gws.get("client_id") or ""), - gws_client_secret=str(gws.get("client_secret") or ""), - gws_project_id=str(gws.get("project_id") or ""), - oauthlib_insecure_transport=str(gws.get("oauthlib_insecure_transport") or "1"), - instance_admin_email=get_instance_admin_email(), - ) - - for slug, expected in ( - ("asana", asana_prompt()), - ("gws", expected_gws), - ("jira", atlassian_prompt()), - ): - m = re.search(rf'(.*?)', body, re.DOTALL) - assert m, f"{slug}-prompt block missing from /home" - actual = _html.unescape(m.group(1)) - assert actual == expected, ( - f"{slug}-prompt body diverged from connector_prompts module — " - f"the home tile and setup script will paste different text. " - f"len(home)={len(actual)} len(module)={len(expected)}" - ) +# `test_home_renders_connector_prompts_from_shared_module` was dropped here +# alongside the removal of the /home `
` +# block. The test pinned source-of-truth parity between the home tile +# `` blocks and `app/web/connector_prompts.py`. With the +# tiles gone, the only surface left for those strings is the install-hero's +# Step 4 clipboard payload (rendered via `_claude_setup_instructions.jinja` +# from `setup_instructions_lines`, which is built in +# `app/web/setup_instructions.py::_connectors_block` calling the same +# `connector_prompts.py` functions). One surface, no drift risk → the +# parity test is redundant. If a second surface ever re-renders these +# prompts, restore a parity test scoped to that new consumer. # ── Getting Started + Overview + Usage modes (PR #289 home additions) ────