@bundle-stats/ui 3.4.0-alpha.3 → 3.4.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 (48) hide show
  1. package/lib/app/app.js +3 -1
  2. package/lib/app/header/header.js +2 -1
  3. package/lib/components/budget-info/budget-info.js +11 -17
  4. package/lib/components/budget-info/budget-info.stories.js +27 -12
  5. package/lib/components/budget-insights/budget-insights.js +37 -75
  6. package/lib/components/budget-insights/budget-insights.module.css +10 -2
  7. package/lib/components/budget-insights/budget-insights.stories.js +124 -63
  8. package/lib/components/bundle-assets/bundle-assets.js +2 -1
  9. package/lib/components/bundle-assets-totals-table/bundle-assets-totals-table.js +3 -4
  10. package/lib/components/bundle-modules/bundle-modules.js +1 -1
  11. package/lib/components/summary/summary.js +6 -12
  12. package/lib/components/summary/summary.module.css +1 -45
  13. package/lib/components/summary/summary.stories.js +41 -13
  14. package/lib/components/summary-item/summary-item.js +14 -22
  15. package/lib/components/summary-item/summary-item.module.css +25 -7
  16. package/lib/components/summary-item/summary-item.stories.js +20 -6
  17. package/lib/ui/hover-card/hover-card.js +7 -1
  18. package/lib-esm/app/app.js +3 -1
  19. package/lib-esm/app/header/header.js +2 -1
  20. package/lib-esm/components/budget-info/budget-info.js +11 -12
  21. package/lib-esm/components/budget-info/budget-info.stories.js +27 -12
  22. package/lib-esm/components/budget-insights/budget-insights.js +35 -71
  23. package/lib-esm/components/budget-insights/budget-insights.module.css +10 -2
  24. package/lib-esm/components/budget-insights/budget-insights.stories.js +115 -55
  25. package/lib-esm/components/bundle-assets/bundle-assets.js +2 -1
  26. package/lib-esm/components/bundle-assets-totals-table/bundle-assets-totals-table.js +3 -4
  27. package/lib-esm/components/bundle-modules/bundle-modules.js +1 -1
  28. package/lib-esm/components/summary/summary.js +6 -11
  29. package/lib-esm/components/summary/summary.module.css +1 -45
  30. package/lib-esm/components/summary/summary.stories.js +41 -13
  31. package/lib-esm/components/summary-item/summary-item.js +11 -20
  32. package/lib-esm/components/summary-item/summary-item.module.css +25 -7
  33. package/lib-esm/components/summary-item/summary-item.stories.js +20 -6
  34. package/lib-esm/ui/hover-card/hover-card.js +7 -1
  35. package/package.json +25 -25
  36. package/src/app/app.jsx +2 -2
  37. package/src/app/header/header.jsx +1 -1
  38. package/src/components/budget-info/budget-info.jsx +12 -22
  39. package/src/components/budget-insights/budget-insights.jsx +49 -82
  40. package/src/components/budget-insights/budget-insights.module.css +10 -2
  41. package/src/components/bundle-assets/bundle-assets.jsx +1 -1
  42. package/src/components/bundle-assets-totals-table/bundle-assets-totals-table.jsx +3 -3
  43. package/src/components/bundle-modules/bundle-modules.jsx +1 -1
  44. package/src/components/summary/summary.jsx +13 -17
  45. package/src/components/summary/summary.module.css +1 -45
  46. package/src/components/summary-item/summary-item.jsx +11 -17
  47. package/src/components/summary-item/summary-item.module.css +25 -7
  48. package/src/ui/hover-card/hover-card.jsx +5 -0
@@ -17,8 +17,6 @@ var _utils = require("@bundle-stats/utils");
17
17
 
18
18
  var _constants = require("../../constants");
19
19
 
20
- var _icon = require("../../ui/icon");
21
-
22
20
  var _box = require("../../layout/box");
23
21
 
24
22
  var _flexStack = require("../../layout/flex-stack");
