@bundle-stats/ui 3.4.0-alpha.5 → 4.0.0-alpha.7

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 (143) hide show
  1. package/lib/app/app.js +6 -21
  2. package/lib/app/app.stories.js +1 -22
  3. package/lib/assets/icons.svg +0 -8
  4. package/lib/components/asset-info/asset-info.js +1 -1
  5. package/lib/components/bundle-assets/bundle-assets.js +1 -1
  6. package/lib/components/bundle-assets/index.js +1 -1
  7. package/lib/components/bundle-assets-totals-chart-bars/bundle-assets-totals-chart-bars.js +1 -1
  8. package/lib/components/bundle-assets-totals-table/bundle-assets-totals-table.js +8 -44
  9. package/lib/components/bundle-assets-totals-table/bundle-assets-totals-table.module.css +2 -2
  10. package/lib/components/bundle-assets-totals-table/bundle-assets-totals-table.stories.js +1 -20
  11. package/lib/components/bundle-modules/bundle-modules.js +1 -1
  12. package/lib/components/bundle-modules/index.js +1 -1
  13. package/lib/components/bundle-packages/bundle-packages.js +1 -1
  14. package/lib/components/bundle-packages/index.js +1 -1
  15. package/lib/components/component-link.js +1 -1
  16. package/lib/components/index.js +0 -8
  17. package/lib/components/job-meta/job-meta.js +1 -1
  18. package/lib/components/job-name/job-name.js +1 -1
  19. package/lib/components/metrics-table/metrics-table.js +1 -1
  20. package/lib/components/metrics-table-options/metrics-table-options.js +1 -1
  21. package/lib/components/module-info/module-info.js +1 -1
  22. package/lib/components/summary/summary.js +13 -24
  23. package/lib/components/summary/summary.module.css +1 -45
  24. package/lib/components/summary/summary.stories.js +1 -30
  25. package/lib/components/summary-item/summary-item.js +14 -37
  26. package/lib/components/summary-item/summary-item.module.css +25 -13
  27. package/lib/components/summary-item/summary-item.stories.js +53 -51
  28. package/lib/constants.js +4 -4
  29. package/lib/layout/box/box.js +1 -1
  30. package/lib/layout/flex-stack/flex-stack.js +1 -1
  31. package/lib/layout/footer/footer.js +1 -1
  32. package/lib/layout/separator.js +1 -1
  33. package/lib/layout/stack/stack.js +1 -1
  34. package/lib/query-state.js +1 -1
  35. package/lib/ui/alert/alert.js +3 -13
  36. package/lib/ui/container/container.js +1 -1
  37. package/lib/ui/filters/filters.container.js +3 -3
  38. package/lib/ui/filters/filters.js +1 -1
  39. package/lib/ui/horizontal-bar-chart/horizontal-bar-chart.js +2 -2
  40. package/lib/ui/hover-card/hover-card.js +8 -2
  41. package/lib/ui/hover-card/hover-card.stories.js +1 -1
  42. package/lib/ui/icon/icon.js +1 -3
  43. package/lib/ui/input/input.js +1 -1
  44. package/lib/ui/loader/loader.js +1 -1
  45. package/lib/ui/logo/logo.js +1 -1
  46. package/lib/ui/panels/panels.js +1 -1
  47. package/lib/ui/skeleton/skeleton.js +1 -1
  48. package/lib/ui/sort-dropdown/sort-dropdown.js +1 -1
  49. package/lib/ui/tag/tag.js +1 -1
  50. package/lib/ui/tooltip/tooltip.js +1 -1
  51. package/lib-esm/app/app.js +6 -20
  52. package/lib-esm/app/app.stories.js +1 -22
  53. package/lib-esm/assets/icons.svg +0 -8
  54. package/lib-esm/components/asset-info/asset-info.js +1 -1
  55. package/lib-esm/components/bundle-assets/bundle-assets.js +1 -1
  56. package/lib-esm/components/bundle-assets/bundle-assets.utils.js +1 -0
  57. package/lib-esm/components/bundle-assets/index.js +1 -1
  58. package/lib-esm/components/bundle-assets-totals-chart-bars/bundle-assets-totals-chart-bars.js +1 -1
  59. package/lib-esm/components/bundle-assets-totals-table/bundle-assets-totals-table.js +8 -25
  60. package/lib-esm/components/bundle-assets-totals-table/bundle-assets-totals-table.module.css +2 -2
  61. package/lib-esm/components/bundle-assets-totals-table/bundle-assets-totals-table.stories.js +0 -18
  62. package/lib-esm/components/bundle-modules/bundle-modules.js +1 -1
  63. package/lib-esm/components/bundle-modules/index.js +1 -1
  64. package/lib-esm/components/bundle-packages/bundle-packages.js +1 -1
  65. package/lib-esm/components/bundle-packages/bundle-packages.utils.js +1 -0
  66. package/lib-esm/components/bundle-packages/index.js +1 -1
  67. package/lib-esm/components/component-link.js +1 -1
  68. package/lib-esm/components/index.js +0 -1
  69. package/lib-esm/components/job-meta/job-meta.js +1 -1
  70. package/lib-esm/components/job-name/job-name.js +1 -1
  71. package/lib-esm/components/metrics-table/metrics-table.js +1 -1
  72. package/lib-esm/components/metrics-table-options/metrics-table-options.js +1 -1
  73. package/lib-esm/components/module-info/module-info.js +1 -1
  74. package/lib-esm/components/summary/summary.js +14 -22
  75. package/lib-esm/components/summary/summary.module.css +1 -45
  76. package/lib-esm/components/summary/summary.stories.js +1 -28
  77. package/lib-esm/components/summary-item/summary-item.js +11 -33
  78. package/lib-esm/components/summary-item/summary-item.module.css +25 -13
  79. package/lib-esm/components/summary-item/summary-item.stories.js +38 -50
  80. package/lib-esm/constants.js +4 -4
  81. package/lib-esm/layout/box/box.js +1 -1
  82. package/lib-esm/layout/flex-stack/flex-stack.js +1 -1
  83. package/lib-esm/layout/footer/footer.js +1 -1
  84. package/lib-esm/layout/separator.js +1 -1
  85. package/lib-esm/layout/stack/stack.js +1 -1
  86. package/lib-esm/query-state.js +1 -1
  87. package/lib-esm/ui/alert/alert.js +3 -6
  88. package/lib-esm/ui/container/container.js +1 -1
  89. package/lib-esm/ui/filters/filters.container.js +1 -1
  90. package/lib-esm/ui/filters/filters.js +2 -1
  91. package/lib-esm/ui/hover-card/hover-card.js +8 -2
  92. package/lib-esm/ui/hover-card/hover-card.stories.js +1 -1
  93. package/lib-esm/ui/icon/icon.js +1 -3
  94. package/lib-esm/ui/input/input.js +1 -1
  95. package/lib-esm/ui/loader/loader.js +1 -1
  96. package/lib-esm/ui/logo/logo.js +1 -1
  97. package/lib-esm/ui/panels/panels.js +1 -1
  98. package/lib-esm/ui/skeleton/skeleton.js +1 -1
  99. package/lib-esm/ui/sort-dropdown/sort-dropdown.js +1 -1
  100. package/lib-esm/ui/tag/tag.js +1 -1
  101. package/lib-esm/ui/tooltip/tooltip.js +1 -1
  102. package/package.json +26 -26
  103. package/src/app/app.jsx +5 -12
  104. package/src/assets/icons.svg +0 -8
  105. package/src/components/bundle-assets-totals-table/bundle-assets-totals-table.jsx +13 -27
  106. package/src/components/bundle-assets-totals-table/bundle-assets-totals-table.module.css +2 -2
  107. package/src/components/index.js +0 -1
  108. package/src/components/summary/summary.jsx +19 -24
  109. package/src/components/summary/summary.module.css +1 -45
  110. package/src/components/summary-item/summary-item.jsx +10 -23
  111. package/src/components/summary-item/summary-item.module.css +25 -13
  112. package/src/constants.js +11 -7
  113. package/src/ui/alert/alert.jsx +2 -7
  114. package/src/ui/hover-card/hover-card.jsx +5 -0
  115. package/src/ui/icon/icon.jsx +0 -2
  116. package/lib/assets/icons/alert-circle.svg +0 -1
  117. package/lib/assets/icons/check-circle.svg +0 -1
  118. package/lib/components/budget-info/budget-info.js +0 -80
  119. package/lib/components/budget-info/budget-info.module.css +0 -40
  120. package/lib/components/budget-info/budget-info.stories.js +0 -44
  121. package/lib/components/budget-info/index.js +0 -18
  122. package/lib/components/budget-insights/budget-insights.js +0 -200
  123. package/lib/components/budget-insights/budget-insights.module.css +0 -53
  124. package/lib/components/budget-insights/budget-insights.stories.js +0 -104
  125. package/lib/components/budget-insights/index.js +0 -18
  126. package/lib-esm/assets/icons/alert-circle.svg +0 -1
  127. package/lib-esm/assets/icons/check-circle.svg +0 -1
  128. package/lib-esm/components/budget-info/budget-info.js +0 -58
  129. package/lib-esm/components/budget-info/budget-info.module.css +0 -40
  130. package/lib-esm/components/budget-info/budget-info.stories.js +0 -30
  131. package/lib-esm/components/budget-info/index.js +0 -1
  132. package/lib-esm/components/budget-insights/budget-insights.js +0 -148
  133. package/lib-esm/components/budget-insights/budget-insights.module.css +0 -53
  134. package/lib-esm/components/budget-insights/budget-insights.stories.js +0 -84
  135. package/lib-esm/components/budget-insights/index.js +0 -1
  136. package/src/assets/icons/alert-circle.svg +0 -1
  137. package/src/assets/icons/check-circle.svg +0 -1
  138. package/src/components/budget-info/budget-info.jsx +0 -65
  139. package/src/components/budget-info/budget-info.module.css +0 -40
  140. package/src/components/budget-info/index.js +0 -1
  141. package/src/components/budget-insights/budget-insights.jsx +0 -157
  142. package/src/components/budget-insights/budget-insights.module.css +0 -53
  143. package/src/components/budget-insights/index.js +0 -1
