@bundle-stats/ui 4.13.0-beta.9 → 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 (198) 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 +38 -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 +41 -4
  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-treemap/index.js +4 -0
  27. package/lib/components/metrics-treemap/index.js.map +1 -1
  28. package/lib/components/metrics-treemap/metrics-treemap.constants.js +3 -0
  29. package/lib/components/metrics-treemap/metrics-treemap.constants.js.map +1 -0
  30. package/lib/components/metrics-treemap/metrics-treemap.i18n.js +6 -0
  31. package/lib/components/metrics-treemap/metrics-treemap.i18n.js.map +1 -0
  32. package/lib/components/metrics-treemap/metrics-treemap.js +100 -62
  33. package/lib/components/metrics-treemap/metrics-treemap.js.map +1 -1
  34. package/lib/components/metrics-treemap/metrics-treemap.module.css +139 -51
  35. package/lib/components/metrics-treemap/metrics-treemap.utils.js +109 -0
  36. package/lib/components/metrics-treemap/metrics-treemap.utils.js.map +1 -0
  37. package/lib/components/module-info/module-info.js +1 -2
  38. package/lib/components/module-info/module-info.js.map +1 -1
  39. package/lib/components/run-info/run-info.module.css +7 -7
  40. package/lib/css/variables.css +14 -13
  41. package/lib/hooks/metrics-display-type.js +45 -24
  42. package/lib/hooks/metrics-display-type.js.map +1 -1
  43. package/lib/hooks/search-params.js +1 -0
  44. package/lib/hooks/search-params.js.map +1 -1
  45. package/lib/layout/box/box.module.css +4 -2
  46. package/lib/layout/flex-stack/flex-stack.js +3 -4
  47. package/lib/layout/flex-stack/flex-stack.js.map +1 -1
  48. package/lib/layout/flex-stack/flex-stack.module.css +19 -23
  49. package/lib/ui/button/button.js +5 -4
  50. package/lib/ui/button/button.js.map +1 -1
  51. package/lib/ui/button/button.module.css +55 -53
  52. package/lib/ui/dropdown/dropdown.js +2 -2
  53. package/lib/ui/dropdown/dropdown.js.map +1 -1
  54. package/lib/ui/filters/filters.js +2 -2
  55. package/lib/ui/filters/filters.js.map +1 -1
  56. package/lib/ui/filters/filters.module.css +8 -1
  57. package/lib/ui/hover-card/hover-card.js +1 -1
  58. package/lib/ui/hover-card/hover-card.js.map +1 -1
  59. package/lib/ui/icon/icon.js +2 -1
  60. package/lib/ui/icon/icon.js.map +1 -1
  61. package/lib/ui/input-search/input-search.js +1 -1
  62. package/lib/ui/input-search/input-search.js.map +1 -1
  63. package/lib/ui/loader/loader.js +1 -1
  64. package/lib/ui/loader/loader.js.map +1 -1
  65. package/lib/ui/table/table.module.css +30 -0
  66. package/lib/ui/tag/tag.module.css +3 -3
  67. package/lib/ui/toolbar/toolbar.module.css +1 -3
  68. package/lib-esm/app/app.js +4 -8
  69. package/lib-esm/app/app.js.map +1 -1
  70. package/lib-esm/app/app.module.css +2 -2
  71. package/lib-esm/assets/icons.svg +70 -67
  72. package/lib-esm/assets/icons.svg.js +14 -12
  73. package/lib-esm/assets/icons.svg.js.map +1 -1
  74. package/lib-esm/components/bundle-assets/bundle-assets.js +45 -11
  75. package/lib-esm/components/bundle-assets/bundle-assets.js.map +1 -1
  76. package/lib-esm/components/bundle-assets/bundle-assets.module.css +0 -5
  77. package/lib-esm/components/bundle-assets-totals/bundle-assets-totals.js +15 -13
  78. package/lib-esm/components/bundle-assets-totals/bundle-assets-totals.js.map +1 -1
  79. package/lib-esm/components/bundle-modules/bundle-modules.i18n.js +1 -1
  80. package/lib-esm/components/bundle-modules/bundle-modules.js +39 -16
  81. package/lib-esm/components/bundle-modules/bundle-modules.js.map +1 -1
  82. package/lib-esm/components/bundle-modules/bundle-modules.module.css +0 -5
  83. package/lib-esm/components/bundle-packages/bundle-packages.js +44 -10
  84. package/lib-esm/components/bundle-packages/bundle-packages.js.map +1 -1
  85. package/lib-esm/components/bundle-packages/bundle-packages.module.css +0 -5
  86. package/lib-esm/components/delta/delta.js +1 -1
  87. package/lib-esm/components/delta/delta.js.map +1 -1
  88. package/lib-esm/components/delta/delta.module.css +10 -1
  89. package/lib-esm/components/jobs-header/jobs-header.module.css +0 -4
  90. package/lib-esm/components/metrics-display-selector/metrics-display-selector.js +41 -4
  91. package/lib-esm/components/metrics-display-selector/metrics-display-selector.js.map +1 -1
  92. package/lib-esm/components/metrics-display-selector/metrics-display-selector.module.css +15 -7
  93. package/lib-esm/components/metrics-treemap/index.js +1 -0
  94. package/lib-esm/components/metrics-treemap/index.js.map +1 -1
  95. package/lib-esm/components/metrics-treemap/metrics-treemap.constants.js +2 -0
  96. package/lib-esm/components/metrics-treemap/metrics-treemap.constants.js.map +1 -0
  97. package/lib-esm/components/metrics-treemap/metrics-treemap.i18n.js +3 -0
  98. package/lib-esm/components/metrics-treemap/metrics-treemap.i18n.js.map +1 -0
  99. package/lib-esm/components/metrics-treemap/metrics-treemap.js +102 -63
  100. package/lib-esm/components/metrics-treemap/metrics-treemap.js.map +1 -1
  101. package/lib-esm/components/metrics-treemap/metrics-treemap.module.css +139 -51
  102. package/lib-esm/components/metrics-treemap/metrics-treemap.utils.js +105 -0
  103. package/lib-esm/components/metrics-treemap/metrics-treemap.utils.js.map +1 -0
  104. package/lib-esm/components/module-info/module-info.js +1 -2
  105. package/lib-esm/components/module-info/module-info.js.map +1 -1
  106. package/lib-esm/components/run-info/run-info.module.css +7 -7
  107. package/lib-esm/css/variables.css +14 -13
  108. package/lib-esm/hooks/metrics-display-type.js +46 -24
  109. package/lib-esm/hooks/metrics-display-type.js.map +1 -1
  110. package/lib-esm/hooks/search-params.js +1 -0
  111. package/lib-esm/hooks/search-params.js.map +1 -1
  112. package/lib-esm/layout/box/box.module.css +4 -2
  113. package/lib-esm/layout/flex-stack/flex-stack.js +3 -4
  114. package/lib-esm/layout/flex-stack/flex-stack.js.map +1 -1
  115. package/lib-esm/layout/flex-stack/flex-stack.module.css +19 -23
  116. package/lib-esm/ui/button/button.js +5 -4
  117. package/lib-esm/ui/button/button.js.map +1 -1
  118. package/lib-esm/ui/button/button.module.css +55 -53
  119. package/lib-esm/ui/dropdown/dropdown.js +2 -2
  120. package/lib-esm/ui/dropdown/dropdown.js.map +1 -1
  121. package/lib-esm/ui/filters/filters.js +2 -2
  122. package/lib-esm/ui/filters/filters.js.map +1 -1
  123. package/lib-esm/ui/filters/filters.module.css +8 -1
  124. package/lib-esm/ui/hover-card/hover-card.js +1 -1
  125. package/lib-esm/ui/hover-card/hover-card.js.map +1 -1
  126. package/lib-esm/ui/icon/icon.js +2 -1
  127. package/lib-esm/ui/icon/icon.js.map +1 -1
  128. package/lib-esm/ui/input-search/input-search.js +1 -1
  129. package/lib-esm/ui/input-search/input-search.js.map +1 -1
  130. package/lib-esm/ui/loader/loader.js +1 -1
  131. package/lib-esm/ui/loader/loader.js.map +1 -1
  132. package/lib-esm/ui/table/table.module.css +30 -0
  133. package/lib-esm/ui/tag/tag.module.css +3 -3
  134. package/lib-esm/ui/toolbar/toolbar.module.css +1 -3
  135. package/package.json +9 -9
  136. package/src/app/app.jsx +4 -12
  137. package/src/app/app.module.css +2 -2
  138. package/src/assets/icons/check.svg +4 -0
  139. package/src/assets/icons.svg +70 -67
  140. package/src/assets/icons.svg.jsx +12 -12
  141. package/src/components/bundle-assets/bundle-assets.jsx +82 -25
  142. package/src/components/bundle-assets/bundle-assets.module.css +0 -5
  143. package/src/components/bundle-assets-totals/bundle-assets-totals.jsx +53 -46
  144. package/src/components/bundle-modules/bundle-modules.i18n.ts +1 -1
  145. package/src/components/bundle-modules/bundle-modules.module.css +0 -5
  146. package/src/components/bundle-modules/bundle-modules.tsx +116 -53
  147. package/src/components/bundle-packages/bundle-packages.jsx +77 -20
  148. package/src/components/bundle-packages/bundle-packages.module.css +0 -5
  149. package/src/components/delta/delta.jsx +1 -1
  150. package/src/components/delta/delta.module.css +10 -1
  151. package/src/components/jobs-header/jobs-header.module.css +0 -4
  152. package/src/components/metrics-display-selector/metrics-display-selector.module.css +15 -7
  153. package/src/components/metrics-display-selector/metrics-display-selector.stories.tsx +33 -0
  154. package/src/components/metrics-display-selector/metrics-display-selector.tsx +83 -25
  155. package/src/components/metrics-treemap/__tests__/metrics-treemap.utils.ts +188 -0
  156. package/src/components/metrics-treemap/index.ts +1 -0
  157. package/src/components/metrics-treemap/metrics-treemap.constants.ts +52 -0
  158. package/src/components/metrics-treemap/metrics-treemap.i18n.ts +2 -0
  159. package/src/components/metrics-treemap/metrics-treemap.module.css +139 -51
  160. package/src/components/metrics-treemap/metrics-treemap.stories.tsx +44 -10
  161. package/src/components/metrics-treemap/metrics-treemap.tsx +329 -121
  162. package/src/components/metrics-treemap/metrics-treemap.utils.ts +162 -0
  163. package/src/components/module-info/module-info.tsx +1 -1
  164. package/src/components/run-info/run-info.module.css +7 -7
  165. package/src/css/variables.css +14 -13
  166. package/src/hooks/metrics-display-type.ts +79 -29
  167. package/src/hooks/search-params.js +1 -0
  168. package/src/layout/box/box.module.css +4 -2
  169. package/src/layout/flex-stack/flex-stack.module.css +19 -23
  170. package/src/layout/flex-stack/flex-stack.tsx +2 -8
  171. package/src/ui/button/button.module.css +55 -53
  172. package/src/ui/button/button.stories.tsx +16 -9
  173. package/src/ui/button/button.tsx +8 -7
  174. package/src/ui/dropdown/dropdown.tsx +2 -3
  175. package/src/ui/filters/filters.module.css +8 -1
  176. package/src/ui/filters/filters.tsx +2 -3
  177. package/src/ui/hover-card/hover-card.tsx +1 -1
  178. package/src/ui/icon/icon.tsx +2 -1
  179. package/src/ui/input-search/input-search.tsx +1 -0
  180. package/src/ui/loader/loader.jsx +1 -1
  181. package/src/ui/table/table.module.css +30 -0
  182. package/src/ui/tag/tag.module.css +3 -3
  183. package/src/ui/toolbar/toolbar.module.css +1 -3
  184. package/types/components/bundle-modules/bundle-modules.i18n.d.ts +1 -1
  185. package/types/components/delta/delta.d.ts +2 -2
  186. package/types/components/metrics-display-selector/metrics-display-selector.d.ts +3 -1
  187. package/types/components/metrics-treemap/index.d.ts +1 -0
  188. package/types/components/metrics-treemap/metrics-treemap.constants.d.ts +20 -0
  189. package/types/components/metrics-treemap/metrics-treemap.d.ts +7 -5
  190. package/types/components/metrics-treemap/metrics-treemap.i18n.d.ts +2 -0
  191. package/types/components/metrics-treemap/metrics-treemap.utils.d.ts +5 -0
  192. package/types/hooks/metrics-display-type.d.ts +8 -2
  193. package/types/ui/dropdown/dropdown.d.ts +0 -1
  194. package/types/ui/icon/icon.d.ts +4 -2
  195. package/types/ui/loader/loader.d.ts +2 -2
  196. package/lib/components/bundle-assets-totals/bundle-assets-totals.module.css +0 -7
  197. package/lib-esm/components/bundle-assets-totals/bundle-assets-totals.module.css +0 -7
  198. package/src/components/bundle-assets-totals/bundle-assets-totals.module.css +0 -7
