@bundle-stats/ui 4.16.0 → 4.17.0-beta.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.
Files changed (103) hide show
  1. package/lib/components/asset-info/asset-info.js +14 -5
  2. package/lib/components/asset-info/asset-info.js.map +1 -1
  3. package/lib/components/asset-info/asset-info.module.css +9 -0
  4. package/lib/components/asset-meta-tag/asset-meta-tag.js +17 -0
  5. package/lib/components/asset-meta-tag/asset-meta-tag.js.map +1 -0
  6. package/lib/components/asset-meta-tag/asset-meta-tag.module.css +56 -0
  7. package/lib/components/asset-meta-tag/index.js +18 -0
  8. package/lib/components/asset-meta-tag/index.js.map +1 -0
  9. package/lib/components/asset-name/asset-name.js +31 -0
  10. package/lib/components/asset-name/asset-name.js.map +1 -0
  11. package/lib/components/asset-name/asset-name.module.css +32 -0
  12. package/lib/components/asset-name/index.js +18 -0
  13. package/lib/components/asset-name/index.js.map +1 -0
  14. package/lib/components/asset-not-predictive/asset-not-predictive.js +6 -4
  15. package/lib/components/asset-not-predictive/asset-not-predictive.js.map +1 -1
  16. package/lib/components/asset-not-predictive/asset-not-predictive.module.css +6 -1
  17. package/lib/components/bundle-assets/bundle-assets.js +3 -38
  18. package/lib/components/bundle-assets/bundle-assets.js.map +1 -1
  19. package/lib/components/bundle-assets/bundle-assets.module.css +0 -64
  20. package/lib/components/bundle-assets/bundle-assets.utils.js +62 -29
  21. package/lib/components/bundle-assets/bundle-assets.utils.js.map +1 -1
  22. package/lib/components/bundle-assets/index.js +1 -1
  23. package/lib/components/bundle-assets/index.js.map +1 -1
  24. package/lib/components/entry-info/entry-info.js +4 -3
  25. package/lib/components/entry-info/entry-info.js.map +1 -1
  26. package/lib/components/metrics-treemap/metrics-treemap.utils.js +0 -1
  27. package/lib/components/metrics-treemap/metrics-treemap.utils.js.map +1 -1
  28. package/lib/components/preview-source/preview-source.js +1 -1
  29. package/lib/components/preview-source/preview-source.js.map +1 -1
  30. package/lib/stories/wrapper.js +5 -2
  31. package/lib/stories/wrapper.js.map +1 -1
  32. package/lib/ui/tag/tag.js.map +1 -1
  33. package/lib-esm/components/asset-info/asset-info.js +14 -5
  34. package/lib-esm/components/asset-info/asset-info.js.map +1 -1
  35. package/lib-esm/components/asset-info/asset-info.module.css +9 -0
  36. package/lib-esm/components/asset-meta-tag/asset-meta-tag.js +10 -0
  37. package/lib-esm/components/asset-meta-tag/asset-meta-tag.js.map +1 -0
  38. package/lib-esm/components/asset-meta-tag/asset-meta-tag.module.css +56 -0
  39. package/lib-esm/components/asset-meta-tag/index.js +2 -0
  40. package/lib-esm/components/asset-meta-tag/index.js.map +1 -0
  41. package/lib-esm/components/asset-name/asset-name.js +24 -0
  42. package/lib-esm/components/asset-name/asset-name.js.map +1 -0
  43. package/lib-esm/components/asset-name/asset-name.module.css +32 -0
  44. package/lib-esm/components/asset-name/index.js +2 -0
  45. package/lib-esm/components/asset-name/index.js.map +1 -0
  46. package/lib-esm/components/asset-not-predictive/asset-not-predictive.js +6 -4
  47. package/lib-esm/components/asset-not-predictive/asset-not-predictive.js.map +1 -1
  48. package/lib-esm/components/asset-not-predictive/asset-not-predictive.module.css +6 -1
  49. package/lib-esm/components/bundle-assets/bundle-assets.js +3 -38
  50. package/lib-esm/components/bundle-assets/bundle-assets.js.map +1 -1
  51. package/lib-esm/components/bundle-assets/bundle-assets.module.css +0 -64
  52. package/lib-esm/components/bundle-assets/bundle-assets.utils.js +58 -25
  53. package/lib-esm/components/bundle-assets/bundle-assets.utils.js.map +1 -1
  54. package/lib-esm/components/bundle-assets/index.js +2 -2
  55. package/lib-esm/components/bundle-assets/index.js.map +1 -1
  56. package/lib-esm/components/entry-info/entry-info.js +4 -3
  57. package/lib-esm/components/entry-info/entry-info.js.map +1 -1
  58. package/lib-esm/components/metrics-treemap/metrics-treemap.utils.js +0 -1
  59. package/lib-esm/components/metrics-treemap/metrics-treemap.utils.js.map +1 -1
  60. package/lib-esm/components/preview-source/preview-source.js +1 -1
  61. package/lib-esm/components/preview-source/preview-source.js.map +1 -1
  62. package/lib-esm/stories/wrapper.js +5 -2
  63. package/lib-esm/stories/wrapper.js.map +1 -1
  64. package/lib-esm/ui/tag/tag.js.map +1 -1
  65. package/package.json +11 -11
  66. package/src/app/app-gladys.stories.tsx +41 -0
  67. package/src/app/app-home-assistant.stories.tsx +41 -0
  68. package/src/app/app-outline.stories.tsx +41 -0
  69. package/src/app/app.stories.tsx +127 -0
  70. package/src/components/asset-info/asset-info.module.css +9 -0
  71. package/src/components/asset-info/asset-info.tsx +46 -14
  72. package/src/components/asset-meta-tag/asset-meta-tag.module.css +56 -0
  73. package/src/components/asset-meta-tag/asset-meta-tag.tsx +34 -0
  74. package/src/components/asset-meta-tag/index.ts +1 -0
  75. package/src/components/asset-name/asset-name.module.css +32 -0
  76. package/src/components/asset-name/asset-name.stories.tsx +85 -0
  77. package/src/components/asset-name/asset-name.tsx +59 -0
  78. package/src/components/asset-name/index.ts +1 -0
  79. package/src/components/asset-not-predictive/asset-not-predictive.module.css +6 -1
  80. package/src/components/asset-not-predictive/asset-not-predictive.tsx +16 -12
  81. package/src/components/bundle-assets/__tests__/add-metric-report-asset-row-data.ts +235 -0
  82. package/src/components/bundle-assets/__tests__/get-asset-meta-status.ts +21 -0
  83. package/src/components/bundle-assets/__tests__/get-is-not-predictive.ts +119 -0
  84. package/src/components/bundle-assets/bundle-assets.jsx +15 -84
  85. package/src/components/bundle-assets/bundle-assets.module.css +0 -64
  86. package/src/components/bundle-assets/bundle-assets.utils.js +95 -26
  87. package/src/components/bundle-assets/index.jsx +2 -7
  88. package/src/components/entry-info/entry-info.tsx +18 -13
  89. package/src/components/metrics-treemap/metrics-treemap.utils.ts +0 -1
  90. package/src/components/preview-source/preview-source.tsx +11 -1
  91. package/src/stories/wrapper.jsx +21 -15
  92. package/src/types.d.ts +30 -1
  93. package/src/ui/tag/tag.tsx +4 -3
  94. package/types/components/asset-info/asset-info.d.ts +5 -4
  95. package/types/components/asset-meta-tag/asset-meta-tag.d.ts +8 -0
  96. package/types/components/asset-meta-tag/index.d.ts +1 -0
  97. package/types/components/asset-name/asset-name.d.ts +8 -0
  98. package/types/components/asset-name/index.d.ts +1 -0
  99. package/types/components/asset-not-predictive/asset-not-predictive.d.ts +6 -6
  100. package/types/components/bundle-assets/bundle-assets.utils.d.ts +3 -3
  101. package/types/components/entry-info/entry-info.d.ts +7 -1
  102. package/types/stories/wrapper.d.ts +1 -1
  103. package/types/ui/tag/tag.d.ts +4 -4
