@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
@@ -13,12 +13,13 @@
13
13
  }
14
14
 
15
15
  .summaryContainer {
16
- padding-top: var(--space-large);
16
+ padding-top: var(--space-medium);
17
17
  padding-bottom: var(--space-small);
18
18
  }
19
19
 
20
20
  .tabsContainer {
21
21
  border-bottom: 1px solid var(--color-outline);
22
+ background: var(--color-light);
22
23
  }
23
24
 
24
25
  .tabs {
@@ -34,14 +35,14 @@
34
35
  }
35
36
 
36
37
  .tabsContent {
37
- padding-top: var(--space-large);
38
- padding-bottom: var(--space-large);
38
+ padding-top: var(--space-medium);
39
+ padding-bottom: var(--space-medium);
39
40
  min-height: 480px;
40
41
  }
41
42
 
42
43
  @media (min-width: 600px) {
43
44
  :root {
44
- --header-height: 80px;
45
+ --header-height: 72px;
45
46
  }
46
47
 
47
48
  .header {
@@ -54,4 +55,10 @@
54
55
  background-color: var(--color-background);
55
56
  border-bottom: 1px solid var(--color-outline);
56
57
  }
58
+
59
+ .tabsContainer {
60
+ position: sticky;
61
+ top: var(--header-height);
62
+ z-index: 100;
63
+ }
57
64
  }
@@ -3,7 +3,6 @@ import PropTypes from 'prop-types';
3
3
  import cx from 'classnames';
4
4
  import { Container } from '../../ui/container';
5
5
  import { JobsHeader } from '../../components/jobs-header';
6
- import { Logo } from '../../ui/logo';
7
6
  import css from './header.module.css';