@@ -0,0 +1,162 @@
1
+ import {
2
+ DeltaType,
3
+ type MetricRunInfoBaseline,
4
+ type MetricRunInfo,
5
+ type ReportMetricRow,
6
+ } from '@bundle-stats/utils';
7
+
8
+ import type { TreeLeaf, TreeNodeChildren, Tree, TreeTotal } from './metrics-treemap.constants';
9
+
10
+ const ROOT_LABEL = '(root)';
11
+
12
+ /**
13
+ * Set node value to the largest run value to allow to
14
+ * display the impact of deleted/new entries
15
+ */
16
+ function getReportMetricRowMaxValue(item: ReportMetricRow): number {
17
+ const values = item.runs.map((run) => run?.value || 0);
18
+ return Math.max(...values);
19
+ }
20
+
21
+ /**
22
+ * Generate treemap node list(flat)
23
+ */
24
+ export function getTreemapNodes(items: Array<ReportMetricRow>): Tree {
25
+ const rootChildren: Array<TreeLeaf> = items.map((item) => ({
26
+ id: item.key,
27
+ label: item.label,
28
+ value: getReportMetricRowMaxValue(item),
29
+ item,
30
+ }));
31
+
32
+ return {
33
+ id: '',
34
+ label: ROOT_LABEL,
35
+ value: 0,
36
+ children: rootChildren,
37
+ };
38
+ }
39
+
40
+ function getItemValues(runs: ReportMetricRow['runs']): TreeTotal {
41
+ const runCount = runs?.length;
42
+ const current = runs[0]?.value || 0;
43
+
44
+ if (runCount < 2) {
45
+ return { current, baseline: 0 };
46
+ }
47
+
48
+ return {
49
+ current,
50
+ baseline: runs[runCount - 1]?.value || 0,
51
+ };
52
+ }
53
+
54
+ /**
55
+ * Recursively set treemap nodes
56
+ */
57
+ function setTreeNode(
58
+ nodes: TreeNodeChildren,
59
+ slugs: Array<string>,
60
+ currentSlugId: number,
61
+ newNode: TreeLeaf,
62
+ ): TreeTotal {
63
+ const baseSlugs = slugs.slice(0, currentSlugId);
64
+ const [currentSlug, ...restSlug] = slugs.slice(currentSlugId);
65
+
66
+ // Add to current nodes if there are no child nodes
67
+ if (!currentSlug) {
68
+ nodes.push(newNode);
69
+ return getItemValues(newNode.item.runs);
70
+ }
71
+
72
+ const currentNodePath = [...baseSlugs, currentSlug].join('/');
73
+
74
+ // Check for existing parent in current nodes
75
+ let parentNode = nodes.find((treeNode) => treeNode.id === currentNodePath) as Tree;
76
+
77
+ // Create the new parentNode if missing
78
+ if (!parentNode) {
79
+ parentNode = {
80
+ id: currentNodePath,
81
+ label: currentSlug,
82
+ value: 0,
83
+ children: [],
84
+ total: {
85
+ current: 0,
86
+ baseline: 0,
87
+ },
88
+ };
89
+
90
+ nodes.push(parentNode);
91
+ }
92
+
93
+ // accumulate children values
94
+ const nodeValues = getItemValues(newNode?.item?.runs);
95
+
96
+ parentNode.total = {
97
+ current: (parentNode.total?.current || 0) + nodeValues.current,
98
+ baseline: (parentNode.total?.baseline || 0) + (nodeValues.baseline || 0),
99
+ };
100
+
101
+ // If there are no other slugs, the new node is as leaf and we add it to the parent
102
+ if (restSlug.length === 0) {
103
+ parentNode.children.push(newNode);
104
+ return getItemValues(newNode.item.runs);
105
+ }
106
+
107
+ return setTreeNode(parentNode.children, slugs, currentSlugId + 1, newNode);
108
+ }
109
+
110
+ /**
111
+ * Generate treemap nodes tree by directory
112
+ */
113
+ export function getTreemapNodesGroupedByPath(items: Array<ReportMetricRow>): Tree {
114
+ const treeNodes: TreeNodeChildren = [];
115
+ const total = { current: 0, baseline: 0 };
116
+
117
+ items.forEach((item) => {
118
+ const slugs = item.key.split('/');
119
+ const baseSlugs = slugs.slice(0, -1);
120
+ const baseName = slugs.slice(-1)[0];
121
+
122
+ const treeNode = {
123
+ id: item.key,
124
+ label: baseName,
125
+ value: getReportMetricRowMaxValue(item),
126
+ item,
127
+ };
128
+
129
+ const childrenTotal = setTreeNode(treeNodes, baseSlugs, 0, treeNode);
130
+
131
+ total.current += childrenTotal.current || 0;
132
+ total.baseline += childrenTotal.baseline || 0;
133
+ });
134
+
135
+ return {
136
+ id: '',
137
+ label: ROOT_LABEL,
138
+ value: 0,
139
+ children: treeNodes,
140
+ total,
141
+ };
142
+ }
143
+
144
+ export function resolveGroupDeltaType(
145
+ metricRunInfo?: MetricRunInfo | MetricRunInfoBaseline,
146
+ ): DeltaType.NO_CHANGE | DeltaType.NEGATIVE | DeltaType.POSITIVE {
147
+ if (!metricRunInfo) {
148
+ return DeltaType.NO_CHANGE;
149
+ }
150
+
151
+ const deltaType = 'displayDelta' in metricRunInfo ? metricRunInfo.deltaType : undefined;
152
+
153
+ if (deltaType?.match(/NEGATIVE/)) {
154
+ return DeltaType.NEGATIVE;
155
+ }
156
+
157
+ if (deltaType?.match(/POSITIVE/)) {
158
+ return DeltaType.POSITIVE;
159
+ }
160
+
161
+ return DeltaType.NO_CHANGE;
162
+ }
@@ -76,7 +76,7 @@ export const ModuleInfo = (props: ModuleInfoProps & React.ComponentProps<'div'>)
76
76
  (currentRun, index) =>
