From dbe66a05687e13889e7bd9b85e75f80d277e01eb Mon Sep 17 00:00:00 2001 From: chihlasm Date: Fri, 27 Mar 2026 05:04:20 +0000 Subject: [PATCH] feat: bold dashboard redesign with inline stats, section labels, and chip icons MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Restructure QuickStartPage for a more professional, informative layout: - Left-aligned hero greeting (text-4xl) with date context and inline stat strip - GreetingStatStrip shows resolved/active/MTTR at a glance - Remove collapsible toggle — dashboard stats always visible - Section labels with trailing border lines for visual hierarchy - Suggestion chips with category icons, card-style hover, press feedback - Fix cyan focus ring and icon color to ember orange design system - Session cards: line-clamp-2 descriptions, font-medium text, problem_domain metadata - Widen container max-w-3xl → max-w-4xl for breathing room - Add .impeccable.md and .github/copilot-instructions.md design context - CLAUDE.md audit: fix stale references, remove duplication, update counts Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/copilot-instructions.md | 32 +++++++ .impeccable.md | 68 ++++++++++++++ CLAUDE.md | 66 ++++--------- .../dashboard/ActiveFlowPilotSessions.tsx | 50 +++++----- .../dashboard/GreetingStatStrip.tsx | 54 +++++++++++ .../components/dashboard/PerformanceCards.tsx | 2 +- .../dashboard/RecentFlowPilotSessions.tsx | 31 ++++--- .../dashboard/StartSessionInput.tsx | 32 ++++--- frontend/src/pages/QuickStartPage.tsx | 93 ++++++++++--------- 9 files changed, 284 insertions(+), 144 deletions(-) create mode 100644 .github/copilot-instructions.md create mode 100644 .impeccable.md create mode 100644 frontend/src/components/dashboard/GreetingStatStrip.tsx diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 00000000..bab9e749 --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,32 @@ +# Copilot Instructions — ResolutionFlow + +## Design Context + +### Users +MSP engineers — IT professionals at Managed Service Providers who troubleshoot infrastructure and support issues for multiple client companies. They work under ticket pressure, need to resolve issues fast, and produce clean documentation automatically. + +### Brand Personality +**Three words:** Professional, Modern, SaaS +**Voice:** Direct, competent, no fluff. Built by MSP engineers, for MSP engineers. +**Emotional goals:** Confidence, competence, clarity, focus. + +### Aesthetic Direction +- Flat, high-contrast dark theme (Sentry/PostHog-inspired). Premium and clean. +- **References:** Notion (clarity), Stripe (polish), Figma (functional density) +- **Anti-references:** Microsoft Teams (clutter), Kaseya VSA 9 (dated patterns) +- Accent: ember orange (#f97316), max 5% of UI. No glassmorphism, no gradient surfaces, no ambient effects. +- See `DESIGN-SYSTEM.md` for full token and component specs. + +### Accessibility +- WCAG 2.2 AA baseline +- Enhanced focus appearance on all interactive elements +- 7:1 contrast ratio for data visualization colors +- `prefers-reduced-motion` fully supported +- Never rely on color alone for status — pair with icons or text + +### Design Principles +1. **Clarity over decoration.** Every pixel should communicate. No ornamental effects. +2. **Density without clutter.** Use typography hierarchy and spacing to create structure, not chrome. +3. **Confidence through consistency.** Same patterns, same tokens, same behavior everywhere. +4. **Speed is a feature.** Minimize clicks. Copilot-first — primary interaction is typing. +5. **Accessible by default.** WCAG 2.2, enhanced focus, high-contrast data viz, motion sensitivity. diff --git a/.impeccable.md b/.impeccable.md new file mode 100644 index 00000000..5b5813d6 --- /dev/null +++ b/.impeccable.md @@ -0,0 +1,68 @@ +# Design Context — ResolutionFlow + +> Persistent design guidance for all AI sessions. Source of truth for design intent and principles. +> For component specs, tokens, and implementation details, see [DESIGN-SYSTEM.md](DESIGN-SYSTEM.md). + +## Users + +**MSP engineers** — IT professionals at Managed Service Providers who troubleshoot infrastructure and support issues for multiple client companies. They work under ticket pressure, juggling PSA tools (ConnectWise, Autotask, HaloPSA) and need to resolve issues fast while producing clean documentation. + +**Context of use:** Mid-ticket, often stressed, switching between tools. They need the interface to get out of their way and help them think clearly. Documentation is a pain point — it should feel automatic, not like extra work. + +**Job to be done:** Describe an issue, get guided through resolution, and walk away with professional ticket notes — without manual writeup. + +## Brand Personality + +**Three words:** Professional, Modern, SaaS + +**Voice:** Direct, competent, no fluff. Built by MSP engineers, for MSP engineers. The product speaks like a senior colleague — helpful without being patronizing, technical without being dense. + +**Emotional goals:** Confidence, competence, clarity, focus. The interface should make engineers feel like they have a reliable system backing them up. Every interaction should reinforce trust and reduce cognitive load. + +## Aesthetic Direction + +**Visual tone:** Flat, high-contrast dark theme. Premium and clean — Sentry/PostHog DNA. Minimal decoration, maximum signal. Information density without clutter. + +**References:** +- **Notion** — clarity of layout, whitespace discipline, typography hierarchy +- **Stripe** — polish, professional confidence, attention to micro-detail +- **Figma** — functional density done right, tool-like precision, dark mode execution + +**Anti-references:** +- **Microsoft Teams** — cluttered, inconsistent spacing, overwhelming chrome, unclear hierarchy +- **Kaseya VSA 9** — dated UI patterns, poor information density, legacy enterprise feel + +**Theme:** Dark mode primary (charcoal palette). Light mode planned but not yet implemented. + +**Accent:** Ember orange (#f97316) — conveys urgency fitting a troubleshooting context. Used sparingly (max 5% of UI). Warning uses yellow (#eab308), not amber, to stay distinct. + +**Hard rules:** No glassmorphism, no gradient surfaces, no ambient orbs, no backdrop blur, no decorative shadows at rest. Elevation = lighter surface + border, not shadow. + +## Accessibility + +**Target:** WCAG 2.2 AA as baseline, with two enhanced commitments: +- **Enhanced focus appearance** — all interactive elements must have visible, high-contrast focus indicators (not just inputs). Keyboard navigation must be obvious and consistent. +- **7:1 contrast ratio for data visualization** — chart colors, graph elements, and any data-bearing color must meet AAA contrast against their background. Standard text follows AA (4.5:1 body, 3:1 large). + +**Already implemented:** +- `prefers-reduced-motion` fully handled (animations collapse to 0.01ms) +- Mobile responsive (app shell collapses below 768px) +- Bottom-sheet modals on mobile +- Styled scrollbars (6px, subtle) + +**Considerations for future work:** +- Color blindness: avoid relying on red/green distinction alone for status — always pair with icons or text labels +- Screen reader: ensure all interactive elements have accessible names +- Keyboard: all flows must be completable without a mouse + +## Design Principles + +1. **Clarity over decoration.** Every pixel should communicate. If an element doesn't help the user understand or act, remove it. No ornamental gradients, glows, or effects. + +2. **Density without clutter.** MSP engineers work with lots of data. Show what matters, hide what doesn't. Use typography hierarchy and spacing — not chrome — to create structure. + +3. **Confidence through consistency.** Same patterns, same tokens, same behavior everywhere. Predictability builds trust. Reference [DESIGN-SYSTEM.md](DESIGN-SYSTEM.md) for every component decision. + +4. **Speed is a feature.** The interface should feel instant. Minimize clicks to action. Auto-generate what can be auto-generated. The copilot-first UX means the primary interaction is typing, not navigating. + +5. **Accessible by default.** WCAG 2.2 compliance isn't a checklist item — it's a design constraint. Enhanced focus, high-contrast data viz, and motion sensitivity are built in, not bolted on. diff --git a/CLAUDE.md b/CLAUDE.md index 9e90c07a..965f8f29 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,6 +1,6 @@ # CLAUDE.md - Patherly / ResolutionFlow Project Context -> **Last Updated:** March 25, 2026 +> **Last Updated:** March 27, 2026 --- @@ -23,25 +23,13 @@ - **Design aesthetic:** Flat, high-contrast dark theme (Sentry/PostHog-inspired). No glass morphism, no gradients on surfaces, no ambient effects. Light mode planned. - **Accent color:** Ember orange (#f97316 / #ea580c). Used sparingly — ≤5% of the UI. Warning is yellow (#eab308), not amber, to stay distinct from accent. - **Fonts:** IBM Plex Sans (`font-sans`, body), Bricolage Grotesque (`font-heading`, headings), JetBrains Mono (`font-mono`, code) — loaded via Google Fonts -- **Logo:** 30px gradient square (cyan) + "ResolutionFlow" in Bricolage Grotesque 700 +- **Logo:** 30px gradient square (ember orange) + "ResolutionFlow" in Bricolage Grotesque 700 - **Layout:** Icon rail sidebar (72px default) with hover flyout panels. Pinnable to full 260px sidebar. See [DESIGN-SYSTEM.md](DESIGN-SYSTEM.md) - **Brand assets:** `brand-assets/` (source SVGs), `frontend/src/assets/brand/` (app assets), `frontend/public/icons/` (favicon) - **Terminology:** User-facing label is "Flows" (not "Trees"). Procedural flows are called "Projects" in the UI. Step Library is called "Solutions Library" in the UI. Maintenance flows are hidden from UI for pilot (backend still supports them). `tree_type` column values unchanged in DB. - **Reference mockups:** `docs/mockups/` (HTML files, open in browser) -**Component styling rules:** - -- Primary buttons: solid `accent` background (#f97316), white text, 5px radius -- Ghost buttons: transparent with 1px `border-default`, hover `bg-elevated` -- Cards: `bg-card` with 1px `border-default`, 8px radius. NO shadows, NO blur, NO gradients. -- Badges: pill-shaped (20px radius), semantic dim background + matching text color -- Active nav: `accent-dim` background + `accent-text` color + 3px left accent bar -- Stat cards: 3px colored left border (accent/success/warning by position) -- Code blocks: `bg-code` with JetBrains Mono, material-inspired syntax highlighting -- Status colors: green/`#34d399` (success), yellow/`#eab308` (warning), red/`#f87171` (danger) — ONLY for semantic meaning -- Section labels: 10px, 600 weight, uppercase, `text-muted`, 1.2px letter-spacing - -When adding new pages/components: reference [DESIGN-SYSTEM.md](DESIGN-SYSTEM.md). Use flat dark surfaces, 1px borders, no decorative effects. All colors via CSS variables. Use "Flows" not "Trees" in all user-facing text; use "Projects" not "Procedures" for procedural flows. +**Component styling:** See Design System section below and [DESIGN-SYSTEM.md](DESIGN-SYSTEM.md). All colors via CSS variables. Use "Flows" not "Trees" in user-facing text; use "Projects" not "Procedures" for procedural flows. ## Implementation Principles @@ -54,9 +42,9 @@ When adding new pages/components: reference [DESIGN-SYSTEM.md](DESIGN-SYSTEM.md) ## Current State - **Phase:** Go-to-Market Validation (Pre-PMF) -- **Backend:** Complete (35+ API endpoints, 100+ integration tests) +- **Backend:** Complete (55+ API endpoints, 100+ integration tests) - **Frontend:** Core features complete, Tree Editor functional -- **Database:** PostgreSQL with Docker, 75 migrations +- **Database:** PostgreSQL with Docker, 98 migrations - **Detailed status:** [CURRENT-STATE.md](CURRENT-STATE.md) ### What's In Progress @@ -65,20 +53,6 @@ When adding new pages/components: reference [DESIGN-SYSTEM.md](DESIGN-SYSTEM.md) - Solutions Library spec written (`docs/plans/2026-03-23-solutions-library-design.md`), implementation post-pilot - Remaining open issues: #66 Templates + Import/Export, #60 Recurring Issue Detection, #58 Step Feedback Flag -### Recently Completed - -- Copilot-first dashboard redesign: ChatGPT-style input, suggestion chips, simplified sidebar -- Charcoal color palette: sidebar-darkest approach (`#10121a` sidebar, `#1a1c23` page, `#22252e` cards) -- Unified Command Palette: merged QuickLaunch into omnibar, removed lightning bolt button -- "Solutions Library" rename from "Step Library" site-wide -- Maintenance flows hidden from UI for pilot -- Landing page copy rewrite: copilot-first messaging ("Resolve tickets faster. Notes write themselves.") -- Spring bounce hover animation on dashboard cards -- Amber "New Session" button in sidebar -- Landing page design audit: hamburger menu, Privacy/Terms pages, branding alignment -- Root directory cleanup: archived 9 completed docs, tracked marketing assets -- GitHub issues triage: closed 10 stale issues (6 completed, 4 deferred) - --- ## Tech Stack @@ -95,7 +69,7 @@ When adding new pages/components: reference [DESIGN-SYSTEM.md](DESIGN-SYSTEM.md) ### Frontend - **Framework:** React 19 + Vite + TypeScript -- **Styling:** Tailwind CSS v4 (`@tailwindcss/vite` plugin, CSS-only config in `index.css`) — flat dark theme with cyan accent (see [DESIGN-SYSTEM.md](DESIGN-SYSTEM.md)) +- **Styling:** Tailwind CSS v4 (`@tailwindcss/vite` plugin, CSS-only config in `index.css`) — flat dark theme with ember orange accent (see [DESIGN-SYSTEM.md](DESIGN-SYSTEM.md)) - **State:** Zustand (with immer + zundo for undo/redo) - **Routing:** React Router v7 - **API Client:** Axios with token refresh interceptor @@ -110,7 +84,7 @@ patherly/ ├── backend/ │ ├── app/ │ │ ├── main.py # FastAPI entry point -│ │ ├── api/endpoints/ # Route handlers (auth, trees, sessions, admin, steps, survey, copilot, assistant_chat, psa_connections) +│ │ ├── api/endpoints/ # Route handlers (auth, trees, sessions, admin, steps, survey, copilot, assistant_chat, integrations) │ │ │ ├── flow_proposals.py # Knowledge Flywheel review queue CRUD │ │ │ └── flowpilot_analytics.py # FlowPilot dashboard metrics │ │ ├── api/deps.py # Auth dependencies (includes require_team_admin) @@ -118,7 +92,7 @@ patherly/ │ │ ├── core/ # config, database, permissions, security, audit, rate_limit │ │ ├── models/ # SQLAlchemy models (includes FlowProposal) │ │ ├── schemas/ # Pydantic schemas -│ │ ├── services/psa/ # PSA provider abstraction (base, connectwise/, cache, encryption, registry, types) +│ │ ├── services/psa/ # PSA provider abstraction (base, connectwise/, autotask/, halopsa/, cache, encryption, registry, types) │ │ ├── services/knowledge_flywheel.py # AI session analysis → flow proposals │ │ ├── services/knowledge_flywheel_scheduler.py # APScheduler job for batch analysis │ │ └── services/knowledge_gap_service.py # Weak options & escalation signal detection @@ -131,7 +105,7 @@ patherly/ │ │ ├── components/ # common, layout, dashboard, tree-editor, session, procedural, procedural-editor, library, step-library, ui, flowpilot │ │ ├── hooks/ # usePermissions, useSessionTimer, useKeyboardShortcuts │ │ ├── pages/ # All page components -│ │ ├── store/ # Zustand stores (auth, treeEditor, proceduralEditor, userPreferences) +│ │ ├── store/ # Zustand stores (auth, treeEditor, proceduralEditor, userPreferences, scriptGeneratorStore) │ │ └── types/ # TypeScript interfaces │ └── (Tailwind v4: CSS-only config in src/index.css) ├── docs/plans/archive/ # Archived design/impl docs (pre-March 2026) @@ -202,7 +176,7 @@ Official ConnectWise developer guides live in `docs/connectwise/best-practices/` - Auth: API Key auth (Base64 of `companyId+publicKey:privateKey`) + `clientId` header on every request - `clientId` is server-side config (`CW_CLIENT_ID` in `config.py`) — identifies the ResolutionFlow app, NOT per-tenant. Per-connection credentials: `company_id`, `public_key`, `private_key`, `server_url` - All PSA integration code in `services/psa/` — provider pattern with `PSAProvider` abstract base class, `ConnectWiseProvider` implementation, `PsaProviderRegistry` for multi-PSA dispatch -- PSA endpoints in `api/endpoints/psa_connections.py` — connection CRUD, ticket ops, member mapping +- PSA endpoints in `api/endpoints/integrations.py` — connection CRUD, ticket ops, member mapping - Credentials encrypted at rest via `services/psa/encryption.py` (Fernet) - Each MSP tenant provides their own CW credentials — ResolutionFlow stores these per-team, never per-user - Design for the Autotask integration following the same service layer pattern (future PSA) @@ -366,11 +340,6 @@ gh run view --json jobs --jq '.jobs[] | {name: .name, conclusion: .conclusi **88. Charcoal palette — sidebar-darkest approach:** Sidebar `#10121a`, page `#1a1c23`, cards `#22252e`, borders `#2e3240`. This gives more contrast range than true-dark (`#0c0d10`). All colors via CSS variables in `index.css` `@theme` block. Accent is ember orange (#f97316), not cyan. -**89. QuickLaunch merged into CommandPalette:** There is no separate QuickLaunch/lightning bolt. The unified Cmd+K omnibar handles search, navigation, quick actions, and FlowPilot. `QuickLaunch.tsx` was deleted. - -**90. Copilot-first UX direction:** The FlowPilot AI chat copilot is the primary experience. Dashboard centers on the chat input. Guided flows (decision trees) are accessible but secondary — in sidebar under "Flows". Maintenance flows are hidden from UI for pilot. - -**91. "New Session" button is amber-400:** Sidebar uses `bg-amber-400/15 text-amber-400` for the New Session button, not cyan. This makes it visually distinct from the cyan accent used elsewhere. **92. `tsc -b` in Dockerfile is stricter than `npx tsc --noEmit`:** The production build (`tsc -b && vite build`) enforces `noUnusedLocals` and `noUnusedParameters` as hard errors. After any refactor that moves logic between components or removes features, trace every import and destructured prop to remove orphans. IDE warnings (yellow squiggles) flag these — check them before pushing. @@ -390,6 +359,12 @@ gh run view --json jobs --jq '.jobs[] | {name: .name, conclusion: .conclusi **100. Hover pop-out card pattern:** For cards that expand on hover "in front of everything": use `pointer-events-none` on the scrim (`fixed inset-0 z-40 bg-black/30`), absolute-position the expanded card at `z-50` with its own `onClick` handler, and dismiss via `onMouseLeave` on the wrapper div. Never put interactive event handlers on the scrim — it blocks clicks on sibling elements. +**101. AI marker format compliance:** The AI assistant uses `[QUESTIONS]`, `[ACTIONS]`, and `[FORK]` markers in responses. Parsed by `unified_chat_service.py` (`_parse_*_marker` functions), returned as structured data in the API response. System prompt in `assistant_chat_service.py` has a final reminder section, and each user message gets an invisible `[SYSTEM: ...]` reminder appended in `_call_anthropic_cached()`. If markers stop appearing: check conversation history stores `display_content` (stripped), verify system prompt final reminder exists, check user message reminder injection is active. + +**102. TaskLane activation must happen in ALL chat response paths:** `AssistantChatPage.tsx` has three code paths calling `sendChatMessage`: `handleSend` (regular messages), `sendPrefill` (dashboard handoff), `handleResumeNew` (resume from concluded session). ALL three must check `response.actions`/`response.questions` and call `setShowTaskLane(true)`. Missing this in any path causes TaskLane to not appear on first message. + +**103. Docker not available in code-server container:** The dev environment runs code-server inside Docker on the VPS. The `docker` CLI is not available inside the code-server container. To query the database, use the VPS SSH session: `docker exec resolutionflow_postgres psql -U postgres -d resolutionflow -t -c "SQL"`. Python is also not available in the container. + --- ## RBAC & Permissions @@ -517,14 +492,6 @@ When a feature, fix, or significant piece of work is finished and merged/committ --- -## gstack - -Use `/browse` from gstack for **all web browsing** — never use `mcp__claude-in-chrome__*` tools. - -**Available skills:** `/office-hours`, `/plan-ceo-review`, `/plan-eng-review`, `/plan-design-review`, `/design-consultation`, `/review`, `/ship`, `/browse`, `/qa`, `/qa-only`, `/design-review`, `/setup-browser-cookies`, `/retro`, `/investigate`, `/document-release`, `/codex`, `/careful`, `/freeze`, `/guard`, `/unfreeze`, `/gstack-upgrade` - ---- - ## Future Roadmap - **Phase 3:** PSA integrations (ConnectWise in progress), file attachments, client context, analytics @@ -541,6 +508,5 @@ Use `/browse` from gstack for **all web browsing** — never use `mcp__claude-in | Development Roadmap | [03-DEVELOPMENT-ROADMAP.md](03-DEVELOPMENT-ROADMAP.md) | | GitHub Issues | `gh issue list --state open` | | Bugs & Fixes | CLAUDE.md → Critical Lessons Learned section | -| Feature Specs | [04-FEATURE-SPECIFICATIONS.md](04-FEATURE-SPECIFICATIONS.md) | | Design System | [DESIGN-SYSTEM.md](DESIGN-SYSTEM.md) | | Dev Environment | [DEV-ENV.md](DEV-ENV.md) — 46.202.92.250 setup, Docker, CORS, networking | diff --git a/frontend/src/components/dashboard/ActiveFlowPilotSessions.tsx b/frontend/src/components/dashboard/ActiveFlowPilotSessions.tsx index 9c232919..cc534ac1 100644 --- a/frontend/src/components/dashboard/ActiveFlowPilotSessions.tsx +++ b/frontend/src/components/dashboard/ActiveFlowPilotSessions.tsx @@ -15,7 +15,7 @@ function timeAgo(dateStr: string): string { return `${Math.floor(hours / 24)}d ago` } -export function ActiveFlowPilotSessions() { +export function ActiveFlowPilotSessions({ hideHeader = false }: { hideHeader?: boolean }) { const [sessions, setSessions] = useState([]) const [loading, setLoading] = useState(true) const navigate = useNavigate() @@ -30,9 +30,11 @@ export function ActiveFlowPilotSessions() { if (loading) { return (
-
-

