@bundle-stats/ui 4.4.0 → 4.5.0-beta.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 (186) hide show
  1. package/lib/app/header/header.module.css +1 -0
  2. package/lib/assets/icons.svg +17 -11
  3. package/lib/assets/icons.svg.js +15 -11
  4. package/lib/assets/icons.svg.js.map +1 -1
  5. package/lib/components/bundle-assets/bundle-assets.js +3 -11
  6. package/lib/components/bundle-assets/bundle-assets.js.map +1 -1
  7. package/lib/components/bundle-assets/bundle-assets.utils.js +8 -20
  8. package/lib/components/bundle-assets/bundle-assets.utils.js.map +1 -1
  9. package/lib/components/bundle-assets/index.js +0 -2
  10. package/lib/components/bundle-assets/index.js.map +1 -1
  11. package/lib/components/bundle-modules/bundle-modules.js +2 -10
  12. package/lib/components/bundle-modules/bundle-modules.js.map +1 -1
  13. package/lib/components/bundle-modules/bundle-modules.utils.js +1 -13
  14. package/lib/components/bundle-modules/bundle-modules.utils.js.map +1 -1
  15. package/lib/components/bundle-modules/index.js +2 -4
  16. package/lib/components/bundle-modules/index.js.map +1 -1
  17. package/lib/components/bundle-packages/bundle-packages.js +2 -10
  18. package/lib/components/bundle-packages/bundle-packages.js.map +1 -1
  19. package/lib/components/bundle-packages/bundle-packages.utils.js +1 -13
  20. package/lib/components/bundle-packages/bundle-packages.utils.js.map +1 -1
  21. package/lib/components/bundle-packages/index.js +2 -4
  22. package/lib/components/bundle-packages/index.js.map +1 -1
  23. package/lib/components/jobs-header/jobs-header.js +2 -2
  24. package/lib/components/jobs-header/jobs-header.js.map +1 -1
  25. package/lib/components/metrics-table/metrics-table.js +47 -104
  26. package/lib/components/metrics-table/metrics-table.js.map +1 -1
  27. package/lib/components/metrics-table/metrics-table.module.css +18 -17
  28. package/lib/components/metrics-table-search/metrics-table-search.js +1 -1
  29. package/lib/components/metrics-table-search/metrics-table-search.js.map +1 -1
  30. package/lib/components/metrics-table-title/metrics-table-title.js +2 -2
  31. package/lib/components/metrics-table-title/metrics-table-title.js.map +1 -1
  32. package/lib/components/metrics-table-title/metrics-table-title.module.css +3 -1
  33. package/lib/components/{job-header → sort-button}/index.js +1 -1
  34. package/lib/components/sort-button/index.js.map +1 -0
  35. package/lib/components/sort-button/sort-button.js +73 -0
  36. package/lib/components/sort-button/sort-button.js.map +1 -0
  37. package/lib/components/sort-button/sort-button.module.css +89 -0
  38. package/lib/components/total-size-type-title/total-size-type-title.js +1 -1
  39. package/lib/components/total-size-type-title/total-size-type-title.js.map +1 -1
  40. package/lib/constants.js +5 -1
  41. package/lib/constants.js.map +1 -1
  42. package/lib/hooks/rows-sort.js +13 -5
  43. package/lib/hooks/rows-sort.js.map +1 -1
  44. package/lib/ui/icon/icon.js +2 -0
  45. package/lib/ui/icon/icon.js.map +1 -1
  46. package/lib/ui/index.js +1 -3
  47. package/lib/ui/index.js.map +1 -1
  48. package/lib-esm/app/header/header.module.css +1 -0
  49. package/lib-esm/assets/icons.svg +17 -11
  50. package/lib-esm/assets/icons.svg.js +15 -11
  51. package/lib-esm/assets/icons.svg.js.map +1 -1
  52. package/lib-esm/components/bundle-assets/bundle-assets.js +3 -11
  53. package/lib-esm/components/bundle-assets/bundle-assets.js.map +1 -1
  54. package/lib-esm/components/bundle-assets/bundle-assets.utils.js +8 -21
  55. package/lib-esm/components/bundle-assets/bundle-assets.utils.js.map +1 -1
  56. package/lib-esm/components/bundle-assets/index.js +0 -2
  57. package/lib-esm/components/bundle-assets/index.js.map +1 -1
  58. package/lib-esm/components/bundle-modules/bundle-modules.js +2 -10
  59. package/lib-esm/components/bundle-modules/bundle-modules.js.map +1 -1
  60. package/lib-esm/components/bundle-modules/bundle-modules.utils.js +1 -14
  61. package/lib-esm/components/bundle-modules/bundle-modules.utils.js.map +1 -1
  62. package/lib-esm/components/bundle-modules/index.js +2 -4
  63. package/lib-esm/components/bundle-modules/index.js.map +1 -1
  64. package/lib-esm/components/bundle-packages/bundle-packages.js +2 -10
  65. package/lib-esm/components/bundle-packages/bundle-packages.js.map +1 -1
  66. package/lib-esm/components/bundle-packages/bundle-packages.utils.js +1 -14
  67. package/lib-esm/components/bundle-packages/bundle-packages.utils.js.map +1 -1
  68. package/lib-esm/components/bundle-packages/index.js +2 -4
  69. package/lib-esm/components/bundle-packages/index.js.map +1 -1
  70. package/lib-esm/components/jobs-header/jobs-header.js +2 -2
  71. package/lib-esm/components/jobs-header/jobs-header.js.map +1 -1
  72. package/lib-esm/components/metrics-table/metrics-table.js +47 -81
  73. package/lib-esm/components/metrics-table/metrics-table.js.map +1 -1
  74. package/lib-esm/components/metrics-table/metrics-table.module.css +18 -17
  75. package/lib-esm/components/metrics-table-search/metrics-table-search.js +1 -1
  76. package/lib-esm/components/metrics-table-search/metrics-table-search.js.map +1 -1
  77. package/lib-esm/components/metrics-table-title/metrics-table-title.js +2 -2
  78. package/lib-esm/components/metrics-table-title/metrics-table-title.js.map +1 -1
  79. package/lib-esm/components/metrics-table-title/metrics-table-title.module.css +3 -1
  80. package/lib-esm/components/sort-button/index.js +2 -0
  81. package/lib-esm/components/sort-button/index.js.map +1 -0
  82. package/lib-esm/components/sort-button/sort-button.js +43 -0
  83. package/lib-esm/components/sort-button/sort-button.js.map +1 -0
  84. package/lib-esm/components/sort-button/sort-button.module.css +89 -0
  85. package/lib-esm/components/total-size-type-title/total-size-type-title.js +1 -1
  86. package/lib-esm/components/total-size-type-title/total-size-type-title.js.map +1 -1
  87. package/lib-esm/constants.js +4 -0
  88. package/lib-esm/constants.js.map +1 -1
  89. package/lib-esm/hooks/rows-sort.js +11 -4
  90. package/lib-esm/hooks/rows-sort.js.map +1 -1
  91. package/lib-esm/ui/icon/icon.js +2 -0
  92. package/lib-esm/ui/icon/icon.js.map +1 -1
  93. package/lib-esm/ui/index.js +0 -1
  94. package/lib-esm/ui/index.js.map +1 -1
  95. package/package.json +5 -5
  96. package/src/app/header/header.module.css +1 -0
  97. package/src/assets/icons/chevron-down.svg +1 -0
  98. package/src/assets/icons/chevron-up.svg +1 -0
  99. package/src/assets/icons/github.svg +1 -1
  100. package/src/assets/icons.svg +17 -11
  101. package/src/assets/icons.svg.jsx +25 -11
  102. package/src/components/bundle-assets/bundle-assets.jsx +3 -10
  103. package/src/components/bundle-assets/bundle-assets.utils.js +8 -24
  104. package/src/components/bundle-assets/index.jsx +0 -2
  105. package/src/components/bundle-modules/bundle-modules.jsx +2 -14
  106. package/src/components/bundle-modules/bundle-modules.utils.js +1 -17
  107. package/src/components/bundle-modules/index.jsx +2 -4
  108. package/src/components/bundle-packages/bundle-packages.jsx +2 -9
  109. package/src/components/bundle-packages/bundle-packages.utils.js +1 -17
  110. package/src/components/bundle-packages/index.jsx +2 -4
  111. package/src/components/jobs-header/jobs-header.tsx +2 -2
  112. package/src/components/metrics-table/metrics-table.jsx +142 -132
  113. package/src/components/metrics-table/metrics-table.module.css +18 -17
  114. package/src/components/metrics-table-search/metrics-table-search.jsx +1 -1
  115. package/src/components/metrics-table-title/metrics-table-title.jsx +2 -2
  116. package/src/components/metrics-table-title/metrics-table-title.module.css +3 -1
  117. package/src/components/sort-button/index.ts +1 -0
  118. package/src/components/sort-button/sort-button.module.css +89 -0
  119. package/src/components/sort-button/sort-button.tsx +108 -0
  120. package/src/components/total-size-type-title/total-size-type-title.jsx +1 -1
  121. package/src/constants.js +5 -0
  122. package/src/hooks/rows-sort.ts +48 -0
  123. package/src/types.d.ts +4 -0
  124. package/src/ui/icon/icon.tsx +2 -0
  125. package/src/ui/index.js +0 -1
  126. package/types/components/bundle-assets/bundle-assets.d.ts +0 -1
  127. package/types/components/bundle-assets/bundle-assets.utils.d.ts +1 -1
  128. package/types/components/bundle-modules/bundle-modules.d.ts +1 -3
  129. package/types/components/bundle-modules/bundle-modules.utils.d.ts +1 -1
  130. package/types/components/bundle-packages/bundle-packages.d.ts +0 -1
  131. package/types/components/bundle-packages/bundle-packages.utils.d.ts +1 -1
  132. package/types/components/metrics-table/metrics-table.d.ts +3 -7
  133. package/types/components/sort-button/index.d.ts +1 -0
  134. package/types/components/sort-button/sort-button.d.ts +11 -0
  135. package/types/constants.d.ts +4 -0
  136. package/types/hooks/rows-sort.d.ts +14 -11
  137. package/types/ui/icon/icon.d.ts +4 -0
  138. package/types/ui/index.d.ts +0 -1
  139. package/lib/components/bundle-assets/bundle-assets.constants.js +0 -21
  140. package/lib/components/bundle-assets/bundle-assets.constants.js.map +0 -1
  141. package/lib/components/bundle-modules/bundle-modules.constants.js +0 -21
  142. package/lib/components/bundle-modules/bundle-modules.constants.js.map +0 -1
  143. package/lib/components/bundle-packages/bundle-packages.constants.js +0 -21
  144. package/lib/components/bundle-packages/bundle-packages.constants.js.map +0 -1
  145. package/lib/components/job-header/index.js.map +0 -1
  146. package/lib/components/job-header/job-header.js +0 -54
  147. package/lib/components/job-header/job-header.js.map +0 -1
  148. package/lib/components/job-header/job-header.module.css +0 -19
  149. package/lib/ui/sort-dropdown/index.js +0 -18
  150. package/lib/ui/sort-dropdown/index.js.map +0 -1
  151. package/lib/ui/sort-dropdown/sort-dropdown.js +0 -101
  152. package/lib/ui/sort-dropdown/sort-dropdown.js.map +0 -1
  153. package/lib/ui/sort-dropdown/sort-dropdown.module.css +0 -22
  154. package/lib-esm/components/bundle-assets/bundle-assets.constants.js +0 -18
  155. package/lib-esm/components/bundle-assets/bundle-assets.constants.js.map +0 -1
  156. package/lib-esm/components/bundle-modules/bundle-modules.constants.js +0 -18
  157. package/lib-esm/components/bundle-modules/bundle-modules.constants.js.map +0 -1
  158. package/lib-esm/components/bundle-packages/bundle-packages.constants.js +0 -18
  159. package/lib-esm/components/bundle-packages/bundle-packages.constants.js.map +0 -1
  160. package/lib-esm/components/job-header/index.js +0 -2
  161. package/lib-esm/components/job-header/index.js.map +0 -1
  162. package/lib-esm/components/job-header/job-header.js +0 -47
  163. package/lib-esm/components/job-header/job-header.js.map +0 -1
  164. package/lib-esm/components/job-header/job-header.module.css +0 -19
  165. package/lib-esm/ui/sort-dropdown/index.js +0 -2
  166. package/lib-esm/ui/sort-dropdown/index.js.map +0 -1
  167. package/lib-esm/ui/sort-dropdown/sort-dropdown.js +0 -71
  168. package/lib-esm/ui/sort-dropdown/sort-dropdown.js.map +0 -1
  169. package/lib-esm/ui/sort-dropdown/sort-dropdown.module.css +0 -22
  170. package/src/components/bundle-assets/bundle-assets.constants.js +0 -18
  171. package/src/components/bundle-modules/bundle-modules.constants.js +0 -18
  172. package/src/components/bundle-packages/bundle-packages.constants.js +0 -18
  173. package/src/components/job-header/index.js +0 -1
  174. package/src/components/job-header/job-header.jsx +0 -69
  175. package/src/components/job-header/job-header.module.css +0 -19
  176. package/src/hooks/rows-sort.js +0 -24
  177. package/src/ui/sort-dropdown/index.js +0 -1
  178. package/src/ui/sort-dropdown/sort-dropdown.jsx +0 -121
  179. package/src/ui/sort-dropdown/sort-dropdown.module.css +0 -22
  180. package/types/components/bundle-assets/bundle-assets.constants.d.ts +0 -21
  181. package/types/components/bundle-modules/bundle-modules.constants.d.ts +0 -21
  182. package/types/components/bundle-packages/bundle-packages.constants.d.ts +0 -21
  183. package/types/components/job-header/index.d.ts +0 -1
  184. package/types/components/job-header/job-header.d.ts +0 -26
  185. package/types/ui/sort-dropdown/index.d.ts +0 -1
  186. package/types/ui/sort-dropdown/sort-dropdown.d.ts +0 -24