@@ -0,0 +1,127 @@
1
+ import React from 'react';
2
+ import type { Meta, StoryObj } from '@storybook/react';
3
+ import { createJobs } from '@bundle-stats/utils';
4
+ import merge from 'lodash/merge';
5
+
6
+ /* eslint-disable import/no-unresolved, import/no-relative-packages */
7
+ import currentData from '../../../../fixtures/job.current';
8
+ import baselineData from '../../../../fixtures/job.baseline';
9
+ /* eslint-enable import/no-unresolved, import/no-relative-packages */
10
+ import { App } from '.';
11
+
12
+ const CURRENT_SOURCE = {
13
+ webpack: {
14
+ ...currentData.rawData.webpack,
15
+ builtAt: currentData.createdAt,
16
+ hash: currentData.commit,
17
+ },
18
+ };
19
+
20
+ const BASELINE_SOURCE = {
21
+ webpack: {
22
+ ...baselineData.rawData.webpack,
23
+ builtAt: baselineData.createdAt,
24
+ hash: baselineData.commit,
25
+ },
26
+ };
27
+
28
+ const JOBS = createJobs([CURRENT_SOURCE, BASELINE_SOURCE]);
29
+
30
+ const MULTIPLE_JOBS = createJobs([
31
+ CURRENT_SOURCE,
32
+ BASELINE_SOURCE,
33
+ {
34
+ webpack: {
35
+ ...baselineData.rawData.webpack,
36
+ builtAt: baselineData.createdAt,
37
+ hash: 'aaaa1111',
38
+ assets: baselineData.rawData.webpack.assets.filter((asset) => asset.name.match(/.(css|js)$/)),
39
+ modules: baselineData.rawData.webpack.modules.slice(0, 100),
40
+ },
41
+ },
42
+ ]);
43
+
44
+ const [CURRENT_JOB, BASELINE_JOB] = JOBS;
45
+
46
+ const meta: Meta<typeof App> = {
47
+ title: 'App',
48
+ component: App,
49
+ parameters: {
50
+ layout: 'fullscreen',
51
+ },
52
+ args: {
53
+ version: '1.0',
54
+ },
55
+ };
56
+
57
+ export default meta;
58
+
59
+ type Story = StoryObj<typeof meta>;
60
+
61
+ export const Default: Story = {
62
+ render: (args) => <App jobs={JOBS} {...args} />,
63
+ };
64
+
65
+ export const NoInsights: Story = {
66
+ render: (args) => (
67
+ <App
68
+ jobs={[
69
+ {
70
+ ...CURRENT_JOB,
71
+ insights: undefined,
72
+ },
73
+ BASELINE_JOB,
74
+ ]}
75
+ {...args}
76
+ />
77
+ ),
78
+ };
79
+
80
+ export const AssetMetaChanges: Story = {
81
+ render: (args) => {
82
+ const current = merge({}, CURRENT_SOURCE);
83
+ const baseline = merge({}, CURRENT_SOURCE);
84
+
85
+ current.webpack.assets.push({
86
+ name: 'assets/js/vendors-auth.1a278dc.js',
87
+ size: 26364,
88
+ });
89
+ current.webpack.chunks.push({
90
+ id: 100,
91
+ entry: false,
92
+ initial: false,
93
+ files: ['assets/js/vendors-auth.1a278dc.js'],
94
+ names: ['vendors-auth'],
95
+ });
96
+
97
+ baseline.webpack.assets.push({
98
+ name: 'assets/js/vendors-auth.1a278dc.js',
99
+ size: 26364,
100
+ });
101
+ baseline.webpack.chunks.push({
102
+ id: 100,
103
+ entry: false,
104
+ initial: true,
105
+ files: ['assets/js/vendors-auth.1a278dc.js'],
106
+ names: ['vendors-auth'],
107
+ });
108
+
109
+ return <App jobs={createJobs([current, baseline])} {...args} />;
110
+ },
111
+ };
112
+
113
+ export const NoBaseline: Story = {
114
+ render: (args) => <App jobs={createJobs([CURRENT_SOURCE])} {...args} />,
115
+ };
116
+
117
+ export const EmptyBaseline: Story = {
118
+ render: (args) => <App jobs={createJobs([CURRENT_SOURCE, { webpack: null }])} {...args} />,
119
+ };
120
+
121
+ export const MultipleBaselines: Story = {
122
+ render: (args) => <App jobs={MULTIPLE_JOBS} {...args} />,
123
+ };
124
+
125
+ export const Empty: Story = {
126
+ render: (args) => <App {...args} />,
127
+ };
@@ -29,3 +29,12 @@
29
29
  content: ' ';
