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) ────