Repository navigation
Commit f48aa45
refactor(app-shell): move ObjectView's view management handlers into a sibling hook (slice 11b) (#26542)
<!-- claude-projects-attribution: {"github_login":"os-steve"} -->
_Requested by **Steve** · [project
thread](https://claude.ai/code/project/chan_01FdL1XeUyvVNxLreh3F4Qi9?thread=cmsg_01FdL1XeUyvVNxLreh3F4Qi9VtKf3F9dzJPJM4RRtABaEc)_
Fixes #25992 (slice 11b, the last slice of the move-only split; slices 1
to 11a landed as #26152, #26233, #26310, #26336, #26353, #26374, #26396,
#26412, #26434 and #26492). With this PR, every region of the seam table
in #26336 that was marked for a slice has moved; what stays in
`ObjectView.tsx` is the shared state (A, C, F, J), the panel and dialog
state, the hook calls and the JSX.
Clause-②: no
Metadata-protocol: none
## What moved
Base `a2e4b760` (the branch's merge of `main` at `73683ee1`, slice 11a
merged). `ui/packages/app-shell/src/views/ObjectView.tsx` is 1480 lines
there. Three blocks of `ObjectViewInner` move verbatim into one custom
hook, `useObjectViewViewCrud`, in the new sibling module
`objectViewViewCrud.tsx`. Every input is passed as an argument, typed
from its source (no `any`), and the component destructures the 13
handlers under their original names. No identifier is renamed and no
context is added.
- **B: the view-config save and create doors** (lines 228–371). The
objectui#12504 note on the retired `persistViewPatch`, the objectui#4155
block comment on the absent `persistViewFilter`, `handleViewConfigSave`
and `handleViewCreate`, with their docblocks and dependency lists.
- **B: `handleViewUpdate`** (lines 789–796), the panel's draft field
update, with its docblock.
- **I: view switching and the view-tab CRUD callbacks** (lines
798–1002). `handleViewChange`, the mobile view switcher items and
`useMobileViewSwitcherRegistration`, `handleCreateView`,
`handleViewAction`, `isSavedView`, `handleRenameView`,
`handleDeleteView`, `handlePinView`, `handleSetDefaultView`, the
objectui#12418 docblock and `handleReorderViews`, `handleConfigView` and
`handleAddView`.
The hook is called where `handleViewUpdate` stood, after
`useObjectViewListUrlState`. It returns `handleViewConfigSave`,
`handleViewCreate`, `handleViewUpdate`, `handleViewChange`,
`handleCreateView`, `handleViewAction`, `handleRenameView`,
`handleDeleteView`, `handlePinView`, `handleSetDefaultView`,
`handleReorderViews`, `handleConfigView` and `handleAddView`.
`isSavedView` and the mobile switcher items stay inside the hook, their
only readers.
**What stays.** The five `useState` calls of B (`showViewConfigPanel`,
`viewConfigPanelMode`, `showCreateViewDialog`, `manageViewsOpen`,
`viewDraft`, lines 217–226) stay in the component. `activeView` (F, line
758) reads `viewDraft` before the hook's inputs exist, and the JSX reads
the panel and dialog flags. The hook receives the setters.
**Hook order.** `handleViewConfigSave` and `handleViewCreate` (two
`useCallback`s) used to run before the record count state, `useAuth` and
every hook down to `useObjectViewListUrlState`. They now run after it,
inside the new hook, right before `handleViewUpdate`. They could not be
called at their old spot: their bodies call `setRefreshKey`, declared at
line 401, so passing it to a hook there would hit the TDZ. Nothing
between their old and new positions reads them (measured: no reference
between lines 372 and 788). The hooks of `handleViewUpdate` and I keep
their order and position. The seat's ruling allows this shift when
stated.
### Imports
Each import moves with its only readers: `formatMetadataError`,
`viewTabLabel`, `persistRuntimeMetadata` / `createRuntimeMetadata` /
`viewEnvelope`, `PREVIEW_QUERY_FLAG` / `PREVIEW_QUERY_VALUE`,
`useMobileViewSwitcherRegistration`, `MobileViewSwitcherItem`,
`isSavedViewId`, `buildAddViewSpec`, `setDefaultViewPatches`,
`buildViewConfigSaveBody` and `dispatchViewPatches`. These names are
still re-exported from `ObjectView.tsx` where they were before, and
those lines are unchanged. Names the component still reads elsewhere
(`useCallback`, `useMemo`, `toast`, `VIEW_TYPE_ICONS`) are imported by
the module as well. Nothing new is exported from `ObjectView.tsx`, and
the package entry is untouched. `ObjectView.tsx` goes from 1480 to 1151
lines.
Move-only proof: the multiset of non-blank lines of the base
`ObjectView.tsx` is contained in the new `ObjectView.tsx` plus the
module, except 9 lines. Every one of the 9 is an import line or an
import-list entry that lost a moved name: the `PREVIEW_QUERY_FLAG` and
`PREVIEW_QUERY_VALUE` entries, the `../utils/viewIdentity.js` import
(replaced by its trimmed form), the `buildAddViewSpec`,
`setDefaultViewPatches` and `buildViewConfigSaveBody` entries of the
`./objectViewTabs.js` list, and the three-line `./objectViewOptions.js`
import of `dispatchViewPatches`. The module imports each of those names
itself. The added lines are:
- the trimmed import and the new import;
- the module header and imports;
- the hook signature and parameter types;
- the `return`;
- in `ObjectView.tsx`, the call with its destructuring and a two-line
comment.
## Test edits
Five source-scan readers move to the file that now holds what they read.
Each edit is a path or file-list change, and no assertion changed:
1. `writeRefusalCensus-11583.test.ts`: the six `LEDGER` rows for
`handleViewConfigSave`, `handleViewCreate`, `handleRenameView`,
`handleDeleteView`, `handlePinView` and `handleSetDefaultView` change
`file: 'ObjectView.tsx'` to `file: 'objectViewViewCrud.tsx'`. Callees,
counts, pins and reasons are unchanged. The census walks `views/`, so it
finds the sites in the new file.
2. `ui/scripts/__tests__/check-i18n-call-site-keys.test.ts`: the
`deleteViewConfirm` row of the deleted-fallbacks list →
`packages/app-shell/src/views/objectViewViewCrud.tsx`. Its absent and
present markers are unchanged.
3. `ObjectView.overlayPatchOnly.test.ts`: the joined `objectViewCode`
list gains `'objectViewViewCrud.tsx'`. The control's
`handleViewConfigSave` and `persistRuntimeMetadata` reads are there now.
4. `view-filter-fold.ratchet.test.ts`: the joined `objectViewSrc` list
gains `objectViewViewCrud.tsx`, for the `handleViewConfigSave`
initializer the ratchet parses.
5. `ObjectView.unboundAdapterCall.test.ts`: the detach-then-call ratchet
reads `ObjectView.tsx` and `objectViewViewCrud.tsx` joined, the same way
as the two above. Without this edit it would still pass, but it would no
longer read `handleSetDefaultView` and `handlePinView`, the handlers it
guards.
Edit 5 is the one the seat's list did not name. It is listed for the
same reason as the others: the scan's subject moved.
## Seam table rows this PR changes (measured on `a2e4b760`)
The full table (regions A to Q) is in #26336.
| # | Concern | Lines on `a2e4b760` | Reads | Read by | Slice |
|---|---|---|---|---|---|
| B (state) | Panel and dialog open state, `viewDraft` | 217–226 | — |
F, H, I, N, O, P, Q | stays (shared state) |
| B | `handleViewConfigSave`, `handleViewCreate` and their notes |
228–371 | A, C (`setRefreshKey`) | Q | **11b, this PR** |
| B | `handleViewUpdate` | 789–796 | B (`setViewDraft`), F (`baseView`)
| Q | **11b, this PR** |
| I | View switching, mobile switcher, view-tab CRUD callbacks |
798–1002 | A, B, C, F | N, Q | **11b, this PR** |
## Verification
The full readings are in the os-dev-report comment on the card:
- app-shell `type-check` after rebuilding its dependency closure;
- 208 test files: every `ObjectView.*` test in `views/` (the view CRUD,
refusal, create-view, default-view, view-config save and mobile FAB
tests among them), the `AppContent*` tests, and every other test that
reads `ObjectView.tsx` as source, including the five re-pointed ones;
- eslint on the touched files;
- the derived dispatch gates;
- a Console build.
## Acceptance notes
- eslint: 0 errors, and no new `no-explicit-any`. `ObjectView.tsx` plus
the module report 83 warnings, against 80 for the base `ObjectView.tsx`
alone.
- Added: 10 `react-hooks/exhaustive-deps` warnings in the module, and 1
existing one (the `objectName` warning on `handleDeleteView`) now also
names `setRefreshKey`. Each added warning names a state setter that is
now a hook parameter (`setRefreshKey`, `setViewDraft`,
`setShowViewConfigPanel`, `setViewConfigPanelMode`,
`setShowCreateViewDialog`). The rule treats a `useState` setter as
stable only in the component that declares it. The dependency lists are
kept verbatim, because adding the setters would change code; the setters
are stable, so behaviour is the same. Slice 8 drew the same class of
warning at its hook boundary.
- Gone: the 2 `exhaustive-deps` warnings on `handleViewChange`, the 4
`preserve-manual-memoization` skips on these handlers, and 1
`react-hooks/immutability` finding (`handleViewConfigSave` reading
`setRefreshKey` before its declaration).
- Unchanged: the other `exhaustive-deps` warnings (`listPrefs` in
`handleReorderViews`, and the two on the `objectDef` effect) only moved
lines.
- Net: 80 + 10 − 2 − 4 − 1 = 83.
- The test edits add no warning.
Changeset: `.changeset/25992-objectview-view-crud-split.md` (patch,
`@object-ui/app-shell`).
---
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_01QciHBvFJXnhZqXmdqpDtpz
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent a89074a commit f48aa45
8 files changed
Lines changed: 526 additions & 384 deletions
File tree
- .changeset
- ui
- packages/app-shell/src/views
- scripts/__tests__
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
308 | 308 | | |
309 | 309 | | |
310 | 310 | | |
311 | | - | |
| 311 | + | |
312 | 312 | | |
313 | 313 | | |
314 | 314 | | |
| |||
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
188 | 188 | | |
189 | 189 | | |
190 | 190 | | |
191 | | - | |
192 | | - | |
| 191 | + | |
| 192 | + | |
193 | 193 | | |
194 | | - | |
| 194 | + | |
195 | 195 | | |
196 | 196 | | |
197 | 197 | | |
| |||
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
43 | 43 | | |
44 | 44 | | |
45 | 45 | | |
46 | | - | |
| 46 | + | |
47 | 47 | | |
48 | 48 | | |
49 | 49 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
88 | 88 | | |
89 | 89 | | |
90 | 90 | | |
91 | | - | |
| 91 | + | |
92 | 92 | | |
93 | 93 | | |
94 | 94 | | |
95 | 95 | | |
96 | | - | |
| 96 | + | |
97 | 97 | | |
98 | 98 | | |
99 | 99 | | |
100 | 100 | | |
101 | | - | |
| 101 | + | |
102 | 102 | | |
103 | 103 | | |
104 | 104 | | |
105 | 105 | | |
106 | | - | |
| 106 | + | |
107 | 107 | | |
108 | 108 | | |
109 | 109 | | |
110 | 110 | | |
111 | | - | |
| 111 | + | |
112 | 112 | | |
113 | 113 | | |
114 | 114 | | |
115 | 115 | | |
116 | | - | |
| 116 | + | |
117 | 117 | | |
118 | 118 | | |
119 | 119 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1088 | 1088 | | |
1089 | 1089 | | |
1090 | 1090 | | |
1091 | | - | |
| 1091 | + | |
1092 | 1092 | | |
1093 | 1093 | | |
1094 | 1094 | | |
| |||
0 commit comments