30
30
  }
31
31
 
32
+ .runNameTags {
33
+ display: flex;
34
+ align-items: center;
35
+ gap: calc(var(--space-xxxsmall) / 2);
36
+ }
37
+
38
+ .runNameTags:empty {
39
+ display: block;
40
+ }
@@ -1,3 +1,4 @@
1
+ import type { ComponentProps, ElementType, ReactNode } from 'react';
1
2
  import React, { useMemo } from 'react';
2
3
  import cx from 'classnames';
3
4
  import noop from 'lodash/noop';
@@ -9,16 +10,17 @@ import {
9
10
  getBundleAssetsFileTypeComponentLink,
10
11
  getModuleFileType,
11
12
  } from '@bundle-stats/utils';
12
- import { Asset, MetaChunk } from '@bundle-stats/utils/types/webpack';
13
+ import type { AssetMetricRun, MetaChunk } from '@bundle-stats/utils/types/webpack';
13
14
 
15
+ import type { ReportMetricAssetRow } from '../../types';
14
16
  import { FlexStack } from '../../layout/flex-stack';
15
- import { Tag } from '../../ui/tag';
17
+ import { AssetMetaTag } from '../asset-meta-tag';
16
18
  import { ComponentLink } from '../component-link';
17
19
  import { EntryInfo, EntryInfoMetaLink } from '../entry-info';
