mirror of https://github.com/buster-so/buster.git
179 lines
5.7 KiB
TypeScript
179 lines
5.7 KiB
TypeScript
'use client';
|
|
|
|
import React, { useMemo, useState } from 'react';
|
|
import isEmpty from 'lodash/isEmpty';
|
|
import { doesChartHaveValidAxis } from './helpers';
|
|
import { useMemoizedFn, useMount } from '@/hooks';
|
|
import {
|
|
NoChartData,
|
|
PreparingYourRequestLoader
|
|
} from './LoadingComponents/ChartLoadingComponents';
|
|
import BusterTableChart from './TableChart';
|
|
import { BusterChartProps, ChartEncodes, ChartType } from '@/api/asset_interfaces/metric/charts';
|
|
import { DEFAULT_DATA } from './BusterChartLegend/config';
|
|
import { NoValidAxis } from './LoadingComponents';
|
|
import BusterMetricChart from './MetricChart';
|
|
import { BusterChartErrorWrapper } from './BusterChartErrorWrapper';
|
|
import { BusterChartWrapper } from './BusterChartWrapper';
|
|
import { BusterChartRenderComponentProps } from './interfaces/chartComponentInterfaces';
|
|
import { BusterChartComponent } from './BusterChartComponent';
|
|
import { DEFAULT_CHART_CONFIG } from '@/api/asset_interfaces/metric/defaults';
|
|
|
|
export const BusterChart: React.FC<BusterChartProps> = React.memo(
|
|
({
|
|
data = DEFAULT_DATA,
|
|
groupByMethod = 'sum',
|
|
loading = false,
|
|
className = '',
|
|
animate = true,
|
|
animateLegend = true,
|
|
readOnly = true,
|
|
id,
|
|
error,
|
|
tableColumnOrder,
|
|
tableColumnWidths,
|
|
tableHeaderBackgroundColor,
|
|
tableHeaderFontColor,
|
|
tableColumnFontColor,
|
|
metricColumnId,
|
|
metricHeader,
|
|
metricSubHeader,
|
|
metricValueAggregate,
|
|
metricValueLabel,
|
|
onChartMounted: onChartMountedProp,
|
|
onInitialAnimationEnd,
|
|
selectedChartType,
|
|
columnLabelFormats = DEFAULT_CHART_CONFIG.columnLabelFormats,
|
|
columnSettings = DEFAULT_CHART_CONFIG.columnSettings,
|
|
...props
|
|
}) => {
|
|
const [isMounted, setIsMounted] = useState(false); //there is a responsive bug where we need to wait for the chart to mount before we can animate it
|
|
const isTable = selectedChartType === ChartType.Table;
|
|
const showNoData = !loading && (isEmpty(data) || data === null);
|
|
|
|
const selectedAxis: ChartEncodes | undefined = useMemo(() => {
|
|
const { pieChartAxis, comboChartAxis, scatterAxis, barAndLineAxis } = props;
|
|
if (selectedChartType === ChartType.Pie) return pieChartAxis;
|
|
if (selectedChartType === ChartType.Combo) return comboChartAxis;
|
|
if (selectedChartType === ChartType.Scatter) return scatterAxis;
|
|
if (selectedChartType === ChartType.Bar) return barAndLineAxis;
|
|
if (selectedChartType === ChartType.Line) return barAndLineAxis;
|
|
}, [
|
|
selectedChartType,
|
|
props.pieChartAxis,
|
|
props.comboChartAxis,
|
|
props.scatterAxis,
|
|
props.barAndLineAxis
|
|
]);
|
|
|
|
const hasValidAxis = useMemo(() => {
|
|
return doesChartHaveValidAxis({
|
|
selectedChartType,
|
|
selectedAxis,
|
|
isTable
|
|
});
|
|
}, [selectedChartType, isTable, selectedAxis]);
|
|
|
|
const onChartMounted = useMemoizedFn((chart?: any) => {
|
|
onChartMountedProp?.(chart);
|
|
});
|
|
|
|
const onInitialAnimationEndPreflight = useMemoizedFn(() => {
|
|
onInitialAnimationEnd?.();
|
|
});
|
|
|
|
const SwitchComponent = useMemoizedFn(() => {
|
|
//chartjs need the parent to be mounted to render the chart. It is intermitent when it throws when the parent is not mounted.
|
|
if (!isMounted && selectedChartType !== ChartType.Table) return null;
|
|
|
|
if (loading || error) {
|
|
return <PreparingYourRequestLoader error={error} />;
|
|
}
|
|
|
|
if (showNoData || !data) {
|
|
return <NoChartData />;
|
|
}
|
|
|
|
if (!hasValidAxis) {
|
|
return <NoValidAxis type={selectedChartType} data={data} />;
|
|
}
|
|
|
|
if (isTable) {
|
|
return (
|
|
<BusterTableChart
|
|
tableColumnOrder={tableColumnOrder}
|
|
tableColumnWidths={tableColumnWidths}
|
|
tableHeaderBackgroundColor={tableHeaderBackgroundColor}
|
|
tableHeaderFontColor={tableHeaderFontColor}
|
|
tableColumnFontColor={tableColumnFontColor}
|
|
columnLabelFormats={columnLabelFormats}
|
|
readOnly={readOnly}
|
|
data={data}
|
|
type={ChartType.Table}
|
|
onMounted={onChartMounted}
|
|
onInitialAnimationEnd={onInitialAnimationEndPreflight}
|
|
/>
|
|
);
|
|
}
|
|
|
|
if (selectedChartType === ChartType.Metric) {
|
|
return (
|
|
<BusterMetricChart
|
|
data={data}
|
|
columnLabelFormats={columnLabelFormats}
|
|
onMounted={onChartMounted}
|
|
metricColumnId={metricColumnId}
|
|
metricHeader={metricHeader}
|
|
animate={animate}
|
|
metricSubHeader={metricSubHeader}
|
|
metricValueAggregate={metricValueAggregate}
|
|
metricValueLabel={metricValueLabel}
|
|
onInitialAnimationEnd={onInitialAnimationEndPreflight}
|
|
/>
|
|
);
|
|
}
|
|
|
|
if (!isMounted) {
|
|
return (
|
|
<div className="to-bg-gradient-to-r to-border/10 h-full w-full bg-gradient-to-b from-transparent" />
|
|
);
|
|
}
|
|
|
|
const chartProps: BusterChartRenderComponentProps = {
|
|
...DEFAULT_CHART_CONFIG,
|
|
columnMetadata: props.columnMetadata ?? [],
|
|
data,
|
|
onChartMounted,
|
|
onInitialAnimationEnd: onInitialAnimationEndPreflight,
|
|
selectedAxis: selectedAxis!,
|
|
animate,
|
|
animateLegend,
|
|
className,
|
|
columnLabelFormats,
|
|
selectedChartType,
|
|
loading,
|
|
columnSettings,
|
|
readOnly,
|
|
...props
|
|
};
|
|
|
|
return <BusterChartComponent {...chartProps} />;
|
|
});
|
|
|
|
useMount(() => {
|
|
setTimeout(() => {
|
|
setIsMounted(true);
|
|
}, 25);
|
|
});
|
|
|
|
return (
|
|
<BusterChartErrorWrapper>
|
|
<BusterChartWrapper id={id} className={className} loading={loading}>
|
|
{SwitchComponent()}
|
|
</BusterChartWrapper>
|
|
</BusterChartErrorWrapper>
|
|
);
|
|
}
|
|
);
|
|
BusterChart.displayName = 'BusterChart';
|