fix(flowpilot): fix 4 Phase 2 escalation bugs + update Tailwind version in CLAUDE.md

- Fix escalation status mismatch: hook set 'escalated' but backend returns
  'requesting_escalation'
- Fix list_sessions to include sessions picked up by Engineer B via
  escalation_package->>'picked_up_by' JSONB query
- Fix sidebar escalation icon color: was Tailwind class 'text-amber-400'
  passed to style={{color}}, now hex '#fbbf24'
- Replace window.location.reload() after ticket linking with
  onReloadSession callback to preserve session state
- Update CLAUDE.md: Tailwind CSS v3 → v4 (@tailwindcss/vite, CSS-only config)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-19 03:10:11 +00:00
parent bbe590bfec
commit ce118b51d8
6 changed files with 21 additions and 10 deletions

View File

@@ -23,7 +23,7 @@
- **Fonts:** Bricolage Grotesque (`font-heading`, headings/titles), IBM Plex Sans (`font-sans`, body text), JetBrains Mono (`font-label`, labels/badges/timestamps) — loaded via Google Fonts
- **Logo:** Inline SVG in `BrandLogo.tsx` (decision-tree icon with cyan gradient). Wordmark: "Resolution" in `text-foreground` + "Flow" in `text-gradient-brand`
- **Brand assets:** `brand-assets/` (source SVGs + brand-guide.html), `frontend/src/assets/brand/` (app assets), `frontend/public/icons/` (favicon)
- **CSS utilities:** `text-gradient-brand`, `bg-gradient-brand`, `bg-gradient-brand-hover` (defined in `tailwind.config.js` and `index.css`). Glass utilities: `.glass-card` (interactive, `scale(1.02)` hover), `.glass-card-static` (no hover transform), `.active-glow` (breathing cyan shadow)
- **CSS utilities:** `text-gradient-brand`, `bg-gradient-brand`, `bg-gradient-brand-hover` (defined in `index.css` via `@theme`). Glass utilities: `.glass-card` (interactive, `scale(1.02)` hover), `.glass-card-static` (no hover transform), `.active-glow` (breathing cyan shadow)
- **Layout:** App shell with persistent sidebar + top bar + main content (CSS Grid). Two fixed atmosphere orbs (cyan top-right, purple bottom-left) behind the shell for ambient glow. See [UI-DESIGN-SYSTEM.md](UI-DESIGN-SYSTEM.md)
- **Navigation:** Sidebar nav with type sub-items (All Flows → Troubleshooting / Projects / Maintenance). Pinned flows section for quick access. NO workspace switcher. See [UI-DESIGN-SYSTEM.md](UI-DESIGN-SYSTEM.md)
- **Terminology:** User-facing label is "Flows" (not "Trees"). Procedural flows are called "Projects" in the UI. Maintenance flows are called "Maintenance" in the UI. `tree_type` column values unchanged in DB.
@@ -91,7 +91,7 @@ When adding new pages/components: use "ResolutionFlow" branding, ice-cyan gradie
### Frontend
- **Framework:** React 19 + Vite + TypeScript
- **Styling:** Tailwind CSS v3 — dark-first with purple gradient accents (see Branding section)
- **Styling:** Tailwind CSS v4 (`@tailwindcss/vite` plugin, CSS-only config in `index.css`) — dark-first with ice-cyan gradient accents (see Branding section)
- **State:** Zustand (with immer + zundo for undo/redo)
- **Routing:** React Router v7
- **API Client:** Axios with token refresh interceptor
@@ -124,7 +124,7 @@ patherly/
│ │ ├── pages/ # All page components
│ │ ├── store/ # Zustand stores (auth, treeEditor, proceduralEditor, userPreferences)
│ │ └── types/ # TypeScript interfaces
│ └── tailwind.config.js
│ └── (Tailwind v4: CSS-only config in src/index.css)
├── docs/plans/archive/ # Archived design/impl docs (pre-March 2026)
├── CLAUDE.md # This file
├── CURRENT-STATE.md # Detailed feature status

View File

