Skip to content

v2: rules page — list, detail, create/edit form#1107

Merged
canalesb93 merged 3 commits into
mainfrom
v2-rules-page
May 16, 2026
Merged

v2: rules page — list, detail, create/edit form#1107
canalesb93 merged 3 commits into
mainfrom
v2-rules-page

Conversation

@canalesb93
Copy link
Copy Markdown
Owner

Summary

  • Builds the Rules page and its subpages for the v2 SPA — list, detail, create/edit form.
  • List mirrors v1's row-card layout (avatar, stage, conditions/actions counts, hits) and adds search + enabled filter + sort.
  • Form supports the full DSL surface: visual conditions builder with field/op/value pickers, action builder (set_category / add_tag / remove_tag / add_comment), AND/OR logic toggle, pipeline-stage presets (Baseline/Standard/Refinement/Override), live preview panel, JSON escape hatch for nested combinators, combination-warning hints.
  • Detail page renders read-only conditions/actions, stat tiles, retroactive-apply confirm dialog, delete confirm dialog.
  • All four routes hit /api/v1/rules* via the v2 session cookie — no new backend code. Rule conditions follow the canonical field grammar in docs/rule-dsl.md (provider_name, provider_merchant_name, …).

Files

  • web/src/api/types.tsCondition, RuleAction, TransactionRule, RulesPage, RulePreviewResult, plus create/update inputs.
  • web/src/api/queries/rules.tsuseRules, useRule, useRuleSyncHistory, useCreateRule, useUpdateRule, useToggleRule, useDeleteRule, useApplyRule, usePreviewRule.
  • web/src/features/rules/rule-utils.ts (field grammar, condition⇄form transforms, stage presets), rule-row.tsx, rule-form.tsx, condition-row.tsx, action-row.tsx, preview-panel.tsx, rule-display.tsx (read-only conditions/actions).
  • web/src/routes/{rules,rule-detail,rule-form}.tsx — page shells.
  • web/src/main.tsx — registers the four routes.

Screenshots

Rules list (4 rules — system + user-created)

rules list desktop

Rule detail ("Uber rides → Rideshare", with retroactive apply + delete rails)

rule detail desktop

New rule form

new rule form desktop

Edit rule form (round-tripped two-condition AND tree)

edit rule form desktop

Mobile — list + new form

List · mobileNew rule · mobile
rules list mobile new rule mobile

Test plan

  • bun run build (tsc + vite) green.
  • List, detail, new-form, edit-form render against the local backend with the v2 session cookie.
  • Created a 2-condition AND rule via API and confirmed it round-trips through the edit form (field dropdowns populate from canonical field names).
  • Mobile breakpoint validated for list + form (390×844).
  • Manual: retroactive apply (/api/v1/rules/{id}/apply) — wired but not run end-to-end this session.
  • Manual: delete-with-confirm — wired through useDeleteRule but not exercised in browser.

🤖 Generated with Claude Code

Build the Rules page and its subpages for the v2 SPA. Mirrors the v1 admin
UI structure (list with stage badges and hit counts, detail with conditions/
actions cards and a retroactive-apply action, form with visual condition +
action builders, JSON escape hatch, live preview panel, pipeline-stage
presets) on shadcn primitives + TanStack Router/Query + RHF/zod.

Wires four routes: /rules (list, PAGE_OVERRIDE), /rules/new, /rules/$id
(detail), /rules/$id/edit. All hit the public /api/v1/rules surface via the
v2 session cookie. Rule conditions follow the canonical field grammar from
docs/rule-dsl.md.
Resolves a conflict in main.tsx — keeps both the accounts route additions
from main and the rules route additions from this branch.

Also fixes a layout issue where the absolutely-positioned Edit + kebab
buttons on each rule row overlapped the lg-only stats columns
(stage / last active). The Link content now carries `pr-24` on sm+ so the
stats columns end well clear of the action cluster.
@canalesb93
Copy link
Copy Markdown
Owner Author

Layout fix — Edit + kebab no longer overlap the lg-stats columns; resolved the merge conflict in main.tsx against main (rules + accounts routes side by side).

rules list after fix

Merges main (api-keys + providers + accounts pages). Conflict in
web/src/api/types.ts auto-resolved to keep both blocks.

Simplify-pass on the rules code (from three review agents):

- Extract `RuleAvatar` with size variant — shared between rule-row.tsx
  and rule-detail.tsx, dropping a parallel 4-branch avatar.
- Extract `categoryTileStyle()` to rule-utils.ts — was inlined 3×.
- Reuse the shadcn `Pagination` primitives via a new
  components/pagination-bar.tsx (TransactionsPagination now wraps it).
- Use `AlertDialogAction variant="destructive"` instead of inlining the
  destructive class string in two places.
- Reuse `flattenCategories` from queries/categories instead of a parallel
  tree walk inside condition-row.
- Lift `useCategories` / `useTags` to RuleActionsDisplay once instead of
  per-row subscriptions in CategoryName / TagChip.
- Drop the dead `useTags()` + `void tags` workaround in condition-row's
  ValueInput; move `isCategoryEq` derivation inside.
- Replace `withMutationToast(() => Promise.reject/resolve)` abuse in
  rule-form route with direct `sonner` calls.
- Type `getRowErrors` with `UseFormReturn<RuleFormValues>` instead of
  `any`; drop the eslint-disable.
- Drop dead UUID-keyed `useRule` invalidation in update/toggle mutations.
- Use the `isMatchAll()` helper in `comboWarnings` instead of inline
  `Object.keys(...).length === 0`. Add `watchedTrigger` so the memo dep
  list is honest.
- Drop unused `RULES_PAGE_SIZE` export from rules.tsx; remove
  WHAT-narrating section comments inside the form.
@canalesb93 canalesb93 merged commit 77dee75 into main May 16, 2026
10 checks passed
Copy link
Copy Markdown
Owner Author

Merge activity

@canalesb93 canalesb93 deleted the v2-rules-page branch May 16, 2026 06:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant