@bundle-stats/ui 4.13.0-rc.0 → 4.13.0-rc.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/components/bundle-assets/bundle-assets.js +24 -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 +11 -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 +12 -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 +58 -26
- 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 +24 -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 +11 -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 +12 -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 +58 -26
- 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 +74 -48
- package/src/components/bundle-assets/index.jsx +4 -0
- package/src/components/bundle-modules/bundle-modules.tsx +33 -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 +21 -7
- package/src/components/metrics-treemap/metrics-treemap.constants.ts +11 -0
- package/src/components/metrics-treemap/metrics-treemap.module.css +58 -26
- package/src/components/metrics-treemap/metrics-treemap.tsx +173 -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
|
@@ -2,6 +2,7 @@ import React, { useCallback, useMemo } from 'react';
|
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
3
|
import cx from 'classnames';
|
|
4
4
|
import get from 'lodash/get';
|
|
5
|
+
import escapeRegExp from 'lodash/escapeRegExp';
|
|
5
6
|
import {
|
|
6
7
|
ASSET_ENTRY_TYPE,
|
|
7
8
|
ASSET_FILE_TYPE,
|
|
@@ -48,12 +49,11 @@ const DISPLAY_TYPE_GROUPS = {
|
|
|
48
49
|
};
|
|
49
50
|
|
|
50
51
|
const getFileTypeFilters = (filters) =>
|
|
51
|
-
Object.entries(FILE_TYPE_LABELS)
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
}));
|
|
52
|
+
Object.entries(FILE_TYPE_LABELS).map(([key, label]) => ({
|
|
53
|
+
key,
|
|
54
|
+
label,
|
|
55
|
+
defaultValue: get(filters, `${ASSET_FILE_TYPE}.${key}`, true),
|
|
56
|
+
}));
|
|
57
57
|
|
|
58
58
|
const getFilters = ({ compareMode, filters }) => ({
|
|
59
59
|
[ASSET_FILTERS.CHANGED]: {
|
|
@@ -146,6 +146,7 @@ const RowHeader = ({ row, customComponentLink: CustomComponentLink, filters, sea
|
|
|
146
146
|
|
|
147
147
|
RowHeader.propTypes = {
|
|
148
148
|
row: PropTypes.shape({
|
|
149
|
+
key: PropTypes.string,
|
|
149
150
|
label: PropTypes.string,
|
|
150
151
|
isNotPredictive: PropTypes.bool,
|
|
151
152
|
isChunk: PropTypes.bool,
|
|
@@ -153,23 +154,28 @@ RowHeader.propTypes = {
|
|
|
153
154
|
isEntry: PropTypes.bool,
|
|
154
155
|
runs: PropTypes.arrayOf(PropTypes.object), // eslint-disable-line react/forbid-prop-types
|
|
155
156
|
}).isRequired,
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
name: PropTypes.string,
|
|
160
|
-
}),
|
|
161
|
-
),
|
|
162
|
-
labels: PropTypes.arrayOf(PropTypes.string).isRequired,
|
|
163
|
-
CustomComponentLink: PropTypes.elementType.isRequired,
|
|
157
|
+
customComponentLink: PropTypes.elementType.isRequired,
|
|
158
|
+
filters: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
|
|
159
|
+
search: PropTypes.string,
|
|
164
160
|
};
|
|
165
161
|
|
|
166
162
|
RowHeader.defaultProps = {
|
|
167
|
-
|
|
163
|
+
search: '',
|
|
168
164
|
};
|
|
169
165
|
|
|
170
166
|
const ViewMetricsTreemap = (props) => {
|
|
171
|
-
const {
|
|
167
|
+
const {
|
|
168
|
+
metricsTableTitle,
|
|
169
|
+
jobs,
|
|
170
|
+
items,
|
|
171
|
+
displayType,
|
|
172
|
+
emptyMessage,
|
|
173
|
+
showEntryInfo,
|
|
174
|
+
updateSearch,
|
|
175
|
+
search,
|
|
176
|
+
} = props;
|
|
172
177
|
|
|
178
|
+
// Get treenodes based on group
|
|
173
179
|
const treeNodes = useMemo(() => {
|
|
174
180
|
if (displayType.groupBy === 'folder') {
|
|
175
181
|
return getTreemapNodesGroupedByPath(items);
|
|
@@ -178,19 +184,28 @@ const ViewMetricsTreemap = (props) => {
|
|
|
178
184
|
return getTreemapNodes(items);
|
|
179
185
|
}, [items, displayType.groupBy]);
|
|
180
186
|
|
|
187
|
+
// Search based on the group path on group title click
|
|
181
188
|
const onGroupClick = useCallback(
|
|
182
189
|
(groupPath) => {
|
|
190
|
+
// Clear seach when groupPath is emty (root)
|
|
191
|
+
if (groupPath === '') {
|
|
192
|
+
updateSearch('');
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
183
195
|
// Search by group path
|
|
184
196
|
// 1. use `^` to match only the string beggining
|
|
185
|
-
// 2. add `/` suffix to match
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
197
|
+
// 2. add `/` suffix to exactly match the directory
|
|
198
|
+
const newSearch = `^${escapeRegExp(groupPath)}/`;
|
|
199
|
+
|
|
200
|
+
// Reset search when toggling the same groupPath
|
|
201
|
+
if (newSearch === search) {
|
|
190
202
|
updateSearch('');
|
|
203
|
+
return;
|
|
191
204
|
}
|
|
205
|
+
|
|
206
|
+
updateSearch(`^${groupPath}/`);
|
|
192
207
|
},
|
|
193
|
-
[updateSearch],
|
|
208
|
+
[updateSearch, search],
|
|
194
209
|
);
|
|
195
210
|
|
|
196
211
|
return (
|
|
@@ -219,12 +234,14 @@ ViewMetricsTreemap.propTypes = {
|
|
|
219
234
|
emptyMessage: PropTypes.node.isRequired,
|
|
220
235
|
showEntryInfo: PropTypes.func.isRequired,
|
|
221
236
|
updateSearch: PropTypes.func.isRequired,
|
|
237
|
+
search: PropTypes.string.isRequired,
|
|
222
238
|
};
|
|
223
239
|
|
|
224
240
|
export const BundleAssets = (props) => {
|
|
225
241
|
const {
|
|
226
242
|
className,
|
|
227
243
|
jobs,
|
|
244
|
+
chunks,
|
|
228
245
|
items,
|
|
229
246
|
allItems,
|
|
230
247
|
updateFilters,
|
|
@@ -252,14 +269,17 @@ export const BundleAssets = (props) => {
|
|
|
252
269
|
[jobs, filters],
|
|
253
270
|
);
|
|
254
271
|
|
|
255
|
-
const metricsTableTitle = useMemo(
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
272
|
+
const metricsTableTitle = useMemo(
|
|
273
|
+
() => (
|
|
274
|
+
<MetricsTableTitle
|
|
275
|
+
title={I18N.ASSETS}
|
|
276
|
+
info={`${items.length}/${totalRowCount}`}
|
|
277
|
+
popoverInfo={I18N.ASSETS_INFO}
|
|
278
|
+
popoverHref={config.documentation.assets}
|
|
279
|
+
/>
|
|
280
|
+
),
|
|
281
|
+
[items, totalRowCount],
|
|
282
|
+
);
|
|
263
283
|
|
|
264
284
|
const renderRowHeader = useCallback(
|
|
265
285
|
(row) => (
|
|
@@ -273,21 +293,24 @@ export const BundleAssets = (props) => {
|
|
|
273
293
|
[CustomComponentLink, filters, search],
|
|
274
294
|
);
|
|
275
295
|
|
|
276
|
-
const emptyMessage = useMemo(
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
296
|
+
const emptyMessage = useMemo(
|
|
297
|
+
() => (
|
|
298
|
+
<EmptySet
|
|
299
|
+
resources="assets"
|
|
300
|
+
filtered={totalRowCount !== 0}
|
|
301
|
+
handleResetFilters={resetFilters}
|
|
302
|
+
handleViewAll={resetAllFilters}
|
|
303
|
+
/>
|
|
304
|
+
),
|
|
305
|
+
[totalRowCount, resetFilters, resetAllFilters],
|
|
306
|
+
);
|
|
284
307
|
|
|
285
308
|
const entryItem = useMemo(() => {
|
|
286
309
|
if (!entryId) {
|
|
287
310
|
return null;
|
|
288
311
|
}
|
|
289
312
|
|
|
290
|
-
return allItems.find(({ key }) => key === entryId)
|
|
313
|
+
return allItems.find(({ key }) => key === entryId);
|
|
291
314
|
}, [allItems, entryId]);
|
|
292
315
|
|
|
293
316
|
return (
|
|
@@ -341,10 +364,12 @@ export const BundleAssets = (props) => {
|
|
|
341
364
|
<ViewMetricsTreemap
|
|
342
365
|
jobs={jobs}
|
|
343
366
|
items={items}
|
|
367
|
+
metricsTableTitle={metricsTableTitle}
|
|
344
368
|
displayType={displayType}
|
|
345
369
|
emptyMessage={emptyMessage}
|
|
346
370
|
showEntryInfo={showEntryInfo}
|
|
347
371
|
updateSearch={updateSearch}
|
|
372
|
+
search={search}
|
|
348
373
|
/>
|
|
349
374
|
)}
|
|
350
375
|
</Box>
|
|
@@ -355,7 +380,7 @@ export const BundleAssets = (props) => {
|
|
|
355
380
|
className={css.assetInfo}
|
|
356
381
|
item={entryItem}
|
|
357
382
|
labels={jobLabels}
|
|
358
|
-
chunks={
|
|
383
|
+
chunks={chunks}
|
|
359
384
|
customComponentLink={CustomComponentLink}
|
|
360
385
|
onClose={hideEntryInfo}
|
|
361
386
|
/>
|
|
@@ -378,13 +403,12 @@ BundleAssets.propTypes = {
|
|
|
378
403
|
PropTypes.shape({
|
|
379
404
|
internalBuildNumber: PropTypes.number,
|
|
380
405
|
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
406
|
}),
|
|
387
407
|
).isRequired,
|
|
408
|
+
chunks: PropTypes.arrayOf({
|
|
409
|
+
id: PropTypes.string,
|
|
410
|
+
name: PropTypes.string,
|
|
411
|
+
}).isRequired,
|
|
388
412
|
items: PropTypes.arrayOf(
|
|
389
413
|
PropTypes.shape({
|
|
390
414
|
key: PropTypes.string,
|
|
@@ -414,9 +438,11 @@ BundleAssets.propTypes = {
|
|
|
414
438
|
direction: PropTypes.string,
|
|
415
439
|
}).isRequired,
|
|
416
440
|
updateSort: PropTypes.func.isRequired,
|
|
417
|
-
allItems: PropTypes.arrayOf(
|
|
418
|
-
|
|
419
|
-
|
|
441
|
+
allItems: PropTypes.arrayOf(
|
|
442
|
+
PropTypes.shape({
|
|
443
|
+
key: PropTypes.string,
|
|
444
|
+
}),
|
|
445
|
+
).isRequired,
|
|
420
446
|
customComponentLink: PropTypes.elementType,
|
|
421
447
|
hideEntryInfo: PropTypes.func.isRequired,
|
|
422
448
|
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,9 @@
|
|
|
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
|
+
import escapeRegExp from 'lodash/escapeRegExp';
|
|
4
5
|
|
|
6
|
+
import { WebpackChunk } from '@bundle-stats/utils';
|
|
5
7
|
import { SortAction } from '../../types';
|
|
6
8
|
import config from '../../config.json';
|
|
7
9
|
import I18N from '../../i18n';
|
|
@@ -29,7 +31,7 @@ import { MetricsTableTitle } from '../metrics-table-title';
|
|
|
29
31
|
import { ModuleInfo } from '../module-info';
|
|
30
32
|
import { generateFilterFieldsData } from './bundle-modules.utils';
|
|
31
33
|
import { ModuleMetric } from './bundle-modules.constants';
|
|
32
|
-
import type {
|
|
34
|
+
import type { ReportMetricModuleRow } from './bundle-modules.types';
|
|
33
35
|
import * as I18N_MODULES from './bundle-modules.i18n';
|
|
34
36
|
import css from './bundle-modules.module.css';
|
|
35
37
|
import { useMetricsDisplayType } from '../../hooks/metrics-display-type';
|
|
@@ -73,12 +75,22 @@ interface ViewMetricsTreemapProps {
|
|
|
73
75
|
emptyMessage: React.ReactNode;
|
|
74
76
|
showEntryInfo: React.ComponentProps<typeof MetricsTreemap>['onItemClick'];
|
|
75
77
|
updateSearch: (newSerarch: string) => void;
|
|
78
|
+
search: string;
|
|
76
79
|
}
|
|
77
80
|
|
|
78
81
|
const ViewMetricsTreemap = (props: ViewMetricsTreemapProps) => {
|
|
79
|
-
const {
|
|
80
|
-
|
|
82
|
+
const {
|
|
83
|
+
metricsTableTitle,
|
|
84
|
+
jobs,
|
|
85
|
+
items,
|
|
86
|
+
displayType,
|
|
87
|
+
emptyMessage,
|
|
88
|
+
showEntryInfo,
|
|
89
|
+
updateSearch,
|
|
90
|
+
search,
|
|
91
|
+
} = props;
|
|
81
92
|
|
|
93
|
+
// Get treenodes based on group
|
|
82
94
|
const treeNodes = useMemo(() => {
|
|
83
95
|
if (displayType.groupBy === 'folder') {
|
|
84
96
|
return getTreemapNodesGroupedByPath(items);
|
|
@@ -87,19 +99,28 @@ const ViewMetricsTreemap = (props: ViewMetricsTreemapProps) => {
|
|
|
87
99
|
return getTreemapNodes(items);
|
|
88
100
|
}, [items, displayType]);
|
|
89
101
|
|
|
102
|
+
// Search based on the group path on group title click
|
|
90
103
|
const onGroupClick = useCallback(
|
|
91
104
|
(groupPath: string) => {
|
|
105
|
+
// Clear seach when groupPath is emty (root)
|
|
106
|
+
if (groupPath === '') {
|
|
107
|
+
updateSearch('');
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
92
110
|
// Search by group path
|
|
93
111
|
// 1. use `^` to match only the string beggining
|
|
94
|
-
// 2. add `/` suffix to match
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
112
|
+
// 2. add `/` suffix to exactly match the directory
|
|
113
|
+
const newSearch = `^${escapeRegExp(groupPath)}/`;
|
|
114
|
+
|
|
115
|
+
// Reset search when toggling the same groupPath
|
|
116
|
+
if (newSearch === search) {
|
|
99
117
|
updateSearch('');
|
|
118
|
+
return;
|
|
100
119
|
}
|
|
120
|
+
|
|
121
|
+
updateSearch(newSearch);
|
|
101
122
|
},
|
|
102
|
-
[updateSearch],
|
|
123
|
+
[updateSearch, search],
|
|
103
124
|
);
|
|
104
125
|
|
|
105
126
|
return (
|
|
@@ -122,7 +143,7 @@ interface BundleModulesProps extends React.ComponentProps<'div'> {
|
|
|
122
143
|
jobs?: Array<Job>;
|
|
123
144
|
items?: Array<ReportMetricModuleRow>;
|
|
124
145
|
allItems?: Array<ReportMetricModuleRow>;
|
|
125
|
-
chunks?: Array<
|
|
146
|
+
chunks?: Array<WebpackChunk>;
|
|
126
147
|
|
|
127
148
|
totalRowCount: number;
|
|
128
149
|
|
|
@@ -305,6 +326,7 @@ export const BundleModules = (props: BundleModulesProps) => {
|
|
|
305
326
|
emptyMessage={emptyMessage}
|
|
306
327
|
showEntryInfo={showEntryInfo}
|
|
307
328
|
updateSearch={updateSearch}
|
|
329
|
+
search={search}
|
|
308
330
|
/>
|
|
309
331
|
)}
|
|
310
332
|
</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),
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React, { useCallback, useMemo } from 'react';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
3
|
import cx from 'classnames';
|
|
4
|
+
import { escapeRegExp } from 'lodash/escapeRegExp';
|
|
4
5
|
import { COMPONENT, PACKAGE_FILTERS, PACKAGES_SEPARATOR, SECTIONS } from '@bundle-stats/utils';
|
|
5
6
|
|
|
6
7
|
import config from '../../config.json';
|
|
@@ -120,8 +121,9 @@ RowHeader.propTypes = {
|
|
|
120
121
|
};
|
|
121
122
|
|
|
122
123
|
const ViewMetricsTreemap = (props) => {
|
|
123
|
-
const { metricsTableTitle, jobs, items, displayType, emptyMessage, showEntryInfo, updateSearch } = props;
|
|
124
|
+
const { metricsTableTitle, jobs, items, displayType, emptyMessage, showEntryInfo, updateSearch, search } = props;
|
|
124
125
|
|
|
126
|
+
// Get treenodes based on group
|
|
125
127
|
const treeNodes = useMemo(() => {
|
|
126
128
|
if (displayType.groupBy === 'folder') {
|
|
127
129
|
return getTreemapNodesGroupedByPath(items);
|
|
@@ -130,19 +132,28 @@ const ViewMetricsTreemap = (props) => {
|
|
|
130
132
|
return getTreemapNodes(items);
|
|
131
133
|
}, [items, displayType.groupBy]);
|
|
132
134
|
|
|
135
|
+
// Search based on the group path on group title click
|
|
133
136
|
const onGroupClick = useCallback(
|
|
134
137
|
(groupPath) => {
|
|
138
|
+
// Clear seach when groupPath is emty (root)
|
|
139
|
+
if (groupPath === '') {
|
|
140
|
+
updateSearch('');
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
135
143
|
// Search by group path
|
|
136
144
|
// 1. use `^` to match only the string beggining
|
|
137
|
-
// 2. add `/` suffix to match
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
145
|
+
// 2. add `/` suffix to exactly match the directory
|
|
146
|
+
const newSearch = `^${escapeRegExp(groupPath)}/`;
|
|
147
|
+
|
|
148
|
+
// Reset search when toggling the same groupPath
|
|
149
|
+
if (newSearch === search) {
|
|
142
150
|
updateSearch('');
|
|
151
|
+
return;
|
|
143
152
|
}
|
|
153
|
+
|
|
154
|
+
updateSearch(newSearch);
|
|
144
155
|
},
|
|
145
|
-
[updateSearch],
|
|
156
|
+
[updateSearch, search],
|
|
146
157
|
);
|
|
147
158
|
|
|
148
159
|
return (
|
|
@@ -171,6 +182,7 @@ ViewMetricsTreemap.propTypes = {
|
|
|
171
182
|
emptyMessage: PropTypes.node.isRequired,
|
|
172
183
|
showEntryInfo: PropTypes.func.isRequired,
|
|
173
184
|
updateSearch: PropTypes.func.isRequired,
|
|
185
|
+
search: PropTypes.string.isRequired,
|
|
174
186
|
};
|
|
175
187
|
|
|
176
188
|
export const BundlePackages = (props) => {
|
|
@@ -296,10 +308,12 @@ export const BundlePackages = (props) => {
|
|
|
296
308
|
<ViewMetricsTreemap
|
|
297
309
|
jobs={jobs}
|
|
298
310
|
items={items}
|
|
311
|
+
metricsTableTitle={metricsTableTitle}
|
|
299
312
|
displayType={displayType}
|
|
300
313
|
emptyMessage={emptyMessage}
|
|
301
314
|
showEntryInfo={showEntryInfo}
|
|
302
315
|
updateSearch={updateSearch}
|
|
316
|
+
search={search}
|
|
303
317
|
/>
|
|
304
318
|
)}
|
|
305
319
|
</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;
|