From 53911d5abd9e2347ab44a0bad8d0734878751279 Mon Sep 17 00:00:00 2001 From: Aditya Hegde Date: Tue, 23 Dec 2025 19:38:26 +0530 Subject: [PATCH 1/2] fix: deploy not leading to home page --- web-admin/src/features/alerts/selectors.ts | 4 +- .../listing/deploying-dashboards.ts | 82 +++++++++---------- .../features/dashboards/listing/selectors.ts | 4 +- .../src/features/projects/status/selectors.ts | 4 +- .../features/scheduled-reports/selectors.ts | 4 +- web-admin/src/lib/refetch-interval-store.ts | 2 +- .../[project]/-/dashboards/+page.svelte | 56 ++----------- .../-/deploy-landing-page/+page.svelte | 35 ++++++++ .../+page.ts | 2 - .../[project]/-/invite/+page.svelte | 3 +- .../project/deploy/UpdateProjectPopup.svelte | 7 +- .../features/project/deploy/route-utils.ts | 34 ++++++-- .../src/features/project/deploy/utils.ts | 5 ++ .../src/routes/(misc)/deploy/+page.svelte | 2 +- .../(misc)/deploy/project/create/+page.svelte | 2 +- .../(misc)/deploy/project/select/+page.svelte | 2 + .../(misc)/deploy/project/update/+page.svelte | 6 +- 17 files changed, 132 insertions(+), 122 deletions(-) create mode 100644 web-admin/src/routes/[organization]/[project]/-/deploy-landing-page/+page.svelte rename web-admin/src/routes/[organization]/[project]/-/{dashboards => deploy-landing-page}/+page.ts (80%) diff --git a/web-admin/src/features/alerts/selectors.ts b/web-admin/src/features/alerts/selectors.ts index 7115eec5a30..97e69247cba 100644 --- a/web-admin/src/features/alerts/selectors.ts +++ b/web-admin/src/features/alerts/selectors.ts @@ -9,7 +9,7 @@ import { createRuntimeServiceListResources, type V1AlertSpec, } from "@rilldata/web-common/runtime-client"; -import { createSmartRefetchInterval } from "@rilldata/web-admin/lib/refetch-interval-store"; +import { smartRefetchInterval } from "@rilldata/web-admin/lib/refetch-interval-store"; import { derived, type Readable, readable } from "svelte/store"; export function useAlerts(instanceId: string, enabled = true) { @@ -22,7 +22,7 @@ export function useAlerts(instanceId: string, enabled = true) { query: { enabled: enabled && !!instanceId, refetchOnMount: true, - refetchInterval: createSmartRefetchInterval, + refetchInterval: smartRefetchInterval, }, }, ); diff --git a/web-admin/src/features/dashboards/listing/deploying-dashboards.ts b/web-admin/src/features/dashboards/listing/deploying-dashboards.ts index 928609a0a0c..85cb9214d09 100644 --- a/web-admin/src/features/dashboards/listing/deploying-dashboards.ts +++ b/web-admin/src/features/dashboards/listing/deploying-dashboards.ts @@ -1,4 +1,3 @@ -import { isResourceReconciling } from "@rilldata/web-admin/lib/refetch-interval-store.ts"; import { ResourceKind } from "@rilldata/web-common/features/entity-management/resource-selectors.ts"; import { createRuntimeServiceListResources, @@ -6,59 +5,70 @@ import { type V1Resource, } from "@rilldata/web-common/runtime-client"; import type { CreateQueryResult } from "@tanstack/svelte-query"; +import { isResourceReconciling } from "@rilldata/web-admin/lib/refetch-interval-store.ts"; export function useDeployingDashboards( instanceId: string, orgName: string, projName: string, - deploying: boolean, deployingDashboard: string | null, ): CreateQueryResult<{ - redirectToDashboardPath: string | null; - dashboardsReconciling: boolean; + redirectPath: string | null; dashboardsErrored: boolean; }> { return createRuntimeServiceListResources(instanceId, undefined, { query: { select: (data) => { - if (!deploying) { + const resources = data.resources ?? []; + const dashboards = resources.filter(isDashboard); + + const reconciling = getDashboardsReconciling( + dashboards, + deployingDashboard, + ); + if (reconciling) { return { - redirectToDashboardPath: null, - dashboardsReconciling: false, + redirectPath: null, dashboardsErrored: false, }; } - const resources = data.resources ?? []; - const dashboards = resources.filter(isDashboard); - const dashboard = getDashboard(dashboards, deployingDashboard) ?? null; - const hasValidDashboard = dashboard - ? isValidDashboard(dashboard) - : false; + const dashboardsErrored = getDashboardsErrored( + dashboards, + deployingDashboard, + ); + if (dashboardsErrored) { + const dashboardsErrored = getDashboardsErrored( + dashboards, + deployingDashboard, + ); + return { + // Redirect to status page is dashboards errored + redirectPath: dashboardsErrored + ? `/${orgName}/${projName}/-/status` + : null, + dashboardsErrored, + }; + } - if (!hasValidDashboard || !dashboard?.meta?.name?.name) { + // Redirect to home page if no specific dashboard was deployed + if (!deployingDashboard) { return { - redirectToDashboardPath: null, - dashboardsReconciling: getDashboardsReconciling( - dashboards, - deployingDashboard, - ), - dashboardsErrored: getDashboardsErrored( - dashboards, - deployingDashboard, - ), + redirectPath: `/${orgName}/${projName}`, + dashboardsErrored: false, }; } + const dashboard = dashboards.find( + (res) => res.meta?.name?.name === deployingDashboard, + ); const resourceRoute = dashboard.meta?.name?.kind === ResourceKind.Explore ? "explore" : "canvas"; - const redirectToDashboardPath = `/${orgName}/${projName}/${resourceRoute}/${dashboard.meta.name.name}`; - + const redirectPath = `/${orgName}/${projName}/${resourceRoute}/${dashboard.meta.name.name}`; return { - redirectToDashboardPath, - dashboardsReconciling: false, + redirectPath, dashboardsErrored: false, }; }, @@ -66,24 +76,6 @@ export function useDeployingDashboards( }); } -function getDashboard( - dashboards: V1Resource[], - dashboardName: string | null, -): V1Resource | undefined { - let dashboard: V1Resource | undefined; - if (dashboardName) { - dashboard = dashboards.find( - (res) => res.meta?.name?.name === dashboardName, - ); - } else { - dashboard = - dashboards.find((res) => res.canvas?.state?.validSpec) ?? - dashboards.find((res) => res.explore?.state?.validSpec); - } - - return dashboard; -} - function getDashboardsReconciling( dashboards: V1Resource[], dashboardName: string | null, diff --git a/web-admin/src/features/dashboards/listing/selectors.ts b/web-admin/src/features/dashboards/listing/selectors.ts index 7f28a786b57..6489c6e56c6 100644 --- a/web-admin/src/features/dashboards/listing/selectors.ts +++ b/web-admin/src/features/dashboards/listing/selectors.ts @@ -4,7 +4,7 @@ import type { V1Resource } from "@rilldata/web-common/runtime-client"; import { createRuntimeServiceListResources } from "@rilldata/web-common/runtime-client"; import type { CreateQueryResult } from "@tanstack/svelte-query"; import { derived } from "svelte/store"; -import { createSmartRefetchInterval } from "@rilldata/web-admin/lib/refetch-interval-store"; +import { smartRefetchInterval } from "@rilldata/web-admin/lib/refetch-interval-store"; export function useDashboardsLastUpdated( instanceId: string, @@ -42,7 +42,7 @@ export function useDashboards( select: (data) => { return data.resources.filter((res) => res.canvas || res.explore); }, - refetchInterval: createSmartRefetchInterval, + refetchInterval: smartRefetchInterval, }, }); } diff --git a/web-admin/src/features/projects/status/selectors.ts b/web-admin/src/features/projects/status/selectors.ts index d226fb687fd..34340c930b8 100644 --- a/web-admin/src/features/projects/status/selectors.ts +++ b/web-admin/src/features/projects/status/selectors.ts @@ -7,7 +7,7 @@ import { type V1ListResourcesResponse, } from "@rilldata/web-common/runtime-client"; import { ResourceKind } from "@rilldata/web-common/features/entity-management/resource-selectors"; -import { createSmartRefetchInterval } from "@rilldata/web-admin/lib/refetch-interval-store"; +import { smartRefetchInterval } from "@rilldata/web-admin/lib/refetch-interval-store"; export function useProjectDeployment(orgName: string, projName: string) { return createAdminServiceGetProject( @@ -42,7 +42,7 @@ export function useResources(instanceId: string) { resources: filtered, }; }, - refetchInterval: createSmartRefetchInterval, + refetchInterval: smartRefetchInterval, }, }, ); diff --git a/web-admin/src/features/scheduled-reports/selectors.ts b/web-admin/src/features/scheduled-reports/selectors.ts index 2fd13655fdb..a38f5a9a8a8 100644 --- a/web-admin/src/features/scheduled-reports/selectors.ts +++ b/web-admin/src/features/scheduled-reports/selectors.ts @@ -5,7 +5,7 @@ import { createRuntimeServiceGetResource, createRuntimeServiceListResources, } from "@rilldata/web-common/runtime-client"; -import { createSmartRefetchInterval } from "@rilldata/web-admin/lib/refetch-interval-store"; +import { smartRefetchInterval } from "@rilldata/web-admin/lib/refetch-interval-store"; export function useReports(instanceId: string, enabled = true) { return createRuntimeServiceListResources( @@ -17,7 +17,7 @@ export function useReports(instanceId: string, enabled = true) { query: { enabled: enabled && !!instanceId, refetchOnMount: true, - refetchInterval: createSmartRefetchInterval, + refetchInterval: smartRefetchInterval, }, }, ); diff --git a/web-admin/src/lib/refetch-interval-store.ts b/web-admin/src/lib/refetch-interval-store.ts index 701e889b6ee..aca648adbe2 100644 --- a/web-admin/src/lib/refetch-interval-store.ts +++ b/web-admin/src/lib/refetch-interval-store.ts @@ -70,7 +70,7 @@ const queryRefetchStateMap = new WeakMap< * @param query The TanStack query object * @returns The refetch interval (number in ms or false to disable) */ -export function createSmartRefetchInterval( +export function smartRefetchInterval( query: Query< V1ListResourcesResponse, HTTPError, diff --git a/web-admin/src/routes/[organization]/[project]/-/dashboards/+page.svelte b/web-admin/src/routes/[organization]/[project]/-/dashboards/+page.svelte index 5b1ecb27568..93c430bbe3e 100644 --- a/web-admin/src/routes/[organization]/[project]/-/dashboards/+page.svelte +++ b/web-admin/src/routes/[organization]/[project]/-/dashboards/+page.svelte @@ -1,61 +1,19 @@ {project} overview - Rill -{#if showError} - -{:else if showSpinner} - -{:else} - -
- -
-
-{/if} + +
+ +
+
diff --git a/web-admin/src/routes/[organization]/[project]/-/deploy-landing-page/+page.svelte b/web-admin/src/routes/[organization]/[project]/-/deploy-landing-page/+page.svelte new file mode 100644 index 00000000000..cbc16df27b1 --- /dev/null +++ b/web-admin/src/routes/[organization]/[project]/-/deploy-landing-page/+page.svelte @@ -0,0 +1,35 @@ + + + diff --git a/web-admin/src/routes/[organization]/[project]/-/dashboards/+page.ts b/web-admin/src/routes/[organization]/[project]/-/deploy-landing-page/+page.ts similarity index 80% rename from web-admin/src/routes/[organization]/[project]/-/dashboards/+page.ts rename to web-admin/src/routes/[organization]/[project]/-/deploy-landing-page/+page.ts index 2075a09ff34..2a2be6254f0 100644 --- a/web-admin/src/routes/[organization]/[project]/-/dashboards/+page.ts +++ b/web-admin/src/routes/[organization]/[project]/-/deploy-landing-page/+page.ts @@ -1,11 +1,9 @@ import { DeployingDashboardUrlParam } from "@rilldata/web-common/features/project/deploy/utils.ts"; export const load = ({ url: { searchParams } }) => { - const deploying = searchParams.has("deploying"); const deployingDashboard = searchParams.get(DeployingDashboardUrlParam); return { - deploying, deployingDashboard, }; }; diff --git a/web-admin/src/routes/[organization]/[project]/-/invite/+page.svelte b/web-admin/src/routes/[organization]/[project]/-/invite/+page.svelte index 3924ff89bfc..0529a586647 100644 --- a/web-admin/src/routes/[organization]/[project]/-/invite/+page.svelte +++ b/web-admin/src/routes/[organization]/[project]/-/invite/+page.svelte @@ -68,8 +68,7 @@ function getDeployLandingPage() { const u = new URL($page.url); - u.pathname = `/${organization}/${project}/-/dashboards`; - u.searchParams.set("deploying", "true"); + u.pathname = `/${organization}/${project}/-/deploy-landing-page`; return u.toString(); } diff --git a/web-common/src/features/project/deploy/UpdateProjectPopup.svelte b/web-common/src/features/project/deploy/UpdateProjectPopup.svelte index 5a2a977c7fd..20d7db08e57 100644 --- a/web-common/src/features/project/deploy/UpdateProjectPopup.svelte +++ b/web-common/src/features/project/deploy/UpdateProjectPopup.svelte @@ -1,4 +1,5 @@ diff --git a/web-common/src/features/dashboards/workspace/DeployProjectCTA.svelte b/web-common/src/features/dashboards/workspace/DeployProjectCTA.svelte index 9193e40392d..4d86f6cfa2e 100644 --- a/web-common/src/features/dashboards/workspace/DeployProjectCTA.svelte +++ b/web-common/src/features/dashboards/workspace/DeployProjectCTA.svelte @@ -66,6 +66,7 @@ $: redirectPageUrl = copyWithAdditionalArguments($page.url, { deploy: "true", }); + $: console.log("Deploy route:", $deployPageUrl); async function onDeploy(resumingDeploy = false) { await waitUntil(() => !get(deploymentState).loading); diff --git a/web-common/src/features/entity-management/file-artifacts.ts b/web-common/src/features/entity-management/file-artifacts.ts index 0be89adcdc1..df6b8e2f314 100644 --- a/web-common/src/features/entity-management/file-artifacts.ts +++ b/web-common/src/features/entity-management/file-artifacts.ts @@ -8,8 +8,9 @@ import { type V1ResourceName, } from "@rilldata/web-common/runtime-client"; import type { QueryClient } from "@tanstack/svelte-query"; -import { derived, get, writable } from "svelte/store"; +import { derived, get, writable, type Readable } from "svelte/store"; import { FileArtifact } from "./file-artifact"; +import { page } from "$app/stores"; class UnsavedFilesStore { private unsavedFiles = writable(new Set()); @@ -171,6 +172,14 @@ export class FileArtifacts { } return null; } + + public createCurrentResourceStore(): Readable { + return derived(page, (pageState, set) => { + const filePath = pageState.url.pathname.replace("/files", ""); + const fileArtifact = this.getFileArtifact(filePath); + return fileArtifact.resourceName.subscribe(set); + }); + } } export const fileArtifacts = new FileArtifacts(); diff --git a/web-common/src/features/project/deploy/UpdateProjectPopup.svelte b/web-common/src/features/project/deploy/UpdateProjectPopup.svelte index 20d7db08e57..3974628cc78 100644 --- a/web-common/src/features/project/deploy/UpdateProjectPopup.svelte +++ b/web-common/src/features/project/deploy/UpdateProjectPopup.svelte @@ -9,6 +9,7 @@ import { getManageProjectAccess } from "@rilldata/web-common/features/project/selectors.ts"; import type { Project } from "@rilldata/web-common/proto/gen/rill/admin/v1/api_pb"; import Rocket from "svelte-radix/Rocket.svelte"; + import { fileArtifacts } from "@rilldata/web-common/features/entity-management/file-artifacts.ts"; export let open = false; export let matchingProjects: Project[]; @@ -22,9 +23,11 @@ $: enableUpdate = !!selectedProject; + const currentResource = fileArtifacts.createCurrentResourceStore(); $: deployUrl = selectedProject ? getUpdateProjectRoute( $page, + $currentResource, selectedProject.orgName, selectedProject.name, ) diff --git a/web-common/src/features/project/deploy/route-utils.ts b/web-common/src/features/project/deploy/route-utils.ts index e1e944404dc..da932117bfc 100644 --- a/web-common/src/features/project/deploy/route-utils.ts +++ b/web-common/src/features/project/deploy/route-utils.ts @@ -3,7 +3,6 @@ import { ResourceKind } from "@rilldata/web-common/features/entity-management/re import { DeployingDashboardUrlParam, getDeployingDashboard, - getDeployingDashboardFromUrl, } from "@rilldata/web-common/features/project/deploy/utils.ts"; import { addPosthogSessionIdToUrl } from "@rilldata/web-common/lib/analytics/posthog.ts"; import { createLocalServiceGitStatus } from "@rilldata/web-common/runtime-client/local-service"; @@ -12,6 +11,7 @@ import { derived, readable } from "svelte/store"; import { getLocalGitRepoStatus } from "../selectors"; import { page } from "$app/stores"; import { featureFlags } from "../../feature-flags"; +import type { V1ResourceName } from "@rilldata/web-common/runtime-client"; /** * Returns a {@link Readable} with a route to deploy. @@ -43,6 +43,7 @@ export function getCreateProjectRoute(orgName: string, useGit = false) { export function getUpdateProjectRoute( page: Page, + currentResource: V1ResourceName | undefined, orgName: string, projectName: string, createManagedRepo = false, @@ -57,7 +58,15 @@ export function getUpdateProjectRoute( deployUrl.searchParams.set("create_managed_repo", "true"); } - if (isDashboardVizRoute(page)) { + if ( + currentResource?.kind === ResourceKind.Explore || + currentResource?.kind === ResourceKind.Canvas + ) { + deployUrl.searchParams.set( + DeployingDashboardUrlParam, + currentResource.name!, + ); + } else if (isDashboardVizRoute(page)) { deployUrl.searchParams.set(DeployingDashboardUrlParam, page.params.name); } @@ -82,7 +91,7 @@ export function getSelectOrganizationRoute() { export function getDeployLandingPage(frontendUrl: string, isInvite: boolean) { const url = new URL(frontendUrl); - const deployingDashboard = getDeployingDashboardFromUrl(); + const deployingDashboard = getDeployingDashboard(); if (deployingDashboard) { url.searchParams.set(DeployingDashboardUrlParam, deployingDashboard); } diff --git a/web-common/src/features/project/deploy/utils.ts b/web-common/src/features/project/deploy/utils.ts index 7dd03059cae..f3263c123fe 100644 --- a/web-common/src/features/project/deploy/utils.ts +++ b/web-common/src/features/project/deploy/utils.ts @@ -16,10 +16,9 @@ export function maybeSetDeployingDashboard(url: URL) { } export function getDeployingDashboard() { - return sessionStorage.getItem(deployingDashboardKey); -} - -export function getDeployingDashboardFromUrl() { const url = new URL(window.location.href); - return url.searchParams.get(DeployingDashboardUrlParam); + return ( + sessionStorage.getItem(deployingDashboardKey) || + url.searchParams.get(DeployingDashboardUrlParam) + ); } diff --git a/web-integration/tests/deploy.spec.ts b/web-integration/tests/deploy.spec.ts index 39a28e4077b..02248dcf1ff 100644 --- a/web-integration/tests/deploy.spec.ts +++ b/web-integration/tests/deploy.spec.ts @@ -77,6 +77,15 @@ test.describe("Deploy journey", () => { rillDevPage.getByText("Deploy this project for free"), ).toBeVisible(); // Hit continue to start deployment + await expect + .poll( + () => + rillDevPage + .getByRole("button", { name: "Continue" }) + .getAttribute("href"), + { intervals: Array(15).fill(1_000), timeout: 15_000 }, + ) + .toMatch(/deploying_dashboard/); await rillDevPage.getByRole("button", { name: "Continue" }).click(); // Await for the popped up deploy page after hitting deploy @@ -131,6 +140,10 @@ test.describe("Deploy journey", () => { await rillDevPage .getByTitle("Display name") .fill("Adbids dashboard edited first org"); + // Wait for reconcile to complete and dashboard is ready + await expect(rillDevPage.getByText("Total records 100k")).toBeVisible({ + timeout: 30_000, + }); // Start waiting for popup before clicking Deploy. const popupPromise = rillDevPage.waitForEvent("popup"); @@ -152,12 +165,10 @@ test.describe("Deploy journey", () => { // Await for the popped up deploy page after hitting deploy const deployPage = await popupPromise; - await ensureProjectRedeployed(deployPage); - - await ensureDashboardTitle( - deployPage, - "Adbids dashboard edited first org", - ); + // Explore is opened with updated title after a re-deploying. + await expect( + deployPage.getByLabel("Breadcrumb navigation, level 2"), + ).toHaveText("Adbids dashboard edited first org", { timeout: 120_000 }); }); }); @@ -197,10 +208,10 @@ test.describe("Deploy journey", () => { await assertAndSkipInvite(deployPage); - // Canvas is opened. - await expect( - deployPage.getByLabel("Breadcrumb navigation, level 2"), - ).toHaveText("Adbids Canvas Dashboard"); + // Project homepage is opened on since we are not deploying from any dashboard. + await expect(deployPage.getByText("Welcome to")).toBeVisible({ + timeout: 120_000, + }); // Org title is correct await expect( @@ -225,18 +236,3 @@ async function assertAndSkipInvite(page: Page) { // Skip invite and continue to status page. await page.getByRole("button", { name: "Skip for now" }).click(); } - -async function ensureProjectRedeployed(page: Page) { - // Project homepage is opened on a re-deploy. This can take a while, so it has increased timeout. - await expect(page.getByText("Welcome to")).toBeVisible({ - timeout: 120_000, - }); -} - -async function ensureDashboardTitle(page: Page, title: string) { - await expect( - page.getByRole("link", { - name: title, - }), - ).toBeVisible({ timeout: 60_000 }); -} diff --git a/web-local/src/routes/(misc)/deploy/+page.svelte b/web-local/src/routes/(misc)/deploy/+page.svelte index e83c18d96c7..eaec1ed5e0e 100644 --- a/web-local/src/routes/(misc)/deploy/+page.svelte +++ b/web-local/src/routes/(misc)/deploy/+page.svelte @@ -78,7 +78,12 @@ const singleProject = $matchingProjects.data!.projects[0]; // Project already exists. Run a redeploy return goto( - getUpdateProjectRoute($page, singleProject.orgName, singleProject.name), + getUpdateProjectRoute( + $page, + undefined, + singleProject.orgName, + singleProject.name, + ), ); } else { return goto(getSelectProjectRoute()); diff --git a/web-local/src/routes/(misc)/deploy/project/select/+page.svelte b/web-local/src/routes/(misc)/deploy/project/select/+page.svelte index 2fa7829c1c9..82742003090 100644 --- a/web-local/src/routes/(misc)/deploy/project/select/+page.svelte +++ b/web-local/src/routes/(misc)/deploy/project/select/+page.svelte @@ -15,6 +15,7 @@ $: deployUrl = getUpdateProjectRoute( $page, + undefined, selectedProject?.orgName ?? "", selectedProject?.name ?? "", );