Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions web-admin/src/features/alerts/selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 { smartRefetchIntervalFunc } from "@rilldata/web-admin/lib/refetch-interval-store";
import { derived, type Readable, readable } from "svelte/store";

export function useAlerts(instanceId: string, enabled = true) {
Expand All @@ -22,7 +22,7 @@ export function useAlerts(instanceId: string, enabled = true) {
query: {
enabled: enabled && !!instanceId,
refetchOnMount: true,
refetchInterval: createSmartRefetchInterval,
refetchInterval: smartRefetchIntervalFunc,
},
},
);
Expand Down
93 changes: 43 additions & 50 deletions web-admin/src/features/dashboards/listing/deploying-dashboards.ts
Original file line number Diff line number Diff line change
@@ -1,89 +1,86 @@
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,
V1ReconcileStatus,
type V1Resource,
} from "@rilldata/web-common/runtime-client";
import type { CreateQueryResult } from "@tanstack/svelte-query";
import {
isResourceReconciling,
smartRefetchIntervalFunc,
} 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) {
const dashboard = dashboards.find(
(res) => res.meta?.name?.name === deployingDashboard,
);

// Redirect to home page if no specific dashboard was deployed
if (!deployingDashboard || !dashboard?.meta?.name) {
return {
redirectToDashboardPath: null,
dashboardsReconciling: getDashboardsReconciling(
dashboards,
deployingDashboard,
),
dashboardsErrored: getDashboardsErrored(
dashboards,
deployingDashboard,
),
redirectPath: `/${orgName}/${projName}`,
dashboardsErrored: false,
};
}

const resourceRoute =
dashboard.meta?.name?.kind === ResourceKind.Explore
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,
};
},
refetchInterval: smartRefetchIntervalFunc,
},
});
}

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,
Expand Down Expand Up @@ -116,10 +113,6 @@ function isDashboard(res: V1Resource) {
return res.canvas || res.explore;
}

function isValidDashboard(res: V1Resource) {
return Boolean(res.canvas?.state?.validSpec || res.explore?.state?.validSpec);
}

function hasErrored(res: V1Resource) {
return (
res.meta?.reconcileStatus === V1ReconcileStatus.RECONCILE_STATUS_IDLE &&
Expand Down
4 changes: 2 additions & 2 deletions web-admin/src/features/dashboards/listing/selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 { smartRefetchIntervalFunc } from "@rilldata/web-admin/lib/refetch-interval-store";

export function useDashboardsLastUpdated(
instanceId: string,
Expand Down Expand Up @@ -42,7 +42,7 @@ export function useDashboards(
select: (data) => {
return data.resources.filter((res) => res.canvas || res.explore);
},
refetchInterval: createSmartRefetchInterval,
refetchInterval: smartRefetchIntervalFunc,
},
});
}
4 changes: 2 additions & 2 deletions web-admin/src/features/projects/status/selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 { smartRefetchIntervalFunc } from "@rilldata/web-admin/lib/refetch-interval-store";

export function useProjectDeployment(orgName: string, projName: string) {
return createAdminServiceGetProject<V1Deployment | undefined>(
Expand Down Expand Up @@ -42,7 +42,7 @@ export function useResources(instanceId: string) {
resources: filtered,
};
},
refetchInterval: createSmartRefetchInterval,
refetchInterval: smartRefetchIntervalFunc,
},
},
);
Expand Down
4 changes: 2 additions & 2 deletions web-admin/src/features/scheduled-reports/selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
createRuntimeServiceGetResource,
createRuntimeServiceListResources,
} from "@rilldata/web-common/runtime-client";
import { createSmartRefetchInterval } from "@rilldata/web-admin/lib/refetch-interval-store";
import { smartRefetchIntervalFunc } from "@rilldata/web-admin/lib/refetch-interval-store";