@@ -1,110 +1,119 @@
1
- import React, { useMemo } from 'react';
1
+ import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
  import cx from 'classnames';
4
4
  import isEmpty from 'lodash/isEmpty';
5
5
  import sum from 'lodash/sum';
6
6
  import { METRIC_TYPE_FILE_SIZE, getGlobalMetricType, getMetricRunInfo } from '@bundle-stats/utils';
7
7
 
8
+ import { Icon } from '../../ui/icon';
8
9
  import { Table } from '../../ui/table';
10
+ import { Stack } from '../../layout/stack';
9
11
  import { Metric } from '../metric';
10
12
  import { Delta } from '../delta';
11
13
  import { JobName } from '../job-name';
14
+ import { SortButton } from '../sort-button';
12
15
  import styles from './metrics-table.module.css';
13
16
 
14
17
  const METRIC_TYPE_DATA = getGlobalMetricType(null, METRIC_TYPE_FILE_SIZE);
15
18
  const VISIBLE_COUNT = 500;
19
+ const BASELINE_COLUMN_SPAN = 1;
20
+ const CURRENT_COLUMN_SPAN = 3;
21
+ const BASELINE_TITLE = 'Baseline';
22
+ const CURRENT_TITLE = 'Current';
16
23
 
17
- const getRowsRunTotal = (rows, runIndex) => sum(rows.map((row) => row?.runs?.[runIndex]?.value || 0));
24
+ const getRowsRunTotal = (rows, runIndex) =>
25
+ sum(rows.map((row) => row?.runs?.[runIndex]?.value || 0));
18
26
 
