buster/web/src/controllers/DashboardController/DashboardViewDashboardContr.../DashboardContentController/DashboardContentController.tsx

136 lines
4.5 KiB
TypeScript
Raw Normal View History

2025-02-02 13:17:37 +08:00
'use client';
import React, { useEffect, useMemo, useState } from 'react';
import isEmpty from 'lodash/isEmpty';
2025-02-20 10:53:49 +08:00
import { BusterResizeableGrid, BusterResizeableGridRow } from '@/components/ui/grid';
2025-03-08 07:02:56 +08:00
import { useDebounceFn, useMemoizedFn } from '@/hooks';
2025-02-02 13:17:37 +08:00
import { hasRemovedMetrics, hasUnmappedMetrics, normalizeNewMetricsIntoGrid } from './helpers';
import { DashboardMetricItem } from './DashboardMetricItem';
2025-02-06 07:43:18 +08:00
import { DashboardContentControllerProvider } from './DashboardContentControllerContext';
2025-02-02 13:17:37 +08:00
import type {
BusterMetric,
BusterDashboardResponse,
DashboardConfig
} from '@/api/asset_interfaces';
2025-02-06 07:43:18 +08:00
import { DashboardEmptyState } from './DashboardEmptyState';
2025-03-13 08:40:15 +08:00
import { type useUpdateDashboardConfig } from '@/api/buster_rest/dashboards';
const DEFAULT_EMPTY_ROWS: DashboardConfig['rows'] = [];
2025-02-01 06:21:50 +08:00
const DEFAULT_EMPTY_METRICS: BusterMetric[] = [];
const DEFAULT_EMPTY_CONFIG: DashboardConfig = {};
2025-02-06 07:43:18 +08:00
export const DashboardContentController: React.FC<{
allowEdit?: boolean;
2025-02-13 14:11:44 +08:00
metrics: BusterDashboardResponse['metrics'] | undefined;
dashboard: BusterDashboardResponse['dashboard'] | undefined;
2025-03-13 08:40:15 +08:00
onUpdateDashboardConfig: ReturnType<typeof useUpdateDashboardConfig>['mutateAsync'];
2025-02-14 06:58:14 +08:00
onOpenAddContentModal: () => void;
}> = React.memo(
2025-02-06 07:43:18 +08:00
({
2025-02-14 06:58:14 +08:00
onOpenAddContentModal,
2025-02-06 07:43:18 +08:00
dashboard,
allowEdit,
metrics = DEFAULT_EMPTY_METRICS,
onUpdateDashboardConfig
}) => {
2025-02-13 14:11:44 +08:00
const dashboardConfig = dashboard?.config || DEFAULT_EMPTY_CONFIG;
const configRows = dashboardConfig?.rows || DEFAULT_EMPTY_ROWS;
const hasMetrics = !isEmpty(metrics);
2025-02-02 13:17:37 +08:00
const [draggingId, setDraggingId] = useState<string | null>(null);
const { run: debouncedForInitialRenderOnUpdateDashboardConfig } = useDebounceFn(
onUpdateDashboardConfig,
{ wait: 650, leading: true }
);
const onRowLayoutChange = useMemoizedFn((rows: BusterResizeableGridRow[]) => {
const formattedRows: DashboardConfig['rows'] = rows.map((row) => {
return {
...row,
items: row.items.map((item) => ({
id: item.id
}))
};
});
2025-03-13 08:40:15 +08:00
onUpdateDashboardConfig({ rows: formattedRows, id: dashboard!.id });
});
2025-02-02 13:17:37 +08:00
const remapMetrics = useMemo(() => {
const res = hasUnmappedMetrics(metrics, configRows) || hasRemovedMetrics(metrics, configRows);
return res;
}, [metrics, configRows.length]);
const rows = useMemo(() => {
2025-02-02 13:17:37 +08:00
return remapMetrics ? normalizeNewMetricsIntoGrid(metrics, configRows) : configRows;
}, [remapMetrics, metrics, configRows]);
const dashboardRows = useMemo(() => {
return rows
.filter((row) => row.items.length > 0)
.map((row) => {
return {
...row,
items: row.items.map((item) => {
return {
...item,
children: (
<DashboardMetricItem
key={item.id}
metricId={item.id}
2025-02-13 14:11:44 +08:00
dashboardId={dashboard!.id}
allowEdit={allowEdit}
2025-02-06 07:43:18 +08:00
numberOfMetrics={metrics.length}
/>
)
};
})
};
});
}, [rows]);
const onDragEnd = useMemoizedFn(() => {
setDraggingId(null);
});
const onStartDrag = useMemoizedFn(({ id }: { id: string }) => {
setDraggingId(id);
});
useEffect(() => {
2025-02-13 14:11:44 +08:00
if (remapMetrics && dashboard?.id) {
2025-03-13 08:40:15 +08:00
debouncedForInitialRenderOnUpdateDashboardConfig({ rows, id: dashboard.id });
}
2025-02-13 14:11:44 +08:00
}, [dashboard?.id, remapMetrics]);
return (
2025-02-06 13:35:46 +08:00
<div className="dashboard-content-controller">
2025-02-13 14:11:44 +08:00
{hasMetrics && !!dashboardRows.length && !!dashboard ? (
2025-02-06 07:43:18 +08:00
<DashboardContentControllerProvider dashboard={dashboard}>
<BusterResizeableGrid
rows={dashboardRows}
allowEdit={allowEdit}
onRowLayoutChange={onRowLayoutChange}
onStartDrag={onStartDrag}
onEndDrag={onDragEnd}
overlayComponent={
draggingId && (
<DashboardMetricItem
metricId={draggingId}
allowEdit={false}
2025-02-06 07:43:18 +08:00
dashboardId={dashboard.id}
isDragOverlay
2025-02-06 07:43:18 +08:00
numberOfMetrics={metrics.length}
/>
)
}
/>
2025-02-06 07:43:18 +08:00
</DashboardContentControllerProvider>
) : (
2025-02-14 06:58:14 +08:00
<DashboardEmptyState onOpenAddContentModal={onOpenAddContentModal} />
)}
</div>
);
}
);
2025-02-06 07:43:18 +08:00
DashboardContentController.displayName = 'DashboardIndividualDashboard';