Skip to content
Merged
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
6 changes: 5 additions & 1 deletion web-admin/src/features/navigation/nav-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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]"
);
}

/**
Expand Down
34 changes: 23 additions & 11 deletions web-admin/src/features/projects/ProjectHeader.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@
import { createAdminServiceGetProjectWithBearerToken } from "@rilldata/web-admin/features/public-urls/get-project-with-bearer-token";
import Breadcrumbs from "@rilldata/web-common/components/navigation/breadcrumbs/Breadcrumbs.svelte";
import type { PathOption } from "@rilldata/web-common/components/navigation/breadcrumbs/types";
import { ResourceKind } from "@rilldata/web-common/features/entity-management/resource-selectors";
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";
import { ResourceKind } from "@rilldata/web-common/features/entity-management/resource-selectors";
import { useExplore } from "@rilldata/web-common/features/explores/selectors";
import { featureFlags } from "@rilldata/web-common/features/feature-flags";
import Header from "@rilldata/web-common/layout/header/Header.svelte";
Expand All @@ -21,10 +22,6 @@
createAdminServiceGetCurrentUser,
createAdminServiceGetDeploymentCredentials,
} from "../../client";
import {
useBreadcrumbOrgPaths,
useBreadcrumbProjectPaths,
} from "../navigation/breadcrumb-selectors";
import ViewAsUserChip from "../../features/view-as-user/ViewAsUserChip.svelte";
import { viewAsUserStore } from "../../features/view-as-user/viewAsUserStore";
import CreateAlert from "../alerts/CreateAlert.svelte";
Expand All @@ -33,14 +30,18 @@
import SignIn from "../authentication/SignIn.svelte";
import LastRefreshedDate from "../dashboards/listing/LastRefreshedDate.svelte";
import { useDashboards } from "../dashboards/listing/selectors";
import PageTitle from "../public-urls/PageTitle.svelte";
import { useReports } from "../scheduled-reports/selectors";
import {
useBreadcrumbOrgPaths,
useBreadcrumbProjectPaths,
} from "../navigation/breadcrumb-selectors";
import {
isCanvasDashboardPage,
isMetricsExplorerPage,
isProjectPage,
isPublicURLPage,
} from "../navigation/nav-utils";
import PageTitle from "../public-urls/PageTitle.svelte";
import { useReports } from "../scheduled-reports/selectors";

export let organization: string;
export let project: string;
Expand Down Expand Up @@ -184,9 +185,18 @@
$: isDashboardValid = !!exploreSpec;
$: hasUserAccess = $user.isSuccess && $user.data.user && !onPublicURLPage;

$: publicURLDashboardTitle =
$exploreQuery.data?.explore?.explore?.state?.validSpec?.displayName ||
dashboard;
$: canvasQuery = useCanvas(runtimeClient, dashboard, {
enabled:
!!runtimeClient.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];
</script>
Expand Down Expand Up @@ -252,7 +262,9 @@
<ChatToggle />
{/if}
<CanvasBookmarks {organization} {project} canvasName={dashboard} />
<ShareDashboardPopover createMagicAuthTokens={false} />
<ShareDashboardPopover
createMagicAuthTokens={effectiveCreateMagicAuthTokens}
/>
{/if}

{#if $user.isSuccess}
Expand Down
98 changes: 98 additions & 0 deletions web-admin/src/features/public-urls/CanvasFiltersSection.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
<script lang="ts">
import type { AdminServiceIssueMagicAuthTokenBody } from "@rilldata/web-admin/client";
import { getCanvasStore } from "@rilldata/web-common/features/canvas/state-managers/state-managers";
import type { UIFilters } from "@rilldata/web-common/features/canvas/stores/filter-manager";
import CanvasFilterChipsReadOnly from "@rilldata/web-common/features/dashboards/filters/CanvasFilterChipsReadOnly.svelte";
import { ResourceKind } from "@rilldata/web-common/features/entity-management/resource-selectors";
import { useRuntimeClient } from "@rilldata/web-common/runtime-client/v2";
import { derived } from "svelte/store";
import {
getCanvasFilters,
getSanitizedCanvasStateUrl,
hasCanvasFilters,
} from "./canvas-form-utils";

const runtimeClient = useRuntimeClient();

export let dashboard: string;
export let onFilterStateChange: (hasFilters: boolean) => void;
export let onProvideFilters: (
provider: () => Partial<AdminServiceIssueMagicAuthTokenBody>,
) => void;

$: canvasStore = getCanvasStore(dashboard, runtimeClient.instanceId);
$: canvasEntity = canvasStore.canvasEntity;
$: canvasFilterManager = canvasEntity.filterManager;
$: canvasActiveUIFiltersStore = canvasFilterManager.activeUIFiltersStore;

// Create a derived store that only includes filters with actual values (not just pinned ones)
$: canvasAppliedFiltersStore = derived(
canvasActiveUIFiltersStore,
($activeFilters) => {
const appliedDimensionFilters = new Map();
const appliedMeasureFilters = new Map();

// Filter dimension filters that have selected values or input text
$activeFilters.dimensionFilters.forEach((filter, key) => {
const hasValues =
(filter.selectedValues && filter.selectedValues.length > 0) ||
(filter.inputText && filter.inputText.trim() !== "");
if (hasValues) {
appliedDimensionFilters.set(key, filter);
}
});

// Filter measure filters that have a filter expression
$activeFilters.measureFilters.forEach((filter, key) => {
if (filter.filter) {
appliedMeasureFilters.set(key, filter);
}
});

return {
dimensionFilters: appliedDimensionFilters,
measureFilters: appliedMeasureFilters,
complexFilters: $activeFilters.complexFilters,
hasFilters:
appliedDimensionFilters.size > 0 ||
appliedMeasureFilters.size > 0 ||
$activeFilters.complexFilters.length > 0,
hasClearableFilters:
appliedDimensionFilters.size > 0 || appliedMeasureFilters.size > 0,
} as UIFilters;
},
);

$: canvasFilters = getCanvasFilters(canvasEntity);
$: canvasStateUrl = getSanitizedCanvasStateUrl(new URL(window.location.href));
$: hasSomeFilter = hasCanvasFilters(canvasEntity);

// Notify parent of filter state changes
$: onFilterStateChange(hasSomeFilter);

// Provide filter data to parent
$: onProvideFilters(() => ({
resourceType: ResourceKind.Canvas as string,
metricsViewFilters: canvasFilters,
fields: undefined, // Grant full access to all fields
state: canvasStateUrl || undefined,
}));
</script>

{#if hasSomeFilter}
<hr class="mt-4 mb-4" />

<div class="flex flex-col gap-y-1">
<p class="text-xs text-fg-primary font-normal">
The following filters will be locked and hidden:
</p>
{#if canvasAppliedFiltersStore}
<div class="flex flex-col gap-2 my-2">
<CanvasFilterChipsReadOnly
uiFilters={$canvasAppliedFiltersStore}
col={false}
/>
</div>
{/if}
</div>
{/if}
Loading
Loading