77
77
  !isEmpty(currentRun?.chunkIds) && (
78
78
  <EntryInfo.Meta label="Chunks" className={css.chunks}>
79
- Job #{index + 1}:
79
+ {labels[index]}:
80
80
  {currentRun.chunkIds.map((chunkId) => {
81
81
  const chunk = chunks?.find(({ id }) => id === chunkId);
82
82
 
@@ -31,6 +31,10 @@
31
31
  font-weight: bold;
32
32
  }
33
33
 
34
+ .delta {
35
+ font-weight: normal;
36
+ }
37
+
34
38
  .deltaValue + .deltaValue::before {
35
39
  margin-left: calc(var(--space-xxxsmall) / 2);
36
40
  margin-right: calc(var(--space-xxxsmall) / 2);
@@ -72,17 +76,13 @@
72
76
 
73
77
  /* Size variation */
74
78
  .small .currentMetric {
75
- font-size: var(--size-large);
79
+ font-size: var(--size-medium);
76
80
  }
77
81
 
78
82
  .large .currentMetric {
79
- font-size: var(--size-xxxlarge);
83
+ font-size: var(--size-xxlarge);
80
84
  }
81
85
 
82
86
  .large .baselineMetric {
83
- font-size: var(--size-medium);
84
- }
85
-
86
- .large .delta {
87
- margin-left: var(--space-xxxsmall);
87
+ font-size: var(--size-small);
88
88
  }
@@ -29,20 +29,20 @@
29
29
  /*
30
30
  * Color scheme:
31
31
  * https://coolors.co/287acc-da444e-55b950-efcc1a-192339
32
- * http://mcg.mbitson.com/#!?mcgpalette0=%23da444e&mcgpalette1=%2355b950&mcgpalette2=%23efcc1a&mcgpalette3=%23353138&mcgpalette4=%23287acc&themename=mcgtheme
32
+ * http://mcg.mbitson.com/#!?mcgpalette0=%23da444e&mcgpalette1=%2355b950&mcgpalette2=%23efcc1a&mcgpalette3=%233e3c49&mcgpalette4=%23287acc&themename=bundle-stats
33
33
  * https://hihayk.github.io/scale/#4/5/50/90/-51/0/0/14/353138/53/49/56/white
34
34
  */
35
35
  --color-gray-25: #f9f9fa;
36
36
  --color-gray-50: #e8e8e9;
37
- --color-gray-100: #c6c5c7;
38
- --color-gray-200: #a2a0a4;
39
- --color-gray-300: #7e7b80;
40
- --color-gray-400: #59565c;
41
- --color-gray-500: #353138;
42
- --color-gray-600: #302b31;
43
- --color-gray-700: #2a252a;
44
- --color-gray-800: #231e22;
45
- --color-gray-900: #1c181b;
37
+ --color-gray-100: #c5c5c8;
38
+ --color-gray-200: #9f9ea4;
39
+ --color-gray-300: #787780;
40
+ --color-gray-400: #5b5964;
41
+ --color-gray-500: #3e3c49;
42
+ --color-gray-600: #383642;
43
+ --color-gray-700: #302e39;
44
+ --color-gray-800: #282731;
45
+ --color-gray-900: #1b1a21;
46
46
 
47
47
  --color-gray-ultra-light: var(--color-gray-200);
48
48
  --color-gray-light: var(--color-gray-300);
@@ -192,9 +192,10 @@
192
192
  --shadow-layer: 0 0 var(--space-xxxsmall) var(--color-shadow);
193
193
  --shadow-layer-high: 0 0 var(--space-xxsmall) var(--color-shadow);
194
194
 
195
- --radius-small: 4px;
196
- --radius-medium: 5px;
197
- --radius-large: 6px;
195
+ --radius-xsmall: 3px;
196
+ --radius-small: 5px;
197
+ --radius-medium: 7px;
198
+ --radius-large: 9px;
198
199
 
199
200
  --outline-hover: 0 0 0 3px var(--color-highlight);
200
201
 
@@ -4,53 +4,103 @@ import { StringParam, useQueryParams } from 'use-query-params';
4
4
 
5
5
  import { MetricsDisplayType } from '../constants';
6
6
 
7
- const DEFAULT_DISPLAY_TYPE = MetricsDisplayType.TABLE;
8
- const PARAM_NAME = 'dt';
7
+ const DEFAULT_VALUE = MetricsDisplayType.TABLE;
8
+ const DEFAULT_GROUP_BY = '';
9
9
 
10
- type UseMetricsDisplayType = [MetricsDisplayType, (value: MetricsDisplayType) => void];
10
+ // Display type query param name
11
+ const QUERY_PARAM_VALUE = 'dt';
12
+ // Display type group by param name
13
+ const QUERY_PARAM_GROUP_BY = 'dtg';
11
14
 
12
- export const useMetricsDisplayType = (): UseMetricsDisplayType => {
13
- const [{ [PARAM_NAME]: queryDisplayType }, setQueryParams] = useQueryParams({
14
- [PARAM_NAME]: StringParam,
15
+ type MetricsDisplayTypeData = {
16
+ value: MetricsDisplayType;
17
+ groupBy: string;
18
+ };
19
+
20
+ type UseMetricsDisplayType = [
21
+ { value: MetricsDisplayType; groupBy?: string },
22
+ (newDisplayType: MetricsDisplayType, newGroupBy?: string) => void,
23
+ ];
24
+
25
+ export const useMetricsDisplayType = (
26
+ groups?: Partial<Record<MetricsDisplayType, Array<string>>>,
27
+ ): UseMetricsDisplayType => {
28
+ const [queryParams, setQueryParams] = useQueryParams({
29
+ [QUERY_PARAM_VALUE]: StringParam,
30
+ [QUERY_PARAM_GROUP_BY]: StringParam,
15
31
  });
16
- const [storageDisplayType, setStoreageDisplayType] = useLocalStorage(
17
- PARAM_NAME,
18
- MetricsDisplayType.TABLE,
32
+
33
+ const { [QUERY_PARAM_VALUE]: queryParamValue, [QUERY_PARAM_GROUP_BY]: queryParamGroupBy } =
34
+ queryParams;
35
+ const [localStorage, setLocalStorage] = useLocalStorage<Partial<MetricsDisplayTypeData>>(
36
+ 'storage',
37
+ {
38
+ value: DEFAULT_VALUE,
39
+ groupBy: DEFAULT_GROUP_BY,
40
+ },
19
41
  );
20
42
 
21
- const displayType = useMemo(() => {
22
- const value = queryDisplayType || storageDisplayType;
43
+ /**
44
+ * Normalize display type value
45
+ */
46
+ const value = useMemo(() => {
47
+ const resolvedValue = queryParamValue ?? localStorage?.value;
48
+
49
+ if (!resolvedValue) {
50
+ return DEFAULT_VALUE;
51
+ }
52
+
53
+ if (!Object.values(MetricsDisplayType).includes(resolvedValue as MetricsDisplayType)) {
54
+ return DEFAULT_VALUE;
55
+ }
23
56
 
24
- if (!value) {
25
- return DEFAULT_DISPLAY_TYPE;
57
+ return resolvedValue as MetricsDisplayType;
58
+ }, [queryParamValue, localStorage?.value]);
59
+
60
+ /**
61
+ * Normalize display type group by
62
+ */
63
+ const groupBy = useMemo(() => {
64
+ const resolvedValue = queryParamGroupBy ?? localStorage?.groupBy;
65
+
66
+ if (!resolvedValue) {
67
+ return DEFAULT_GROUP_BY;
26
68
  }
27
69
 
28
- if (!Object.values(MetricsDisplayType).includes(value as MetricsDisplayType)) {
29
- return DEFAULT_DISPLAY_TYPE;
70
+ if (!groups?.[value]?.includes(resolvedValue as MetricsDisplayType)) {
71
+ return DEFAULT_GROUP_BY;
30
72
  }
31
73
 
32
- return value as MetricsDisplayType;
33
- }, [queryDisplayType, storageDisplayType]);
74
+ return resolvedValue;
75
+ }, [queryParamGroupBy, localStorage?.groupBy]);
34
76
 
77
+ /**
78
+ * Synchronize query params when values are different
79
+ */
35
80
  useEffect(() => {
36
- // Update query string display type when missing
37
- if (queryDisplayType !== displayType) {
38
- setQueryParams({ [PARAM_NAME]: displayType });
81
+ if (value !== queryParamValue || groupBy !== queryParamGroupBy) {
82
+ setQueryParams({ [QUERY_PARAM_VALUE]: value, [QUERY_PARAM_GROUP_BY]: groupBy });
39
83
  }
84
+ }, [value, queryParamValue, groupBy, queryParamGroupBy, setQueryParams]);
40
85
 
41
- // Update storage state when query string is set and different
42
- if (storageDisplayType !== displayType) {
43
- setStoreageDisplayType(queryDisplayType as MetricsDisplayType);
86
+ /**
87
+ * Synchronize storage when values are different
88
+ */
89
+ useEffect(() => {
90
+ if (value !== localStorage?.value || groupBy !== localStorage.groupBy) {
91
+ setLocalStorage({ value, groupBy });
44
92
  }
45
- }, [displayType, queryDisplayType, storageDisplayType, setQueryParams, setStoreageDisplayType]);
93
+ }, [value, groupBy, setLocalStorage, localStorage]);
46
94
 
47
95
  const setDisplayType = useCallback(
48
- (value: MetricsDisplayType) => {
49
- setStoreageDisplayType(value);
50
- setQueryParams({ [PARAM_NAME]: value });
96
+ (newValue: MetricsDisplayType, newGroupBy: string = DEFAULT_GROUP_BY) => {
97
+ setQueryParams({
98
+ [QUERY_PARAM_VALUE]: newValue,
99
+ [QUERY_PARAM_GROUP_BY]: newGroupBy,
100
+ });
51
101
  },
52
- [setStoreageDisplayType, setQueryParams],
102
+ [setQueryParams],
53
103
  );
54
104
 
55
- return [displayType, setDisplayType];
105
+ return useMemo(() => [{ value, groupBy }, setDisplayType], [value, groupBy, setDisplayType]);
56
106
  };
@@ -38,6 +38,7 @@ const getSearchReducer =
38
38
  const newState = {
39
39
  filters: payload,
40
40
  search: state.search,
41
+ searchPattern: getSearchPattern(state.search),
41
42
  };
42
43
  setParentState(newState);
43
44
  return newState;
@@ -8,11 +8,13 @@
8
8
  }
9
9
 
10
10
  .outline > :first-child {
11
- border-radius: var(--radius-medium) var(--radius-medium) 0 0;
11
+ border-top-left-radius: var(--radius-medium);
12
+ border-top-right-radius: var(--radius-medium);
12
13
  }
13
14
 
14
15
  .outline > :last-child {
15
- border-radius: 0 0 var(--radius-medium) var(--radius-medium);
16
+ border-bottom-left-radius: var(--radius-medium);
17
+ border-bottom-right-radius: var(--radius-medium);
16
18
  }
17
19
 
18
20
  .outlineHover {
@@ -1,48 +1,44 @@
1
1
  .root {
2
2
  display: flex;
3
- align-items: stretch;
4
3
  justify-content: flex-start;
5
- }
6
-
7
- .root > .item:last-child {
8
- margin-right: 0;
4
+ gap: 0;
9
5
  }
10
6
 
11
7
  /** Space variation */
12
- .space--xxxsmall > .item {
13
- margin: 0 var(--space-xxxsmall) 0 0;
8
+ .space--xxxsmall {
9
+ gap: var(--space-xxxsmall);
14
10
  }
15
11
 
16
- .space--xxsmall > .item {
17
- margin: 0 var(--space-xxsmall) 0 0;
12
+ .space--xxsmall {
13
+ gap: var(--space-xxsmall);
18
14
  }
19
15
 
20
- .space--xsmall > .item {
21
- margin: 0 var(--space-xsmall) 0 0;
16
+ .space--xsmall {
17
+ gap: var(--space-xsmall);
22
18
  }
23
19
 
24
- .space--small > .item {
25
- margin: 0 var(--space-small) 0 0;
20
+ .space--small {
21
+ gap: var(--space-small);
26
22
  }
27
23
 
28
- .space--medium > .item {
29
- margin: 0 var(--space-medium) 0 0;
24
+ .space--medium {
25
+ gap: var(--space-medium);
30
26
  }
31
27
 
32
- .space--large > .item {
33
- margin: 0 var(--space-large) 0 0;
28
+ .space--large {
29
+ gap: var(--space-large);
34
30
  }
35
31
 
36
- .space--xlarge > .item {
37
- margin: 0 var(--space-xlarge) 0 0;
32
+ .space--xlarge {
33
+ gap: var(--space-xlarge);
38
34
  }
39
35
 
40
- .space--xxlarge > .item {
41
- margin: 0 var(--space-xxlarge) 0 0;
36
+ .space--xxlarge {
37
+ gap: var(--space-xxlarge);
42
38
  }
43
39
 
44
- .space--xxxlarge > .item {
45
- margin: 0 var(--space-xxxlarge) 0 0;
40
+ .space--xxxlarge {
41
+ gap: var(--space-xxxlarge);
46
42
  }
47
43
 
48
44
  /** Align items variation */
@@ -2,7 +2,6 @@ import React from 'react';
2
2
  import cx from 'classnames';
3
3
 
4
4
  import { NO_SPACE, SPACES } from '../../tokens';
5
- import { getRenderChildWithClassName } from '../../utils';
6
5
  import css from './flex-stack.module.css';
7
6
 
8
7
  type SpaceValue = (typeof SPACES)[number];
@@ -22,22 +21,17 @@ export const FlexStack = <T extends React.ElementType = 'div'>(
22
21
  className = '',
23
22
  space = NO_SPACE,
24
23
  inline = false,
25
- children = null,
26
24
  alignItems = '',
27
25
  ...restProps
28
26
  } = props;
29
27
 
30
28
  const rootClassName = cx(
31
- className,
32
29
  css.root,
33
30
  css[`space--${space}`],
34
31
  css[`align-items--${alignItems}`],
35
32
  inline && css.inline,
33
+ className,
36
34
  );
37
35
 
38
- return (
39
- <Component {...restProps} className={rootClassName}>
40
- {React.Children.map(children, getRenderChildWithClassName(css.item))}
41
- </Component>
42
- );
36
+ return <Component {...restProps} className={rootClassName} />;
43
37
  };
@@ -1,14 +1,21 @@
1
1
  .root {
2
+ /* use for vertical padding and to compute gap and horizontal spacing */
3
+ --button-space: 0px;
4
+ /* button border width */
5
+ --border-width: 0px;
6
+
2
7
  display: inline-flex;
3
8
  align-items: center;
4
- gap: var(--space-xxsmall);
9
+ justify-content: center;
10
+ gap: calc(max(var(--button-space), var(--space-xxsmall)) * 0.66);
5
11
  appearance: none;
6
12
  padding: 0;
7
- border: 0;
13
+ border: var(--border-width) solid transparent;
8
14
  background: none;
9
15
  transition: var(--transition-out);
10
16
  color: var(--color-text-ultra-light);
11
17
  font-family: var(--font-family);
18
+ white-space: nowrap;
12
19
  }
13
20
 
14
21
  a.root {
@@ -18,6 +25,7 @@ a.root {
18
25
  .root:hover,
19
26
  .root:active,
20
27
  .root:focus {
28
+ outline: none;
21
29
  color: var(--color-text-light);
22
30
  transition: var(--transition-in);
23
31
  }
@@ -98,7 +106,7 @@ a.root {
98
106
  * Solid Kind variation
99
107
  */
100
108
  .solid {
101
- background: var(--color-text-light);
109
+ background: var(--color-text-ultra-light);
102
110
  color: var(--color-background);
103
111
  }
104
112
 
@@ -106,7 +114,7 @@ a.root {
106
114
  .solid:active,
107
115
  .solid:focus {
108
116
  box-shadow: var(--outline-hover);
109
- background: var(--color-text);
117
+ background: var(--color-text-light);
110
118
  color: var(--color-background);
111
119
  }
112
120
 
@@ -170,11 +178,51 @@ a.root {
170
178
  background: var(--color-success-dark);
171
179
  }
172
180
 
181
+ /**
182
+ * Size variation
183
+ */
184
+ .small {
185
+ --button-space: var(--space-xxsmall);
186
+
187
+ font-size: var(--size-small);
188
+ line-height: var(--space-small);
189
+ }
190
+
191
+ .small .glyph {
192
+ width: var(--space-small);
193
+ height: var(--space-small);
194
+ }
195
+
196
+ .medium {
197
+ --button-space: var(--space-xsmall);
198
+
199
+ font-size: var(--size-medium);
200
+ line-height: calc(var(--space-small) + var(--space-xxxsmall));
201
+ }
202
+
203
+ .medium .glyph {
204
+ width: calc(var(--space-small) + var(--space-xxxsmall));
205
+ height: calc(var(--space-small) + var(--space-xxxsmall));
206
+ }
207
+
208
+ .large {
209
+ --button-space: var(--space-small);
210
+
211
+ font-size: var(--size-large);
212
+ line-height: var(--space-medium);
213
+ }
214
+
215
+ .large .glyph {
216
+ width: var(--space-medium);
217
+ height: var(--space-medium);
218
+ }
219
+
173
220
  /**
174
221
  * Outline variation
175
222
  */
176
223
  .outline {
177
- border: 1px solid var(--color-outline);
224
+ --border-width: 1px;
225
+ border-color: var(--color-outline);
178
226
  }
179
227
 
180
228
  .outline:hover,
@@ -244,58 +292,12 @@ a.root {
244
292
  border-color: var(--color-outline-success-dark);
245
293
  }
246
294
 
247
- /**
248
- * Size variation
249
- */
250
- .small {
251
- font-size: var(--size-small);
252
- gap: var(--space-xxxsmall);
253
- line-height: var(--space-small);
254
- }
255
-
256
- .small .glyph {
257
- width: calc(var(--space-xsmall) + 2px);
258
- height: calc(var(--space-xsmall) + 2px);
259
- margin: 1px; /* compensate to keep the same height when the text is not provided */
260
- }
261
-
262
- .medium {
263
- font-size: var(--size-medium);
264
- gap: var(--space-xxsmall);
265
- line-height: var(--space-small);
266
- }
267
-
268
- .large {
269
- font-size: var(--size-large);
270
- gap: var(--space-xxsmall);
271
- line-height: var(--space-small);
272
- }
273
295
 
274
296
  /**
275
297
  * Padding variation
276
298
  */
277
- .padding--small {
278
- padding: var(--space-xxsmall);
279
- }
280
-
281
- .outline--padding--small {
282
- padding: calc(var(--space-xxsmall) - 1px);
283
- }
284
-
285
- .padding--medium {
286
- padding: var(--space-xsmall);
287
- }
288
-
289
- .outline--padding--medium {
290
- padding: calc(var(--space-xsmall) - 1px);
291
- }
292
-
293
- .padding--large {
294
- padding: var(--space-small);
295
- }
296
-
297
- .outline--padding--large {
298
- padding: calc(var(--space-small) - 1px);
299
+ .padding {
300
+ padding: calc(var(--button-space) - var(--border-width));
299
301
  }
300
302
 
301
303
  /**