You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit f20b5b4
Browse filesBrowse the repository at this point in the historyBrowse files
fix(settings): decouple access settings from usage analytics (#8828)
* fix(settings): decouple access settings from usage analytics
* fix(billing): refuse expired reads and recover transaction timeouts
* chore(settings): simplify ledger fixture and correct plan documentation
* fix(settings): use neutral read-error feedback consistently
* refactor(settings): share the named plan and seat response type
@@ -228,11 +229,14 @@ and — on activatable rows only — the hover band. Never hand-roll any of it,
228
229
renders the value paragraph itself; pass a node when the value needs its own
229
230
presentation (a control, an icon beside the value, status styling).
230
231
-**`SettingsEmptyState`** (`…/components/settings-empty-state`) — the canonical
231
-
muted status message, for empty lists, "no results", loading gates, **and
232
-
failed loads** (`tone='error'`). `variant='fill'` (default) centers in the
233
-
available height; `variant='inline'` sits in flow. Never hand-roll
234
-
`<div className='flex h-full items-center justify-center …'>` or
235
-
`<div className='py-4 text-center …'>`.
232
+
muted status message for empty lists, "no results", loading gates, and failed
233
+
reads. `variant='fill'` (default) centers in the available height;
234
+
`variant='inline'` sits in flow. Never hand-roll its layout.
235
+
-**`SettingsQueryErrorState`** (same module) — the muted read-failure message
236
+
with an accessible alert and retry control. Show an initial failure when data
237
+
is unavailable; preserve cached content, mounted editors, and unsaved drafts
238
+
during background failures, using an inline status. Validation and mutation
239
+
failures retain their error styling.
236
240
-**`RowActionsMenu`** (`…/components/row-actions-menu`) — the trailing `...`
237
241
actions menu for a list row. Pass `label` (aria-label) and
238
242
`actions: RowAction[]` (`{ label, onSelect, destructive?, disabled? }`); the
@@ -395,6 +399,6 @@ A settings page is design-system-clean when:
395
399
-[ ] Every **resource** list row (a thing with an identity — a tool, a server, a key, a credential) is a `SettingsResourceRow` in a `RESOURCE_LIST_STACK`/`RESOURCE_LIST_GRID` — no wrapper `<button>`/`<Link>`, no hand-passed arrow, no re-derived title/subtitle spans. Rows with a genuinely different shape stay bespoke, and draw their own arrow with `RESOURCE_ROW_ARROW_CLASSES`: multi-line bodies (inbox tasks), tabular columns (billing invoices, credit usage), grids (secrets), and the member rows (see the avatar note above).
396
400
-[ ] Rows that open a detail page use `navigable` + `clickLabel`; flat records use `RowActionsMenu`. Not both.
397
401
-[ ] Decorative trailing content is in `badge`, not `trailing`.
398
-
-[ ] Labeled sections use `SettingsSection`; read-only fields use `SettingsField`; empty/loading/error use `SettingsEmptyState`.
402
+
-[ ] Labeled sections use `SettingsSection`; read-only fields use `SettingsField`; empty/loading/read-failure messages use `SettingsEmptyState`, with `SettingsQueryErrorState` when offering retry.
399
403
-[ ] Delete is a plain `id:'delete'` header action behind a `ChipConfirmModal`; `destructive` is reserved for bulk actions.
400
404
-[ ] The local gate in the root `CLAUDE.md` ("How your work is checked") passes.
<!-- Generated from .claude/rules/sim-settings-pages.md by `bun run skills:sync`. Edit the source, not this file. -->
7
7
8
8
# Settings Pages
9
9
10
-
The Next.js `settings/[section]/layout.tsx` owns all settings page chrome via
10
+
Workspace and organization `settings/[section]/layout.tsx` own page chrome via
11
11
`SettingsHeaderShell` — a fixed header bar (a left back chip + right-aligned
12
12
action chips), a scroll region, and a centered `max-w-[48rem]` content column led
13
13
by a **title + description from navigation metadata**. The chrome stays mounted
14
14
across section navigation. Its routed title and description are available before
15
15
the section body resolves. Each section renders through the **`SettingsPanel`**
16
16
registrar
17
-
(`@/app/workspace/[workspaceId]/settings/components/settings-panel`), which feeds
17
+
(`@/components/settings/settings-panel`), which feeds
18
18
the shell its header data and renders only the section body. Sections supply
19
19
**data**, never chrome.
20
20
@@ -31,7 +31,7 @@ shell (fed through `SettingsPanel`):
31
31
## Canonical page shape
32
32
33
33
```tsx
34
-
import { SettingsPanel } from '@/app/workspace/[workspaceId]/settings/components/settings-panel'
34
+
import { SettingsPanel } from '@/components/settings/settings-panel'
35
35
36
36
return (
37
37
<SettingsPanel
@@ -225,11 +225,14 @@ and — on activatable rows only — the hover band. Never hand-roll any of it,
225
225
renders the value paragraph itself; pass a node when the value needs its own
226
226
presentation (a control, an icon beside the value, status styling).
227
227
- **`SettingsEmptyState`** (`…/components/settings-empty-state`) — the canonical
228
-
muted status message, for empty lists, "no results", loading gates, **and
229
-
failed loads** (`tone='error'`). `variant='fill'` (default) centers in the
230
-
available height; `variant='inline'` sits in flow. Never hand-roll
231
-
`<div className='flex h-full items-center justify-center …'>` or
232
-
`<div className='py-4 text-center …'>`.
228
+
muted status message for empty lists, "no results", loading gates, and failed
229
+
reads. `variant='fill'` (default) centers in the available height;
230
+
`variant='inline'` sits in flow. Never hand-roll its layout.
231
+
- **`SettingsQueryErrorState`** (same module) — the muted read-failure message
232
+
with an accessible alert and retry control. Show an initial failure when data
233
+
is unavailable; preserve cached content, mounted editors, and unsaved drafts
234
+
during background failures, using an inline status. Validation and mutation
235
+
failures retain their error styling.
233
236
- **`RowActionsMenu`** (`…/components/row-actions-menu`) — the trailing `...`
234
237
actions menu for a list row. Pass `label` (aria-label) and
235
238
`actions: RowAction[]` (`{ label, onSelect, destructive?, disabled? }`); the
@@ -392,6 +395,6 @@ A settings page is design-system-clean when:
392
395
- [ ] Every **resource** list row (a thing with an identity — a tool, a server, a key, a credential) is a `SettingsResourceRow` in a `RESOURCE_LIST_STACK`/`RESOURCE_LIST_GRID` — no wrapper `<button>`/`<Link>`, no hand-passed arrow, no re-derived title/subtitle spans. Rows with a genuinely different shape stay bespoke, and draw their own arrow with `RESOURCE_ROW_ARROW_CLASSES`: multi-line bodies (inbox tasks), tabular columns (billing invoices, credit usage), grids (secrets), and the member rows (see the avatar note above).
393
396
- [ ] Rows that open a detail page use `navigable` + `clickLabel`; flat records use `RowActionsMenu`. Not both.
394
397
- [ ] Decorative trailing content is in `badge`, not `trailing`.
395
-
- [ ] Labeled sections use `SettingsSection`; read-only fields use `SettingsField`; empty/loading/error use `SettingsEmptyState`.
398
+
- [ ] Labeled sections use `SettingsSection`; read-only fields use `SettingsField`; empty/loading/read-failure messages use `SettingsEmptyState`, with `SettingsQueryErrorState` when offering retry.
396
399
- [ ] Delete is a plain `id:'delete'` header action behind a `ChipConfirmModal`; `destructive` is reserved for bulk actions.
397
400
- [ ] The local gate in the root `CLAUDE.md` ("How your work is checked") passes.
0 commit comments