Files
pad/web
xarmian 99e8802095 feat(board): wire bulk lane actions via the bulk endpoint (TASK-1672) (#674)
* feat(board): wire bulk lane actions via the bulk endpoint (TASK-1672)

Extract LaneActionsMenu.svelte — a drill-down kebab menu — and populate
it with the full mutation set, each operating on the lane's CURRENTLY-
FILTERED items via api.items.bulk:
- Archive all (count + "(filtered)" in the confirm)
- Move all to ▸ (other status lanes; status-grouped boards only)
- Tag all ▸ (free input + workspace tag suggestions)
- Untag all ▸ (tags present on the lane's items)
- Set priority ▸ (the priority field's options)
- Assign all ▸ (workspace members by name)

Page handlers funnel through a shared runBulk() that calls the bulk
endpoint once, deltaSyncs, and toasts the updated/failed counts; it
returns the affected ids for TASK-1674's undo. BoardView threads the
lane's items + member/tag data + callbacks into the menu; the old
inline menu markup/styles (TASK-1671) move into the component. All
actions canEdit-gated. Drill-down clicks stopPropagation (the Svelte 5
same-click detach fix). Move scope = status, Assign = members only.

* fix(board): chunk bulk lane actions at the 1000-id server cap per Codex review (round 1)

The bulk endpoint rejects >1000 ids; the old per-item archive loop had
no ceiling, so a >1000-item filtered lane would fail every action with
"too many items". runBulk now chunks ids at 1000 (one bulk call per
chunk — a few SSE events instead of thousands) and aggregates the
updated/failed counts across chunks.

* fix(board): finalize partial bulk results when a chunk throws per Codex review (round 2)

A thrown chunk returned early, skipping deltaSync and the count toast —
leaving the UI stale after earlier chunks had already mutated items
server-side, behind a generic error. Move the try/catch inside the loop
(break on throw), then always deltaSync (when anything succeeded) and
toast the partial result: 'Verb N, M failed' on partial success, the
server error message only when nothing succeeded.

* fix(board): gate bulk lane actions on owner/editor role per Codex review (round 3)

canEditThisCollection is grant-aware (true for collection edit grants),
but the bulk endpoint requires workspace owner/editor (TASK-1668), so a
grant-only editor saw the lane bulk actions and got a 403 per click.
Gate the bulk callbacks (archive-all/move/tag/untag/set-priority/assign,
in both Board and List) on a new canBulkEdit = owner|editor role. The
single `+` create stays grant-aware (canEditThisCollection). LaneActions-
Menu's action callbacks are now optional and each entry hides when its
callback is absent, so a grant-editor sees only "Add item here".

* fix(board): drive lane-action visibility off callbacks, not canEdit per Codex review (round 4)

The kebab wrapper was still inside {#if canEdit} (= canEditThisCollection),
so an owner/editor without a collection edit grant (canBulkEdit true,
canEdit false) couldn't open the menu at all. Show the `+` when
onCreateInColumn is wired and the kebab when any menu action is wired
(hasMenuActions) — each callback already encodes its own permission.
Same fix for ListView's archive-group button (gate on onArchiveGroup
alone, not canEdit && onArchiveGroup).

* fix(board): lane-aware kebab visibility per Codex review (round 5)

The kebab showed whenever any bulk callback existed, but the bulk menu
entries only render for a non-empty lane — so a role-only bulk editor
(no onCreateInColumn) saw a ⋯ that opened an empty panel on empty
schema lanes. Show the kebab only when onCreateInColumn is wired OR the
lane has items AND a bulk action is wired.
2026-05-30 22:20:07 -04:00
..
2026-03-26 01:52:36 +00:00
2026-03-26 01:52:36 +00:00
2026-03-26 01:52:36 +00:00
2026-03-26 01:52:36 +00:00
2026-03-26 01:52:36 +00:00
2026-03-26 01:52:36 +00:00

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