From b4f7125229a1a580ce281c7c2c8a72b2a8fcd402 Mon Sep 17 00:00:00 2001 From: Dhiraj Kumar Date: Fri, 30 Jan 2026 19:19:46 +0530 Subject: [PATCH 1/5] init canvas public URL --- .../navigation/TopNavigationBar.svelte | 18 +- .../src/features/navigation/nav-utils.ts | 6 +- .../public-urls/CanvasFiltersSection.svelte | 108 +++++++++ .../public-urls/CreatePublicURLForm.svelte | 208 +++++++----------- .../public-urls/ExploreFiltersSection.svelte | 92 ++++++++ .../features/public-urls/canvas-form-utils.ts | 54 +++++ .../[project]/-/share/[token]/+page.ts | 34 ++- .../[token]/canvas/[dashboard]/+page.svelte | 49 +++++ 8 files changed, 432 insertions(+), 137 deletions(-) create mode 100644 web-admin/src/features/public-urls/CanvasFiltersSection.svelte create mode 100644 web-admin/src/features/public-urls/ExploreFiltersSection.svelte create mode 100644 web-admin/src/features/public-urls/canvas-form-utils.ts create mode 100644 web-admin/src/routes/[organization]/[project]/-/share/[token]/canvas/[dashboard]/+page.svelte diff --git a/web-admin/src/features/navigation/TopNavigationBar.svelte b/web-admin/src/features/navigation/TopNavigationBar.svelte index 2ad06decdcc..5f4c926c75e 100644 --- a/web-admin/src/features/navigation/TopNavigationBar.svelte +++ b/web-admin/src/features/navigation/TopNavigationBar.svelte @@ -7,6 +7,7 @@ import Rill from "@rilldata/web-common/components/icons/Rill.svelte"; import Breadcrumbs from "@rilldata/web-common/components/navigation/breadcrumbs/Breadcrumbs.svelte"; import type { PathOption } from "@rilldata/web-common/components/navigation/breadcrumbs/types"; + import { useCanvas } from "@rilldata/web-common/features/canvas/selector"; import ChatToggle from "@rilldata/web-common/features/chat/layouts/sidebar/ChatToggle.svelte"; import GlobalDimensionSearch from "@rilldata/web-common/features/dashboards/dimension-search/GlobalDimensionSearch.svelte"; import StateManagersProvider from "@rilldata/web-common/features/dashboards/state-managers/StateManagersProvider.svelte"; @@ -196,9 +197,18 @@ $: isDashboardValid = !!exploreSpec; $: hasUserAccess = $user.isSuccess && $user.data.user && !onPublicURLPage; - $: publicURLDashboardTitle = - $exploreQuery.data?.explore?.explore?.state?.validSpec?.displayName || - dashboard; + $: canvasQuery = useCanvas(instanceId, dashboard, { + enabled: + !!instanceId && + !!dashboard && + !!onCanvasDashboardPage && + !!onPublicURLPage, + }); + + $: publicURLDashboardTitle = onCanvasDashboardPage + ? $canvasQuery.data?.canvas?.displayName || dashboard + : $exploreQuery.data?.explore?.explore?.state?.validSpec?.displayName || + dashboard; $: currentPath = [organization, project, dashboard, report || alert]; @@ -273,7 +283,7 @@ {#if onCanvasDashboardPage && hasUserAccess} - + {/if} {#if $user.isSuccess} {#if $user.data && $user.data.user} diff --git a/web-admin/src/features/navigation/nav-utils.ts b/web-admin/src/features/navigation/nav-utils.ts index 52f283f4472..42e0db4d0fb 100644 --- a/web-admin/src/features/navigation/nav-utils.ts +++ b/web-admin/src/features/navigation/nav-utils.ts @@ -38,7 +38,11 @@ export function isMetricsExplorerPage(page: Page): boolean { } export function isCanvasDashboardPage(page: Page): boolean { - return page.route.id === "/[organization]/[project]/canvas/[dashboard]"; + return ( + page.route.id === "/[organization]/[project]/canvas/[dashboard]" || + page.route.id === + "/[organization]/[project]/-/share/[token]/canvas/[dashboard]" + ); } /** diff --git a/web-admin/src/features/public-urls/CanvasFiltersSection.svelte b/web-admin/src/features/public-urls/CanvasFiltersSection.svelte new file mode 100644 index 00000000000..1a1b4bf403b --- /dev/null +++ b/web-admin/src/features/public-urls/CanvasFiltersSection.svelte @@ -0,0 +1,108 @@ + + +{#if hasSomeFilter} +
+ +
+

+ The following filters will be locked and hidden: +

+ {#if canvasAppliedFiltersStore} +
+ +
+ {/if} +
+{/if} diff --git a/web-admin/src/features/public-urls/CreatePublicURLForm.svelte b/web-admin/src/features/public-urls/CreatePublicURLForm.svelte index eb3633a9783..ed780e894d8 100644 --- a/web-admin/src/features/public-urls/CreatePublicURLForm.svelte +++ b/web-admin/src/features/public-urls/CreatePublicURLForm.svelte @@ -3,7 +3,9 @@ import { createAdminServiceIssueMagicAuthToken, getAdminServiceListMagicAuthTokensQueryKey, + type AdminServiceIssueMagicAuthTokenBody, } from "@rilldata/web-admin/client"; + import { isCanvasDashboardPage } from "@rilldata/web-admin/features/navigation/nav-utils"; import { Button, IconButton } from "@rilldata/web-common/components/button"; import Calendar from "@rilldata/web-common/components/date-picker/Calendar.svelte"; import Input from "@rilldata/web-common/components/forms/Input.svelte"; @@ -15,69 +17,49 @@ PopoverContent, PopoverTrigger, } from "@rilldata/web-common/components/popover"; - import ExploreFilterChipsReadOnly from "@rilldata/web-common/features/dashboards/filters/ExploreFilterChipsReadOnly.svelte"; - import { mergeDimensionAndMeasureFilters } from "@rilldata/web-common/features/dashboards/filters/measure-filters/measure-filter-utils.ts"; - import { getStateManagers } from "@rilldata/web-common/features/dashboards/state-managers/state-managers"; - import { useTimeControlStore } from "@rilldata/web-common/features/dashboards/time-controls/time-control-store"; - import { ResourceKind } from "@rilldata/web-common/features/entity-management/resource-selectors"; import { copyToClipboard } from "@rilldata/web-common/lib/actions/copy-to-clipboard"; import type { HTTPError } from "@rilldata/web-common/runtime-client/fetchWrapper"; + import { runtime } from "@rilldata/web-common/runtime-client/runtime-store"; import { useQueryClient } from "@tanstack/svelte-query"; import { Pencil } from "lucide-svelte"; import { DateTime } from "luxon"; import { defaults, superForm } from "sveltekit-superforms"; import { yup } from "sveltekit-superforms/adapters"; import { object, string } from "yup"; - import { - convertDateToMinutes, - getExploreFields, - getSanitizedExploreStateParam, - hasDashboardDimensionThresholdFilter, - hasDashboardWhereFilter, - } from "./form-utils"; + import CanvasFiltersSection from "./CanvasFiltersSection.svelte"; + import ExploreFiltersSection from "./ExploreFiltersSection.svelte"; + import { convertDateToMinutes } from "./form-utils"; const queryClient = useQueryClient(); - const StateManagers = getStateManagers(); - - const { - dashboardStore, - metricsViewName, - selectors: { - measures: { visibleMeasures }, - dimensions: { visibleDimensions }, - }, - validSpecStore, - } = StateManagers; $: ({ organization, project, dashboard } = $page.params); - - const timeControlStore = useTimeControlStore(StateManagers); + $: ({ instanceId } = $runtime); + $: isCanvas = isCanvasDashboardPage($page); $: isTitleEmpty = $form.title.trim() === ""; - $: exploreFields = getExploreFields( - $dashboardStore, - $visibleDimensions, - $visibleMeasures, - ); - - $: sanitizedState = getSanitizedExploreStateParam( - $dashboardStore, - exploreFields, - $validSpecStore.data?.explore, - ); - - $: hasWhereFilter = hasDashboardWhereFilter($dashboardStore); - $: hasDimensionThresholdFilter = - hasDashboardDimensionThresholdFilter($dashboardStore); - $: hasSomeFilter = hasWhereFilter || hasDimensionThresholdFilter; - let url: string | null = null; let setExpiration = false; let apiError: string; let popoverOpen = false; let copied = false; + // These will be set by the child components via callbacks + let hasSomeFilter = false; + let dashboardDataProvider: + | (() => Partial) + | null = null; + + function handleFilterStateChange(hasFilters: boolean) { + hasSomeFilter = hasFilters; + } + + function handleProvideFilters( + provider: () => Partial, + ) { + dashboardDataProvider = provider; + } + const formId = "create-public-url-form"; const initialValues = { @@ -101,29 +83,21 @@ const values = form.data; try { - const filter = hasSomeFilter - ? mergeDimensionAndMeasureFilters( - $dashboardStore.whereFilter, - $dashboardStore.dimensionThresholdFilters, - ) - : undefined; - // TODO : add a check upstream to make sure if filter exists, metricsViewName is defined - const metricsViewFilters = filter - ? { [$metricsViewName]: filter } - : undefined; + if (!dashboardDataProvider) { + throw new Error("Dashboard data provider not initialized"); + } + + const dashboardData = dashboardDataProvider(); const { url: _url } = await $issueMagicAuthToken.mutateAsync({ org: organization, project, data: { - resourceType: ResourceKind.Explore as string, + ...dashboardData, resourceName: dashboard, - metricsViewFilters, - fields: exploreFields, ttlMinutes: setExpiration ? convertDateToMinutes(values.expiresAt).toString() : undefined, - state: sanitizedState ? sanitizedState : undefined, displayName: values.title, }, }); @@ -174,53 +148,52 @@ Create a shareable public URL for this view. - {#if !url} -
- -
+
+ +
-
-
- - -
- {#if setExpiration} -
- - - - - - - - - { - $form.expiresAt = date.toISO(); - popoverOpen = false; - }} - /> - - -
- {/if} +
+
+ +
+ {#if setExpiration} +
+ + + + + + + + + { + $form.expiresAt = date.toISO(); + popoverOpen = false; + }} + /> + + +
+ {/if} +
- - + - {#if hasSomeFilter} -
- -
-

- The following filters will be locked and hidden: -

-
- -
-
- -

- Measures and dimensions will be limited to current visible set. -

- {/if} + {#if isCanvas && instanceId} + + {:else} + {/if}