Active Sessions

-
+ {!hideHeader && ( +
+

Active Sessions

+
+ )}
{Array.from({ length: 3 }).map((_, i) => (
@@ -44,25 +46,27 @@ export function ActiveFlowPilotSessions() { return (
-
-
-

Active Sessions

- {sessions.length > 0 && ( - - {sessions.length} - - )} -
- - View all - -
+
+

Active Sessions

+ {sessions.length > 0 && ( + + {sessions.length} + + )} +
+ + View all + +
+ )} {sessions.length === 0 ? (
@@ -95,7 +99,7 @@ export function ActiveFlowPilotSessions() { {session.confidence_tier || 'starting'}
-

+

{session.session_type === 'chat' ? (session.title || session.problem_summary || 'Chat in progress') : (session.problem_summary || 'Session in progress')} diff --git a/frontend/src/components/dashboard/GreetingStatStrip.tsx b/frontend/src/components/dashboard/GreetingStatStrip.tsx new file mode 100644 index 00000000..f3c88fe7 --- /dev/null +++ b/frontend/src/components/dashboard/GreetingStatStrip.tsx @@ -0,0 +1,54 @@ +import { useState, useEffect } from 'react' +import { CheckCircle, Clock, Zap } from 'lucide-react' +import type { LucideIcon } from 'lucide-react' +import { sidebarApi } from '@/api' + +interface StatItem { + icon: LucideIcon + value: string | number | null + label: string + color: string +} + +export function GreetingStatStrip() { + const [resolved, setResolved] = useState(null) + const [active, setActive] = useState(null) + const [avgMttr, setAvgMttr] = useState(null) + + useEffect(() => { + sidebarApi.getStats() + .then((stats) => { + setResolved(stats.resolved_today) + setActive(stats.active_count) + const avg = stats.resolved_today > 0 + ? Math.round(stats.total_session_minutes_today / stats.resolved_today) + : null + setAvgMttr(avg != null ? `${avg}m` : null) + }) + .catch(() => {}) + }, []) + + const stats: StatItem[] = [ + { icon: CheckCircle, value: resolved, label: 'resolved today', color: '#34d399' }, + { icon: Zap, value: active, label: 'active now', color: '#f97316' }, + { icon: Clock, value: avgMttr, label: 'avg MTTR', color: '#848b9b' }, + ] + + return ( +

+ {stats.map(({ icon: Icon, value, label, color }) => ( +
+ +
+

+ {value ?? '\u2014'} +

+

+ {label} +

+
+
+ ))} +
+ ) +} diff --git a/frontend/src/components/dashboard/PerformanceCards.tsx b/frontend/src/components/dashboard/PerformanceCards.tsx index dde40e24..60816ba5 100644 --- a/frontend/src/components/dashboard/PerformanceCards.tsx +++ b/frontend/src/components/dashboard/PerformanceCards.tsx @@ -52,7 +52,7 @@ export function PerformanceCards() { label: 'Active Now', value: active, icon: TrendingUp, - iconColor: '#38bdf8', + iconColor: '#848b9b', href: '/sessions?filter=active', }, { diff --git a/frontend/src/components/dashboard/RecentFlowPilotSessions.tsx b/frontend/src/components/dashboard/RecentFlowPilotSessions.tsx index c108fac7..26b21a8c 100644 --- a/frontend/src/components/dashboard/RecentFlowPilotSessions.tsx +++ b/frontend/src/components/dashboard/RecentFlowPilotSessions.tsx @@ -22,7 +22,7 @@ const STATUS_CONFIG: Record abandoned: { icon: XCircle, color: '#8891a0' }, } -export function RecentFlowPilotSessions() { +export function RecentFlowPilotSessions({ hideHeader = false }: { hideHeader?: boolean }) { const [sessions, setSessions] = useState([]) const navigate = useNavigate() @@ -42,18 +42,20 @@ export function RecentFlowPilotSessions() { return (
-
-

Recent Sessions

- - History - -
+

Recent Sessions

+ + History + +
+ )}
{sessions.map((session, i) => { const config = STATUS_CONFIG[session.status] || STATUS_CONFIG.abandoned @@ -73,11 +75,14 @@ export function RecentFlowPilotSessions() { )}
-

+

{session.session_type === 'chat' ? (session.title || session.problem_summary || 'Chat') : (session.problem_summary || 'Session')}

+ {session.problem_domain && ( +

{session.problem_domain}

+ )}
{timeAgo(session.resolved_at || session.created_at)} diff --git a/frontend/src/components/dashboard/StartSessionInput.tsx b/frontend/src/components/dashboard/StartSessionInput.tsx index c306073d..b5031ad1 100644 --- a/frontend/src/components/dashboard/StartSessionInput.tsx +++ b/frontend/src/components/dashboard/StartSessionInput.tsx @@ -1,18 +1,19 @@ import { useState, useRef, useEffect, useCallback } from 'react' import { useNavigate } from 'react-router-dom' -import { Send, Paperclip, Terminal, Loader2, X, RotateCcw, ImagePlus } from 'lucide-react' +import { Send, Paperclip, Terminal, Loader2, X, RotateCcw, ImagePlus, Globe, Mail, Lock, Printer, Shield } from 'lucide-react' +import type { LucideIcon } from 'lucide-react' import { cn } from '@/lib/utils' import { uploadsApi } from '@/api/uploads' import { toast } from '@/lib/toast' import type { PendingUpload } from '@/types/upload' -const SUGGESTIONS = [ - 'VPN not connecting', - 'Outlook not syncing', - 'User locked out', - 'Slow internet', - 'Printer issues', - 'MFA problems', +const SUGGESTIONS: { icon: LucideIcon; label: string }[] = [ + { icon: Globe, label: 'VPN not connecting' }, + { icon: Mail, label: 'Outlook not syncing' }, + { icon: Lock, label: 'User locked out' }, + { icon: Globe, label: 'Slow internet' }, + { icon: Printer, label: 'Printer issues' }, + { icon: Shield, label: 'MFA problems' }, ] const ACCEPTED_FILE_TYPES = 'image/png,image/jpeg,image/gif,image/webp,.txt,.log,.csv,.pdf,.docx' @@ -199,7 +200,7 @@ export function StartSessionInput() {
{/* Drag overlay */} {isDragOver && ( @@ -337,15 +338,16 @@ export function StartSessionInput() {
{/* Suggestion chips */} -
- {SUGGESTIONS.map((s) => ( +
+ {SUGGESTIONS.map(({ icon: Icon, label }) => ( ))}
diff --git a/frontend/src/pages/QuickStartPage.tsx b/frontend/src/pages/QuickStartPage.tsx index 152ff346..f19f0813 100644 --- a/frontend/src/pages/QuickStartPage.tsx +++ b/frontend/src/pages/QuickStartPage.tsx @@ -1,4 +1,3 @@ -import { useState } from 'react' import { PageMeta } from '@/components/common/PageMeta' import { useAuthStore } from '@/store/authStore' import { StartSessionInput } from '@/components/dashboard/StartSessionInput' @@ -8,31 +7,49 @@ import { PerformanceCards } from '@/components/dashboard/PerformanceCards' import { KnowledgeBaseCards } from '@/components/dashboard/KnowledgeBaseCards' import { TeamSummary } from '@/components/dashboard/TeamSummary' import { RecentFlowPilotSessions } from '@/components/dashboard/RecentFlowPilotSessions' -import { ChevronDown } from 'lucide-react' -import { cn } from '@/lib/utils' +import { GreetingStatStrip } from '@/components/dashboard/GreetingStatStrip' + +function SectionLabel({ children, action }: { children: React.ReactNode; action?: React.ReactNode }) { + return ( +
+ + {children} + +
+ {action &&
{action}
} +
+ ) +} export function QuickStartPage() { const user = useAuthStore((s) => s.user) - const [dashboardExpanded, setDashboardExpanded] = useState(false) - const greeting = new Date().getHours() < 12 + const now = new Date() + const greeting = now.getHours() < 12 ? 'morning' - : new Date().getHours() < 18 + : now.getHours() < 18 ? 'afternoon' : 'evening' + const dayOfWeek = now.toLocaleDateString('en-US', { weekday: 'long' }) + const formattedDate = now.toLocaleDateString('en-US', { month: 'long', day: 'numeric' }) + const firstName = user?.name?.split(' ')[0] || 'there' return (
-
- {/* Hero: Greeting + Input */} -
-

- Good {greeting}, {user?.name?.split(' ')[0] || 'there'} -

-

- What are you troubleshooting? -

+
+ {/* Hero: Greeting + Stat Strip */} +
+
+

+ {dayOfWeek}, {formattedDate} +

+

+ Good {greeting},
+ {firstName}. +

+
+
{/* Chat-style input */} @@ -44,39 +61,31 @@ export function QuickStartPage() {
{/* Active Sessions */} -
- +
+ Active Sessions +
+ +
{/* Recent Sessions */} -
- +
+ Recent Sessions +
+ +
- {/* Collapsible Dashboard section */} -
- - - {dashboardExpanded && ( -
- -
- - -
+ {/* Dashboard — always visible */} +
+ Dashboard +
+ +
+ +
- )} +