Skip to content
Merged
123 changes: 123 additions & 0 deletions .claude/rules/sim-settings-pages.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
---
paths:
- "apps/sim/app/workspace/*/settings/**"
- "apps/sim/ee/**/components/**"
---

# Settings Pages

Every settings page renders through the shared **`SettingsPanel`** primitive
(`@/app/workspace/[workspaceId]/settings/components/settings-panel`). It owns the
page chrome so pages never hand-roll it: a fixed header bar (right-aligned
actions), a scroll region, and a centered `max-w-[48rem]` content column led by a
**title + description that come from navigation metadata**. Pages render only
their body.

Do NOT hand-roll any of these in a settings page — they are the panel's job:

- `<div className='flex h-full flex-col bg-[var(--bg)]'>` shell
- the header bar (`flex flex-shrink-0 … px-[16px] pt-[8.5px] pb-[8.5px]`)
- the scroll container (`min-h-0 flex-1 overflow-y-auto px-6 [scrollbar-gutter:stable_both-edges]`)
- the content column (`mx-auto … max-w-[48rem] … gap-7`)
- a title block (`<h1 className='font-medium text-[var(--text-body)] text-lg'>` + `<p className='text-[var(--text-muted)] text-md'>`)
- the page-level search input

## Canonical page shape

```tsx
import { SettingsPanel } from '@/app/workspace/[workspaceId]/settings/components/settings-panel'

return (
<SettingsPanel
actions={
<Chip leftIcon={Plus} variant='primary' onClick={onCreate}>
Create
</Chip>
}
search={{ value: searchTerm, onChange: setSearchTerm, placeholder: 'Search …' }}
>
{/* body only — sections, lists, forms */}
</SettingsPanel>
)
```

When the page has modal/dialog siblings, wrap them with the panel in a fragment:

```tsx
return (
<>
<SettingsPanel actions={…}>{body}</SettingsPanel>
<SomeModal … />
</>
)
```

## `SettingsPanel` props

- `actions?: ReactNode` — right-aligned header chips. Wrap multiple in a fragment;
the slot reserves the 30px chip height even when empty, so vertical rhythm is
identical across pages. Conditional actions are fine: `actions={canManage && <Chip…/>}`.
- `search?: { value; onChange: (value: string) => void; placeholder?; disabled? }` —
renders the canonical search field directly below the title. Pass `setSearchTerm`
straight to `onChange`. Use this for a standalone search; if search shares a row
with other controls (sort, filters, a date picker), render that whole row in
`children` instead and omit the prop.
- `title?` / `description?` — overrides for the nav-driven defaults. **Only** for a
detail sub-view that needs a different heading; normal pages never pass these.
- `scrollContainerRef?: React.Ref<HTMLDivElement>` — forwards a ref to the scroll
region (e.g. programmatic scroll-to-bottom).
- `contentClassName?` — layout/spacing only; reach for it rarely. Prefer the
default `gap-7`.

## Title + description live in navigation metadata

`apps/sim/app/workspace/[workspaceId]/settings/navigation.ts` is the single source
of truth. Every `NavigationItem` carries a one-line `description`; `SettingsPanel`
resolves both via `getSettingsSectionMeta(section)` and the
`SettingsSectionProvider` the settings shell wraps around the active section.

Adding a new settings page:

1. Add the `SettingsSection` id + a `NavigationItem` (with `label` **and**
`description`) in `navigation.ts`. Keep descriptions verb-first, one line,
~40–55 chars, in the product voice (see `.claude/rules/constitution.md`).
2. Render the component inside the shell's `effectiveSection` switch in
`settings/[section]/settings.tsx`.
3. Build the component body inside `<SettingsPanel>` — no shell, no title block.

## Other shared settings primitives (do not re-roll these)

- **`SettingsEmptyState`** (`…/components/settings-empty-state`) — the canonical
muted status message. `variant='fill'` (default) centers in the available
height (empty list, or a not-entitled/loading gate); `variant='inline'` sits in
flow (a search "no results"). Never hand-roll
`<div className='flex h-full items-center justify-center text-[var(--text-muted)] text-sm'>`
or `<div className='py-4 text-center …'>`. It owns the `--text-muted` + `text-sm`
tokens, so it also keeps these messages consistent across pages.
- **`RowActionsMenu`** (`…/components/row-actions-menu`) — the trailing `...`
actions menu for a list row. Pass `label` (aria-label) and
`actions: RowAction[]` (`{ label, onSelect, destructive?, disabled? }`); the
component renders the canonical flush `...` trigger + `DropdownMenuContent`.
Conditional items become array spreads: `...(canManage ? [{…}] : [])`. Never
hand-roll the `<DropdownMenu>` + `<MoreHorizontal>` trigger per page.

