@bundle-stats/ui 4.12.1 → 4.13.0-beta.2
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 +3 -7
- package/lib/app/app.js.map +1 -1
- package/lib/assets/icons.svg +26 -20
- package/lib/assets/icons.svg.js +27 -23
- package/lib/assets/icons.svg.js.map +1 -1
- package/lib/components/bundle-assets/bundle-assets.js +11 -3
- package/lib/components/bundle-assets/bundle-assets.js.map +1 -1
- package/lib/components/bundle-assets/index.js +3 -4
- package/lib/components/bundle-assets/index.js.map +1 -1
- package/lib/components/bundle-assets-totals/bundle-assets-totals.js +77 -0
- package/lib/components/bundle-assets-totals/bundle-assets-totals.js.map +1 -0
- package/lib/components/bundle-assets-totals/bundle-assets-totals.module.css +7 -0
- package/lib/{ui/horizontal-bar-chart → components/bundle-assets-totals}/index.js +1 -1
- package/lib/components/bundle-assets-totals/index.js.map +1 -0
- package/lib/components/bundle-modules/bundle-modules.js +9 -2
- package/lib/components/bundle-modules/bundle-modules.js.map +1 -1
- package/lib/components/bundle-modules/index.js +3 -4
- package/lib/components/bundle-modules/index.js.map +1 -1
- package/lib/components/bundle-packages/bundle-packages.js +10 -2
- package/lib/components/bundle-packages/bundle-packages.js.map +1 -1
- package/lib/components/bundle-packages/index.js +3 -4
- package/lib/components/bundle-packages/index.js.map +1 -1
- package/lib/components/index.js +3 -5
- package/lib/components/index.js.map +1 -1
- package/lib/components/{bundle-assets-totals-table → metrics-display-selector}/index.js +1 -1
- package/lib/components/metrics-display-selector/index.js.map +1 -0
- package/lib/components/metrics-display-selector/metrics-display-selector.js +21 -0
- package/lib/components/metrics-display-selector/metrics-display-selector.js.map +1 -0
- package/lib/components/metrics-display-selector/metrics-display-selector.module.css +10 -0
- package/lib/components/{bundle-assets-totals-chart-bars → metrics-treemap}/index.js +1 -1
- package/lib/components/metrics-treemap/index.js.map +1 -0
- package/lib/components/metrics-treemap/metrics-treemap.js +168 -0
- package/lib/components/metrics-treemap/metrics-treemap.js.map +1 -0
- package/lib/components/metrics-treemap/metrics-treemap.module.css +184 -0
- package/lib/constants.js +6 -1
- package/lib/constants.js.map +1 -1
- package/lib/hooks/entry-info.js +12 -0
- package/lib/hooks/entry-info.js.map +1 -0
- package/lib/hooks/metrics-display-type.js +40 -0
- package/lib/hooks/metrics-display-type.js.map +1 -0
- package/lib/query-state.js +1 -1
- package/lib/query-state.js.map +1 -1
- package/lib/ui/button/button.module.css +1 -0
- package/lib/ui/icon/icon.js +2 -0
- package/lib/ui/icon/icon.js.map +1 -1
- package/lib/ui/index.js +1 -3
- package/lib/ui/index.js.map +1 -1
- package/lib-esm/app/app.js +3 -7
- package/lib-esm/app/app.js.map +1 -1
- package/lib-esm/assets/icons.svg +26 -20
- package/lib-esm/assets/icons.svg.js +27 -23
- package/lib-esm/assets/icons.svg.js.map +1 -1
- package/lib-esm/components/bundle-assets/bundle-assets.js +11 -3
- package/lib-esm/components/bundle-assets/bundle-assets.js.map +1 -1
- package/lib-esm/components/bundle-assets/index.js +5 -6
- package/lib-esm/components/bundle-assets/index.js.map +1 -1
- package/lib-esm/components/bundle-assets-totals/bundle-assets-totals.js +47 -0
- package/lib-esm/components/bundle-assets-totals/bundle-assets-totals.js.map +1 -0
- package/lib-esm/components/bundle-assets-totals/bundle-assets-totals.module.css +7 -0
- package/lib-esm/components/bundle-assets-totals/index.js +2 -0
- package/lib-esm/components/bundle-assets-totals/index.js.map +1 -0
- package/lib-esm/components/bundle-modules/bundle-modules.js +9 -2
- package/lib-esm/components/bundle-modules/bundle-modules.js.map +1 -1
- package/lib-esm/components/bundle-modules/index.js +3 -4
- package/lib-esm/components/bundle-modules/index.js.map +1 -1
- package/lib-esm/components/bundle-packages/bundle-packages.js +10 -2
- package/lib-esm/components/bundle-packages/bundle-packages.js.map +1 -1
- package/lib-esm/components/bundle-packages/index.js +5 -6
- package/lib-esm/components/bundle-packages/index.js.map +1 -1
- package/lib-esm/components/index.js +1 -2
- package/lib-esm/components/index.js.map +1 -1
- package/lib-esm/components/metrics-display-selector/index.js +2 -0
- package/lib-esm/components/metrics-display-selector/index.js.map +1 -0
- package/lib-esm/components/metrics-display-selector/metrics-display-selector.js +14 -0
- package/lib-esm/components/metrics-display-selector/metrics-display-selector.js.map +1 -0
- package/lib-esm/components/metrics-display-selector/metrics-display-selector.module.css +10 -0
- package/lib-esm/components/metrics-treemap/index.js +2 -0
- package/lib-esm/components/metrics-treemap/index.js.map +1 -0
- package/lib-esm/components/metrics-treemap/metrics-treemap.js +140 -0
- package/lib-esm/components/metrics-treemap/metrics-treemap.js.map +1 -0
- package/lib-esm/components/metrics-treemap/metrics-treemap.module.css +184 -0
- package/lib-esm/constants.js +5 -0
- package/lib-esm/constants.js.map +1 -1
- package/lib-esm/hooks/entry-info.js +8 -0
- package/lib-esm/hooks/entry-info.js.map +1 -0
- package/lib-esm/hooks/metrics-display-type.js +36 -0
- package/lib-esm/hooks/metrics-display-type.js.map +1 -0
- package/lib-esm/query-state.js +1 -1
- package/lib-esm/query-state.js.map +1 -1
- package/lib-esm/ui/button/button.module.css +1 -0
- package/lib-esm/ui/icon/icon.js +2 -0
- package/lib-esm/ui/icon/icon.js.map +1 -1
- package/lib-esm/ui/index.js +0 -1
- package/lib-esm/ui/index.js.map +1 -1
- package/package.json +7 -4
- package/src/app/app.jsx +4 -8
- package/src/assets/icons/table.svg +3 -0
- package/src/assets/icons/treemap.svg +4 -0
- package/src/assets/icons.svg +26 -20
- package/src/assets/icons.svg.jsx +91 -55
- package/src/components/bundle-assets/bundle-assets.jsx +25 -11
- package/src/components/bundle-assets/index.jsx +10 -5
- package/src/components/bundle-assets-totals/bundle-assets-totals.jsx +94 -0
- package/src/components/bundle-assets-totals/bundle-assets-totals.module.css +7 -0
- package/src/components/bundle-assets-totals/index.js +1 -0
- package/src/components/bundle-modules/bundle-modules.tsx +26 -12
- package/src/components/bundle-modules/index.tsx +4 -3
- package/src/components/bundle-packages/bundle-packages.jsx +24 -10
- package/src/components/bundle-packages/index.jsx +10 -5
- package/src/components/index.js +1 -2
- package/src/components/metrics-display-selector/index.tsx +1 -0
- package/src/components/metrics-display-selector/metrics-display-selector.module.css +10 -0
- package/src/components/metrics-display-selector/metrics-display-selector.tsx +47 -0
- package/src/components/metrics-treemap/index.ts +1 -0
- package/src/components/metrics-treemap/metrics-treemap.module.css +184 -0
- package/src/components/metrics-treemap/metrics-treemap.stories.tsx +23 -0
- package/src/components/metrics-treemap/metrics-treemap.tsx +308 -0
- package/src/{constants.js → constants.ts} +5 -0
- package/src/hooks/entry-info.ts +19 -0
- package/src/hooks/metrics-display-type.ts +56 -0
- package/src/query-state.tsx +1 -1
- package/src/types.d.ts +2 -0
- package/src/ui/button/button.module.css +1 -0
- package/src/ui/icon/icon.tsx +2 -0
- package/src/ui/index.js +0 -1
- package/types/components/bundle-assets/bundle-assets.d.ts +2 -1
- package/types/components/{bundle-assets-totals-table/bundle-assets-totals-table.d.ts → bundle-assets-totals/bundle-assets-totals.d.ts} +2 -2
- package/types/components/bundle-assets-totals/index.d.ts +1 -0
- package/types/components/bundle-modules/bundle-modules.d.ts +2 -1
- package/types/components/bundle-modules/index.d.ts +1 -1
- package/types/components/bundle-packages/bundle-packages.d.ts +1 -0
- package/types/components/index.d.ts +1 -2
- package/types/components/metrics-display-selector/index.d.ts +1 -0
- package/types/components/metrics-display-selector/metrics-display-selector.d.ts +9 -0
- package/types/components/metrics-treemap/index.d.ts +1 -0
- package/types/components/metrics-treemap/metrics-treemap.d.ts +9 -0
- package/types/constants.d.ts +19 -15
- package/types/hooks/entry-info.d.ts +8 -0
- package/types/hooks/metrics-display-type.d.ts +4 -0
- package/types/ui/icon/icon.d.ts +4 -0
- package/types/ui/index.d.ts +0 -1
- package/lib/components/bundle-assets-totals-chart-bars/bundle-assets-totals-chart-bars.js +0 -95
- package/lib/components/bundle-assets-totals-chart-bars/bundle-assets-totals-chart-bars.js.map +0 -1
- package/lib/components/bundle-assets-totals-chart-bars/bundle-assets-totals-chart-bars.module.css +0 -42
- package/lib/components/bundle-assets-totals-chart-bars/index.js.map +0 -1
- package/lib/components/bundle-assets-totals-table/bundle-assets-totals-table.js +0 -57
- package/lib/components/bundle-assets-totals-table/bundle-assets-totals-table.js.map +0 -1
- package/lib/components/bundle-assets-totals-table/bundle-assets-totals-table.module.css +0 -3
- package/lib/components/bundle-assets-totals-table/index.js.map +0 -1
- package/lib/ui/horizontal-bar-chart/horizontal-bar-chart.js +0 -102
- package/lib/ui/horizontal-bar-chart/horizontal-bar-chart.js.map +0 -1
- package/lib/ui/horizontal-bar-chart/horizontal-bar-chart.module.css +0 -42
- package/lib/ui/horizontal-bar-chart/index.js.map +0 -1
- package/lib-esm/components/bundle-assets-totals-chart-bars/bundle-assets-totals-chart-bars.js +0 -66
- package/lib-esm/components/bundle-assets-totals-chart-bars/bundle-assets-totals-chart-bars.js.map +0 -1
- package/lib-esm/components/bundle-assets-totals-chart-bars/bundle-assets-totals-chart-bars.module.css +0 -42
- package/lib-esm/components/bundle-assets-totals-chart-bars/index.js +0 -2
- package/lib-esm/components/bundle-assets-totals-chart-bars/index.js.map +0 -1
- package/lib-esm/components/bundle-assets-totals-table/bundle-assets-totals-table.js +0 -27
- package/lib-esm/components/bundle-assets-totals-table/bundle-assets-totals-table.js.map +0 -1
- package/lib-esm/components/bundle-assets-totals-table/bundle-assets-totals-table.module.css +0 -3
- package/lib-esm/components/bundle-assets-totals-table/index.js +0 -2
- package/lib-esm/components/bundle-assets-totals-table/index.js.map +0 -1
- package/lib-esm/ui/horizontal-bar-chart/horizontal-bar-chart.js +0 -96
- package/lib-esm/ui/horizontal-bar-chart/horizontal-bar-chart.js.map +0 -1
- package/lib-esm/ui/horizontal-bar-chart/horizontal-bar-chart.module.css +0 -42
- package/lib-esm/ui/horizontal-bar-chart/index.js +0 -2
- package/lib-esm/ui/horizontal-bar-chart/index.js.map +0 -1
- package/src/components/bundle-assets-totals-chart-bars/bundle-assets-totals-chart-bars.jsx +0 -106
- package/src/components/bundle-assets-totals-chart-bars/bundle-assets-totals-chart-bars.module.css +0 -42
- package/src/components/bundle-assets-totals-chart-bars/index.js +0 -1
- package/src/components/bundle-assets-totals-table/bundle-assets-totals-table.jsx +0 -55
- package/src/components/bundle-assets-totals-table/bundle-assets-totals-table.module.css +0 -3
- package/src/components/bundle-assets-totals-table/index.js +0 -1
- package/src/ui/horizontal-bar-chart/horizontal-bar-chart.jsx +0 -156
- package/src/ui/horizontal-bar-chart/horizontal-bar-chart.module.css +0 -42
- package/src/ui/horizontal-bar-chart/index.js +0 -1
- package/types/components/bundle-assets-totals-chart-bars/bundle-assets-totals-chart-bars.d.ts +0 -22
- package/types/components/bundle-assets-totals-chart-bars/index.d.ts +0 -1
- package/types/components/bundle-assets-totals-table/index.d.ts +0 -1
- package/types/ui/horizontal-bar-chart/horizontal-bar-chart.d.ts +0 -23
- package/types/ui/horizontal-bar-chart/index.d.ts +0 -1
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
import React, { RefObject, forwardRef, useCallback, useMemo, useRef } from 'react';
|
|
2
|
+
import { useDebounce, useHoverDirty, useMeasure, useMouseHovered } from 'react-use';
|
|
3
|
+
import cx from 'classnames';
|
|
4
|
+
import type { ReportMetricRow, MetricRunInfo, MetricRunInfoBaseline } from '@bundle-stats/utils';
|
|
5
|
+
import { hierarchy, treemap, treemapSquarify, window } from 'd3';
|
|
6
|
+
import { Tooltip, TooltipArrow, TooltipAnchor, useTooltipState, useTooltip } from 'ariakit/tooltip';
|
|
7
|
+
|
|
8
|
+
import { Stack } from '../../layout/stack';
|
|
9
|
+
import { FileName } from '../../ui/file-name';
|
|
10
|
+
import { Delta } from '../delta';
|
|
11
|
+
import { RunInfo } from '../run-info';
|
|
12
|
+
import css from './metrics-treemap.module.css';
|
|
13
|
+
|
|
14
|
+
const SQUARIFY_RATIO = 1.78;
|
|
15
|
+
const PADDING_OUTER = 0;
|
|
16
|
+
const PADDING_INNER = 1;
|
|
17
|
+
|
|
18
|
+
type TileSizeDisplay = 'minimal' | 'small' | 'default';
|
|
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 {
|
|
51
|
+
item: ReportMetricRow;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const LeafTooltipContent = (props: LeafTooltipContentProps) => {
|
|
55
|
+
const { item } = props;
|
|
56
|
+
|
|
57
|
+
const currentRun = item.runs[0] as MetricRunInfo;
|
|
58
|
+
const baselineRun = item.runs[item.runs.length - 1] as MetricRunInfoBaseline;
|
|
59
|
+
|
|
60
|
+
return (
|
|
61
|
+
<Stack space="small" className={css.leafTooltipContent}>
|
|
62
|
+
<h3 className={css.leafTooltipContentTitle}>
|
|
63
|
+
<FileName as="code" name={item.label} />
|
|
64
|
+
</h3>
|
|
65
|
+
<RunInfo
|
|
66
|
+
current={currentRun.displayValue}
|
|
67
|
+
delta={currentRun.displayDeltaPercentage}
|
|
68
|
+
deltaType={currentRun.deltaType}
|
|
69
|
+
baseline={baselineRun?.displayValue || '0B'}
|
|
70
|
+
/>
|
|
71
|
+
</Stack>
|
|
72
|
+
);
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
interface LeafContentProps {
|
|
76
|
+
sizeDisplay: 'minimal' | 'small' | 'default';
|
|
77
|
+
item: ReportMetricRow;
|
|
78
|
+
runInfo: MetricRunInfo;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const LeafContent = forwardRef((props: LeafContentProps, ref: React.Ref<HTMLDivElement>) => {
|
|
82
|
+
const { sizeDisplay, item, runInfo } = props;
|
|
83
|
+
|
|
84
|
+
if (sizeDisplay === 'minimal') {
|
|
85
|
+
return <div className={css.leafContent} ref={ref} />;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return (
|
|
89
|
+
<div className={css.leafContent} ref={ref}>
|
|
90
|
+
<p className={css.leadContentLabel}>{item.label}</p>
|
|
91
|
+
{sizeDisplay !== 'small' && (
|
|
92
|
+
<p className={css.leadContentValue}>
|
|
93
|
+
<span className={css.leadContentMetric}>{runInfo.displayValue}</span>
|
|
94
|
+
<Delta
|
|
95
|
+
className={css.leadContentDelta}
|
|
96
|
+
displayValue={runInfo.displayDeltaPercentage}
|
|
97
|
+
deltaType={runInfo.deltaType}
|
|
98
|
+
/>
|
|
99
|
+
</p>
|
|
100
|
+
)}
|
|
101
|
+
</div>
|
|
102
|
+
);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
const LeafContentWithTooltip = (props: LeafContentProps & { parentRef: RefObject<Element> }) => {
|
|
106
|
+
const { sizeDisplay, item, runInfo, parentRef } = props;
|
|
107
|
+
|
|
108
|
+
const pointer = useMouseHovered(parentRef, { whenHovered: true });
|
|
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?.pageXOffset ?? 0),
|
|
119
|
+
y: pointer.docY - (document?.defaultView?.pageYOffset ?? 0),
|
|
120
|
+
w: 1,
|
|
121
|
+
h: 1,
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
return newRect;
|
|
125
|
+
}, [pointer.docX, pointer.docY]);
|
|
126
|
+
|
|
127
|
+
const tooltipState = useTooltipState({ gutter: 8, getAnchorRect, timeout: 100 });
|
|
128
|
+
|
|
129
|
+
// Update tooltip position when poiner values are changing
|
|
130
|
+
useDebounce(tooltipState.render, 10, [pointer.docX, pointer.docY]);
|
|
131
|
+
|
|
132
|
+
return (
|
|
133
|
+
<>
|
|
134
|
+
<TooltipAnchor state={tooltipState} className={css.leafContentTooltipAnchor}>
|
|
135
|
+
<LeafContent sizeDisplay={sizeDisplay} item={item} runInfo={runInfo} />
|
|
136
|
+
</TooltipAnchor>
|
|
137
|
+
<Tooltip state={tooltipState} className={css.tooltip}>
|
|
138
|
+
<TooltipArrow state={tooltipState} size={16} className={css.leafTooltipArrow} />
|
|
139
|
+
<LeafTooltipContent item={item} />
|
|
140
|
+
</Tooltip>
|
|
141
|
+
</>
|
|
142
|
+
);
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
const LeafAction = forwardRef((props: React.ComponentProps<'button'>, ref) => (
|
|
146
|
+
// @ts-expect-error
|
|
147
|
+
<button type="button" xmlns="http://www.w3.org/1999/xhtml" ref={ref} {...props} />
|
|
148
|
+
));
|
|
149
|
+
|
|
150
|
+
interface TreeNode {
|
|
151
|
+
id: string;
|
|
152
|
+
value: number;
|
|
153
|
+
item: ReportMetricRow;
|
|
154
|
+
children?: Array<TreeNode>;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
interface RootTree {
|
|
158
|
+
id: string;
|
|
159
|
+
value: number;
|
|
160
|
+
children: Array<TreeNode>;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
interface LeafProps {
|
|
164
|
+
x: number;
|
|
165
|
+
y: number;
|
|
166
|
+
width: number;
|
|
167
|
+
height: number;
|
|
168
|
+
data: TreeNode;
|
|
169
|
+
onClick?: (id: string) => void;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const Leaf = (props: LeafProps) => {
|
|
173
|
+
const { x, y, width, height, data, onClick } = props;
|
|
174
|
+
|
|
175
|
+
const { item } = data;
|
|
176
|
+
const runInfo = item.runs?.[0] as MetricRunInfo;
|
|
177
|
+
|
|
178
|
+
const sizeDisplay = useMemo(() => resolveLeafSizeDisplay(width, height), [width, height]);
|
|
179
|
+
const handleOnClick = useCallback(() => onClick?.(item.key), [item.key]);
|
|
180
|
+
|
|
181
|
+
const leafContentRef = useRef<HTMLElement>(null);
|
|
182
|
+
const hover = useHoverDirty(leafContentRef);
|
|
183
|
+
|
|
184
|
+
const leafClassName = cx(
|
|
185
|
+
css.leaf,
|
|
186
|
+
css[`leaf-${runInfo.deltaType}`],
|
|
187
|
+
sizeDisplay === 'small' && css.leafSmall,
|
|
188
|
+
);
|
|
189
|
+
|
|
190
|
+
return (
|
|
191
|
+
<g className={leafClassName}>
|
|
192
|
+
<rect x={x} y={y} width={width} height={height} className={css.leafBackground} />
|
|
193
|
+
<rect x={x} y={y} width={width} height={height} className={css.leafBackdrop} />
|
|
194
|
+
<foreignObject height={height} width={width} x={x} y={y} className={css.leafWrapper}>
|
|
195
|
+
<LeafAction onClick={handleOnClick} ref={leafContentRef} className={css.leafAction}>
|
|
196
|
+
{hover ? (
|
|
197
|
+
<LeafContentWithTooltip
|
|
198
|
+
sizeDisplay={sizeDisplay}
|
|
199
|
+
item={item}
|
|
200
|
+
runInfo={runInfo}
|
|
201
|
+
parentRef={leafContentRef}
|
|
202
|
+
/>
|
|
203
|
+
) : (
|
|
204
|
+
<LeafContent sizeDisplay={sizeDisplay} item={item} runInfo={runInfo} />
|
|
205
|
+
)}
|
|
206
|
+
</LeafAction>
|
|
207
|
+
</foreignObject>
|
|
208
|
+
</g>
|
|
209
|
+
);
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
interface UseMetricsTreemapHierarchyParams {
|
|
213
|
+
items: Array<ReportMetricRow>;
|
|
214
|
+
width: number;
|
|
215
|
+
height: number;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function useMetricsTreemapHierarchy(params: UseMetricsTreemapHierarchyParams) {
|
|
219
|
+
const { items, width, height } = params;
|
|
220
|
+
|
|
221
|
+
const treemapHierarchy = useMemo(() => {
|
|
222
|
+
const children = items.map((item) => {
|
|
223
|
+
/**
|
|
224
|
+
* Set leaf value to the largest run value to allow to
|
|
225
|
+
* display the impact of deleted / items
|
|
226
|
+
*/
|
|
227
|
+
const values = item.runs.map((run) => run?.value || 0);
|
|
228
|
+
const value = Math.max(...values);
|
|
229
|
+
|
|
230
|
+
return {
|
|
231
|
+
id: item.key,
|
|
232
|
+
value,
|
|
233
|
+
item,
|
|
234
|
+
};
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
const treemapData = {
|
|
238
|
+
id: 'root',
|
|
239
|
+
name: 'root',
|
|
240
|
+
value: 0,
|
|
241
|
+
children,
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
const customHierarchy = hierarchy<RootTree>(treemapData);
|
|
245
|
+
customHierarchy.sum((node) => node.value);
|
|
246
|
+
// @ts-expect-error
|
|
247
|
+
customHierarchy.sort((a, b) => b.value - a.value);
|
|
248
|
+
|
|
249
|
+
return customHierarchy;
|
|
250
|
+
}, [items]);
|
|
251
|
+
|
|
252
|
+
const cells = useMemo(() => {
|
|
253
|
+
const createTremapLayout = treemap()
|
|
254
|
+
.size([width, height])
|
|
255
|
+
.tile(treemapSquarify.ratio(SQUARIFY_RATIO))
|
|
256
|
+
.paddingOuter(PADDING_OUTER)
|
|
257
|
+
.paddingInner(PADDING_INNER);
|
|
258
|
+
// @ts-expect-error
|
|
259
|
+
const tremapLayout = createTremapLayout(treemapHierarchy);
|
|
260
|
+
|
|
261
|
+
return tremapLayout.leaves().filter((leaf) => Boolean(leaf.parent));
|
|
262
|
+
}, [height, width, treemapHierarchy]);
|
|
263
|
+
|
|
264
|
+
return cells;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
interface MetricsTreemapProps {
|
|
268
|
+
items: Array<ReportMetricRow>;
|
|
269
|
+
emptyMessage?: React.ReactNode;
|
|
270
|
+
onItemClick?: (entryId: string) => void;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
export const MetricsTreemap = (props: MetricsTreemapProps & React.ComponentProps<'div'>) => {
|
|
274
|
+
const { className = '', items, onItemClick, emptyMessage = 'No data', ...restProps } = props;
|
|
275
|
+
|
|
276
|
+
const [containerRef, { width, height }] = useMeasure<HTMLDivElement>();
|
|
277
|
+
const cells = useMetricsTreemapHierarchy({ items, width, height });
|
|
278
|
+
|
|
279
|
+
return (
|
|
280
|
+
<div className={cx(css.root, className)} {...restProps} ref={containerRef}>
|
|
281
|
+
{cells.length > 0 ? (
|
|
282
|
+
<svg viewBox={`0 0 ${width} ${height}`} className={css.canvas}>
|
|
283
|
+
{cells.map((leaf) => {
|
|
284
|
+
if (!leaf.parent) {
|
|
285
|
+
return null;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
return (
|
|
289
|
+
<Leaf
|
|
290
|
+
x={leaf.x0}
|
|
291
|
+
y={leaf.y0}
|
|
292
|
+
width={leaf.x1 - leaf.x0}
|
|
293
|
+
height={leaf.y1 - leaf.y0}
|
|
294
|
+
data={leaf.data as TreeNode}
|
|
295
|
+
onClick={onItemClick}
|
|
296
|
+
key={leaf.id}
|
|
297
|
+
/>
|
|
298
|
+
);
|
|
299
|
+
})}
|
|
300
|
+
</svg>
|
|
301
|
+
) : (
|
|
302
|
+
<div className={css.emptyMessage}>
|
|
303
|
+
<div className={css.emptyMessageWrapper}>{emptyMessage}</div>
|
|
304
|
+
</div>
|
|
305
|
+
)}
|
|
306
|
+
</div>
|
|
307
|
+
);
|
|
308
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { useCallback } from 'react';
|
|
2
|
+
|
|
3
|
+
interface UseEntryInfoParams {
|
|
4
|
+
setState: (data: { entryId: string }) => void;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
type UseEntryInfo = [() => void, (entryId: string) => void];
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Show/hide side panel entry
|
|
11
|
+
*/
|
|
12
|
+
export function useEntryInfo(params: UseEntryInfoParams): UseEntryInfo {
|
|
13
|
+
const { setState } = params;
|
|
14
|
+
|
|
15
|
+
const hideEntryInfo = useCallback(() => setState({ entryId: '' }), [setState]);
|
|
16
|
+
const showEntryInfo = useCallback((entryId: string) => setState({ entryId }), [setState]);
|
|
17
|
+
|
|
18
|
+
return [hideEntryInfo, showEntryInfo];
|
|
19
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { useCallback, useEffect, useMemo } from 'react';
|
|
2
|
+
import { useLocalStorage } from 'react-use';
|
|
3
|
+
import { StringParam, useQueryParams } from 'use-query-params';
|
|
4
|
+
|
|
5
|
+
import { MetricsDisplayType } from '../constants';
|
|
6
|
+
|
|
7
|
+
const DEFAULT_DISPLAY_TYPE = MetricsDisplayType.TABLE;
|
|
8
|
+
const PARAM_NAME = 'dt';
|
|
9
|
+
|
|
10
|
+
type UseMetricsDisplayType = [MetricsDisplayType, (value: MetricsDisplayType) => void];
|
|
11
|
+
|
|
12
|
+
export const useMetricsDisplayType = (): UseMetricsDisplayType => {
|
|
13
|
+
const [{ [PARAM_NAME]: queryDisplayType }, setQueryParams] = useQueryParams({
|
|
14
|
+
[PARAM_NAME]: StringParam,
|
|
15
|
+
});
|
|
16
|
+
const [storageDisplayType, setStoreageDisplayType] = useLocalStorage(
|
|
17
|
+
PARAM_NAME,
|
|
18
|
+
MetricsDisplayType.TABLE,
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
const displayType = useMemo(() => {
|
|
22
|
+
const value = queryDisplayType || storageDisplayType;
|
|
23
|
+
|
|
24
|
+
if (!value) {
|
|
25
|
+
return DEFAULT_DISPLAY_TYPE;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (!Object.values(MetricsDisplayType).includes(value as MetricsDisplayType)) {
|
|
29
|
+
return DEFAULT_DISPLAY_TYPE;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return value as MetricsDisplayType;
|
|
33
|
+
}, [queryDisplayType, storageDisplayType]);
|
|
34
|
+
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
// Update query string display type when missing
|
|
37
|
+
if (queryDisplayType !== displayType) {
|
|
38
|
+
setQueryParams({ [PARAM_NAME]: displayType });
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Update storage state when query string is set and different
|
|
42
|
+
if (storageDisplayType !== displayType) {
|
|
43
|
+
setStoreageDisplayType(queryDisplayType as MetricsDisplayType);
|
|
44
|
+
}
|
|
45
|
+
}, [displayType, queryDisplayType, storageDisplayType, setQueryParams, setStoreageDisplayType]);
|
|
46
|
+
|
|
47
|
+
const setDisplayType = useCallback(
|
|
48
|
+
(value: MetricsDisplayType) => {
|
|
49
|
+
setStoreageDisplayType(value);
|
|
50
|
+
setQueryParams({ [PARAM_NAME]: value });
|
|
51
|
+
},
|
|
52
|
+
[setStoreageDisplayType, setQueryParams],
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
return [displayType, setDisplayType];
|
|
56
|
+
};
|
package/src/query-state.tsx
CHANGED
package/src/types.d.ts
CHANGED
|
@@ -8,8 +8,10 @@ interface FilterFieldData {
|
|
|
8
8
|
defaultValue: boolean;
|
|
9
9
|
disabled?: boolean;
|
|
10
10
|
}
|
|
11
|
+
|
|
11
12
|
type FilterGroupFieldData = {
|
|
12
13
|
label: string;
|
|
13
14
|
children: Array<{ key: string } & FilterFieldData>;
|
|
14
15
|
};
|
|
16
|
+
|
|
15
17
|
type FilterFieldsData = Record<string, FilterFieldData | FilterGroupFieldData>;
|
package/src/ui/icon/icon.tsx
CHANGED
package/src/ui/index.js
CHANGED
|
@@ -6,7 +6,6 @@ export { Dropdown } from './dropdown';
|
|
|
6
6
|
export { EmptySet } from './empty-set';
|
|
7
7
|
export { FileName } from './file-name';
|
|
8
8
|
export { Filters } from './filters';
|
|
9
|
-
export { HorizontalBarChart } from './horizontal-bar-chart';
|
|
10
9
|
export { HoverCard } from './hover-card';
|
|
11
10
|
export { Icon } from './icon';
|
|
12
11
|
export { Input } from './input';
|
|
@@ -47,11 +47,12 @@ export namespace BundleAssets {
|
|
|
47
47
|
direction: PropTypes.Requireable<string>;
|
|
48
48
|
}>>>;
|
|
49
49
|
export let updateSort: PropTypes.Validator<(...args: any[]) => any>;
|
|
50
|
-
export let allItems: PropTypes.
|
|
50
|
+
export let allItems: PropTypes.Validator<(PropTypes.InferProps<{
|
|
51
51
|
key: PropTypes.Requireable<string>;
|
|
52
52
|
}> | null | undefined)[]>;
|
|
53
53
|
export let customComponentLink: PropTypes.Requireable<PropTypes.ReactComponentLike>;
|
|
54
54
|
export let hideEntryInfo: PropTypes.Validator<(...args: any[]) => any>;
|
|
55
|
+
export let showEntryInfo: PropTypes.Validator<(...args: any[]) => any>;
|
|
55
56
|
}
|
|
56
57
|
}
|
|
57
58
|
import React from 'react';
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
export function
|
|
1
|
+
export function BundleAssetsTotals({ className, jobs, customComponentLink: CustomComponentLink, ...restProps }: {
|
|
2
2
|
[x: string]: any;
|
|
3
3
|
className: any;
|
|
4
4
|
jobs: any;
|
|
5
5
|
customComponentLink: any;
|
|
6
6
|
}): React.JSX.Element;
|
|
7
|
-
export namespace
|
|
7
|
+
export namespace BundleAssetsTotals {
|
|
8
8
|
namespace defaultProps {
|
|
9
9
|
export let className: string;
|
|
10
10
|
export let jobs: never[];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./bundle-assets-totals";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import
|
|
2
|
+
import { SortAction } from '../../types';
|
|
3
3
|
import { ModuleMetric } from './bundle-modules.constants';
|
|
4
4
|
import type { Chunk, Job, ReportMetricModuleRow } from './bundle-modules.types';
|
|
5
5
|
interface BundleModulesProps extends React.ComponentProps<'div'> {
|
|
@@ -18,6 +18,7 @@ interface BundleModulesProps extends React.ComponentProps<'div'> {
|
|
|
18
18
|
updateSearch: (newSerarch: string) => void;
|
|
19
19
|
entryId?: string;
|
|
20
20
|
hideEntryInfo: () => void;
|
|
21
|
+
showEntryInfo: (entryId: string) => void;
|
|
21
22
|
moduleMetric: ModuleMetric;
|
|
22
23
|
setModuleMetric: (newValue: ModuleMetric) => void;
|
|
23
24
|
customComponentLink: React.ElementType;
|
|
@@ -2,7 +2,7 @@ import React from 'react';
|
|
|
2
2
|
import type { SortAction } from '../../types';
|
|
3
3
|
import { BundleModules as BaseComponent } from './bundle-modules';
|
|
4
4
|
import * as types from './bundle-modules.types';
|
|
5
|
-
interface BundleModulesProps extends Omit<React.ComponentProps<typeof BaseComponent>, 'jobs' | 'items' | 'chunks' | 'updateFilters' | 'resetFilters' | 'resetAllFilters' | 'filters' | 'sort' | 'updateSort' | 'search' | 'updateSearch' | 'allItems' | 'totalRowCount' | 'hideEntryInfo'> {
|
|
5
|
+
interface BundleModulesProps extends Omit<React.ComponentProps<typeof BaseComponent>, 'jobs' | 'items' | 'chunks' | 'updateFilters' | 'resetFilters' | 'resetAllFilters' | 'filters' | 'sort' | 'updateSort' | 'search' | 'updateSearch' | 'allItems' | 'totalRowCount' | 'hideEntryInfo' | 'showEntryInfo'> {
|
|
6
6
|
jobs: Array<types.Job>;
|
|
7
7
|
filters: Record<string, boolean>;
|
|
8
8
|
search?: string;
|
|
@@ -45,6 +45,7 @@ export namespace BundlePackages {
|
|
|
45
45
|
let entryId_1: PropTypes.Requireable<string>;
|
|
46
46
|
export { entryId_1 as entryId };
|
|
47
47
|
export let hideEntryInfo: PropTypes.Validator<(...args: any[]) => any>;
|
|
48
|
+
export let showEntryInfo: PropTypes.Validator<(...args: any[]) => any>;
|
|
48
49
|
}
|
|
49
50
|
}
|
|
50
51
|
import React from 'react';
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
export { BrowsertimeTable } from "./browsertime-table";
|
|
2
2
|
export { BundleAssets } from "./bundle-assets";
|
|
3
|
-
export {
|
|
4
|
-
export { BundleAssetsTotalsChartBars } from "./bundle-assets-totals-chart-bars";
|
|
3
|
+
export { BundleAssetsTotals } from "./bundle-assets-totals";
|
|
5
4
|
export { BundlePackages } from "./bundle-packages";
|
|
6
5
|
export { BundleModules } from "./bundle-modules";
|
|
7
6
|
export { ComponentLink } from "./component-link";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './metrics-display-selector';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { MetricsDisplayType } from '../../constants';
|
|
3
|
+
import { FlexStack } from '../../layout/flex-stack';
|
|
4
|
+
interface MetricsDisplaySelectorProps {
|
|
5
|
+
value: MetricsDisplayType;
|
|
6
|
+
onSelect: (newValue: MetricsDisplayType) => void;
|
|
7
|
+
}
|
|
8
|
+
export declare const MetricsDisplaySelector: (props: MetricsDisplaySelectorProps & Omit<React.ComponentProps<typeof FlexStack>, 'onSelect' | 'value'>) => React.JSX.Element;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './metrics-treemap';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { ReportMetricRow } from '@bundle-stats/utils';
|
|
3
|
+
interface MetricsTreemapProps {
|
|
4
|
+
items: Array<ReportMetricRow>;
|
|
5
|
+
emptyMessage?: React.ReactNode;
|
|
6
|
+
onItemClick?: (entryId: string) => void;
|
|
7
|
+
}
|
|
8
|
+
export declare const MetricsTreemap: (props: MetricsTreemapProps & React.ComponentProps<'div'>) => React.JSX.Element;
|
|
9
|
+
export {};
|
package/types/constants.d.ts
CHANGED
|
@@ -1,18 +1,22 @@
|
|
|
1
|
-
export
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
}
|
|
7
|
-
export const SECTION_URLS: {
|
|
1
|
+
export declare const URLS: {
|
|
2
|
+
OVERVIEW: string;
|
|
3
|
+
ASSETS: string;
|
|
4
|
+
MODULES: string;
|
|
5
|
+
PACKAGES: string;
|
|
6
|
+
};
|
|
7
|
+
export declare const SECTION_URLS: {
|
|
8
8
|
[x: string]: string;
|
|
9
9
|
};
|
|
10
|
-
export const ASSETS_SIZES_FILE_TYPE_MAP: {};
|
|
11
|
-
export const METRICS_WEBPACK_GENERAL: string[];
|
|
12
|
-
export const METRICS_WEBPACK_ASSETS: string[];
|
|
13
|
-
export const METRICS_WEBPACK_MODULES: string[];
|
|
14
|
-
export const METRICS_WEBPACK_PACKAGES: string[];
|
|
15
|
-
export
|
|
16
|
-
|
|
17
|
-
|
|
10
|
+
export declare const ASSETS_SIZES_FILE_TYPE_MAP: {};
|
|
11
|
+
export declare const METRICS_WEBPACK_GENERAL: string[];
|
|
12
|
+
export declare const METRICS_WEBPACK_ASSETS: string[];
|
|
13
|
+
export declare const METRICS_WEBPACK_MODULES: string[];
|
|
14
|
+
export declare const METRICS_WEBPACK_PACKAGES: string[];
|
|
15
|
+
export declare const SORT: {
|
|
16
|
+
ASC: string;
|
|
17
|
+
DESC: string;
|
|
18
|
+
};
|
|
19
|
+
export declare enum MetricsDisplayType {
|
|
20
|
+
TABLE = "table",
|
|
21
|
+
TREEMAP = "treemap"
|
|
18
22
|
}
|
package/types/ui/icon/icon.d.ts
CHANGED
|
@@ -14,6 +14,8 @@ declare const ICONS: {
|
|
|
14
14
|
readonly GITHUB: "github";
|
|
15
15
|
readonly INFO: "info";
|
|
16
16
|
readonly HELP: "help";
|
|
17
|
+
readonly TABLE: "table";
|
|
18
|
+
readonly TREEMAP: "treemap";
|
|
17
19
|
readonly MENU: "menu";
|
|
18
20
|
readonly MORE_VERTICAL: "more-vertical";
|
|
19
21
|
readonly SORT: "sort";
|
|
@@ -47,6 +49,8 @@ export declare const Icon: {
|
|
|
47
49
|
readonly GITHUB: "github";
|
|
48
50
|
readonly INFO: "info";
|
|
49
51
|
readonly HELP: "help";
|
|
52
|
+
readonly TABLE: "table";
|
|
53
|
+
readonly TREEMAP: "treemap";
|
|
50
54
|
readonly MENU: "menu";
|
|
51
55
|
readonly MORE_VERTICAL: "more-vertical";
|
|
52
56
|
readonly SORT: "sort";
|
package/types/ui/index.d.ts
CHANGED
|
@@ -6,7 +6,6 @@ export { Dropdown } from "./dropdown";
|
|
|
6
6
|
export { EmptySet } from "./empty-set";
|
|
7
7
|
export { FileName } from "./file-name";
|
|
8
8
|
export { Filters } from "./filters";
|
|
9
|
-
export { HorizontalBarChart } from "./horizontal-bar-chart";
|
|
10
9
|
export { HoverCard } from "./hover-card";
|
|
11
10
|
export { Icon } from "./icon";
|
|
12
11
|
export { Input } from "./input";
|