@bundle-stats/ui 4.13.0-rc.0 → 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/components/bundle-assets/bundle-assets.js +23 -22
- package/lib/components/bundle-assets/bundle-assets.js.map +1 -1
- package/lib/components/bundle-assets/index.js +3 -1
- package/lib/components/bundle-assets/index.js.map +1 -1
- package/lib/components/bundle-modules/bundle-modules.js +10 -6
- package/lib/components/bundle-modules/bundle-modules.js.map +1 -1
- 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 +11 -6
- package/lib/components/bundle-packages/bundle-packages.js.map +1 -1
- package/lib/components/metrics-treemap/metrics-treemap.constants.js +7 -0
- package/lib/components/metrics-treemap/metrics-treemap.constants.js.map +1 -1
- package/lib/components/metrics-treemap/metrics-treemap.js +69 -71
- package/lib/components/metrics-treemap/metrics-treemap.js.map +1 -1
- package/lib/components/metrics-treemap/metrics-treemap.module.css +47 -10
- package/lib/components/metrics-treemap/metrics-treemap.utils.js +60 -1
- package/lib/components/metrics-treemap/metrics-treemap.utils.js.map +1 -1
- 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/components/bundle-assets/bundle-assets.js +23 -23
- package/lib-esm/components/bundle-assets/bundle-assets.js.map +1 -1
- 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-modules/bundle-modules.js +10 -6
- package/lib-esm/components/bundle-modules/bundle-modules.js.map +1 -1
- 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 +11 -6
- package/lib-esm/components/bundle-packages/bundle-packages.js.map +1 -1
- package/lib-esm/components/metrics-treemap/metrics-treemap.constants.js +6 -1
- package/lib-esm/components/metrics-treemap/metrics-treemap.constants.js.map +1 -1
- package/lib-esm/components/metrics-treemap/metrics-treemap.js +65 -68
- package/lib-esm/components/metrics-treemap/metrics-treemap.js.map +1 -1
- package/lib-esm/components/metrics-treemap/metrics-treemap.module.css +47 -10
- package/lib-esm/components/metrics-treemap/metrics-treemap.utils.js +57 -0
- package/lib-esm/components/metrics-treemap/metrics-treemap.utils.js.map +1 -1
- 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 +3 -3
- package/src/components/bundle-assets/bundle-assets.jsx +72 -48
- package/src/components/bundle-assets/index.jsx +4 -0
- package/src/components/bundle-modules/bundle-modules.tsx +32 -11
- 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 +19 -7
- package/src/components/metrics-treemap/metrics-treemap.constants.ts +11 -0
- package/src/components/metrics-treemap/metrics-treemap.module.css +47 -10
- package/src/components/metrics-treemap/metrics-treemap.tsx +171 -110
- package/src/components/metrics-treemap/metrics-treemap.utils.ts +107 -1
- 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.utils.d.ts +3 -7
- package/types/components/bundle-modules/index.d.ts +2 -2
- package/types/components/metrics-treemap/metrics-treemap.constants.d.ts +8 -0
- package/types/components/metrics-treemap/metrics-treemap.d.ts +1 -1
- package/types/components/metrics-treemap/metrics-treemap.utils.d.ts +11 -1
- 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/utils.js.map +0 -1
- package/lib-esm/utils.js +0 -30
- package/lib-esm/utils.js.map +0 -1
- package/src/utils.jsx +0 -38
- package/types/utils.d.ts +0 -3
|
@@ -48,12 +48,11 @@ const DISPLAY_TYPE_GROUPS = {
|
|
|
48
48
|
};
|
|
49
49
|
|
|
50
50
|
const getFileTypeFilters = (filters) =>
|
|
51
|
-
Object.entries(FILE_TYPE_LABELS)
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
}));
|
|
51
|
+
Object.entries(FILE_TYPE_LABELS).map(([key, label]) => ({
|
|
52
|
+
key,
|
|
53
|
+
label,
|
|
54
|
+
defaultValue: get(filters, `${ASSET_FILE_TYPE}.${key}`, true),
|
|
55
|
+
}));
|
|
57
56
|
|
|
58
57
|
const getFilters = ({ compareMode, filters }) => ({
|
|
59
58
|
[ASSET_FILTERS.CHANGED]: {
|
|
@@ -146,6 +145,7 @@ const RowHeader = ({ row, customComponentLink: CustomComponentLink, filters, sea
|
|
|
146
145
|
|
|
147
146
|
RowHeader.propTypes = {
|
|
148
147
|
row: PropTypes.shape({
|
|
148
|
+
key: PropTypes.string,
|
|
149
149
|
label: PropTypes.string,
|
|
150
150
|
isNotPredictive: PropTypes.bool,
|
|
151
151
|
isChunk: PropTypes.bool,
|
|
@@ -153,23 +153,28 @@ RowHeader.propTypes = {
|
|
|
153
153
|
isEntry: PropTypes.bool,
|
|
154
154
|
runs: PropTypes.arrayOf(PropTypes.object), // eslint-disable-line react/forbid-prop-types
|
|
155
155
|
}).isRequired,
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
name: PropTypes.string,
|
|
160
|
-
}),
|
|
161
|
-
),
|
|
162
|
-
labels: PropTypes.arrayOf(PropTypes.string).isRequired,
|
|
163
|
-
CustomComponentLink: PropTypes.elementType.isRequired,
|
|
156
|
+
customComponentLink: PropTypes.elementType.isRequired,
|
|
157
|
+
filters: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
|
|
158
|
+
search: PropTypes.string,
|
|
164
159
|
};
|
|
165
160
|
|
|
166
161
|
RowHeader.defaultProps = {
|
|
167
|
-
|
|
162
|
+
search: '',
|
|
168
163
|
};
|
|
169
164
|
|
|
170
165
|
const ViewMetricsTreemap = (props) => {
|
|
171
|
-
const {
|
|
166
|
+
const {
|
|
167
|
+
metricsTableTitle,
|
|
168
|
+
jobs,
|
|
169
|
+
items,
|
|
170
|
+
displayType,
|
|
171
|
+
emptyMessage,
|
|
172
|
+
showEntryInfo,
|
|
173
|
+
updateSearch,
|
|
174
|
+
search,
|
|
175
|
+
} = props;
|
|
172
176
|
|
|
177
|
+
// Get treenodes based on group
|
|
173
178
|
const treeNodes = useMemo(() => {
|
|
174
179
|
if (displayType.groupBy === 'folder') {
|
|
175
180
|
return getTreemapNodesGroupedByPath(items);
|
|
@@ -178,19 +183,28 @@ const ViewMetricsTreemap = (props) => {
|
|
|
178
183
|
return getTreemapNodes(items);
|
|
179
184
|
}, [items, displayType.groupBy]);
|
|
180
185
|
|
|
186
|
+
// Search based on the group path on group title click
|
|
181
187
|
const onGroupClick = useCallback(
|
|
182
188
|
(groupPath) => {
|
|
189
|
+
// Clear seach when groupPath is emty (root)
|
|
190
|
+
if (groupPath === '') {
|
|
191
|
+
updateSearch('');
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
183
194
|
// Search by group path
|
|
184
195
|
// 1. use `^` to match only the string beggining
|
|
185
|
-
// 2. add `/` suffix to match
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
196
|
+
// 2. add `/` suffix to exactly match the directory
|
|
197
|
+
const newSearch = `^${groupPath}/`;
|
|
198
|
+
|
|
199
|
+
// Reset search when toggling the same groupPath
|
|
200
|
+
if (newSearch === search) {
|
|
190
201
|
updateSearch('');
|
|
202
|
+
return;
|
|
191
203
|
}
|
|
204
|
+
|
|
205
|
+
updateSearch(`^${groupPath}/`);
|
|
192
206
|
},
|
|
193
|
-
[updateSearch],
|
|
207
|
+
[updateSearch, search],
|
|
194
208
|
);
|
|
195
209
|
|
|
196
210
|
return (
|
|
@@ -219,12 +233,14 @@ ViewMetricsTreemap.propTypes = {
|
|
|
219
233
|
emptyMessage: PropTypes.node.isRequired,
|
|
220
234
|
showEntryInfo: PropTypes.func.isRequired,
|
|
221
235
|
updateSearch: PropTypes.func.isRequired,
|
|
236
|
+
search: PropTypes.string.isRequired,
|
|
222
237
|
};
|
|
223
238
|
|
|
224
239
|
export const BundleAssets = (props) => {
|
|
225
240
|
const {
|
|
226
241
|
className,
|
|
227
242
|
jobs,
|
|
243
|
+
chunks,
|
|
228
244
|
items,
|
|
229
245
|
allItems,
|
|
230
246
|
updateFilters,
|
|
@@ -252,14 +268,17 @@ export const BundleAssets = (props) => {
|
|
|
252
268
|
[jobs, filters],
|
|
253
269
|
);
|
|
254
270
|
|
|
255
|
-
const metricsTableTitle = useMemo(
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
271
|
+
const metricsTableTitle = useMemo(
|
|
272
|
+
() => (
|
|
273
|
+
<MetricsTableTitle
|
|
274
|
+
title={I18N.ASSETS}
|
|
275
|
+
info={`${items.length}/${totalRowCount}`}
|
|
276
|
+
popoverInfo={I18N.ASSETS_INFO}
|
|
277
|
+
popoverHref={config.documentation.assets}
|
|
278
|
+
/>
|
|
279
|
+
),
|
|
280
|
+
[items, totalRowCount],
|
|
281
|
+
);
|
|
263
282
|
|
|
264
283
|
const renderRowHeader = useCallback(
|
|
265
284
|
(row) => (
|
|
@@ -273,21 +292,24 @@ export const BundleAssets = (props) => {
|
|
|
273
292
|
[CustomComponentLink, filters, search],
|
|
274
293
|
);
|
|
275
294
|
|
|
276
|
-
const emptyMessage = useMemo(
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
295
|
+
const emptyMessage = useMemo(
|
|
296
|
+
() => (
|
|
297
|
+
<EmptySet
|
|
298
|
+
resources="assets"
|
|
299
|
+
filtered={totalRowCount !== 0}
|
|
300
|
+
handleResetFilters={resetFilters}
|
|
301
|
+
handleViewAll={resetAllFilters}
|
|
302
|
+
/>
|
|
303
|
+
),
|
|
304
|
+
[totalRowCount, resetFilters, resetAllFilters],
|
|
305
|
+
);
|
|
284
306
|
|
|
285
307
|
const entryItem = useMemo(() => {
|
|
286
308
|
if (!entryId) {
|
|
287
309
|
return null;
|
|
288
310
|
}
|
|
289
311
|
|
|
290
|
-
return allItems.find(({ key }) => key === entryId)
|
|
312
|
+
return allItems.find(({ key }) => key === entryId);
|
|
291
313
|
}, [allItems, entryId]);
|
|
292
314
|
|
|
293
315
|
return (
|
|
@@ -345,6 +367,7 @@ export const BundleAssets = (props) => {
|
|
|
345
367
|
emptyMessage={emptyMessage}
|
|
346
368
|
showEntryInfo={showEntryInfo}
|
|
347
369
|
updateSearch={updateSearch}
|
|
370
|
+
search={search}
|
|
348
371
|
/>
|
|
349
372
|
)}
|
|
350
373
|
</Box>
|
|
@@ -355,7 +378,7 @@ export const BundleAssets = (props) => {
|
|
|
355
378
|
className={css.assetInfo}
|
|
356
379
|
item={entryItem}
|
|
357
380
|
labels={jobLabels}
|
|
358
|
-
chunks={
|
|
381
|
+
chunks={chunks}
|
|
359
382
|
customComponentLink={CustomComponentLink}
|
|
360
383
|
onClose={hideEntryInfo}
|
|
361
384
|
/>
|
|
@@ -378,13 +401,12 @@ BundleAssets.propTypes = {
|
|
|
378
401
|
PropTypes.shape({
|
|
379
402
|
internalBuildNumber: PropTypes.number,
|
|
380
403
|
label: PropTypes.string,
|
|
381
|
-
meta: PropTypes.shape({
|
|
382
|
-
webpack: PropTypes.shape({
|
|
383
|
-
chunks: PropTypes.array, // eslint-disable-line react/forbid-prop-types
|
|
384
|
-
}),
|
|
385
|
-
}),
|
|
386
404
|
}),
|
|
387
405
|
).isRequired,
|
|
406
|
+
chunks: PropTypes.arrayOf({
|
|
407
|
+
id: PropTypes.string,
|
|
408
|
+
name: PropTypes.string,
|
|
409
|
+
}).isRequired,
|
|
388
410
|
items: PropTypes.arrayOf(
|
|
389
411
|
PropTypes.shape({
|
|
390
412
|
key: PropTypes.string,
|
|
@@ -414,9 +436,11 @@ BundleAssets.propTypes = {
|
|
|
414
436
|
direction: PropTypes.string,
|
|
415
437
|
}).isRequired,
|
|
416
438
|
updateSort: PropTypes.func.isRequired,
|
|
417
|
-
allItems: PropTypes.arrayOf(
|
|
418
|
-
|
|
419
|
-
|
|
439
|
+
allItems: PropTypes.arrayOf(
|
|
440
|
+
PropTypes.shape({
|
|
441
|
+
key: PropTypes.string,
|
|
442
|
+
}),
|
|
443
|
+
).isRequired,
|
|
420
444
|
customComponentLink: PropTypes.elementType,
|
|
421
445
|
hideEntryInfo: PropTypes.func.isRequired,
|
|
422
446
|
showEntryInfo: PropTypes.func.isRequired,
|
|
@@ -11,6 +11,7 @@ import { useRowsFilter } from '../../hooks/rows-filter';
|
|
|
11
11
|
import { useRowsSort } from '../../hooks/rows-sort';
|
|
12
12
|
import { useSearchParams } from '../../hooks/search-params';
|
|
13
13
|
import { useEntryInfo } from '../../hooks/entry-info';
|
|
14
|
+
import { getJobsChunksData } from '../../utils/jobs';
|
|
14
15
|
import { BundleAssets as BundleAssetsComponent } from './bundle-assets';
|
|
15
16
|
import {
|
|
16
17
|
addRowAssetFlags,
|
|
@@ -22,6 +23,8 @@ import {
|
|
|
22
23
|
export const BundleAssets = (props) => {
|
|
23
24
|
const { jobs, filters, search, setState, sortBy, direction, ...restProps } = props;
|
|
24
25
|
|
|
26
|
+
const { chunks } = useMemo(() => getJobsChunksData(jobs), [jobs]);
|
|
27
|
+
|
|
25
28
|
const { defaultFilters, allEntriesFilters } = useMemo(
|
|
26
29
|
() => ({
|
|
27
30
|
defaultFilters: {
|
|
@@ -70,6 +73,7 @@ export const BundleAssets = (props) => {
|
|
|
70
73
|
return (
|
|
71
74
|
<BundleAssetsComponent
|
|
72
75
|
jobs={jobs}
|
|
76
|
+
chunks={chunks}
|
|
73
77
|
{...restProps}
|
|
74
78
|
{...searchParams}
|
|
75
79
|
{...sortParams}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import React, { useCallback, useMemo } from 'react';
|
|
2
2
|
import cx from 'classnames';
|
|
3
|
-
import { SECTIONS, COMPONENT } from '@bundle-stats/utils';
|
|
3
|
+
import { SECTIONS, COMPONENT, type Job } from '@bundle-stats/utils';
|
|
4
4
|
|
|
5
|
+
import { WebpackChunk } from '@bundle-stats/utils';
|
|
5
6
|
import { SortAction } from '../../types';
|
|
6
7
|
import config from '../../config.json';
|
|
7
8
|
import I18N from '../../i18n';
|
|
@@ -29,7 +30,7 @@ import { MetricsTableTitle } from '../metrics-table-title';
|
|
|
29
30
|
import { ModuleInfo } from '../module-info';
|
|
30
31
|
import { generateFilterFieldsData } from './bundle-modules.utils';
|
|
31
32
|
import { ModuleMetric } from './bundle-modules.constants';
|
|
32
|
-
import type {
|
|
33
|
+
import type { ReportMetricModuleRow } from './bundle-modules.types';
|
|
33
34
|
import * as I18N_MODULES from './bundle-modules.i18n';
|
|
34
35
|
import css from './bundle-modules.module.css';
|
|
35
36
|
import { useMetricsDisplayType } from '../../hooks/metrics-display-type';
|
|
@@ -73,12 +74,22 @@ interface ViewMetricsTreemapProps {
|
|
|
73
74
|
emptyMessage: React.ReactNode;
|
|
74
75
|
showEntryInfo: React.ComponentProps<typeof MetricsTreemap>['onItemClick'];
|
|
75
76
|
updateSearch: (newSerarch: string) => void;
|
|
77
|
+
search: string;
|
|
76
78
|
}
|
|
77
79
|
|
|
78
80
|
const ViewMetricsTreemap = (props: ViewMetricsTreemapProps) => {
|
|
79
|
-
const {
|
|
80
|
-
|
|
81
|
+
const {
|
|
82
|
+
metricsTableTitle,
|
|
83
|
+
jobs,
|
|
84
|
+
items,
|
|
85
|
+
displayType,
|
|
86
|
+
emptyMessage,
|
|
87
|
+
showEntryInfo,
|
|
88
|
+
updateSearch,
|
|
89
|
+
search,
|
|
90
|
+
} = props;
|
|
81
91
|
|
|
92
|
+
// Get treenodes based on group
|
|
82
93
|
const treeNodes = useMemo(() => {
|
|
83
94
|
if (displayType.groupBy === 'folder') {
|
|
84
95
|
return getTreemapNodesGroupedByPath(items);
|
|
@@ -87,19 +98,28 @@ const ViewMetricsTreemap = (props: ViewMetricsTreemapProps) => {
|
|
|
87
98
|
return getTreemapNodes(items);
|
|
88
99
|
}, [items, displayType]);
|
|
89
100
|
|
|
101
|
+
// Search based on the group path on group title click
|
|
90
102
|
const onGroupClick = useCallback(
|
|
91
103
|
(groupPath: string) => {
|
|
104
|
+
// Clear seach when groupPath is emty (root)
|
|
105
|
+
if (groupPath === '') {
|
|
106
|
+
updateSearch('');
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
92
109
|
// Search by group path
|
|
93
110
|
// 1. use `^` to match only the string beggining
|
|
94
|
-
// 2. add `/` suffix to match
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
111
|
+
// 2. add `/` suffix to exactly match the directory
|
|
112
|
+
const newSearch = `^${groupPath}/`;
|
|
113
|
+
|
|
114
|
+
// Reset search when toggling the same groupPath
|
|
115
|
+
if (newSearch === search) {
|
|
99
116
|
updateSearch('');
|
|
117
|
+
return;
|
|
100
118
|
}
|
|
119
|
+
|
|
120
|
+
updateSearch(newSearch);
|
|
101
121
|
},
|
|
102
|
-
[updateSearch],
|
|
122
|
+
[updateSearch, search],
|
|
103
123
|
);
|
|
104
124
|
|
|
105
125
|
return (
|
|
@@ -122,7 +142,7 @@ interface BundleModulesProps extends React.ComponentProps<'div'> {
|
|
|
122
142
|
jobs?: Array<Job>;
|
|
123
143
|
items?: Array<ReportMetricModuleRow>;
|
|
124
144
|
allItems?: Array<ReportMetricModuleRow>;
|
|
125
|
-
chunks?: Array<
|
|
145
|
+
chunks?: Array<WebpackChunk>;
|
|
126
146
|
|
|
127
147
|
totalRowCount: number;
|
|
128
148
|
|
|
@@ -305,6 +325,7 @@ export const BundleModules = (props: BundleModulesProps) => {
|
|
|
305
325
|
emptyMessage={emptyMessage}
|
|
306
326
|
showEntryInfo={showEntryInfo}
|
|
307
327
|
updateSearch={updateSearch}
|
|
328
|
+
search={search}
|
|
308
329
|
/>
|
|
309
330
|
)}
|
|
310
331
|
</Box>
|
|
@@ -1,10 +1,5 @@
|
|
|
1
|
-
import { Module } from '@bundle-stats/utils/lib-esm/webpack/types';
|
|
2
|
-
import { ReportMetricRun } from '@bundle-stats/utils/types/report/types';
|
|
3
|
-
|
|
4
|
-
export interface Chunk {
|
|
5
|
-
id: string;
|
|
6
|
-
name: string;
|
|
7
|
-
}
|
|
1
|
+
import type { Module } from '@bundle-stats/utils/lib-esm/webpack/types';
|
|
2
|
+
import type { ReportMetricRun } from '@bundle-stats/utils/types/report/types';
|
|
8
3
|
|
|
9
4
|
export type ReportMetricModuleRow = {
|
|
10
5
|
thirdParty: boolean;
|
|
@@ -12,13 +7,3 @@ export type ReportMetricModuleRow = {
|
|
|
12
7
|
fileType: string;
|
|
13
8
|
} & ReportMetricRun &
|
|
14
9
|
Module;
|
|
15
|
-
|
|
16
|
-
export interface Job {
|
|
17
|
-
label: string;
|
|
18
|
-
internalBuildNumber: number;
|
|
19
|
-
meta?: {
|
|
20
|
-
webpack?: {
|
|
21
|
-
chunks?: Array<Chunk>;
|
|
22
|
-
};
|
|
23
|
-
};
|
|
24
|
-
}
|
|
@@ -2,12 +2,11 @@ import intersection from 'lodash/intersection';
|
|
|
2
2
|
import get from 'lodash/get';
|
|
3
3
|
import isEmpty from 'lodash/isEmpty';
|
|
4
4
|
import union from 'lodash/union';
|
|
5
|
-
import uniqBy from 'lodash/uniqBy';
|
|
6
5
|
import orderBy from 'lodash/orderBy';
|
|
7
|
-
import type { MetricRunInfo, ReportMetricRow } from '@bundle-stats/utils';
|
|
8
|
-
// @ts-ignore
|
|
9
|
-
import { MODULE_PATH_PACKAGES, type Module } from '@bundle-stats/utils/lib-esm/webpack';
|
|
10
6
|
import {
|
|
7
|
+
type WebpackChunk,
|
|
8
|
+
type MetricRunInfo,
|
|
9
|
+
type ReportMetricRow,
|
|
11
10
|
FILE_TYPE_LABELS,
|
|
12
11
|
MODULE_CHUNK,
|
|
13
12
|
MODULE_FILTERS,
|
|
@@ -19,10 +18,12 @@ import {
|
|
|
19
18
|
getModuleSourceTypeFilters,
|
|
20
19
|
getModuleFileTypeFilters,
|
|
21
20
|
} from '@bundle-stats/utils';
|
|
21
|
+
// @ts-ignore
|
|
22
|
+
import { MODULE_PATH_PACKAGES, type Module } from '@bundle-stats/utils/lib-esm/webpack';
|
|
22
23
|
import type { ReportMetricRun } from '@bundle-stats/utils/types/report/types';
|
|
23
24
|
|
|
24
25
|
import type { FilterFieldsData, FilterGroupFieldData } from '../../types';
|
|
25
|
-
import type {
|
|
26
|
+
import type { ReportMetricModuleRow } from './bundle-modules.types';
|
|
26
27
|
import * as I18N from './bundle-modules.i18n';
|
|
27
28
|
|
|
28
29
|
export const addRowFlags = (row: Module & ReportMetricRow): ReportMetricModuleRow => {
|
|
@@ -98,18 +99,6 @@ export const generateGetRowFilter =
|
|
|
98
99
|
};
|
|
99
100
|
/* eslint-enable prettier/prettier */
|
|
100
101
|
|
|
101
|
-
export const extractChunkData = (jobs: Array<Job>) => {
|
|
102
|
-
const jobChunks = jobs.map((job) => job?.meta?.webpack?.chunks || []);
|
|
103
|
-
const chunks = uniqBy(jobChunks.flat(), ({ id }) => id);
|
|
104
|
-
|
|
105
|
-
const chunkIds = chunks?.map(({ id }) => id);
|
|
106
|
-
|
|
107
|
-
return {
|
|
108
|
-
chunks,
|
|
109
|
-
chunkIds,
|
|
110
|
-
};
|
|
111
|
-
};
|
|
112
|
-
|
|
113
102
|
export const generateFilters = (chunkIds: Array<string>, multipleJobs: boolean) => {
|
|
114
103
|
const allEntriesFilters = {
|
|
115
104
|
[MODULE_FILTERS.CHANGED]: false,
|
|
@@ -137,7 +126,7 @@ interface GetFiltersFormDataParams {
|
|
|
137
126
|
/**
|
|
138
127
|
* Chunk data
|
|
139
128
|
*/
|
|
140
|
-
chunks: Array<
|
|
129
|
+
chunks: Array<WebpackChunk>;
|
|
141
130
|
/**
|
|
142
131
|
* Compare mode
|
|
143
132
|
*/
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import React, { useCallback, useMemo } from 'react';
|
|
2
|
+
import type { Job } from '@bundle-stats/utils';
|
|
2
3
|
// @ts-ignore
|
|
3
4
|
import * as webpack from '@bundle-stats/utils/lib-esm/webpack';
|
|
4
5
|
|
|
5
6
|
import type { SortAction } from '../../types';
|
|
7
|
+
import { getJobsChunksData } from '../../utils/jobs';
|
|
6
8
|
import { useRowsFilter } from '../../hooks/rows-filter';
|
|
7
9
|
import { useRowsSort } from '../../hooks/rows-sort';
|
|
8
10
|
import { useSearchParams } from '../../hooks/search-params';
|
|
@@ -10,7 +12,6 @@ import { useEntryInfo } from '../../hooks/entry-info';
|
|
|
10
12
|
import { BundleModules as BaseComponent } from './bundle-modules';
|
|
11
13
|
import {
|
|
12
14
|
addRowFlags,
|
|
13
|
-
extractChunkData,
|
|
14
15
|
generateGetRowFilter,
|
|
15
16
|
generateFilters,
|
|
16
17
|
getCustomSort,
|
|
@@ -64,7 +65,7 @@ interface BundleModulesProps
|
|
|
64
65
|
| 'hideEntryInfo'
|
|
65
66
|
| 'showEntryInfo'
|
|
66
67
|
> {
|
|
67
|
-
jobs: Array<
|
|
68
|
+
jobs: Array<Job>;
|
|
68
69
|
filters: Record<string, boolean>;
|
|
69
70
|
search?: string;
|
|
70
71
|
metric?: string;
|
|
@@ -78,7 +79,7 @@ export const BundleModules = (props: BundleModulesProps) => {
|
|
|
78
79
|
|
|
79
80
|
const [moduleMetric, setModuleMetric] = useModuleMetric({ metric, setState });
|
|
80
81
|
|
|
81
|
-
const { chunks, chunkIds } = useMemo(() =>
|
|
82
|
+
const { chunks, chunkIds } = useMemo(() => getJobsChunksData(jobs), [jobs]);
|
|
82
83
|
|
|
83
84
|
const { defaultFilters, allEntriesFilters } = useMemo(
|
|
84
85
|
() => generateFilters(chunkIds, jobs.length > 1),
|
|
@@ -120,8 +120,9 @@ RowHeader.propTypes = {
|
|
|
120
120
|
};
|
|
121
121
|
|
|
122
122
|
const ViewMetricsTreemap = (props) => {
|
|
123
|
-
const { metricsTableTitle, jobs, items, displayType, emptyMessage, showEntryInfo, updateSearch } = props;
|
|
123
|
+
const { metricsTableTitle, jobs, items, displayType, emptyMessage, showEntryInfo, updateSearch, search } = props;
|
|
124
124
|
|
|
125
|
+
// Get treenodes based on group
|
|
125
126
|
const treeNodes = useMemo(() => {
|
|
126
127
|
if (displayType.groupBy === 'folder') {
|
|
127
128
|
return getTreemapNodesGroupedByPath(items);
|
|
@@ -130,19 +131,28 @@ const ViewMetricsTreemap = (props) => {
|
|
|
130
131
|
return getTreemapNodes(items);
|
|
131
132
|
}, [items, displayType.groupBy]);
|
|
132
133
|
|
|
134
|
+
// Search based on the group path on group title click
|
|
133
135
|
const onGroupClick = useCallback(
|
|
134
136
|
(groupPath) => {
|
|
137
|
+
// Clear seach when groupPath is emty (root)
|
|
138
|
+
if (groupPath === '') {
|
|
139
|
+
updateSearch('');
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
135
142
|
// Search by group path
|
|
136
143
|
// 1. use `^` to match only the string beggining
|
|
137
|
-
// 2. add `/` suffix to match
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
144
|
+
// 2. add `/` suffix to exactly match the directory
|
|
145
|
+
const newSearch = `^${groupPath}/`;
|
|
146
|
+
|
|
147
|
+
// Reset search when toggling the same groupPath
|
|
148
|
+
if (newSearch === search) {
|
|
142
149
|
updateSearch('');
|
|
150
|
+
return;
|
|
143
151
|
}
|
|
152
|
+
|
|
153
|
+
updateSearch(newSearch);
|
|
144
154
|
},
|
|
145
|
-
[updateSearch],
|
|
155
|
+
[updateSearch, search],
|
|
146
156
|
);
|
|
147
157
|
|
|
148
158
|
return (
|
|
@@ -171,6 +181,7 @@ ViewMetricsTreemap.propTypes = {
|
|
|
171
181
|
emptyMessage: PropTypes.node.isRequired,
|
|
172
182
|
showEntryInfo: PropTypes.func.isRequired,
|
|
173
183
|
updateSearch: PropTypes.func.isRequired,
|
|
184
|
+
search: PropTypes.string.isRequired,
|
|
174
185
|
};
|
|
175
186
|
|
|
176
187
|
export const BundlePackages = (props) => {
|
|
@@ -300,6 +311,7 @@ export const BundlePackages = (props) => {
|
|
|
300
311
|
emptyMessage={emptyMessage}
|
|
301
312
|
showEntryInfo={showEntryInfo}
|
|
302
313
|
updateSearch={updateSearch}
|
|
314
|
+
search={search}
|
|
303
315
|
/>
|
|
304
316
|
)}
|
|
305
317
|
</Box>
|
|
@@ -50,3 +50,14 @@ export interface Tree {
|
|
|
50
50
|
export type TreeNode = Tree | TreeLeaf;
|
|
51
51
|
|
|
52
52
|
export type TreeNodeChildren = Array<TreeNode>;
|
|
53
|
+
|
|
54
|
+
export type TileGroupSizeDisplay = 'minimal' | 'small' | 'default';
|
|
55
|
+
|
|
56
|
+
export type TileSizeDisplay = 'minimal' | 'small' | 'default';
|
|
57
|
+
|
|
58
|
+
export const SQUARIFY_RATIO = 1.66;
|
|
59
|
+
export const PADDING_OUTER = 1;
|
|
60
|
+
export const PADDING_INNER = 2;
|
|
61
|
+
export const NESTED_PADDING = 4;
|
|
62
|
+
export const NESTED_PADDING_TOP = 16 + NESTED_PADDING * 2;
|
|
63
|
+
export const NESTED_PADDING_LEFT = 8;
|
|
@@ -25,26 +25,58 @@
|
|
|
25
25
|
|
|
26
26
|
.tileGroupTitle {
|
|
27
27
|
width: 100%;
|
|
28
|
-
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.tileGroupTitleContent {
|
|
31
|
+
width: 100%;
|
|
32
|
+
padding: var(--space-xxxsmall) 2px var(--space-xxxsmall) var(--space-xxsmall);
|
|
33
|
+
display: flex;
|
|
34
|
+
align-items: center;
|
|
29
35
|
color: var(--color-text);
|
|
30
36
|
font-family: var(--font-family-fixed);
|
|
31
37
|
font-size: 10px;
|
|
32
|
-
line-height:
|
|
38
|
+
line-height: var(--space-small);
|
|
33
39
|
overflow: hidden;
|
|
34
40
|
white-space: nowrap;
|
|
35
41
|
text-overflow: ellipsis;
|
|
36
42
|
}
|
|
37
43
|
|
|
44
|
+
.tileGroupTitleText,
|
|
38
45
|
.tileGroupTitleTotal {
|
|
39
|
-
|
|
46
|
+
flex: 0 0 auto;
|
|
47
|
+
min-width: 0;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.tileGroupTitleTotal {
|
|
51
|
+
margin-left: var(--space-xxsmall);
|
|
52
|
+
color: var(--color-text-light);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.tileGroupTitle {
|
|
56
|
+
transition: var(--ui-transition-out);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.tileGroupTitle:hover .tileGroupTitleText {
|
|
60
|
+
text-decoration: underline;
|
|
61
|
+
transition: var(--ui-transition-in);
|
|
40
62
|
}
|
|
41
63
|
|
|
42
64
|
/** Tile group size variation */
|
|
43
|
-
.
|
|
65
|
+
.tileGroup {
|
|
44
66
|
transition: var(--ui-transition-in);
|
|
45
67
|
transition-property: left, top, width, height;
|
|
46
68
|
}
|
|
47
69
|
|
|
70
|
+
.tileGroup--minimal .tileGroupTitle,
|
|
71
|
+
.tileGroup--small .tileGroupTitle {
|
|
72
|
+
height: 100%; /* full height when title is missing or we do not render any children */
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.tileGroup--minimal .tileGroupTitleContent,
|
|
76
|
+
.tileGroup--small .tileGroupTitleContent {
|
|
77
|
+
min-height: 100%;
|
|
78
|
+
}
|
|
79
|
+
|
|
48
80
|
/** Tile group nested variation */
|
|
49
81
|
.nested .tileGroup {
|
|
50
82
|
background-color: rgba(27, 26, 33, 0.05);
|
|
@@ -141,7 +173,13 @@
|
|
|
141
173
|
flex: 0 1 auto;
|
|
142
174
|
width: 100%;
|
|
143
175
|
min-width: 0;
|
|
144
|
-
max-height: calc(2em * var(--line-height-heading));
|
|
176
|
+
max-height: calc(2em * var(--line-height-heading)); /* render max 2 rows */
|
|
177
|
+
overflow-wrap: break-word;
|
|
178
|
+
word-wrap: break-word;
|
|
179
|
+
word-break: break-all;
|
|
180
|
+
word-break: break-word;
|
|
181
|
+
hyphens: auto;
|
|
182
|
+
white-space: normal;
|
|
145
183
|
overflow: hidden;
|
|
146
184
|
}
|
|
147
185
|
|
|
@@ -162,9 +200,8 @@
|
|
|
162
200
|
|
|
163
201
|
/** Tile size variation */
|
|
164
202
|
.tileSizeSmall .tileContent {
|
|
165
|
-
padding: var(--space-xxxsmall)
|
|
166
|
-
|
|
167
|
-
font-size: var(--size-xsmall);
|
|
203
|
+
padding: var(--space-xxxsmall);
|
|
204
|
+
font-size: 10px;
|
|
168
205
|
}
|
|
169
206
|
|
|
170
207
|
.tileSizeSmall .tileContentLabel {
|
|
@@ -173,7 +210,7 @@
|
|
|
173
210
|
|
|
174
211
|
.tileSizeDefault {
|
|
175
212
|
transition: var(--ui-transition-in);
|
|
176
|
-
transition-property: left top width height;
|
|
213
|
+
transition-property: left, top, width, height;
|
|
177
214
|
}
|
|
178
215
|
|
|
179
216
|
/** Tile diff variation */
|
|
@@ -196,7 +233,7 @@
|
|
|
196
233
|
}
|
|
197
234
|
|
|
198
235
|
.tile-NO_CHANGE {
|
|
199
|
-
color: var(--color-text-
|
|
236
|
+
color: var(--color-text-light);
|
|
200
237
|
}
|
|
201
238
|
|
|
202
239
|
.tile-NO_CHANGE::before {
|