mirror of https://github.com/buster-so/buster.git
dashboard pass the version number
This commit is contained in:
parent
f3a8dbd89d
commit
a05a81feaf
|
@ -36,36 +36,41 @@ import { RustApiError } from '../../buster_rest/errors';
|
||||||
export const useGetMetric = <TData = IBusterMetric>(
|
export const useGetMetric = <TData = IBusterMetric>(
|
||||||
{
|
{
|
||||||
id,
|
id,
|
||||||
version_number: version_number_prop
|
versionNumber: versionNumberProp
|
||||||
}: {
|
}: {
|
||||||
id: string | undefined;
|
id: string | undefined;
|
||||||
version_number?: number | null; //if null it will not use a params from the query params
|
versionNumber?: number | null; //if null it will not use a params from the query params
|
||||||
},
|
},
|
||||||
params?: Omit<UseQueryOptions<IBusterMetric, RustApiError, TData>, 'queryKey' | 'queryFn'>
|
params?: Omit<UseQueryOptions<IBusterMetric, RustApiError, TData>, 'queryKey' | 'queryFn'>
|
||||||
) => {
|
) => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
const setOriginalMetric = useOriginalMetricStore((x) => x.setOriginalMetric);
|
const setOriginalMetric = useOriginalMetricStore((x) => x.setOriginalMetric);
|
||||||
const { versionNumber: versionNumberPathParam } = useParams() as {
|
|
||||||
versionNumber: string | undefined;
|
|
||||||
};
|
|
||||||
const versionNumberQueryParam = useSearchParams().get('versionNumber');
|
|
||||||
const versionNumber = versionNumberQueryParam || versionNumberPathParam;
|
|
||||||
const getAssetPassword = useBusterAssetsContextSelector((x) => x.getAssetPassword);
|
const getAssetPassword = useBusterAssetsContextSelector((x) => x.getAssetPassword);
|
||||||
const setAssetPasswordError = useBusterAssetsContextSelector((x) => x.setAssetPasswordError);
|
const setAssetPasswordError = useBusterAssetsContextSelector((x) => x.setAssetPasswordError);
|
||||||
const { password } = getAssetPassword(id!);
|
const { password } = getAssetPassword(id!);
|
||||||
|
|
||||||
const queryClient = useQueryClient();
|
const { versionNumber: versionNumberPathParam, metricId: metricIdPathParam } = useParams() as {
|
||||||
|
versionNumber: string | undefined;
|
||||||
|
metricId: string | undefined;
|
||||||
|
};
|
||||||
|
const versionNumberQueryParam = useSearchParams().get('versionNumber');
|
||||||
|
const versionNumberFromParams = metricIdPathParam
|
||||||
|
? versionNumberQueryParam || versionNumberPathParam
|
||||||
|
: undefined;
|
||||||
|
|
||||||
const version_number = useMemo(() => {
|
const versionNumber = useMemo(() => {
|
||||||
if (version_number_prop === null) return undefined;
|
if (versionNumberProp === null) return undefined;
|
||||||
return version_number_prop || versionNumber ? parseInt(versionNumber!) : undefined;
|
return versionNumberProp || versionNumberFromParams
|
||||||
}, [version_number_prop, versionNumber]);
|
? parseInt(versionNumberFromParams!)
|
||||||
|
: undefined;
|
||||||
|
}, [versionNumberProp, versionNumberFromParams]);
|
||||||
|
|
||||||
const options = useMemo(() => {
|
const options = useMemo(() => {
|
||||||
return metricsQueryKeys.metricsGetMetric(id!, version_number);
|
return metricsQueryKeys.metricsGetMetric(id!, versionNumber);
|
||||||
}, [id, version_number]);
|
}, [id, versionNumber]);
|
||||||
|
|
||||||
const queryFn = useMemoizedFn(async () => {
|
const queryFn = useMemoizedFn(async () => {
|
||||||
const result = await getMetric({ id: id!, password, version_number });
|
const result = await getMetric({ id: id!, password, version_number: versionNumber });
|
||||||
const oldMetric = queryClient.getQueryData(options.queryKey);
|
const oldMetric = queryClient.getQueryData(options.queryKey);
|
||||||
const updatedMetric = upgradeMetricToIMetric(result, oldMetric || null);
|
const updatedMetric = upgradeMetricToIMetric(result, oldMetric || null);
|
||||||
setOriginalMetric(updatedMetric);
|
setOriginalMetric(updatedMetric);
|
||||||
|
@ -108,32 +113,38 @@ export const useGetMetricsList = (
|
||||||
*/
|
*/
|
||||||
export const useGetMetricData = ({
|
export const useGetMetricData = ({
|
||||||
id,
|
id,
|
||||||
version_number: version_number_prop
|
versionNumber: versionNumberProp
|
||||||
}: {
|
}: {
|
||||||
id: string | undefined;
|
id: string | undefined;
|
||||||
version_number?: number;
|
versionNumber?: number;
|
||||||
}) => {
|
}) => {
|
||||||
const {
|
const {
|
||||||
isFetched: isFetchedMetric,
|
isFetched: isFetchedMetric,
|
||||||
error: errorMetric,
|
error: errorMetric,
|
||||||
data: fetchedMetricData
|
data: fetchedMetricData
|
||||||
} = useGetMetric({ id }, { select: (x) => x.id });
|
} = useGetMetric({ id }, { select: (x) => x.id });
|
||||||
const { versionNumber: versionNumberPathParam } = useParams() as {
|
const { versionNumber: versionNumberPathParam, metricId: metricIdPathParam } = useParams() as {
|
||||||
versionNumber: string | undefined;
|
versionNumber: string | undefined;
|
||||||
|
metricId: string | undefined;
|
||||||
};
|
};
|
||||||
const versionNumberQueryParam = useSearchParams().get('versionNumber');
|
const versionNumberQueryParam = useSearchParams().get('versionNumber');
|
||||||
const versionNumber = versionNumberQueryParam || versionNumberPathParam;
|
const versionNumberFromParams = metricIdPathParam
|
||||||
|
? versionNumberQueryParam || versionNumberPathParam
|
||||||
|
: undefined;
|
||||||
|
|
||||||
const version_number = useMemo(() => {
|
const versionNumber = useMemo(() => {
|
||||||
return version_number_prop || versionNumber ? parseInt(versionNumber!) : undefined;
|
if (versionNumberProp === null) return undefined;
|
||||||
}, [version_number_prop, versionNumber]);
|
return versionNumberProp || versionNumberFromParams
|
||||||
|
? parseInt(versionNumberFromParams!)
|
||||||
|
: undefined;
|
||||||
|
}, [versionNumberProp, versionNumberFromParams]);
|
||||||
|
|
||||||
const queryFn = useMemoizedFn(() => {
|
const queryFn = useMemoizedFn(() => {
|
||||||
return getMetricData({ id: id!, version_number });
|
return getMetricData({ id: id!, version_number: versionNumber });
|
||||||
});
|
});
|
||||||
|
|
||||||
return useQuery({
|
return useQuery({
|
||||||
...metricsQueryKeys.metricsGetData(id!, version_number),
|
...metricsQueryKeys.metricsGetData(id!, versionNumber),
|
||||||
queryFn,
|
queryFn,
|
||||||
enabled: () => {
|
enabled: () => {
|
||||||
return !!id && isFetchedMetric && !errorMetric && !!fetchedMetricData;
|
return !!id && isFetchedMetric && !errorMetric && !!fetchedMetricData;
|
||||||
|
|
|
@ -17,7 +17,7 @@ const dashboardGetList = (
|
||||||
|
|
||||||
const dashboardGetDashboard = (dashboardId: string, version_number?: number) =>
|
const dashboardGetDashboard = (dashboardId: string, version_number?: number) =>
|
||||||
queryOptions<BusterDashboardResponse>({
|
queryOptions<BusterDashboardResponse>({
|
||||||
queryKey: ['dashboard', 'get', dashboardId, version_number] as const,
|
queryKey: ['dashboard', 'get', dashboardId, version_number || 'latest'] as const,
|
||||||
staleTime: 10 * 1000
|
staleTime: 10 * 1000
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,10 @@
|
||||||
export default async function Page({ params }: { params: Promise<{ versionNumber: string }> }) {
|
import { DashboardViewDashboardController } from '@/controllers/DashboardController/DashboardViewDashboardController/DashboardViewDashboardController';
|
||||||
const { versionNumber } = await params;
|
|
||||||
return <div>Version {versionNumber}</div>;
|
export default async function Page({
|
||||||
|
params
|
||||||
|
}: {
|
||||||
|
params: Promise<{ versionNumber: string; dashboardId: string; chatId: string }>;
|
||||||
|
}) {
|
||||||
|
const { versionNumber, dashboardId, chatId } = await params;
|
||||||
|
return <DashboardViewDashboardController dashboardId={dashboardId} chatId={chatId} readOnly />;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
|
import { MetricViewChart } from '@/controllers/MetricController/MetricViewChart';
|
||||||
|
|
||||||
export default async function MetricVersionPage({
|
export default async function MetricVersionPage({
|
||||||
params
|
params
|
||||||
}: {
|
}: {
|
||||||
params: Promise<{ versionNumber: string }>;
|
params: Promise<{ versionNumber: string; metricId: string }>;
|
||||||
}) {
|
}) {
|
||||||
const { versionNumber } = await params;
|
const { versionNumber, metricId } = await params;
|
||||||
|
|
||||||
return <div>MetricVersionPage {versionNumber}</div>;
|
return <MetricViewChart metricId={metricId} />;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
|
import { DashboardViewDashboardController } from '@/controllers/DashboardController/DashboardViewDashboardController';
|
||||||
|
|
||||||
export default async function DashboardVersionPage({
|
export default async function DashboardVersionPage({
|
||||||
params
|
params
|
||||||
}: {
|
}: {
|
||||||
params: Promise<{ versionNumber: string }>;
|
params: Promise<{ versionNumber: string; dashboardId: string }>;
|
||||||
}) {
|
}) {
|
||||||
const { versionNumber } = await params;
|
const { versionNumber, dashboardId } = await params;
|
||||||
return <div>DashboardVersionPage {versionNumber}</div>;
|
return <DashboardViewDashboardController dashboardId={dashboardId} chatId={undefined} readOnly />;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
|
import { MetricViewChart } from '@/controllers/MetricController/MetricViewChart';
|
||||||
|
|
||||||
export default async function MetricVersionPage({
|
export default async function MetricVersionPage({
|
||||||
params
|
params
|
||||||
}: {
|
}: {
|
||||||
params: Promise<{ versionNumber: string }>;
|
params: Promise<{ versionNumber: string; metricId: string }>;
|
||||||
}) {
|
}) {
|
||||||
const { versionNumber } = await params;
|
const { versionNumber, metricId } = await params;
|
||||||
return <div>MetricVersionPage {versionNumber}</div>;
|
return <MetricViewChart metricId={metricId} />;
|
||||||
}
|
}
|
||||||
|
|
|
@ -137,7 +137,7 @@ export const BusterResizeColumns: React.FC<ContainerProps> = ({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SortableContext id={rowId} items={items} disabled={false}>
|
<SortableContext id={rowId} items={items} disabled={false}>
|
||||||
<div ref={setNodeRef} className="relative h-full w-full">
|
<div ref={setNodeRef} className="buster-resize-columns relative h-full w-full">
|
||||||
<BusterDragColumnMarkers
|
<BusterDragColumnMarkers
|
||||||
isDraggingIndex={columnMarkerColumnIndex}
|
isDraggingIndex={columnMarkerColumnIndex}
|
||||||
itemsLength={items.length}
|
itemsLength={items.length}
|
||||||
|
|
|
@ -18,12 +18,12 @@ import {
|
||||||
import { arrayMove } from '@dnd-kit/sortable';
|
import { arrayMove } from '@dnd-kit/sortable';
|
||||||
import { BusterSortableOverlay } from './_BusterSortableOverlay';
|
import { BusterSortableOverlay } from './_BusterSortableOverlay';
|
||||||
import { BusterResizeableGridRow } from './interfaces';
|
import { BusterResizeableGridRow } from './interfaces';
|
||||||
import clsx from 'clsx';
|
|
||||||
import { v4 as uuidv4 } from 'uuid';
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
import { useMemoizedFn } from '@/hooks';
|
import { useMemoizedFn } from '@/hooks';
|
||||||
import isEqual from 'lodash/isEqual';
|
import isEqual from 'lodash/isEqual';
|
||||||
import { BusterResizeRows } from './BusterResizeRows';
|
import { BusterResizeRows } from './BusterResizeRows';
|
||||||
import { NUMBER_OF_COLUMNS, NEW_ROW_ID, MIN_ROW_HEIGHT, TOP_SASH_ID } from './helpers';
|
import { NUMBER_OF_COLUMNS, NEW_ROW_ID, MIN_ROW_HEIGHT, TOP_SASH_ID } from './helpers';
|
||||||
|
import { cn } from '@/lib/utils';
|
||||||
|
|
||||||
const measuringConfig = {
|
const measuringConfig = {
|
||||||
droppable: {
|
droppable: {
|
||||||
|
@ -331,7 +331,7 @@ export const BusterResizeableGrid: React.FC<{
|
||||||
onDragCancel={onDragCancel}
|
onDragCancel={onDragCancel}
|
||||||
collisionDetection={collisionDetectionStrategy}
|
collisionDetection={collisionDetectionStrategy}
|
||||||
sensors={sensors}>
|
sensors={sensors}>
|
||||||
<div className={clsx('h-full w-full', 'buster-resizeable-grid', className)}>
|
<div className={cn('buster-resizeable-grid h-full w-full', className)}>
|
||||||
<BusterResizeRows
|
<BusterResizeRows
|
||||||
rows={rows}
|
rows={rows}
|
||||||
className={className}
|
className={className}
|
||||||
|
|
|
@ -19,6 +19,7 @@ import type {
|
||||||
} from '@/api/asset_interfaces';
|
} from '@/api/asset_interfaces';
|
||||||
import { DashboardEmptyState } from './DashboardEmptyState';
|
import { DashboardEmptyState } from './DashboardEmptyState';
|
||||||
import { type useUpdateDashboardConfig } from '@/api/buster_rest/dashboards';
|
import { type useUpdateDashboardConfig } from '@/api/buster_rest/dashboards';
|
||||||
|
import last from 'lodash/last';
|
||||||
|
|
||||||
const DEFAULT_EMPTY_ROWS: DashboardConfig['rows'] = [];
|
const DEFAULT_EMPTY_ROWS: DashboardConfig['rows'] = [];
|
||||||
const DEFAULT_EMPTY_METRICS: Record<string, BusterMetric> = {};
|
const DEFAULT_EMPTY_METRICS: Record<string, BusterMetric> = {};
|
||||||
|
@ -61,6 +62,12 @@ export const DashboardContentController: React.FC<{
|
||||||
return {
|
return {
|
||||||
...row,
|
...row,
|
||||||
items: row.items.map((item) => {
|
items: row.items.map((item) => {
|
||||||
|
const selectedMetric = metrics[item.id];
|
||||||
|
const versionNumber =
|
||||||
|
last(selectedMetric.versions)?.version_number === selectedMetric.version_number
|
||||||
|
? undefined
|
||||||
|
: selectedMetric.version_number;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
children: (
|
children: (
|
||||||
|
@ -71,6 +78,7 @@ export const DashboardContentController: React.FC<{
|
||||||
readOnly={readOnly}
|
readOnly={readOnly}
|
||||||
chatId={chatId}
|
chatId={chatId}
|
||||||
numberOfMetrics={numberOfMetrics}
|
numberOfMetrics={numberOfMetrics}
|
||||||
|
versionNumber={versionNumber}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
@ -104,6 +112,8 @@ export const DashboardContentController: React.FC<{
|
||||||
}
|
}
|
||||||
}, [dashboard?.id, remapMetrics]);
|
}, [dashboard?.id, remapMetrics]);
|
||||||
|
|
||||||
|
console.log(hasMetrics, dashboardRows, dashboard);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="dashboard-content-controller">
|
<div className="dashboard-content-controller">
|
||||||
{hasMetrics && !!dashboardRows.length && !!dashboard ? (
|
{hasMetrics && !!dashboardRows.length && !!dashboard ? (
|
||||||
|
@ -118,11 +128,12 @@ export const DashboardContentController: React.FC<{
|
||||||
draggingId && (
|
draggingId && (
|
||||||
<DashboardMetricItem
|
<DashboardMetricItem
|
||||||
metricId={draggingId}
|
metricId={draggingId}
|
||||||
readOnly={false}
|
readOnly={true}
|
||||||
dashboardId={dashboard.id}
|
dashboardId={dashboard.id}
|
||||||
isDragOverlay
|
isDragOverlay
|
||||||
numberOfMetrics={numberOfMetrics}
|
numberOfMetrics={numberOfMetrics}
|
||||||
chatId={undefined}
|
chatId={undefined}
|
||||||
|
versionNumber={metrics[draggingId]?.version_number}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import { BusterChart } from '@/components/ui/charts/BusterChart';
|
||||||
|
|
||||||
const DashboardMetricItemBase: React.FC<{
|
const DashboardMetricItemBase: React.FC<{
|
||||||
metricId: string;
|
metricId: string;
|
||||||
|
versionNumber: number | undefined;
|
||||||
chatId: string | undefined;
|
chatId: string | undefined;
|
||||||
dashboardId: string;
|
dashboardId: string;
|
||||||
numberOfMetrics: number;
|
numberOfMetrics: number;
|
||||||
|
@ -18,6 +19,7 @@ const DashboardMetricItemBase: React.FC<{
|
||||||
}> = ({
|
}> = ({
|
||||||
readOnly,
|
readOnly,
|
||||||
dashboardId,
|
dashboardId,
|
||||||
|
versionNumber,
|
||||||
className = '',
|
className = '',
|
||||||
metricId,
|
metricId,
|
||||||
isDragOverlay = false,
|
isDragOverlay = false,
|
||||||
|
@ -32,7 +34,7 @@ const DashboardMetricItemBase: React.FC<{
|
||||||
initialAnimationEnded,
|
initialAnimationEnded,
|
||||||
setInitialAnimationEnded,
|
setInitialAnimationEnded,
|
||||||
isFetchedMetricData
|
isFetchedMetricData
|
||||||
} = useDashboardMetric({ metricId });
|
} = useDashboardMetric({ metricId, versionNumber });
|
||||||
|
|
||||||
const loadingMetricData = !!metric && !isFetchedMetricData;
|
const loadingMetricData = !!metric && !isFetchedMetricData;
|
||||||
const chartOptions = metric?.chart_config;
|
const chartOptions = metric?.chart_config;
|
||||||
|
@ -69,8 +71,6 @@ const DashboardMetricItemBase: React.FC<{
|
||||||
setInitialAnimationEnded(metricId);
|
setInitialAnimationEnded(metricId);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!chartOptions) return null;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
ref={conatinerRef}
|
ref={conatinerRef}
|
||||||
|
@ -96,7 +96,7 @@ const DashboardMetricItemBase: React.FC<{
|
||||||
isTable ? '' : 'p-3',
|
isTable ? '' : 'p-3',
|
||||||
isDragOverlay ? 'pointer-events-none' : 'pointer-events-auto'
|
isDragOverlay ? 'pointer-events-none' : 'pointer-events-auto'
|
||||||
)}>
|
)}>
|
||||||
{renderChart && (
|
{renderChart && chartOptions && (
|
||||||
<BusterChart
|
<BusterChart
|
||||||
data={data}
|
data={data}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
|
@ -115,5 +115,9 @@ const DashboardMetricItemBase: React.FC<{
|
||||||
};
|
};
|
||||||
|
|
||||||
export const DashboardMetricItem = React.memo(DashboardMetricItemBase, (prev, next) => {
|
export const DashboardMetricItem = React.memo(DashboardMetricItemBase, (prev, next) => {
|
||||||
return prev.metricId === next.metricId && prev.dashboardId === next.dashboardId;
|
return (
|
||||||
|
prev.metricId === next.metricId &&
|
||||||
|
prev.dashboardId === next.dashboardId &&
|
||||||
|
prev.versionNumber === next.versionNumber
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
|
@ -3,9 +3,15 @@ import { useEffect, useMemo, useRef } from 'react';
|
||||||
import { useInViewport } from '@/hooks';
|
import { useInViewport } from '@/hooks';
|
||||||
import { useGetMetric, useGetMetricData } from '@/api/buster_rest/metrics';
|
import { useGetMetric, useGetMetricData } from '@/api/buster_rest/metrics';
|
||||||
|
|
||||||
export const useDashboardMetric = ({ metricId }: { metricId: string }) => {
|
export const useDashboardMetric = ({
|
||||||
|
metricId,
|
||||||
|
versionNumber
|
||||||
|
}: {
|
||||||
|
metricId: string;
|
||||||
|
versionNumber: number | undefined;
|
||||||
|
}) => {
|
||||||
const { data: metric, isFetched: isMetricFetched } = useGetMetric(
|
const { data: metric, isFetched: isMetricFetched } = useGetMetric(
|
||||||
{ id: metricId },
|
{ id: metricId, versionNumber },
|
||||||
{
|
{
|
||||||
select: ({
|
select: ({
|
||||||
name,
|
name,
|
||||||
|
@ -32,7 +38,7 @@ export const useDashboardMetric = ({ metricId }: { metricId: string }) => {
|
||||||
data: metricData,
|
data: metricData,
|
||||||
isFetched: isFetchedMetricData,
|
isFetched: isFetchedMetricData,
|
||||||
dataUpdatedAt: metricDataUpdatedAt
|
dataUpdatedAt: metricDataUpdatedAt
|
||||||
} = useGetMetricData({ id: metricId });
|
} = useGetMetricData({ id: metricId, versionNumber });
|
||||||
const dashboard = useDashboardContentControllerContextSelector(({ dashboard }) => dashboard);
|
const dashboard = useDashboardContentControllerContextSelector(({ dashboard }) => dashboard);
|
||||||
const metricMetadata = useDashboardContentControllerContextSelector(
|
const metricMetadata = useDashboardContentControllerContextSelector(
|
||||||
({ metricMetadata }) => metricMetadata[metricId]
|
({ metricMetadata }) => metricMetadata[metricId]
|
||||||
|
|
|
@ -10,23 +10,24 @@ export const DashboardLayoutContainer: React.FC<{
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
dashboardId: string;
|
dashboardId: string;
|
||||||
}> = ({ children, dashboardId }) => {
|
}> = ({ children, dashboardId }) => {
|
||||||
const { data: permission } = useGetDashboard(
|
|
||||||
{ id: dashboardId },
|
|
||||||
{ select: (x) => x.permission }
|
|
||||||
);
|
|
||||||
const isEditor = canEdit(permission);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{children}
|
{children}
|
||||||
{isEditor && <MemoizedAddToDashboardModal dashboardId={dashboardId} />}
|
<MemoizedAddToDashboardModal dashboardId={dashboardId} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const MemoizedAddToDashboardModal = React.memo(({ dashboardId }: { dashboardId: string }) => {
|
const MemoizedAddToDashboardModal = React.memo(({ dashboardId }: { dashboardId: string }) => {
|
||||||
|
const { data: permission } = useGetDashboard(
|
||||||
|
{ id: dashboardId },
|
||||||
|
{ select: (x) => x.permission }
|
||||||
|
);
|
||||||
|
const isEditor = canEdit(permission);
|
||||||
const { openAddContentModal, onCloseAddContentModal } = useDashboardContentStore();
|
const { openAddContentModal, onCloseAddContentModal } = useDashboardContentStore();
|
||||||
|
|
||||||
|
if (!isEditor) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AddToDashboardModal
|
<AddToDashboardModal
|
||||||
open={openAddContentModal}
|
open={openAddContentModal}
|
||||||
|
|
Loading…
Reference in New Issue