@spteck/fluentui-react-charts 1.0.4 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +255 -0
- package/dist/fluentui-react-charts.cjs.development.js +2478 -2198
- package/dist/fluentui-react-charts.cjs.development.js.map +1 -1
- package/dist/fluentui-react-charts.cjs.production.min.js +1 -1
- package/dist/fluentui-react-charts.cjs.production.min.js.map +1 -1
- package/dist/fluentui-react-charts.esm.js +2479 -2200
- package/dist/fluentui-react-charts.esm.js.map +1 -1
- package/dist/hooks/index.d.ts +1 -1
- package/dist/hooks/useChartFactory.d.ts +6 -0
- package/dist/hooks/{useGraphUtils.d.ts → useChartUtils.d.ts} +2 -5
- package/dist/hooks/useIndexedDBCache.d.ts +33 -0
- package/dist/index.d.ts +1 -0
- package/package.json +2 -1
- package/src/charts/BarChart/BarChart.tsx +2 -2
- package/src/charts/ComboChart/ComboChart.tsx +2 -2
- package/src/charts/Doughnut/DoughnutChart.tsx +2 -2
- package/src/charts/PieChart/PieChart.tsx +3 -3
- package/src/charts/areaChart/AreaChart.tsx +2 -2
- package/src/charts/barHorizontalChart/BarHotizontalChart.tsx +2 -2
- package/src/charts/bubbleChart/BubbleChart.tsx +2 -2
- package/src/charts/floatBarChart/FloatBarChart.tsx +2 -2
- package/src/charts/lineChart/LineChart.tsx +2 -2
- package/src/charts/polarChart/PolarChart.tsx +2 -2
- package/src/charts/radarChart/RadarChart.tsx +2 -2
- package/src/charts/scatterChart/ScatterChart.tsx +2 -2
- package/src/charts/stackedLineChart/StackedLineChart.tsx +2 -2
- package/src/charts/steamChart/SteamChart.tsx +2 -2
- package/src/components/dashboard/DashBoard.tsx +117 -23
- package/src/components/dashboard/ExampleDashboardUsage.tsx +1 -1
- package/src/components/dashboard/IDashboardProps.tsx +0 -2
- package/src/hooks/index.ts +1 -1
- package/src/hooks/useChartFactory.tsx +136 -0
- package/src/hooks/{useGraphUtils.tsx → useChartUtils.tsx} +3 -130
- package/src/hooks/useIndexedDBCache.ts +122 -0
- package/src/hooks/useResponsiveLegend.ts +2 -2
- package/src/index.tsx +1 -0
- package/src/models/ICardChartContainer.tsx +0 -2
package/dist/hooks/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export * from './
|
|
1
|
+
export * from './useChartUtils';
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import { ChartType, TooltipOptions } from 'chart.js';
|
|
2
2
|
import { Theme } from '@fluentui/react-components';
|
|
3
|
-
import { IChart } from '../models/IChart';
|
|
4
|
-
import React from 'react';
|
|
5
3
|
/**
|
|
6
4
|
* Lightens a given hex color by a percentage amount (0 to 1).
|
|
7
5
|
*/
|
|
@@ -21,12 +19,11 @@ export declare const createAxisLabelFormatter: ({ maxLength, suffix, prefix, }:
|
|
|
21
19
|
}) => (this: any, value: string | number) => string;
|
|
22
20
|
declare function debounce<T extends (...args: any[]) => void>(fn: T, delay: number): T;
|
|
23
21
|
/**
|
|
24
|
-
*
|
|
22
|
+
* useChartUtils — shared theming and chart helpers.
|
|
25
23
|
*/
|
|
26
|
-
export declare function
|
|
24
|
+
export declare function useChartUtils(theme?: Theme): {
|
|
27
25
|
lightenColor: (hex: string, amount: number) => string;
|
|
28
26
|
getFluentPalette: (_theme: Theme) => string[];
|
|
29
|
-
getChartComponent: (chart: IChart, theme: Theme) => React.JSX.Element;
|
|
30
27
|
createFluentTooltip: typeof createFluentTooltip;
|
|
31
28
|
createAxisLabelFormatter: ({ maxLength, suffix, prefix, }: {
|
|
32
29
|
maxLength?: number | undefined;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export interface CacheData<T> {
|
|
2
|
+
data: T;
|
|
3
|
+
timestamp: number;
|
|
4
|
+
}
|
|
5
|
+
interface UseIndexedDBCacheReturn<T> {
|
|
6
|
+
getData: (key: string) => Promise<T | undefined>;
|
|
7
|
+
setData: (key: string, data: T) => Promise<void>;
|
|
8
|
+
deleteData: (key: string) => Promise<void>;
|
|
9
|
+
clearAllCache: () => Promise<void>;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Custom hook to manage IndexedDB cache with a specified maximum age.
|
|
13
|
+
*
|
|
14
|
+
* @template T - The type of data to be cached.
|
|
15
|
+
* @param {number} [maxAge=DEFAULT_MAX_AGE] - The maximum age (in milliseconds) for cached data before it is considered expired.
|
|
16
|
+
* @returns {UseIndexedDBCacheReturn<T>} An object containing methods to interact with the cache.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* const { getData, setData, deleteData, clearAllCache } = useIndexedDBCache<MyDataType>(3600000);
|
|
20
|
+
*
|
|
21
|
+
* @function
|
|
22
|
+
* @name useIndexedDBCache
|
|
23
|
+
* @memberof hooks
|
|
24
|
+
* @inner
|
|
25
|
+
*
|
|
26
|
+
* @typedef {Object} UseIndexedDBCacheReturn<T>
|
|
27
|
+
* @property {function(string): Promise<T | undefined>} getData - Retrieves cached data by key.
|
|
28
|
+
* @property {function(string, T): Promise<void>} setData - Caches data with a specified key.
|
|
29
|
+
* @property {function(string): Promise<void>} deleteData - Deletes cached data by key.
|
|
30
|
+
* @property {function(): Promise<void>} clearAllCache - Clears all cached data.
|
|
31
|
+
*/
|
|
32
|
+
export declare const useIndexedDBCache: <T>(maxAge?: number) => UseIndexedDBCacheReturn<T>;
|
|
33
|
+
export default useIndexedDBCache;
|
package/dist/index.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "1.0.
|
|
2
|
+
"version": "1.0.6",
|
|
3
3
|
"license": "MIT",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"typings": "dist/index.d.ts",
|
|
@@ -54,6 +54,7 @@
|
|
|
54
54
|
"@fluentui/react-components": "^9.66.2",
|
|
55
55
|
"@iconify/react": "^6.0.0",
|
|
56
56
|
"@juggle/resize-observer": "^3.4.0",
|
|
57
|
+
"@spteck/m365-hooks": "^1.2.0",
|
|
57
58
|
"chart.js": "^4.5.0",
|
|
58
59
|
"chartjs-plugin-datalabels": "^2.2.0",
|
|
59
60
|
"react": "^18.3.1",
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
Tooltip,
|
|
10
10
|
} from 'chart.js';
|
|
11
11
|
import React, { useMemo, useState } from 'react';
|
|
12
|
-
import { createAxisLabelFormatter,
|
|
12
|
+
import { createAxisLabelFormatter, useChartUtils } from '../../hooks/useChartUtils';
|
|
13
13
|
|
|
14
14
|
import { Bar } from 'react-chartjs-2';
|
|
15
15
|
import ChartDataLabels from 'chartjs-plugin-datalabels';
|
|
@@ -50,7 +50,7 @@ export default function BarChart<T extends object>({
|
|
|
50
50
|
data.length > 1 ? data.map(s => s.label) : [data[0]?.label]
|
|
51
51
|
);
|
|
52
52
|
|
|
53
|
-
const { lightenColor, getFluentPalette, createFluentTooltip } =
|
|
53
|
+
const { lightenColor, getFluentPalette, createFluentTooltip } = useChartUtils(
|
|
54
54
|
theme
|
|
55
55
|
);
|
|
56
56
|
const styles = useGraphGlobalStyles();
|
|
@@ -16,8 +16,8 @@ import { Theme, webLightTheme } from '@fluentui/react-components';
|
|
|
16
16
|
import { Chart } from 'react-chartjs-2';
|
|
17
17
|
import ChartDataLabels from 'chartjs-plugin-datalabels';
|
|
18
18
|
import RenderLegend from '../../components/RenderLegend/RenderLegend';
|
|
19
|
+
import { useChartUtils } from '../../hooks/useChartUtils';
|
|
19
20
|
import { useGraphGlobalStyles } from '../../graphGlobalStyles/useGraphGlobalStyles';
|
|
20
|
-
import { useGraphUtils } from '../../hooks/useGraphUtils';
|
|
21
21
|
|
|
22
22
|
ChartJS.register(ChartDataLabels);
|
|
23
23
|
ChartJS.register(
|
|
@@ -58,7 +58,7 @@ export default function ComboChart<T extends object>({
|
|
|
58
58
|
);
|
|
59
59
|
|
|
60
60
|
const styles = useGraphGlobalStyles();
|
|
61
|
-
const { lightenColor, getFluentPalette, createFluentTooltip } =
|
|
61
|
+
const { lightenColor, getFluentPalette, createFluentTooltip } = useChartUtils(theme);
|
|
62
62
|
|
|
63
63
|
const seriesColors = useMemo(() => {
|
|
64
64
|
return data.reduce((acc, series, idx) => {
|
|
@@ -12,8 +12,8 @@ import { Theme, webLightTheme } from '@fluentui/react-components';
|
|
|
12
12
|
import ChartDataLabels from 'chartjs-plugin-datalabels';
|
|
13
13
|
import { Doughnut } from 'react-chartjs-2';
|
|
14
14
|
import RenderValueLegend from '../../components/renderValueLegend/RenderValueLegend';
|
|
15
|
+
import { useChartUtils } from '../../hooks/useChartUtils';
|
|
15
16
|
import { useGraphGlobalStyles } from '../../graphGlobalStyles/useGraphGlobalStyles';
|
|
16
|
-
import { useGraphUtils } from '../../hooks/useGraphUtils';
|
|
17
17
|
|
|
18
18
|
ChartJS.register(ChartDataLabels);
|
|
19
19
|
ChartJS.register(ArcElement, Tooltip, Legend, Title);
|
|
@@ -39,7 +39,7 @@ export default function DoughnutChart<T extends object>({
|
|
|
39
39
|
theme = webLightTheme,
|
|
40
40
|
}: DoughnutChartProps<T>) {
|
|
41
41
|
const styles = useGraphGlobalStyles();
|
|
42
|
-
const { lightenColor, getFluentPalette, createFluentTooltip } =
|
|
42
|
+
const { lightenColor, getFluentPalette, createFluentTooltip } = useChartUtils(
|
|
43
43
|
theme
|
|
44
44
|
);
|
|
45
45
|
const [hiddenLabels, setHiddenLabels] = useState<string[]>([]);
|
|
@@ -12,9 +12,9 @@ import { Theme, webLightTheme } from '@fluentui/react-components';
|
|
|
12
12
|
import ChartDataLabels from 'chartjs-plugin-datalabels';
|
|
13
13
|
import { Pie } from 'react-chartjs-2';
|
|
14
14
|
import RenderValueLegend from '../../components/renderValueLegend/RenderValueLegend';
|
|
15
|
-
import { createFluentTooltip } from '../../hooks/
|
|
15
|
+
import { createFluentTooltip } from '../../hooks/useChartUtils';
|
|
16
|
+
import { useChartUtils } from '../../hooks/useChartUtils';
|
|
16
17
|
import { useGraphGlobalStyles } from '../../graphGlobalStyles/useGraphGlobalStyles';
|
|
17
|
-
import { useGraphUtils } from '../../hooks/useGraphUtils';
|
|
18
18
|
|
|
19
19
|
ChartJS.register(ChartDataLabels);
|
|
20
20
|
ChartJS.register(ArcElement, Tooltip, Legend, Title);
|
|
@@ -39,7 +39,7 @@ export default function PieChart<T extends object>({
|
|
|
39
39
|
showDataLabels = false,
|
|
40
40
|
theme = webLightTheme,
|
|
41
41
|
}: PieChartProps<T>) {
|
|
42
|
-
const { getFluentPalette, lightenColor } =
|
|
42
|
+
const { getFluentPalette, lightenColor } = useChartUtils(theme);
|
|
43
43
|
const [hiddenLabels, setHiddenLabels] = useState<string[]>([]);
|
|
44
44
|
const styles = useGraphGlobalStyles();
|
|
45
45
|
const toggleLabel = (label: string): void => {
|
|
@@ -16,8 +16,8 @@ import { Theme, webLightTheme } from '@fluentui/react-components';
|
|
|
16
16
|
import ChartDataLabels from 'chartjs-plugin-datalabels';
|
|
17
17
|
import { Line } from 'react-chartjs-2';
|
|
18
18
|
import RenderLegend from '../../components/RenderLegend/RenderLegend';
|
|
19
|
+
import { useChartUtils } from '../../hooks/useChartUtils';
|
|
19
20
|
import { useGraphGlobalStyles } from '../../graphGlobalStyles/useGraphGlobalStyles';
|
|
20
|
-
import { useGraphUtils } from '../../hooks/useGraphUtils';
|
|
21
21
|
|
|
22
22
|
ChartJS.register(
|
|
23
23
|
CategoryScale,
|
|
@@ -55,7 +55,7 @@ export default function AreaChart<T extends object>({
|
|
|
55
55
|
);
|
|
56
56
|
|
|
57
57
|
const styles = useGraphGlobalStyles();
|
|
58
|
-
const { lightenColor, getFluentPalette, createFluentTooltip } =
|
|
58
|
+
const { lightenColor, getFluentPalette, createFluentTooltip } = useChartUtils(
|
|
59
59
|
theme
|
|
60
60
|
);
|
|
61
61
|
|
|
@@ -14,8 +14,8 @@ import { Bar } from 'react-chartjs-2';
|
|
|
14
14
|
import ChartDataLabels from 'chartjs-plugin-datalabels';
|
|
15
15
|
import RenderLegend from '../../components/RenderLegend/RenderLegend';
|
|
16
16
|
import { Theme } from '@fluentui/react-theme';
|
|
17
|
+
import { useChartUtils } from '../../hooks/useChartUtils';
|
|
17
18
|
import { useGraphGlobalStyles } from '../../graphGlobalStyles/useGraphGlobalStyles';
|
|
18
|
-
import { useGraphUtils } from '../../hooks/useGraphUtils';
|
|
19
19
|
|
|
20
20
|
ChartJS.register(
|
|
21
21
|
CategoryScale,
|
|
@@ -55,7 +55,7 @@ export default function BarHorizontalChart<T extends object>({
|
|
|
55
55
|
);
|
|
56
56
|
const styles = useGraphGlobalStyles();
|
|
57
57
|
|
|
58
|
-
const { lightenColor, getFluentPalette , createFluentTooltip} =
|
|
58
|
+
const { lightenColor, getFluentPalette , createFluentTooltip} = useChartUtils(theme);
|
|
59
59
|
|
|
60
60
|
const seriesColors = useMemo(() => {
|
|
61
61
|
return data.reduce((acc, series, idx) => {
|
|
@@ -15,8 +15,8 @@ import { Theme, webLightTheme } from '@fluentui/react-components';
|
|
|
15
15
|
import { Bubble } from 'react-chartjs-2';
|
|
16
16
|
import ChartDataLabels from 'chartjs-plugin-datalabels';
|
|
17
17
|
import RenderLegend from '../../components/RenderLegend/RenderLegend';
|
|
18
|
+
import { useChartUtils } from '../../hooks/useChartUtils';
|
|
18
19
|
import { useGraphGlobalStyles } from '../../graphGlobalStyles/useGraphGlobalStyles';
|
|
19
|
-
import { useGraphUtils } from '../../hooks/useGraphUtils';
|
|
20
20
|
|
|
21
21
|
ChartJS.register(
|
|
22
22
|
CategoryScale,
|
|
@@ -51,7 +51,7 @@ export default function BubbleChart<T extends object>({
|
|
|
51
51
|
data.length > 1 ? data.map(s => s.label) : [data[0]?.label]
|
|
52
52
|
);
|
|
53
53
|
|
|
54
|
-
const { lightenColor, getFluentPalette, createFluentTooltip } =
|
|
54
|
+
const { lightenColor, getFluentPalette, createFluentTooltip } = useChartUtils(
|
|
55
55
|
theme
|
|
56
56
|
);
|
|
57
57
|
|
|
@@ -14,8 +14,8 @@ import { Theme, webLightTheme } from '@fluentui/react-components';
|
|
|
14
14
|
import { Bar } from 'react-chartjs-2';
|
|
15
15
|
import ChartDataLabels from 'chartjs-plugin-datalabels';
|
|
16
16
|
import RenderLegend from '../../components/RenderLegend/RenderLegend';
|
|
17
|
+
import { useChartUtils } from '../../hooks/useChartUtils';
|
|
17
18
|
import { useGraphGlobalStyles } from '../../graphGlobalStyles/useGraphGlobalStyles';
|
|
18
|
-
import { useGraphUtils } from '../../hooks/useGraphUtils';
|
|
19
19
|
|
|
20
20
|
ChartJS.register(ChartDataLabels);
|
|
21
21
|
ChartJS.register(
|
|
@@ -49,7 +49,7 @@ export default function FloatingBarChart<T extends object>({
|
|
|
49
49
|
);
|
|
50
50
|
|
|
51
51
|
const styles = useGraphGlobalStyles();
|
|
52
|
-
const { lightenColor, getFluentPalette, createFluentTooltip } =
|
|
52
|
+
const { lightenColor, getFluentPalette, createFluentTooltip } = useChartUtils(
|
|
53
53
|
theme
|
|
54
54
|
);
|
|
55
55
|
|
|
@@ -15,8 +15,8 @@ import { Theme, webLightTheme } from '@fluentui/react-components';
|
|
|
15
15
|
import ChartDataLabels from 'chartjs-plugin-datalabels';
|
|
16
16
|
import { Line } from 'react-chartjs-2';
|
|
17
17
|
import RenderLegend from '../../components/RenderLegend/RenderLegend';
|
|
18
|
+
import { useChartUtils } from '../../hooks/useChartUtils';
|
|
18
19
|
import { useGraphGlobalStyles } from '../../graphGlobalStyles/useGraphGlobalStyles';
|
|
19
|
-
import { useGraphUtils } from '../../hooks/useGraphUtils';
|
|
20
20
|
|
|
21
21
|
ChartJS.register(ChartDataLabels);
|
|
22
22
|
ChartJS.register(
|
|
@@ -51,7 +51,7 @@ export default function LineChart<T extends object>({
|
|
|
51
51
|
);
|
|
52
52
|
|
|
53
53
|
const styles = useGraphGlobalStyles();
|
|
54
|
-
const { lightenColor, getFluentPalette , createFluentTooltip} =
|
|
54
|
+
const { lightenColor, getFluentPalette , createFluentTooltip} = useChartUtils(theme);
|
|
55
55
|
|
|
56
56
|
const seriesColors = useMemo(() => {
|
|
57
57
|
return data.reduce((acc, series, idx) => {
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
} from 'chart.js';
|
|
10
10
|
import React, { useMemo, useState } from 'react';
|
|
11
11
|
import { Theme, webLightTheme } from '@fluentui/react-components';
|
|
12
|
-
import { createFluentTooltip,
|
|
12
|
+
import { createFluentTooltip, useChartUtils } from '../../hooks/useChartUtils';
|
|
13
13
|
|
|
14
14
|
import ChartDataLabels from 'chartjs-plugin-datalabels';
|
|
15
15
|
import { PolarArea } from 'react-chartjs-2';
|
|
@@ -45,7 +45,7 @@ export default function PolarChart<T extends object>({
|
|
|
45
45
|
showDataLabels = true,
|
|
46
46
|
theme = webLightTheme,
|
|
47
47
|
}: PolarChartProps<T>) {
|
|
48
|
-
const { getFluentPalette, lightenColor } =
|
|
48
|
+
const { getFluentPalette, lightenColor } = useChartUtils(theme);
|
|
49
49
|
const [hiddenLabels, setHiddenLabels] = useState<string[]>([]);
|
|
50
50
|
const styles = useGraphGlobalStyles();
|
|
51
51
|
const toggleLabel = (label: string) => {
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
} from 'chart.js';
|
|
12
12
|
import React, { useMemo, useState } from 'react';
|
|
13
13
|
import { Theme, webLightTheme } from '@fluentui/react-components';
|
|
14
|
-
import { createFluentTooltip,
|
|
14
|
+
import { createFluentTooltip, useChartUtils } from '../../hooks/useChartUtils';
|
|
15
15
|
|
|
16
16
|
import ChartDataLabels from 'chartjs-plugin-datalabels';
|
|
17
17
|
import { Radar } from 'react-chartjs-2';
|
|
@@ -51,7 +51,7 @@ export default function RadarChart<T extends object>({
|
|
|
51
51
|
);
|
|
52
52
|
|
|
53
53
|
const styles = useGraphGlobalStyles();
|
|
54
|
-
const { lightenColor, getFluentPalette } =
|
|
54
|
+
const { lightenColor, getFluentPalette } = useChartUtils(theme);
|
|
55
55
|
|
|
56
56
|
const seriesColors = useMemo(() => {
|
|
57
57
|
return data.reduce((acc, series, idx) => {
|
|
@@ -12,8 +12,8 @@ import { Theme, webLightTheme } from '@fluentui/react-components';
|
|
|
12
12
|
import ChartDataLabels from 'chartjs-plugin-datalabels';
|
|
13
13
|
import RenderLegend from '../../components/RenderLegend/RenderLegend';
|
|
14
14
|
import { Scatter } from 'react-chartjs-2';
|
|
15
|
+
import { useChartUtils } from '../../hooks/useChartUtils';
|
|
15
16
|
import { useGraphGlobalStyles } from '../../graphGlobalStyles/useGraphGlobalStyles';
|
|
16
|
-
import { useGraphUtils } from '../../hooks/useGraphUtils';
|
|
17
17
|
|
|
18
18
|
ChartJS.register(ChartDataLabels);
|
|
19
19
|
ChartJS.register(LinearScale, PointElement, Tooltip, Legend);
|
|
@@ -39,7 +39,7 @@ export default function ScatterChart<T extends object>({
|
|
|
39
39
|
data.map(s => s.label)
|
|
40
40
|
);
|
|
41
41
|
const styles = useGraphGlobalStyles();
|
|
42
|
-
const { getFluentPalette, lightenColor, createFluentTooltip } =
|
|
42
|
+
const { getFluentPalette, lightenColor, createFluentTooltip } = useChartUtils(
|
|
43
43
|
theme
|
|
44
44
|
);
|
|
45
45
|
|
|
@@ -15,8 +15,8 @@ import { Theme, webLightTheme } from '@fluentui/react-components';
|
|
|
15
15
|
import ChartDataLabels from 'chartjs-plugin-datalabels';
|
|
16
16
|
import { Line } from 'react-chartjs-2';
|
|
17
17
|
import RenderLegend from '../../components/RenderLegend/RenderLegend';
|
|
18
|
+
import { useChartUtils } from '../../hooks/useChartUtils';
|
|
18
19
|
import { useGraphGlobalStyles } from '../../graphGlobalStyles/useGraphGlobalStyles';
|
|
19
|
-
import { useGraphUtils } from '../../hooks/useGraphUtils';
|
|
20
20
|
|
|
21
21
|
ChartJS.register(ChartDataLabels);
|
|
22
22
|
ChartJS.register(
|
|
@@ -51,7 +51,7 @@ export default function StackedLineChart<T extends object>({
|
|
|
51
51
|
);
|
|
52
52
|
|
|
53
53
|
const styles = useGraphGlobalStyles();
|
|
54
|
-
const { lightenColor, getFluentPalette, createFluentTooltip } =
|
|
54
|
+
const { lightenColor, getFluentPalette, createFluentTooltip } = useChartUtils(theme);
|
|
55
55
|
|
|
56
56
|
const seriesColors = useMemo(() => {
|
|
57
57
|
return data.reduce((acc, series, idx) => {
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
} from 'chart.js';
|
|
13
13
|
import React, { useMemo, useState } from 'react';
|
|
14
14
|
import { Theme, ToggleButton, webLightTheme } from '@fluentui/react-components';
|
|
15
|
-
import { createFluentTooltip,
|
|
15
|
+
import { createFluentTooltip, useChartUtils } from '../../hooks/useChartUtils';
|
|
16
16
|
|
|
17
17
|
import ChartDataLabels from 'chartjs-plugin-datalabels';
|
|
18
18
|
import { Line } from 'react-chartjs-2';
|
|
@@ -55,7 +55,7 @@ export default function SteamChart<T extends object>({
|
|
|
55
55
|
const [showPercent, setShowPercent] = useState(false);
|
|
56
56
|
const styles = useGraphGlobalStyles();
|
|
57
57
|
|
|
58
|
-
const { lightenColor, getFluentPalette } =
|
|
58
|
+
const { lightenColor, getFluentPalette } = useChartUtils(theme);
|
|
59
59
|
|
|
60
60
|
const seriesColors = useMemo(() => {
|
|
61
61
|
return data.reduce((acc, series, idx) => {
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
1
|
import { Card, CardHeader, Text, Theme } from '@fluentui/react-components';
|
|
4
2
|
import React, {
|
|
5
3
|
useCallback,
|
|
@@ -13,11 +11,15 @@ import { ICardChartContainer } from '../../models/ICardChartContainer';
|
|
|
13
11
|
import { IDashboardProps } from './IDashboardProps';
|
|
14
12
|
import { NoDashboards } from './NoDashboards';
|
|
15
13
|
import { SelectZoom } from './selectZoom/SelectZoom';
|
|
14
|
+
import { useChartFactory } from '../../hooks/useChartFactory';
|
|
16
15
|
import { useDashboardStyles } from './useDashboardStyles';
|
|
17
|
-
import {
|
|
16
|
+
import { useIndexedDBCache } from '@spteck/m365-hooks';
|
|
18
17
|
|
|
19
18
|
const MINIMUM_DASHBOARD_WIDTH = 600;
|
|
20
19
|
const MAX_ROWS = 4;
|
|
20
|
+
const DASHBOARD_LAYOUT_CACHE_KEY = 'dashboard-layout-settings';
|
|
21
|
+
const DASHBOARD_ORDER_CACHE_KEY = 'dashboard-card-order';
|
|
22
|
+
const CACHE_EXPIRATION_DAYS = 30;
|
|
21
23
|
|
|
22
24
|
export const Dashboard: React.FC<IDashboardProps> = ({
|
|
23
25
|
cardCharts,
|
|
@@ -27,8 +29,22 @@ export const Dashboard: React.FC<IDashboardProps> = ({
|
|
|
27
29
|
maxSpanRows = MAX_ROWS,
|
|
28
30
|
}) => {
|
|
29
31
|
const styles = useDashboardStyles();
|
|
32
|
+
const { getChartComponent } = useChartFactory();
|
|
33
|
+
|
|
34
|
+
// Cache with 30-day expiration for dashboard layout settings
|
|
35
|
+
const { getData, setData } = useIndexedDBCache<Record<string, { spanCols: number; spanRows: number }>>(
|
|
36
|
+
CACHE_EXPIRATION_DAYS * 24 * 60 * 60 * 1000
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
// Cache for card order
|
|
40
|
+
const {
|
|
41
|
+
getData: getOrderData,
|
|
42
|
+
setData: setOrderData
|
|
43
|
+
} = useIndexedDBCache<string[]>(
|
|
44
|
+
CACHE_EXPIRATION_DAYS * 24 * 60 * 60 * 1000
|
|
45
|
+
);
|
|
30
46
|
|
|
31
|
-
|
|
47
|
+
|
|
32
48
|
|
|
33
49
|
const [CardChartContainer, setCardChartContainer] = useState<
|
|
34
50
|
ICardChartContainer[]
|
|
@@ -42,21 +58,97 @@ export const Dashboard: React.FC<IDashboardProps> = ({
|
|
|
42
58
|
const containerRef = useRef<HTMLDivElement>(null);
|
|
43
59
|
|
|
44
60
|
React.useEffect(() => {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
61
|
+
// Load cached card order and sizes
|
|
62
|
+
const initializeData = async () => {
|
|
63
|
+
try {
|
|
64
|
+
const [cachedSizes, cachedOrder] = await Promise.all([
|
|
65
|
+
getData(DASHBOARD_LAYOUT_CACHE_KEY),
|
|
66
|
+
getOrderData(DASHBOARD_ORDER_CACHE_KEY)
|
|
67
|
+
]);
|
|
68
|
+
|
|
69
|
+
// Restore card order if available, otherwise use original order
|
|
70
|
+
let orderedCards = cardCharts;
|
|
71
|
+
if (cachedOrder && cachedOrder.length > 0) {
|
|
72
|
+
// Reorder cards based on cached order, but handle cases where cards might have been added/removed
|
|
73
|
+
const cardMap = new Map(cardCharts.map(card => [card.id, card]));
|
|
74
|
+
const validCachedOrder = cachedOrder.filter(id => cardMap.has(id));
|
|
75
|
+
const missingCards = cardCharts.filter(card => !cachedOrder.includes(card.id));
|
|
76
|
+
|
|
77
|
+
orderedCards = [
|
|
78
|
+
...validCachedOrder.map(id => cardMap.get(id)!),
|
|
79
|
+
...missingCards
|
|
80
|
+
];
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
setCardChartContainer(orderedCards);
|
|
84
|
+
|
|
85
|
+
const initialSizes: Record<
|
|
86
|
+
string,
|
|
87
|
+
{ spanCols: number; spanRows: number }
|
|
88
|
+
> = {};
|
|
89
|
+
|
|
90
|
+
cardCharts.forEach(c => {
|
|
91
|
+
const cachedSize = cachedSizes?.[c.id];
|
|
92
|
+
initialSizes[c.id] = {
|
|
93
|
+
spanCols: cachedSize?.spanCols ?? c.defaultSpan?.spanCols ?? 1,
|
|
94
|
+
spanRows: cachedSize?.spanRows ?? c.defaultSpan?.spanRows ?? 1,
|
|
95
|
+
};
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
setSizes(initialSizes);
|
|
99
|
+
} catch (error) {
|
|
100
|
+
// Fallback to default values if cache fails
|
|
101
|
+
console.warn('Failed to load dashboard data from cache:', error);
|
|
102
|
+
setCardChartContainer(cardCharts);
|
|
103
|
+
const fallbackSizes: Record<
|
|
104
|
+
string,
|
|
105
|
+
{ spanCols: number; spanRows: number }
|
|
106
|
+
> = {};
|
|
107
|
+
cardCharts.forEach(c => {
|
|
108
|
+
fallbackSizes[c.id] = {
|
|
109
|
+
spanCols: c.defaultSpan?.spanCols ?? 1,
|
|
110
|
+
spanRows: c.defaultSpan?.spanRows ?? 1,
|
|
111
|
+
};
|
|
112
|
+
});
|
|
113
|
+
setSizes(fallbackSizes);
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
initializeData();
|
|
118
|
+
}, [cardCharts, getData, getOrderData]);
|
|
119
|
+
|
|
120
|
+
// Save sizes to cache whenever they change
|
|
121
|
+
useEffect(() => {
|
|
122
|
+
const saveSizesToCache = async () => {
|
|
123
|
+
try {
|
|
124
|
+
await setData(DASHBOARD_LAYOUT_CACHE_KEY, sizes);
|
|
125
|
+
} catch (error) {
|
|
126
|
+
console.warn('Failed to save dashboard layout to cache:', error);
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
// Only save if sizes is not empty (avoid saving initial empty state)
|
|
131
|
+
if (Object.keys(sizes).length > 0) {
|
|
132
|
+
saveSizesToCache();
|
|
133
|
+
}
|
|
134
|
+
}, [sizes, setData]);
|
|
135
|
+
|
|
136
|
+
// Save card order to cache whenever it changes
|
|
137
|
+
useEffect(() => {
|
|
138
|
+
const saveOrderToCache = async () => {
|
|
139
|
+
try {
|
|
140
|
+
const cardOrder = CardChartContainer.map(card => card.id);
|
|
141
|
+
await setOrderData(DASHBOARD_ORDER_CACHE_KEY, cardOrder);
|
|
142
|
+
} catch (error) {
|
|
143
|
+
console.warn('Failed to save dashboard order to cache:', error);
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
// Only save if CardChartContainer is not empty
|
|
148
|
+
if (CardChartContainer.length > 0) {
|
|
149
|
+
saveOrderToCache();
|
|
150
|
+
}
|
|
151
|
+
}, [CardChartContainer, setOrderData]);
|
|
60
152
|
|
|
61
153
|
useEffect(() => {
|
|
62
154
|
if (containerWidth <= MINIMUM_DASHBOARD_WIDTH) {
|
|
@@ -110,12 +202,14 @@ export const Dashboard: React.FC<IDashboardProps> = ({
|
|
|
110
202
|
|
|
111
203
|
const handleZoomSelect = useCallback(
|
|
112
204
|
(id: string, span: { spanCols: number; spanRows: number }) => {
|
|
205
|
+
const newSizes = {
|
|
206
|
+
spanCols: Math.min(Math.max(span.spanCols, 1), maxZoom),
|
|
207
|
+
spanRows: Math.min(Math.max(span.spanRows, 1), maxSpanRows),
|
|
208
|
+
};
|
|
209
|
+
|
|
113
210
|
setSizes(prev => ({
|
|
114
211
|
...prev,
|
|
115
|
-
[id]:
|
|
116
|
-
spanCols: Math.min(Math.max(span.spanCols, 1), maxZoom),
|
|
117
|
-
spanRows: Math.min(Math.max(span.spanRows, 1), maxSpanRows),
|
|
118
|
-
},
|
|
212
|
+
[id]: newSizes,
|
|
119
213
|
}));
|
|
120
214
|
},
|
|
121
215
|
[maxZoom, maxSpanRows]
|
|
@@ -105,7 +105,7 @@ const ExampleDashboardUsage: React.FC<{ theme: Theme }> = ({ theme }) => {
|
|
|
105
105
|
cardCharts={cardChartContainers}
|
|
106
106
|
theme={theme ?? webLightTheme}
|
|
107
107
|
containerWidth={window.innerWidth}
|
|
108
|
-
containerHeight={window.innerHeight - 100} // Adjust height for header
|
|
108
|
+
containerHeight={(window.innerHeight - 100).toString()} // Adjust height for header
|
|
109
109
|
/>
|
|
110
110
|
</Stack>
|
|
111
111
|
);
|
package/src/hooks/index.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export * from './
|
|
1
|
+
export * from './useChartUtils';
|