@bundle-stats/ui 4.13.0-beta.8 → 4.13.0-rc.0

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 (227) hide show
  1. package/lib/app/app.js +4 -8
  2. package/lib/app/app.js.map +1 -1
  3. package/lib/app/app.module.css +2 -2
  4. package/lib/assets/icons.svg +70 -67
  5. package/lib/assets/icons.svg.js +14 -12
  6. package/lib/assets/icons.svg.js.map +1 -1
  7. package/lib/components/bundle-assets/bundle-assets.js +44 -10
  8. package/lib/components/bundle-assets/bundle-assets.js.map +1 -1
  9. package/lib/components/bundle-assets/bundle-assets.module.css +0 -5
  10. package/lib/components/bundle-assets-totals/bundle-assets-totals.js +14 -12
  11. package/lib/components/bundle-assets-totals/bundle-assets-totals.js.map +1 -1
  12. package/lib/components/bundle-modules/bundle-modules.i18n.js +1 -1
  13. package/lib/components/bundle-modules/bundle-modules.js +39 -15
  14. package/lib/components/bundle-modules/bundle-modules.js.map +1 -1
  15. package/lib/components/bundle-modules/bundle-modules.module.css +0 -5
  16. package/lib/components/bundle-packages/bundle-packages.js +43 -9
  17. package/lib/components/bundle-packages/bundle-packages.js.map +1 -1
  18. package/lib/components/bundle-packages/bundle-packages.module.css +0 -5
  19. package/lib/components/delta/delta.js +1 -1
  20. package/lib/components/delta/delta.js.map +1 -1
  21. package/lib/components/delta/delta.module.css +10 -1
  22. package/lib/components/jobs-header/jobs-header.module.css +0 -4
  23. package/lib/components/metrics-display-selector/metrics-display-selector.js +42 -5
  24. package/lib/components/metrics-display-selector/metrics-display-selector.js.map +1 -1
  25. package/lib/components/metrics-display-selector/metrics-display-selector.module.css +15 -7
  26. package/lib/components/metrics-table-header/metrics-table-header.js +7 -7
  27. package/lib/components/metrics-table-header/metrics-table-header.js.map +1 -1
  28. package/lib/components/metrics-table-header/metrics-table-header.module.css +11 -4
  29. package/lib/components/metrics-table-options/metrics-table-options.js +2 -2
  30. package/lib/components/metrics-table-options/metrics-table-options.js.map +1 -1
  31. package/lib/components/metrics-table-title/metrics-table-title.js +1 -1
  32. package/lib/components/metrics-table-title/metrics-table-title.js.map +1 -1
  33. package/lib/components/metrics-table-title/metrics-table-title.module.css +1 -0
  34. package/lib/components/metrics-treemap/index.js +4 -0
  35. package/lib/components/metrics-treemap/index.js.map +1 -1
  36. package/lib/components/metrics-treemap/metrics-treemap.constants.js +3 -0
  37. package/lib/components/metrics-treemap/metrics-treemap.constants.js.map +1 -0
  38. package/lib/components/metrics-treemap/metrics-treemap.i18n.js +6 -0
  39. package/lib/components/metrics-treemap/metrics-treemap.i18n.js.map +1 -0
  40. package/lib/components/metrics-treemap/metrics-treemap.js +100 -62
  41. package/lib/components/metrics-treemap/metrics-treemap.js.map +1 -1
  42. package/lib/components/metrics-treemap/metrics-treemap.module.css +139 -51
  43. package/lib/components/metrics-treemap/metrics-treemap.utils.js +109 -0
  44. package/lib/components/metrics-treemap/metrics-treemap.utils.js.map +1 -0
  45. package/lib/components/module-info/module-info.js +1 -2
  46. package/lib/components/module-info/module-info.js.map +1 -1
  47. package/lib/components/run-info/run-info.module.css +7 -7
  48. package/lib/css/variables.css +14 -13
  49. package/lib/hooks/metrics-display-type.js +45 -24
  50. package/lib/hooks/metrics-display-type.js.map +1 -1
  51. package/lib/hooks/search-params.js +1 -0
  52. package/lib/hooks/search-params.js.map +1 -1
  53. package/lib/layout/box/box.module.css +4 -2
  54. package/lib/layout/flex-stack/flex-stack.js +3 -4
  55. package/lib/layout/flex-stack/flex-stack.js.map +1 -1
  56. package/lib/layout/flex-stack/flex-stack.module.css +19 -23
  57. package/lib/ui/button/button.js +5 -4
  58. package/lib/ui/button/button.js.map +1 -1
  59. package/lib/ui/button/button.module.css +55 -53
  60. package/lib/ui/dropdown/dropdown.js +10 -40
  61. package/lib/ui/dropdown/dropdown.js.map +1 -1
  62. package/lib/ui/dropdown/index.js.map +1 -1
  63. package/lib/ui/filters/filters.js +33 -35
  64. package/lib/ui/filters/filters.js.map +1 -1
  65. package/lib/ui/filters/filters.module.css +55 -67
  66. package/lib/ui/hover-card/hover-card.js +1 -1
  67. package/lib/ui/hover-card/hover-card.js.map +1 -1
  68. package/lib/ui/icon/icon.js +2 -1
  69. package/lib/ui/icon/icon.js.map +1 -1
  70. package/lib/ui/input-search/input-search.js +1 -1
  71. package/lib/ui/input-search/input-search.js.map +1 -1
  72. package/lib/ui/loader/loader.js +1 -1
  73. package/lib/ui/loader/loader.js.map +1 -1
  74. package/lib/ui/table/table.module.css +30 -0
  75. package/lib/ui/tag/tag.module.css +3 -3
  76. package/lib/ui/toolbar/toolbar.module.css +1 -3
  77. package/lib-esm/app/app.js +4 -8
  78. package/lib-esm/app/app.js.map +1 -1
  79. package/lib-esm/app/app.module.css +2 -2
  80. package/lib-esm/assets/icons.svg +70 -67
  81. package/lib-esm/assets/icons.svg.js +14 -12
  82. package/lib-esm/assets/icons.svg.js.map +1 -1
  83. package/lib-esm/components/bundle-assets/bundle-assets.js +45 -11
  84. package/lib-esm/components/bundle-assets/bundle-assets.js.map +1 -1
  85. package/lib-esm/components/bundle-assets/bundle-assets.module.css +0 -5
  86. package/lib-esm/components/bundle-assets-totals/bundle-assets-totals.js +15 -13
  87. package/lib-esm/components/bundle-assets-totals/bundle-assets-totals.js.map +1 -1
  88. package/lib-esm/components/bundle-modules/bundle-modules.i18n.js +1 -1
  89. package/lib-esm/components/bundle-modules/bundle-modules.js +40 -16
  90. package/lib-esm/components/bundle-modules/bundle-modules.js.map +1 -1
  91. package/lib-esm/components/bundle-modules/bundle-modules.module.css +0 -5
  92. package/lib-esm/components/bundle-packages/bundle-packages.js +44 -10
  93. package/lib-esm/components/bundle-packages/bundle-packages.js.map +1 -1
  94. package/lib-esm/components/bundle-packages/bundle-packages.module.css +0 -5
  95. package/lib-esm/components/delta/delta.js +1 -1
  96. package/lib-esm/components/delta/delta.js.map +1 -1
  97. package/lib-esm/components/delta/delta.module.css +10 -1
  98. package/lib-esm/components/jobs-header/jobs-header.module.css +0 -4
  99. package/lib-esm/components/metrics-display-selector/metrics-display-selector.js +42 -5
  100. package/lib-esm/components/metrics-display-selector/metrics-display-selector.js.map +1 -1
  101. package/lib-esm/components/metrics-display-selector/metrics-display-selector.module.css +15 -7
  102. package/lib-esm/components/metrics-table-header/metrics-table-header.js +7 -7
  103. package/lib-esm/components/metrics-table-header/metrics-table-header.js.map +1 -1
  104. package/lib-esm/components/metrics-table-header/metrics-table-header.module.css +11 -4
  105. package/lib-esm/components/metrics-table-options/metrics-table-options.js +3 -3
  106. package/lib-esm/components/metrics-table-options/metrics-table-options.js.map +1 -1
  107. package/lib-esm/components/metrics-table-title/metrics-table-title.js +1 -1
  108. package/lib-esm/components/metrics-table-title/metrics-table-title.js.map +1 -1
  109. package/lib-esm/components/metrics-table-title/metrics-table-title.module.css +1 -0
  110. package/lib-esm/components/metrics-treemap/index.js +1 -0
  111. package/lib-esm/components/metrics-treemap/index.js.map +1 -1
  112. package/lib-esm/components/metrics-treemap/metrics-treemap.constants.js +2 -0
  113. package/lib-esm/components/metrics-treemap/metrics-treemap.constants.js.map +1 -0
  114. package/lib-esm/components/metrics-treemap/metrics-treemap.i18n.js +3 -0
  115. package/lib-esm/components/metrics-treemap/metrics-treemap.i18n.js.map +1 -0
  116. package/lib-esm/components/metrics-treemap/metrics-treemap.js +102 -63
  117. package/lib-esm/components/metrics-treemap/metrics-treemap.js.map +1 -1
  118. package/lib-esm/components/metrics-treemap/metrics-treemap.module.css +139 -51
  119. package/lib-esm/components/metrics-treemap/metrics-treemap.utils.js +105 -0
  120. package/lib-esm/components/metrics-treemap/metrics-treemap.utils.js.map +1 -0
  121. package/lib-esm/components/module-info/module-info.js +1 -2
  122. package/lib-esm/components/module-info/module-info.js.map +1 -1
  123. package/lib-esm/components/run-info/run-info.module.css +7 -7
  124. package/lib-esm/css/variables.css +14 -13
  125. package/lib-esm/hooks/metrics-display-type.js +46 -24
  126. package/lib-esm/hooks/metrics-display-type.js.map +1 -1
  127. package/lib-esm/hooks/search-params.js +1 -0
  128. package/lib-esm/hooks/search-params.js.map +1 -1
  129. package/lib-esm/layout/box/box.module.css +4 -2
  130. package/lib-esm/layout/flex-stack/flex-stack.js +3 -4
  131. package/lib-esm/layout/flex-stack/flex-stack.js.map +1 -1
  132. package/lib-esm/layout/flex-stack/flex-stack.module.css +19 -23
  133. package/lib-esm/ui/button/button.js +5 -4
  134. package/lib-esm/ui/button/button.js.map +1 -1
  135. package/lib-esm/ui/button/button.module.css +55 -53
  136. package/lib-esm/ui/dropdown/dropdown.js +8 -39
  137. package/lib-esm/ui/dropdown/dropdown.js.map +1 -1
  138. package/lib-esm/ui/dropdown/index.js.map +1 -1
  139. package/lib-esm/ui/filters/filters.js +34 -36
  140. package/lib-esm/ui/filters/filters.js.map +1 -1
  141. package/lib-esm/ui/filters/filters.module.css +55 -67
  142. package/lib-esm/ui/hover-card/hover-card.js +1 -1
  143. package/lib-esm/ui/hover-card/hover-card.js.map +1 -1
  144. package/lib-esm/ui/icon/icon.js +2 -1
  145. package/lib-esm/ui/icon/icon.js.map +1 -1
  146. package/lib-esm/ui/input-search/input-search.js +1 -1
  147. package/lib-esm/ui/input-search/input-search.js.map +1 -1
  148. package/lib-esm/ui/loader/loader.js +1 -1
  149. package/lib-esm/ui/loader/loader.js.map +1 -1
  150. package/lib-esm/ui/table/table.module.css +30 -0
  151. package/lib-esm/ui/tag/tag.module.css +3 -3
  152. package/lib-esm/ui/toolbar/toolbar.module.css +1 -3
  153. package/package.json +9 -9
  154. package/src/app/app.jsx +4 -12
  155. package/src/app/app.module.css +2 -2
  156. package/src/assets/icons/check.svg +4 -0
  157. package/src/assets/icons.svg +70 -67
  158. package/src/assets/icons.svg.jsx +12 -12
  159. package/src/components/bundle-assets/bundle-assets.jsx +82 -25
  160. package/src/components/bundle-assets/bundle-assets.module.css +0 -5
  161. package/src/components/bundle-assets-totals/bundle-assets-totals.jsx +53 -46
  162. package/src/components/bundle-modules/bundle-modules.i18n.ts +1 -1
  163. package/src/components/bundle-modules/bundle-modules.module.css +0 -5
  164. package/src/components/bundle-modules/bundle-modules.tsx +117 -53
  165. package/src/components/bundle-packages/bundle-packages.jsx +77 -20
  166. package/src/components/bundle-packages/bundle-packages.module.css +0 -5
  167. package/src/components/delta/delta.jsx +1 -1
  168. package/src/components/delta/delta.module.css +10 -1
  169. package/src/components/jobs-header/jobs-header.module.css +0 -4
  170. package/src/components/metrics-display-selector/metrics-display-selector.module.css +15 -7
  171. package/src/components/metrics-display-selector/metrics-display-selector.stories.tsx +33 -0
  172. package/src/components/metrics-display-selector/metrics-display-selector.tsx +86 -28
  173. package/src/components/metrics-table-header/metrics-table-header.module.css +11 -4
  174. package/src/components/metrics-table-header/metrics-table-header.tsx +7 -7
  175. package/src/components/metrics-table-options/metrics-table-options.jsx +4 -10
  176. package/src/components/metrics-table-title/metrics-table-title.jsx +1 -1
  177. package/src/components/metrics-table-title/metrics-table-title.module.css +1 -0
  178. package/src/components/metrics-treemap/__tests__/metrics-treemap.utils.ts +188 -0
  179. package/src/components/metrics-treemap/index.ts +1 -0
  180. package/src/components/metrics-treemap/metrics-treemap.constants.ts +52 -0
  181. package/src/components/metrics-treemap/metrics-treemap.i18n.ts +2 -0
  182. package/src/components/metrics-treemap/metrics-treemap.module.css +139 -51
  183. package/src/components/metrics-treemap/metrics-treemap.stories.tsx +44 -10
  184. package/src/components/metrics-treemap/metrics-treemap.tsx +329 -120
  185. package/src/components/metrics-treemap/metrics-treemap.utils.ts +162 -0
  186. package/src/components/module-info/module-info.tsx +1 -1
  187. package/src/components/run-info/run-info.module.css +7 -7
  188. package/src/css/variables.css +14 -13
  189. package/src/hooks/metrics-display-type.ts +79 -29
  190. package/src/hooks/search-params.js +1 -0
  191. package/src/layout/box/box.module.css +4 -2
  192. package/src/layout/flex-stack/flex-stack.module.css +19 -23
  193. package/src/layout/flex-stack/flex-stack.tsx +2 -8
  194. package/src/ui/button/button.module.css +55 -53
  195. package/src/ui/button/button.stories.tsx +16 -9
  196. package/src/ui/button/button.tsx +8 -7
  197. package/src/ui/dropdown/dropdown.stories.tsx +25 -0
  198. package/src/ui/dropdown/dropdown.tsx +66 -0
  199. package/src/ui/filters/filters.module.css +55 -67
  200. package/src/ui/filters/filters.stories.tsx +109 -0
  201. package/src/ui/filters/filters.tsx +128 -167
  202. package/src/ui/hover-card/hover-card.tsx +1 -1
  203. package/src/ui/icon/icon.tsx +2 -1
  204. package/src/ui/input-search/input-search.tsx +1 -0
  205. package/src/ui/loader/loader.jsx +1 -1
  206. package/src/ui/table/table.module.css +30 -0
  207. package/src/ui/tag/tag.module.css +3 -3
  208. package/src/ui/toolbar/toolbar.module.css +1 -3
  209. package/types/components/bundle-modules/bundle-modules.i18n.d.ts +1 -1
  210. package/types/components/delta/delta.d.ts +2 -2
  211. package/types/components/metrics-display-selector/metrics-display-selector.d.ts +5 -3
  212. package/types/components/metrics-treemap/index.d.ts +1 -0
  213. package/types/components/metrics-treemap/metrics-treemap.constants.d.ts +20 -0
  214. package/types/components/metrics-treemap/metrics-treemap.d.ts +7 -5
  215. package/types/components/metrics-treemap/metrics-treemap.i18n.d.ts +2 -0
  216. package/types/components/metrics-treemap/metrics-treemap.utils.d.ts +5 -0
  217. package/types/hooks/metrics-display-type.d.ts +8 -2
  218. package/types/ui/dropdown/dropdown.d.ts +12 -47
  219. package/types/ui/dropdown/index.d.ts +1 -1
  220. package/types/ui/filters/filters.d.ts +2 -7
  221. package/types/ui/icon/icon.d.ts +4 -2
  222. package/types/ui/loader/loader.d.ts +2 -2
  223. package/lib/components/bundle-assets-totals/bundle-assets-totals.module.css +0 -7
  224. package/lib-esm/components/bundle-assets-totals/bundle-assets-totals.module.css +0 -7
  225. package/src/components/bundle-assets-totals/bundle-assets-totals.module.css +0 -7
  226. package/src/ui/dropdown/dropdown.jsx +0 -88
  227. /package/src/ui/dropdown/{index.js → index.ts} +0 -0
