ENG-2213 Settings catalog: address every setting by key and location - #1379
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
PR size/scope checkThis PR is over our review-size guideline.
Please split this into smaller PRs unless there is a clear reason the changes need to land together. If keeping it as one PR, please add a brief justification covering:
|
|
This pull request has been ignored for the connected project Preview Branches by Supabase. |
bc865f3 to
81f750e
Compare
81f750e to
fd2b364
Compare
fd2b364 to
8f6c3bd
Compare
8f6c3bd to
0a82e0e
Compare
0a82e0e to
2867339
Compare
2867339 to
369c7f8
Compare
369c7f8 to
c3c5884
Compare
c3c5884 to
4c1e173
Compare
4c1e173 to
1ba0ab8
Compare
mdroidian
left a comment
There was a problem hiding this comment.
Non-blocking: the catalog duplicates labels and descriptions already defined in the settings components. For example, “Graph-wide default” and its description appear in both PreferencesGeneral.tsx and settingsCatalog.ts.
Can we explicitly cover consolidating these in ENG-2187 (or elsewhere), so the controls and search read the same labels and descriptions? The current fallback still lets the two copies drift apart.
For example, define the shared metadata once:
export const NODE_TRIGGER_SETTING = {
settingKeys: [GLOBAL_KEYS.trigger],
label: "Graph-wide default",
description: "The trigger to create the node menu.",
docsLink: ROAM_DOCS.creatingNodes,
};The control reads it:
<GlobalTextPanel
title={NODE_TRIGGER_SETTING.label}
description={withDocsLink(
NODE_TRIGGER_SETTING.description,
NODE_TRIGGER_SETTING.docsLink,
)}
settingKeys={NODE_TRIGGER_SETTING.settingKeys}
initialValue={globalSettings[GLOBAL_KEYS.trigger]}
{...legacyBlocks.trigger}
/>Search uses the same definition with its navigation metadata:
{
...NODE_TRIGGER_SETTING,
group: "Node trigger",
keywords: ["trigger", "node menu", "global"],
path: rootPath(SETTINGS_TAB_IDS.preferencesGeneral),
}This is illustrative; the existing catalog could hold the shared definitions rather than introducing another metadata source.
I also agree with the Codex request for focused unit tests before merge, though I wouldn’t classify missing coverage alone as P1. Please cover nested addresses, per-node expansion, unique IDs, availability filtering, and exclusion of settings without a path. These are runtime behaviors that type checking won’t verify; there’s no need to snapshot the entire catalog.
| group?: string; | ||
| description?: string; | ||
| docsLink?: string; | ||
| /** Synonyms and pre-ENG-2189 section names, so muscle memory still resolves. */ |
There was a problem hiding this comment.
pre-ENG-2189 isn't very helpful on it's own. What additional context should we add here?
| return ( | ||
| <div className="inline-grid grid-cols-[auto_auto] items-center gap-x-4 gap-y-2 p-1"> | ||
| <div | ||
| className="inline-grid grid-cols-[auto_auto] items-center gap-x-4 gap-y-2 p-1" |
There was a problem hiding this comment.
grid-cols-[auto_auto] is not included in roam's tailwind.
This is covered in the roam-global-tailwind skill. Could you investigate if claude is using that skill? And if not, ask what we can change so that it does use that skill
cd64c79 to
03d0bf0
Compare
03d0bf0 to
87bdb96
Compare
87bdb96 to
edcb81c
Compare
edcb81c to
3b106af
Compare
3b106af to
ec08b6e
Compare
ec08b6e to
2ff5465
Compare
Records what every setting row is called and where it lives, so a later change can find a setting without knowing which tab it is on. Nothing in the codebase held this. `zodSchema.ts` is storage shape — no labels, no descriptions, no locations — and `settingKeys.ts` holds block keys that diverge from what a row renders: `GLOBAL_KEYS.trigger` renders as "Graph-wide default", `PERSONAL_KEYS.personalNodeMenuTrigger` as "Personal override". Nor can it be collected at runtime: `Tabs` uses `renderActiveTabPanelOnly`, so inactive panels are out of the DOM and rows cannot self-register. So the label, group, description, doc link and location are authored, one entry per row. Everything else is derived rather than restated. Entries are keyed by `GROUP.member`, addresses are built by resolving that id against the `settingKeys.ts` constants, and the catalog is declared `satisfies Record<RowKeyId, AuthoredSetting>`. A key added to `settingKeys.ts` is then a compile error until it is either given an entry or listed in `NonRowKeyId` with a reason, so a new setting cannot silently go missing. The remaining gap is the reverse direction: nothing checks that a row rendering `settingKeys` was classified as a row rather than exempted. An entry's `path` is the only field a relocation has to touch. Node-type settings give `path` as a function of the node uid, so one entry expands to one result per node type and adding a node type never edits this file. Six rows rendered without an anchor, so they had no stable address; each now passes the key constants already in scope at its call site. `SETTINGS_TAB_META` becomes the single source for tab labels, because a renamed tab would otherwise drift away from the locations recorded here. `SettingItemRow` falls back to the catalog for a description when the prop is omitted, so ENG-2187 can migrate call sites by deleting props rather than by copying text. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The key was exempted as "persisted UI state and canvas-written values", but CanvasShortcutSettings renders it as a visible editor under Features > Canvas, so a real setting was missing from the index: searching "canvas shortcut" only found the discourse tool shortcut. Authored as one row rather than one per node type, because the overrides share a single stored value; the anchor goes on the grid so a jump lands on it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The catalog is what makes search navigable, and its invariants fail quietly: a duplicate id breaks React keys, a nested setting that drops its parent segment collides with a same-named top-level key, and an entry pointing at a tab that no longer exists sends the user nowhere. Also pins the two rules the export move introduced: settings living outside the Settings dialog stay out of the index, and stay authored here anyway so their rows keep reading one description. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…sTabId Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Index and Format now sit under Identity and Specification under Legacy, so the breadcrumbs search shows match the page. Format's description loses the DEPRECATED note along with the row. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
ENG-2096 removed the setting on main. The catalog is exhaustive over the key groups, so its row had to go with the key. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
ENG-2189 moved the row so the tab can hide itself. `path` is data, so nothing would have failed: search would just have navigated to the wrong tab. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2ff5465 to
4b1bd2f
Compare
https://www.loom.com/share/b2cacd88016b48bc923f81da0edd204d
Reviewer brief
Result: Every setting row now has a stable address and a recorded location. Nothing consumes this yet — ENG-2184 (ENG-2184 Add search to the settings panel #1378, stacked on top) is the first reader. It is split out because it is ~590 lines that are mostly declarative data, and it dominated that diff.
Review focus — why this is authored rather than derived. Three constraints, worth checking before reading
settingsCatalog.tsas a pile of literals:TabsusesrenderActiveTabPanelOnly, so inactive panels are out of the DOM and rows cannot self-register.zodSchema.tsis storage shape — no labels, no descriptions, no locations. Location is a pure UI fact with no runtime source.GLOBAL_KEYS.triggerrenders as "Graph-wide default",PERSONAL_KEYS.personalNodeMenuTriggeras "Personal override", andDISCOURSE_NODE_KEYSvalues are"canvasSettings","key-image".Review focus — the key list is not restated, and coverage is a type error. Entries are keyed by
GROUP.member; addresses are built by resolving that id against thesettingKeys.tsconstants; the object is declaredsatisfies Record<RowKeyId, AuthoredSetting>, whereRowKeyIdis every key insettingKeys.tsminus an explicitNonRowKeyIdlist (22 containers, admin-only flags and nested sub-controls, each with its reason). Adding a key tosettingKeys.tsfails to compile until it is entered or exempted.Verified by mutation: deleting
GLOBAL_KEYS.canvasPageFormatfrom the catalog, and adding a new key tosettingKeys.ts, each failtscwith TS1360.Risk or follow-up:
settingKeyswas classified as a row rather than exempted, so exempting a key that is really a visible row would drop it from search silently. TheNonRowKeyIdlist is the part most worth a careful read.LeftSidebarPersonalSettings.tsxpasssettingKeys={[]}— per-section instances with no stable address. Pre-existing; exempted asLEFT_SIDEBAR_KEYS.childrenand needs an addressing scheme rather than a one-liner.SettingItemRow's catalog description fallback has no call site yet. It exists so ENG-2187 can migrate rows by deleting props instead of copying text.Verification
pnpm ci:validate(check-types + 142 unit tests) and eslint on the changed files — 0 errors, no new warnings on added lines.Export/Link type,Query/Hide query metadata,canvasSettings/color,suggestiveRules/embeddingRef,template. These have to matchsettingAnchorexactly or ENG-2184's jump lands nowhere.Grammar › Nodes › Claim › RecognitionandGrammar › Nodes › Evidence › Recognition, with unique ids.Scope check
$scope-checkagainst the ENG ticket and final diff.Done When:SettingItemRowfallback. ENG-2184 originally scoped description search out; it was requested during implementation. Storing the text once and letting the row read it back is what stops the row and search drifting apart.PreferencesGeneralraw string →PERSONAL_KEYS.reifiedRelationTriples, for consistency with every other row's addressing.SETTINGS_TAB_META, withSettings.tsxtitling its tabs from it. Locations are recorded per tab, so a renamed tab would otherwise drift away from the catalog.Local delegated full review