Repository navigation
refactor(app-shell): move ObjectView's view management handlers into a sibling hook (slice 11b) - #26542
Conversation
…tViewOptions.ts (slice 2) The timeline/calendar/gantt/gallery/kanban ViewOptions, storedLegacyOptions, isSameOptionsValue and dispatchViewPatches move verbatim out of views/ObjectView.tsx into views/objectViewOptions.ts. ObjectView.tsx imports them back and re-exports every name it exported before. Test edits forced by the move: the four source scans that read the ObjectView face (calendarBinding-7029, galleryBinding-7547, ganttBinding-7070, titleFieldConvergence) now read ObjectView.tsx plus objectViewOptions.ts, and the writeRefusalCensus-11583 LEDGER row for dispatchViewPatches is keyed by its new file. Claude-Session: https://claude.ai/code/session_01QciHBvFJXnhZqXmdqpDtpz Co-authored-by: Claude <noreply@anthropic.com>
…ome.tsx (slice 3) ObjectNotFoundState, the saved-view tab strip's viewport check (VIEW_TABS_MIN_WIDTH, viewTabsFitNow, useViewTabsFit) and keepInlineEditModeForTheSession move verbatim out of views/ObjectView.tsx into views/objectViewChrome.tsx. ObjectView.tsx imports them back and re-exports ObjectNotFoundState, the one name it exported. No test edits. Claude-Session: https://claude.ai/code/session_01QciHBvFJXnhZqXmdqpDtpz Co-authored-by: Claude <noreply@anthropic.com>
…unt into a sibling hook Slice 4 of the move-only ObjectView split. The realtime subscription, the reconnection conflict resolution and the footer record-count fetch move verbatim from ObjectViewInner into useObjectViewLiveData in views/objectViewLiveData.ts. The component calls the hook at the same position (hook order unchanged) and passes its inputs explicitly; the recordCount state stays in the component. No test edits. Claude-Session: https://claude.ai/code/session_01QciHBvFJXnhZqXmdqpDtpz Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QciHBvFJXnhZqXmdqpDtpz Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QciHBvFJXnhZqXmdqpDtpz Co-authored-by: Claude <noreply@anthropic.com>
…igation into sibling hooks Slices 5 and 6 of the move-only ObjectView split, paired in one PR. - The identity-import gate, its password-policy state and data source, and the managed-environment Users marker move verbatim into useObjectViewIdentity in views/objectViewIdentity.tsx. - The record navigation overlay (detail navigation config, drawer recordId URL state, row click, expand to page, list record links) moves verbatim into useObjectViewRecordNavigation in views/objectViewRecordNavigation.ts. The URL equality filters and the user-filter selections between its two blocks stay in the component. Inputs are passed explicitly; the component destructures the returned values under their original names. No test edits. Claude-Session: https://claude.ai/code/session_01QciHBvFJXnhZqXmdqpDtpz Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QciHBvFJXnhZqXmdqpDtpz Co-authored-by: Claude <noreply@anthropic.com>
…m their sources activeView, objectDef and objects were written as `any` in the new hook's parameter type. They now name where the component gets each value: the element of buildViewTabs' result, and ConsoleObjectViewProps['objects'] and its element. No new no-explicit-any warning; the moved bodies are unchanged. Claude-Session: https://claude.ai/code/session_01QciHBvFJXnhZqXmdqpDtpz Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QciHBvFJXnhZqXmdqpDtpz Co-authored-by: Claude <noreply@anthropic.com>
…a sibling hook Slice 7 of the move-only ObjectView split. The environment list's entitlements, the list actions and their localized toolbar copies, and the create and import buttons' toolbar-scope predicates move verbatim into useObjectViewToolbarAffordances in views/objectViewToolbarAffordances.ts. The resolveAffordance verdict memo stays in the component (the affordance grant census reads it there) and is passed in with the other inputs, typed from their sources. No test edits. Claude-Session: https://claude.ai/code/session_01QciHBvFJXnhZqXmdqpDtpz Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QciHBvFJXnhZqXmdqpDtpz Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QciHBvFJXnhZqXmdqpDtpz Co-authored-by: Claude <noreply@anthropic.com>
…ate into sibling hooks Slice 8 of the move-only ObjectView split. - The header's list_toolbar actions (less the record-scoped ones the selection bar carries), the nav runAction deep link and the action:bar node move verbatim into useObjectViewHeaderToolbar in views/objectViewHeaderToolbar.ts. - The list's uf_ URL state (seed, write-back, Reset view) moves into useObjectViewListUrlState, and the filter[...] equality filters with the restored user-filter selections into useObjectViewUrlFilters, both in views/objectViewListUrlState.ts. Hook parameters are typed from their sources. One test edit, path only: ObjectView.urlFilterSuffix-9196 reads objectViewListUrlState.ts, where the scanned block now lives. Claude-Session: https://claude.ai/code/session_01QciHBvFJXnhZqXmdqpDtpz Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QciHBvFJXnhZqXmdqpDtpz Co-authored-by: Claude <noreply@anthropic.com>
…and header chrome into sibling hooks Move-only split of ObjectViewInner: the view tab items, ViewTabBar and its own-row face go to objectViewTabBar.tsx; the merged views and the plugin ObjectViewSchema go to objectViewPluginSchema.ts; the create button, folded header actions menu and refused-view face go to objectViewHeaderChrome.tsx. Each hook is called where its block stood. Claude-Session: https://claude.ai/code/session_01QciHBvFJXnhZqXmdqpDtpz Co-authored-by: Claude <noreply@anthropic.com>
… into sibling sub-components Move-only split of ObjectViewInner's JSX: the PageHeader block goes to ObjectViewPageHeader in objectViewPageHeader.tsx, and the non-split NavigationOverlay with its RecordDetailView goes to ObjectViewRecordOverlay in objectViewRecordOverlay.tsx. Every value is passed in as a prop; the rendered DOM is unchanged. Claude-Session: https://claude.ai/code/session_01QciHBvFJXnhZqXmdqpDtpz Co-authored-by: Claude <noreply@anthropic.com>
…hook Move-only split of ObjectViewInner: renderListView, the column-declaration flags and the held list identity refs only it reads, and the lazy ObjectChart it mounts go to useObjectViewListRenderer in objectViewListRenderer.tsx, called where renderListView stood. Six source-scan tests read the new file (path or file-list changes only). Claude-Session: https://claude.ai/code/session_01QciHBvFJXnhZqXmdqpDtpz Co-authored-by: Claude <noreply@anthropic.com>
…a sibling hook (slice 11b) The view-config save and create handlers, the draft field update, view switching, the mobile view switcher registration and the view-tab CRUD callbacks move verbatim from ObjectViewInner into useObjectViewViewCrud (objectViewViewCrud.tsx). The panel and dialog state stays in the component. Six source-scan readers follow the moved handlers (path or file-list edits only). Claude-Session: https://claude.ai/code/session_01QciHBvFJXnhZqXmdqpDtpz Co-authored-by: Claude <noreply@anthropic.com>
席位核对 · ACCEPT · seat
|
Requested by Steve · project thread
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.tsxis 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 ofmainat73683ee1, slice 11a merged).ui/packages/app-shell/src/views/ObjectView.tsxis 1480 lines there. Three blocks ofObjectViewInnermove verbatim into one custom hook,useObjectViewViewCrud, in the new sibling moduleobjectViewViewCrud.tsx. Every input is passed as an argument, typed from its source (noany), and the component destructures the 13 handlers under their original names. No identifier is renamed and no context is added.persistViewPatch, the objectui#4155 block comment on the absentpersistViewFilter,handleViewConfigSaveandhandleViewCreate, with their docblocks and dependency lists.handleViewUpdate(lines 789–796), the panel's draft field update, with its docblock.handleViewChange, the mobile view switcher items anduseMobileViewSwitcherRegistration,handleCreateView,handleViewAction,isSavedView,handleRenameView,handleDeleteView,handlePinView,handleSetDefaultView, the objectui#12418 docblock andhandleReorderViews,handleConfigViewandhandleAddView.The hook is called where
handleViewUpdatestood, afteruseObjectViewListUrlState. It returnshandleViewConfigSave,handleViewCreate,handleViewUpdate,handleViewChange,handleCreateView,handleViewAction,handleRenameView,handleDeleteView,handlePinView,handleSetDefaultView,handleReorderViews,handleConfigViewandhandleAddView.isSavedViewand the mobile switcher items stay inside the hook, their only readers.What stays. The five
useStatecalls of B (showViewConfigPanel,viewConfigPanelMode,showCreateViewDialog,manageViewsOpen,viewDraft, lines 217–226) stay in the component.activeView(F, line 758) readsviewDraftbefore the hook's inputs exist, and the JSX reads the panel and dialog flags. The hook receives the setters.Hook order.
handleViewConfigSaveandhandleViewCreate(twouseCallbacks) used to run before the record count state,useAuthand every hook down touseObjectViewListUrlState. They now run after it, inside the new hook, right beforehandleViewUpdate. They could not be called at their old spot: their bodies callsetRefreshKey, 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 ofhandleViewUpdateand 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,buildViewConfigSaveBodyanddispatchViewPatches. These names are still re-exported fromObjectView.tsxwhere 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 fromObjectView.tsx, and the package entry is untouched.ObjectView.tsxgoes from 1480 to 1151 lines.Move-only proof: the multiset of non-blank lines of the base
ObjectView.tsxis contained in the newObjectView.tsxplus the module, except 9 lines. Every one of the 9 is an import line or an import-list entry that lost a moved name: thePREVIEW_QUERY_FLAGandPREVIEW_QUERY_VALUEentries, the../utils/viewIdentity.jsimport (replaced by its trimmed form), thebuildAddViewSpec,setDefaultViewPatchesandbuildViewConfigSaveBodyentries of the./objectViewTabs.jslist, and the three-line./objectViewOptions.jsimport ofdispatchViewPatches. The module imports each of those names itself. The added lines are:return;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:
writeRefusalCensus-11583.test.ts: the sixLEDGERrows forhandleViewConfigSave,handleViewCreate,handleRenameView,handleDeleteView,handlePinViewandhandleSetDefaultViewchangefile: 'ObjectView.tsx'tofile: 'objectViewViewCrud.tsx'. Callees, counts, pins and reasons are unchanged. The census walksviews/, so it finds the sites in the new file.ui/scripts/__tests__/check-i18n-call-site-keys.test.ts: thedeleteViewConfirmrow of the deleted-fallbacks list →packages/app-shell/src/views/objectViewViewCrud.tsx. Its absent and present markers are unchanged.ObjectView.overlayPatchOnly.test.ts: the joinedobjectViewCodelist gains'objectViewViewCrud.tsx'. The control'shandleViewConfigSaveandpersistRuntimeMetadatareads are there now.view-filter-fold.ratchet.test.ts: the joinedobjectViewSrclist gainsobjectViewViewCrud.tsx, for thehandleViewConfigSaveinitializer the ratchet parses.ObjectView.unboundAdapterCall.test.ts: the detach-then-call ratchet readsObjectView.tsxandobjectViewViewCrud.tsxjoined, the same way as the two above. Without this edit it would still pass, but it would no longer readhandleSetDefaultViewandhandlePinView, 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.
a2e4b760viewDrafthandleViewConfigSave,handleViewCreateand their notessetRefreshKey)handleViewUpdatesetViewDraft), F (baseView)Verification
The full readings are in the os-dev-report comment on the card:
type-checkafter rebuilding its dependency closure;ObjectView.*test inviews/(the view CRUD, refusal, create-view, default-view, view-config save and mobile FAB tests among them), theAppContent*tests, and every other test that readsObjectView.tsxas source, including the five re-pointed ones;Acceptance notes
no-explicit-any.ObjectView.tsxplus the module report 83 warnings, against 80 for the baseObjectView.tsxalone.react-hooks/exhaustive-depswarnings in the module, and 1 existing one (theobjectNamewarning onhandleDeleteView) now also namessetRefreshKey. Each added warning names a state setter that is now a hook parameter (setRefreshKey,setViewDraft,setShowViewConfigPanel,setViewConfigPanelMode,setShowCreateViewDialog). The rule treats auseStatesetter 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.exhaustive-depswarnings onhandleViewChange, the 4preserve-manual-memoizationskips on these handlers, and 1react-hooks/immutabilityfinding (handleViewConfigSavereadingsetRefreshKeybefore its declaration).exhaustive-depswarnings (listPrefsinhandleReorderViews, and the two on theobjectDefeffect) only moved lines.Changeset:
.changeset/25992-objectview-view-crud-split.md(patch,@object-ui/app-shell).🤖 Generated with Claude Code
https://claude.ai/code/session_01QciHBvFJXnhZqXmdqpDtpz