mirror of
https://github.com/PerpetualSoftware/pad.git
synced 2026-09-20 17:43:26 +00:00
bafb3c2be5
* feat(web): create-time Display/Quick Actions + live prompt preview
Closes TASK-599 in PLAN-593 — the last task.
Closes the parity gap between Create and Edit modals by bringing the
Display and Quick Actions editors to the Create flow (under an
"Advanced" reveal so the default create path stays short), and adds a
live substitution preview to the Quick Actions prompt editor in both
modals.
New shared code
- web/src/lib/utils/quick-action-preview.ts: single source of truth
for the template-variable list, kept in lockstep with the runtime
substitution in QuickActionsMenu. Exports parsePrompt() that
tokenizes a prompt into text / known-var / unknown-var segments,
plus contextFromItem() (real items for Edit) and
placeholderContext() (synthetic for Create or empty collections).
- DisplaySettingsEditor.svelte: extracts the 5 display selects
(default view, layout, board/list group-by, list sort-by) into a
reusable pure-presentation block with bindable props.
- QuickActionsEditor.svelte: extracts the full Quick Actions sub-UI
(both Item and Collection sections) with add/remove/reorder logic
internal to the component. Each action card now renders a live
preview panel below the prompt input showing the resolved output
with subtle blue highlights on known variables and red + wavy
underline on unknown ones. An explicit warning line appears below
the preview when typos are detected.
EditCollectionModal
- Replaces the inline Display tab markup with DisplaySettingsEditor.
- Replaces the inline Quick Actions tab markup with QuickActionsEditor.
- Fetches the first item in the collection on open
(api.items.listByCollection limit=1) to build a realistic preview
context; falls back to placeholder values if the collection is
empty or the fetch fails.
- Net result: ~390 lines removed (deduped into the components), local
state for action list and group-by derivation remains here since it
drives the schema save.
CreateCollectionModal
- New collapsible "Advanced" section below the fields area, collapsed
by default. Contains DisplaySettingsEditor + QuickActionsEditor.
- New state for default_view / layout / board_group_by / list_group_by
/ list_sort_by / quick_actions, wired into handleCreate's settings
serialization.
- Template selection now pre-fills the Advanced state from the
template's settings (board_group_by, default_view, quick_actions
etc.), so template-provided settings are preserved even for users
who never open the Advanced section.
- Derived selectFieldKeys / sortableFieldKeys from the (not-yet-saved)
fields so the group-by pickers reflect what the user is building.
- A small $effect auto-corrects boardGroupBy / listGroupBy when the
user removes the select field they pointed at (Advanced only —
doesn't mutate state behind the user's back while collapsed).
- Preview context uses placeholderContext() since no items exist yet;
the {collection} token updates live as the user types a name.
Out of scope
- Cross-field done-detection (separate, tracked in TASK-604).
- Any new field types / schema additions.
* fix(web): scope-aware previews and honest empty-resolution rendering
Two Codex findings on PR #139, both about preview accuracy:
P2: Use scope-aware context for collection action previews
Collection-scope actions run with `item` unset in QuickActionsMenu,
so item-only variables ({ref}, {title}, {status}, {priority},
{content}, {fields}, {plan}, {phase}) resolve to empty strings at
runtime. The preview was parsing collection-scope prompts with the
same item-populated context used for item-scope actions, so the
preview could show rich substitutions the user would never actually
get when clicking the action.
Fix: add toCollectionScope() in quick-action-preview.ts that clears
item-only variables and keeps only {collection}. QuickActionsEditor
now derives itemScopeContext (verbatim) and collectionScopeContext
(reshaped), and the two sections parse against the right one.
P2: Render empty resolved variables as empty in preview
The preview template `{seg.resolved || `{${seg.name}}`}` treated
legit empty substitutions as falsy and fell through to the raw
token, so a known variable that legitimately resolves to `""` at
runtime (e.g. {plan} with no plan, or any item variable in a
collection-scope action) was displayed as if the token would be
copied literally. That's the opposite of what runtime actually
does.
Fix: when seg.resolved === '', render an italic muted "(empty)"
pill with a tooltip explaining the variable resolves to an empty
string. Non-empty resolutions render unchanged. This surfaces the
emptiness to the user without lying about what gets copied.
Both fixes pair with the scope-aware context change — collection-
scope previews now correctly show all item variables as "(empty)"
instead of rich values, matching runtime output exactly.
* fix(web): drop template quick_actions from spread so user can clear them
Codex P2 (PR #139): the Create modal merged `selectedSettings` into
the final settings object and only wrote `quick_actions` when
`savedActions.length > 0`. After picking a template with pre-shipped
quick actions, a user who deleted every quick-action row would still
end up saving the template's original quick_actions because they were
re-introduced by `...selectedSettings`. "Remove all quick actions"
was effectively impossible for templates that defined them.
Fix: destructure `quick_actions` out of `selectedSettings` before the
spread, leaving only the non-action template fields (default_view,
board_group_by, etc.) to be merged. `quickActions` state is already
the single source of truth for quick actions — it's populated from
the template on pick and then edited by the user — so the spread no
longer needs to contribute them. This makes `savedActions` ← the
in-editor list authoritative, including when it's empty.
Pad Web UI
SvelteKit 2 + Svelte 5 frontend for Pad, compiled to static files and embedded into the Go binary.
Development
npm install
npm run dev # Dev server at localhost:5173 (proxies API to localhost:7777)
npm run build # Production build to build/
npm run check # Type checking with svelte-check
When developing, run the Go backend separately with make dev from the project root.
Building for Production
Do not build in isolation. Always use make build from the project root — this builds the web frontend, then compiles the Go binary with the build output embedded via //go:embed.
Stack
- Svelte 5 with runes (
$state,$derived,$effect) - SvelteKit 2 with
adapter-static(SPA mode) - Tiptap block editor with markdown round-trip
- svelte-dnd-action for drag-and-drop in board/list views
- SSE for real-time updates
- TypeScript throughout
Structure
src/
routes/ SvelteKit pages
+layout.svelte App shell (sidebar + main)
+page.svelte Landing/redirect
[workspace]/
+page.svelte Dashboard (collections, phases, activity)
+layout.svelte SSE connection per workspace
[collection]/
+page.svelte Collection view (board/list)
[collection]/[item]/
+page.svelte Item detail + editor
conventions/ Purpose-built conventions page
playbooks/ Purpose-built playbooks page
settings/ Workspace settings
lib/
api/client.ts HTTP API client
components/
layout/ Sidebar, navigation
editor/ Tiptap editor, raw markdown editor
fields/ FieldEditor, relation picker
items/ ItemCard, ItemDetail
collections/ BoardView, ListView
common/ StatusBadge, badges, modals
search/ CommandPalette
activity/ ActivityFeed
stores/ Svelte 5 reactive stores
workspace.svelte.ts Workspace state
collections.svelte.ts Collection + item state
ui.svelte.ts Sidebar, mobile state
types/index.ts TypeScript types and constants
app.css Global styles and design tokens