18
20
  import css from './asset-info.module.css';
19
21
 
20
22
  interface ChunkModulesLinkProps {
21
- as: React.ElementType;
23
+ as: ElementType;
22
24
  chunks: Array<MetaChunk>;
23
25
  chunkId: string;
24
26
  name: string;
@@ -30,7 +32,7 @@ const ChunkModulesLink = ({
30
32
  chunkId,
31
33
  name,
32
34
  onClick,
33
- }: ChunkModulesLinkProps & React.ComponentProps<'a'>) => {
35
+ }: ChunkModulesLinkProps & ComponentProps<'a'>) => {
34
36
  const chunk = chunks?.find(({ id }) => id === chunkId);
35
37
 
36
38
  if (!chunk) {
@@ -51,6 +53,26 @@ const ChunkModulesLink = ({
51
53
  );
52
54
  };
53
55
 
56
+ type AssetRunNameProps = {
57
+ run: ReportMetricAssetRow;
58
+ children: ReactNode;
59
+ };
60
+
61
+ const AssetRunName = (props: AssetRunNameProps) => {
62
+ const { run, children } = props;
63
+
64
+ return (
65
+ <>
66
+ <span className={css.runNameTags}>
67
+ {run.isEntry && <AssetMetaTag tag="entry" title="Entry" size="small" />}
68
+ {run.isInitial && <AssetMetaTag tag="initial" title="Initial" size="small" />}
69
+ {run.isChunk && <AssetMetaTag tag="chunk" title="Chunk" size="small" />}
70
+ </span>
71
+ {children}
72
+ </>
73
+ );
74
+ };
75
+
54
76
  interface AssetInfoProps {
55
77
  item: {
56
78
  label: string;
@@ -60,15 +82,15 @@ interface AssetInfoProps {
60
82
  isInitial?: boolean;
61
83
  isNotPredictive?: boolean;
62
84
  fileType?: string;
63
- runs: Array<Asset & MetricRunInfo>;
85
+ runs: Array<AssetMetricRun & MetricRunInfo>;
64
86
  };
65
87
  chunks?: Array<MetaChunk>;
66
88
  labels: Array<string>;
67
- customComponentLink?: React.ElementType;
89
+ customComponentLink?: ElementType;
68
90
  onClose: () => void;
69
91
  }
70
92
 
71
- export const AssetInfo = (props: AssetInfoProps & React.ComponentProps<'div'>) => {
93
+ export const AssetInfo = (props: AssetInfoProps & ComponentProps<'div'>) => {
72
94
  const {
73
95
  className = '',
74
96
  chunks = null,
@@ -89,34 +111,43 @@ export const AssetInfo = (props: AssetInfoProps & React.ComponentProps<'div'>) =
89
111
  return (
90
112
  <FlexStack space="xxxsmall" alignItems="center" className={css.tags}>
91
113
  {item.isEntry && (
92
- <Tag
114
+ <AssetMetaTag
93
115
  as={CustomComponentLink}
94
116
  {...getBundleAssetsByEntryType('entry')}
95
117
  onClick={onClick}
96
- className={cx(css.assetNameTag, css.assetNameTagEntry)}
118
+ tag="entry"
119
+ size="medium"
120
+ status={item.isEntry}
121
+ className={css.assetNameTag}
97
122
  >
98
123
  Entrypoint
99
- </Tag>
124
+ </AssetMetaTag>
100
125
  )}
101
126
  {item.isInitial && (
102
- <Tag
127
+ <AssetMetaTag
103
128
  as={CustomComponentLink}
104
129
  {...getBundleAssetsByEntryType('initial')}
105
130
  onClick={onClick}
131
+ tag="initial"
132
+ size="medium"
133
+ status={item.isInitial}
106
134
  className={cx(css.assetNameTag, css.assetNameTagInitial)}
107
135
  >
108
136
  Initial
109
- </Tag>
137
+ </AssetMetaTag>
110
138
  )}
111
139
  {item.isChunk && (
112
- <Tag
140
+ <AssetMetaTag
113
141
  as={CustomComponentLink}
114
142
  {...getBundleAssetsByEntryType('chunk')}
115
143
  onClick={onClick}
144
+ tag="chunk"
145
+ size="medium"
146
+ status={item.isChunk}
116
147
  className={cx(css.assetNameTag, css.assetNameTagChunk)}
117
148
  >
118
149
  Chunk
119
- </Tag>
150
+ </AssetMetaTag>
120
151
  )}
121
152
  </FlexStack>
122
153
  );
@@ -130,6 +161,7 @@ export const AssetInfo = (props: AssetInfoProps & React.ComponentProps<'div'>) =
130
161
  labels={labels}
131
162
  tags={tags}
132
163
  onClose={onClose}
164
+ RunName={AssetRunName}
133
165
  className={cx(css.root, className)}
134
166
  >
135
167
  {item.fileType && (
@@ -0,0 +1,56 @@
1
+ .root {
2
+ --background-color: var(--color-info);
3
+ background: var(--background-color);
4
+ overflow: hidden;
5
+ position: relative;
6
+ vertical-align: middle;
7
+ }
8
+
9
+ .root::before {
10
+ display: block;
11
+ content: ' ';
12
+ padding: 2px;
13
+ position: absolute;
14
+ left: 0;
15
+ top: 0;
16
+ width: 100%;
17
+ height: 100%;
18
+ font-size: 8px;
19
+ line-height: 1;
20
+ vertical-align: middle;
21
+ }
22
+
23
+ /* tag */
24
+ .entry {
25
+ --background-color: var(--color-info-dark);
26
+ }
27
+
28
+ .entry:empty::before {
29
+ content: 'e';
30
+ }
31
+
32
+ .initial {
33
+ --background-color: var(--color-info);
34
+ }
35
+
36
+ .initial:empty::before {
37
+ content: 'i';
38
+ }
39
+
40
+ .chunk {
41
+ --background-color: var(--color-info-light);
42
+ }
43
+
44
+ .chunk:empty::before {
45
+ content: 'c';
46
+ }
47
+
48
+ /* status */
49
+ .added {
50
+ background: linear-gradient(-45deg, var(--color-danger-light) 50%, var(--background-color) 50%) !important;
51
+ }
52
+
53
+ .removed {
54
+ background: linear-gradient(135deg, var(--color-danger-light) 50%, var(--background-color) 50%) !important;
55
+ }
56
+
@@ -0,0 +1,34 @@
1
+ import React from 'react';
2
+ import cx from 'classnames';
3
+
4
+ import type { TagProps } from '../../ui/tag';
5
+ import { Tag } from '../../ui/tag';
6
+ import css from './asset-meta-tag.module.css';
7
+ import type { ReportMetricAssetRowMetaStatus } from '../../types';
8
+
9
+ export type AssetMetaTagProps = {
10
+ tag: 'entry' | 'initial' | 'chunk';
11
+ status?: ReportMetricAssetRowMetaStatus | boolean;
12
+ } & TagProps;
13
+
14
+ export const AssetMetaTag = (props: AssetMetaTagProps) => {
15
+ const { className = '', title, tag, status, ...restProps } = props;
16
+
17
+ const rootClassName = cx(
18
+ css.root,
19
+ status === 'added' && css.added,
20
+ status === 'removed' && css.removed,
21
+ css[tag],
22
+ className,
23
+ );
24
+
25
+ return (
26
+ <Tag
27
+ className={rootClassName}
28
+ title={title}
29
+ size={Tag.SIZES.SMALL}
30
+ kind={Tag.KINDS.INFO}
31
+ {...restProps}
32
+ />
33
+ );
34
+ };
@@ -0,0 +1 @@
1
+ export * from './asset-meta-tag';
@@ -0,0 +1,32 @@
1
+ .notPredictive {
2
+ margin-right: var(--space-xxsmall);
3
+ display: inline-block;
4
+ width: var(--space-small);
5
+ height: var(--space-small);
6
+ }
7
+
8
+ .notPredictiveIcon {
9
+ color: var(--color-warning-dark);
10
+ }
11
+
12
+ .notPredictiveHoverCard {
13
+ max-width: 480px;
14
+ }
15
+
16
+ .metaTags {
17
+ display: inline;
18
+ margin-right: var(--space-xxxsmall);
19
+ }
20
+
21
+ .metaTag + .metaTag {
22
+ margin-left: calc(var(--space-xxxsmall) / 2);
23
+ }
24
+
25
+ .metaTags:empty {
26
+ display: none;
27
+ }
28
+
29
+ .nameText {
30
+ display: inline-block;
31
+ vertical-align: middle;
32
+ }
@@ -0,0 +1,85 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+
3
+ import { AssetName } from '.';
4
+
5
+ const ROW = {
6
+ key: 'asset/main.js',
7
+ label: 'asset/main.js',
8
+ changed: true,
9
+ isEntry: false,
10
+ isChunk: false,
11
+ isInitial: false,
12
+ isAsset: true,
13
+ isNotPredictive: false,
14
+ fileType: 'JS',
15
+ biggerIsBetter: false,
16
+ runs: [
17
+ { name: 'asset/main.abcd1234.js', value: 1024 * 10 },
18
+ { name: 'asset/main.abcd1234.js', value: 1024 * 11 },
19
+ ],
20
+ };
21
+
22
+ const meta = {
23
+ title: 'Components/AssetName',
24
+ component: AssetName,
25
+ args: {
26
+ customComponentLink: 'span',
27
+ filters: {},
28
+ search: '',
29
+ },
30
+ } as Meta<typeof AssetName>;
31
+
32
+ export default meta;
33
+
34
+ type Story = StoryObj<typeof meta>;
35
+
36
+ export const Default: Story = {
37
+ args: {
38
+ row: ROW,
39
+ },
40
+ };
41
+
42
+ export const MetaDefault: Story = {
43
+ args: {
44
+ row: {
45
+ ...ROW,
46
+ isEntry: true,
47
+ isChunk: true,
48
+ isInitial: true,
49
+ isAsset: false,
50
+ },
51
+ },
52
+ };
53
+
54
+ export const MetaAdded: Story = {
55
+ args: {
56
+ row: {
57
+ ...ROW,
58
+ isEntry: 'added',
59
+ isChunk: 'added',
60
+ isInitial: 'added',
61
+ isAsset: false,
62
+ },
63
+ },
64
+ };
65
+
66
+ export const MetaRemoved: Story = {
67
+ args: {
68
+ row: {
69
+ ...ROW,
70
+ isEntry: 'removed',
71
+ isChunk: 'removed',
72
+ isInitial: 'removed',
73
+ isAsset: false,
74
+ },
75
+ },
76
+ };
77
+
78
+ export const NotPredictive: Story = {
79
+ args: {
80
+ row: {
81
+ ...ROW,
82
+ isNotPredictive: true,
83
+ },
84
+ },
85
+ };
@@ -0,0 +1,59 @@
1
+ import React, { ElementType } from 'react';
2
+
3
+ import { Icon } from '../../ui/icon';
4
+ import { FileName } from '../../ui/file-name';
5
+ import { HoverCard } from '../../ui/hover-card';
6
+ import { AssetNotPredictive } from '../asset-not-predictive';
7
+
8
+ import type { ReportMetricAssetRow } from '../../types';
9
+ import { AssetMetaTag } from '../asset-meta-tag';
10
+ import css from './asset-name.module.css';
11
+
12
+ const RUN_TITLE_CURRENT = 'Current';
13
+ const RUN_TITLE_BASELINE = 'Baseline';
14
+ const RUNS_LABELS = [RUN_TITLE_CURRENT, RUN_TITLE_BASELINE];
15
+
16
+ export type AssetNameProps = {
17
+ className?: string;
18
+ row: ReportMetricAssetRow;
19
+ customComponentLink: ElementType;
20
+ };
21
+
22
+ export const AssetName = (props: AssetNameProps) => {
23
+ const { className = '', customComponentLink: CustomComponentLink, row } = props;
24
+ const { label, isNotPredictive, runs, isChunk, isEntry, isInitial } = row;
25
+
26
+ return (
27
+ <span className={className}>
28
+ {isNotPredictive && (
29
+ <HoverCard
30
+ label={<Icon className={css.notPredictiveIcon} glyph={Icon.ICONS.WARNING} />}
31
+ className={css.notPredictive}
32
+ hoverCardClassName={css.notPredictiveHoverCard}
33
+ >
34
+ <AssetNotPredictive runs={runs} labels={RUNS_LABELS} />
35
+ </HoverCard>
36
+ )}
37
+
38
+ <CustomComponentLink entryId={row.key} className={css.name}>
39
+ <span className={css.metaTags}>
40
+ {isEntry && (
41
+ <AssetMetaTag className={css.metaTag} title="Entrypoint" tag="entry" status={isEntry} />
42
+ )}
43
+ {isInitial && (
44
+ <AssetMetaTag
45
+ className={css.metaTag}
46
+ title="Initial"
47
+ tag="initial"
48
+ status={isInitial}
49
+ />
50
+ )}
51
+ {isChunk && (
52
+ <AssetMetaTag className={css.metaTag} title="Chunk" tag="chunk" status={isChunk} />
53
+ )}
54
+ </span>
55
+ <FileName className={css.nameText} name={label} />
56
+ </CustomComponentLink>
57
+ </span>
58
+ );
59
+ };
@@ -0,0 +1 @@
1
+ export * from './asset-name';
@@ -1,3 +1,8 @@
1
- .tableValue {
1
+ .colName {
2
+ width: 100%;
3
+ overflow: hidden;
4
+ }
5
+
6
+ .colValue {
2
7
  text-align: right;
3
8
  }
@@ -1,24 +1,28 @@
1
+ import type { ComponentProps } from 'react';
1
2
  import React from 'react';
2
3
  import cx from 'classnames';
3
- import type { Asset } from '@bundle-stats/utils/types/webpack';
4
+ import type { AssetMetricRun } from '@bundle-stats/utils/types/webpack';
4
5
 
5
6
  import { Stack } from '../../layout/stack';
6
7
  import { Table } from '../../ui/table';
7
8
  import css from './asset-not-predictive.module.css';
9
+ import { Alert } from '../../ui';
8
10
 
9
- interface AssetNotPredictiveProps {
10
- runs?: Array<Asset>;
11
- labels?: Array<string>
12
- }
11
+ export type AssetNotPredictiveProps = {
12
+ runs?: Array<AssetMetricRun>;
13
+ labels?: Array<string>;
14
+ } & ComponentProps<'div'>;
13
15
 
14
- export const AssetNotPredictive = (props: AssetNotPredictiveProps & React.ComponentProps<'div'>) => {
16
+ export const AssetNotPredictive = (props: AssetNotPredictiveProps) => {
15
17
  const { className = '', runs = null, labels = null, ...restProps } = props;
16
18
 
17
19
  return (
18
- <Stack space="xsmall" {...restProps} className={cx(css.root, className)}>
19
- <p className={css.text}>
20
- Asset file name is the same, but the size has changed.
21
- </p>
20
+ <Stack space="small" {...restProps} className={cx(css.root, className)}>
21
+ <h3>Asset hash is not predictive</h3>
22
+ <Alert kind="warning">
23
+ File names are identical, but the size is different. Content changes without a hash change
24
+ can cause runtime errors.
25
+ </Alert>
22
26
  {runs && (
23
27
  <Table outline compact>
24
28
  <Table.THead>
@@ -32,8 +36,8 @@ export const AssetNotPredictive = (props: AssetNotPredictiveProps & React.Compon
32
36
  {runs.map(({ name, value }, index) => (
33
37
  <Table.Tr key={name}>
34
38
  <Table.Th>{labels?.[index]}</Table.Th>
35
- <Table.Td>{name}</Table.Td>
36
- <Table.Td className={css.tableValue}>{value}</Table.Td>
39
+ <Table.Td className={css.colName}>{name}</Table.Td>
40
+ <Table.Td className={css.colvalue}>{value}</Table.Td>
37
41
  </Table.Tr>
38
42
  ))}
39
43
  </Table.TBody>