@@ -1,148 +0,0 @@
1
- function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
2
-
3
- import React, { useMemo, useState } from 'react';
4
- import PropTypes from 'prop-types';
5
- import cx from 'classnames';
6
- import { METRIC_COMPONENT_LINKS } from '@bundle-stats/utils';
7
- import * as budgetsInsightsTransformer from '@bundle-stats/utils/lib-esm/transformers/budgets-insights';
8
- import { Box } from '../../layout/box';
9
- import { Stack } from '../../layout/stack';
10
- import { FlexStack } from '../../layout/flex-stack';
11
- import { Alert } from '../../ui/alert';
12
- import { Icon } from '../../ui/icon';
13
- import { ComponentLink } from '../component-link';
14
- import css from './budget-insights.module.css';
15
-
16
- const Budget = props => {
17
- const {
18
- className,
19
- metricId,
20
- budgetInsight,
21
- CustomLink
22
- } = props;
23
- const componentLinkOptions = METRIC_COMPONENT_LINKS.get(metricId);
24
- const budgetInsightInfo = budgetsInsightsTransformer.getInfo(metricId, budgetInsight);
25
- const {
26
- data: messageData
27
- } = budgetInsightInfo.message;
28
- 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 `);
31
- };
32
-
33
- Budget.propTypes = {
34
- className: PropTypes.string,
35
- metricId: PropTypes.string.isRequired,
36
- budgetInsight: PropTypes.shape({
37
- currentValue: PropTypes.number.isRequired,
38
- budgetValue: PropTypes.number.isRequired,
39
- failed: PropTypes.bool.isRequired
40
- }).isRequired,
41
- CustomLink: PropTypes.elementType.isRequired
42
- };
43
- Budget.defaultProps = {
44
- className: ''
45
- };
46
-
47
- const BudgetsGroup = props => {
48
- const {
49
- className,
50
- kind,
51
- source,
52
- budgets,
53
- CustomLink
54
- } = props;
55
- const [showBudgets, setShowBudgets] = useState(false);
56
- const isFailed = kind === 'danger';
57
- return /*#__PURE__*/React.createElement(Alert, {
58
- kind: kind,
59
- padding: "none",
60
- className: cx(css.group, css[kind], className)
61
- }, /*#__PURE__*/React.createElement(Box, {
62
- padding: ['xsmall', 'small'],
63
- className: css.groupHeader,
64
- as: "button",
65
- type: "button",
66
- onClick: () => setShowBudgets(!showBudgets)
67
- }, /*#__PURE__*/React.createElement(FlexStack, {
68
- space: "xxsmall",
69
- className: css.groupTitle
70
- }, /*#__PURE__*/React.createElement(Icon, {
71
- 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", {
74
- className: css.groupTitleToggle
75
- }, showBudgets ? 'hide' : 'show', " all"))), showBudgets && /*#__PURE__*/React.createElement(Box, {
76
- padding: ['xsmall', 'small'],
77
- className: css.groupContent
78
- }, /*#__PURE__*/React.createElement(Stack, {
79
- space: "none"
80
- }, budgets.map(_ref => {
81
- let [key, budget] = _ref;
82
- return /*#__PURE__*/React.createElement(Budget, {
83
- key: key,
84
- metricId: `${source}.${key}`,
85
- budgetInsight: budget,
86
- CustomLink: CustomLink
87
- });
88
- }))));
89
- };
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
- BudgetInsights.propTypes = {
139
- className: PropTypes.string,
140
- source: PropTypes.string.isRequired,
141
- budgets: PropTypes.object.isRequired,
142
- // eslint-disable-line react/forbid-prop-types
143
- CustomLink: PropTypes.elementType
144
- };
145
- BudgetInsights.defaultProps = {
146
- className: '',
147
- CustomLink: ComponentLink
148
- };
@@ -1,53 +0,0 @@
1
- .groupHeader {
2
- width: 100%;
3
- border: none;
4
- background: none;
5
- cursor: pointer;
6
- color: inherit;
7
- }
8
-
9
- .groupTitle {
10
- width: 100%;
11
- align-items: center;
12
- }
13
-
14
- .groupTitle:hover {
15
- color: var(--color-text-dark);
16
- text-decoration: underline;
17
- }
18
-
19
- .groupTitleToggle {
20
- margin: 0 0 0 auto !important;
21
- }
22
-
23
- .danger .groupIcon {
24
- color: var(--color-danger);
25
- }
26
-
27
- .success .groupIcon {
28
- color: var(--color-success);
29
- }
30
-
31
- .groupContent {
32
- padding-top: 0px;
33
- background: transparent;
34
- }
35
-
36
- .budget {
37
- display: block;
38
- color: var(--color-text);
39
- text-decoration: none;
40
- }
41
-
42
- .budgetLabel,
43
- .budgetValue {
44
- color: var(--color-text-dark);
45
- font-weight: 500;
46
- }
47
-
48
- .budget:hover,
49
- .budget:focus,
50
- .budget:active {
51
- color: var(--color-text);
52
- text-decoration: underline;
53
- }
@@ -1,84 +0,0 @@
1
- import React from 'react';
2
- import { MemoryRouter } from 'react-router-dom';
3
- import { BudgetInsights } from '.';
4
- export default {
5
- title: 'Components/BudgetInsights',
6
- component: BudgetInsights,
7
- decorators: [Story => /*#__PURE__*/React.createElement(MemoryRouter, null, /*#__PURE__*/React.createElement(Story, null))]
8
- };
9
-
10
- const Template = args => /*#__PURE__*/React.createElement(BudgetInsights, args);
11
-
12
- export const Default = Template.bind();
13
- Default.args = {
14
- source: 'webpack',
15
- budgets: {
16
- totalSizeByTypeALL: {
17
- currentValue: 2097917,
18
- budgetValue: 2097152,
19
- failed: true
20
- },
21
- totalInitialSizeJS: {
22
- currentValue: 1265645,
23
- budgetValue: 524288,
24
- failed: true
25
- },
26
- totalInitialSizeCSS: {
27
- currentValue: 48866,
28
- budgetValue: 51200,
29
- failed: false
30
- },
31
- chunkCount: {
32
- currentValue: 12,
33
- budgetValue: 50,
34
- failed: false
35
- },
36
- moduleCount: {
37
- currentValue: 1059,
38
- budgetValue: 2000,
39
- failed: false
40
- },
41
- duplicatePackagesCount: {
42
- currentValue: 13,
43
- budgetValue: 5,
44
- failed: true
45
- },
46
- 'sizes.totalSizeByTypeJS': {
47
- currentValue: 1981470,
48
- budgetValue: 2097152,
49
- failed: false
50
- },
51
- 'sizes.totalSizeByTypeCSS': {
52
- currentValue: 56091,
53
- budgetValue: 20480,
54
- failed: true
55
- }
56
- }
57
- };
58
- export const FailedBudgets = Template.bind();
59
- FailedBudgets.args = {
60
- source: 'webpack',
61
- budgets: {
62
- totalSizeByTypeALL: {
63
- currentValue: 2097917,
64
- budgetValue: 2097152,
65
- failed: true
66
- },
67
- totalInitialSizeJS: {
68
- currentValue: 1265645,
69
- budgetValue: 524288,
70
- failed: true
71
- }
72
- }
73
- };
74
- export const SingleBudget = Template.bind();
75
- SingleBudget.args = {
76
- source: 'webpack',
77
- budgets: {
78
- totalInitialSizeJS: {
79
- currentValue: 524288,
80
- budgetValue: 1265645,
81
- failed: false
82
- }
83
- }
84
- };
@@ -1 +0,0 @@
1
- export * from './budget-insights';
@@ -1 +0,0 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-alert-circle"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="8" x2="12" y2="12"></line><line x1="12" y1="16" x2="12.01" y2="16"></line></svg>
@@ -1 +0,0 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-check-circle"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"></path><polyline points="22 4 12 14.01 9 11.01"></polyline></svg>
@@ -1,65 +0,0 @@
1
- import React from 'react';
2
- import cx from 'classnames';
3
- import PropTypes from 'prop-types';
4
- import { InsightType } from '@bundle-stats/utils';
5
- import * as budgetsInsightsTransformer from '@bundle-stats/utils/lib-esm/transformers/budgets-insights';
6
-
7
- import { Icon } from '../../ui/icon';
8
- import { Tooltip } from '../../ui/tooltip';
9
-
10
- import css from './budget-info.module.css';
11
-
12
- const INSIGHT_TYPE_MAP = {
13
- [InsightType.SUCCESS]: {
14
- className: css.success,
15
- glyph: Icon.ICONS.CHECK_CIRCLE,
16
- },
17
- [InsightType.ERROR]: {
18
- className: css.error,
19
- glyph: Icon.ICONS.ALERT_CIRCLE,
20
- },
21
- [InsightType.WARNING]: {
22
- className: css.warning,
23
- glyph: Icon.ICONS.WARNING,
24
- },
25
- };
26
-
27
- export const BudgetInfo = ({ className = '', metricId, budgetInsight }) => {
28
- const budgetInsightInfo = budgetsInsightsTransformer.getInfo(metricId, budgetInsight);
29
- const { className: insightTypeClassName, glyph } = INSIGHT_TYPE_MAP[budgetInsightInfo.type];
30
-
31
- const rootClassName = cx(css.root, insightTypeClassName, className);
32
- const { data: messageData } = budgetInsightInfo.message;
33
-
34
- return (
35
- <Tooltip
36
- className={rootClassName}
37
- title={
38
- <>
39
- <strong>{messageData.metricLabel}</strong>
40
- {` value (`}
41
- <strong>{messageData.currentValue}</strong>
42
- {`) is ${messageData.diffLabel} `}
43
- <strong>{messageData.budgetValue}</strong>
44
- {` budget `}
45
- </>
46
- }
47
- >
48
- <Icon className={css.icon} glyph={glyph} size="medium" />
49
- </Tooltip>
50
- );
51
- };
52
-
53
- BudgetInfo.propTypes = {
54
- metricId: PropTypes.string.isRequired,
55
- budgetInsight: PropTypes.shape({
56
- currentValue: PropTypes.number,
57
- budgetValue: PropTypes.number,
58
- failed: PropTypes.bool,
59
- }).isRequired,
60
- className: PropTypes.string,
61
- };
62
-
63
- BudgetInfo.defaultProps = {
64
- className: '',
65
- };
@@ -1,40 +0,0 @@
1
- .root {
2
- display: inline-block;
3
- line-height: 1em;
4
- }
5
-
6
- /* Budget error */
7
- .error .icon {
8
- color: var(--color-danger);
9
- }
10
-
11
- .error .icon:hover,
12
- .error .icon:focus,
13
- .error .icon:active
14
- {
15
- color: var(--color-danger-light);
16
- }
17
-
18
- /* Budget success */
19
- .success .icon {
20
- color: var(--color-success);
21
- }
22
-
23
- .success .icon:hover,
24
- .success .icon:focus,
25
- .success .icon:active
26
- {
27
- color: var(--color-success-light);
28
- }
29
-
30
- /* Budget warning */
31
- .warning .icon {
32
- color: var(--color-warning-dark);
33
- }
34
-
35
- .warning .icon:hover,
36
- .warning .icon:focus,
37
- .warning .icon:active
38
- {
39
- color: var(--color-warning);
40
- }
@@ -1 +0,0 @@
1
- export * from './budget-info';
@@ -1,157 +0,0 @@
1
- import React, { useMemo, useState } from 'react';
2
- import PropTypes from 'prop-types';
3
- import cx from 'classnames';
4
- import { METRIC_COMPONENT_LINKS } from '@bundle-stats/utils';
5
- import * as budgetsInsightsTransformer from '@bundle-stats/utils/lib-esm/transformers/budgets-insights';
6
-
7
- import { Box } from '../../layout/box';
8
- import { Stack } from '../../layout/stack';
9
- import { FlexStack } from '../../layout/flex-stack';
10
- import { Alert } from '../../ui/alert';
11
- import { Icon } from '../../ui/icon';
12
- import { ComponentLink } from '../component-link';
13
- import css from './budget-insights.module.css';
14
-
15
- const Budget = (props) => {
16
- const { className, metricId, budgetInsight, CustomLink } = props;
17
- const componentLinkOptions = METRIC_COMPONENT_LINKS.get(metricId);
18
- const budgetInsightInfo = budgetsInsightsTransformer.getInfo(metricId, budgetInsight);
19
- const { data: messageData } = budgetInsightInfo.message;
20
-
21
- return (
22
- <CustomLink className={cx(css.budget, className)} {...componentLinkOptions?.link}>
23
- <strong>{messageData.metricLabel}</strong>
24
- {` value (`}
25
- <strong>{messageData.currentValue}</strong>
26
- {`) is ${messageData.diffLabel} `}
27
- <strong>{messageData.budgetValue}</strong>
28
- {` budget `}
29
- </CustomLink>
30
- );
31
- };
32
-
33
- Budget.propTypes = {
34
- className: PropTypes.string,
35
- metricId: PropTypes.string.isRequired,
36
- budgetInsight: PropTypes.shape({
37
- currentValue: PropTypes.number.isRequired,
38
- budgetValue: PropTypes.number.isRequired,
39
- failed: PropTypes.bool.isRequired,
40
- }).isRequired,
41
- CustomLink: PropTypes.elementType.isRequired,
42
- };
43
-
44
- Budget.defaultProps = {
45
- className: '',
46
- };
47
-
48
- const BudgetsGroup = (props) => {
49
- const { className, kind, source, budgets, CustomLink } = props;
50
- const [showBudgets, setShowBudgets] = useState(false);
51
-
52
- const isFailed = kind === 'danger';
53
-
54
- return (
55
- <Alert kind={kind} padding="none" className={cx(css.group, css[kind], className)}>
56
- <Box
57
- padding={['xsmall', 'small']}
58
- className={css.groupHeader}
59
- as="button"
60
- type="button"
61
- onClick={() => setShowBudgets(!showBudgets)}
62
- >
63
- <FlexStack space="xxsmall" className={css.groupTitle}>
64
- <Icon
65
- className={css.groupIcon}
66
- glyph={isFailed ? Icon.ICONS.ALERT_CIRCLE : Icon.ICONS.CHECK_CIRCLE}
67
- />
68
- <span>
69
- <strong>{budgets.length}</strong>
70
- {` budget ${budgets.length > 1 ? 'checks' : 'check'} ${isFailed ? 'failed' : 'passed'}`}
71
- </span>
72
- <span className={css.groupTitleToggle}>{showBudgets ? 'hide' : 'show'} all</span>
73
- </FlexStack>
74
- </Box>
75
-
76
- {showBudgets && (
77
- <Box padding={['xsmall', 'small']} className={css.groupContent}>
78
- <Stack space="none">
79
- {budgets.map(([key, budget]) => (
80
- <Budget
81
- key={key}
82
- metricId={`${source}.${key}`}
83
- budgetInsight={budget}
84
- CustomLink={CustomLink}
85
- />
86
- ))}
87
- </Stack>
88
- </Box>
89
- )}
90
- </Alert>
91
- );
92
- };
93
-
94
- BudgetsGroup.propTypes = {
95
- className: PropTypes.string,
96
- kind: PropTypes.oneOf(['success', 'danger']).isRequired,
97
- source: PropTypes.string.isRequired,
98
- budgets: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
99
- CustomLink: PropTypes.elementType.isRequired,
100
- };
101
-
102
- BudgetsGroup.defaultProps = {
103
- className: '',
104
- };
105
-
106
- export const BudgetInsights = (props) => {
107
- const { className, source, budgets, CustomLink } = props;
108
-
109
- const [failedBudgets, passedBudgets] = useMemo(() => {
110
- const passed = [];
111
- const failed = [];
112
-
113
- Object.entries(budgets).forEach(([key, budget]) => {
114
- if (budget.failed) {
115
- failed.push([key, budget]);
116
- } else {
117
- passed.push([key, budget]);
118
- }
119
- });
120
-
121
- return [failed, passed];
122
- }, [budgets]);
123
-
124
- return (
125
- <Stack className={className} space="xsmall">
126
- {failedBudgets.length > 0 && (
127
- <BudgetsGroup
128
- kind="danger"
129
- source={source}
130
- budgets={failedBudgets}
131
- CustomLink={CustomLink}
132
- />
133
- )}
134
-
135
- {passedBudgets.length > 0 && (
136
- <BudgetsGroup
137
- kind="success"
138
- source={source}
139
- budgets={passedBudgets}
140
- CustomLink={CustomLink}
141
- />
142
- )}
143
- </Stack>
144
- );
145
- };
146
-
147
- BudgetInsights.propTypes = {
148
- className: PropTypes.string,
149
- source: PropTypes.string.isRequired,
150
- budgets: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
151
- CustomLink: PropTypes.elementType,
152
- };
153
-
154
- BudgetInsights.defaultProps = {
155
- className: '',
156
- CustomLink: ComponentLink,
157
- };
@@ -1,53 +0,0 @@
1
- .groupHeader {
2
- width: 100%;
3
- border: none;
4
- background: none;
5
- cursor: pointer;
6
- color: inherit;
7
- }
8
-
9
- .groupTitle {
10
- width: 100%;
11
- align-items: center;
12
- }
13
-
14
- .groupTitle:hover {
15
- color: var(--color-text-dark);
16
- text-decoration: underline;
17
- }
18
-
19
- .groupTitleToggle {
20
- margin: 0 0 0 auto !important;
21
- }
22
-
23
- .danger .groupIcon {
24
- color: var(--color-danger);
25
- }
26
-
27
- .success .groupIcon {
28
- color: var(--color-success);
29
- }
30
-
31
- .groupContent {
32
- padding-top: 0px;
33
- background: transparent;
34
- }
35
-
36
- .budget {
37
- display: block;
38
- color: var(--color-text);
39
- text-decoration: none;
40
- }
41
-
42
- .budgetLabel,
43
- .budgetValue {
44
- color: var(--color-text-dark);
45
- font-weight: 500;
46
- }
47
-
48
- .budget:hover,
49
- .budget:focus,
50
- .budget:active {
51
- color: var(--color-text);
52
- text-decoration: underline;
53
- }
@@ -1 +0,0 @@
1
- export * from './budget-insights';