@bundle-stats/ui 3.3.0-alpha.1 → 3.4.0-alpha.3

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 (190) hide show
  1. package/CHANGELOG.md +65 -13
  2. package/lib/app/app.js +137 -102
  3. package/lib/app/app.module.css +11 -4
  4. package/lib/app/header/header.js +1 -10
  5. package/lib/components/asset-info/asset-info.module.css +1 -0
  6. package/lib/components/bundle-assets/bundle-assets.js +104 -52
  7. package/lib/components/bundle-assets/bundle-assets.module.css +24 -26
  8. package/lib/components/bundle-assets-totals-table/bundle-assets-totals-table.js +13 -3
  9. package/lib/components/bundle-modules/bundle-modules.js +68 -68
  10. package/lib/components/bundle-modules/bundle-modules.module.css +11 -2
  11. package/lib/components/bundle-modules/bundle-modules.utils.js +14 -10
  12. package/lib/components/bundle-modules/index.js +4 -4
  13. package/lib/components/bundle-packages/bundle-packages.js +100 -44
  14. package/lib/components/bundle-packages/bundle-packages.module.css +17 -21
  15. package/lib/components/delta/delta.module.css +1 -0
  16. package/lib/components/job-header/job-header.js +3 -1
  17. package/lib/components/job-header/job-header.module.css +6 -8
  18. package/lib/components/jobs-header/jobs-header.module.css +5 -0
  19. package/lib/components/metrics-table/metrics-table.js +72 -59
  20. package/lib/components/metrics-table/metrics-table.module.css +18 -7
  21. package/lib/components/metrics-table-search/metrics-table-search.module.css +5 -4
  22. package/lib/components/metrics-table-title/metrics-table-title.js +9 -7
  23. package/lib/components/metrics-table-title/metrics-table-title.module.css +2 -0
  24. package/lib/components/module-info/module-info.js +2 -2
  25. package/lib/components/module-info/module-info.module.css +1 -0
  26. package/lib/components/summary/summary.js +1 -1
  27. package/lib/components/summary-item/summary-item.js +15 -18
  28. package/lib/components/summary-item/summary-item.module.css +1 -23
  29. package/lib/components/total-size-type-title/total-size-type-title.js +7 -3
  30. package/lib/constants.js +1 -1
  31. package/lib/css/default.css +14 -3
  32. package/lib/css/variables.css +17 -17
  33. package/lib/hooks/search-params.js +31 -31
  34. package/lib/layout/box/box.module.css +9 -0
  35. package/lib/layout/footer/footer.module.css +1 -1
  36. package/lib/layout/index.js +8 -0
  37. package/lib/layout/separator.js +48 -0
  38. package/lib/layout/separator.module.css +5 -0
  39. package/lib/ui/dropdown/dropdown.js +21 -26
  40. package/lib/ui/dropdown/dropdown.module.css +11 -12
  41. package/lib/ui/dropdown/dropdown.stories.js +2 -9
  42. package/lib/ui/empty-set/empty-set.js +5 -4
  43. package/lib/ui/empty-set/empty-set.module.css +2 -2
  44. package/lib/ui/filters/filters.container.js +1 -1
  45. package/lib/ui/filters/filters.js +22 -7
  46. package/lib/ui/filters/filters.module.css +3 -3
  47. package/lib/ui/horizontal-bar-chart/horizontal-bar-chart.js +1 -1
  48. package/lib/ui/hover-card/hover-card.js +102 -0
  49. package/lib/ui/hover-card/hover-card.module.css +29 -0
  50. package/lib/ui/hover-card/hover-card.stories.js +56 -0
  51. package/lib/ui/hover-card/index.js +18 -0
  52. package/lib/ui/icon/icon.js +6 -6
  53. package/lib/ui/icon/icon.module.css +1 -0
  54. package/lib/ui/index.js +8 -8
  55. package/lib/ui/table/table.js +5 -74
  56. package/lib/ui/table/table.module.css +41 -25
  57. package/lib/ui/table/table.stories.js +1 -1
  58. package/lib/ui/{popover → tag}/index.js +4 -4
  59. package/lib/ui/tag/tag.js +72 -0
  60. package/lib/ui/tag/tag.module.css +55 -0
  61. package/lib/ui/tag/tag.stories.js +38 -0
  62. package/lib/ui/tooltip/tooltip.js +10 -9
  63. package/lib/ui/tooltip/tooltip.module.css +2 -1
  64. package/lib-esm/app/app.js +132 -102
  65. package/lib-esm/app/app.module.css +11 -4
  66. package/lib-esm/app/header/header.js +1 -9
  67. package/lib-esm/components/asset-info/asset-info.module.css +1 -0
  68. package/lib-esm/components/bundle-assets/bundle-assets.js +97 -56
  69. package/lib-esm/components/bundle-assets/bundle-assets.module.css +24 -26
  70. package/lib-esm/components/bundle-assets-totals-table/bundle-assets-totals-table.js +7 -3
  71. package/lib-esm/components/bundle-modules/bundle-modules.js +50 -51
  72. package/lib-esm/components/bundle-modules/bundle-modules.module.css +11 -2
  73. package/lib-esm/components/bundle-modules/bundle-modules.utils.js +14 -6
  74. package/lib-esm/components/bundle-modules/index.js +5 -3
  75. package/lib-esm/components/bundle-packages/bundle-packages.js +88 -41
  76. package/lib-esm/components/bundle-packages/bundle-packages.module.css +17 -21
  77. package/lib-esm/components/delta/delta.module.css +1 -0
  78. package/lib-esm/components/job-header/job-header.js +2 -1
  79. package/lib-esm/components/job-header/job-header.module.css +6 -8
  80. package/lib-esm/components/jobs-header/jobs-header.module.css +5 -0
  81. package/lib-esm/components/metrics-table/metrics-table.js +61 -53
  82. package/lib-esm/components/metrics-table/metrics-table.module.css +18 -7
  83. package/lib-esm/components/metrics-table-search/metrics-table-search.module.css +5 -4
  84. package/lib-esm/components/metrics-table-title/metrics-table-title.js +8 -7
  85. package/lib-esm/components/metrics-table-title/metrics-table-title.module.css +2 -0
  86. package/lib-esm/components/module-info/module-info.js +2 -2
  87. package/lib-esm/components/module-info/module-info.module.css +1 -0
  88. package/lib-esm/components/summary/summary.js +1 -1
  89. package/lib-esm/components/summary-item/summary-item.js +14 -18
  90. package/lib-esm/components/summary-item/summary-item.module.css +1 -23
  91. package/lib-esm/components/total-size-type-title/total-size-type-title.js +6 -3
  92. package/lib-esm/constants.js +1 -1
  93. package/lib-esm/css/default.css +14 -3
  94. package/lib-esm/css/variables.css +17 -17
  95. package/lib-esm/hooks/search-params.js +27 -28
  96. package/lib-esm/layout/box/box.module.css +9 -0
  97. package/lib-esm/layout/footer/footer.module.css +1 -1
  98. package/lib-esm/layout/index.js +1 -0
  99. package/lib-esm/layout/separator.js +28 -0
  100. package/lib-esm/layout/separator.module.css +5 -0
  101. package/lib-esm/ui/dropdown/dropdown.js +20 -25
  102. package/lib-esm/ui/dropdown/dropdown.module.css +11 -12
  103. package/lib-esm/ui/dropdown/dropdown.stories.js +2 -7
  104. package/lib-esm/ui/empty-set/empty-set.js +4 -4
  105. package/lib-esm/ui/empty-set/empty-set.module.css +2 -2
  106. package/lib-esm/ui/filters/filters.js +20 -5
  107. package/lib-esm/ui/filters/filters.module.css +3 -3
  108. package/lib-esm/ui/hover-card/hover-card.js +83 -0
  109. package/lib-esm/ui/hover-card/hover-card.module.css +29 -0
  110. package/lib-esm/ui/hover-card/hover-card.stories.js +35 -0
  111. package/lib-esm/ui/hover-card/index.js +1 -0
  112. package/lib-esm/ui/icon/icon.js +3 -3
  113. package/lib-esm/ui/icon/icon.module.css +1 -0
  114. package/lib-esm/ui/index.js +1 -1
  115. package/lib-esm/ui/table/table.js +5 -65
  116. package/lib-esm/ui/table/table.module.css +41 -25
  117. package/lib-esm/ui/table/table.stories.js +1 -1
  118. package/lib-esm/ui/tag/index.js +1 -0
  119. package/lib-esm/ui/tag/tag.js +45 -0
  120. package/lib-esm/ui/tag/tag.module.css +55 -0
  121. package/lib-esm/ui/tag/tag.stories.js +23 -0
  122. package/lib-esm/ui/tooltip/tooltip.js +10 -9
  123. package/lib-esm/ui/tooltip/tooltip.module.css +2 -1
  124. package/package.json +33 -31
  125. package/src/app/app.jsx +142 -145
  126. package/src/app/app.module.css +11 -4
  127. package/src/app/header/header.jsx +0 -10
  128. package/src/components/asset-info/asset-info.module.css +1 -0
  129. package/src/components/bundle-assets/bundle-assets.jsx +85 -31
  130. package/src/components/bundle-assets/bundle-assets.module.css +24 -26
  131. package/src/components/bundle-assets-totals-table/bundle-assets-totals-table.jsx +2 -0
  132. package/src/components/bundle-modules/bundle-modules.jsx +53 -36
  133. package/src/components/bundle-modules/bundle-modules.module.css +11 -2
  134. package/src/components/bundle-modules/bundle-modules.utils.js +16 -4
  135. package/src/components/bundle-modules/index.jsx +3 -0
  136. package/src/components/bundle-packages/bundle-packages.jsx +89 -39
  137. package/src/components/bundle-packages/bundle-packages.module.css +17 -21
  138. package/src/components/delta/delta.module.css +1 -0
  139. package/src/components/job-header/job-header.jsx +2 -1
  140. package/src/components/job-header/job-header.module.css +6 -8
  141. package/src/components/jobs-header/jobs-header.module.css +5 -0
  142. package/src/components/metrics-table/metrics-table.jsx +53 -44
  143. package/src/components/metrics-table/metrics-table.module.css +18 -7
  144. package/src/components/metrics-table-search/metrics-table-search.module.css +5 -4
  145. package/src/components/metrics-table-title/metrics-table-title.jsx +20 -21
  146. package/src/components/metrics-table-title/metrics-table-title.module.css +2 -0
  147. package/src/components/module-info/module-info.jsx +3 -7
  148. package/src/components/module-info/module-info.module.css +1 -0
  149. package/src/components/summary/summary.jsx +1 -1
  150. package/src/components/summary-item/summary-item.jsx +21 -27
  151. package/src/components/summary-item/summary-item.module.css +1 -23
  152. package/src/components/total-size-type-title/total-size-type-title.jsx +6 -9
  153. package/src/constants.js +1 -1
  154. package/src/css/default.css +14 -3
  155. package/src/css/variables.css +17 -17
  156. package/src/hooks/search-params.js +42 -33
  157. package/src/layout/box/box.module.css +9 -0
  158. package/src/layout/footer/footer.module.css +1 -1
  159. package/src/layout/index.js +1 -0
  160. package/src/layout/separator.jsx +25 -0
  161. package/src/layout/separator.module.css +5 -0
  162. package/src/ui/dropdown/dropdown.jsx +16 -22
  163. package/src/ui/dropdown/dropdown.module.css +11 -12
  164. package/src/ui/empty-set/empty-set.jsx +25 -21
  165. package/src/ui/empty-set/empty-set.module.css +2 -2
  166. package/src/ui/filters/filters.jsx +64 -53
  167. package/src/ui/filters/filters.module.css +3 -3
  168. package/src/ui/hover-card/hover-card.jsx +73 -0
  169. package/src/ui/hover-card/hover-card.module.css +29 -0
  170. package/src/ui/hover-card/index.js +1 -0
  171. package/src/ui/icon/icon.jsx +11 -7
  172. package/src/ui/icon/icon.module.css +1 -0
  173. package/src/ui/index.js +1 -1
  174. package/src/ui/table/table.jsx +5 -52
  175. package/src/ui/table/table.module.css +41 -25
  176. package/src/ui/tag/index.js +1 -0
  177. package/src/ui/tag/tag.jsx +49 -0
  178. package/src/ui/tag/tag.module.css +55 -0
  179. package/src/ui/tooltip/tooltip.jsx +10 -14
  180. package/src/ui/tooltip/tooltip.module.css +2 -1
  181. package/lib/ui/popover/popover.js +0 -92
  182. package/lib/ui/popover/popover.module.css +0 -66
  183. package/lib/ui/popover/popover.stories.js +0 -26
  184. package/lib-esm/ui/popover/index.js +0 -1
  185. package/lib-esm/ui/popover/popover.js +0 -71
  186. package/lib-esm/ui/popover/popover.module.css +0 -66
  187. package/lib-esm/ui/popover/popover.stories.js +0 -14
  188. package/src/ui/popover/index.js +0 -1
  189. package/src/ui/popover/popover.jsx +0 -79
  190. package/src/ui/popover/popover.module.css +0 -66