## Detail sub-views (the one exception)

A drill-down view reached from a list row (selected MCP server, workflow MCP
server, credential set, permission group) keeps its **own** chrome because it
needs a left-aligned back button (`<Chip leftIcon={ArrowLeft}>`), which the panel
header (right-actions only) does not model. Leave those returns as hand-rolled
shells; only the list/main view uses `SettingsPanel`. Gate/early-return states
(not-entitled, loading, upgrade prompts) also stay as-is.

## Audit checklist

A settings page is design-system-clean when:

- [ ] Its main return is a `<SettingsPanel>` (or `<>…<SettingsPanel>…</>` with modal siblings) — no hand-rolled shell/header/scroll/column.
- [ ] It renders **no** hand-rolled `<h1>`/description title block — the title comes from nav metadata.
- [ ] Header chips are in `actions`; a standalone search is in the `search` prop.
- [ ] Its `NavigationItem` has an accurate, consistent-length `description`.
- [ ] Detail sub-views and entitlement/loading gates keep their own chrome (intentional).
- [ ] No business logic, handlers, or conditional rendering changed by the migration.
- [ ] `tsc`, `biome`, and the page's tests pass.
57 changes: 57 additions & 0 deletions .claude/skills/add-settings-page/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
---
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)

Sim settings pages all render through the shared **`SettingsPanel`** primitive,
which owns the page chrome and renders a nav-driven title + description. The full
convention lives in `.claude/rules/sim-settings-pages.md` — read it first; this
skill is the procedure.

Key paths:
- Layout primitive: `apps/sim/app/workspace/[workspaceId]/settings/components/settings-panel/settings-panel.tsx`
- Nav metadata (titles + descriptions): `apps/sim/app/workspace/[workspaceId]/settings/navigation.ts`
- Section switch + provider: `apps/sim/app/workspace/[workspaceId]/settings/[section]/settings.tsx`
- Pages: `apps/sim/app/workspace/[workspaceId]/settings/components/<name>/<name>.tsx` and EE pages under `apps/sim/ee/<feature>/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`.** Never hand-roll the shell, header
bar, scroll region, content column, or title block. Put header buttons in
`actions`, a standalone search in `search={{ value, onChange, placeholder }}`,
and the page content as `children`. Modals go beside the panel inside a `<>`.
4. **Verify:** `cd apps/sim && bunx tsc --noEmit`; `bunx biome check --write <file>`.

