dashboard pass the version number

This commit is contained in:
Nate Kelley 2025-04-08 22:08:10 -06:00
parent f3a8dbd89d
commit a05a81feaf
No known key found for this signature in database
GPG Key ID: FD90372AB8D98B4F
12 changed files with 101 additions and 56 deletions

View File

@ -36,36 +36,41 @@ import { RustApiError } from '../../buster_rest/errors';
export const useGetMetric = <TData = IBusterMetric>(
{
id,
version_number: version_number_prop
versionNumber: versionNumberProp
}: {
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'>
) => {
const queryClient = useQueryClient();
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 setAssetPasswordError = useBusterAssetsContextSelector((x) => x.setAssetPasswordError);
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(() => {
if (version_number_prop === null) return undefined;
return version_number_prop || versionNumber ? parseInt(versionNumber!) : undefined;
}, [version_number_prop, versionNumber]);
const versionNumber = useMemo(() => {
if (versionNumberProp === null) return undefined;
return versionNumberProp || versionNumberFromParams
? parseInt(versionNumberFromParams!)
: undefined;
}, [versionNumberProp, versionNumberFromParams]);
const options = useMemo(() => {
return metricsQueryKeys.metricsGetMetric(id!, version_number);
}, [id, version_number]);
return metricsQueryKeys.metricsGetMetric(id!, versionNumber);
}, [id, versionNumber]);
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 updatedMetric = upgradeMetricToIMetric(result, oldMetric || null);
setOriginalMetric(updatedMetric);
@ -108,32 +113,38 @@ export const useGetMetricsList = (
*/
export const useGetMetricData = ({
id,
version_number: version_number_prop
versionNumber: versionNumberProp
}: {
id: string | undefined;
version_number?: number;
versionNumber?: number;
}) => {
const {
isFetched: isFetchedMetric,
error: errorMetric,
data: fetchedMetricData
} = useGetMetric({ id }, { select: (x) => x.id });
const { versionNumber: versionNumberPathParam } = useParams() as {
const { versionNumber: versionNumberPathParam, metricId: metricIdPathParam } = useParams() as {
versionNumber: string | undefined;
metricId: string | undefined;
};
const versionNumberQueryParam = useSearchParams().get('versionNumber');
const versionNumber = versionNumberQueryParam || versionNumberPathParam;
const versionNumberFromParams = metricIdPathParam
? versionNumberQueryParam || versionNumberPathParam
: undefined;
const version_number = useMemo(() => {
return version_number_prop || versionNumber ? parseInt(versionNumber!) : undefined;
}, [version_number_prop, versionNumber]);
const versionNumber = useMemo(() => {
if (versionNumberProp === null) return undefined;
return versionNumberProp || versionNumberFromParams
? parseInt(versionNumberFromParams!)
: undefined;
}, [versionNumberProp, versionNumberFromParams]);
const queryFn = useMemoizedFn(() => {
return getMetricData({ id: id!, version_number });
return getMetricData({ id: id!, version_number: versionNumber });
});
return useQuery({
...metricsQueryKeys.metricsGetData(id!, version_number),
...metricsQueryKeys.metricsGetData(id!, versionNumber),
queryFn,
enabled: () => {
return !!id && isFetchedMetric && !errorMetric && !!fetchedMetricData;

View File

@ -17,7 +17,7 @@ const dashboardGetList = (
const dashboardGetDashboard = (dashboardId: string, version_number?: number) =>
queryOptions<BusterDashboardResponse>({
queryKey: ['dashboard', 'get', dashboardId, version_number] as const,
queryKey: ['dashboard', 'get', dashboardId, version_number || 'latest'] as const,
staleTime: 10 * 1000
});

View File

@ -1,4 +1,10 @@
export default async function Page({ params }: { params: Promise<{ versionNumber: string }> }) {
const { versionNumber } = await params;
return <div>Version {versionNumber}</div>;
import { DashboardViewDashboardController } from '@/controllers/DashboardController/DashboardViewDashboardController/DashboardViewDashboardController';
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 />;
}

View File

@ -1,9 +1,11 @@
import { MetricViewChart } from '@/controllers/MetricController/MetricViewChart';
export default async function MetricVersionPage({
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} />;
}

View File

@ -1,8 +1,10 @@
import { DashboardViewDashboardController } from '@/controllers/DashboardController/DashboardViewDashboardController';
export default async function DashboardVersionPage({
params
}: {
params: Promise<{ versionNumber: string }>;
params: Promise<{ versionNumber: string; dashboardId: string }>;
}) {
const { versionNumber } = await params;
return <div>DashboardVersionPage {versionNumber}</div>;
const { versionNumber, dashboardId } = await params;
return <DashboardViewDashboardController dashboardId={dashboardId} chatId={undefined} readOnly />;
}

View File

@ -1,8 +1,10 @@
import { MetricViewChart } from '@/controllers/MetricController/MetricViewChart';
export default async function MetricVersionPage({
params
}: {
params: Promise<{ versionNumber: string }>;
params: Promise<{ versionNumber: string; metricId: string }>;
}) {
const { versionNumber } = await params;
return <div>MetricVersionPage {versionNumber}</div>;
const { versionNumber, metricId } = await params;
return <MetricViewChart metricId={metricId} />;
}

View File

@ -137,7 +137,7 @@ export const BusterResizeColumns: React.FC<ContainerProps> = ({
return (
<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
isDraggingIndex={columnMarkerColumnIndex}
itemsLength={items.length}

View File

@ -18,12 +18,12 @@ import {
import { arrayMove } from '@dnd-kit/sortable';
import { BusterSortableOverlay } from './_BusterSortableOverlay';
import { BusterResizeableGridRow } from './interfaces';
import clsx from 'clsx';
import { v4 as uuidv4 } from 'uuid';
import { useMemoizedFn } from '@/hooks';
import isEqual from 'lodash/isEqual';
import { BusterResizeRows } from './BusterResizeRows';
import { NUMBER_OF_COLUMNS, NEW_ROW_ID, MIN_ROW_HEIGHT, TOP_SASH_ID } from './helpers';
import { cn } from '@/lib/utils';
const measuringConfig = {
droppable: {
@ -331,7 +331,7 @@ export const BusterResizeableGrid: React.FC<{
onDragCancel={onDragCancel}
collisionDetection={collisionDetectionStrategy}
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
rows={rows}
className={className}

View File

@ -19,6 +19,7 @@ import type {
} from '@/api/asset_interfaces';
import { DashboardEmptyState } from './DashboardEmptyState';
import { type useUpdateDashboardConfig } from '@/api/buster_rest/dashboards';
import last from 'lodash/last';
const DEFAULT_EMPTY_ROWS: DashboardConfig['rows'] = [];
const DEFAULT_EMPTY_METRICS: Record<string, BusterMetric> = {};
@ -61,6 +62,12 @@ export const DashboardContentController: React.FC<{
return {
...row,
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 {
...item,
children: (
@ -71,6 +78,7 @@ export const DashboardContentController: React.FC<{
readOnly={readOnly}
chatId={chatId}
numberOfMetrics={numberOfMetrics}
versionNumber={versionNumber}
/>
)
};
@ -104,6 +112,8 @@ export const DashboardContentController: React.FC<{
}
}, [dashboard?.id, remapMetrics]);
console.log(hasMetrics, dashboardRows, dashboard);
return (
<div className="dashboard-content-controller">
{hasMetrics && !!dashboardRows.length && !!dashboard ? (
@ -118,11 +128,12 @@ export const DashboardContentController: React.FC<{
draggingId && (
<DashboardMetricItem
metricId={draggingId}
readOnly={false}
readOnly={true}
dashboardId={dashboard.id}
isDragOverlay
numberOfMetrics={numberOfMetrics}
chatId={undefined}
versionNumber={metrics[draggingId]?.version_number}
/>
)
}

View File

@ -9,6 +9,7 @@ import { BusterChart } from '@/components/ui/charts/BusterChart';
const DashboardMetricItemBase: React.FC<{
metricId: string;
versionNumber: number | undefined;
chatId: string | undefined;
dashboardId: string;
numberOfMetrics: number;
@ -18,6 +19,7 @@ const DashboardMetricItemBase: React.FC<{
}> = ({
readOnly,
dashboardId,
versionNumber,
className = '',
metricId,
isDragOverlay = false,
@ -32,7 +34,7 @@ const DashboardMetricItemBase: React.FC<{
initialAnimationEnded,
setInitialAnimationEnded,
isFetchedMetricData
} = useDashboardMetric({ metricId });
} = useDashboardMetric({ metricId, versionNumber });
const loadingMetricData = !!metric && !isFetchedMetricData;
const chartOptions = metric?.chart_config;
@ -69,8 +71,6 @@ const DashboardMetricItemBase: React.FC<{
setInitialAnimationEnded(metricId);
});
if (!chartOptions) return null;
return (
<Card
ref={conatinerRef}
@ -96,7 +96,7 @@ const DashboardMetricItemBase: React.FC<{
isTable ? '' : 'p-3',
isDragOverlay ? 'pointer-events-none' : 'pointer-events-auto'
)}>
{renderChart && (
{renderChart && chartOptions && (
<BusterChart
data={data}
loading={loading}
@ -115,5 +115,9 @@ const DashboardMetricItemBase: React.FC<{
};
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
);
});

View File

@ -3,9 +3,15 @@ import { useEffect, useMemo, useRef } from 'react';
import { useInViewport } from '@/hooks';
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(
{ id: metricId },
{ id: metricId, versionNumber },
{
select: ({
name,
@ -32,7 +38,7 @@ export const useDashboardMetric = ({ metricId }: { metricId: string }) => {
data: metricData,
isFetched: isFetchedMetricData,
dataUpdatedAt: metricDataUpdatedAt
} = useGetMetricData({ id: metricId });
} = useGetMetricData({ id: metricId, versionNumber });
const dashboard = useDashboardContentControllerContextSelector(({ dashboard }) => dashboard);
const metricMetadata = useDashboardContentControllerContextSelector(
({ metricMetadata }) => metricMetadata[metricId]

View File

@ -10,23 +10,24 @@ export const DashboardLayoutContainer: React.FC<{
children: React.ReactNode;
dashboardId: string;
}> = ({ children, dashboardId }) => {
const { data: permission } = useGetDashboard(
{ id: dashboardId },
{ select: (x) => x.permission }
);
const isEditor = canEdit(permission);
return (
<>
{children}
{isEditor && <MemoizedAddToDashboardModal dashboardId={dashboardId} />}
<MemoizedAddToDashboardModal dashboardId={dashboardId} />
</>
);
};
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();
if (!isEditor) return null;
return (
<AddToDashboardModal
open={openAddContentModal}