@@ -1,4 +1,4 @@
1
- import React, {useCallback} from 'react';
1
+ import React, { useCallback, useMemo, useState } from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
  import cx from 'classnames';
4
4
  import {
@@ -15,8 +15,9 @@ import { Stack } from '../../layout/stack';
15
15
  import { FlexStack } from '../../layout/flex-stack';
16
16
  import { EmptySet } from '../../ui/empty-set';
17
17
  import { Filters } from '../../ui/filters';
18
- import { Popover } from '../../ui/popover';
18
+ import { HoverCard } from '../../ui/hover-card';
19
19
  import { SortDropdown } from '../../ui/sort-dropdown';
20
+ import { Tag } from '../../ui/tag';
20
21
  import { Toolbar } from '../../ui/toolbar';
21
22
  import { FileName } from '../../ui/file-name';
22
23
  import { ComponentLink } from '../component-link';
@@ -27,27 +28,28 @@ import { MetricsTableTitle } from '../metrics-table-title';
27
28
  import css from './bundle-packages.module.css';
28
29
 
29
30
  const PackagePopoverContent = ({ name, fullName, path, duplicate, CustomComponentLink }) => {
30
- const normalizedPackagePath = path || `node_modules/${fullName.split(PACKAGES_SEPARATOR).join('/node_modules/')}/`;
31
+ const normalizedPackagePath =
32
+ path || `node_modules/${fullName.split(PACKAGES_SEPARATOR).join('/node_modules/')}/`;
31
33
  const [normalizedName, packageId] = name.split(PACKAGE_ID_SEPARATOR);
32
34
 
33
35
  return (
34
- <Stack space="xxsmall" className={css.packagePopover}>
36
+ <Stack space="xsmall" className={css.packageHoverCard}>
35
37
  <Stack space="xxxsmall">
36
- <h3 className={css.packagePopoverTitle}>
38
+ <h3 className={css.packageHoverCardTitle}>
37
39
  {normalizedName}
38
40
  {packageId && (
39
- <span className={css.packagePopoverTitleIndex}>
41
+ <span className={css.packageHoverCardTitleIndex}>
40
42
  {`${PACKAGE_ID_SEPARATOR}${packageId}`}
41
43
  </span>
42
44
  )}
43
45
  </h3>
44
- <p className={css.packagePopoverPath}>
45
- <FileName className={css.packagePopoverPathValue} name={normalizedPackagePath} />
46
+ <p className={css.packageHoverCardPath}>
47
+ <FileName className={css.packageHoverCardPathValue} name={normalizedPackagePath} />
46
48
  </p>
47
49
  </Stack>
48
50
 
49
- <ul className={css.packagePopoverList}>
50
- <li className={css.packagePopoverItem}>
51
+ <ul className={css.packageHoverCardList}>
52
+ <li className={css.packageHoverCardItem}>
51
53
  <a
52
54
  href={`https://www.npmjs.com/package/${normalizedName}`}
53
55
  target="_blank"
@@ -56,7 +58,7 @@ const PackagePopoverContent = ({ name, fullName, path, duplicate, CustomComponen
56
58
  npmjs.com
57
59
  </a>
58
60
  </li>
59
- <li className={css.packagePopoverItem}>
61
+ <li className={css.packageHoverCardItem}>
60
62
  <a
61
63
  href={`https://bundlephobia.com/result?p=${normalizedName}`}
62
64
  target="_blank"
@@ -67,7 +69,7 @@ const PackagePopoverContent = ({ name, fullName, path, duplicate, CustomComponen
67
69
  </li>
68
70
  </ul>
69
71
 
70
- <Stack space="xxxsmall" className={css.packagePopover.actions}>
72
+ <Stack space="xxxsmall" className={css.packageHoverCardActions}>
71
73
  {duplicate && (
72
74
  <div>
73
75
  <CustomComponentLink {...getBundlePackagesByNameComponentLink(normalizedName)}>
@@ -96,38 +98,86 @@ PackagePopoverContent.defaultProps = {
96
98
  path: '',
97
99
  };
98
100
 
99
- const PackageRowHeader = ({ item, CustomComponentLink }) => {
100
- const packageNames = item.label.split(PACKAGES_SEPARATOR);
101
- const { path } = item.runs[0] || {};
101
+ const PackageName = ({ packageName, path, showDuplicateFlag, row, CustomComponentLink }) => {
102
+ const [showHoverCard, setHoverCard] = useState(false);
103
+ const handleOnMouseEnter = useCallback(() => setHoverCard(true), [showHoverCard]);
104
+
105
+ const label = useMemo(
106
+ () => (
107
+ <>
108
+ {showDuplicateFlag && row.duplicate && (
109
+ <Tag
110
+ className={css.packageNameTagDuplicate}
111
+ title="Duplicate package"
112
+ kind={Tag.KINDS.DANGER}
113
+ size={Tag.SIZES.SMALL}
114
+ />
115
+ )}
116
+ <span className={css.packageNameLabel}>{packageName}</span>
117
+ </>
118
+ ),
119
+ [packageName, showDuplicateFlag, row],
120
+ );
121
+
122
+ if (!showHoverCard) {
123
+ return (
124
+ <span className={css.packageName} onMouseEnter={handleOnMouseEnter}>
125
+ {label}
126
+ </span>
127
+ );
128
+ }
102
129
 
103
130
  return (
104
- <span className={css.packageNames}>
105
- {packageNames.map((packageName, index) => {
106
- // Render duplicate flag only for the last entry
107
- const duplicateFlag = index === packageNames.length - 1 && item.duplicate && (
108
- <span className={css.duplicate} title="Duplicate package">
109
- D
110
- </span>
111
- );
131
+ <HoverCard className={css.packageName} label={<span className={css.packageName}>{label}</span>}>
132
+ <PackagePopoverContent
133
+ name={packageName}
134
+ path={path}
135
+ fullName={row.label}
136
+ duplicate={row.duplicate}
137
+ CustomComponentLink={CustomComponentLink}
138
+ />
139
+ </HoverCard>
140
+ );
141
+ };
112
142
 
113
- return (
114
- <Popover className={css.packageName} icon={duplicateFlag} label={packageName}>
115
- <PackagePopoverContent
116
- name={packageName}
117
- path={path}
118
- fullName={item.label}
119
- duplicate={item.duplicate}
120
- CustomComponentLink={CustomComponentLink}
121
- />
122
- </Popover>
123
- );
124
- })}
143
+ PackageName.propTypes = {
144
+ packageName: PropTypes.string.isRequired,
145
+ path: PropTypes.string.isRequired,
146
+ showDuplicateFlag: PropTypes.bool.isRequired,
147
+ row: PropTypes.shape({
148
+ label: PropTypes.string,
149
+ duplicate: PropTypes.bool,
150
+ runs: PropTypes.arrayOf(
151
+ PropTypes.shape({
152
+ path: PropTypes.string,
153
+ }),
154
+ ).isRequired,
155
+ }).isRequired,
156
+ CustomComponentLink: PropTypes.elementType.isRequired,
157
+ };
158
+
159
+ const RowHeader = ({ row, CustomComponentLink }) => {
160
+ const packageNames = row.label.split(PACKAGES_SEPARATOR);
161
+ const { path } = row.runs[0] || {};
162
+
163
+ return (
164
+ <span className={css.packageNames}>
165
+ {packageNames.map((packageName, index) => (
166
+ <PackageName
167
+ packageName={packageName}
168
+ path={path}
169
+ // Render duplicate flag only for the last entry
170
+ showDuplicateFlag={index === packageNames.length - 1}
171
+ row={row}
172
+ CustomComponentLink={CustomComponentLink}
173
+ />
174
+ ))}
125
175
  </span>
126
176
  );
127
177
  };
128
178
 
129
- PackageRowHeader.propTypes = {
130
- item: PropTypes.shape({
179
+ RowHeader.propTypes = {
180
+ row: PropTypes.shape({
131
181
  label: PropTypes.string,
132
182
  duplicate: PropTypes.bool,
133
183
  runs: PropTypes.arrayOf(
@@ -168,7 +218,7 @@ export const BundlePackages = (props) => {
168
218
  );
169
219
 
170
220
  const renderRowHeader = useCallback(
171
- (item) => <PackageRowHeader item={item} CustomComponentLink={CustomComponentLink} />,
221
+ (row) => <RowHeader row={row} CustomComponentLink={CustomComponentLink} />,
172
222
  [CustomComponentLink],
173
223
  );
174
224
 
@@ -186,7 +236,7 @@ export const BundlePackages = (props) => {
186
236
  </FlexStack>
187
237
  )}
188
238
  >
189
- <FlexStack>
239
+ <FlexStack space="xxsmall">
190
240
  <MetricsTableSearch
191
241
  className={css.toolbarSearch}
192
242
  placeholder="Search by name"
@@ -12,23 +12,8 @@
12
12
  margin-right: -1px; /** collapse border */
13
13
  }
14
14
 
15
- .duplicate {
16
- margin-right: var(--space-xxxsmall);
17
- display: inline-block;
18
- width: var(--space-small);
19
- height: var(--space-small);
20
- font-size: 10px;
21
- font-weight: bold;
22
- line-height: var(--space-small);
23
- text-align: center;
24
- text-transform: uppercase;
25
- vertical-align: middle;
26
-
27
- background: var(--color-danger);
28
- color: var(--color-light);
29
- }
30
-
31
15
  .packageName {
16
+ display: inline-block;
32
17
  color: var(--color-text-light);
33
18
  }
34
19
 
@@ -43,22 +28,33 @@
43
28
  color: var(--color-text-ultra-light);
44
29
  }
45
30
 
46
- .packagePopover {
47
- min-width: 320px;
31
+ .packageNameTagDuplicate {
32
+ margin-right: var(--space-xxxsmall);
33
+ vertical-align: middle;
34
+ }
35
+
36
+ .packageNameLabel {
37
+ vertical-align: middle;
38
+ }
39
+
40
+ .packageNameTagDuplicate::before {
41
+ content: 'd';
48
42
  }
49
43
 
50
- .packagePopoverTitleIndex {
44
+
45
+ .packageHoverCardTitleIndex {
51
46
  color: var(--color-text-light);
52
47
  font-weight: normal;
53
48
  }
54
49
 
55
- .packagePopoverPathValue {
50
+ .packageHoverCardPathValue {
51
+ width: 100%;
56
52
  padding: var(--space-xxxsmall);
57
53
  background: var(--color-highlight-warning);
58
54
  font-family: var(--font-family-monospace);
59
55
  }
60
56
 
61
- .packagePopoverList {
57
+ .packageHoverCardList {
62
58
  padding: 0;
63
59
  list-style: inside;
64
60
  }
@@ -28,6 +28,7 @@
28
28
  }
29
29
 
30
30
  .inverted {
31
+ border-radius: var(--radius-small);
31
32
  background-color: var(--color-gray-ultra-light);
32
33
  color: var(--color-light);
33
34
  }
@@ -8,6 +8,7 @@ import { SOURCE_PATH_WEBPACK_STATS, formatDate, formatTime } from '@bundle-stats
8
8
  import { FlexStack } from '../../layout/flex-stack';
9
9
  import { Stack } from '../../layout/stack';
10
10
  import { Icon } from '../../ui/icon';
11
+ import { Tag } from '../../ui/tag';
11
12
  import css from './job-header.module.css';
12
13
 
13
14
  export const JobHeader = (props) => {
@@ -20,7 +21,7 @@ export const JobHeader = (props) => {
20
21
  <Stack className={rootClassName} space="xxsmall">
21
22
  <h1 className={css.title}>
22
23
  <span>{`#${job.internalBuildNumber}`}</span>
23
- {tag && <span className={css.tag}>{tag}</span>}
24
+ {tag && <Tag className={css.tag}>{tag}</Tag>}
24
25
  </h1>
25
26
  <FlexStack className={css.meta} space="xxsmall">
26
27
  {builtAt && (
@@ -1,22 +1,20 @@
1
1
  .title {
2
+ font-size: var(--size-xlarge);
2
3
  line-height: 1;
3
4
  font-weight: bold;
4
5
  vertical-align: top;
5
6
  }
6
7
 
7
8
  .tag {
8
- padding: var(--space-xxxsmall);
9
- margin-left: var(--space-xxxsmall);
10
- background-color: var(--color-highlight);
11
- color: var(--color-text-light);
12
- display: inline-block;
13
- font-size: 9px;
14
- line-height: var(--space-xxsmall);
15
- font-weight: normal;
9
+ margin-left: var(--space-xxsmall);
16
10
  vertical-align: top;
11
+ outline: 1px solid var(--color-outline);
12
+ background: var(--color-highlight);
13
+ color: var(--color-text-light);
17
14
  }
18
15
 
19
16
  .meta {
17
+ font-size: var(--size-small);
20
18
  color: var(--color-text-light);
21
19
  }
22
20
 
@@ -9,3 +9,8 @@
9
9
  padding: 0 var(--space-medium);
10
10
  border-left: 1px solid var(--color-outline);
11
11
  }
12
+
13
+ .item:first-child {
14
+ border-left: 0;
15
+ padding-left: 0;
16
+ }
@@ -12,7 +12,8 @@ import styles from './metrics-table.module.css';
12
12
 
13
13
  const METRIC_TYPE_DATA = getGlobalMetricType(null, METRIC_TYPE_FILE_SIZE);
14
14
 
15
- const getRowsRunTotal = (rows, runIndex) => sum(rows.map((row) => get(row, `runs[${runIndex}].value`, 0)));
15
+ const getRowsRunTotal = (rows, runIndex) =>
16
+ sum(rows.map((row) => get(row, `runs[${runIndex}].value`, 0)));
16
17
 
17
18
  const getHeaderLabelCells = (rows) => (run, runIndex, runs) => {
18
19
  const isBaseline = runIndex === runs.length - 1;
@@ -102,46 +103,58 @@ const getHeaderRows = (runs, items, showHeaderSum, title) => [
102
103
  : []),
103
104
  ];
104
105
 
105
- const generateRowCells = (item, index, items) => {
106
- const isBaseline = index === items.length - 1;
106
+ const MetricsTableRow = ({ item, renderRowHeader }) => (
107
+ <Table.Tr className={cx(!item.changed && styles.unchanged)}>
108
+ <Table.Th className={styles.metricName}>{renderRowHeader(item)}</Table.Th>
107
109
 
108
- // eslint-disable-next-line react/destructuring-assignment
109
- if (!item || typeof item.value === 'undefined') {
110
- return ['-', ...(!isBaseline ? [''] : [])];
111
- }
110
+ {item.runs.map((run, index) => {
111
+ const isBaseline = index === item.runs.length - 1;
112
+ const valueClassName = cx(styles.value, !isBaseline && styles.current);
112
113
 
113
- const { displayValue, deltaPercentage, displayDeltaPercentage, deltaType } = item;
114
+ // Empty cells if no value
115
+ if (!run || typeof run.value === 'undefined') {
116
+ return (
117
+ <>
118
+ <Table.Td className={valueClassName}>-</Table.Td>
119
+ {!isBaseline && <Table.Td className={styles.delta} />}
120
+ </>
121
+ );
122
+ }
114
123
 
115
- const cells = [<Metric value={displayValue} />];
124
+ const { displayValue, deltaPercentage, displayDeltaPercentage, deltaType } = run;
116
125
 
117
- if (!isBaseline) {
118
- cells.push(
119
- typeof deltaPercentage === 'number' && (
120
- <Delta displayValue={displayDeltaPercentage} deltaType={deltaType} />
121
- ),
122
- );
123
- }
126
+ return (
127
+ <>
128
+ <Table.Td className={valueClassName}>
129
+ <Metric value={displayValue} />
130
+ </Table.Td>
131
+ {!isBaseline && typeof deltaPercentage === 'number' && (
132
+ <Table.Td className={styles.delta}>
133
+ <Delta displayValue={displayDeltaPercentage} deltaType={deltaType} />
134
+ </Table.Td>
135
+ )}
136
+ </>
137
+ );
138
+ })}
139
+ </Table.Tr>
140
+ );
124
141
 
125
- return cells;
142
+ MetricsTableRow.propTypes = {
143
+ item: PropTypes.shape({
144
+ changed: PropTypes.bool,
145
+ runs: PropTypes.arrayOf(
146
+ PropTypes.shape({
147
+ value: PropTypes.number,
148
+ displayValue: PropTypes.string,
149
+ deltaPercentage: PropTypes.number,
150
+ displayDeltaPercentage: PropTypes.string,
151
+ deltaType: PropTypes.string,
152
+ }),
153
+ ),
154
+ }).isRequired,
155
+ renderRowHeader: PropTypes.func.isRequired,
126
156
  };
127
157
 
128
- const getRows = (runs, items, renderRowHeader) =>
129
- items.map((item, index) => {
130
- const { changed } = item;
131
-
132
- return {
133
- key: item?.key || index,
134
- className: changed ? '' : styles.unchanged,
135
- cells: [
136
- // Metric name
137
- renderRowHeader(item),
138
-
139
- // Metric item values
140
- ...item.runs.map(generateRowCells).flat(),
141
- ],
142
- };
143
- });
144
-
145
158
  export const MetricsTable = ({
146
159
  className,
147
160
  renderRowHeader,
@@ -151,9 +164,11 @@ export const MetricsTable = ({
151
164
  showHeaderSum,
152
165
  headerRows,
153
166
  title,
167
+ ...restProps
154
168
  }) => {
155
169
  const { headers, columnClassNames } = useMemo(() => {
156
170
  const headerColumns = getHeaderRows(runs, items, showHeaderSum, title);
171
+
157
172
  return {
158
173
  headers: [...headerRows, ...headerColumns],
159
174
  // First header row has the column class names
@@ -161,8 +176,6 @@ export const MetricsTable = ({
161
176
  };
162
177
  }, [headerRows, runs, items, showHeaderSum, title]);
163
178
 
164
- const rows = useMemo(() => getRows(runs, items, renderRowHeader), [runs, items, renderRowHeader]);
165
-
166
179
  const rootClassName = cx(
167
180
  styles.root,
168
181
  className,
@@ -171,7 +184,7 @@ export const MetricsTable = ({
171
184
  );
172
185
 
173
186
  return (
174
- <Table className={rootClassName} compact>
187
+ <Table className={rootClassName} compact {...restProps}>
175
188
  <Table.THead>
176
189
  {headers.map((headerRow) => {
177
190
  const { cells, className: rowClassName } = headerRow.cells
@@ -188,13 +201,9 @@ export const MetricsTable = ({
188
201
  })}
189
202
  </Table.THead>
190
203
  <Table.TBody>
191
- {!isEmpty(rows) ? (
192
- rows.map(({ key, className: rowClassName, cells }) => (
193
- <Table.Tr key={key} className={rowClassName}>
194
- {cells.map((cell, index) => (
195
- <Table.Td className={columnClassNames[index]}>{cell}</Table.Td>
196
- ))}
197
- </Table.Tr>
204
+ {!isEmpty(items) ? (
205
+ items.map((item) => (
206
+ <MetricsTableRow key={item.key} item={item} renderRowHeader={renderRowHeader} />
198
207
  ))
199
208
  ) : (
200
209
  <Table.Tr>
@@ -1,11 +1,11 @@
1
- .jobName a {
1
+ .root a {
2
2
  color: inherit;
3
3
  text-decoration: none;
4
4
  }
5
5
 
6
- .jobName a:hover,
7
- .jobName a:active,
8
- .jobName a:focus {
6
+ .root a:hover,
7
+ .root a:active,
8
+ .root a:focus {
9
9
  color: var(--color-primary);
10
10
  text-decoration: underline;
11
11
  }
@@ -15,21 +15,31 @@
15
15
  width: 100%;
16
16
  }
17
17
 
18
- .value {
18
+ .root .value {
19
19
  padding-left: var(--space-large);
20
20
  text-align: right;
21
+ vertical-align: baseline;
21
22
  }
22
23
 
23
- .delta {
24
+ .root .delta {
24
25
  padding-left: 0;
25
26
  text-align: left;
26
27
  font-size: var(--size-xsmall);
28
+ vertical-align: baseline;
27
29
  }
28
30
 
29
- .value.current {
31
+ .root tbody .delta {
32
+ line-height: 1.6rem; /* baseline alignment with the value */
33
+ }
34
+
35
+ .root .value.current {
30
36
  padding-right: var(--space-xxsmall);
31
37
  }
32
38
 
39
+ .jobName {
40
+ white-space: nowrap;
41
+ }
42
+
33
43
  /* columns overrides for showHeaderSum */
34
44
  .showHeaderSum .headerRowColumns .value,
35
45
  .showHeaderSum .headerRowColumns .delta {
@@ -45,6 +55,7 @@
45
55
  }
46
56
 
47
57
  /** rows */
58
+ .multipleRuns .unchanged th,
48
59
  .multipleRuns .unchanged td {
49
60
  color: var(--color-text-light);
50
61
  }
@@ -5,6 +5,7 @@
5
5
  }
6
6
 
7
7
  .input {
8
+ border-radius: var(--radius-small);
8
9
  height: var(--space-large);
9
10
  border-color: var(--color-outline);
10
11
  }
@@ -21,12 +22,12 @@
21
22
  cursor: pointer;
22
23
  border-radius: 50%;
23
24
  position: absolute;
24
- right: 0;
25
+ right: 2px;
25
26
  top: 50%;
26
27
  transform: translateY(-50%);
27
- padding: var(--space-xxsmall);
28
- width: var(--space-large);
29
- height: var(--space-large);
28
+ padding: var(--space-xxxsmall);
29
+ width: var(--space-medium);
30
+ height: var(--space-medium);
30
31
  background: radial-gradient(var(--color-background) 50%, transparent);
31
32
  color: var(--color-text-ultra-light);
32
33
  transition: var(--transition-in);
@@ -5,7 +5,8 @@ import cx from 'classnames';
5
5
  import I18N from '../../i18n';
6
6
  import { FlexStack } from '../../layout/flex-stack';
7
7
  import { Stack } from '../../layout/stack';
8
- import { Popover } from '../../ui/popover';
8
+ import { Icon } from '../../ui/icon';
9
+ import { HoverCard } from '../../ui/hover-card';
9
10
  import css from './metrics-table-title.module.css';
10
11
 
11
12
  export const MetricsTableTitle = (props) => {
@@ -13,26 +14,24 @@ export const MetricsTableTitle = (props) => {
13
14
  const rootClassName = cx(css.root, className);
14
15
 
15
16
  return (
16
- <Stack space="xxxsmall" className={rootClassName}>
17
- <FlexStack space="xxxsmall">
18
- <span>{title}</span>
19
- {info && <span className={css.info}>{info}</span>}
20
- {(popoverInfo || popoverHref) && (
21
- <Popover icon="help">
22
- <Stack space="xxxsmall">
23
- {popoverInfo && <p>{popoverInfo}</p>}
24
- {popoverHref && (
25
- <p>
26
- <a href={popoverHref} target="_blank" rel="noreferrer">
27
- {I18N.READ_MORE}
28
- </a>
29
- </p>
30
- )}
31
- </Stack>
32
- </Popover>
33
- )}
34
- </FlexStack>
35
- </Stack>
17
+ <FlexStack space="xxxsmall" className={rootClassName}>
18
+ <span>{title}</span>
19
+ {info && <span className={css.info}>{info}</span>}
20
+ {(popoverInfo || popoverHref) && (
21
+ <HoverCard label={<Icon glyph="help" />}>
22
+ <Stack space="xxxsmall">
23
+ {popoverInfo && <p>{popoverInfo}</p>}
24
+ {popoverHref && (
25
+ <p>
26
+ <a href={popoverHref} target="_blank" rel="noreferrer">
27
+ {I18N.READ_MORE}
28
+ </a>
29
+ </p>
30
+ )}
31
+ </Stack>
32
+ </HoverCard>
33
+ )}
34
+ </FlexStack>
36
35
  );
37
36
  };
38
37
 
@@ -1,5 +1,7 @@
1
1
  .root {
2
+ align-items: center;
2
3
  font-weight: bold;
4
+ line-height: var(--space-small);
3
5
  text-transform: uppercase;
4
6
  color: var(--color-text-light);
5
7
  }
@@ -20,7 +20,7 @@ export const ModuleInfo = (props) => {
20
20
  } = props;
21
21
 
22
22
  return (
23
- <Stack space="small" className={className}>
23
+ <Stack space="xsmall" className={className}>
24
24
  {item.runs.map((run, index) => {
25
25
  const TitleComponent = index !== 0 ? 'h4' : 'h3';
26
26
  const key = `module-info-${run?.name || index}-${index}`;
@@ -30,7 +30,7 @@ export const ModuleInfo = (props) => {
30
30
  <TitleComponent>{labels[index]}</TitleComponent>
31
31
  {index === 0 && !isEmpty(run?.chunkIds) && (
32
32
  <div className={css.chunks}>
33
- <strong className={css.chunksTitle}>Chunks:</strong>
33
+ <span className={css.chunksTitle}>Chunks:</span>
34
34
  {run.chunkIds.map((chunkId) => {
35
35
  const chunk = find(chunks, { id: chunkId });
36
36
 
@@ -51,11 +51,7 @@ export const ModuleInfo = (props) => {
51
51
  </div>
52
52
  )}
53
53
 
54
- <FileName
55
- className={css.fileName}
56
- as="code"
57
- name={run?.name || '-'}
58
- />
54
+ <FileName className={css.fileName} as="code" name={run?.name || '-'} />
59
55
  </Stack>
60
56
  );
61
57
  })}
@@ -15,6 +15,7 @@
15
15
  }
16
16
 
17
17
  .fileName {
18
+ max-width: 100%;
18
19
  padding: 2px;
19
20
  background: var(--color-highlight-warning);
20
21
  }
@@ -34,7 +34,7 @@ export const Summary = ({
34
34
  size={size}
35
35
  id={metricId}
36
36
  data={get(data, metricId)}
37
- budget={get(budgets, metricId)}
37
+ budget={get(budgets, getSourceMetricId(metricId))}
38
38
  loading={loading}
39
39
  showMetricDescription
40
40
  showDelta={showSummaryItemDelta && metricOptions.showDelta !== false}