@@ -15,7 +15,7 @@ from typing import Annotated, Optional
from uuid import UUID
from fastapi import APIRouter, Depends, HTTPException, Query, Request, status
from sqlalchemy import select, func
from sqlalchemy import or_, select, func
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import selectinload
@@ -465,10 +465,16 @@ async def list_sessions(
skip: int = Query(0, ge=0),
limit: int = Query(20, ge=1, le=100),
):
"""List the current user's AI sessions."""
"""List the current user's AI sessions (owned or picked up)."""
user_id_str = str(current_user.id)
query = (
select(AISession)
.where(AISession.user_id == current_user.id)
.where(
or_(
AISession.user_id == current_user.id,
AISession.escalation_package["picked_up_by"].as_string() == user_id_str,
)
)
.order_by(AISession.created_at.desc())
.offset(skip)
.limit(limit)

View File

@@ -35,6 +35,7 @@ interface FlowPilotSessionProps {
onPause?: () => Promise<void>
onResume?: () => Promise<void>
onRate: (rating: number) => void
onReloadSession?: () => Promise<void>
}
export function FlowPilotSession({
@@ -54,6 +55,7 @@ export function FlowPilotSession({
onPause,
onResume,
onRate,
onReloadSession,
}: FlowPilotSessionProps) {
const scrollRef = useRef<HTMLDivElement>(null)
const [showTicketPicker, setShowTicketPicker] = useState(false)
@@ -87,7 +89,9 @@ export function FlowPilotSession({
})
toast.success(`Linked to ticket #${ticketId}`)
// Reload session to get updated ticket_data
window.location.reload()
if (onReloadSession) {
await onReloadSession()
}
} catch {
toast.error('Failed to link ticket')
} finally {

View File

@@ -86,7 +86,7 @@ export function Sidebar() {
<NavItem href="/pilot" icon={Sparkles} label="New Session" iconColor={NAV_COLORS.dashboard} collapsed />
<NavItem href="/" icon={LayoutGrid} label="Dashboard" iconColor={NAV_COLORS.dashboard} collapsed />
<NavItem href="/sessions" icon={Clock} label="Sessions" badge={stats?.active_count || undefined} iconColor={NAV_COLORS.sessions} collapsed />
<NavItem href="/escalations" icon={AlertTriangle} label="Escalations" iconColor="text-amber-400" collapsed />
<NavItem href="/escalations" icon={AlertTriangle} label="Escalations" iconColor="#fbbf24" collapsed />
<NavItem href="/trees" icon={Network} label="All Flows" matchPaths={['/trees', '/flows']} iconColor={NAV_COLORS.flows} collapsed />
<NavItem href="/assistant" icon={Brain} label="FlowPilot" iconColor={NAV_COLORS.flowPilot} collapsed />
<NavItem href="/scripts" icon={Code2} label="Script Library" iconColor={NAV_COLORS.scripts} collapsed />
@@ -136,7 +136,7 @@ export function Sidebar() {
Resolve
</div>
<NavItem href="/sessions" icon={Clock} label="Sessions" badge={stats?.active_count || undefined} iconColor={NAV_COLORS.sessions} />
<NavItem href="/escalations" icon={AlertTriangle} label="Escalations" iconColor="text-amber-400" />
<NavItem href="/escalations" icon={AlertTriangle} label="Escalations" iconColor="#fbbf24" />
<NavItem
href="/trees"
icon={Network}

View File

@@ -151,7 +151,7 @@ export function useFlowPilotSession(): UseFlowPilotSession {
setIsProcessing(true)
try {
const result = await aiSessionsApi.escalateSession(session.id, data)
setSession(prev => prev ? { ...prev, status: 'escalated' } : null)
setSession(prev => prev ? { ...prev, status: 'requesting_escalation' } : null)
setDocumentation(result.documentation)
setPsaPushStatus(result.psa_push_status)
setPsaPushError(result.psa_push_error)

View File

@@ -179,6 +179,7 @@ export default function FlowPilotSessionPage() {
onPause={fp.pauseSession}
onResume={fp.resumeOwnSession}
onRate={fp.rateSession}
onReloadSession={() => fp.loadSession(fp.session!.id)}
/>
</div>
</div>