@bundle-stats/ui 4.13.0-beta.9 → 4.13.0-rc.1
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/lib/app/app.js +4 -8
- package/lib/app/app.js.map +1 -1
- package/lib/app/app.module.css +2 -2
- package/lib/assets/icons.svg +70 -67
- package/lib/assets/icons.svg.js +14 -12
- package/lib/assets/icons.svg.js.map +1 -1
- package/lib/components/bundle-assets/bundle-assets.js +61 -26
- package/lib/components/bundle-assets/bundle-assets.js.map +1 -1
- package/lib/components/bundle-assets/bundle-assets.module.css +0 -5
- package/lib/components/bundle-assets/index.js +3 -1
- package/lib/components/bundle-assets/index.js.map +1 -1
- package/lib/components/bundle-assets-totals/bundle-assets-totals.js +14 -12
- package/lib/components/bundle-assets-totals/bundle-assets-totals.js.map +1 -1
- package/lib/components/bundle-modules/bundle-modules.i18n.js +1 -1
- package/lib/components/bundle-modules/bundle-modules.js +42 -15
- package/lib/components/bundle-modules/bundle-modules.js.map +1 -1
- package/lib/components/bundle-modules/bundle-modules.module.css +0 -5
- package/lib/components/bundle-modules/bundle-modules.utils.js +2 -13
- package/lib/components/bundle-modules/bundle-modules.utils.js.map +1 -1
- package/lib/components/bundle-modules/index.js +2 -1
- package/lib/components/bundle-modules/index.js.map +1 -1
- package/lib/components/bundle-packages/bundle-packages.js +48 -9
- package/lib/components/bundle-packages/bundle-packages.js.map +1 -1
- package/lib/components/bundle-packages/bundle-packages.module.css +0 -5
- package/lib/components/delta/delta.js +1 -1
- package/lib/components/delta/delta.js.map +1 -1
- package/lib/components/delta/delta.module.css +10 -1
- package/lib/components/jobs-header/jobs-header.module.css +0 -4
- package/lib/components/metrics-display-selector/metrics-display-selector.js +41 -4
- package/lib/components/metrics-display-selector/metrics-display-selector.js.map +1 -1
- package/lib/components/metrics-display-selector/metrics-display-selector.module.css +15 -7
- package/lib/components/metrics-treemap/index.js +4 -0
- package/lib/components/metrics-treemap/index.js.map +1 -1
- package/lib/components/metrics-treemap/metrics-treemap.constants.js +10 -0
- package/lib/components/metrics-treemap/metrics-treemap.constants.js.map +1 -0
- package/lib/components/metrics-treemap/metrics-treemap.i18n.js +6 -0
- package/lib/components/metrics-treemap/metrics-treemap.i18n.js.map +1 -0
- package/lib/components/metrics-treemap/metrics-treemap.js +131 -95
- package/lib/components/metrics-treemap/metrics-treemap.js.map +1 -1
- package/lib/components/metrics-treemap/metrics-treemap.module.css +179 -54
- package/lib/components/metrics-treemap/metrics-treemap.utils.js +168 -0
- package/lib/components/metrics-treemap/metrics-treemap.utils.js.map +1 -0
- package/lib/components/module-info/module-info.js +1 -2
- package/lib/components/module-info/module-info.js.map +1 -1
- package/lib/components/run-info/run-info.module.css +7 -7
- package/lib/css/variables.css +14 -13
- package/lib/hooks/metrics-display-type.js +45 -24
- package/lib/hooks/metrics-display-type.js.map +1 -1
- package/lib/hooks/search-params.js +1 -0
- package/lib/hooks/search-params.js.map +1 -1
- package/lib/layout/box/box.module.css +4 -2
- package/lib/layout/flex-stack/flex-stack.js +3 -4
- package/lib/layout/flex-stack/flex-stack.js.map +1 -1
- package/lib/layout/flex-stack/flex-stack.module.css +19 -23
- package/lib/ui/button/button.js +5 -4
- package/lib/ui/button/button.js.map +1 -1
- package/lib/ui/button/button.module.css +55 -53
- package/lib/ui/dropdown/dropdown.js +2 -2
- package/lib/ui/dropdown/dropdown.js.map +1 -1
- package/lib/ui/filters/filters.js +2 -2
- package/lib/ui/filters/filters.js.map +1 -1
- package/lib/ui/filters/filters.module.css +8 -1
- package/lib/ui/hover-card/hover-card.js +1 -1
- package/lib/ui/hover-card/hover-card.js.map +1 -1
- package/lib/ui/icon/icon.js +2 -1
- package/lib/ui/icon/icon.js.map +1 -1
- package/lib/ui/input-search/input-search.js +1 -1
- package/lib/ui/input-search/input-search.js.map +1 -1
- package/lib/ui/loader/loader.js +1 -1
- package/lib/ui/loader/loader.js.map +1 -1
- package/lib/ui/table/table.module.css +30 -0
- package/lib/ui/tag/tag.module.css +3 -3
- package/lib/ui/toolbar/toolbar.module.css +1 -3
- package/lib/utils/colors.js +22 -0
- package/lib/utils/colors.js.map +1 -0
- package/lib/{utils.js → utils/components.js} +2 -17
- package/lib/utils/components.js.map +1 -0
- package/lib/utils/index.js +20 -0
- package/lib/utils/index.js.map +1 -0
- package/lib/utils/jobs.js +18 -0
- package/lib/utils/jobs.js.map +1 -0
- package/lib-esm/app/app.js +4 -8
- package/lib-esm/app/app.js.map +1 -1
- package/lib-esm/app/app.module.css +2 -2
- package/lib-esm/assets/icons.svg +70 -67
- package/lib-esm/assets/icons.svg.js +14 -12
- package/lib-esm/assets/icons.svg.js.map +1 -1
- package/lib-esm/components/bundle-assets/bundle-assets.js +62 -28
- package/lib-esm/components/bundle-assets/bundle-assets.js.map +1 -1
- package/lib-esm/components/bundle-assets/bundle-assets.module.css +0 -5
- package/lib-esm/components/bundle-assets/index.js +3 -1
- package/lib-esm/components/bundle-assets/index.js.map +1 -1
- package/lib-esm/components/bundle-assets-totals/bundle-assets-totals.js +15 -13
- package/lib-esm/components/bundle-assets-totals/bundle-assets-totals.js.map +1 -1
- package/lib-esm/components/bundle-modules/bundle-modules.i18n.js +1 -1
- package/lib-esm/components/bundle-modules/bundle-modules.js +43 -16
- package/lib-esm/components/bundle-modules/bundle-modules.js.map +1 -1
- package/lib-esm/components/bundle-modules/bundle-modules.module.css +0 -5
- package/lib-esm/components/bundle-modules/bundle-modules.utils.js +1 -11
- package/lib-esm/components/bundle-modules/bundle-modules.utils.js.map +1 -1
- package/lib-esm/components/bundle-modules/index.js +3 -2
- package/lib-esm/components/bundle-modules/index.js.map +1 -1
- package/lib-esm/components/bundle-packages/bundle-packages.js +49 -10
- package/lib-esm/components/bundle-packages/bundle-packages.js.map +1 -1
- package/lib-esm/components/bundle-packages/bundle-packages.module.css +0 -5
- package/lib-esm/components/delta/delta.js +1 -1
- package/lib-esm/components/delta/delta.js.map +1 -1
- package/lib-esm/components/delta/delta.module.css +10 -1
- package/lib-esm/components/jobs-header/jobs-header.module.css +0 -4
- package/lib-esm/components/metrics-display-selector/metrics-display-selector.js +41 -4
- package/lib-esm/components/metrics-display-selector/metrics-display-selector.js.map +1 -1
- package/lib-esm/components/metrics-display-selector/metrics-display-selector.module.css +15 -7
- package/lib-esm/components/metrics-treemap/index.js +1 -0
- package/lib-esm/components/metrics-treemap/index.js.map +1 -1
- package/lib-esm/components/metrics-treemap/metrics-treemap.constants.js +7 -0
- package/lib-esm/components/metrics-treemap/metrics-treemap.constants.js.map +1 -0
- package/lib-esm/components/metrics-treemap/metrics-treemap.i18n.js +3 -0
- package/lib-esm/components/metrics-treemap/metrics-treemap.i18n.js.map +1 -0
- package/lib-esm/components/metrics-treemap/metrics-treemap.js +134 -98
- package/lib-esm/components/metrics-treemap/metrics-treemap.js.map +1 -1
- package/lib-esm/components/metrics-treemap/metrics-treemap.module.css +179 -54
- package/lib-esm/components/metrics-treemap/metrics-treemap.utils.js +162 -0
- package/lib-esm/components/metrics-treemap/metrics-treemap.utils.js.map +1 -0
- package/lib-esm/components/module-info/module-info.js +1 -2
- package/lib-esm/components/module-info/module-info.js.map +1 -1
- package/lib-esm/components/run-info/run-info.module.css +7 -7
- package/lib-esm/css/variables.css +14 -13
- package/lib-esm/hooks/metrics-display-type.js +46 -24
- package/lib-esm/hooks/metrics-display-type.js.map +1 -1
- package/lib-esm/hooks/search-params.js +1 -0
- package/lib-esm/hooks/search-params.js.map +1 -1
- package/lib-esm/layout/box/box.module.css +4 -2
- package/lib-esm/layout/flex-stack/flex-stack.js +3 -4
- package/lib-esm/layout/flex-stack/flex-stack.js.map +1 -1
- package/lib-esm/layout/flex-stack/flex-stack.module.css +19 -23
- package/lib-esm/ui/button/button.js +5 -4
- package/lib-esm/ui/button/button.js.map +1 -1
- package/lib-esm/ui/button/button.module.css +55 -53
- package/lib-esm/ui/dropdown/dropdown.js +2 -2
- package/lib-esm/ui/dropdown/dropdown.js.map +1 -1
- package/lib-esm/ui/filters/filters.js +2 -2
- package/lib-esm/ui/filters/filters.js.map +1 -1
- package/lib-esm/ui/filters/filters.module.css +8 -1
- package/lib-esm/ui/hover-card/hover-card.js +1 -1
- package/lib-esm/ui/hover-card/hover-card.js.map +1 -1
- package/lib-esm/ui/icon/icon.js +2 -1
- package/lib-esm/ui/icon/icon.js.map +1 -1
- package/lib-esm/ui/input-search/input-search.js +1 -1
- package/lib-esm/ui/input-search/input-search.js.map +1 -1
- package/lib-esm/ui/loader/loader.js +1 -1
- package/lib-esm/ui/loader/loader.js.map +1 -1
- package/lib-esm/ui/table/table.module.css +30 -0
- package/lib-esm/ui/tag/tag.module.css +3 -3
- package/lib-esm/ui/toolbar/toolbar.module.css +1 -3
- package/lib-esm/utils/colors.js +15 -0
- package/lib-esm/utils/colors.js.map +1 -0
- package/lib-esm/utils/components.js +16 -0
- package/lib-esm/utils/components.js.map +1 -0
- package/lib-esm/utils/index.js +4 -0
- package/lib-esm/utils/index.js.map +1 -0
- package/lib-esm/utils/jobs.js +11 -0
- package/lib-esm/utils/jobs.js.map +1 -0
- package/package.json +9 -9
- package/src/app/app.jsx +4 -12
- package/src/app/app.module.css +2 -2
- package/src/assets/icons/check.svg +4 -0
- package/src/assets/icons.svg +70 -67
- package/src/assets/icons.svg.jsx +12 -12
- package/src/components/bundle-assets/bundle-assets.jsx +147 -66
- package/src/components/bundle-assets/bundle-assets.module.css +0 -5
- package/src/components/bundle-assets/index.jsx +4 -0
- package/src/components/bundle-assets-totals/bundle-assets-totals.jsx +53 -46
- package/src/components/bundle-modules/bundle-modules.i18n.ts +1 -1
- package/src/components/bundle-modules/bundle-modules.module.css +0 -5
- package/src/components/bundle-modules/bundle-modules.tsx +140 -56
- package/src/components/bundle-modules/bundle-modules.types.d.ts +2 -17
- package/src/components/bundle-modules/bundle-modules.utils.ts +7 -18
- package/src/components/bundle-modules/index.tsx +4 -3
- package/src/components/bundle-packages/bundle-packages.jsx +89 -20
- package/src/components/bundle-packages/bundle-packages.module.css +0 -5
- package/src/components/delta/delta.jsx +1 -1
- package/src/components/delta/delta.module.css +10 -1
- package/src/components/jobs-header/jobs-header.module.css +0 -4
- package/src/components/metrics-display-selector/metrics-display-selector.module.css +15 -7
- package/src/components/metrics-display-selector/metrics-display-selector.stories.tsx +33 -0
- package/src/components/metrics-display-selector/metrics-display-selector.tsx +83 -25
- package/src/components/metrics-treemap/__tests__/metrics-treemap.utils.ts +188 -0
- package/src/components/metrics-treemap/index.ts +1 -0
- package/src/components/metrics-treemap/metrics-treemap.constants.ts +63 -0
- package/src/components/metrics-treemap/metrics-treemap.i18n.ts +2 -0
- package/src/components/metrics-treemap/metrics-treemap.module.css +179 -54
- package/src/components/metrics-treemap/metrics-treemap.stories.tsx +44 -10
- package/src/components/metrics-treemap/metrics-treemap.tsx +453 -184
- package/src/components/metrics-treemap/metrics-treemap.utils.ts +268 -0
- package/src/components/module-info/module-info.tsx +1 -1
- package/src/components/run-info/run-info.module.css +7 -7
- package/src/css/variables.css +14 -13
- package/src/hooks/metrics-display-type.ts +79 -29
- package/src/hooks/search-params.js +1 -0
- package/src/layout/box/box.module.css +4 -2
- package/src/layout/flex-stack/flex-stack.module.css +19 -23
- package/src/layout/flex-stack/flex-stack.tsx +2 -8
- package/src/ui/button/button.module.css +55 -53
- package/src/ui/button/button.stories.tsx +16 -9
- package/src/ui/button/button.tsx +8 -7
- package/src/ui/dropdown/dropdown.tsx +2 -3
- package/src/ui/filters/filters.module.css +8 -1
- package/src/ui/filters/filters.tsx +2 -3
- package/src/ui/hover-card/hover-card.tsx +1 -1
- package/src/ui/icon/icon.tsx +2 -1
- package/src/ui/input-search/input-search.tsx +1 -0
- package/src/ui/loader/loader.jsx +1 -1
- package/src/ui/table/table.module.css +30 -0
- package/src/ui/tag/tag.module.css +3 -3
- package/src/ui/toolbar/toolbar.module.css +1 -3
- package/src/utils/colors.ts +19 -0
- package/src/utils/components.tsx +19 -0
- package/src/utils/index.ts +3 -0
- package/src/utils/jobs.ts +22 -0
- package/types/components/bundle-assets/bundle-assets.d.ts +1 -5
- package/types/components/bundle-modules/bundle-modules.d.ts +4 -2
- package/types/components/bundle-modules/bundle-modules.i18n.d.ts +1 -1
- package/types/components/bundle-modules/bundle-modules.utils.d.ts +3 -7
- package/types/components/bundle-modules/index.d.ts +2 -2
- package/types/components/delta/delta.d.ts +2 -2
- package/types/components/metrics-display-selector/metrics-display-selector.d.ts +3 -1
- package/types/components/metrics-treemap/index.d.ts +1 -0
- package/types/components/metrics-treemap/metrics-treemap.constants.d.ts +28 -0
- package/types/components/metrics-treemap/metrics-treemap.d.ts +7 -5
- package/types/components/metrics-treemap/metrics-treemap.i18n.d.ts +2 -0
- package/types/components/metrics-treemap/metrics-treemap.utils.d.ts +15 -0
- package/types/hooks/metrics-display-type.d.ts +8 -2
- package/types/ui/dropdown/dropdown.d.ts +0 -1
- package/types/ui/icon/icon.d.ts +4 -2
- package/types/ui/loader/loader.d.ts +2 -2
- package/types/utils/colors.d.ts +1 -0
- package/types/utils/components.d.ts +2 -0
- package/types/utils/index.d.ts +3 -0
- package/types/utils/jobs.d.ts +7 -0
- package/lib/components/bundle-assets-totals/bundle-assets-totals.module.css +0 -7
- package/lib/utils.js.map +0 -1
- package/lib-esm/components/bundle-assets-totals/bundle-assets-totals.module.css +0 -7
- package/lib-esm/utils.js +0 -30
- package/lib-esm/utils.js.map +0 -1
- package/src/components/bundle-assets-totals/bundle-assets-totals.module.css +0 -7
- package/src/utils.jsx +0 -38
- package/types/utils.d.ts +0 -3
|
@@ -1,65 +1,65 @@
|
|
|
1
|
-
import React, {
|
|
2
|
-
|
|
1
|
+
import React, {
|
|
2
|
+
type ComponentProps,
|
|
3
|
+
type MouseEventHandler,
|
|
4
|
+
type ReactNode,
|
|
5
|
+
type Ref,
|
|
6
|
+
type RefObject,
|
|
7
|
+
forwardRef,
|
|
8
|
+
useCallback,
|
|
9
|
+
useMemo,
|
|
10
|
+
useRef,
|
|
11
|
+
} from 'react';
|
|
12
|
+
import { useHoverDirty, useMeasure } from 'react-use';
|
|
3
13
|
import cx from 'classnames';
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
14
|
+
import { HierarchyRectangularNode, hierarchy, treemap, treemapSquarify } from 'd3';
|
|
15
|
+
import { Tooltip, TooltipArrow, TooltipAnchor } from 'ariakit/tooltip';
|
|
16
|
+
import {
|
|
17
|
+
type ReportMetricRow,
|
|
18
|
+
type MetricRunInfo,
|
|
19
|
+
type MetricRunInfoBaseline,
|
|
20
|
+
METRIC_TYPE_CONFIGS,
|
|
21
|
+
formatFileSize,
|
|
22
|
+
getMetricRunInfo,
|
|
23
|
+
} from '@bundle-stats/utils';
|
|
7
24
|
|
|
8
25
|
import { Stack } from '../../layout/stack';
|
|
9
26
|
import { FileName } from '../../ui/file-name';
|
|
10
27
|
import { Delta } from '../delta';
|
|
11
28
|
import { RunInfo } from '../run-info';
|
|
29
|
+
import {
|
|
30
|
+
type TreeLeaf,
|
|
31
|
+
type TreeNode,
|
|
32
|
+
type Tree,
|
|
33
|
+
SQUARIFY_RATIO,
|
|
34
|
+
PADDING_OUTER,
|
|
35
|
+
PADDING_INNER,
|
|
36
|
+
NESTED_PADDING,
|
|
37
|
+
NESTED_PADDING_TOP,
|
|
38
|
+
NESTED_PADDING_LEFT,
|
|
39
|
+
TileSizeDisplay,
|
|
40
|
+
} from './metrics-treemap.constants';
|
|
41
|
+
import * as I18N from './metrics-treemap.i18n';
|
|
12
42
|
import css from './metrics-treemap.module.css';
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
* Resolve the tile size using predefined values to avoid
|
|
22
|
-
* computing the size of the content for every tile
|
|
23
|
-
*/
|
|
24
|
-
const PADDING_TOP = 4;
|
|
25
|
-
const PADDING_BOTTOM = 2; // substracted to allow longer texts to appear
|
|
26
|
-
const PADDING_LEFT = 16;
|
|
27
|
-
const PADDING_RIGHT = 4; // substracted to allow longer texts to not break
|
|
28
|
-
const VERTICAL_SPACING = 4;
|
|
29
|
-
const LINE_HEIGHT = 16;
|
|
30
|
-
const LINE_HEIGHT_SMALL = 13.3;
|
|
31
|
-
|
|
32
|
-
function resolveLeafSizeDisplay(width: number, height: number): TileSizeDisplay {
|
|
33
|
-
if (
|
|
34
|
-
height > PADDING_TOP + PADDING_BOTTOM + VERTICAL_SPACING + LINE_HEIGHT * 2 &&
|
|
35
|
-
width > PADDING_LEFT + PADDING_RIGHT + 128
|
|
36
|
-
) {
|
|
37
|
-
return 'default';
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
if (
|
|
41
|
-
height > PADDING_TOP + PADDING_BOTTOM + LINE_HEIGHT_SMALL * 2 &&
|
|
42
|
-
width > PADDING_LEFT + PADDING_BOTTOM + 48
|
|
43
|
-
) {
|
|
44
|
-
return 'small';
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
return 'minimal';
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
interface LeafTooltipContentProps {
|
|
43
|
+
import {
|
|
44
|
+
resolveGroupDeltaType,
|
|
45
|
+
resolveTileSizeDisplay,
|
|
46
|
+
resolveTileGroupSizeDisplay,
|
|
47
|
+
useTooltipStateWithMouseFollow,
|
|
48
|
+
} from './metrics-treemap.utils';
|
|
49
|
+
|
|
50
|
+
interface TileTooltipContentProps {
|
|
51
51
|
item: ReportMetricRow;
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
const
|
|
54
|
+
const TileTooltipContent = (props: TileTooltipContentProps) => {
|
|
55
55
|
const { item } = props;
|
|
56
56
|
|
|
57
57
|
const currentRun = item.runs[0] as MetricRunInfo;
|
|
58
58
|
const baselineRun = item.runs[item.runs.length - 1] as MetricRunInfoBaseline;
|
|
59
59
|
|
|
60
60
|
return (
|
|
61
|
-
<Stack space="small" className={css.
|
|
62
|
-
<h3 className={css.
|
|
61
|
+
<Stack space="small" className={css.tileTooltipContent}>
|
|
62
|
+
<h3 className={css.tileTooltipContentTitle}>
|
|
63
63
|
<FileName as="code" name={item.label} />
|
|
64
64
|
</h3>
|
|
65
65
|
<RunInfo
|
|
@@ -72,227 +72,496 @@ const LeafTooltipContent = (props: LeafTooltipContentProps) => {
|
|
|
72
72
|
);
|
|
73
73
|
};
|
|
74
74
|
|
|
75
|
-
interface
|
|
76
|
-
|
|
75
|
+
interface TileContentProps {
|
|
76
|
+
/**
|
|
77
|
+
* Node label
|
|
78
|
+
*/
|
|
79
|
+
label: string;
|
|
80
|
+
/**
|
|
81
|
+
* Tile id - metric label or basename for grouped tiles
|
|
82
|
+
*/
|
|
77
83
|
item: ReportMetricRow;
|
|
84
|
+
/**
|
|
85
|
+
* The estimated size of the tile
|
|
86
|
+
*/
|
|
87
|
+
sizeDisplay: TileSizeDisplay;
|
|
88
|
+
/**
|
|
89
|
+
* Metric run info
|
|
90
|
+
*/
|
|
78
91
|
runInfo: MetricRunInfo;
|
|
79
92
|
}
|
|
80
93
|
|
|
81
|
-
const
|
|
82
|
-
const { sizeDisplay, item, runInfo } = props;
|
|
94
|
+
const TileContent = forwardRef((props: TileContentProps, ref: Ref<HTMLDivElement>) => {
|
|
95
|
+
const { label, sizeDisplay, item, runInfo } = props;
|
|
83
96
|
|
|
97
|
+
// Render only the container
|
|
84
98
|
if (sizeDisplay === 'minimal') {
|
|
85
|
-
return <div className={css.
|
|
99
|
+
return <div className={css.tileContent} ref={ref} />;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const resolvedLabel = label || item.label;
|
|
103
|
+
|
|
104
|
+
// Render only the label
|
|
105
|
+
if (sizeDisplay === 'small') {
|
|
106
|
+
return (
|
|
107
|
+
<div className={css.tileContent} ref={ref}>
|
|
108
|
+
<p className={css.tileContentLabel}>{resolvedLabel}</p>
|
|
109
|
+
</div>
|
|
110
|
+
);
|
|
86
111
|
}
|
|
87
112
|
|
|
88
113
|
return (
|
|
89
|
-
<div className={css.
|
|
90
|
-
<
|
|
91
|
-
{
|
|
92
|
-
<
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
</p>
|
|
100
|
-
)}
|
|
114
|
+
<div className={css.tileContent} ref={ref}>
|
|
115
|
+
<p className={css.tileContentLabel}>{label || item.label}</p>
|
|
116
|
+
<p className={css.tileContentValue}>
|
|
117
|
+
<span className={css.tileContentMetric}>{runInfo.displayValue}</span>
|
|
118
|
+
<Delta
|
|
119
|
+
className={css.tileContentDelta}
|
|
120
|
+
displayValue={runInfo.displayDeltaPercentage}
|
|
121
|
+
deltaType={runInfo.deltaType}
|
|
122
|
+
/>
|
|
123
|
+
</p>
|
|
101
124
|
</div>
|
|
102
125
|
);
|
|
103
126
|
});
|
|
104
127
|
|
|
105
|
-
const
|
|
106
|
-
const { sizeDisplay, item, runInfo, parentRef } = props;
|
|
128
|
+
const TileContentWithTooltip = (props: TileContentProps & { parentRef: RefObject<Element> }) => {
|
|
129
|
+
const { label, sizeDisplay, item, runInfo, parentRef } = props;
|
|
107
130
|
|
|
108
|
-
const
|
|
109
|
-
|
|
110
|
-
// Return custom rect based on the mouse position
|
|
111
|
-
const getAnchorRect = useCallback(() => {
|
|
112
|
-
// Skip custom component rect area if the pointer position is empty
|
|
113
|
-
if (pointer.docX === 0 && pointer.docY === 0 && pointer.elW === 0 && pointer.elH === 0) {
|
|
114
|
-
return null;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
const newRect = {
|
|
118
|
-
x: pointer.docX - (document?.defaultView?.scrollX ?? 0),
|
|
119
|
-
y: pointer.docY - (document?.defaultView?.scrollY ?? 0),
|
|
120
|
-
w: 1,
|
|
121
|
-
h: 1,
|
|
122
|
-
};
|
|
123
|
-
|
|
124
|
-
return newRect;
|
|
125
|
-
}, [pointer.docX, pointer.docY]);
|
|
126
|
-
|
|
127
|
-
const tooltipState = useTooltipState({ gutter: 12, getAnchorRect, timeout: 120 });
|
|
128
|
-
|
|
129
|
-
// Update tooltip position when poiner values are changing
|
|
130
|
-
useDebounce(tooltipState.render, 5, [pointer.docX, pointer.docY]);
|
|
131
|
+
const tooltipState = useTooltipStateWithMouseFollow({ parentRef });
|
|
131
132
|
|
|
132
133
|
return (
|
|
133
134
|
<>
|
|
134
|
-
<TooltipAnchor state={tooltipState} className={css.
|
|
135
|
-
<
|
|
135
|
+
<TooltipAnchor state={tooltipState} className={css.tileContentTooltipAnchor}>
|
|
136
|
+
<TileContent label={label} sizeDisplay={sizeDisplay} item={item} runInfo={runInfo} />
|
|
136
137
|
</TooltipAnchor>
|
|
137
138
|
<Tooltip state={tooltipState} className={css.tooltip}>
|
|
138
|
-
<TooltipArrow state={tooltipState} size={16} className={css.
|
|
139
|
-
<
|
|
139
|
+
<TooltipArrow state={tooltipState} size={16} className={css.tileTooltipArrow} />
|
|
140
|
+
<TileTooltipContent item={item} />
|
|
140
141
|
</Tooltip>
|
|
141
142
|
</>
|
|
142
143
|
);
|
|
143
144
|
};
|
|
144
145
|
|
|
145
|
-
interface
|
|
146
|
-
id: string;
|
|
147
|
-
value: number;
|
|
148
|
-
item: ReportMetricRow;
|
|
149
|
-
children?: Array<TreeNode>;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
interface RootTree {
|
|
153
|
-
id: string;
|
|
154
|
-
value: number;
|
|
155
|
-
children: Array<TreeNode>;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
interface LeafProps {
|
|
146
|
+
interface TileProps {
|
|
159
147
|
left: number;
|
|
160
148
|
top: number;
|
|
161
149
|
width: number;
|
|
162
150
|
height: number;
|
|
163
|
-
data:
|
|
151
|
+
data: TreeLeaf;
|
|
164
152
|
onClick?: (id: string) => void;
|
|
165
153
|
}
|
|
166
154
|
|
|
167
|
-
const
|
|
155
|
+
const Tile = (props: TileProps) => {
|
|
168
156
|
const { left, top, width, height, data, onClick } = props;
|
|
169
157
|
|
|
170
|
-
const { item } = data;
|
|
158
|
+
const { item, label } = data;
|
|
171
159
|
const runInfo = item.runs?.[0] as MetricRunInfo;
|
|
172
160
|
|
|
173
|
-
const sizeDisplay = useMemo(() =>
|
|
174
|
-
const handleOnClick = useCallback(
|
|
161
|
+
const sizeDisplay = useMemo(() => resolveTileSizeDisplay(width, height), [width, height]);
|
|
162
|
+
const handleOnClick: MouseEventHandler<HTMLDivElement> = useCallback(
|
|
163
|
+
(event) => {
|
|
164
|
+
event.stopPropagation();
|
|
165
|
+
onClick?.(item.key);
|
|
166
|
+
},
|
|
167
|
+
[item.key, onClick],
|
|
168
|
+
);
|
|
175
169
|
|
|
176
|
-
const
|
|
177
|
-
const hover = useHoverDirty(
|
|
170
|
+
const contentRef = useRef<HTMLDivElement>(null);
|
|
171
|
+
const hover = useHoverDirty(contentRef);
|
|
178
172
|
|
|
179
|
-
const
|
|
180
|
-
css.
|
|
181
|
-
css[`
|
|
182
|
-
sizeDisplay === 'small' && css.
|
|
183
|
-
|
|
173
|
+
const className = cx(
|
|
174
|
+
css.tile,
|
|
175
|
+
css[`tile-${runInfo.deltaType}`],
|
|
176
|
+
sizeDisplay === 'small' && css.tileSizeSmall,
|
|
177
|
+
sizeDisplay === 'default' && css.tileSizeDefault,
|
|
178
|
+
left === PADDING_INNER && css.tileFirstCol,
|
|
184
179
|
);
|
|
185
180
|
|
|
181
|
+
/* eslint-disable jsx-a11y/click-events-have-key-events, jsx-a11y/interactive-supports-focus */
|
|
186
182
|
return (
|
|
187
|
-
<
|
|
188
|
-
type="button"
|
|
183
|
+
<div
|
|
189
184
|
onClick={handleOnClick}
|
|
190
|
-
|
|
185
|
+
role="button"
|
|
186
|
+
aria-label={I18N.TILE_LABEL}
|
|
187
|
+
ref={contentRef}
|
|
191
188
|
style={{ left, top, width, height }}
|
|
192
|
-
className={
|
|
189
|
+
className={className}
|
|
193
190
|
>
|
|
194
191
|
{hover ? (
|
|
195
|
-
<
|
|
192
|
+
<TileContentWithTooltip
|
|
193
|
+
label={label}
|
|
196
194
|
sizeDisplay={sizeDisplay}
|
|
197
195
|
item={item}
|
|
198
196
|
runInfo={runInfo}
|
|
199
|
-
parentRef={
|
|
197
|
+
parentRef={contentRef}
|
|
198
|
+
/>
|
|
199
|
+
) : (
|
|
200
|
+
<TileContent label={label} sizeDisplay={sizeDisplay} item={item} runInfo={runInfo} />
|
|
201
|
+
)}
|
|
202
|
+
</div>
|
|
203
|
+
);
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
interface TileGroupTitleTooltipContentProps {
|
|
207
|
+
title: string;
|
|
208
|
+
runInfo: MetricRunInfo;
|
|
209
|
+
baselineDisplayValue?: string;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const TileGroupTitleTooltipContent = (props: TileGroupTitleTooltipContentProps) => {
|
|
213
|
+
const { title, runInfo, baselineDisplayValue } = props;
|
|
214
|
+
|
|
215
|
+
return (
|
|
216
|
+
<Stack space="small" className={css.tileTooltip}>
|
|
217
|
+
<h3 className={css.tileTooltipContentTitle}>
|
|
218
|
+
<FileName as="code" name={title} />
|
|
219
|
+
</h3>
|
|
220
|
+
<RunInfo
|
|
221
|
+
current={runInfo.displayValue}
|
|
222
|
+
baseline={baselineDisplayValue}
|
|
223
|
+
delta={runInfo.displayDeltaPercentage}
|
|
224
|
+
deltaType={runInfo.deltaType}
|
|
225
|
+
/>
|
|
226
|
+
</Stack>
|
|
227
|
+
);
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
interface TileGroupTitleContentProps {
|
|
231
|
+
title?: string;
|
|
232
|
+
runInfo?: MetricRunInfo;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
const TileGroupTitleContent = (props: TileGroupTitleContentProps) => {
|
|
236
|
+
const { title, runInfo } = props;
|
|
237
|
+
|
|
238
|
+
return (
|
|
239
|
+
<div className={css.tileGroupTitleContent}>
|
|
240
|
+
{title && <span className={css.tileGroupTitleText}>{title}</span>}
|
|
241
|
+
{runInfo && (
|
|
242
|
+
<span className={css.tileGroupTitleTotal}>
|
|
243
|
+
{runInfo.displayValue}
|
|
244
|
+
{'displayDelta' in runInfo && `(${runInfo.displayDeltaPercentage})`}
|
|
245
|
+
</span>
|
|
246
|
+
)}
|
|
247
|
+
</div>
|
|
248
|
+
);
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
type TileGroupTitleContentWithTooltipProps = {
|
|
252
|
+
parentRef: RefObject<Element>;
|
|
253
|
+
tooltipContent: TileGroupTitleTooltipContentProps;
|
|
254
|
+
} & TileGroupTitleContentProps;
|
|
255
|
+
|
|
256
|
+
const TileGroupTitleContentWithTooltip = (props: TileGroupTitleContentWithTooltipProps) => {
|
|
257
|
+
const { parentRef, tooltipContent, ...restProps } = props;
|
|
258
|
+
|
|
259
|
+
const tooltipState = useTooltipStateWithMouseFollow({ parentRef });
|
|
260
|
+
|
|
261
|
+
return (
|
|
262
|
+
<>
|
|
263
|
+
<TooltipAnchor state={tooltipState} className={css.tileContentTooltipAnchor}>
|
|
264
|
+
<TileGroupTitleContent {...restProps} />
|
|
265
|
+
</TooltipAnchor>
|
|
266
|
+
<Tooltip state={tooltipState} className={css.tooltip}>
|
|
267
|
+
<TooltipArrow state={tooltipState} size={16} className={css.tileTooltipArrow} />
|
|
268
|
+
<TileGroupTitleTooltipContent {...tooltipContent} />
|
|
269
|
+
</Tooltip>
|
|
270
|
+
</>
|
|
271
|
+
);
|
|
272
|
+
};
|
|
273
|
+
|
|
274
|
+
type TileGroupTitleProps = Omit<TileGroupTitleContentWithTooltipProps, 'parentRef'>;
|
|
275
|
+
|
|
276
|
+
const TileGroupTitle = (props: TileGroupTitleProps) => {
|
|
277
|
+
const { tooltipContent, ...restProps } = props;
|
|
278
|
+
const contentRef = useRef<HTMLDivElement>(null);
|
|
279
|
+
const hover = useHoverDirty(contentRef);
|
|
280
|
+
|
|
281
|
+
return (
|
|
282
|
+
<div className={css.tileGroupTitle} ref={contentRef}>
|
|
283
|
+
{hover ? (
|
|
284
|
+
<TileGroupTitleContentWithTooltip
|
|
285
|
+
parentRef={contentRef}
|
|
286
|
+
tooltipContent={tooltipContent}
|
|
287
|
+
{...restProps}
|
|
200
288
|
/>
|
|
201
289
|
) : (
|
|
202
|
-
<
|
|
290
|
+
<TileGroupTitleContent {...restProps} />
|
|
203
291
|
)}
|
|
204
|
-
</
|
|
292
|
+
</div>
|
|
293
|
+
);
|
|
294
|
+
};
|
|
295
|
+
|
|
296
|
+
interface TileGroupProps extends ComponentProps<'div'> {
|
|
297
|
+
/**
|
|
298
|
+
* Node title
|
|
299
|
+
*/
|
|
300
|
+
title?: string;
|
|
301
|
+
/**
|
|
302
|
+
* Group sum
|
|
303
|
+
*/
|
|
304
|
+
total?: Tree['total'];
|
|
305
|
+
/**
|
|
306
|
+
* Node id
|
|
307
|
+
*/
|
|
308
|
+
id: string;
|
|
309
|
+
/**
|
|
310
|
+
* Node children
|
|
311
|
+
*/
|
|
312
|
+
childNodes: HierarchyRectangularNode<TreeNode>['children'];
|
|
313
|
+
/**
|
|
314
|
+
* On click tile handler
|
|
315
|
+
*/
|
|
316
|
+
onItemClick: TileProps['onClick'];
|
|
317
|
+
/**
|
|
318
|
+
* On click group title
|
|
319
|
+
*/
|
|
320
|
+
onGroupClick?: (groupId: string) => void;
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* Node rectangle dimensions
|
|
324
|
+
*/
|
|
325
|
+
width?: number;
|
|
326
|
+
height?: number;
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Node rectangle relative coordinates (relative to parent)
|
|
330
|
+
*/
|
|
331
|
+
left: number;
|
|
332
|
+
top: number;
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* Node rectangle absolute coordinates (relative to canvas)
|
|
336
|
+
*/
|
|
337
|
+
absoluteLeft: number;
|
|
338
|
+
absoluteTop: number;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
const TileGroup = (props: TileGroupProps) => {
|
|
342
|
+
const {
|
|
343
|
+
title = '',
|
|
344
|
+
total,
|
|
345
|
+
id,
|
|
346
|
+
childNodes,
|
|
347
|
+
onItemClick,
|
|
348
|
+
onGroupClick,
|
|
349
|
+
left,
|
|
350
|
+
top,
|
|
351
|
+
width,
|
|
352
|
+
height,
|
|
353
|
+
absoluteLeft,
|
|
354
|
+
absoluteTop,
|
|
355
|
+
} = props;
|
|
356
|
+
|
|
357
|
+
const onClick: MouseEventHandler<HTMLDivElement> = useCallback(
|
|
358
|
+
(event) => {
|
|
359
|
+
onGroupClick?.(id);
|
|
360
|
+
event.stopPropagation();
|
|
361
|
+
},
|
|
362
|
+
[onGroupClick, id],
|
|
363
|
+
);
|
|
364
|
+
|
|
365
|
+
const displaySize = useMemo(
|
|
366
|
+
() => resolveTileGroupSizeDisplay(width || 0, height || 0),
|
|
367
|
+
[width, height],
|
|
368
|
+
);
|
|
369
|
+
|
|
370
|
+
// Prepare data
|
|
371
|
+
const [runInfo, baselineDisplayValue, deltaType] = useMemo(() => {
|
|
372
|
+
if (!total) {
|
|
373
|
+
return [];
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
const resolvedRunInfo = getMetricRunInfo(
|
|
377
|
+
METRIC_TYPE_CONFIGS.METRIC_TYPE_FILE_SIZE,
|
|
378
|
+
total.current,
|
|
379
|
+
total.baseline,
|
|
380
|
+
) as MetricRunInfo;
|
|
381
|
+
const resolvedBaselineDisplayValue = formatFileSize(total.baseline);
|
|
382
|
+
const resolvedDeltaType = resolveGroupDeltaType(resolvedRunInfo);
|
|
383
|
+
|
|
384
|
+
return [resolvedRunInfo, resolvedBaselineDisplayValue, resolvedDeltaType];
|
|
385
|
+
}, [total]);
|
|
386
|
+
|
|
387
|
+
const rootClassName = cx(
|
|
388
|
+
css.tileGroup,
|
|
389
|
+
css[`tileGroup--${deltaType}`],
|
|
390
|
+
css[`tileGroup--${displaySize}`],
|
|
391
|
+
);
|
|
392
|
+
|
|
393
|
+
// Tooltip data
|
|
394
|
+
// - by default show the node id (full path) as title
|
|
395
|
+
const tooltipContent = {
|
|
396
|
+
title: id || title,
|
|
397
|
+
runInfo,
|
|
398
|
+
baselineDisplayValue,
|
|
399
|
+
} as TileGroupTitleTooltipContentProps;
|
|
400
|
+
|
|
401
|
+
if (title && displaySize === 'minimal') {
|
|
402
|
+
return (
|
|
403
|
+
<div
|
|
404
|
+
onClick={onClick}
|
|
405
|
+
role="button"
|
|
406
|
+
aria-label={I18N.TILE_GROUP_LABEL}
|
|
407
|
+
className={rootClassName}
|
|
408
|
+
style={{ left, top, width, height }}
|
|
409
|
+
>
|
|
410
|
+
<TileGroupTitle tooltipContent={tooltipContent} />
|
|
411
|
+
</div>
|
|
412
|
+
);
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
if (title && displaySize === 'small') {
|
|
416
|
+
return (
|
|
417
|
+
<div
|
|
418
|
+
onClick={onClick}
|
|
419
|
+
role="button"
|
|
420
|
+
aria-label={I18N.TILE_GROUP_LABEL}
|
|
421
|
+
style={{ left, top, width, height }}
|
|
422
|
+
className={rootClassName}
|
|
423
|
+
>
|
|
424
|
+
<TileGroupTitle title={title} tooltipContent={tooltipContent} />
|
|
425
|
+
</div>
|
|
426
|
+
);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
return (
|
|
430
|
+
<div
|
|
431
|
+
onClick={onClick}
|
|
432
|
+
role="button"
|
|
433
|
+
aria-label={I18N.TILE_GROUP_LABEL}
|
|
434
|
+
className={cx(rootClassName, css.tileGroupSizeDefault)}
|
|
435
|
+
style={{ left, top, width, height }}
|
|
436
|
+
>
|
|
437
|
+
<TileGroupTitle title={title} runInfo={runInfo} tooltipContent={tooltipContent} />
|
|
438
|
+
{childNodes?.map((childNode) => {
|
|
439
|
+
if ('children' in childNode) {
|
|
440
|
+
const groupData = childNode.data as Tree;
|
|
441
|
+
|
|
442
|
+
return (
|
|
443
|
+
<TileGroup
|
|
444
|
+
title={groupData.label}
|
|
445
|
+
total={groupData.total}
|
|
446
|
+
id={groupData.id}
|
|
447
|
+
childNodes={childNode.children}
|
|
448
|
+
left={childNode.x0 - absoluteLeft}
|
|
449
|
+
top={childNode.y0 - absoluteTop}
|
|
450
|
+
absoluteLeft={childNode.x0}
|
|
451
|
+
absoluteTop={childNode.y0}
|
|
452
|
+
width={childNode.x1 - childNode.x0}
|
|
453
|
+
height={childNode.y1 - childNode.y0}
|
|
454
|
+
onItemClick={onItemClick}
|
|
455
|
+
onGroupClick={onGroupClick}
|
|
456
|
+
key={groupData.id}
|
|
457
|
+
/>
|
|
458
|
+
);
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
return (
|
|
462
|
+
<Tile
|
|
463
|
+
data={childNode.data as TreeLeaf}
|
|
464
|
+
left={childNode.x0 - absoluteLeft}
|
|
465
|
+
top={childNode.y0 - absoluteTop}
|
|
466
|
+
width={childNode.x1 - childNode.x0}
|
|
467
|
+
height={childNode.y1 - childNode.y0}
|
|
468
|
+
onClick={onItemClick}
|
|
469
|
+
key={childNode.data.id}
|
|
470
|
+
/>
|
|
471
|
+
);
|
|
472
|
+
})}
|
|
473
|
+
</div>
|
|
205
474
|
);
|
|
206
475
|
};
|
|
207
476
|
|
|
208
477
|
interface UseMetricsTreemapHierarchyParams {
|
|
209
|
-
|
|
478
|
+
treeNodes: Tree;
|
|
210
479
|
width: number;
|
|
211
480
|
height: number;
|
|
481
|
+
nested: boolean;
|
|
212
482
|
}
|
|
213
483
|
|
|
214
484
|
function useMetricsTreemapHierarchy(params: UseMetricsTreemapHierarchyParams) {
|
|
215
|
-
const {
|
|
485
|
+
const { treeNodes, width, height, nested } = params;
|
|
216
486
|
|
|
217
487
|
const treemapHierarchy = useMemo(() => {
|
|
218
|
-
const
|
|
219
|
-
|
|
220
|
-
* Set leaf value to the largest run value to allow to
|
|
221
|
-
* display the impact of deleted / items
|
|
222
|
-
*/
|
|
223
|
-
const values = item.runs.map((run) => run?.value || 0);
|
|
224
|
-
const value = Math.max(...values);
|
|
225
|
-
|
|
226
|
-
return {
|
|
227
|
-
id: item.key,
|
|
228
|
-
value,
|
|
229
|
-
item,
|
|
230
|
-
};
|
|
231
|
-
});
|
|
232
|
-
|
|
233
|
-
const treemapData = {
|
|
234
|
-
id: 'root',
|
|
235
|
-
name: 'root',
|
|
236
|
-
value: 0,
|
|
237
|
-
children,
|
|
238
|
-
};
|
|
239
|
-
|
|
240
|
-
const customHierarchy = hierarchy<RootTree>(treemapData);
|
|
488
|
+
const customHierarchy = hierarchy<Tree>(treeNodes);
|
|
489
|
+
|
|
241
490
|
customHierarchy.sum((node) => node.value);
|
|
491
|
+
// sort by value descending for all cases
|
|
242
492
|
// @ts-expect-error
|
|
243
493
|
customHierarchy.sort((a, b) => b.value - a.value);
|
|
244
494
|
|
|
245
495
|
return customHierarchy;
|
|
246
|
-
}, [
|
|
496
|
+
}, [treeNodes]);
|
|
247
497
|
|
|
248
|
-
const
|
|
249
|
-
|
|
498
|
+
const treemapNodes = useMemo(() => {
|
|
499
|
+
let createTremapLayout = treemap()
|
|
250
500
|
.size([width, height])
|
|
251
501
|
.tile(treemapSquarify.ratio(SQUARIFY_RATIO))
|
|
252
|
-
.paddingOuter(PADDING_OUTER)
|
|
253
|
-
|
|
254
|
-
//
|
|
255
|
-
|
|
502
|
+
.paddingOuter(PADDING_OUTER);
|
|
503
|
+
|
|
504
|
+
// Add padding top for group title
|
|
505
|
+
if (nested) {
|
|
506
|
+
createTremapLayout = createTremapLayout
|
|
507
|
+
.padding(NESTED_PADDING)
|
|
508
|
+
.paddingLeft(NESTED_PADDING_LEFT)
|
|
509
|
+
.paddingTop(NESTED_PADDING_TOP);
|
|
510
|
+
} else {
|
|
511
|
+
createTremapLayout = createTremapLayout.paddingInner(PADDING_INNER);
|
|
512
|
+
}
|
|
256
513
|
|
|
257
|
-
|
|
514
|
+
// @ts-expect-error
|
|
515
|
+
return createTremapLayout(treemapHierarchy) as HierarchyRectangularNode<TreeNode>;
|
|
258
516
|
}, [height, width, treemapHierarchy]);
|
|
259
517
|
|
|
260
|
-
return
|
|
518
|
+
return treemapNodes;
|
|
261
519
|
}
|
|
262
520
|
|
|
263
521
|
interface MetricsTreemapProps {
|
|
264
|
-
|
|
265
|
-
emptyMessage?:
|
|
522
|
+
treeNodes: Tree;
|
|
523
|
+
emptyMessage?: ReactNode;
|
|
524
|
+
nested?: boolean;
|
|
266
525
|
onItemClick?: (entryId: string) => void;
|
|
526
|
+
onGroupClick?: (entryId: string) => void;
|
|
267
527
|
}
|
|
268
528
|
|
|
269
|
-
export const MetricsTreemap = (props: MetricsTreemapProps &
|
|
270
|
-
const {
|
|
529
|
+
export const MetricsTreemap = (props: MetricsTreemapProps & ComponentProps<'div'>) => {
|
|
530
|
+
const {
|
|
531
|
+
className = '',
|
|
532
|
+
treeNodes,
|
|
533
|
+
onItemClick,
|
|
534
|
+
onGroupClick,
|
|
535
|
+
emptyMessage = 'No data',
|
|
536
|
+
nested = false,
|
|
537
|
+
...restProps
|
|
538
|
+
} = props;
|
|
271
539
|
|
|
272
540
|
const [containerRef, { width, height }] = useMeasure<HTMLDivElement>();
|
|
273
|
-
const
|
|
541
|
+
const rootNode = useMetricsTreemapHierarchy({ treeNodes, width, height, nested });
|
|
274
542
|
|
|
275
543
|
return (
|
|
276
|
-
<div
|
|
277
|
-
{
|
|
544
|
+
<div
|
|
545
|
+
className={cx(css.root, nested && css.nested, className)}
|
|
546
|
+
{...restProps}
|
|
547
|
+
ref={containerRef}
|
|
548
|
+
>
|
|
549
|
+
{rootNode.children && rootNode.children?.length > 0 ? (
|
|
278
550
|
<div className={css.canvas}>
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
/>
|
|
294
|
-
);
|
|
295
|
-
})}
|
|
551
|
+
<TileGroup
|
|
552
|
+
title={nested ? rootNode.data.label : undefined}
|
|
553
|
+
total={(rootNode.data as Tree).total}
|
|
554
|
+
id={rootNode.data.id}
|
|
555
|
+
childNodes={rootNode.children}
|
|
556
|
+
onItemClick={onItemClick}
|
|
557
|
+
onGroupClick={onGroupClick}
|
|
558
|
+
left={rootNode.x0}
|
|
559
|
+
top={rootNode.y0}
|
|
560
|
+
absoluteLeft={rootNode.x0}
|
|
561
|
+
absoluteTop={rootNode.y0}
|
|
562
|
+
width={rootNode.x1 - rootNode.x0}
|
|
563
|
+
height={rootNode.y1 - rootNode.y0}
|
|
564
|
+
/>
|
|
296
565
|
</div>
|
|
297
566
|
) : (
|
|
298
567
|
<div className={css.emptyMessage}>
|