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