diff --git a/web-admin/src/features/edit-session/EditSessionViewAs.svelte b/web-admin/src/features/edit-session/EditSessionViewAs.svelte
new file mode 100644
index 00000000000..35aacbca5f1
--- /dev/null
+++ b/web-admin/src/features/edit-session/EditSessionViewAs.svelte
@@ -0,0 +1,85 @@
+
+
+{#if hasSecurityPolicy}
+
+{/if}
diff --git a/web-admin/src/features/edit-session/updateEditSessionDevJWT.ts b/web-admin/src/features/edit-session/updateEditSessionDevJWT.ts
new file mode 100644
index 00000000000..62a92c675ef
--- /dev/null
+++ b/web-admin/src/features/edit-session/updateEditSessionDevJWT.ts
@@ -0,0 +1,56 @@
+import {
+ selectedMockUserJWT,
+ selectedMockUserStore,
+} from "@rilldata/web-common/features/dashboards/granular-access-policies/stores";
+import type { MockUser } from "@rilldata/web-common/features/dashboards/granular-access-policies/useMockUsers";
+import {
+ invalidateAllMetricsViews,
+ invalidateCanvasQueries,
+} from "@rilldata/web-common/runtime-client/invalidation";
+import type { RuntimeClient } from "@rilldata/web-common/runtime-client/v2";
+import type { QueryClient } from "@tanstack/svelte-query";
+import { adminServiceGetDeployment } from "@rilldata/web-admin/client";
+import { getDomain } from "@rilldata/web-admin/features/projects/user-management/selectors.ts";
+
+export function createUpdateEditSessionDevJWT(
+ deploymentId: string,
+ editSessionJwt: string,
+) {
+ return async (
+ queryClient: QueryClient,
+ client: RuntimeClient,
+ mockUser: MockUser | null,
+ ) => {
+ selectedMockUserStore.set(mockUser);
+
+ if (mockUser === null) {
+ selectedMockUserJWT.set(null);
+ client.updateJwt(editSessionJwt, "user");
+ } else {
+ try {
+ const { name, email, groups, admin, ...customAttributes } = mockUser;
+
+ const { accessToken } = await adminServiceGetDeployment(deploymentId, {
+ attributes: {
+ email,
+ ...(email ? { domain: getDomain(email) } : {}),
+ name: name || "Mock User",
+ admin: !!admin,
+ groups: groups || [],
+ ...customAttributes,
+ },
+ });
+
+ if (!accessToken) throw new Error("No JWT returned");
+
+ selectedMockUserJWT.set(accessToken);
+ client.updateJwt(accessToken, "mock");
+ } catch {
+ // no-op
+ }
+ }
+
+ await invalidateAllMetricsViews(queryClient, client.instanceId);
+ return invalidateCanvasQueries(queryClient, client.instanceId);
+ };
+}
diff --git a/web-admin/src/features/projects/header/ProjectHeader.svelte b/web-admin/src/features/projects/header/ProjectHeader.svelte
index 1f35ee90745..924670dcecb 100644
--- a/web-admin/src/features/projects/header/ProjectHeader.svelte
+++ b/web-admin/src/features/projects/header/ProjectHeader.svelte
@@ -54,6 +54,7 @@
import { useReports } from "../../scheduled-reports/selectors";
import SharePersonalFile from "web-admin/src/features/personal-files/SharePersonalFile.svelte";
import VisualizationsBreadcrumbDropdown from "./VisualizationsBreadcrumbDropdown.svelte";
+ import EditSessionViewAs from "@rilldata/web-admin/features/edit-session/EditSessionViewAs.svelte";
export let organization: string;
export let project: string;
@@ -65,6 +66,8 @@
export let planDisplayName: string | undefined;
export let organizationLogoUrl: string | undefined;
export let editContext: boolean = false;
+ export let editSessionDeploymentId: string | undefined = undefined;
+ export let editSessionJwt: string | undefined = undefined;
const user = createAdminServiceGetCurrentUser();
const runtimeClient = useRuntimeClient();
@@ -216,6 +219,12 @@
{#if editContext}
+ {#if editSessionDeploymentId && editSessionJwt}
+
+ {/if}
{#if $developerChat && !onEditDashboardPreview}
{/if}
diff --git a/web-admin/src/features/projects/user-management/selectors.ts b/web-admin/src/features/projects/user-management/selectors.ts
index 7130b2bdbb1..cb3e90cba89 100644
--- a/web-admin/src/features/projects/user-management/selectors.ts
+++ b/web-admin/src/features/projects/user-management/selectors.ts
@@ -27,7 +27,7 @@ export function emailIsPublic(email: string) {
return RillPublicEmailDomains.includes(domain);
}
-function getDomain(email: string) {
+export function getDomain(email: string) {
const domainParts = email.split("@");
return domainParts.length ? domainParts[domainParts.length - 1] : "";
}
diff --git a/web-admin/src/routes/[organization]/[project]/-/edit/+layout.svelte b/web-admin/src/routes/[organization]/[project]/-/edit/+layout.svelte
index b9ef1836869..0fe886e06a8 100644
--- a/web-admin/src/routes/[organization]/[project]/-/edit/+layout.svelte
+++ b/web-admin/src/routes/[organization]/[project]/-/edit/+layout.svelte
@@ -192,6 +192,8 @@
{planDisplayName}
{organizationLogoUrl}
editContext={true}
+ editSessionDeploymentId={deployment.id}
+ editSessionJwt={jwt}
/>
@@ -45,7 +51,7 @@
active={viewAsMenuOpen}
removeTooltipText={m.dashboard_clear_view()}
onRemove={() => {
- updateDevJWT(queryClient, client, null);
+ devJTWUpdater(queryClient, client, null);
}}
>
@@ -68,7 +74,7 @@
{#each $mockUsers.data as user (user?.email)}
{
- updateDevJWT(queryClient, client, user);
+ devJTWUpdater(queryClient, client, user);
}}
class="flex gap-x-2 items-center"
>