@@ -73,23 +71,19 @@ var Summary = function Summary(_ref) {
73
71
  metricId = _ref5[0],
74
72
  metricOptions = _ref5[1];
75
73
 
76
- return /*#__PURE__*/_react["default"].createElement("div", {
74
+ return /*#__PURE__*/_react["default"].createElement(_summaryItem.SummaryItem, _extends({
77
75
  key: metricId,
78
- className: _summaryModule["default"].item
79
- }, /*#__PURE__*/_react["default"].createElement(_summaryItem.SummaryItem, {
76
+ className: _summaryModule["default"].item,
77
+ as: SummaryItemCustomLink
78
+ }, metricOptions.link, {
80
79
  size: size,
81
80
  id: metricId,
82
81
  data: (0, _get2["default"])(data, metricId),
83
- budget: (0, _get2["default"])(budgets, getSourceMetricId(metricId)),
82
+ budget: (0, _get2["default"])(budgets, ['data', getSourceMetricId(metricId)]),
84
83
  loading: loading,
85
84
  showMetricDescription: true,
86
85
  showDelta: showSummaryItemDelta && metricOptions.showDelta !== false
87
- }), !loading && /*#__PURE__*/_react["default"].createElement(SummaryItemCustomLink, _extends({}, metricOptions.link, {
88
- className: _summaryModule["default"].readMore
89
- }), /*#__PURE__*/_react["default"].createElement(_icon.Icon, {
90
- className: _summaryModule["default"].readMoreIcon,
91
- glyph: _icon.Icon.ICONS.ARROW_RIGHT_CIRLCE
92
- })));
86
+ }));
93
87
  })));
94
88
  };
95
89
 
@@ -6,49 +6,5 @@
6
6
  .item {
7
7
  padding: var(--space-small);
8
8
  flex: 1 0 25%; /* force equal sizes */
9
- position: relative;
10
- z-index: 1;
11
- }
12
-
13
- .item::before {
14
- content: '';
15
- display: block;
16
- width: 1px;
17
- position: absolute;
18
- left: -1px;
19
- top: var(--space-small);
20
- bottom: var(--space-small);
21
- background: var(--color-outline);
22
- }
23
-
24
- .readMore {
25
- display: block;
26
- position: absolute;
27
- right: 0;
28
- bottom: 0;
29
- padding: var(--space-small);
30
- color: var(--color-text-ultra-light);
31
- transition: var(--transition-out);
32
- }
33
-
34
- .readMore:hover,
35
- .readMore:focus {
36
- color: var(--color-primary);
37
- transition: var(--transition-in);
38
- }
39
-
40
- .readMoreIcon {
41
- display: block;
42
- }
43
-
44
- /** hover state */
45
- .readMore {
46
- opacity: 0;
47
- }
48
-
49
- .item:hover .readMore,
50
- .item:active .readMore,
51
- .item:focus .readMore {
52
- opacity: 1;
53
- transition: var(--transition-in);
9
+ text-decoration: none;
54
10
  }
