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

139 lines
4.6 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-03-22 05:43:29 +08:00
import {
hasRemovedMetrics,
hasUnmappedMetrics,
normalizeNewMetricsIntoGrid,
removeChildrenFromItems
} from './helpers';
2025-02-02 13:17:37 +08:00
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-03-18 12:40:09 +08:00
const DEFAULT_EMPTY_METRICS: Record<string, BusterMetric> = {};
const DEFAULT_EMPTY_CONFIG: DashboardConfig = {};
2025-02-06 07:43:18 +08:00
export const DashboardContentController: React.FC<{
2025-03-19 03:36:58 +08:00
readOnly?: boolean;
2025-02-13 14:11:44 +08:00
metrics: BusterDashboardResponse['metrics'] | undefined;
2025-03-30 12:28:15 +08:00
chatId: string | undefined;
2025-02-13 14:11:44 +08:00
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,
2025-03-30 12:28:15 +08:00
chatId,
2025-03-19 03:36:58 +08:00
readOnly = false,
2025-02-06 07:43:18 +08:00
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);
2025-03-18 12:40:09 +08:00
const numberOfMetrics = Object.values(metrics).length;
2025-02-02 13:17:37 +08:00
const remapMetrics = useMemo(() => {
2025-03-21 03:37:34 +08:00
return hasUnmappedMetrics(metrics, configRows) || hasRemovedMetrics(metrics, configRows);
}, [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}
2025-03-19 03:36:58 +08:00
readOnly={readOnly}
2025-03-30 12:28:15 +08:00
chatId={chatId}
2025-03-18 12:40:09 +08:00
numberOfMetrics={numberOfMetrics}
/>
)
};
})
};
});
2025-03-21 03:37:34 +08:00
}, [rows, readOnly, dashboard?.id, numberOfMetrics]);
const { run: debouncedForInitialRenderOnUpdateDashboardConfig } = useDebounceFn(
onUpdateDashboardConfig,
{ wait: 650, leading: true }
);
const onRowLayoutChange = useMemoizedFn((rows: BusterResizeableGridRow[]) => {
2025-03-22 05:43:29 +08:00
if (dashboard) {
onUpdateDashboardConfig({ rows: removeChildrenFromItems(rows), id: dashboard.id });
}
2025-03-21 03:37:34 +08:00
});
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}
2025-03-19 03:36:58 +08:00
readOnly={readOnly}
onRowLayoutChange={onRowLayoutChange}
onStartDrag={onStartDrag}
onEndDrag={onDragEnd}
overlayComponent={
draggingId && (
<DashboardMetricItem
metricId={draggingId}
2025-03-19 03:36:58 +08:00
readOnly={false}
2025-02-06 07:43:18 +08:00
dashboardId={dashboard.id}
isDragOverlay
2025-03-18 12:40:09 +08:00
numberOfMetrics={numberOfMetrics}
2025-03-30 12:28:15 +08:00
chatId={undefined}
/>
)
}
/>
2025-02-06 07:43:18 +08:00
</DashboardContentControllerProvider>
2025-03-22 04:03:43 +08:00
) : !readOnly ? (
2025-02-14 06:58:14 +08:00
<DashboardEmptyState onOpenAddContentModal={onOpenAddContentModal} />
2025-03-22 04:03:43 +08:00
) : null}
</div>
);
}
);
2025-02-06 07:43:18 +08:00
DashboardContentController.displayName = 'DashboardIndividualDashboard';