feat: flexible intake — deferred variables + prepared sessions (#103)

* feat: flexible intake — deferred variables + prepared sessions

Remove blocking intake form modal. Variables are now filled inline during
flow execution or pre-filled via prepared sessions. Adds PATCH /sessions/{id}/variables
endpoint, POST /sessions/prepare for session pre-staging, inline variable prompts
in StepDetail, editable Session Variables panel, and "Prepared for You" dashboard section.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: pass treeData directly to startSession to avoid stale state

setTree(treeData) hasn't committed when startSession runs immediately
after, so tree is still null and getStepsFromTree returns []. This
caused the step detail area to render empty on new session start.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: wire PrepareSessionModal entry point in Flow Library

Add "Prepare session" button (clipboard icon) to grid, list, and table
views for procedural/maintenance flows. Clicking fetches tree intake
fields and account members, then opens PrepareSessionModal.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit was merged in pull request #103.
This commit is contained in:
chihlasm
2026-03-10 09:49:51 -04:00
committed by GitHub
parent 4727106141
commit ccd06c9ed4
25 changed files with 1214 additions and 102 deletions

View File

@@ -22,7 +22,7 @@ export function SessionHistoryPage() {
const [hasMore, setHasMore] = useState(false)
const [trees, setTrees] = useState<TreeListItem[]>([])
const [isLoading, setIsLoading] = useState(true)
const [filter, setFilter] = useState<'all' | 'completed' | 'active'>('all')
const [filter, setFilter] = useState<'all' | 'completed' | 'active' | 'prepared'>('all')
// Initialize filters from URL params
const [filters, setFilters] = useState<SessionFilterState>(() => {
@@ -67,8 +67,10 @@ export function SessionHistoryPage() {
try {
const params: Record<string, string | boolean> = {}
// Tab filter (all/active/completed)
if (filter !== 'all') {
// Tab filter (all/active/completed/prepared)
if (filter === 'prepared') {
params.status = 'prepared'
} else if (filter !== 'all') {
params.completed = filter === 'completed'
}
@@ -173,7 +175,7 @@ export function SessionHistoryPage() {
{/* Filter Tabs */}
<div className="mb-6 flex gap-2 border-b border-border">
{(['all', 'active', 'completed'] as const).map((tab) => (
{(['all', 'active', 'completed', 'prepared'] as const).map((tab) => (
<button
key={tab}
onClick={() => setFilter(tab)}
@@ -267,7 +269,7 @@ export function SessionHistoryPage() {
{/* Timestamps */}
<p className="mt-1 text-sm text-muted-foreground">
Started: {formatDate(session.started_at)}
Started: {session.started_at ? formatDate(session.started_at) : 'Not started'}
{session.completed_at && (
<> · Completed: {formatDate(session.completed_at)}</>
)}