export function useReports(instanceId: string, enabled = true) {
return createRuntimeServiceListResources(
Expand All @@ -17,7 +17,7 @@ export function useReports(instanceId: string, enabled = true) {
query: {
enabled: enabled && !!instanceId,
refetchOnMount: true,
refetchInterval: createSmartRefetchInterval,
refetchInterval: smartRefetchIntervalFunc,
},
},
);
Expand Down
4 changes: 2 additions & 2 deletions web-admin/src/lib/refetch-interval-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,13 @@ const queryRefetchStateMap = new WeakMap<
>();

/**
* Creates a smart refetch interval function that uses a WeakMap to store state.
* A smart refetch interval function that uses a WeakMap to store state.
* This approach keeps refetch state per query without mutating the query object.
*
* @param query The TanStack query object
* @returns The refetch interval (number in ms or false to disable)
*/
export function createSmartRefetchInterval(
export function smartRefetchIntervalFunc(
query: Query<
V1ListResourcesResponse,
HTTPError,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,61 +1,19 @@
<script lang="ts">
import { goto } from "$app/navigation";
import { navigating, page } from "$app/stores";
import { page } from "$app/stores";
import ContentContainer from "@rilldata/web-admin/components/layout/ContentContainer.svelte";
import DashboardBuilding from "@rilldata/web-common/features/dashboards/DashboardBuilding.svelte";
import DashboardErrored from "@rilldata/web-admin/features/dashboards/DashboardErrored.svelte";
import DashboardsTable from "@rilldata/web-admin/features/dashboards/listing/DashboardsTable.svelte";
import { useDeployingDashboards } from "@rilldata/web-admin/features/dashboards/listing/deploying-dashboards.ts";
import { runtime } from "@rilldata/web-common/runtime-client/runtime-store";
import type { PageData } from "./$types";

export let data: PageData;
const { deploying, deployingDashboard } = data;

$: ({
params: { organization, project },
params: { project },
} = $page);
$: ({ instanceId } = $runtime);

$: deployingDashboards = useDeployingDashboards(
instanceId,
organization,
project,
deploying,
deployingDashboard,
);
$: ({ isPending, data: deployingDashboardsData } = $deployingDashboards);
$: ({ redirectToDashboardPath, dashboardsReconciling, dashboardsErrored } =
deployingDashboardsData ?? {
redirectToDashboardPath: null,
dashboardsReconciling: false,
dashboardsErrored: false,
});

$: if (redirectToDashboardPath) {
void goto(redirectToDashboardPath);
}
// Continue showing a spinner when redirecting to target dashboard after deploy.
// This prevents a flash just after dashboard has loaded and before the dashboard components get mounted.
$: redirecting = $navigating?.to?.url.pathname === redirectToDashboardPath;

$: showSpinner =
dashboardsReconciling || (deploying && isPending) || redirecting;
$: showError = dashboardsErrored && !redirecting;
</script>

<svelte:head>
<title>{project} overview - Rill</title>
</svelte:head>

{#if showError}
<DashboardErrored {organization} {project} />
{:else if showSpinner}
<DashboardBuilding multipleDashboards />
{:else}
<ContentContainer maxWidth={800} title="Project dashboards">
<div class="flex flex-col items-center gap-y-4">
<DashboardsTable />
</div>
</ContentContainer>
{/if}
<ContentContainer maxWidth={800} title="Project dashboards">
<div class="flex flex-col items-center gap-y-4">
<DashboardsTable />
</div>
</ContentContainer>
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<script lang="ts">
import { goto } from "$app/navigation";
import DashboardBuilding from "@rilldata/web-common/features/dashboards/DashboardBuilding.svelte";
import { useDeployingDashboards } from "@rilldata/web-admin/features/dashboards/listing/deploying-dashboards.ts";
import { eventBus } from "@rilldata/web-common/lib/event-bus/event-bus.ts";
import type { PageData } from "./$types";

export let data: PageData;
const { organization, project, runtime, deployingDashboard } = data;

const deployingDashboardResp = useDeployingDashboards(
runtime.instanceId,
organization,
project.name,
deployingDashboard,
);

$: ({ data: deployingDashboardsData } = $deployingDashboardResp);
$: ({ redirectPath, dashboardsErrored } = deployingDashboardsData ?? {
redirectPath: null,
dashboardsErrored: false,
});

$: if (redirectPath) {
if (dashboardsErrored) {
eventBus.emit("notification", {
type: "error",
message: "Failed to deploy dashboards",
});
}
void goto(redirectPath);
}
</script>

<DashboardBuilding multipleDashboards />
Original file line number Diff line number Diff line change
@@ -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,
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@

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`;
console.log("Redirecting to deploy landing page: ", u.toString());
return u.toString();
}
</script>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
11 changes: 10 additions & 1 deletion web-common/src/features/entity-management/file-artifacts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<string>());
Expand Down Expand Up @@ -171,6 +172,14 @@ export class FileArtifacts {
}
return null;
}

public createCurrentResourceStore(): Readable<V1ResourceName | undefined> {
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();
Loading
Loading