@@ -5,7 +5,9 @@ import { COMPONENT, PACKAGE_FILTERS, PACKAGES_SEPARATOR, SECTIONS } from '@bundl
5
5
 
6
6
  import config from '../../config.json';
7
7
  import I18N from '../../i18n';
8
+ import { Box } from '../../layout/box';
8
9
  import { FlexStack } from '../../layout/flex-stack';
10
+ import { Stack } from '../../layout/stack';
9
11
  import { InputSearch } from '../../ui/input-search';
10
12
  import { EmptySet } from '../../ui/empty-set';
11
13
  import { Filters } from '../../ui/filters';
@@ -22,9 +24,13 @@ import { SEARCH_PLACEHOLDER } from './bundle-packages.i18n';
22
24
  import css from './bundle-packages.module.css';
23
25
  import { MetricsDisplaySelector } from '../metrics-display-selector';
24
26
  import { MetricsDisplayType } from '../../constants';
25
- import { MetricsTreemap } from '../metrics-treemap';
27
+ import { MetricsTreemap, getTreemapNodes, getTreemapNodesGroupedByPath } from '../metrics-treemap';
26
28
  import { useMetricsDisplayType } from '../../hooks/metrics-display-type';
27
29
 
30
+ const DISPLAY_TYPE_GROUPS = {
31
+ [MetricsDisplayType.TREEMAP]: ['folder'],
32
+ };
33
+
28
34
  const getDropdownFilters = ({ compareMode, filters }) => ({
29
35
  [PACKAGE_FILTERS.CHANGED]: {
30
36
  label: 'Changed',
@@ -113,6 +119,60 @@ RowHeader.propTypes = {
113
119
  search: PropTypes.string,
114
120
  };
115
121
 
122
+ const ViewMetricsTreemap = (props) => {
123
+ const { metricsTableTitle, jobs, items, displayType, emptyMessage, showEntryInfo, updateSearch } = props;
124
+
125
+ const treeNodes = useMemo(() => {
126
+ if (displayType.groupBy === 'folder') {
127
+ return getTreemapNodesGroupedByPath(items);
128
+ }
129
+
130
+ return getTreemapNodes(items);
131
+ }, [items, displayType.groupBy]);
132
+
133
+ const onGroupClick = useCallback(
134
+ (groupPath) => {
135
+ // Search by group path
136
+ // 1. use `^` to match only the string beggining
137
+ // 2. add `/` suffix to match only exact directories
138
+ // 3. if the group path is empty(root), clear search
139
+ if (groupPath) {
140
+ updateSearch(`^${groupPath}/`);
141
+ } else {
142
+ updateSearch('');
143
+ }
144
+ },
145
+ [updateSearch],
146
+ );
147
+
148
+ return (
149
+ <>
150
+ <Table compact>
151
+ <MetricsTableHeader metricTitle={metricsTableTitle} showSum jobs={jobs} rows={items} />
152
+ </Table>
153
+ <MetricsTreemap
154
+ treeNodes={treeNodes}
155
+ nested={Boolean(displayType.groupBy)}
156
+ emptyMessage={emptyMessage}
157
+ onItemClick={showEntryInfo}
158
+ onGroupClick={onGroupClick}
159
+ />
160
+ </>
161
+ );
162
+ };
163
+
164
+ ViewMetricsTreemap.propTypes = {
165
+ jobs: PropTypes.arrayOf(PropTypes.object).isRequired, // eslint-disable-line react/forbid-prop-types
166
+ items: PropTypes.arrayOf(PropTypes.object).isRequired, // eslint-disable-line react/forbid-prop-types
167
+ metricsTableTitle: PropTypes.node.isRequired,
168
+ displayType: PropTypes.shape({
169
+ groupBy: PropTypes.string,
170
+ }).isRequired,
171
+ emptyMessage: PropTypes.node.isRequired,
172
+ showEntryInfo: PropTypes.func.isRequired,
173
+ updateSearch: PropTypes.func.isRequired,
174
+ };
175
+
116
176
  export const BundlePackages = (props) => {
117
177
  const {
118
178
  className,
@@ -137,7 +197,7 @@ export const BundlePackages = (props) => {
137
197
 
138
198
  const jobLabels = jobs?.map((job) => job?.label);
139
199
 
140
- const [displayType, setDisplayType] = useMetricsDisplayType();
200
+ const [displayType, setDisplayType] = useMetricsDisplayType(DISPLAY_TYPE_GROUPS);
141
201
 
142
202
  const dropdownFilters = useMemo(
143
203
  () => getDropdownFilters({ compareMode: jobs?.length > 1, filters }),
@@ -191,12 +251,12 @@ export const BundlePackages = (props) => {
191
251
 
192
252
  return (
193
253
  <>
194
- <section className={cx(css.root, className)}>
254
+ <Stack space="xsmall" as="section" className={cx(css.root, className)}>
195
255
  <Toolbar
196
256
  className={css.toolbar}
197
257
  renderActions={({ actionClassName }) => (
198
258
  <FlexStack space="xxsmall" className={cx(css.dropdown, actionClassName)}>
199
- <MetricsDisplaySelector onSelect={setDisplayType} value={displayType} />
259
+ <MetricsDisplaySelector onSelect={setDisplayType} value={displayType.value} groupBy={displayType.groupBy} groups={DISPLAY_TYPE_GROUPS} />
200
260
  <MetricsTableOptions
201
261
  handleViewAll={resetAllFilters}
202
262
  handleResetFilters={resetFilters}
@@ -219,8 +279,8 @@ export const BundlePackages = (props) => {
219
279
  />
220
280
  </FlexStack>
221
281
  </Toolbar>
222
- <main>
223
- {displayType === MetricsDisplayType.TABLE && (
282
+ <Box outline as="main">
283
+ {displayType.value === MetricsDisplayType.TABLE && (
224
284
  <MetricsTable
225
285
  runs={jobs}
226
286
  items={items}
@@ -232,21 +292,18 @@ export const BundlePackages = (props) => {
232
292
  updateSort={updateSort}
233
293
  />
234
294
  )}
235
- {displayType === MetricsDisplayType.TREEMAP && (
236
- <>
237
- <Table compact>
238
- <MetricsTableHeader
239
- metricTitle={metricsTableTitle}
240
- showSum
241
- jobs={jobs}
242
- rows={items}
243
- />
244
- </Table>
245
- <MetricsTreemap emptyMessage={emptyMessage} items={items} onItemClick={showEntryInfo} />
246
- </>
295
+ {displayType.value === MetricsDisplayType.TREEMAP && (
296
+ <ViewMetricsTreemap
297
+ jobs={jobs}
298
+ items={items}
299
+ displayType={displayType}
300
+ emptyMessage={emptyMessage}
301
+ showEntryInfo={showEntryInfo}
302
+ updateSearch={updateSearch}
303
+ />
247
304
  )}
248
- </main>
249
- </section>
305
+ </Box>
306
+ </Stack>
250
307
  {entryItem && (
251
308
  <PackageInfo
252
309
  className={css.packageInfo}
@@ -2,14 +2,9 @@
2
2
  color: var(--color-text-light);
3
3
  }
4
4
 
5
- .toolbar {
6
- border-bottom: 1px solid var(--color-outline);
7
- }
8
-
9
5
  .toolbarSearch {
10
6
  width: 100%;
11
7
  max-width: 240px;
12
- margin-right: -1px; /** collapse border */
13
8
  }
14
9
 
15
10
  .hoverCard {
@@ -4,7 +4,7 @@ import cx from 'classnames';
4
4
 
5
5
  import css from './delta.module.css';
6
6
 
7
- export const Delta = ({ className, displayValue, deltaType, inverted }) => {
7
+ export const Delta = ({ className = '', displayValue, deltaType, inverted = false }) => {
8
8
  const rootClassName = cx(css.root, className, inverted && css.inverted, css[deltaType]);
9
9
  return <span className={rootClassName}>{displayValue}</span>;
10
10
  };
@@ -4,6 +4,10 @@
4
4
  white-space: nowrap;
5
5
  }
6
6
 
7
+ .CHANGE {
8
+ color: var(--color-info);
9
+ }
10
+
7
11
  .HIGH_NEGATIVE {
8
12
  color: var(--color-red-dark);
9
13
  }
@@ -29,11 +33,16 @@
29
33
  }
30
34
 
31
35
  .inverted {
32
- border-radius: var(--radius-small);
36
+ padding: 0 2px;
37
+ border-radius: var(--radius-xsmall);
33
38
  background-color: var(--color-gray-ultra-light);
34
39
  color: var(--color-light);
35
40
  }
36
41
 
42
+ .inverted.CHANGE {
43
+ background: var(--color-info-light);
44
+ }
45
+
37
46
  .inverted.HIGH_NEGATIVE {
38
47
  background: var(--color-red-dark);
39
48
  }
@@ -24,10 +24,6 @@
24
24
  background: linear-gradient(90deg, transparent, var(--color-background));
25
25
  }
26
26
 
27
- .item + .item {
28
- margin-left: var(--space-small);
29
- }
30
-
31
27
  .item:first-child {
32
28
  border-left: 0;
33
29
  padding-left: 0;
@@ -1,10 +1,18 @@
1
- .button {
2
- text-decoration: none;
1
+ .buttonActive {
2
+ background: var(--color-highlight);
3
3
  }
4
4
 
5
- .buttonActive,
6
- .buttonActive:active,
7
- .buttonActive:focus {
8
- color: var(--color-primary);
9
- border-color: var(--color-primary);
5
+ /* explicit ControlGroup last item styles to override ariakit injected sibling nodes */
6
+ .itemLast {
7
+ border-top-right-radius: var(--radius-small) !important;
8
+ border-bottom-right-radius: var(--radius-small) !important;
9
+ }
10
+
11
+ .dropdownItemIcon {
12
+ opacity: 0;
13
+ transition: var(--transition-out);
14
+ }
15
+
16
+ .dropdownItemActive .dropdownItemIcon {
17
+ opacity: 1;
10
18
  }
@@ -0,0 +1,33 @@
1
+ import { action } from '@storybook/addon-actions'; // eslint-disable-line
2
+ import { Meta, StoryObj } from '@storybook/react';
3
+
4
+ import { MetricsDisplayType } from '../../constants';
5
+ import { MetricsDisplaySelector } from '.';
6
+
7
+ const meta: Meta<typeof MetricsDisplaySelector> = {
8
+ title: 'Components/MetricsDisplaySelector',
9
+ component: MetricsDisplaySelector,
10
+ args: {
11
+ onSelect: action('SELECT'),
12
+ },
13
+ } as Meta;
14
+
15
+ export default meta;
16
+
17
+ type Story = StoryObj<typeof meta>;
18
+
19
+ export const Default: Story = {
20
+ args: {
21
+ value: MetricsDisplayType.TABLE,
22
+ },
23
+ };
24
+
25
+ export const TreemapGroups: Story = {
26
+ args: {
27
+ value: MetricsDisplayType.TREEMAP,
28
+ groupBy: '',
29
+ groups: {
30
+ [MetricsDisplayType.TREEMAP]: ['folder'],
31
+ },
32
+ },
33
+ };
@@ -2,46 +2,104 @@ import React from 'react';
2
2
  import cx from 'classnames';
3
3
 
4
4
  import { MetricsDisplayType } from '../../constants';
5
- import { FlexStack } from '../../layout/flex-stack';
6
5
  import { Button } from '../../ui/button';
6
+ import { ControlGroup } from '../../ui/control-group';
7
+ import { Dropdown, DropdownItem } from '../../ui/dropdown';
7
8
  import { Icon } from '../../ui/icon';
8
9
  import css from './metrics-display-selector.module.css';
10
+ import { FlexStack } from '../../layout';
11
+
12
+ const DEFAULT_GROUP_BY = '';
13
+
14
+ const METRICS_DISPLAY_MAP = {
15
+ [MetricsDisplayType.TABLE]: {
16
+ glyph: Icon.ICONS.TABLE,
17
+ label: 'Table',
18
+ },
19
+ [MetricsDisplayType.TREEMAP]: {
20
+ glyph: Icon.ICONS.TREEMAP,
21
+ label: 'Treemap',
22
+ },
23
+ };
24
+
25
+ const displayTypes = Object.values(MetricsDisplayType);
9
26
 
10
27
  interface MetricsDisplaySelectorProps {
11
28
  value: MetricsDisplayType;
12
- onSelect: (newValue: MetricsDisplayType) => void;
29
+ groupBy?: string;
30
+ groups?: Partial<Record<MetricsDisplayType, Array<string>>>;
31
+ onSelect: (newValue: MetricsDisplayType, groupBy?: string) => void;
13
32
  }
14
33
 
15
34
  export const MetricsDisplaySelector = (
16
35
  props: MetricsDisplaySelectorProps &
17
- Omit<React.ComponentProps<typeof FlexStack>, 'onSelect' | 'value'>,
36
+ Omit<React.ComponentProps<typeof ControlGroup>, 'onSelect' | 'value'>,
18
37
  ) => {
19
- const { className = '', value, onSelect, ...restProps } = props;
38
+ const { value, groupBy = DEFAULT_GROUP_BY, groups = {}, onSelect, ...restProps } = props;
20
39
 
21
40
  return (
22
- <FlexStack space="xxsmall" as="nav" className={cx(css.root, className)} {...restProps}>
23
- <Button
24
- outline
25
- active={value === MetricsDisplayType.TABLE}
26
- size="small"
27
- type="button"
28
- glyph={Icon.ICONS.TABLE}
29
- onClick={() => onSelect(MetricsDisplayType.TABLE)}
30
- className={css.button}
31
- >
32
- Table
33
- </Button>
34
- <Button
35
- outline
36
- active={value === MetricsDisplayType.TREEMAP}
37
- size="small"
38
- type="button"
39
- glyph={Icon.ICONS.TREEMAP}
40
- onClick={() => onSelect(MetricsDisplayType.TREEMAP)}
41
- className={cx(css.button)}
42
- >
43
- Treemap
44
- </Button>
45
- </FlexStack>
41
+ <ControlGroup {...restProps}>
42
+ {displayTypes.map((displayType, index) => {
43
+ const displayGroups = groups?.[displayType];
44
+ const displayProps = METRICS_DISPLAY_MAP[displayType];
45
+ const isLast = displayTypes.length - 1 === index;
46
+ const isActive = displayType === value;
47
+
48
+ if (!displayGroups || displayGroups.length === 0) {
49
+ return (
50
+ <Button
51
+ outline
52
+ active={isActive}
53
+ size="small"
54
+ type="button"
55
+ glyph={displayProps.glyph}
56
+ onClick={() => onSelect(displayType)}
57
+ className={isLast && css.itemLast}
58
+ key={displayType}
59
+ >
60
+ {displayProps.label}
61
+ </Button>
62
+ );
63
+ }
64
+
65
+ const displayGroupsData = [
66
+ {
67
+ value: DEFAULT_GROUP_BY,
68
+ label: 'No groups',
69
+ },
70
+ ...displayGroups.map((displayGroup) => ({
71
+ value: displayGroup,
72
+ label: `Group by ${displayGroup}`,
73
+ })),
74
+ ];
75
+
76
+ return (
77
+ <Dropdown
78
+ glyph={displayProps.glyph}
79
+ label={displayProps.label}
80
+ className={cx(isLast && css.itemLast, isActive && css.buttonActive)}
81
+ key={displayType}
82
+ >
83
+ {displayGroupsData.map((displayGroupData) => {
84
+ const isGroupActive = isActive && displayGroupData.value === groupBy;
85
+
86
+ return (
87
+ <DropdownItem
88
+ onClick={() => onSelect(displayType, displayGroupData.value)}
89
+ isActive={isGroupActive}
90
+ className={cx(css.dropdownItem, isGroupActive && css.dropdownItemActive)}
91
+ key={displayGroupData.value}
92
+ >
93
+ <FlexStack space="xxxsmall" alignItems="center">
94
+ <Icon glyph={Icon.ICONS.CHECK} size="small" className={css.dropdownItemIcon} />
95
+ <span>{displayGroupData.label}</span>
96
+ </FlexStack>
97
+ </DropdownItem>
98
+ );
99
+ })}
100
+ </Dropdown>
101
+ );
102
+ })}
103
+ </ControlGroup>
46
104
  );
47
105
  };
@@ -1,9 +1,16 @@
1
1
  /* columns */
2
- .root .metricName {
2
+ .root .col {
3
+ padding-top: var(--space-xxsmall);
4
+ padding-bottom: var(--space-xxsmall);
5
+ }
6
+
7
+ .root .metric {
3
8
  width: 55%;
9
+ vertical-align: middle;
4
10
  }
5
11
 
6
12
  .root .job {
13
+ padding-top: var(--space-xxsmall);
7
14
  text-align: right;
8
15
  }
9
16
 
@@ -30,13 +37,13 @@
30
37
  }
31
38
 
32
39
  /* columns overrides for showHeaderSum */
33
- .showHeaderSum .headerRow .job {
40
+ .showHeaderSum .job {
34
41
  border-bottom: 0;
35
42
  padding-bottom: 0;
36
43
  }
37
44
 
38
- .showHeaderSum .headerRow .sum {
39
- padding-top: var(--space-xxxsmall);
45
+ .showHeaderSum .sum {
46
+ padding-top: 0;
40
47
  font-size: var(--size-small);
41
48
  vertical-align: middle;
42
49
  text-transform: none;
@@ -34,7 +34,7 @@ const JobColumn = ({ job, isBaseline }: JobColumnProps) => {
34
34
  }
35
35
 
36
36
  return (
37
- <Table.Th className={css.job} colSpan={colSpan}>
37
+ <Table.Th className={cx(css.col, css.job)} colSpan={colSpan}>
38
38
  <JobName
39
39
  title={isBaseline ? I18N.BASELINE_TITLE : I18N.CURRENT_TITLE}
40
40
  internalBuildNumber={internalBuildNumber}
@@ -65,7 +65,7 @@ const SumColumn = ({ rows, isBaseline, runIndex, updateSort, sort }: ColumnSumPr
65
65
 
66
66
  return (
67
67
  <>
68
- <Table.Th className={cx(css.value, css.sum)}>
68
+ <Table.Th className={cx(css.col, css.value, css.sum)}>
69
69
  <SortButton
70
70
  fieldPath={fieldPath}
71
71
  fieldName="value"
@@ -78,7 +78,7 @@ const SumColumn = ({ rows, isBaseline, runIndex, updateSort, sort }: ColumnSumPr
78
78
  </Table.Th>
79
79
  {!isBaseline && (
80
80
  <>
81
- <Table.Th className={cx(css.delta, css.sum)}>
81
+ <Table.Th className={cx(css.col, css.delta, css.sum)}>
82
82
  <SortButton
83
83
  fieldPath={fieldPath}
84
84
  fieldName="delta"
@@ -91,7 +91,7 @@ const SumColumn = ({ rows, isBaseline, runIndex, updateSort, sort }: ColumnSumPr
91
91
  )}
92
92
  </SortButton>
93
93
  </Table.Th>
94
- <Table.Th className={cx(css.delta, css.deltaPercentage, css.sum)}>
94
+ <Table.Th className={cx(css.col, css.delta, css.deltaPercentage, css.sum)}>
95
95
  <SortButton
96
96
  fieldPath={fieldPath}
97
97
  fieldName="deltaPercentage"
@@ -146,8 +146,8 @@ export const MetricsTableHeader = (
146
146
 
147
147
  return (
148
148
  <Table.THead className={rootClassName}>
149
- <Table.Tr className={css.headerRow}>
150
- <Table.Th className={css.metricName} rowSpan={showSum ? 2 : 1}>
149
+ <Table.Tr>
150
+ <Table.Th className={cx(css.col, css.metric)} rowSpan={showSum ? 2 : 1}>
151
151
  {metricTitle || ' '}
152
152
  </Table.Th>
153
153
  {jobs.map((job, runIndex) => (
@@ -155,7 +155,7 @@ export const MetricsTableHeader = (
155
155
  ))}
156
156
  </Table.Tr>
157
157
  {showSum && (
158
- <Table.Tr className={css.headerRow}>
158
+ <Table.Tr>
159
159
  {jobs.map((_, runIndex) => (
160
160
  <SumColumn
161
161
  rows={rows}
@@ -2,23 +2,17 @@ import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
 
4
4
  import I18N from '../../i18n';
5
- import { Dropdown } from '../../ui/dropdown';
5
+ import { Dropdown, DropdownItem } from '../../ui/dropdown';
6
6
 
7
7
  export const MetricsTableOptions = (props) => {
8
- const { className, handleViewAll, handleResetFilters, ...restProps } = props;
8
+ const { className, handleViewAll, handleResetFilters, ...restProps } = props;
9
9
 
10
10
  return (
11
11
  <Dropdown className={className} glyph="more-vertical" {...restProps}>
12
12
  {handleResetFilters && (
13
- <Dropdown.Item onClick={handleResetFilters}>
14
- {I18N.RESET_FILTERS}
15
- </Dropdown.Item>
16
- )}
17
- {handleViewAll && (
18
- <Dropdown.Item onClick={handleViewAll}>
19
- {I18N.VIEW_ALL}
20
- </Dropdown.Item>
13
+ <DropdownItem onClick={handleResetFilters}>{I18N.RESET_FILTERS}</DropdownItem>
21
14
  )}
15
+ {handleViewAll && <DropdownItem onClick={handleViewAll}>{I18N.VIEW_ALL}</DropdownItem>}
22
16
  </Dropdown>
23
17
  );
24
18
  };
@@ -15,7 +15,7 @@ export const MetricsTableTitle = (props) => {
15
15
  const rootClassName = cx(css.root, className);
16
16
 
17
17
  return (
18
- <Stack space="xxxsmall" className={rootClassName}>
18
+ <Stack space="none" className={rootClassName}>
19
19
  <FlexStack space="xxxsmall" alignItems="center" as="h3" className={css.title}>
20
20
  <span>{title}</span>
21
21
 
@@ -19,6 +19,7 @@
19
19
  }
20
20
 
21
21
  .info {
22
+ font-size: var(--size-small);
22
23
  font-family: var(--font-family-fixed);
23
24
  font-weight: normal;
24
25
  }