@@ -45,26 +45,54 @@ stories.add('budgets', function () {
45
45
  return /*#__PURE__*/_react["default"].createElement(_.Summary, {
46
46
  data: MULTIPLE_JOBS[0].summary,
47
47
  budgets: {
48
- webpack: {
48
+ data: {
49
49
  totalSizeByTypeALL: {
50
- currentValue: MULTIPLE_JOBS[0].summary.webpack.totalSizeByTypeALL.current,
51
- budgetValue: 1024 * 1024,
52
- failed: false
50
+ type: 'ERROR',
51
+ message: {
52
+ text: 'Metric is over the budget',
53
+ md: 'Metric is over the budget'
54
+ },
55
+ data: {
56
+ currentValue: MULTIPLE_JOBS[0].summary.webpack.totalSizeByTypeALL.current,
57
+ budgetValue: 1024 * 1024,
58
+ failed: false
59
+ }
53
60
  },
54
61
  totalInitialSizeJS: {
55
- currentValue: MULTIPLE_JOBS[0].summary.webpack.totalInitialSizeJS.current,
56
- budgetValue: 512 * 1024,
57
- failed: true
62
+ type: 'WARNING',
63
+ message: {
64
+ text: 'Metric is over the budget',
65
+ md: 'Metric is over the budget'
66
+ },
67
+ data: {
68
+ currentValue: MULTIPLE_JOBS[0].summary.webpack.totalInitialSizeJS.current,
69
+ budgetValue: 512 * 1024,
70
+ failed: true
71
+ }
58
72
  },
59
73
  totalInitialSizeCSS: {
60
- currentValue: MULTIPLE_JOBS[0].summary.webpack.totalInitialSizeCSS.current,
61
- budgetValue: 50 * 1024,
62
- failed: false
74
+ type: 'SUCCESS',
75
+ message: {
76
+ text: 'Metric is under the budget',
77
+ md: 'Metric is under the budget'
78
+ },
79
+ data: {
80
+ currentValue: MULTIPLE_JOBS[0].summary.webpack.totalInitialSizeCSS.current,
81
+ budgetValue: 50 * 1024,
82
+ failed: false
83
+ }
63
84
  },
64
85
  chunkCount: {
65
- currentValue: MULTIPLE_JOBS[0].summary.webpack.chunkCount.current,
66
- budgetValue: 50,
67
- failed: false
86
+ type: 'SUCCESS',
87
+ message: {
88
+ text: 'Metric is under the budget',
89
+ md: 'Metric is under the budget'
90
+ },
91
+ data: {
92
+ currentValue: MULTIPLE_JOBS[0].summary.webpack.chunkCount.current,
93
+ budgetValue: 50,
94
+ failed: false
95
+ }
68
96
  }
69
97
  }
70
98
  }
@@ -15,14 +15,12 @@ var _utils = require("@bundle-stats/utils");
15
15
 
16
16
  var _hoverCard = require("../../ui/hover-card");
17
17
 
18
- var _icon = require("../../ui/icon");
19
-
20
18
  var _skeleton = require("../../ui/skeleton");
21
19
 
22
- var _stack = require("../../layout/stack");
23
-
24
20
  var _flexStack = require("../../layout/flex-stack");
25
21
 
22
+ var _stack = require("../../layout/stack");
23
+
26
24
  var _metric = require("../metric");
27
25
 
28
26
  var _delta = require("../delta");
@@ -46,8 +44,11 @@ var MetricInfo = function MetricInfo(_ref) {
46
44
  url = _ref.url;
47
45
  return /*#__PURE__*/_react["default"].createElement(_stack.Stack, {
48
46
  space: "xxxsmall"
49
- }, /*#__PURE__*/_react["default"].createElement("p", null, description), url && /*#__PURE__*/_react["default"].createElement("p", null, /*#__PURE__*/_react["default"].createElement("a", {
50
- href: url,
47
+ }, /*#__PURE__*/_react["default"].createElement("p", null, description), url && /*#__PURE__*/_react["default"].createElement("p", null, /*#__PURE__*/_react["default"].createElement("button", {
48
+ type: "button",
49
+ onClick: function onClick() {
50
+ return window.open(url);
51
+ },
51
52
  className: _summaryItemModule["default"].readMoreLink
52
53
  }, "Read more")));
53
54
  };
@@ -84,23 +85,17 @@ var SummaryItem = function SummaryItem(_ref2) {
84
85
  var showMetricDescriptionTooltip = showMetricDescription && (metric === null || metric === void 0 ? void 0 : metric.description);
85
86
  var rootClassName = (0, _classnames["default"])(_summaryItemModule["default"].root, className, _summaryItemModule["default"][size], showDelta && _summaryItemModule["default"].showDelta);
86
87
  return /*#__PURE__*/_react["default"].createElement(_stack.Stack, _extends({
87
- space: "xxxsmall",
88
+ space: "xxsmall",
88
89
  as: Component,
89
90
  className: rootClassName
90
91
  }, props), /*#__PURE__*/_react["default"].createElement(_flexStack.FlexStack, {
91
- as: "h3",
92
92
  space: "xxxsmall",
93
+ as: "h3",
93
94
  className: _summaryItemModule["default"].title
94
- }, /*#__PURE__*/_react["default"].createElement("span", {
95
- className: _summaryItemModule["default"].titleLabel
96
- }, metric.label), showMetricDescriptionTooltip && /*#__PURE__*/_react["default"].createElement(_hoverCard.HoverCard, {
97
- className: _summaryItemModule["default"].icon,
98
- label: /*#__PURE__*/_react["default"].createElement(_icon.Icon, {
99
- glyph: "help"
100
- })
101
- }, /*#__PURE__*/_react["default"].createElement(MetricInfo, metric)), budget && /*#__PURE__*/_react["default"].createElement(_budgetInfo.BudgetInfo, {
95
+ }, showMetricDescriptionTooltip ? /*#__PURE__*/_react["default"].createElement(_hoverCard.HoverCard, {
96
+ label: metric.label
97
+ }, /*#__PURE__*/_react["default"].createElement(MetricInfo, metric)) : metric.label, budget && /*#__PURE__*/_react["default"].createElement(_budgetInfo.BudgetInfo, {
102
98
  className: _summaryItemModule["default"].budgetInfo,
103
- metricId: id,
104
99
  budgetInsight: budget
105
100
  })), !loading ? /*#__PURE__*/_react["default"].createElement(_stack.Stack, null, /*#__PURE__*/_react["default"].createElement(_metric.Metric, {
106
101
  className: _summaryItemModule["default"].currentMetric,
@@ -161,9 +156,6 @@ SummaryItem.propTypes = {
161
156
  showDelta: _propTypes["default"].bool,
162
157
 
163
158
  /** Budget insight data */
164
- budget: _propTypes["default"].shape({
165
- currentBalue: _propTypes["default"].number,
166
- budgetValue: _propTypes["default"].number,
167
- failed: _propTypes["default"].bool
168
- })
159
+ budget: _propTypes["default"].object // eslint-disable-line react/forbid-prop-types
160
+
169
161
  };
@@ -8,17 +8,11 @@
8
8
  color: var(--color-text-ultra-light);
9
9
  font-weight: bold;
10
10
  font-size: var(--size-xsmall);
11
- line-height: var(--space-small);
11
+ line-height: 1;
12
12
  text-transform: uppercase;
13
13
  white-space: nowrap;
14
14
  }
15
15
 
16
- .budgetInfo {
17
- position: absolute;
18
- right: 0;
19
- top: 0;
20
- }
21
-
22
16
  .currentMetric {
23
17
  display: block;
24
18
  color: var(--color-heading);
@@ -39,6 +33,30 @@
39
33
  line-height: var(--space-small);
40
34
  }
41
35
 
36
+ .readMoreLink {
37
+ appearance: none;
38
+ background: none;
39
+ margin: 0;
40
+ border: 0;
41
+ padding: 0;
42
+ color: var(--color-primary);
43
+ text-decoration: underline;
44
+ cursor: pointer;
45
+ }
46
+
47
+ .readMoreLink:hover,
48
+ .readMoreLink:active,
49
+ .readMoreLink:focus {
50
+ color: var(--color-primary-dark);
51
+ text-decoration: none;
52
+ }
53
+
54
+ /* Hover state */
55
+ .root:hover .title {
56
+ color: var(--color-text-light);
57
+ }
58
+
59
+
42
60
  /* Loading state */
43
61
  .loading.currentMetric {
44
62
  width: 8em;
@@ -58,9 +58,16 @@ exports.BudgetError = BudgetError;
58
58
  BudgetError.args = {
59
59
  showMetricDescription: true,
60
60
  budget: {
61
- currentValue: 120 * 1000,
62
- budgetValue: 100 * 1000,
63
- failed: true
61
+ type: 'ERROR',
62
+ message: {
63
+ text: 'Metric is over the budget',
64
+ md: 'Metric is over the budget'
65
+ },
66
+ data: {
67
+ currentValue: 120 * 1000,
68
+ budgetValue: 100 * 1000,
69
+ failed: true
70
+ }
64
71
  }
65
72
  };
66
73
  var BudgetSuccess = Template.bind();
@@ -68,9 +75,16 @@ exports.BudgetSuccess = BudgetSuccess;
68
75
  BudgetSuccess.args = {
69
76
  showMetricDescription: true,
70
77
  budget: {
71
- currentValue: 120 * 1000,
72
- budgetValue: 120 * 1024,
73
- failed: false
78
+ type: 'SUCCESS',
79
+ message: {
80
+ text: 'Metric is under the budget',
81
+ md: 'Metric is under the budget'
82
+ },
83
+ data: {
84
+ currentValue: 120 * 1000,
85
+ budgetValue: 120 * 1024,
86
+ failed: false
87
+ }
74
88
  }
75
89
  };
76
90
  var Loading = Template.bind();
@@ -53,6 +53,11 @@ var HoverCard = function HoverCard(props) {
53
53
  }); // Fallback to span if no href
54
54
 
55
55
  var Component = resolveComponent(as, href);
56
+
57
+ var handleOnClick = function handleOnClick(event) {
58
+ event.preventDefault();
59
+ };
60
+
56
61
  return /*#__PURE__*/_react["default"].createElement("div", {
57
62
  className: (0, _classnames["default"])(_hoverCardModule["default"].root, className)
58
63
  }, /*#__PURE__*/_react["default"].createElement(_hovercard.HovercardAnchor, {
@@ -65,7 +70,8 @@ var HoverCard = function HoverCard(props) {
65
70
  className: (0, _classnames["default"])(_hoverCardModule["default"].hoverCard, hoverCardClassName),
66
71
  style: {
67
72
  zIndex: 10000
68
- }
73
+ },
74
+ onClick: handleOnClick
69
75
  }), /*#__PURE__*/_react["default"].createElement(_hovercard.HovercardArrow, {
70
76
  size: 24
71
77
  }), typeof children === 'function' ? children({
@@ -54,6 +54,7 @@ const Layout = _ref => {
54
54
 
55
55
  Layout.propTypes = {
56
56
  jobs: PropTypes.arrayOf(PropTypes.object),
57
+ // eslint-disable-line react/forbid-prop-types
57
58
  version: PropTypes.string
58
59
  };
59
60
  Layout.defaultProps = {
@@ -78,7 +79,8 @@ const JobsProvider = _ref2 => {
78
79
  };
79
80
 
80
81
  JobsProvider.propTypes = {
81
- jobs: PropTypes.arrayOf(PropTypes.object).isRequired
82
+ jobs: PropTypes.arrayOf(PropTypes.object).isRequired // eslint-disable-line react/forbid-prop-types
83
+
82
84
  };
83
85
 
84
86
  const OverviewContent = () => {
@@ -21,7 +21,8 @@ export const Header = _ref => {
21
21
  };
22
22
  Header.propTypes = {
23
23
  className: PropTypes.string,
24
- jobs: PropTypes.arrayOf(PropTypes.object)
24
+ jobs: PropTypes.arrayOf(PropTypes.object) // eslint-disable-line react/forbid-prop-types
25
+
25
26
  };
26
27
  Header.defaultProps = {
27
28
  className: '',
@@ -2,7 +2,6 @@ import React from 'react';
2
2
  import cx from 'classnames';
3
3
  import PropTypes from 'prop-types';
4
4
  import { InsightType } from '@bundle-stats/utils';
5
- import * as budgetsInsightsTransformer from '@bundle-stats/utils/lib-esm/transformers/budgets-insights';
6
5
  import { Icon } from '../../ui/icon';
7
6
  import { Tooltip } from '../../ui/tooltip';
8
7
  import css from './budget-info.module.css';
@@ -23,21 +22,16 @@ const INSIGHT_TYPE_MAP = {
23
22
  export const BudgetInfo = _ref => {
24
23
  let {
25
24
  className = '',
26
- metricId,
27
25
  budgetInsight
28
26
  } = _ref;
29
- const budgetInsightInfo = budgetsInsightsTransformer.getInfo(metricId, budgetInsight);
30
27
  const {
31
28
  className: insightTypeClassName,
32
29
  glyph
33
- } = INSIGHT_TYPE_MAP[budgetInsightInfo.type];
30
+ } = INSIGHT_TYPE_MAP[budgetInsight.type];
34
31
  const rootClassName = cx(css.root, insightTypeClassName, className);
35
- const {
36
- data: messageData
37
- } = budgetInsightInfo.message;
38
32
  return /*#__PURE__*/React.createElement(Tooltip, {
39
33
  className: rootClassName,
40
- title: /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("strong", null, messageData.metricLabel), ` value (`, /*#__PURE__*/React.createElement("strong", null, messageData.currentValue), `) is ${messageData.diffLabel} `, /*#__PURE__*/React.createElement("strong", null, messageData.budgetValue), ` budget `)
34
+ title: budgetInsight.message.text
41
35
  }, /*#__PURE__*/React.createElement(Icon, {
42
36
  className: css.icon,
43
37
  glyph: glyph,
@@ -45,11 +39,16 @@ export const BudgetInfo = _ref => {
45
39
  }));
46
40
  };
47
41
  BudgetInfo.propTypes = {
48
- metricId: PropTypes.string.isRequired,
49
42
  budgetInsight: PropTypes.shape({
50
- currentValue: PropTypes.number,
51
- budgetValue: PropTypes.number,
52
- failed: PropTypes.bool
43
+ type: PropTypes.string,
44
+ message: PropTypes.shape({
45
+ text: PropTypes.string
46
+ }),
47
+ data: PropTypes.shape({
48
+ currentValue: PropTypes.number,
49
+ budgetValue: PropTypes.number,
50
+ failed: PropTypes.bool
51
+ })
53
52
  }).isRequired,
54
53
  className: PropTypes.string
55
54
  };
@@ -5,26 +5,41 @@ import { BudgetInfo } from '.';
5
5
  const stories = storiesOf('Components/BudgetInfo', module);
6
6
  stories.addDecorator(getWrapperDecorator());
7
7
  stories.add('default', () => /*#__PURE__*/React.createElement(BudgetInfo, {
8
- metricId: "webpack.assetCount",
9
8
  budgetInsight: {
10
- budgetValue: 300,
11
- currentValue: 250,
12
- failed: false
9
+ type: 'SUCCESS',
10
+ message: {
11
+ text: 'Metric is under the budget'
12
+ },
13
+ data: {
14
+ budgetValue: 300,
15
+ currentValue: 250,
16
+ failed: false
17
+ }
13
18
  }
14
19
  }));
15
20
  stories.add('error', () => /*#__PURE__*/React.createElement(BudgetInfo, {
16
- metricId: "webpack.assetCount",
17
21
  budgetInsight: {
18
- budgetValue: 300,
19
- currentValue: 350,
20
- failed: true
22
+ type: 'ERROR',
23
+ message: {
24
+ text: 'Metric is over the budget'
25
+ },
26
+ data: {
27
+ budgetValue: 300,
28
+ currentValue: 250,
29
+ failed: false
30
+ }
21
31
  }
22
32
  }));
23
33
  stories.add('warning', () => /*#__PURE__*/React.createElement(BudgetInfo, {
24
- metricId: "webpack.assetCount",
25
34
  budgetInsight: {
26
- budgetValue: 300,
27
- currentValue: 300,
28
- failed: false
35
+ type: 'WARNING',
36
+ message: {
37
+ text: 'Metric is equal the budget'
38
+ },
39
+ data: {
40
+ budgetValue: 300,
41
+ currentValue: 250,
42
+ failed: false
43
+ }
29
44
  }
30
45
  }));
@@ -4,7 +4,6 @@ import React, { useMemo, useState } from 'react';
4
4
  import PropTypes from 'prop-types';
5
5
  import cx from 'classnames';
6
6
  import { METRIC_COMPONENT_LINKS } from '@bundle-stats/utils';
7
- import * as budgetsInsightsTransformer from '@bundle-stats/utils/lib-esm/transformers/budgets-insights';
8
7
  import { Box } from '../../layout/box';
9
8
  import { Stack } from '../../layout/stack';
10
9
  import { FlexStack } from '../../layout/flex-stack';
@@ -17,47 +16,60 @@ const Budget = props => {
17
16
  const {
18
17
  className,
19
18
  metricId,
20
- budgetInsight,
19
+ budget,
21
20
  CustomLink
22
21
  } = props;
23
22
  const componentLinkOptions = METRIC_COMPONENT_LINKS.get(metricId);
24
- const budgetInsightInfo = budgetsInsightsTransformer.getInfo(metricId, budgetInsight);
25
- const {
26
- data: messageData
27
- } = budgetInsightInfo.message;
28
23
  return /*#__PURE__*/React.createElement(CustomLink, _extends({
29
- className: cx(css.budget, className)
30
- }, componentLinkOptions == null ? void 0 : componentLinkOptions.link), /*#__PURE__*/React.createElement("strong", null, messageData.metricLabel), ` value (`, /*#__PURE__*/React.createElement("strong", null, messageData.currentValue), `) is ${messageData.diffLabel} `, /*#__PURE__*/React.createElement("strong", null, messageData.budgetValue), ` budget `);
24
+ className: cx(css.budget, className, budget.type === 'SUCCESS' && css.budgetSuccess)
25
+ }, componentLinkOptions == null ? void 0 : componentLinkOptions.link), budget.message.text);
31
26
  };
32
27
 
33
28
  Budget.propTypes = {
34
29
  className: PropTypes.string,
35
30
  metricId: PropTypes.string.isRequired,
36
- budgetInsight: PropTypes.shape({
37
- currentValue: PropTypes.number.isRequired,
38
- budgetValue: PropTypes.number.isRequired,
39
- failed: PropTypes.bool.isRequired
31
+ budget: PropTypes.shape({
32
+ type: PropTypes.string,
33
+ message: PropTypes.shape({
34
+ text: PropTypes.string
35
+ }),
36
+ data: PropTypes.shape({
37
+ currentValue: PropTypes.number.isRequired,
38
+ budgetValue: PropTypes.number.isRequired,
39
+ failed: PropTypes.bool.isRequired
40
+ })
40
41
  }).isRequired,
41
42
  CustomLink: PropTypes.elementType.isRequired
42
43
  };
43
44
  Budget.defaultProps = {
44
45
  className: ''
45
46
  };
46
-
47
- const BudgetsGroup = props => {
47
+ const BUDGET_ALERT_KIND = new Map([['ERROR', 'danger'], ['WARNING', 'warning'], ['SUCCESS', 'success']]);
48
+ const BUDGET_ICON = new Map([['ERROR', Icon.ICONS.ALERT_CIRCLE], ['WARNING', Icon.ICONS.WARNING], ['SUCCESS', Icon.ICONS.CHECK_CIRCLE]]);
49
+ export const BudgetInsights = props => {
48
50
  const {
49
51
  className,
50
- kind,
51
52
  source,
52
53
  budgets,
53
54
  CustomLink
54
55
  } = props;
55
56
  const [showBudgets, setShowBudgets] = useState(false);
56
- const isFailed = kind === 'danger';
57
+ const iconGlyph = BUDGET_ICON.get(budgets.type);
58
+ const alertKind = BUDGET_ALERT_KIND.get(budgets.type);
59
+ const rootClassName = cx(css.group, className, css[`group-${alertKind}`]);
60
+ const budgetItems = useMemo(() => {
61
+ const items = Object.entries(budgets.data); // When there are errors/warnings, sort budget items first
62
+
63
+ if (['ERROR', 'WARNING'].includes(budgets.type)) {
64
+ items.sort(a => a[1].type === budgets.type ? -1 : 1);
65
+ }
66
+
67
+ return items;
68
+ }, [budgets]);
57
69
  return /*#__PURE__*/React.createElement(Alert, {
58
- kind: kind,
70
+ kind: alertKind,
59
71
  padding: "none",
60
- className: cx(css.group, css[kind], className)
72
+ className: rootClassName
61
73
  }, /*#__PURE__*/React.createElement(Box, {
62
74
  padding: ['xsmall', 'small'],
63
75
  className: css.groupHeader,
@@ -67,74 +79,26 @@ const BudgetsGroup = props => {
67
79
  }, /*#__PURE__*/React.createElement(FlexStack, {
68
80
  space: "xxsmall",
69
81
  className: css.groupTitle
70
- }, /*#__PURE__*/React.createElement(Icon, {
82
+ }, iconGlyph && /*#__PURE__*/React.createElement(Icon, {
71
83
  className: css.groupIcon,
72
- glyph: isFailed ? Icon.ICONS.ALERT_CIRCLE : Icon.ICONS.CHECK_CIRCLE
73
- }), /*#__PURE__*/React.createElement("span", null, /*#__PURE__*/React.createElement("strong", null, budgets.length), ` budget ${budgets.length > 1 ? 'checks' : 'check'} ${isFailed ? 'failed' : 'passed'}`), /*#__PURE__*/React.createElement("span", {
84
+ glyph: iconGlyph
85
+ }), /*#__PURE__*/React.createElement("span", null, budgets.message.text), /*#__PURE__*/React.createElement("span", {
74
86
  className: css.groupTitleToggle
75
87
  }, showBudgets ? 'hide' : 'show', " all"))), showBudgets && /*#__PURE__*/React.createElement(Box, {
76
88
  padding: ['xsmall', 'small'],
77
89
  className: css.groupContent
78
90
  }, /*#__PURE__*/React.createElement(Stack, {
79
91
  space: "none"
80
- }, budgets.map(_ref => {
92
+ }, budgetItems.map(_ref => {
81
93
  let [key, budget] = _ref;
82
94
  return /*#__PURE__*/React.createElement(Budget, {
83
95
  key: key,
84
96
  metricId: `${source}.${key}`,
85
- budgetInsight: budget,
97
+ budget: budget,
86
98
  CustomLink: CustomLink
87
99
  });
88
100
  }))));
89
101
  };
90
-
91
- BudgetsGroup.propTypes = {
92
- className: PropTypes.string,
93
- kind: PropTypes.oneOf(['success', 'danger']).isRequired,
94
- source: PropTypes.string.isRequired,
95
- budgets: PropTypes.object.isRequired,
96
- // eslint-disable-line react/forbid-prop-types
97
- CustomLink: PropTypes.elementType.isRequired
98
- };
99
- BudgetsGroup.defaultProps = {
100
- className: ''
101
- };
102
- export const BudgetInsights = props => {
103
- const {
104
- className,
105
- source,
106
- budgets,
107
- CustomLink
108
- } = props;
109
- const [failedBudgets, passedBudgets] = useMemo(() => {
110
- const passed = [];
111
- const failed = [];
112
- Object.entries(budgets).forEach(_ref2 => {
113
- let [key, budget] = _ref2;
114
-
115
- if (budget.failed) {
116
- failed.push([key, budget]);
117
- } else {
118
- passed.push([key, budget]);
119
- }
120
- });
121
- return [failed, passed];
122
- }, [budgets]);
123
- return /*#__PURE__*/React.createElement(Stack, {
124
- className: className,
125
- space: "xsmall"
126
- }, failedBudgets.length > 0 && /*#__PURE__*/React.createElement(BudgetsGroup, {
127
- kind: "danger",
128
- source: source,
129
- budgets: failedBudgets,
130
- CustomLink: CustomLink
131
- }), passedBudgets.length > 0 && /*#__PURE__*/React.createElement(BudgetsGroup, {
132
- kind: "success",
133
- source: source,
134
- budgets: passedBudgets,
135
- CustomLink: CustomLink
136
- }));
137
- };
138
102
  BudgetInsights.propTypes = {
139
103
  className: PropTypes.string,
140
104
  source: PropTypes.string.isRequired,
@@ -20,11 +20,15 @@
20
20
  margin: 0 0 0 auto !important;
21
21
  }
22
22
 
23
- .danger .groupIcon {
23
+ .group-danger .groupIcon {
24
24
  color: var(--color-danger);
25
25
  }
26
26
 
27
- .success .groupIcon {
27
+ .group-warning .groupIcon {
28
+ color: var(--color-warning);
29
+ }
30
+
31
+ .group-success .groupIcon {
28
32
  color: var(--color-success);
29
33
  }
30
34
 
@@ -39,6 +43,10 @@
39
43
  text-decoration: none;
40
44
  }
41
45
 
46
+ .budgetSuccess {
47
+ color: var(--color-text-light);
48
+ }
49
+
42
50
  .budgetLabel,
43
51
  .budgetValue {
44
52
  color: var(--color-text-dark);