diff --git a/web-admin/src/features/projects/ProjectTabs.svelte b/web-admin/src/features/projects/ProjectTabs.svelte index 0c951097c68..313bf234104 100644 --- a/web-admin/src/features/projects/ProjectTabs.svelte +++ b/web-admin/src/features/projects/ProjectTabs.svelte @@ -5,6 +5,7 @@ } from "@rilldata/web-admin//components/nav/Tab.svelte"; import Tab from "@rilldata/web-admin/components/nav/Tab.svelte"; import { removeBranchFromPath } from "@rilldata/web-admin/features/branches/branch-utils"; + import { viewAsUserStore } from "@rilldata/web-admin/features/view-as-user/viewAsUserStore"; import { featureFlags } from "@rilldata/web-common/features/feature-flags"; import { type V1ProjectPermissions } from "../../client"; @@ -16,48 +17,59 @@ const { chat, reports, alerts } = featureFlags; - $: tabs = [ - { - route: `/${organization}/${project}${branchPrefix}`, - label: "Home", - hasPermission: true, - }, - { - route: `/${organization}/${project}${branchPrefix}/-/ai`, - label: "AI", - hasPermission: $chat, - }, - { - route: `/${organization}/${project}${branchPrefix}/-/dashboards`, - label: "Dashboards", - hasPermission: true, - }, - { - route: `/${organization}/${project}${branchPrefix}/-/query`, - label: "Query", - hasPermission: false, - }, - { - route: `/${organization}/${project}${branchPrefix}/-/reports`, - label: "Reports", - hasPermission: $reports, - }, - { - route: `/${organization}/${project}${branchPrefix}/-/alerts`, - label: "Alerts", - hasPermission: $alerts, - }, - { - route: `/${organization}/${project}${branchPrefix}/-/status`, - label: "Status", - hasPermission: projectPermissions.manageProject, - }, - { - route: `/${organization}/${project}${branchPrefix}/-/settings`, - label: "Settings", - hasPermission: projectPermissions.manageProject, - }, - ]; + // While "View As" is active, the project view is scoped to dashboards + // only — other tabs (Home, AI, Reports, Alerts, Status, Settings) are + // hidden and their routes redirect in the project layout. + $: tabs = $viewAsUserStore + ? [ + { + route: `/${organization}/${project}${branchPrefix}/-/dashboards`, + label: "Dashboards", + hasPermission: true, + }, + ] + : [ + { + route: `/${organization}/${project}${branchPrefix}`, + label: "Home", + hasPermission: true, + }, + { + route: `/${organization}/${project}${branchPrefix}/-/ai`, + label: "AI", + hasPermission: $chat, + }, + { + route: `/${organization}/${project}${branchPrefix}/-/dashboards`, + label: "Dashboards", + hasPermission: true, + }, + { + route: `/${organization}/${project}${branchPrefix}/-/query`, + label: "Query", + hasPermission: false, + }, + { + route: `/${organization}/${project}${branchPrefix}/-/reports`, + label: "Reports", + hasPermission: $reports, + }, + { + route: `/${organization}/${project}${branchPrefix}/-/alerts`, + label: "Alerts", + hasPermission: $alerts, + }, + { + route: `/${organization}/${project}${branchPrefix}/-/status`, + label: "Status", + hasPermission: projectPermissions.manageProject, + }, + { + route: `/${organization}/${project}${branchPrefix}/-/settings`, + label: "Settings", + hasPermission: projectPermissions.manageProject, + }, + ]; $: selectedIndex = tabs?.findLastIndex((t) => isSelected(t.route, pathname)); diff --git a/web-admin/src/routes/[organization]/[project]/+layout.svelte b/web-admin/src/routes/[organization]/[project]/+layout.svelte index ec31aef10f0..a5abf09951b 100644 --- a/web-admin/src/routes/[organization]/[project]/+layout.svelte +++ b/web-admin/src/routes/[organization]/[project]/+layout.svelte @@ -18,6 +18,7 @@ branchPathPrefix, extractBranchFromPath, handleBranchNavigation, + removeBranchFromPath, } from "@rilldata/web-admin/features/branches/branch-utils"; import { V1DeploymentStatus, @@ -109,6 +110,21 @@ }; }); + // While "View As" is active, scope the project view to dashboards only. + // Any other project page (Home, AI, Reports, Alerts, Status, Settings) is + // redirected — entering View As is a deliberate "see what they see" mode, + // and admin surfaces aren't part of that. + $effect(() => { + if (!$viewAsUserStore) return; + if (!onProjectPage) return; + const dashboardsPath = `/${organization}/${project}${branchPrefix}/-/dashboards`; + const normalizedPath = removeBranchFromPath(page.url.pathname); + const normalizedDashboards = removeBranchFromPath(dashboardsPath); + if (!normalizedPath.startsWith(normalizedDashboards)) { + void goto(dashboardsPath); + } + }); + // --- Queries (three auth strategies; cookie and token are mutually exclusive, // mock is an overlay that runs in parallel when View As is active) ---