From 96d230430c84088ce0b8afd45d2d9dd003071bd6 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 7 Oct 2026 20:10:40 +0000 Subject: [PATCH 1/4] fix(app-shell): Studio Interfaces keys a nav surface by the entry's id and previews its slice or view The Interfaces rail identified a nav entry by {type,name} alone, so entries that open one object with different `filters` or `viewName` were one surface: all highlighted at once, one unfiltered preview, and a reload landing on the first. The resolved Surface now carries the entry's `id`, `filters` and `viewName`; the rail and the deep-link restore compare by id when both sides carry one; `?surface=` gains a `nav` key beside it; and the default object canvas reads the entry the way the runtime's nav does (resolveHref, then the landing route's own reading). Claude-Session: https://claude.ai/code/session_01DrKzdPdyLLBW3qpZ4vtk7z Co-authored-by: Claude --- .../studio-design/StudioDesignSurface.tsx | 24 +++- .../src/views/studio-design/navSurface.ts | 113 ++++++++++++--- .../studio-design/studio-canvas-preview.tsx | 132 +++++++++++++++++- .../views/studio-design/useSurfaceDeepLink.ts | 55 +++++++- 4 files changed, 298 insertions(+), 26 deletions(-) diff --git a/packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx b/packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx index 55836d46cd..34cf14857b 100644 --- a/packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx +++ b/packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx @@ -89,7 +89,7 @@ import { listMetadataPreviewTypes, type MetadataSelection, } from '../metadata-admin/preview-registry.js'; -import { getStudioCanvasPreview } from './studio-canvas-preview.js'; +import { getStudioCanvasPreview, StudioCanvasNavEntryContext, type StudioCanvasNavEntry } from './studio-canvas-preview.js'; import { PermissionMatrixEditPage } from '../metadata-admin/PermissionMatrixEditor.js'; import { AccessExplainPanel } from '../metadata-admin/AccessExplainPanel.js'; import { @@ -120,7 +120,7 @@ import { } from './studioScope.js'; import { useMetadataRefreshNonce } from './useMetadataRefreshNonce.js'; import { useHomePath } from '../../hooks/useHomePath.js'; -import { resolveSurface, findSurfaceInTree, type NavNode, type Surface } from './navSurface.js'; +import { resolveSurface, findSurfaceInTree, isSameSurface, type NavNode, type Surface } from './navSurface.js'; import { useSurfaceDeepLink, resolveSurfaceDeepLink, type SurfaceTarget } from './useSurfaceDeepLink.js'; import { isStudioRunLanding } from './studioLanding.js'; import { SurfaceDeepLinkProvider, useRequestedSurface } from './surfaceDeepLinkChannel.js'; @@ -1709,7 +1709,9 @@ function NavTree({ // type-generic fallback. const objIcon = surface?.type === 'object' ? objectIcons?.[surface.name] : undefined; const Icon: React.ElementType = node.icon ? getIcon(node.icon) : objIcon ? getIcon(objIcon) : navIcon(node.type); - const isActive = !!surface && active?.type === surface.type && active?.name === surface.name; + // objectui#11774 — the ENTRY is active, not every entry of its target: + // compared by nav id when both carry one (see `isSameSurface`). + const isActive = !!surface && !!active && isSameSurface(active, surface); return (