diff --git a/frontend_multi_user/src/app.py b/frontend_multi_user/src/app.py index a9da50e3..ca1459a6 100644 --- a/frontend_multi_user/src/app.py +++ b/frontend_multi_user/src/app.py @@ -1020,6 +1020,9 @@ def index(): user = None recent_tasks: list[TaskItem] = [] is_admin = False + nonce = None + user_id = None + example_prompts: list[str] = [] if current_user.is_authenticated: is_admin = current_user.is_admin if not is_admin: @@ -1027,13 +1030,21 @@ def index(): user_uuid = uuid.UUID(str(current_user.id)) user = self.db.session.get(UserAccount, user_uuid) if user: + user_id = str(user.id) + # Generate a nonce so the user can start a plan from the dashboard + nonce = 'DASH_' + str(uuid.uuid4()) recent_tasks = ( TaskItem.query .filter_by(user_id=str(user.id)) .order_by(TaskItem.timestamp_created.desc()) - .limit(5) + .limit(10) .all() ) + # Load example prompts for the "Start New Plan" form + for prompt_uuid in DEMO_FORM_RUN_PROMPT_UUIDS: + prompt_item = self.prompt_catalog.find(prompt_uuid) + if prompt_item: + example_prompts.append(prompt_item.prompt) except Exception: logger.debug("Could not load dashboard data", exc_info=True) return render_template( @@ -1042,6 +1053,9 @@ def index(): credits_balance_display=self._format_credit_display(user.credits_balance) if user else "0", recent_tasks=recent_tasks, is_admin=is_admin, + nonce=nonce, + user_id=user_id, + example_prompts=example_prompts, ) @self.app.route('/healthcheck') diff --git a/frontend_multi_user/templates/index.html b/frontend_multi_user/templates/index.html index 6e86a2e1..8d52f3a7 100644 --- a/frontend_multi_user/templates/index.html +++ b/frontend_multi_user/templates/index.html @@ -285,6 +285,128 @@ font-size: 0.95rem; } + /* ── New plan form ──────────────────────────────── */ + .new-plan-section { + background: var(--color-card-bg); + border: 1px solid var(--color-border); + border-radius: var(--radius-lg); + margin-bottom: 32px; + box-shadow: 0 1px 3px var(--color-card-shadow); + } + .new-plan-header { + display: flex; + align-items: center; + gap: 10px; + padding: 16px 20px; + border-bottom: 1px solid var(--color-border); + } + .new-plan-header svg { + width: 20px; + height: 20px; + color: var(--color-primary); + flex-shrink: 0; + } + .new-plan-header h2 { + font-size: 1.05rem; + font-weight: 700; + margin: 0; + } + .new-plan-body { + padding: 20px; + } + .new-plan-body textarea { + width: 100%; + min-height: 120px; + padding: 12px 14px; + border: 1px solid var(--color-border); + border-radius: var(--radius); + font-family: var(--font-sans); + font-size: 0.9rem; + line-height: 1.5; + resize: vertical; + outline: none; + transition: border-color 0.15s; + box-sizing: border-box; + color: var(--color-text); + background: var(--color-bg); + } + .new-plan-body textarea:focus { + border-color: var(--color-primary); + box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1); + } + .new-plan-body textarea::placeholder { + color: var(--color-text-secondary); + } + .example-chips { + display: flex; + gap: 8px; + flex-wrap: wrap; + margin-bottom: 12px; + } + .example-chip { + display: inline-flex; + align-items: center; + gap: 4px; + padding: 5px 12px; + background: var(--color-bg-soft); + border: 1px solid var(--color-border); + border-radius: 20px; + font-size: 0.78rem; + font-weight: 500; + color: var(--color-text-secondary); + cursor: pointer; + transition: border-color 0.15s, color 0.15s; + } + .example-chip:hover { + border-color: var(--color-primary); + color: var(--color-primary); + } + .new-plan-footer { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; + margin-top: 14px; + } + .new-plan-footer .credit-hint { + font-size: 0.8rem; + color: var(--color-text-secondary); + } + .btn-start-plan { + display: inline-flex; + align-items: center; + gap: 8px; + padding: 10px 28px; + background: var(--color-primary); + color: #fff; + border: none; + border-radius: var(--radius); + font-size: 0.9rem; + font-weight: 600; + cursor: pointer; + transition: background 0.15s, transform 0.1s; + } + .btn-start-plan:hover { + background: var(--color-primary-hover); + transform: translateY(-1px); + } + .btn-start-plan:disabled { + opacity: 0.5; + cursor: not-allowed; + transform: none; + } + .btn-start-plan svg { + width: 16px; + height: 16px; + } + .char-count { + font-size: 0.75rem; + color: var(--color-text-secondary); + text-align: right; + margin-top: 4px; + font-family: "SF Mono", "Fira Code", "Consolas", monospace; + } + /* ── Admin view ─────────────────────────────────── */ .admin-notice { text-align: center; @@ -333,6 +455,46 @@

Welcome back, {{ user.name or user.given_name or "there" }}

+{# ── Start New Plan form ────────────────────────────────────── #} +{% if nonce %} +
+
+ +

Start a New Plan

+
+
+ {% if example_prompts %} +
+ {% for ep in example_prompts %} + + {% endfor %} +
+ {% endif %} +
+ + + + + +
0 characters
+ +
+
+
+{% endif %} +
@@ -361,7 +523,7 @@

Recent Plans

{% else %}
-

You haven't created any plans yet. Get started by creating your first one.

+

You haven't created any plans yet. Describe your idea above and click Generate Plan to get started.

{% endif %} @@ -417,4 +579,32 @@

Avoid Surprises

{% endif %} + +{% if user and nonce and example_prompts %} + +{% endif %} {% endblock %}