Skip to content
Draft
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: 4 additions & 0 deletions web-common/src/features/canvas/CanvasComponent.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,10 @@
@apply outline-destructive;
}

.component-card:has(.component-access-denied) {
@apply outline-border;
}

.selected {
@apply shadow-md outline-primary-400 outline-[1.5px];

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import ComponentHeader from "@rilldata/web-common/features/canvas/ComponentHeader.svelte";
import { getCanvasStore } from "@rilldata/web-common/features/canvas/state-managers/state-managers";
import { Chart } from "@rilldata/web-common/features/components/charts";
import ComponentAccessDenied from "@rilldata/web-common/features/components/ComponentAccessDenied.svelte";
import ComponentError from "@rilldata/web-common/features/components/ComponentError.svelte";
import Spinner from "@rilldata/web-common/features/entity-management/Spinner.svelte";
import { EntityStatus } from "@rilldata/web-common/features/entity-management/types";
Expand Down Expand Up @@ -37,6 +38,7 @@

$: store = getCanvasStore(canvasName, instanceId);
$: ({
canvasEntity,
canvasEntity: {
metricsView,
metricsView: { getMeasuresForMetricView },
Expand All @@ -54,6 +56,8 @@
dimension_filters,
} = chartSpec);

$: isAccessDenied = canvasEntity.isMetricsViewAccessDenied(metrics_view);

$: schemaStore = validateChartSchema(metricsView, chartSpec);

$: schema = $schemaStore;
Expand Down Expand Up @@ -86,6 +90,8 @@
<div class="flex items-center justify-center h-full w-full">
<Spinner status={EntityStatus.Running} size="20px" />
</div>
{:else if error && $isAccessDenied}
<ComponentAccessDenied />
{:else if error}
<ComponentError error={error.message} />
{:else}
Expand All @@ -107,6 +113,8 @@
theme={currentTheme}
/>
{/if}
{:else if $isAccessDenied}
<ComponentAccessDenied />
{:else}
<ComponentError error={schema.error} />
{/if}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<script lang="ts">
import ComponentAccessDenied from "@rilldata/web-common/features/components/ComponentAccessDenied.svelte";

Check failure on line 2 in web-common/src/features/canvas/components/kpi-grid/KPIGrid.svelte

View workflow job for this annotation

GitHub Actions / build

'ComponentAccessDenied' is defined but never used
import ComponentError from "@rilldata/web-common/features/components/ComponentError.svelte";
import type { KPIGridComponent } from ".";
import ComponentHeader from "../../ComponentHeader.svelte";
Expand Down
42 changes: 25 additions & 17 deletions web-common/src/features/canvas/components/kpi/KPIProvider.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import type { Readable } from "svelte/motion";
import type { KPISpec } from ".";
import { KPI } from ".";
import ComponentAccessDenied from "@rilldata/web-common/features/components/ComponentAccessDenied.svelte";
import { getCanvasStore } from "../../state-managers/state-managers";
import { validateKPISchema } from "./selector";

Expand All @@ -22,9 +23,10 @@
const client = useRuntimeClient();

$: ctx = getCanvasStore(canvasName, client.instanceId);
$: ({ canvasEntity } = ctx);
$: ({
metricsView: { getMeasureForMetricView },
} = ctx.canvasEntity);
} = canvasEntity);

$: ({
metrics_view: metricsViewName,
Expand All @@ -44,6 +46,8 @@
hasTimeSeries,
} = $timeAndFilterStore);

$: isAccessDenied = canvasEntity.isMetricsViewAccessDenied(metricsViewName);

$: schema = validateKPISchema(ctx, spec);
$: ({ isValid } = $schema);

Expand Down Expand Up @@ -152,19 +156,23 @@
);
</script>

