--- name: add-settings-page description: Add a new Sim settings page, or audit existing settings pages for design-system compliance with the shared SettingsPanel layout. Use when creating a settings tab, or when asked to check/clean up settings pages so they match the design system (consistent title, header, search, spacing). --- # Settings Page (add / audit) Settings page chrome (header bar, scroll region, content column, nav-driven title + description) is owned by the `settings/[section]/layout.tsx` shell. Each page renders through **`SettingsPanel`**, which registers the page's header data (actions, search, back) with that shell and renders only the body. The full convention lives in `.claude/rules/sim-settings-pages.md` — read it first; this skill is the procedure. Key paths: - Chrome shell: `apps/sim/app/workspace/[workspaceId]/settings/[section]/layout.tsx` (`SettingsHeaderShell`) - `SettingsPanel` registrar: `apps/sim/components/settings/settings-panel.tsx` - Nav metadata (titles + descriptions): `apps/sim/components/settings/navigation.ts` - Section switch + provider: `apps/sim/app/workspace/[workspaceId]/settings/[section]/settings.tsx` - Pages: `apps/sim/app/workspace/[workspaceId]/settings/components//.tsx` and EE pages under `apps/sim/ee//components/` ## Mode A — Add a new settings page 1. **Navigation.** In `navigation.ts`: add the id to the `SettingsSection` union, then a `NavigationItem` with `label` AND a one-line `description` (verb-first, ~40–55 chars, product voice per `.claude/rules/constitution.md`). Place it in the right `section` group and set any gating flags (`requiresHosted`, `requiresEnterprise`, etc.). 2. **Wire the switch.** Add the component to the `effectiveSection` render switch in `settings/[section]/settings.tsx` (lazy `dynamic(...)` like its siblings). 3. **Build the body inside `SettingsPanel`** per the rule's canonical page shape: `actions`, `search`, `children`, modal siblings in a fragment. 4. **If the page has editable state**, wire the shared save/discard stack — put `SaveDiscardActions` (dirty-gated Discard+Save chips) in `actions`, and call `useSettingsUnsavedGuard({ isDirty })` **before any early-return gate**. Detail sub-views additionally route the back chip through `guard.guardBack(closeFn)` and render the shared `UnsavedChangesModal`. Never hand-roll a Save button, a `beforeunload`, or an "Unsaved changes" modal — they're centralized. See the "Save / Discard + unsaved-changes guard" section in `.claude/rules/sim-settings-pages.md`. 5. **Verify:** `cd apps/sim && bun run type-check`; `bunx biome check --write `. ## Mode B — Audit existing settings pages For each page component, confirm the checklist in `.claude/rules/sim-settings-pages.md`: 1. Find hand-rolled shells that should be `SettingsPanel`: `git grep -n "flex h-full flex-col bg-\[var(--bg)\]" -- 'apps/sim/**/settings/' 'apps/sim/ee/'` — every match should be either `settings-panel.tsx`, a **detail sub-view** (has a `` back button), or an entitlement/loading **gate** early-return. Anything else is a page that still needs migrating. 2. Find hand-rolled title blocks (should be 0 outside detail views): `git grep -n "text-\[var(--text-body)\] text-lg" -- 'apps/sim/**/settings/' 'apps/sim/ee/'` 3. Find literal pixel text sizes (should be 0 — see "Text-scale tokens" in `.claude/rules/sim-settings-pages.md` for the token map and the row title/subtitle pairing convention): `git grep -nE "text-\[1[0-8]px\]" -- 'apps/sim/**/settings/' 'apps/sim/ee/'` — should be 0. Display type above the scale (`text-[40px]` hero headings) is deliberate and out of scope. 4. Confirm each page imports `SettingsPanel` and that its `NavigationItem` has an accurate `description` of consistent length with its peers. - Editable pages: confirm Save/Discard go through `SaveDiscardActions` and dirty is wired via `useSettingsUnsavedGuard` (called before early-return gates) — flag any hand-rolled Save button, `beforeunload`, or unsaved modal. `git grep -n "beforeunload" -- 'apps/sim/**/settings/' 'apps/sim/ee/'` should only hit the centralized `use-settings-before-unload.ts`. 5. When migrating a page, change ONLY the structural shell→`SettingsPanel` swap: move header chips to `actions`, the standalone search to `search`, delete the `

` title block, replace the three closing `` (column/scroll/shell) with ``, and keep modal siblings in a `<>` fragment. Do NOT touch handlers, state, queries, conditional rendering, or detail/gate returns. Drop per-page `gap-*`/`pt-*` on the content column in favor of the panel default. 6. When fixing literal pixel text sizes, replace ONLY the size class with its exact-pixel-equivalent named token (e.g. `text-[12px]` → `text-caption`, never a different size) — this must render pixel-identical, not restyle the page. Leave color tokens (`--text-primary` vs `--text-body`, etc.) untouched unless they're also being changed for an unrelated, deliberate reason. 7. Remove now-unused imports (`ChipInput`/`Search`) ONLY after grepping that they are not still used elsewhere in the file (e.g. by a detail view). 8. **Verify the whole sweep:** `bun run type-check`, `biome check` on every touched file, and run the affected pages' tests. Diff each file against the base and confirm the change is purely structural before shipping. ## Mode C — Migrate list rows to `SettingsResourceRow` Read "The resource row" in `.claude/rules/sim-settings-pages.md` first — it is the contract. Then, per page: 1. Find hand-rolled rows: `git grep -n "truncate text-\[var(--text-body)\] text-sm" -- 'apps/sim/app/workspace/' 'apps/sim/ee/'` Every match outside `settings-resource-row.tsx` is either a row to migrate or a genuinely different shape (multi-line body, tabular columns, a grid) that stays bespoke — decide which, and say so. 2. Replace the row *and* its wrapper: a `