Skip to content

Commit 9495fbb

Browse files
committed
fix(app-shell): compute the sidebar's pruned trees inline, without new lint findings
The two useMemo wrappers drew react-hooks/exhaustive-deps and preserve-manual-memoization on the lines they added. A tree with nothing to prune comes back as the array it was, so the memo bought nothing and nothing downstream keys on a pruned tree's identity. Also drops two new explicit anys (an annotation on ObjectView's listActions, a test cast). Claude-Session: https://claude.ai/code/session_01AswpQDLCKiZos2jCXknwKz Co-authored-by: Claude <noreply@anthropic.com>
1 parent 174f48f commit 9495fbb

3 files changed

Lines changed: 14 additions & 15 deletions

File tree

‎packages/app-shell/src/layout/UnifiedSidebar.tsx‎

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -237,19 +237,18 @@ export function UnifiedSidebar({ activeAppName }: UnifiedSidebarProps) {
237237
// because no callback the layout asks answers "may this member read this
238238
// object" (see `withoutUnreadableObjectEntries`). Every area's tree and the
239239
// flat tree are pruned the same way, so the area election below and the drawn
240-
// menu read the same tree.
241-
const readableAreas = React.useMemo(
242-
() => areas.map((area) => {
243-
if (!area.navigation) return area;
244-
const navigation = withoutUnreadableObjectEntries(area.navigation, can);
245-
return navigation === area.navigation ? area : { ...area, navigation };
246-
}),
247-
[areas, can],
248-
);
249-
const readableAppNavigation = React.useMemo(
250-
() => (activeApp?.navigation ? withoutUnreadableObjectEntries(activeApp.navigation, can) : activeApp?.navigation),
251-
[activeApp?.navigation, can],
252-
);
240+
// menu read the same tree. Not memoised: a tree with nothing to prune comes
241+
// back as the very array it was, so a caller who may read everything hands
242+
// the layout the authored tree, and nothing downstream keys on the identity
243+
// of a pruned one (AGENTS.md #10).
244+
const readableAreas = areas.map((area) => {
245+
if (!area.navigation) return area;
246+
const navigation = withoutUnreadableObjectEntries(area.navigation, can);
247+
return navigation === area.navigation ? area : { ...area, navigation };
248+
});
249+
const readableAppNavigation: NavigationItem[] | undefined = activeApp?.navigation
250+
? withoutUnreadableObjectEntries(activeApp.navigation, can)
251+
: activeApp?.navigation;
253252
// A `doc` entry the member may not read is not drawn (objectui#10188) —
254253
// defence in depth behind the server's app read, which already drops it
255254
// (objectstack#19790). Asked only in an app: on Home `activeApp` is merely

‎packages/app-shell/src/views/ObjectView.listActionsReadGate-12109.test.tsx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ function makeDataSource() {
121121
create: vi.fn(async () => ({})),
122122
update: vi.fn(async () => ({})),
123123
delete: vi.fn(async () => ({})),
124-
} as any;
124+
} as never;
125125
}
126126

127127
const USER = { id: 'u_agent', name: 'Agent' };

‎packages/app-shell/src/views/ObjectView.tsx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2003,7 +2003,7 @@ function ObjectViewInner({ dataSource, objects, onEdit, externalRefreshKey }: Co
20032003
// and its list actions go together. A boolean, read each render from the
20042004
// provider's verdict, so the memo below keys on a primitive (AGENTS.md #10).
20052005
const listActionsReadable = mayReadObject(perms.can, objectDef.name);
2006-
const listActions: any[] | undefined = listActionsReadable ? objectDef.actions : undefined;
2006+
const listActions = listActionsReadable ? objectDef.actions : undefined;
20072007
// Localized `list_toolbar` actions, shared by the generic action bar and the
20082008
// environment-aware toolbar (the action:bar renderer filters by location).
20092009
const localizedToolbarActions = useMemo(

0 commit comments

Comments
 (0)