feat(admin): rename /admin/welcome to /admin/agent-prompt (Agent Setup Prompt)

Rename the welcome prompt editor from /admin/welcome to /admin/agent-prompt
and update all UI labels to "Agent Setup Prompt". API endpoint URLs are
unchanged (PUT/GET/DELETE /api/admin/welcome-template, GET /api/welcome).

- Nav menu: "Welcome prompt" → "Agent Setup Prompt", href updated
- Page title and h2 updated in admin_welcome.html
- Error message hint in app/api/welcome.py updated to /admin/agent-prompt
- Dashboard: replace inline <details> preview of _claude_setup_instructions
  with a simple link to /setup (Task C)
- docs/welcome-template.md renamed to docs/agent-setup-prompt.md; internal
  references to /admin/welcome updated
- OpenAPI snapshot path updated
- Tests updated to reflect new route and removed inline preview
This commit is contained in:
ZdenekSrotyr 2026-05-02 21:47:05 +02:00
parent c7b14fb120
commit ecb6c35ad5
8 changed files with 21 additions and 33 deletions

View file

@ -81,7 +81,7 @@ async def get_welcome(
logger.warning("Welcome render failed: %s", e, exc_info=True)
raise HTTPException(
status_code=500,
detail="Welcome template render failed. An admin can fix it at /admin/welcome.",
detail="Welcome template render failed. An admin can fix it at /admin/agent-prompt.",
)
return WelcomeResponse(content=rendered)

View file

@ -14,7 +14,7 @@
<a class="app-nav-link {% if _path.startswith('/setup') or _path.startswith('/install') %}is-active{% endif %}" href="/setup">Setup local agent</a>
{% if session.user.is_admin %}
<a class="app-nav-link {% if _path.startswith('/admin/marketplaces') %}is-active{% endif %}" href="/admin/marketplaces">Marketplaces</a>
{% set _admin_active = _path.startswith('/admin/tables') or _path.startswith('/admin/tokens') or _path.startswith('/admin/users') or _path.startswith('/admin/groups') or _path.startswith('/admin/access') or _path.startswith('/admin/server-config') or _path.startswith('/admin/welcome') or _path.startswith('/admin/setup-banner') %}
{% set _admin_active = _path.startswith('/admin/tables') or _path.startswith('/admin/tokens') or _path.startswith('/admin/users') or _path.startswith('/admin/groups') or _path.startswith('/admin/access') or _path.startswith('/admin/server-config') or _path.startswith('/admin/agent-prompt') %}
<div class="app-nav-menu" id="adminNavMenu">
<button type="button"
class="app-nav-link app-nav-menu-trigger {% if _admin_active %}is-active{% endif %}"
@ -32,8 +32,7 @@
<a class="app-nav-menu-item {% if _path.startswith('/admin/groups') %}is-active{% endif %}" role="menuitem" href="/admin/groups">Groups</a>
<a class="app-nav-menu-item {% if _path.startswith('/admin/access') %}is-active{% endif %}" role="menuitem" href="/admin/access">Resource access</a>
<a class="app-nav-menu-item {% if _path.startswith('/admin/server-config') %}is-active{% endif %}" role="menuitem" href="/admin/server-config">Server config</a>
<a class="app-nav-menu-item {% if _path.startswith('/admin/welcome') %}is-active{% endif %}" role="menuitem" href="/admin/welcome">Welcome prompt</a>
<a class="app-nav-menu-item {% if _path.startswith('/admin/setup-banner') %}is-active{% endif %}" role="menuitem" href="/admin/setup-banner">Setup banner</a>
<a class="app-nav-menu-item {% if _path.startswith('/admin/agent-prompt') %}is-active{% endif %}" role="menuitem" href="/admin/agent-prompt">Agent Setup Prompt</a>
</div>
</div>
{% endif %}

View file

@ -1,5 +1,5 @@
{% extends "base.html" %}
{% block title %}Welcome Prompt — {{ config.INSTANCE_NAME }}{% endblock %}
{% block title %}Agent Setup Prompt — {{ config.INSTANCE_NAME }}{% endblock %}
{% block content %}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/codemirror.min.css"
@ -202,8 +202,8 @@
<div class="welcome-page">
<div class="welcome-toolbar">
<div>
<h2 class="welcome-title">Analyst Welcome Prompt</h2>
<p class="welcome-sub">Customise the CLAUDE.md generated for analysts on <code>da analyst setup</code>.</p>
<h2 class="welcome-title">Agent Setup Prompt</h2>
<p class="welcome-sub">Customise the <code>CLAUDE.md</code> generated for analysts on <code>da analyst setup</code>.</p>
</div>
<div id="status-chip">
{% if is_override %}

View file

@ -2046,20 +2046,7 @@
<a href="/setup" class="env-setup-link">Or open the full setup page →</a>
</div>
<div id="setupClaudeError" class="setup-error" role="alert" style="display:none;"></div>
<details class="setup-preview-card" aria-label="Preview of the clipboard payload">
<summary class="setup-preview-summary">
<span class="setup-preview-chevron" aria-hidden="true"></span>
<span class="setup-preview-title">What Claude Code will receive</span>
</summary>
<p class="setup-preview-sub">
Read-only preview. The real token is generated the moment
you click the button above and is placed directly in your
clipboard — never shown on this page.
</p>
{% with preview_mode=True %}
{% include "_claude_setup_instructions.jinja" %}
{% endwith %}
</details>
<a href="/setup" class="env-setup-link" style="display: block; margin-top: 8px;">View what Claude Code will receive on /setup →</a>
</div>
{% endif %}

View file

@ -1,6 +1,6 @@
# Welcome prompt customization
# Agent Setup Prompt
The welcome prompt is the `CLAUDE.md` file generated in an analyst's local
The agent setup prompt is the `CLAUDE.md` file generated in an analyst's local
workspace by `da analyst setup`. It instructs Claude Code on how to behave in
that workspace — which commands to use, where to read schema metadata, what
metrics exist, what plugins are available.
@ -15,7 +15,7 @@ no admin action is required.
Admins can override the template via:
- **Admin UI:** `/admin/welcome` — textarea editor with placeholder cheatsheet
- **Admin UI:** `/admin/agent-prompt` — textarea editor with placeholder cheatsheet
and live preview button. Save sends a `PUT` to `/api/admin/welcome-template`.
- **REST API:**
- `GET /api/admin/welcome-template` — returns `{content, default, updated_at, updated_by}`. `content` is `null` when no override is set.
@ -32,7 +32,7 @@ audit trail (`updated_at`, `updated_by`) is preserved.
[Jinja2](https://jinja.palletsprojects.com/) with `StrictUndefined`. Any
typo in a placeholder name raises an error at render time rather than
silently emitting an empty string. Server returns HTTP 500 with a hint
pointing at `/admin/welcome`; the admin UI rejects syntax errors AND
pointing at `/admin/agent-prompt`; the admin UI rejects syntax errors AND
undefined-placeholder errors with HTTP 400 on save (validated by rendering
the template against a stub context before persisting).

View file

@ -3358,9 +3358,9 @@
]
}
},
"/admin/welcome": {
"/admin/agent-prompt": {
"get": {
"operationId": "admin_welcome_page_admin_welcome_get",
"operationId": "admin_agent_prompt_page_admin_agent_prompt_get",
"parameters": [
{
"in": "header",

View file

@ -233,14 +233,16 @@ class TestClaudeSetupPreview:
assert "da diagnose" in body
assert "da auth whoami" in body
def test_dashboard_preview_visible(self, web_client, admin_cookie):
def test_dashboard_setup_cta_links_to_setup(self, web_client, admin_cookie):
"""Dashboard setup CTA shows env-setup-cta and a link to /setup instead
of an inline collapsed preview."""
resp = web_client.get("/dashboard", cookies=admin_cookie)
assert resp.status_code == 200
body = resp.text
assert "env-setup-cta" in body
assert "setup-preview-pre" in body
assert "What Claude Code will receive" in body
assert "&lt;will be generated on click&gt;" in body
assert "View what Claude Code will receive on /setup" in body
# inline <details> preview block must no longer appear
assert 'aria-label="Preview of the clipboard payload"' not in body
def test_install_mcp_card_removed(self, web_client):
"""The stale 'Use with Claude Code / MCP' card on /setup has been

View file

@ -102,7 +102,7 @@ def test_put_rejects_undefined_placeholder(seeded_app):
def test_get_welcome_500_includes_reset_hint_on_render_failure(seeded_app, monkeypatch):
"""If an override slips through validation and fails at render time, the
user-visible 500 must point at /admin/welcome rather than leaking a
user-visible 500 must point at /admin/agent-prompt rather than leaking a
Jinja stack trace."""
# Stub render_welcome to raise a TemplateError so we exercise the
# exception path without needing a malformed override (PUT validation
@ -123,7 +123,7 @@ def test_get_welcome_500_includes_reset_hint_on_render_failure(seeded_app, monke
headers=admin,
)
assert r.status_code == 500
assert "/admin/welcome" in r.json()["detail"]
assert "/admin/agent-prompt" in r.json()["detail"]
def test_admin_preview_renders_arbitrary_content(seeded_app):