19
- const getHeaderLabelCells = (rows) => (run, runIndex, runs) => {
20
- const isBaseline = runIndex === runs.length - 1;
21
- const className = cx(styles.value, isBaseline ? styles.baseline : styles.current);
27
+ const ColumnJob = ({ run, isBaseline }) => {
28
+ const colSpan = isBaseline ? BASELINE_COLUMN_SPAN : CURRENT_COLUMN_SPAN;
22
29
 
23
30
  if (!run) {
24
- return [
25
- { children: '-', className },
26
- ...(!isBaseline ? [{ children: ' ', className: styles.delta }] : []),
27
- ];
31
+ return <Table.Th colSpan={colSpan}>-</Table.Th>;
28
32
  }
29
33
 
30
34
  const { label, internalBuildNumber } = run;
31
35
 
32
- const jobName = (
33
- <JobName
34
- title={runIndex === 0 ? 'Current' : 'Baseline'}
35
- internalBuildNumber={internalBuildNumber}
36
- className={styles.jobName}
37
- >
38
- {label}
39
- </JobName>
36
+ return (
37
+ <Table.Th className={styles.job} colSpan={colSpan}>
38
+ <JobName
39
+ title={isBaseline ? BASELINE_TITLE : CURRENT_TITLE}
40
+ internalBuildNumber={internalBuildNumber}
41
+ className={styles.jobName}
42
+ >
43
+ {label}
44
+ </JobName>
45
+ </Table.Th>
40
46
  );
41
-
42
- return [
43
- // Value column
44
- { children: jobName, className },
45
- // Delta column
46
- ...(!isBaseline ? [{ children: ' ', className: cx(styles.delta) }] : []),
47
- ];
48
47
  };
49
48
 
50
- const getHeaderTotalCells = (rows) => (run, runIndex, runs) => {
51
- const isBaseline = runIndex === runs.length - 1;
52
- const className = cx(styles.value, isBaseline ? styles.baseline : styles.current);
53
-
49
+ const ColumnSum = ({ rows, isBaseline, runIndex, updateSort, sort }) => {
54
50
  const currentRunTotal = getRowsRunTotal(rows, runIndex);
55
51
  const baselineRunTotal = !isBaseline && getRowsRunTotal(rows, runIndex + 1);
56
52
  const infoTotal = getMetricRunInfo(METRIC_TYPE_DATA, currentRunTotal, baselineRunTotal);
53
+ const fieldPath = `runs[${runIndex}]`;
57
54
 
58
- return [
59
- // Value column
60
- {
61
- children: <Metric className={styles.tableHeaderRunMetric} value={infoTotal.displayValue} />,
62
- className,
63
- },
64
-
65
- // Delta column
66
- ...(!isBaseline
67
- ? [
68
- {
69
- children: (
55
+ return (
56
+ <>
57
+ <Table.Th className={cx(styles.value, styles.sum)}>
58
+ {(updateSort && sort) ? (
59
+ <SortButton
60
+ fieldPath={fieldPath}
61
+ fieldName="value"
62
+ label="absolute value"
63
+ updateSort={updateSort}
64
+ sort={sort}
65
+ >
66
+ <Metric value={infoTotal.displayValue} />
67
+ </SortButton>
68
+ ) : (
69
+ <Metric value={infoTotal.displayValue} />
70
+ )}
71
+ </Table.Th>
72
+ {!isBaseline && (
73
+ <>
74
+ <Table.Th className={cx(styles.delta, styles.sum)}>
75
+ {(updateSort && sort) ? (
76
+ <SortButton
77
+ fieldPath={fieldPath}
78
+ fieldName="delta"
79
+ label="absolute change"
80
+ updateSort={updateSort}
81
+ sort={sort}
82
+ >
83
+ <Delta displayValue={infoTotal.displayDelta} deltaType={infoTotal.deltaType} />
84
+ </SortButton>
85
+ ) : (
86
+ <Delta displayValue={infoTotal.displayDelta} deltaType={infoTotal.deltaType} />
87
+ )}
88
+ </Table.Th>
89
+ <Table.Th className={cx(styles.delta, styles.sum)}>
90
+ {(updateSort && sort) ? (
91
+ <SortButton
92
+ fieldPath={fieldPath}
93
+ fieldName="deltaPercentage"
94
+ label="absolute percentual change"
95
+ updateSort={updateSort}
96
+ sort={sort}
97
+ >
98
+ <Delta
99
+ displayValue={infoTotal.displayDeltaPercentage}
100
+ deltaType={infoTotal.deltaType}
101
+ />
102
+ </SortButton>
103
+ ) : (
70
104
  <Delta
71
105
  displayValue={infoTotal.displayDeltaPercentage}
72
106
  deltaType={infoTotal.deltaType}
73
107
  />
74
- ),
75
- className: styles.delta,
76
- },
77
- ]
78
- : []),
79
- ];
108
+ )}
109
+ </Table.Th>
110
+ </>
111
+ )}
112
+ </>
113
+ );
80
114
  };
81
115
 
82
- const getHeaderRows = (runs, items, showHeaderSum, title) => [
83
- {
84
- className: styles.headerRowColumns,
85
- cells: [
86
- // Metric name column - one empty strying to render the column
87
- {
88
- children: title || ' ',
89
- className: styles.metricName,
90
- rowSpan: showHeaderSum ? 2 : 1,
91
- },
92
-
93
- // Runs
94
- ...runs.map(getHeaderLabelCells(items)).flat(),
95
- ],
96
- },
97
- ...(showHeaderSum
98
- ? [
99
- {
100
- className: styles.headerRowTotals,
101
- cells: runs.map(getHeaderTotalCells(items)).flat(),
102
- },
103
- ]
104
- : []),
105
- ];
106
-
107
- const MetricsTableRow = ({ item, renderRowHeader }) => (
116
+ const Row = ({ item, renderRowHeader }) => (
108
117
  <Table.Tr className={cx(!item.changed && styles.unchanged)}>
109
118
  <Table.Th className={styles.metricName}>{renderRowHeader(item)}</Table.Th>
110
119
 
@@ -118,11 +127,13 @@ const MetricsTableRow = ({ item, renderRowHeader }) => (
118
127
  <>
119
128
  <Table.Td className={valueClassName}>-</Table.Td>
120
129
  {!isBaseline && <Table.Td className={styles.delta} />}
130
+ {!isBaseline && <Table.Td className={cx(styles.delta, styles.deltaPercentage)} />}
121
131
  </>
122
132
  );
123
133
  }
124
134
 
125
- const { displayValue, deltaPercentage, displayDeltaPercentage, deltaType } = run;
135
+ const { displayValue, deltaPercentage, displayDelta, displayDeltaPercentage, deltaType } =
136
+ run;
126
137
 
127
138
  return (
128
139
  <>
@@ -130,9 +141,14 @@ const MetricsTableRow = ({ item, renderRowHeader }) => (
130
141
  <Metric value={displayValue} />
131
142
  </Table.Td>
132
143
  {!isBaseline && typeof deltaPercentage === 'number' && (
133
- <Table.Td className={styles.delta}>
134
- <Delta displayValue={displayDeltaPercentage} deltaType={deltaType} />
135
- </Table.Td>
144
+ <>
145
+ <Table.Td className={styles.delta}>
146
+ <Delta displayValue={displayDelta} deltaType={deltaType} />
147
+ </Table.Td>
148
+ <Table.Td className={cx(styles.delta, styles.deltaPercentage)}>
149
+ <Delta displayValue={displayDeltaPercentage} deltaType={deltaType} />
150
+ </Table.Td>
151
+ </>
136
152
  )}
137
153
  </>
138
154
  );
@@ -140,7 +156,7 @@ const MetricsTableRow = ({ item, renderRowHeader }) => (
140
156
  </Table.Tr>
141
157
  );
142
158
 
143
- MetricsTableRow.propTypes = {
159
+ Row.propTypes = {
144
160
  item: PropTypes.shape({
145
161
  changed: PropTypes.bool,
146
162
  runs: PropTypes.arrayOf(
@@ -163,21 +179,14 @@ export const MetricsTable = ({
163
179
  items,
164
180
  emptyMessage,
165
181
  showHeaderSum,
166
- headerRows,
167
182
  title,
168
183
  showAllItems,
169
184
  setShowAllItems,
185
+ sort,
186
+ updateSort,
170
187
  ...restProps
171
188
  }) => {
172
- const { headers, columnClassNames } = useMemo(() => {
173
- const headerColumns = getHeaderRows(runs, items, showHeaderSum, title);
174
-
175
- return {
176
- headers: [...headerRows, ...headerColumns],
177
- // First header row has the column class names
178
- columnClassNames: headerColumns[0].cells.map((headerColumn) => headerColumn.className),
179
- };
180
- }, [headerRows, runs, items, showHeaderSum, title]);
189
+ const columnCount = (runs.length - 1) * CURRENT_COLUMN_SPAN + BASELINE_COLUMN_SPAN + 1;
181
190
 
182
191
  const rootClassName = cx(
183
192
  styles.root,
@@ -194,25 +203,38 @@ export const MetricsTable = ({
194
203
  return (
195
204
  <Table className={rootClassName} compact {...restProps}>
196
205
  <Table.THead>
197
- {headers.map((headerRow) => {
198
- const { cells, className: rowClassName } = headerRow.cells
199
- ? headerRow
200
- : { cells: headerRow };
201
-
202
- return (
203
- <Table.Tr className={rowClassName}>
204
- {cells.map((header) => (
205
- <Table.Th {...header} />
206
- ))}
207
- </Table.Tr>
208
- );
209
- })}
206
+ <Table.Tr className={styles.headerRow}>
207
+ <Table.Th className={styles.metricName} rowSpan={showHeaderSum ? 2 : 1}>
208
+ {title || ' '}
209
+ </Table.Th>
210
+ {runs.map((run, runIndex) => (
211
+ <ColumnJob run={run} isBaseline={runIndex === runs.length - 1} />
212
+ ))}
213
+ </Table.Tr>
214
+ {showHeaderSum && (
215
+ <Table.Tr className={styles.headerRow}>
216
+ {runs.map((run, runIndex) => (
217
+ <ColumnSum
218
+ rows={items}
219
+ isBaseline={runIndex === runs.length - 1}
220
+ runIndex={runIndex}
221
+ updateSort={updateSort}
222
+ sort={sort}
223
+ />
224
+ ))}
225
+ </Table.Tr>
226
+ )}
210
227
  </Table.THead>
211
228
  <Table.TBody>
212
229
  {showEmpty && (
213
230
  <Table.Tr>
214
- <Table.Td className={styles.empty} colSpan={columnClassNames?.length || 1}>
215
- {emptyMessage}
231
+ <Table.Td className={styles.empty} colSpan={columnCount}>
232
+ <Stack space="xxsmall">
233
+ <div>
234
+ <Icon glyph={Icon.ICONS.INFO} className={styles.emptyIcon} size="large" />
235
+ </div>
236
+ {emptyMessage}
237
+ </Stack>
216
238
  </Table.Td>
217
239
  </Table.Tr>
218
240
  )}
@@ -220,30 +242,29 @@ export const MetricsTable = ({
220
242
  {showItems && (
221
243
  <>
222
244
  {visibleItems.map((item) => (
223
- <MetricsTableRow key={item.key} item={item} renderRowHeader={renderRowHeader} />
245
+ <Row key={item.key} item={item} renderRowHeader={renderRowHeader} />
224
246
  ))}
225
247
 
226
248
  {hasHiddenItems && (
227
249
  <Table.Tr>
228
- <Table.Td className={styles.showAllItems} colSpan={columnClassNames?.length || 1}>
250
+ <Table.Td className={styles.showAllItems} colSpan={columnCount}>
229
251
  {showAllItems ? (
230
- <button
231
- onClick={() => setShowAllItems(false)}
232
- type="button"
233
- className={styles.showAllItemsButton}
234
- >
235
- Show less
236
- </button>
237
- ) : (
238
- <button
239
- onClick={() => setShowAllItems(true)}
240
- type="button"
241
- className={styles.showAllItemsButton}
242
- >
243
- Show all
244
- </button>
245
- )
246
- }
252
+ <button
253
+ onClick={() => setShowAllItems(false)}
254
+ type="button"
255
+ className={styles.showAllItemsButton}
256
+ >
257
+ Show less
258
+ </button>
259
+ ) : (
260
+ <button
261
+ onClick={() => setShowAllItems(true)}
262
+ type="button"
263
+ className={styles.showAllItemsButton}
264
+ >
265
+ Show all
266
+ </button>
267
+ )}
247
268
  </Table.Td>
248
269
  </Table.Tr>
249
270
  )}
@@ -259,7 +280,6 @@ MetricsTable.defaultProps = {
259
280
  renderRowHeader: (item) => item.label,
260
281
  emptyMessage: 'No entries found.',
261
282
  showHeaderSum: false,
262
- headerRows: [],
263
283
  title: '',
264
284
  };
265
285
 
@@ -285,15 +305,5 @@ MetricsTable.propTypes = {
285
305
  ).isRequired,
286
306
  emptyMessage: PropTypes.element,
287
307
  showHeaderSum: PropTypes.bool,
288
- headerRows: PropTypes.arrayOf(
289
- PropTypes.arrayOf(
290
- PropTypes.oneOfType([
291
- PropTypes.element,
292
- PropTypes.shape({
293
- children: PropTypes.node,
294
- }),
295
- ]),
296
- ),
297
- ),
298
308
  title: PropTypes.element,
299
309
  };
@@ -15,8 +15,9 @@
15
15
  width: 100%;
16
16
  }
17
17
 
18
- .tableHeaderRunMetric {
19
- text-transform: none;
18
+ .root .job {
19
+ padding-right: calc(var(--space-xxxsmall) + var(--space-small));
20
+ text-align: right;
20
21
  }
21
22
 
22
23
  .root .value {
@@ -26,18 +27,13 @@
26
27
  }
27
28
 
28
29
  .root .delta {
29
- padding-left: 0;
30
- text-align: left;
30
+ text-align: right;
31
31
  font-size: var(--size-xsmall);
32
32
  vertical-align: baseline;
33
33
  }
34
34
 
35
35
  .root tbody .delta {
36
- line-height: 1.6rem; /* baseline alignment with the value */
37
- }
38
-
39
- .root .value.current {
40
- padding-right: var(--space-xxsmall);
36
+ line-height: 1.6rem; /* baseline alignment with the column value */
41
37
  }
42
38
 
43
39
  .jobName {
@@ -45,17 +41,16 @@
45
41
  }
46
42
 
47
43
  /* columns overrides for showHeaderSum */
48
- .showHeaderSum .headerRowColumns .value,
49
- .showHeaderSum .headerRowColumns .delta {
44
+ .showHeaderSum .headerRow .job {
50
45
  border-bottom: 0;
51
46
  padding-bottom: 0;
52
47
  }
53
48
 
54
- .headerRowTotals th {
55
- padding-top: 0 !important;
56
- font-weight: normal;
57
- font-size: var(--size-xsmall);
49
+ .showHeaderSum .headerRow .sum {
50
+ padding-top: var(--space-xxxsmall);
51
+ font-size: var(--size-small);
58
52
  vertical-align: middle;
53
+ text-transform: none;
59
54
  }
60
55
 
61
56
  /** rows */
@@ -66,11 +61,17 @@
66
61
 
67
62
  .root .empty {
68
63
  background: none !important;
69
- padding-top: var(--space-xxxlarge);
70
- padding-bottom: var(--space-xxxlarge);
64
+ padding-top: calc(var(--space-xxxlarge) * 2);
65
+ padding-bottom: calc(var(--space-xxxlarge) * 2);
71
66
  text-align: center;
72
67
  }
73
68
 
69
+ .emptyIcon {
70
+ color: var(--color-outline-dark);
71
+ width: var(--space-large);
72
+ height: var(--space-large);
73
+ }
74
+
74
75
  .root .showAllItems {
75
76
  background: none !important;
76
77
  text-align: center;
@@ -52,7 +52,7 @@ export const MetricsTableSearch = (props) => {
52
52
  />
53
53
  {search && (
54
54
  <button className={css.cancelButton} type="button" onClick={handleClearValue}>
55
- <Icon className={css.cancelButtonIcon} glyph="cancel" />
55
+ <Icon className={css.cancelButtonIcon} glyph={Icon.ICONS.CANCEL} />
56
56
  </button>
57
57
  )}
58
58
  </div>
@@ -14,12 +14,12 @@ export const MetricsTableTitle = (props) => {
14
14
  const rootClassName = cx(css.root, className);
15
15
 
16
16
  return (
17
- <Stack className={rootClassName}>
17
+ <Stack space="xxsmall" className={rootClassName}>
18
18
  <FlexStack space="xxxsmall" alignItems="center" as="h3" className={css.title}>
19
19
  <span>{title}</span>
20
20
 
21
21
  {(popoverInfo || popoverHref) && (
22
- <HoverCard label={<Icon glyph="help" className={css.anchorIcon} />} anchorClassName={css.anchor}>
22
+ <HoverCard label={<Icon glyph={Icon.ICONS.HELP} className={css.anchorIcon} />} anchorClassName={css.anchor}>
23
23
  <Stack space="xxxsmall">
24
24
  {popoverInfo && <p>{popoverInfo}</p>}
25
25
  {popoverHref && (
@@ -18,8 +18,10 @@
18
18
  }
19
19
 
20
20
  .info {
21
+ color: var(--color-text-light);
22
+ font-family: var(--font-family-fixed);
21
23
  font-size: var(--size-xsmall);
22
- font-weight: normal;
24
+ font-weight: bold;
23
25
  }
24
26
 
25
27
  .readMoreLink {
@@ -0,0 +1 @@
1
+ export * from './sort-button';
@@ -0,0 +1,89 @@
1
+ .root {
2
+ --icon-dimension: 15px;
3
+ display: inline-block;
4
+ margin: calc(0px - var(--space-xxxsmall));
5
+ margin-right: calc(0px - 1px - var(--icon-dimension));
6
+ border-radius: var(--radius-small);
7
+ position: relative;
8
+ }
9
+
10
+ .button {
11
+ appearance: none;
12
+ cursor: pointer;
13
+ border: 0;
14
+ padding: 0;
15
+ margin: 0;
16
+ background: transparent;
17
+ transition: var(--transition-out);
18
+ }
19
+
20
+ .toggle {
21
+ padding: var(--space-xxxsmall);
22
+ padding-right: calc(1px + var(--icon-dimension));
23
+ }
24
+
25
+ .direction {
26
+ position: absolute;
27
+ padding: 2px;
28
+ display: block;
29
+ overflow: hidden;
30
+ right: -2px; /* compensate for the button padding */
31
+ color: var(--color-text-ultra-light);
32
+ transition: var(--transition-out);
33
+ }
34
+
35
+ .directionIcon {
36
+ display: block;
37
+ width: var(--icon-dimension);
38
+ height: var(--icon-dimension);
39
+ }
40
+
41
+ .directionActive {
42
+ color: var(--color-text);
43
+ transition: var(--transition-in);
44
+ }
45
+
46
+ .direction:hover,
47
+ .direction:active,
48
+ .direction:focus {
49
+ color: var(--color-text-dark);
50
+ transition: var(--transition-in);
51
+ }
52
+
53
+ .directionAsc {
54
+ padding-bottom: 0;
55
+ bottom: 50%;
56
+ }
57
+
58
+ .directionAsc .directionIcon {
59
+ transform: translateY(3px);
60
+ }
61
+
62
+ .directionDesc {
63
+ padding-top: 0;
64
+ top: 50%;
65
+ }
66
+
67
+ .directionDesc .directionIcon {
68
+ transform: translateY(-5px);
69
+ }
70
+
71
+ .root:hover,
72
+ .root:active,
73
+ .root:focus {
74
+ background: var(--color-outline);
75
+ }
76
+
77
+ .direction {
78
+ pointer-events: none;
79
+ opacity: 0;
80
+ }
81
+
82
+ .active .direction,
83
+ .root:hover .direction,
84
+ .root:active .direction,
85
+ .root:focus .direction {
86
+ pointer-events: auto;
87
+ opacity: 1;
88
+ transition: var(--transition-in);
89
+ }