read only prop passdown for version history

This commit is contained in:
Nate Kelley 2025-09-01 16:46:28 -06:00
parent 24d49e54b4
commit 2320aa6f0f
No known key found for this signature in database
GPG Key ID: FD90372AB8D98B4F
8 changed files with 55 additions and 19 deletions

View File

@ -14,10 +14,20 @@ interface DashboardMetricItemBaseProps {
numberOfMetrics: number;
className?: string;
isDragOverlay?: boolean;
animate?: boolean;
readOnly?: boolean;
}
export const DashboardMetricItem: React.FC<DashboardMetricItemBaseProps> = React.memo(
({ dashboardId, metricVersionNumber, metricId, isDragOverlay = false, numberOfMetrics }) => {
({
dashboardId,
animate: animateProp = true,
metricVersionNumber,
metricId,
isDragOverlay = false,
numberOfMetrics,
readOnly = false,
}) => {
const containerRef = useRef<HTMLDivElement>(null);
const hasBeenInViewport = useHasBeenInViewport(containerRef, {
threshold: 0.25,
@ -26,7 +36,7 @@ export const DashboardMetricItem: React.FC<DashboardMetricItemBaseProps> = React
{ id: metricId, versionNumber: metricVersionNumber },
{ select: useCallback((data: BusterMetricData) => data.data?.length || 0, []) }
);
const animate = !isDragOverlay && dataLength < 125 && numberOfMetrics <= 30;
const animate = !isDragOverlay && dataLength < 125 && numberOfMetrics <= 30 && animateProp;
const { attributes, listeners } = useContext(SortableItemContext);
@ -39,10 +49,11 @@ export const DashboardMetricItem: React.FC<DashboardMetricItemBaseProps> = React
metricId={metricId}
versionNumber={metricVersionNumber}
animate={animate}
useHeaderLink
useHeaderLink={!readOnly}
renderChartContent={hasBeenInViewport}
headerSecondaryContent={
!isDragOverlay && (
!isDragOverlay &&
!readOnly && (
<DashboardMetricItemThreeDotMenu
metricId={metricId}
metricVersionNumber={metricVersionNumber}

View File

@ -18,7 +18,7 @@ export type MetricChartCardProps = {
className?: string;
attributes?: DraggableAttributes;
listeners?: DraggableSyntheticListeners;
headerSecondaryContent: React.ReactNode;
headerSecondaryContent?: React.ReactNode;
useHeaderLink?: boolean;
animate?: boolean;
renderChartContent?: boolean; // we do this to avoid expensive rendering if off screen

View File

@ -1,6 +1,8 @@
import React, { useCallback } from 'react';
import type { BusterDashboardResponse } from '@/api/asset_interfaces/dashboard';
import { useGetDashboard, useSaveDashboard } from '@/api/buster_rest/dashboards';
import { DashboardViewDashboardController } from '@/controllers/DashboardController/DashboardViewDashboardController';
import { ScrollArea } from '../../ui/scroll-area';
import { useVersionHistoryModalCommon } from './useVersionHistoryModalCommon';
import { VersionHistoryModal, type VersionHistoryModalProps } from './VersionHistoryModal';
@ -58,7 +60,16 @@ export const DashboardVersionModal = React.memo(
isRestoringVersion={isRestoringVersion}
learnMoreButton={learnMoreButton}
>
{data?.name} {versionNumber}
{versionNumber && (
<ScrollArea className="h-full">
<DashboardViewDashboardController
dashboardId={dashboardId}
readOnly
dashboardVersionNumber={versionNumber}
animate={false}
/>
</ScrollArea>
)}
</VersionHistoryModal>
);
}

View File

@ -70,7 +70,14 @@ export const MetricVersionHistoryModal = React.memo(
isRestoringVersion={isRestoringVersion}
learnMoreButton={learnMoreButton}
>
<MetricViewChart metricId={metricId} versionNumber={versionNumber || undefined} readOnly />
{versionNumber && (
<MetricViewChart
metricId={metricId}
versionNumber={versionNumber || undefined}
readOnly
animate={false}
/>
)}
</VersionHistoryModal>
);
}

View File

@ -1,10 +1,7 @@
import type { DashboardConfig } from '@buster/server-shared/dashboards';
import isEmpty from 'lodash/isEmpty';
import React, { useMemo, useState } from 'react';
import type {
BusterDashboardResponse,
BusterMetric,
DashboardConfig,
} from '@/api/asset_interfaces';
import type { BusterDashboardResponse, BusterMetric } from '@/api/asset_interfaces';
import type { useUpdateDashboardConfig } from '@/api/buster_rest/dashboards';
import { BusterResizeableGrid, type BusterResizeableGridRow } from '@/components/ui/grid';
import { useMemoizedFn } from '@/hooks/useMemoizedFn';
@ -23,11 +20,13 @@ export const DashboardContentController: React.FC<{
dashboard: BusterDashboardResponse['dashboard'] | undefined;
onUpdateDashboardConfig: ReturnType<typeof useUpdateDashboardConfig>['mutateAsync'];
onOpenAddContentModal: () => void;
animate?: boolean;
}> = React.memo(
({
onOpenAddContentModal,
dashboard,
readOnly = false,
animate = true,
metrics = DEFAULT_EMPTY_METRICS,
onUpdateDashboardConfig,
}) => {
@ -49,17 +48,19 @@ export const DashboardContentController: React.FC<{
numberOfMetrics={numberOfMetrics}
dashboardVersionNumber={dashboardVersionNumber}
metricVersionNumber={metrics[draggingId]?.version_number}
readOnly={readOnly}
/>
)
);
}, [draggingId, dashboard?.id, numberOfMetrics, metrics]);
}, [draggingId, dashboard?.id, numberOfMetrics, metrics, readOnly]);
const dashboardRows = useMemo(() => {
const dashboardRows: BusterResizeableGridRow[] = useMemo(() => {
return rows
.filter((row) => row.items.length > 0)
.map((row) => {
return {
...row,
id: String(row.id),
items: row.items.map((item) => {
const selectedMetric = metrics[item.id];
const metricVersionNumber = selectedMetric.version_number;
@ -67,6 +68,7 @@ export const DashboardContentController: React.FC<{
return {
...item,
children: (
//todo move this a callback...
<DashboardMetricItem
key={item.id}
metricId={item.id}
@ -74,13 +76,15 @@ export const DashboardContentController: React.FC<{
numberOfMetrics={numberOfMetrics}
metricVersionNumber={metricVersionNumber}
dashboardVersionNumber={dashboardVersionNumber}
animate={animate}
readOnly={readOnly}
/>
),
};
}),
};
});
}, [JSON.stringify(rows), readOnly, dashboard?.id, numberOfMetrics]);
}, [JSON.stringify(rows), readOnly, dashboard?.id, numberOfMetrics, animate]);
const onRowLayoutChange = useMemoizedFn((layoutRows: BusterResizeableGridRow[]) => {
if (dashboard) {

View File

@ -1,5 +1,5 @@
import type { DashboardConfig } from '@buster/server-shared/dashboards';
import omit from 'lodash/omit';
import type { DashboardConfig } from '@/api/asset_interfaces/dashboard';
import type { BusterMetric } from '@/api/asset_interfaces/metric';
import type { BusterResizeableGridRow } from '@/components/ui/grid';

View File

@ -13,13 +13,15 @@ import { DashboardSaveFilePopup } from './DashboardSaveFilePopup';
export const DashboardViewDashboardController: React.FC<{
dashboardId: string;
readOnly?: boolean;
}> = ({ dashboardId, readOnly: readOnlyProp = false }) => {
dashboardVersionNumber?: number;
animate?: boolean;
}> = ({ dashboardId, dashboardVersionNumber, readOnly: readOnlyProp = false, animate = true }) => {
const {
data: dashboardResponse,
isFetched,
isError,
error,
} = useGetDashboard({ id: dashboardId });
} = useGetDashboard({ id: dashboardId, versionNumber: dashboardVersionNumber });
const { mutateAsync: onUpdateDashboardConfig } = useUpdateDashboardConfig();
@ -61,6 +63,7 @@ export const DashboardViewDashboardController: React.FC<{
onUpdateDashboardConfig={onUpdateDashboardConfig}
onOpenAddContentModal={onOpenDashboardContentModal}
readOnly={isReadOnly}
animate={animate}
/>
{!isReadOnly && !isVersionHistoryMode && !isViewingOldVersion && (

View File

@ -13,7 +13,7 @@ export const DashboardConfigSchema = z.object({
})
.optional(), // columns sizes 1 - 12. MUST add up to 12
rowHeight: z.number().optional(), // pixel based!
id: z.number(),
id: z.string(),
items: z.array(
z.object({
id: z.string(),