<KPI
{measure}
{timeGrain}
{timeZone}
{showTimeComparison}
{hasTimeSeries}
{comparisonLabel}
{interval}
sparkline={spec.sparkline}
{hideTimeRange}
comparisonOptions={spec.comparison}
primaryTotalResult={$totalQuery}
comparisonTotalResult={$comparisonTotalQuery}
primarySparklineResult={$primarySparklineQuery}
comparisonSparklineResult={$comparisonSparklineQuery}
/>
{#if $isAccessDenied}
<ComponentAccessDenied />
{:else}
<KPI
{measure}
{timeGrain}
{timeZone}
{showTimeComparison}
{hasTimeSeries}
{comparisonLabel}
{interval}
sparkline={spec.sparkline}
{hideTimeRange}
comparisonOptions={spec.comparison}
primaryTotalResult={$totalQuery}
comparisonTotalResult={$comparisonTotalQuery}
primarySparklineResult={$primarySparklineQuery}
comparisonSparklineResult={$comparisonSparklineQuery}
/>
{/if}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import type { LeaderboardComponent } from "@rilldata/web-common/features/canvas/components/leaderboard";
import { validateLeaderboardSchema } from "@rilldata/web-common/features/canvas/components/leaderboard/selector";
import { getCanvasStore } from "@rilldata/web-common/features/canvas/state-managers/state-managers";
import ComponentAccessDenied from "@rilldata/web-common/features/components/ComponentAccessDenied.svelte";
import ComponentError from "@rilldata/web-common/features/components/ComponentError.svelte";
import { splitWhereFilter } from "@rilldata/web-common/features/dashboards/filters/measure-filters/measure-filter-utils";
import {
Expand Down Expand Up @@ -45,6 +46,7 @@

$: store = getCanvasStore(canvasName, instanceId);
$: ({
canvasEntity,
canvasEntity: {
metricsView: {
getMetricsViewFromName,
Expand All @@ -65,6 +67,8 @@
numRows = leaderboardProperties.num_rows ?? 7;
}

$: isAccessDenied = canvasEntity.isMetricsViewAccessDenied(metricsViewName);

$: metricsViewQuery = getMetricsViewFromName(metricsViewName);

$: schema = validateLeaderboardSchema(
Expand Down Expand Up @@ -231,6 +235,8 @@
{/each}
</div>
</div>
{:else if $isAccessDenied}
<ComponentAccessDenied />
{:else}
<ComponentError error={schema.error} />
{/if}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
$: ({
parent: {
metricsView: { getMetricsViewFromName },
isMetricsViewAccessDenied,
},
specStore,
config,
Expand All @@ -34,6 +35,8 @@
dimension_filters,
};

$: isAccessDenied = isMetricsViewAccessDenied(tableSpec.metrics_view);

$: _metricViewSpec = getMetricsViewFromName(tableSpec.metrics_view);
$: metricsViewSpec = $_metricViewSpec.metricsView;

Expand Down Expand Up @@ -78,4 +81,5 @@
{pivotDataStore}
pivotConfig={config}
{pivotState}
isAccessDenied={$isAccessDenied}
/>
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<script lang="ts">
import ComponentAccessDenied from "@rilldata/web-common/features/components/ComponentAccessDenied.svelte";
import ComponentError from "@rilldata/web-common/features/components/ComponentError.svelte";
import { splitPivotChips } from "@rilldata/web-common/features/dashboards/pivot/pivot-utils";
import PivotEmpty from "@rilldata/web-common/features/dashboards/pivot/PivotEmpty.svelte";
Expand All @@ -20,6 +21,7 @@
export let pivotConfig: Readable<PivotDataStoreConfig> | undefined;
export let pivotState: Writable<PivotState>;
export let hasHeader = false;
export let isAccessDenied = false;

$: pivotColumns = splitPivotChips($pivotState.columns);

Expand All @@ -33,7 +35,9 @@
class:p-4={hasHeader}
class:pt-1={hasHeader}
>
{#if !schema.isValid}
{#if !schema.isValid && isAccessDenied}
<ComponentAccessDenied />
{:else if !schema.isValid}
<ComponentError error={schema.error} />
{:else if pivotDataStore && $pivotDataStore && pivotConfig && $pivotConfig}
{#if $pivotDataStore?.error?.length}
Expand Down
28 changes: 28 additions & 0 deletions web-common/src/features/canvas/stores/canvas-entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
type V1ComponentSpecRendererProperties,
type V1MetricsView,
type V1MetricsViewSpec,
type V1ResolveCanvasResponseResolvedComponents,
type V1Resource,
type V1ThemeSpec,
} from "@rilldata/web-common/runtime-client";
Expand Down Expand Up @@ -96,6 +97,7 @@ export class CanvasEntity {
filtersEnabledStore = writable<boolean>(true);
_embeddedTheme = writable<V1ThemeSpec | undefined>(undefined);
_metricsViews = writable<Record<string, V1MetricsView | undefined>>({});
_accessDeniedMetricsViews = writable<Set<string>>(new Set());
bannerStore = writable<string | undefined>(undefined);
_maxWidth = writable<number>(DEFAULT_DASHBOARD_WIDTH);
titleStore = writable<string>("");
Expand Down Expand Up @@ -295,6 +297,8 @@ export class CanvasEntity {

if (metricsViews) this._metricsViews.set(metricsViews);

this.computeAccessDeniedMetricsViews(components, metricsViews);

this.checkAndSetFilterEnabled(validSpec);
this.checkAndSetFileArtifact(filePath);
this.checkAndSetDefaultParams(validSpec.defaultPreset ?? {});
Expand Down Expand Up @@ -731,6 +735,30 @@ export class CanvasEntity {
removeComponent = (componentName: string) => {
this.componentsStore.delete(componentName);
};

isMetricsViewAccessDenied = (metricsViewName: string): Readable<boolean> => {
return derived(
this._accessDeniedMetricsViews,
($denied) => $denied.has(metricsViewName),
);
};

private computeAccessDeniedMetricsViews = (
components: V1ResolveCanvasResponseResolvedComponents | undefined,
metricsViews: Record<string, V1MetricsView | undefined> | undefined,
) => {
const accessDenied = new Set<string>();
if (components) {
for (const resource of Object.values(components)) {
const mvName = resource?.component?.state?.validSpec?.rendererProperties
?.metrics_view as string | undefined;
if (mvName && metricsViews && !(mvName in metricsViews)) {
accessDenied.add(mvName);
}
}
}
this._accessDeniedMetricsViews.set(accessDenied);
};
}

export type ComponentPath = [
Expand Down
12 changes: 12 additions & 0 deletions web-common/src/features/components/ComponentAccessDenied.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<script lang="ts">
import { Lock } from "lucide-svelte";
</script>

<div class="component-access-denied flex flex-col gap-y-2 size-full items-center justify-center p-4 text-fg-muted bg-surface-secondary/50">
<div class="p-1.5 bg-surface-secondary rounded-full">
<Lock size="12px" />
</div>
<div class="text-xs font-medium text-center max-w-md">
You don't have access to this component
</div>
</div>
Loading