## 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 `<Chip leftIcon={ArrowLeft}>` 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. Confirm each page imports `SettingsPanel` and that its `NavigationItem` has an
accurate `description` of consistent length with its peers.
4. When migrating a page, change ONLY the structural shell→`SettingsPanel` swap:
move header chips to `actions`, the standalone search to `search`, delete the
`<h1>` title block, replace the three closing `</div>` (column/scroll/shell)
with `</SettingsPanel>`, 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.
5. 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).
6. **Verify the whole sweep:** `tsc --noEmit`, `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.
6 changes: 3 additions & 3 deletions apps/docs/components/icons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2760,10 +2760,10 @@ export function TinybirdIcon(props: SVGProps<SVGSVGElement>) {

export function ThriveIcon(props: SVGProps<SVGSVGElement>) {
return (
<svg {...props} viewBox='0 0 97 27' fill='none' xmlns='http://www.w3.org/2000/svg'>
<svg {...props} viewBox='0 0 27.583 27' fill='none' xmlns='http://www.w3.org/2000/svg'>
<path
d='M18.7559 0C21.8453 0 23.3909 0.000524727 24.5703 0.588867C25.6078 1.10712 26.452 1.93264 26.9814 2.94824C27.5826 4.10418 27.583 5.61553 27.583 8.63965V18.3604C27.583 21.3845 27.5826 22.8973 26.9814 24.0518C26.452 25.0674 25.6078 25.8929 24.5703 26.4111C23.3894 26.9995 21.8453 27 18.7559 27H8.82617C5.73674 27 4.19109 26.9996 3.01172 26.4111C1.97438 25.8929 1.13096 25.0672 0.601562 24.0518C0.000441481 22.8973 1.23549e-09 21.3845 0 18.3604V8.63965C1.23384e-09 5.61553 0.000441463 4.10418 0.601562 2.94824C1.13096 1.9328 1.97438 1.1071 3.01172 0.588867C4.19109 0.000438224 5.73674 7.53417e-10 8.82617 0H18.7559ZM7.16992 7.29004C7.16999 8.03525 7.78752 8.63965 8.54883 8.63965H11.584V20.251C11.5841 20.9961 12.2016 21.6006 12.9629 21.6006H15.998V11.3408C15.998 9.85028 14.7629 8.63965 13.2402 8.63965H20.4102V6.75098C20.4102 6.00586 19.7924 5.40065 19.0312 5.40039H7.16992V7.29004ZM91.6113 9.49121C92.6656 9.49121 93.6059 9.71422 94.4023 10.1533C95.1986 10.5939 95.838 11.2118 96.3018 11.9912C96.7656 12.7708 97 13.6765 97 14.6816C97 14.8801 96.9901 15.0846 96.9688 15.2891C96.9474 15.4937 96.8994 15.7285 96.8262 15.9854C96.817 16.0181 96.7864 16.04 96.7529 16.04L89.3838 16.0752C89.4265 16.199 89.4698 16.3015 89.5186 16.3955C89.7337 16.8152 90.0419 17.1427 90.4355 17.3652C90.8307 17.5891 91.3066 17.7031 91.8496 17.7031C92.3391 17.7031 92.7921 17.6164 93.1963 17.4463C93.5991 17.276 93.9599 17.0153 94.2666 16.6748C94.2803 16.6601 94.3001 16.6494 94.3213 16.6494H94.3242C94.3441 16.6494 94.3642 16.6575 94.3779 16.6709L96.2051 18.4395C96.2325 18.4678 96.2359 18.5111 96.21 18.541C95.6882 19.1517 95.0485 19.6082 94.3086 19.8994C93.5702 20.1906 92.7436 20.3369 91.8496 20.3369C90.71 20.3369 89.6846 20.1045 88.8027 19.6445C87.9194 19.1846 87.2145 18.5347 86.708 17.7119C86.1999 16.8905 85.9434 15.9121 85.9434 14.8936C85.9434 13.875 86.1918 12.9444 86.6846 12.1289C87.1774 11.3135 87.8595 10.6638 88.7139 10.1963C89.5667 9.72884 90.5571 9.49123 91.6113 9.49121ZM72.2812 9.72266C72.3234 9.72266 72.3574 9.75661 72.3574 9.79785V20.0312C72.3574 20.0725 72.3234 20.1064 72.2812 20.1064H68.9688C68.9267 20.1064 68.8926 20.0725 68.8926 20.0312V9.79785C68.8926 9.75665 68.9267 9.72272 68.9688 9.72266H72.2812ZM41.1367 5.49219C41.1793 5.49236 41.2129 5.5247 41.2129 5.56641V8.89062H43.5029C43.5456 8.89068 43.5791 8.92404 43.5791 8.96582V11.7246C43.5789 11.7662 43.5455 11.7988 43.5029 11.7988H41.2109V15.4414C41.2109 15.7789 41.2739 16.0763 41.3975 16.3242C41.5195 16.5706 41.6979 16.7621 41.9268 16.8936C42.1388 17.016 42.3911 17.0813 42.6748 17.0918H43.501C43.5437 17.0918 43.5771 17.1252 43.5771 17.167V20.0312C43.5771 20.073 43.5437 20.1055 43.501 20.1055H42.6709C42.0837 20.0995 41.5302 20.0162 41.0146 19.8564C40.7187 19.7653 40.4341 19.6492 40.1641 19.5088C39.4029 19.1116 38.8039 18.56 38.3828 17.8701C37.9617 17.1801 37.748 16.378 37.748 15.4834V11.7988H36.1455C36.103 11.7988 36.0696 11.7662 36.0693 11.7246V8.96582C36.0693 8.92404 36.1028 8.89068 36.1455 8.89062H37.748V5.56641C37.748 5.52459 37.7815 5.49219 37.8242 5.49219H41.1367ZM49.4961 4.66992C49.5388 4.66997 49.5723 4.70333 49.5723 4.74512V10.4131C49.7584 10.2623 49.9584 10.1296 50.1689 10.0176C50.7945 9.68452 51.4875 9.51367 52.3145 9.51367C53.1413 9.51372 53.8765 9.68308 54.502 10.0176H54.5C55.127 10.3521 55.6223 10.8217 55.9717 11.4131C56.3211 12.0045 56.498 12.7013 56.498 13.4824V20.0312C56.498 20.0729 56.4644 20.1052 56.4219 20.1055H53.1094C53.0667 20.1055 53.0322 20.073 53.0322 20.0312V14.1992C53.0322 13.7034 52.8681 13.2922 52.54 12.9785C52.2121 12.665 51.7954 12.5049 51.3027 12.5049C50.9732 12.5049 50.6734 12.5774 50.4141 12.7178C50.1549 12.8581 49.9473 13.0568 49.7979 13.3105C49.6484 13.5644 49.5723 13.8633 49.5723 14.1992V20.0312C49.5722 20.073 49.5388 20.1054 49.4961 20.1055H46.1836C46.1409 20.1055 46.1074 20.073 46.1074 20.0312V4.74512C46.1074 4.7033 46.1409 4.66992 46.1836 4.66992H49.4961ZM64.9473 9.5127C65.4553 9.5127 65.9103 9.58841 66.2979 9.73926L66.3008 9.74219C66.6883 9.89303 67.0342 10.1221 67.3271 10.4238C67.353 10.4507 67.3549 10.4907 67.332 10.5205L65.375 12.9619C65.3613 12.9783 65.3393 12.9902 65.3164 12.9902H65.3135C65.2921 12.9902 65.2706 12.9813 65.2568 12.9648C65.1363 12.8336 64.9713 12.7265 64.7686 12.6475C64.5626 12.5668 64.3263 12.5264 64.0654 12.5264C63.53 12.5264 63.1045 12.6846 62.7979 12.998C62.4912 13.3117 62.335 13.7944 62.335 14.4307V20.0312C62.3349 20.073 62.3015 20.1055 62.2588 20.1055H58.9463C58.9037 20.1053 58.8701 20.073 58.8701 20.0312V9.79785C58.8701 9.75611 58.9037 9.72278 58.9463 9.72266H62.2588C62.3015 9.72266 62.335 9.75603 62.335 9.79785V10.4082C62.988 9.81379 63.8655 9.51271 64.9473 9.5127ZM77.4883 9.72266C77.5202 9.72266 77.5498 9.7437 77.5605 9.77344L79.7178 15.8672L81.8906 9.77344C81.9014 9.74237 81.9301 9.72277 81.9619 9.72266H85.4688C85.5113 9.72284 85.5449 9.75615 85.5449 9.79785C85.5449 9.81122 85.5412 9.82357 85.5352 9.83398L81.0859 20.0596C81.0738 20.0863 81.0469 20.1043 81.0166 20.1045H78.3496C78.3191 20.1045 78.2915 20.0865 78.2793 20.0596L73.8486 9.82617C73.838 9.80377 73.8408 9.77677 73.8545 9.75586C73.8697 9.73512 73.8922 9.72279 73.918 9.72266H77.4883ZM91.6543 12.1035C91.1555 12.1035 90.7177 12.2203 90.3516 12.4502C89.9854 12.6802 89.6969 13.0029 89.4971 13.4092H89.498C89.457 13.4926 89.4193 13.5852 89.3828 13.6924L93.7002 13.6689C93.659 13.5136 93.6148 13.3815 93.5645 13.2695C93.3982 12.8993 93.1509 12.6098 92.8291 12.4082C92.5057 12.2066 92.1105 12.1035 91.6543 12.1035ZM70.626 4.77441C71.1752 4.77441 71.6253 4.95277 71.9609 5.30371C72.2966 5.6532 72.4658 6.11036 72.4658 6.61816C72.4657 7.1258 72.2969 7.56782 71.9629 7.93066C71.6272 8.29658 71.1768 8.48145 70.626 8.48145C70.1044 8.48139 69.6587 8.29685 69.3018 7.93262C68.9463 7.56977 68.7647 7.14075 68.7646 6.61816C68.7646 6.09543 68.9467 5.65124 69.3037 5.30176C69.6606 4.95252 70.1059 4.77447 70.626 4.77441Z'
fill='#0A0A0A'
d='M18.7559 0C21.8453 0 23.3909 0.000524727 24.5703 0.588867C25.6078 1.10712 26.452 1.93264 26.9814 2.94824C27.5826 4.10418 27.583 5.61553 27.583 8.63965V18.3604C27.583 21.3845 27.5826 22.8973 26.9814 24.0518C26.452 25.0674 25.6078 25.8929 24.5703 26.4111C23.3894 26.9995 21.8453 27 18.7559 27H8.82617C5.73674 27 4.19109 26.9996 3.01172 26.4111C1.97438 25.8929 1.13096 25.0672 0.601562 24.0518C0.000441481 22.8973 1.23549e-09 21.3845 0 18.3604V8.63965C1.23384e-09 5.61553 0.000441463 4.10418 0.601562 2.94824C1.13096 1.9328 1.97438 1.1071 3.01172 0.588867C4.19109 0.000438224 5.73674 7.53417e-10 8.82617 0H18.7559ZM7.16992 7.29004C7.16999 8.03525 7.78752 8.63965 8.54883 8.63965H11.584V20.251C11.5841 20.9961 12.2016 21.6006 12.9629 21.6006H15.998V11.3408C15.998 9.85028 14.7629 8.63965 13.2402 8.63965H20.4102V6.75098C20.4102 6.00586 19.7924 5.40065 19.0312 5.40039H7.16992V7.29004Z'
fill='#000000'
/>
</svg>
)
Expand Down
Loading
Loading