8
7
  export const Header = _ref => {
9
8
  let {
@@ -15,14 +14,7 @@ export const Header = _ref => {
15
14
  className: cx(css.root, className)
16
15
  }, /*#__PURE__*/React.createElement("div", {
17
16
  className: css.inner
18
- }, /*#__PURE__*/React.createElement("a", {
19
- className: css.branding,
20
- href: "https://github.com/relative-ci/bundle-stats",
21
- target: "_blank",
22
- rel: "noopener noreferrer nofollow"
23
- }, /*#__PURE__*/React.createElement(Logo, {
24
- className: css.brandingLogo
25
- }, "BundleStats")), /*#__PURE__*/React.createElement(JobsHeader, {
17
+ }, /*#__PURE__*/React.createElement(JobsHeader, {
26
18
  className: css.jobs,
27
19
  jobs: jobs
28
20
  })));
@@ -1,4 +1,5 @@
1
1
  .fileName {
2
+ max-width: 100%;
2
3
  padding: 2px;
3
4
  background: var(--color-highlight-warning);
4
5
  }
@@ -3,7 +3,7 @@ import _get from "lodash/get";
3
3
 
4
4
  function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
5
5
 
6
- import React, { useMemo } from 'react';
6
+ import React, { useCallback, useMemo, useState } from 'react';
7
7
  import PropTypes from 'prop-types';
8
8
  import cx from 'classnames';
9
9
  import { ASSET_ENTRY_TYPE, ASSET_FILE_TYPE, ASSET_FILTERS, FILE_TYPE_LABELS } from '@bundle-stats/utils';
@@ -12,8 +12,9 @@ import I18N from '../../i18n';
12
12
  import { FlexStack } from '../../layout/flex-stack';
13
13
  import { Icon } from '../../ui/icon';
14
14
  import { FileName } from '../../ui/file-name';
15
- import { Popover } from '../../ui/popover';
15
+ import { HoverCard } from '../../ui/hover-card';
16
16
  import { Tooltip } from '../../ui/tooltip';
17
+ import { Tag } from '../../ui/tag';
17
18
  import { Filters } from '../../ui/filters';
18
19
  import { SortDropdown } from '../../ui/sort-dropdown';
19
20
  import { EmptySet } from '../../ui/empty-set';
@@ -71,58 +72,92 @@ TooltipNotPredictive.propTypes = {
71
72
 
72
73
  };
73
74
 
74
- const getRenderRowHeader = _ref4 => {
75
+ const RowHeader = _ref4 => {
75
76
  let {
77
+ row,
76
78
  labels,
77
- CustomComponentLink,
78
- chunks
79
+ chunks,
80
+ CustomComponentLink
79
81
  } = _ref4;
80
- return item => {
81
- const {
82
- label,
83
- isNotPredictive,
84
- runs,
85
- isChunk,
86
- isEntry,
87
- isInitial
88
- } = item;
89
- return /*#__PURE__*/React.createElement(Popover, {
90
- label: /*#__PURE__*/React.createElement(FileName, {
91
- name: label
92
- }),
93
- icon: /*#__PURE__*/React.createElement("div", {
94
- className: css.assetInfoFlags
95
- }, isNotPredictive && /*#__PURE__*/React.createElement(Tooltip, {
96
- className: css.notPredictive,
97
- title: /*#__PURE__*/React.createElement(TooltipNotPredictive, {
98
- runs: runs
99
- })
100
- }, /*#__PURE__*/React.createElement(Icon, {
101
- className: css.notPredictiveIcon,
102
- glyph: "warning"
103
- })), isChunk && /*#__PURE__*/React.createElement("span", {
104
- title: "Chunk",
105
- className: css.flagChunk
106
- }, "c"), isEntry && /*#__PURE__*/React.createElement("span", {
107
- title: "Entrypoint",
108
- className: css.flagEntry
109
- }, "e"), isInitial && /*#__PURE__*/React.createElement("span", {
110
- title: "Initial",
111
- className: css.flagInitial
112
- }, "i"))
113
- }, /*#__PURE__*/React.createElement(AssetInfo, {
114
- className: css.assetInfo,
115
- item: item,
116
- labels: labels,
117
- chunks: chunks,
118
- CustomComponentLink: CustomComponentLink
119
- }));
120
- };
82
+ const {
83
+ label,
84
+ isNotPredictive,
85
+ runs,
86
+ isChunk,
87
+ isEntry,
88
+ isInitial
89
+ } = row;
90
+ const [showHoverCard, setHoverCard] = useState(false);
91
+ const handleOnMouseEnter = useCallback(() => setHoverCard(true), [showHoverCard]);
92
+ const content = useMemo(() => /*#__PURE__*/React.createElement("span", {
93
+ className: css.assetName
94
+ }, /*#__PURE__*/React.createElement("span", {
95
+ className: css.assetNameTags
96
+ }, isNotPredictive && /*#__PURE__*/React.createElement(Tooltip, {
97
+ className: css.notPredictive,
98
+ title: /*#__PURE__*/React.createElement(TooltipNotPredictive, {
99
+ runs: runs
100
+ })
101
+ }, /*#__PURE__*/React.createElement(Icon, {
102
+ className: css.notPredictiveIcon,
103
+ glyph: "warning"
104
+ })), isChunk && /*#__PURE__*/React.createElement(Tag, {
105
+ className: cx(css.assetNameTag, css.assetNameTagChunk),
106
+ title: "Chunk",
107
+ size: Tag.SIZES.SMALL,
108
+ kind: Tag.KINDS.INFO
109
+ }), isEntry && /*#__PURE__*/React.createElement(Tag, {
110
+ className: cx(css.assetNameTag, css.assetNameTagEntry),
111
+ title: "Entrypoint",
112
+ size: Tag.SIZES.SMALL,
113
+ kind: Tag.KINDS.INFO
114
+ }), isInitial && /*#__PURE__*/React.createElement(Tag, {
115
+ className: cx(css.assetNameTag, css.assetNameTagInitial),
116
+ title: "Initial",
117
+ size: Tag.SIZES.SMALL,
118
+ kind: Tag.KINDS.INFO
119
+ })), /*#__PURE__*/React.createElement(FileName, {
120
+ className: css.assetNameText,
121
+ name: label
122
+ })), [isChunk, isEntry, isInitial, isNotPredictive, runs]);
123
+
124
+ if (!showHoverCard) {
125
+ return /*#__PURE__*/React.createElement("span", {
126
+ onMouseEnter: handleOnMouseEnter
127
+ }, content);
128
+ }
129
+
130
+ return /*#__PURE__*/React.createElement(HoverCard, {
131
+ label: content
132
+ }, /*#__PURE__*/React.createElement(AssetInfo, {
133
+ className: css.assetInfo,
134
+ item: row,
135
+ labels: labels,
136
+ chunks: chunks,
137
+ CustomComponentLink: CustomComponentLink
138
+ }));
121
139
  };
122
140
 
141
+ RowHeader.propTypes = {
142
+ row: PropTypes.shape({
143
+ label: PropTypes.string,
144
+ isNotPredictive: PropTypes.bool,
145
+ isChunk: PropTypes.bool,
146
+ isInitial: PropTypes.bool,
147
+ isEntry: PropTypes.bool,
148
+ runs: PropTypes.arrayOf(PropTypes.object)
149
+ }).isRequired,
150
+ chunks: PropTypes.arrayOf(PropTypes.shape({
151
+ id: PropTypes.string,
152
+ name: PropTypes.string
153
+ })),
154
+ labels: PropTypes.arrayOf(PropTypes.string).isRequired,
155
+ CustomComponentLink: PropTypes.elementType.isRequired
156
+ };
157
+ RowHeader.defaultProps = {
158
+ chunks: []
159
+ };
123
160
  export const BundleAssets = props => {
124
- var _jobs$, _jobs$$meta, _jobs$$meta$webpack;
125
-
126
161
  const {
127
162
  className,
128
163
  jobs,
@@ -146,12 +181,16 @@ export const BundleAssets = props => {
146
181
  handleResetFilters: resetFilters,
147
182
  handleViewAll: resetAllFilters
148
183
  });
149
- const chunks = ((_jobs$ = jobs[0]) == null ? void 0 : (_jobs$$meta = _jobs$.meta) == null ? void 0 : (_jobs$$meta$webpack = _jobs$$meta.webpack) == null ? void 0 : _jobs$$meta$webpack.chunks) || [];
150
- const renderRowHeader = useMemo(() => getRenderRowHeader({
151
- labels: _map(jobs, 'label'),
152
- CustomComponentLink,
153
- chunks
154
- }), [jobs, chunks]);
184
+ const renderRowHeader = useCallback(row => {
185
+ var _jobs$, _jobs$$meta, _jobs$$meta$webpack;
186
+
187
+ return /*#__PURE__*/React.createElement(RowHeader, {
188
+ row: row,
189
+ labels: _map(jobs, 'label'),
190
+ chunks: ((_jobs$ = jobs[0]) == null ? void 0 : (_jobs$$meta = _jobs$.meta) == null ? void 0 : (_jobs$$meta$webpack = _jobs$$meta.webpack) == null ? void 0 : _jobs$$meta$webpack.chunks) || [],
191
+ CustomComponentLink: CustomComponentLink
192
+ });
193
+ }, [jobs, CustomComponentLink]);
155
194
  return /*#__PURE__*/React.createElement("section", {
156
195
  className: cx(css.root, className)
157
196
  }, /*#__PURE__*/React.createElement(Toolbar, {
@@ -161,7 +200,7 @@ export const BundleAssets = props => {
161
200
  actionClassName
162
201
  } = _ref5;
163
202
  return /*#__PURE__*/React.createElement(FlexStack, {
164
- space: "xsmall",
203
+ space: "xxsmall",
165
204
  className: cx(css.dropdown, actionClassName)
166
205
  }, /*#__PURE__*/React.createElement(SortDropdown, _extends({
167
206
  fields: sortFields
@@ -172,7 +211,9 @@ export const BundleAssets = props => {
172
211
  handleResetFilters: resetFilters
173
212
  }));
174
213
  }
175
- }, /*#__PURE__*/React.createElement(FlexStack, null, /*#__PURE__*/React.createElement(MetricsTableSearch, {
214
+ }, /*#__PURE__*/React.createElement(FlexStack, {
215
+ space: "xxsmall"
216
+ }, /*#__PURE__*/React.createElement(MetricsTableSearch, {
176
217
  className: css.toolbarSearch,
177
218
  placeholder: "Search by name",
178
219
  search: search,
@@ -8,6 +8,8 @@
8
8
  margin-right: -1px; /** collapse border */
9
9
  }
10
10
 
11
+ .assetName {}
12
+
11
13
  .notPredictive {
12
14
  margin-right: var(--space-xxsmall);
13
15
  display: inline-block;
@@ -21,50 +23,46 @@
21
23
  vertical-align: top;
22
24
  }
23
25
 
24
- .assetInfoFlags {
25
- display: inline-block;
26
+ .assetNameTags {
27
+ display: inline;
26
28
  margin-right: var(--space-xxxsmall);
27
29
  }
28
30
 
29
- .assetInfoFlags:empty {
31
+ .assetNameTags:empty {
30
32
  display: none;
31
33
  }
32
34
 
33
- .flag {
34
- display: inline-block;
35
- width: var(--space-xsmall);
36
- height: var(--space-xsmall);
37
- font-family: var(--font-family);
38
- font-size: 8px;
39
- font-weight: bold;
40
- background: var(--color-highlight);
41
- color: var(--color-text-light);
42
- line-height: var(--space-xsmall);
43
- text-align: center;
44
- text-transform: uppercase;
35
+ .assetNameTag {
45
36
  vertical-align: middle;
46
37
  }
47
38
 
48
- .flag + .flag {
39
+ .assetNameTag + .assetNameTag {
49
40
  margin-left: 2px;
50
41
  }
51
42
 
52
- .flagEntry {
53
- composes: flag;
43
+ .assetNameTagEntry {
54
44
  background: var(--color-info-light);
55
- color: var(--color-background);
56
45
  }
57
46
 
58
- .flagInitial {
59
- composes: flag;
47
+ .assetNameTagEntry::before {
48
+ content: 'e';
49
+ }
50
+
51
+ .assetNameTagInitial {
60
52
  background: var(--color-info-light);
61
- color: var(--color-background);
62
53
  }
63
54
 
64
- .flagChunk {
65
- composes: flag;
66
- background: var(--color-info);
67
- color: var(--color-background);
55
+ .assetNameTagInitial::before {
56
+ content: 'i';
57
+ }
58
+
59
+ .assetNameTagChunk::before {
60
+ content: 'c';
61
+ }
62
+
63
+ .assetNameText {
64
+ display: inline;
65
+ vertical-align: middle;
68
66
  }
69
67
 
70
68
  /* Tooltip not predictive */
@@ -1,4 +1,7 @@
1
1
  import _get from "lodash/get";
2
+
3
+ function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
4
+
2
5
  import React, { useCallback, useMemo } from 'react';
3
6
  import PropTypes from 'prop-types';
4
7
  import { getBundleAssetsFileTypeComponentLink } from '@bundle-stats/utils';
@@ -15,7 +18,8 @@ export const BundleAssetsTotalsTable = _ref => {
15
18
  let {
16
19
  className,
17
20
  jobs,
18
- customComponentLink: CustomComponentLink
21
+ customComponentLink: CustomComponentLink,
22
+ ...restProps
19
23
  } = _ref;
20
24
  const items = useMemo(() => webpack.compareBySection.sizes(jobs), [jobs]);
21
25
  const budgets = (_jobs$0$insights = jobs[0].insights) == null ? void 0 : (_jobs$0$insights$webp = _jobs$0$insights.webpack) == null ? void 0 : _jobs$0$insights$webp.budgets;
@@ -43,13 +47,13 @@ export const BundleAssetsTotalsTable = _ref => {
43
47
  budgetInsight: budget
44
48
  })));
45
49
  }, [CustomComponentLink]);
46
- return /*#__PURE__*/React.createElement(MetricsTable, {
50
+ return /*#__PURE__*/React.createElement(MetricsTable, _extends({
47
51
  className: className,
48
52
  runs: jobs,
49
53
  items: items,
50
54
  renderRowHeader: renderRowHeader,
51
55
  showHeaderSum: true
52
- });
56
+ }, restProps));
53
57
  };
54
58
  BundleAssetsTotalsTable.defaultProps = {
55
59
  className: '',
@@ -15,8 +15,9 @@ import { FlexStack } from '../../layout/flex-stack';
15
15
  import { EmptySet } from '../../ui/empty-set';
16
16
  import { FileName } from '../../ui/file-name';
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 { MetricsTable } from '../metrics-table';
22
23
  import { MetricsTableSearch } from '../metrics-table-search';
@@ -35,35 +36,41 @@ const RowHeader = _ref => {
35
36
 
36
37
  const chunkIds = _map(chunks, 'id');
37
38
 
38
- const [showPopopver, setPopover] = useState(false);
39
- const handleOnMouseEnter = useCallback(() => setPopover(true), [showPopopver]);
40
- const content = /*#__PURE__*/React.createElement(FileName, {
39
+ const [showHoverCard, setHoverCard] = useState(false);
40
+ const handleOnMouseEnter = useCallback(() => setHoverCard(true), [showHoverCard]);
41
+ const content = useMemo(() => /*#__PURE__*/React.createElement("span", {
42
+ className: css.name
43
+ }, row.duplicated && /*#__PURE__*/React.createElement(Tag, {
44
+ className: css.nameTagDuplicated,
45
+ size: "small",
46
+ kind: Tag.KINDS.DANGER
47
+ }), /*#__PURE__*/React.createElement(FileName, {
48
+ className: css.nameText,
41
49
  name: row.label
42
- });
43
- return /*#__PURE__*/React.createElement("div", {
44
- onMouseEnter: handleOnMouseEnter
45
- }, !showPopopver ? content : /*#__PURE__*/React.createElement(Popover, {
46
- ariaLabel: "View module info",
50
+ })), [row]);
51
+
52
+ if (!showHoverCard) {
53
+ return /*#__PURE__*/React.createElement("div", {
54
+ onMouseEnter: handleOnMouseEnter
55
+ }, content);
56
+ }
57
+
58
+ return /*#__PURE__*/React.createElement(HoverCard, {
47
59
  label: content
48
- }, _ref2 => {
49
- let {
50
- popoverToggle
51
- } = _ref2;
52
- return /*#__PURE__*/React.createElement(ModuleInfo, {
53
- className: css.namePopover,
54
- item: row,
55
- chunks: chunks,
56
- chunkIds: chunkIds,
57
- labels: labels,
58
- customComponentLink: CustomComponentLink,
59
- onClick: popoverToggle
60
- });
60
+ }, /*#__PURE__*/React.createElement(ModuleInfo, {
61
+ className: css.namePopover,
62
+ item: row,
63
+ chunks: chunks,
64
+ chunkIds: chunkIds,
65
+ labels: labels,
66
+ customComponentLink: CustomComponentLink
61
67
  }));
62
68
  };
63
69
 
64
70
  RowHeader.propTypes = {
65
71
  row: PropTypes.shape({
66
- label: PropTypes.string
72
+ label: PropTypes.string,
73
+ duplicated: PropTypes.bool
67
74
  }).isRequired,
68
75
  chunks: PropTypes.arrayOf(PropTypes.shape({
69
76
  id: PropTypes.string,
@@ -75,22 +82,7 @@ RowHeader.propTypes = {
75
82
  RowHeader.defaultProps = {
76
83
  chunks: []
77
84
  };
78
-
79
- const getRenderRowHeader = _ref3 => {
80
- let {
81
- labels,
82
- chunks,
83
- CustomComponentLink
84
- } = _ref3;
85
- return row => /*#__PURE__*/React.createElement(RowHeader, {
86
- row: row,
87
- chunks: chunks,
88
- labels: labels,
89
- CustomComponentLink: CustomComponentLink
90
- });
91
- };
92
-
93
- export const BundleModules = _ref4 => {
85
+ export const BundleModules = _ref2 => {
94
86
  let {
95
87
  className,
96
88
  jobs,
@@ -108,14 +100,14 @@ export const BundleModules = _ref4 => {
108
100
  updateSearch,
109
101
  hasActiveFilters,
110
102
  customComponentLink: CustomComponentLink
111
- } = _ref4;
103
+ } = _ref2;
112
104
  const rootClassName = cx(css.root, className);
113
- const labels = useMemo(() => _map(jobs, 'label'), [jobs]);
114
- const renderRowHeader = useMemo(() => getRenderRowHeader({
115
- labels,
116
- chunks,
117
- CustomComponentLink
118
- }), [labels, chunks]);
105
+ const renderRowHeader = useCallback(row => /*#__PURE__*/React.createElement(RowHeader, {
106
+ row: row,
107
+ chunks: chunks,
108
+ labels: _map(jobs, 'label'),
109
+ CustomComponentLink: CustomComponentLink
110
+ }), [jobs, chunks, CustomComponentLink]);
119
111
  const emptyMessage = /*#__PURE__*/React.createElement(EmptySet, {
120
112
  resources: "modules",
121
113
  filtered: totalRowCount !== 0,
@@ -128,6 +120,11 @@ export const BundleModules = _ref4 => {
128
120
  defaultValue: filters.changed,
129
121
  disabled: jobs.length <= 1
130
122
  },
123
+ [MODULE_FILTERS.DUPLICATED]: {
124
+ label: 'Duplicated',
125
+ defaultValue: filters[MODULE_FILTERS.DUPLICATED],
126
+ disabled: jobs.length <= 1
127
+ },
131
128
  [MODULE_SOURCE_TYPE]: {
132
129
  label: 'Source',
133
130
  [MODULE_FILTERS.FIRST_PARTY]: {
@@ -143,11 +140,11 @@ export const BundleModules = _ref4 => {
143
140
  ...(!_isEmpty(chunks) && {
144
141
  [MODULE_CHUNK]: {
145
142
  label: 'Chunk',
146
- ...chunks.reduce((chunkFilters, _ref5) => {
143
+ ...chunks.reduce((chunkFilters, _ref3) => {
147
144
  let {
148
145
  id,
149
146
  name
150
- } = _ref5;
147
+ } = _ref3;
151
148
  return { ...chunkFilters,
152
149
  [id]: {
153
150
  label: name,
@@ -172,10 +169,10 @@ export const BundleModules = _ref4 => {
172
169
  className: rootClassName
173
170
  }, /*#__PURE__*/React.createElement(Toolbar, {
174
171
  className: css.toolbar,
175
- renderActions: _ref6 => {
172
+ renderActions: _ref4 => {
176
173
  let {
177
174
  actionClassName
178
- } = _ref6;
175
+ } = _ref4;
179
176
  return /*#__PURE__*/React.createElement(FlexStack, {
180
177
  space: "xxsmall",
181
178
  className: cx(css.dropdown, actionClassName)
@@ -188,7 +185,9 @@ export const BundleModules = _ref4 => {
188
185
  handleResetFilters: resetFilters
189
186
  }));
190
187
  }
191
- }, /*#__PURE__*/React.createElement(FlexStack, null, /*#__PURE__*/React.createElement(MetricsTableSearch, {
188
+ }, /*#__PURE__*/React.createElement(FlexStack, {
189
+ space: "xxsmall"
190
+ }, /*#__PURE__*/React.createElement(MetricsTableSearch, {
192
191
  className: css.toolbarSearch,
193
192
  search: search,
194
193
  updateSearch: updateSearch,
@@ -12,6 +12,15 @@
12
12
  margin-right: -1px; /** collapse border */
13
13
  }
14
14
 
15
- .namePopover {
16
- min-width: 280px;
15
+ .nameTagDuplicated {
16
+ margin-right: var(--space-xxxsmall);
17
+ vertical-align: baseline;
18
+ }
19
+
20
+ .nameTagDuplicated::before {
21
+ content: 'D';
22
+ }
23
+
24
+ .nameText {
25
+ vertical-align: middle;
17
26
  }
@@ -7,12 +7,15 @@ import { MODULE_CHUNK, MODULE_FILTERS, MODULE_FILE_TYPE, MODULE_SOURCE_TYPE, get
7
7
  import { SORT_BY_NAME, SORT_BY_SIZE, SORT_BY_DELTA } from './bundle-modules.constants';
8
8
  export const addRowSourceFlag = row => {
9
9
  const {
10
- key
11
- } = row;
12
- const thirdParty = Boolean(key.match(MODULE_PATH_PACKAGES));
13
- return { ...row,
14
- thirdParty
15
- };
10
+ key,
11
+ runs
12
+ } = row; // @NOTE Assign instead destructuring for perf reasons
13
+ // eslint-disable-next-line no-param-reassign
14
+
15
+ row.thirdParty = Boolean(key.match(MODULE_PATH_PACKAGES)); // eslint-disable-next-line no-param-reassign
16
+
17
+ row.duplicated = Boolean(runs.find(run => (run == null ? void 0 : run.duplicated) === true));
18
+ return row;
16
19
  };
17
20
  export const getCustomSort = sortBy => item => {
18
21
  if (sortBy === SORT_BY_NAME) {
@@ -33,6 +36,11 @@ export const getRowFilter = filters => row => {
33
36
  // Skip not changed rows
34
37
  if (filters[MODULE_FILTERS.CHANGED] && !row.changed) {
35
38
  return false;
39
+ } // Skip not duplicated rows
40
+
41
+
42
+ if (filters[MODULE_FILTERS.DUPLICATED] && !row.duplicated) {
43
+ return false;
36
44
  } // Skip not matching source type
37
45
 
38
46
 
@@ -5,7 +5,7 @@ function _extends() { _extends = Object.assign || function (target) { for (var i
5
5
 
6
6
  import React, { useMemo } from 'react';
7
7
  import PropTypes from 'prop-types';
8
- import { getModuleChunkFilters, getModuleSourceTypeFilters, getModuleFileTypeFilters } from '@bundle-stats/utils';
8
+ import { MODULE_FILTERS, getModuleChunkFilters, getModuleSourceTypeFilters, getModuleFileTypeFilters } from '@bundle-stats/utils';
9
9
  import * as webpack from '@bundle-stats/utils/lib-esm/webpack';
10
10
  import { useRowsFilter } from '../../hooks/rows-filter';
11
11
  import { useRowsSort } from '../../hooks/rows-sort';
@@ -45,13 +45,15 @@ export const BundleModules = props => {
45
45
  changed: (jobs == null ? void 0 : jobs.length) > 1,
46
46
  ...getModuleSourceTypeFilters(true),
47
47
  ...getModuleChunkFilters(chunkIds, true),
48
- ...getModuleFileTypeFilters(true)
48
+ ...getModuleFileTypeFilters(true),
49
+ [MODULE_FILTERS.DUPLICATED]: false
49
50
  },
50
51
  allEntriesFilters: {
51
52
  changed: false,
52
53
  ...getModuleSourceTypeFilters(true),
53
54
  ...getModuleChunkFilters(chunkIds, true),
54
- ...getModuleFileTypeFilters(true)
55
+ ...getModuleFileTypeFilters(true),
56
+ [MODULE_FILTERS.DUPLICATED]: false
55
57
  }
56
58
  }), [jobs]);
57
59
  const searchParams = useSearchParams({