From c979301e12669e2148e947def83b5309acf6b755 Mon Sep 17 00:00:00 2001 From: CD Cabrera Date: Tue, 14 Mar 2023 14:53:45 -0400 Subject: [PATCH] feat(config): sw-922 product custom card metrics (#1077) * config, rhacs, rhods, rhosak, card metrics to display * helpers, setImmutableData * graphCard, move isMetricDisplay check to totals comp * graphCardHelpers, set, or determine, isMetricDisplay * graphCardMetricTotals, passthrough, call card callbacks * pageColumns, adjust children isRequired --- jest.config.js | 2 +- src/common/README.md | 19 ++ .../__snapshots__/helpers.test.js.snap | 3 + src/common/helpers.js | 9 + src/components/README.md | 2 +- .../__snapshots__/graphCard.test.js.snap | 25 +- .../graphCardContext.test.js.snap | 8 + .../graphCardHelpers.test.js.snap | 4 + .../graphCardMetricTotals.test.js.snap | 223 +++++++----------- .../graphCard/__tests__/graphCard.test.js | 7 + .../__tests__/graphCardMetricTotals.test.js | 57 ++++- src/components/graphCard/graphCard.js | 22 +- src/components/graphCard/graphCardHelpers.js | 18 +- .../graphCard/graphCardMetricTotals.js | 184 ++++++--------- .../__tests__/__snapshots__/i18n.test.js.snap | 101 +++++--- src/components/pageLayout/pageColumns.js | 5 +- .../product.openshiftContainer.test.js.snap | 16 ++ .../product.openshiftDedicated.test.js.snap | 15 ++ .../product.openshiftMetrics.test.js.snap | 14 ++ .../__snapshots__/product.rhacs.test.js.snap | 43 +++- .../__snapshots__/product.rhel.test.js.snap | 11 + .../__snapshots__/product.rhods.test.js.snap | 43 +++- .../__snapshots__/product.rhosak.test.js.snap | 93 +++++++- .../product.satellite.test.js.snap | 11 + .../product.openshiftContainer.test.js | 4 +- .../product.openshiftDedicated.test.js | 4 +- .../product.openshiftMetrics.test.js | 4 +- src/config/__tests__/product.rhacs.test.js | 36 ++- src/config/__tests__/product.rhel.test.js | 4 +- src/config/__tests__/product.rhods.test.js | 36 ++- src/config/__tests__/product.rhosak.test.js | 36 ++- .../__tests__/product.satellite.test.js | 4 +- src/config/product.rhacs.js | 58 ++++- src/config/product.rhods.js | 58 ++++- src/config/product.rhosak.js | 58 ++++- 35 files changed, 917 insertions(+), 320 deletions(-) diff --git a/jest.config.js b/jest.config.js index e83162c62..75ddcb9e5 100644 --- a/jest.config.js +++ b/jest.config.js @@ -6,7 +6,7 @@ module.exports = { '!src/app.js', '!src/bootstrap.js', '!src/entry.js', - '!src/index.js', + '!src/index*.js', '!src/components/**/index.js', '!src/common/index.js', '!src/redux/index.js', diff --git a/src/common/README.md b/src/common/README.md index 54a13cfbf..b5672f088 100644 --- a/src/common/README.md +++ b/src/common/README.md @@ -171,6 +171,7 @@ Download the debug log file. * [General](#Helpers.module_General) * [~noop](#Helpers.module_General..noop) * [~noopPromise](#Helpers.module_General..noopPromise) : Promise.<{}> + * [~setImmutableData](#Helpers.module_General..setImmutableData) ⇒ \* * [~DEV_MODE](#Helpers.module_General..DEV_MODE) : boolean * [~PROD_MODE](#Helpers.module_General..PROD_MODE) : boolean * [~REVIEW_MODE](#Helpers.module_General..REVIEW_MODE) : boolean @@ -222,6 +223,24 @@ An empty promise. Typically used as a default prop, or during testing. **Kind**: inner constant of [General](#Helpers.module_General) + + +### General~setImmutableData ⇒ \* +Quick set data as "immutable-like". Used to pass object and array data through configuration callbacks. + +**Kind**: inner constant of [General](#Helpers.module_General) + + + + + + + + + + +
ParamType
data*
+ ### General~DEV\_MODE : boolean diff --git a/src/common/__tests__/__snapshots__/helpers.test.js.snap b/src/common/__tests__/__snapshots__/helpers.test.js.snap index b2eed4e88..f00659381 100644 --- a/src/common/__tests__/__snapshots__/helpers.test.js.snap +++ b/src/common/__tests__/__snapshots__/helpers.test.js.snap @@ -47,6 +47,7 @@ exports[`Helpers should expose a window object: limited window object 1`] = ` "noopPromise": Promise {}, "numberDisplay": [Function], "objFreeze": [Function], + "setImmutableData": [Function], } `; @@ -91,6 +92,7 @@ exports[`Helpers should expose a window object: window object 1`] = ` "noopPromise": Promise {}, "numberDisplay": [Function], "objFreeze": [Function], + "setImmutableData": [Function], } `; @@ -146,6 +148,7 @@ exports[`Helpers should have specific functions: helpers 1`] = ` "noopPromise": Promise {}, "numberDisplay": [Function], "objFreeze": [Function], + "setImmutableData": [Function], } `; diff --git a/src/common/helpers.js b/src/common/helpers.js index e8280c382..509b81304 100644 --- a/src/common/helpers.js +++ b/src/common/helpers.js @@ -176,6 +176,14 @@ const objFreeze = obj => { return obj; }; +/** + * Quick set data as "immutable-like". Used to pass object and array data through configuration callbacks. + * + * @param {*} data + * @returns {*} + */ +const setImmutableData = memo(data => objFreeze(data)); + /** * Is dev mode active. * Associated with using the NPM script "start". See dotenv config files for activation. @@ -413,6 +421,7 @@ const helpers = { noopPromise, numberDisplay, objFreeze, + setImmutableData, DEV_MODE, PROD_MODE, REVIEW_MODE, diff --git a/src/components/README.md b/src/components/README.md index 29e644f89..fe87b71a2 100644 --- a/src/components/README.md +++ b/src/components/README.md @@ -2602,7 +2602,7 @@ Display totals for a single metric. props.childrenReact.ReactNode - props.tfunction + props.useGraphCardContextfunction props.useMetricsSelectorfunction diff --git a/src/components/graphCard/__tests__/__snapshots__/graphCard.test.js.snap b/src/components/graphCard/__tests__/__snapshots__/graphCard.test.js.snap index e75a42354..f43ad594f 100644 --- a/src/components/graphCard/__tests__/__snapshots__/graphCard.test.js.snap +++ b/src/components/graphCard/__tests__/__snapshots__/graphCard.test.js.snap @@ -8,6 +8,13 @@ exports[`GraphCard Component should setup basic settings: settings, grouped 1`] value={ { "settings": { + "cards": [ + { + "body": "ipsum", + "footer": "dolor sit", + "header": "lorem", + }, + ], "isMetricDisplay": true, "loremIpsum": false, "metric": undefined, @@ -29,7 +36,7 @@ exports[`GraphCard Component should setup basic settings: settings, grouped 1`] } > @@ -75,12 +82,18 @@ exports[`GraphCard Component should setup basic settings: settings, standalone 1 } } > - + > + + `; diff --git a/src/components/graphCard/__tests__/__snapshots__/graphCardContext.test.js.snap b/src/components/graphCard/__tests__/__snapshots__/graphCardContext.test.js.snap index 02dbc735c..6fea1994a 100644 --- a/src/components/graphCard/__tests__/__snapshots__/graphCardContext.test.js.snap +++ b/src/components/graphCard/__tests__/__snapshots__/graphCardContext.test.js.snap @@ -119,6 +119,10 @@ exports[`GraphCardContext should parse configuration: configuration, grouped 1`] "filtersSettings": [ { "settings": { + "groupMetric": [ + "Core-seconds", + ], + "isMetricDisplay": false, "isMultiMetric": false, "isStandalone": undefined, "metric": undefined, @@ -152,6 +156,10 @@ exports[`GraphCardContext should parse configuration: configuration, standalone "filtersSettings": [ { "settings": { + "groupMetric": [ + "Core-seconds", + ], + "isMetricDisplay": false, "isMultiMetric": false, "isStandalone": undefined, "loremIpsum": true, diff --git a/src/components/graphCard/__tests__/__snapshots__/graphCardHelpers.test.js.snap b/src/components/graphCard/__tests__/__snapshots__/graphCardHelpers.test.js.snap index 8f1436f99..ca0ea1056 100644 --- a/src/components/graphCard/__tests__/__snapshots__/graphCardHelpers.test.js.snap +++ b/src/components/graphCard/__tests__/__snapshots__/graphCardHelpers.test.js.snap @@ -12,6 +12,10 @@ exports[`GraphCardHelpers generateChartSettings should return base graph setting { "settings": { "dolor": "sit", + "groupMetric": [ + "dolorSit", + ], + "isMetricDisplay": false, "isMultiMetric": false, "isStandalone": undefined, "metric": undefined, diff --git a/src/components/graphCard/__tests__/__snapshots__/graphCardMetricTotals.test.js.snap b/src/components/graphCard/__tests__/__snapshots__/graphCardMetricTotals.test.js.snap index 3b1451f6f..f7adafe33 100644 --- a/src/components/graphCard/__tests__/__snapshots__/graphCardMetricTotals.test.js.snap +++ b/src/components/graphCard/__tests__/__snapshots__/graphCardMetricTotals.test.js.snap @@ -1,77 +1,74 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`GraphCardMetricTotals Component should handle multiple display states: error 1`] = ` +exports[`GraphCardMetricTotals Component should handle custom card displays: fulfilled 1`] = `
+ > + lorem + -
+
+ t(ipsum-{{data}}, {"testId":"custom test id","data":"{\\"groupMetricId\\":[\\"hello\\",\\"world\\"]}"}) +
-
+
+ dolor sit timestamp +
+ > + hello-{"groupMetricId":["hello","world"]} + -
+
+ world +
-
+
+ dolor sit timestamp +
-
-
-
-
-
-
-`; - -exports[`GraphCardMetricTotals Component should handle multiple display states: fulfilled 1`] = ` -
-
-
@@ -79,38 +76,57 @@ exports[`GraphCardMetricTotals Component should handle multiple display states: headingLevel="h2" size="md" > - t(curiosity-graph.cardHeadingMetric, {"context":"dailyTotal"}) + dolor
- t(curiosity-graph.cardBodyMetric, {"context":"total"}, [object Object]) + sit
-
+
+ dolor sit timestamp-{"groupMetricId":["hello","world"]} +
+
+
+
+
+
+
+`; + +exports[`GraphCardMetricTotals Component should handle multiple display states: error 1`] = ` +
+
+
- t(curiosity-graph.cardHeadingMetric, {"context":"monthlyTotal"}) - + /> -
- t(curiosity-graph.cardBodyMetric, {"context":"total"}, [object Object]) -
+
@@ -126,10 +142,11 @@ exports[`GraphCardMetricTotals Component should handle multiple display states:
`; -exports[`GraphCardMetricTotals Component should handle multiple display states: pending 1`] = ` +exports[`GraphCardMetricTotals Component should handle multiple display states: fulfilled 1`] = `
@@ -146,50 +164,46 @@ exports[`GraphCardMetricTotals Component should handle multiple display states: headingLevel="h2" size="md" > - + lorem
- + ipsum
- + dolor sit
+
+
+
+
+
+
+`; + +exports[`GraphCardMetricTotals Component should handle multiple display states: pending 1`] = ` +
+
+
@@ -247,61 +261,4 @@ exports[`GraphCardMetricTotals Component should handle multiple display states:
`; -exports[`GraphCardMetricTotals Component should render a basic component: basic 1`] = ` -
-
-
- - - - - </CardTitle> - </CardHeader> - <CardBody> - <div /> - </CardBody> - <CardFooter> - <div /> - </CardFooter> - </Card> - <Card - className="curiosity-usage-graph__totals-column-card " - data-test="graphMonthlyTotalCard" - isPlain={true} - > - <CardHeader> - <CardTitle> - <Title - headingLevel="h2" - size="md" - /> - </CardTitle> - </CardHeader> - <CardBody> - <div /> - </CardBody> - <CardFooter> - <div /> - </CardFooter> - </Card> - </div> - </div> - <div> - <div - className="curiosity-usage-graph__totals-graph-column" - /> - </div> -</div> -`; +exports[`GraphCardMetricTotals Component should render a basic component: basic 1`] = `"lorem ipsum"`; diff --git a/src/components/graphCard/__tests__/graphCard.test.js b/src/components/graphCard/__tests__/graphCard.test.js index 46510a1f4..35d48a5a1 100644 --- a/src/components/graphCard/__tests__/graphCard.test.js +++ b/src/components/graphCard/__tests__/graphCard.test.js @@ -43,6 +43,13 @@ describe('GraphCard Component', () => { settings: { loremIpsum: false, isMetricDisplay: true, + cards: [ + { + header: 'lorem', + body: 'ipsum', + footer: 'dolor sit' + } + ], metric: undefined, metrics: [ { diff --git a/src/components/graphCard/__tests__/graphCardMetricTotals.test.js b/src/components/graphCard/__tests__/graphCardMetricTotals.test.js index c28050b6c..b49872c54 100644 --- a/src/components/graphCard/__tests__/graphCardMetricTotals.test.js +++ b/src/components/graphCard/__tests__/graphCardMetricTotals.test.js @@ -1,9 +1,12 @@ import React from 'react'; import { GraphCardMetricTotals } from '../graphCardMetricTotals'; +import { translate } from '../../i18n/i18nHelpers'; describe('GraphCardMetricTotals Component', () => { it('should render a basic component', async () => { - const props = {}; + const props = { + children: 'lorem ipsum' + }; const component = await shallowHookComponent(<GraphCardMetricTotals {...props} />); expect(component).toMatchSnapshot('basic'); @@ -11,6 +14,20 @@ describe('GraphCardMetricTotals Component', () => { it('should handle multiple display states', async () => { const props = { + useGraphCardContext: () => ({ + children: 'lorem ipsum', + settings: { + isMetricDisplay: true, + groupMetric: ['hello', 'world'], + cards: [ + { + header: 'lorem', + body: 'ipsum', + footer: 'dolor sit' + } + ] + } + }), useMetricsSelector: () => ({ pending: true, error: false, @@ -41,4 +58,42 @@ describe('GraphCardMetricTotals Component', () => { expect(component).toMatchSnapshot('fulfilled'); }); + + it('should handle custom card displays', async () => { + const props = { + useGraphCardContext: () => ({ + children: 'lorem ipsum', + settings: { + isMetricDisplay: true, + groupMetric: ['hello', 'world'], + cards: [ + { + header: 'lorem', + body: passedValues => + translate('ipsum-{{data}}', { testId: 'custom test id', data: JSON.stringify(passedValues) }), + footer: 'dolor sit timestamp' + }, + { + key: 'my custom react key', + header: passedValues => `hello-${JSON.stringify(passedValues)}`, + body: 'world', + footer: 'dolor sit timestamp' + }, + { + header: 'dolor', + body: 'sit', + footer: passedValues => `dolor sit timestamp-${JSON.stringify(passedValues)}` + } + ] + } + }), + useMetricsSelector: () => ({ + pending: false, + error: false, + fulfilled: true + }) + }; + const component = await shallowHookComponent(<GraphCardMetricTotals {...props} />); + expect(component).toMatchSnapshot('fulfilled'); + }); }); diff --git a/src/components/graphCard/graphCard.js b/src/components/graphCard/graphCard.js index a7b3b2ace..d1fc260f8 100644 --- a/src/components/graphCard/graphCard.js +++ b/src/components/graphCard/graphCard.js @@ -31,23 +31,17 @@ import { GraphCardContext, useParseFiltersSettings } from './graphCardContext'; const GraphCard = ({ isDisabled, useParseFiltersSettings: useAliasParseFiltersSettings }) => { const { filtersSettings } = useAliasParseFiltersSettings(); - if (isDisabled) { + if (isDisabled || !filtersSettings?.length) { return null; } - return ( - (filtersSettings?.length && - filtersSettings?.map(filterSetting => ( - <GraphCardContext.Provider key={`graphCard-${filterSetting?.settings?.metrics?.[0]?.id}`} value={filterSetting}> - {(filterSetting?.settings?.isMetricDisplay && ( - <GraphCardMetricTotals> - <GraphCardChart /> - </GraphCardMetricTotals> - )) || <GraphCardChart />} - </GraphCardContext.Provider> - ))) || - null - ); + return filtersSettings?.map(filterSetting => ( + <GraphCardContext.Provider key={`graphCard-${filterSetting?.settings?.metrics?.[0]?.id}`} value={filterSetting}> + <GraphCardMetricTotals> + <GraphCardChart /> + </GraphCardMetricTotals> + </GraphCardContext.Provider> + )); }; /** diff --git a/src/components/graphCard/graphCardHelpers.js b/src/components/graphCard/graphCardHelpers.js index 6fe5d287b..4e4c97541 100644 --- a/src/components/graphCard/graphCardHelpers.js +++ b/src/components/graphCard/graphCardHelpers.js @@ -60,7 +60,7 @@ const generateChartSettings = ({ filters = [], settings: graphCardSettings = {}, if (!metric) { return; } - const { isMultiMetric, isFirst, ...remainingCombinedSettings } = combinedSettings; + const { isMultiMetric, isFirst, isLast, ...remainingCombinedSettings } = combinedSettings; const updatedChartType = filterSettings?.chartType || ChartTypeVariant.area; const isThreshold = filterSettings?.chartType === ChartTypeVariant.threshold; const baseFilterSettings = { @@ -90,9 +90,11 @@ const generateChartSettings = ({ filters = [], settings: graphCardSettings = {}, top: 45 }, ...remainingCombinedSettings, + isMetricDisplay: remainingCombinedSettings?.isMetricDisplay ?? remainingCombinedSettings?.cards?.length > 0, isMultiMetric, isStandalone: undefined, metric: undefined, + groupMetric: new Set([metric]), metrics: [ { ...baseFilterSettings, @@ -103,15 +105,21 @@ const generateChartSettings = ({ filters = [], settings: graphCardSettings = {}, } }); } else { - const lastFiltersSettingsEntry = filtersSettings?.[filtersSettings.length - 1]?.settings; + const currentLastFiltersSettingsEntry = filtersSettings?.[filtersSettings.length - 1]?.settings; - if (lastFiltersSettingsEntry) { - lastFiltersSettingsEntry.metrics.push({ + if (currentLastFiltersSettingsEntry) { + currentLastFiltersSettingsEntry.groupMetric.add(metric); + currentLastFiltersSettingsEntry.metrics.push({ ...baseFilterSettings, ...filterSettings }); } } + + if (isLast) { + const lastFiltersSettingsEntry = filtersSettings?.[filtersSettings.length - 1]?.settings; + lastFiltersSettingsEntry.groupMetric = Array.from(lastFiltersSettingsEntry?.groupMetric).sort(); + } }; filters.forEach(({ filters: groupedMetrics, settings: groupedMetricsSettings, ...remainingSettings }) => { @@ -126,6 +134,7 @@ const generateChartSettings = ({ filters = [], settings: graphCardSettings = {}, ...groupedMetricsSettings, ...metricFilter, isFirst: index === 0, + isLast: groupedMetrics.length - 1 === index, isMultiMetric: groupedMetrics.length > 1 } }); @@ -139,6 +148,7 @@ const generateChartSettings = ({ filters = [], settings: graphCardSettings = {}, ...graphCardSettings, ...remainingSettings, isFirst: true, + isLast: true, isMultiMetric: false } }); diff --git a/src/components/graphCard/graphCardMetricTotals.js b/src/components/graphCard/graphCardMetricTotals.js index e8a47e395..b823a2035 100644 --- a/src/components/graphCard/graphCardMetricTotals.js +++ b/src/components/graphCard/graphCardMetricTotals.js @@ -1,15 +1,13 @@ import React from 'react'; import PropTypes from 'prop-types'; import { Card, CardBody, CardFooter, CardHeader, CardTitle, Title } from '@patternfly/react-core'; -import moment from 'moment'; import _camelCase from 'lodash/camelCase'; import { useProductGraphTallyQuery } from '../productView/productViewContext'; -import { useMetricsSelector } from './graphCardContext'; +import { useGraphCardContext, useMetricsSelector } from './graphCardContext'; import { Loader, SkeletonSize } from '../loader/loader'; -import { dateHelpers, helpers } from '../../common'; import { toolbarFieldOptions } from '../toolbar/toolbarFieldRangedMonthly'; import { RHSM_API_QUERY_SET_TYPES } from '../../services/rhsm/rhsmConstants'; -import { translate } from '../i18n/i18n'; +import { helpers } from '../../common'; /** * @memberof GraphCard @@ -21,20 +19,21 @@ import { translate } from '../i18n/i18n'; * * @param {object} props * @param {React.ReactNode} props.children - * @param {Function} props.t + * @param {Function} props.useGraphCardContext * @param {Function} props.useMetricsSelector * @param {Function} props.useProductGraphTallyQuery * @returns {React.ReactNode} */ const GraphCardMetricTotals = ({ children, - t, + useGraphCardContext: useAliasGraphCardContext, useMetricsSelector: useAliasMetricsSelector, useProductGraphTallyQuery: useAliasProductGraphTallyQuery }) => { + const { settings = {} } = useAliasGraphCardContext(); const { [RHSM_API_QUERY_SET_TYPES.START_DATE]: startDate } = useAliasProductGraphTallyQuery(); const { pending, error, fulfilled, dataSets = [] } = useAliasMetricsSelector(); - const { data = [], id: chartId, metric: metricId, meta = {} } = dataSets[0] || {}; + const { data = [], id: firstChartId, metric: firstMetricId, meta = {} } = dataSets[0] || {}; const { date: lastDate, hasData: lastHasData, y: lastValue } = data[data.length - 1] || {}; const { @@ -54,122 +53,77 @@ const GraphCardMetricTotals = ({ const dailyHasData = isCurrent ? currentHasData : lastHasData; const dailyValue = isCurrent ? currentValue : lastValue; - return ( - <div data-test={`graphMetricTotals-${_camelCase(metricId)}`} className="curiosity-usage-graph__totals"> - <div> - <div className="curiosity-usage-graph__totals-column"> - <Card - isPlain - data-test="graphDailyTotalCard" - className={`curiosity-usage-graph__totals-column-card ${(error && 'blur') || ''}`} - > - <CardHeader> - <CardTitle> - <Title headingLevel="h2" size="md"> - {pending && <Loader variant="skeleton" skeletonProps={{ size: SkeletonSize.lg }} />} - {fulfilled && - t('curiosity-graph.cardHeadingMetric', { - context: ['dailyTotal', chartId], - month: selectedMonth - })} - - - - -
- {pending && } - {fulfilled && - t( - 'curiosity-graph.cardBodyMetric', - { - context: ['total', dailyHasData && chartId], - total: helpers - .numberDisplay(dailyValue) - ?.format({ - average: true, - mantissa: 5, - trimMantissa: true, - lowPrecision: false - }) - ?.toUpperCase() - }, - [] - )} -
-
- -
- {pending && } - {fulfilled && - dailyDate && - t('curiosity-graph.cardFooterMetric', { - date: moment.utc(dailyDate).format(dateHelpers.timestampUTCTimeFormats.yearTimeShort) - })} -
-
-
- - - - - {pending && <Loader variant="skeleton" skeletonProps={{ size: SkeletonSize.lg }} />} - {fulfilled && - t('curiosity-graph.cardHeadingMetric', { - context: ['monthlyTotal', chartId], - month: selectedMonth - })} - - - - -
- {pending && } - {fulfilled && - t( - 'curiosity-graph.cardBodyMetric', - { - context: ['total', monthlyHasData && chartId], - total: helpers - .numberDisplay(monthlyValue) - ?.format({ average: true, mantissa: 5, trimMantissa: true, lowPrecision: false }) - ?.toUpperCase() - }, - [] - )} -
-
- -
- {pending && } - {fulfilled && - monthlyDate && - t('curiosity-graph.cardFooterMetric', { - date: moment.utc(monthlyDate).format(dateHelpers.timestampUTCTimeFormats.yearTimeShort) - })} -
-
-
+ if (settings?.isMetricDisplay && settings?.cards?.length) { + const metricDisplayPassedData = helpers.setImmutableData({ + chartId: firstChartId, + dailyDate, + dailyHasData, + dailyValue, + metricId: firstMetricId, + groupMetricId: [...settings.groupMetric], + monthlyDate, + monthlyHasData, + monthlyValue, + selectedValue: selectedMonth + }); + + return ( +
_camelCase(metricId))?.join('-')}`} + data-test-data={JSON.stringify(metricDisplayPassedData)} + className="curiosity-usage-graph__totals" + > +
+
+ {settings?.cards?.map(({ key, header, body, footer }, index) => ( + + + + + {pending && <Loader variant="skeleton" skeletonProps={{ size: SkeletonSize.lg }} />} + {fulfilled && ((typeof header === 'function' && header(metricDisplayPassedData)) || header)} + + + + +
+ {pending && } + {fulfilled && ((typeof body === 'function' && body(metricDisplayPassedData)) || body)} +
+
+ +
+ {pending && } + {fulfilled && ((typeof footer === 'function' && footer(metricDisplayPassedData)) || footer)} +
+
+
+ ))} +
+
+
+
{children}
-
-
{children}
-
-
- ); + ); + } + + return children; }; /** * Prop types. * - * @type {{useProductGraphTallyQuery: Function, t: Function, children: React.ReactNode, useMetricsSelector: Function}} + * @type {{useProductGraphTallyQuery: Function, children: React.ReactNode, useMetricsSelector: Function}} */ GraphCardMetricTotals.propTypes = { children: PropTypes.node, - t: PropTypes.func, + useGraphCardContext: PropTypes.func, useMetricsSelector: PropTypes.func, useProductGraphTallyQuery: PropTypes.func }; @@ -177,11 +131,11 @@ GraphCardMetricTotals.propTypes = { /** * Default props. * - * @type {{useProductGraphTallyQuery: Function, t: Function, children: React.ReactNode, useMetricsSelector: Function}} + * @type {{useProductGraphTallyQuery: Function, children: React.ReactNode, useMetricsSelector: Function}} */ GraphCardMetricTotals.defaultProps = { children: null, - t: translate, + useGraphCardContext, useMetricsSelector, useProductGraphTallyQuery }; diff --git a/src/components/i18n/__tests__/__snapshots__/i18n.test.js.snap b/src/components/i18n/__tests__/__snapshots__/i18n.test.js.snap index 7a24c25e3..98210daea 100644 --- a/src/components/i18n/__tests__/__snapshots__/i18n.test.js.snap +++ b/src/components/i18n/__tests__/__snapshots__/i18n.test.js.snap @@ -105,35 +105,6 @@ exports[`I18n Component should generate a predictable locale key output snapshot }, ], }, - { - "file": "./src/components/graphCard/graphCardMetricTotals.js", - "keys": [ - { - "key": "curiosity-graph.cardHeadingMetric", - "match": "t('curiosity-graph.cardHeadingMetric', { context: ['dailyTotal', chartId], month: selectedMonth })", - }, - { - "key": "curiosity-graph.cardBodyMetric", - "match": "t( 'curiosity-graph.cardBodyMetric', { context: ['total', dailyHasData && chartId], total: helpers .numberDisplay(dailyValue)", - }, - { - "key": "curiosity-graph.cardFooterMetric", - "match": "t('curiosity-graph.cardFooterMetric', { date: moment.utc(dailyDate)", - }, - { - "key": "curiosity-graph.cardHeadingMetric", - "match": "t('curiosity-graph.cardHeadingMetric', { context: ['monthlyTotal', chartId], month: selectedMonth })", - }, - { - "key": "curiosity-graph.cardBodyMetric", - "match": "t( 'curiosity-graph.cardBodyMetric', { context: ['total', monthlyHasData && chartId], total: helpers .numberDisplay(monthlyValue)", - }, - { - "key": "curiosity-graph.cardFooterMetric", - "match": "t('curiosity-graph.cardFooterMetric', { date: moment.utc(monthlyDate)", - }, - ], - }, { "file": "./src/components/i18n/i18nHelpers.js", "keys": [ @@ -615,6 +586,30 @@ exports[`I18n Component should generate a predictable locale key output snapshot "key": "curiosity-graph.label_axisY", "match": "translate('curiosity-graph.label_axisY', { context: id })", }, + { + "key": "curiosity-graph.cardHeadingMetric", + "match": "translate('curiosity-graph.cardHeadingMetric', { context: ['dailyTotal', metricId], testId: 'graphDailyTotalCard-header' })", + }, + { + "key": "curiosity-graph.cardBodyMetric", + "match": "translate( 'curiosity-graph.cardBodyMetric', { context: ['total', dailyHasData && metricId], testId: 'graphDailyTotalCard-body', total: helpers .numberDisplay(dailyValue)", + }, + { + "key": "curiosity-graph.cardFooterMetric", + "match": "translate('curiosity-graph.cardFooterMetric', { date: moment.utc(dailyDate)", + }, + { + "key": "curiosity-graph.cardHeadingMetric", + "match": "translate('curiosity-graph.cardHeadingMetric', { context: ['monthlyTotal', metricId], testId: 'graphMonthlyTotalCard-header' })", + }, + { + "key": "curiosity-graph.cardBodyMetric", + "match": "translate( 'curiosity-graph.cardBodyMetric', { context: ['total', monthlyHasData && metricId], testId: 'graphMonthlyTotalCard-body', total: helpers .numberDisplay(monthlyValue)", + }, + { + "key": "curiosity-graph.cardFooterMetric", + "match": "translate('curiosity-graph.cardFooterMetric', { date: moment.utc(monthlyDate)", + }, { "key": "curiosity-graph.label_axisX", "match": "translate('curiosity-graph.label_axisX', { context: GRANULARITY_TYPES.DAILY })", @@ -669,6 +664,30 @@ exports[`I18n Component should generate a predictable locale key output snapshot "key": "curiosity-graph.label_axisY", "match": "translate('curiosity-graph.label_axisY', { context: id })", }, + { + "key": "curiosity-graph.cardHeadingMetric", + "match": "translate('curiosity-graph.cardHeadingMetric', { context: ['dailyTotal', metricId], testId: 'graphDailyTotalCard-header' })", + }, + { + "key": "curiosity-graph.cardBodyMetric", + "match": "translate( 'curiosity-graph.cardBodyMetric', { context: ['total', dailyHasData && metricId], testId: 'graphDailyTotalCard-body', total: helpers .numberDisplay(dailyValue)", + }, + { + "key": "curiosity-graph.cardFooterMetric", + "match": "translate('curiosity-graph.cardFooterMetric', { date: moment.utc(dailyDate)", + }, + { + "key": "curiosity-graph.cardHeadingMetric", + "match": "translate('curiosity-graph.cardHeadingMetric', { context: ['monthlyTotal', metricId], testId: 'graphMonthlyTotalCard-header' })", + }, + { + "key": "curiosity-graph.cardBodyMetric", + "match": "translate( 'curiosity-graph.cardBodyMetric', { context: ['total', monthlyHasData && metricId], testId: 'graphMonthlyTotalCard-body', total: helpers .numberDisplay(monthlyValue)", + }, + { + "key": "curiosity-graph.cardFooterMetric", + "match": "translate('curiosity-graph.cardFooterMetric', { date: moment.utc(monthlyDate)", + }, { "key": "curiosity-graph.label_axisX", "match": "translate('curiosity-graph.label_axisX', { context: GRANULARITY_TYPES.DAILY })", @@ -706,6 +725,30 @@ exports[`I18n Component should generate a predictable locale key output snapshot "key": "curiosity-graph.label_axisY", "match": "translate('curiosity-graph.label_axisY', { context: id })", }, + { + "key": "curiosity-graph.cardHeadingMetric", + "match": "translate('curiosity-graph.cardHeadingMetric', { context: ['dailyTotal', metricId], testId: 'graphDailyTotalCard-header' })", + }, + { + "key": "curiosity-graph.cardBodyMetric", + "match": "translate( 'curiosity-graph.cardBodyMetric', { context: ['total', dailyHasData && metricId], testId: 'graphDailyTotalCard-body', total: helpers .numberDisplay(dailyValue)", + }, + { + "key": "curiosity-graph.cardFooterMetric", + "match": "translate('curiosity-graph.cardFooterMetric', { date: moment.utc(dailyDate)", + }, + { + "key": "curiosity-graph.cardHeadingMetric", + "match": "translate('curiosity-graph.cardHeadingMetric', { context: ['monthlyTotal', metricId], testId: 'graphMonthlyTotalCard-header' })", + }, + { + "key": "curiosity-graph.cardBodyMetric", + "match": "translate( 'curiosity-graph.cardBodyMetric', { context: ['total', monthlyHasData && metricId], testId: 'graphMonthlyTotalCard-body', total: helpers .numberDisplay(monthlyValue)", + }, + { + "key": "curiosity-graph.cardFooterMetric", + "match": "translate('curiosity-graph.cardFooterMetric', { date: moment.utc(monthlyDate)", + }, { "key": "curiosity-graph.label_axisX", "match": "translate('curiosity-graph.label_axisX', { context: GRANULARITY_TYPES.DAILY })", diff --git a/src/components/pageLayout/pageColumns.js b/src/components/pageLayout/pageColumns.js index 18bfab068..ec7f0e27f 100644 --- a/src/components/pageLayout/pageColumns.js +++ b/src/components/pageLayout/pageColumns.js @@ -42,16 +42,17 @@ const PageColumns = ({ children, className }) => ( * @type {{children: React.ReactNode, className: string}} */ PageColumns.propTypes = { - children: PropTypes.node.isRequired, + children: PropTypes.node, className: PropTypes.string }; /** * Default props. * - * @type {{className: string}} + * @type {{children: React.ReactNode, className: string}} */ PageColumns.defaultProps = { + children: [], className: '' }; diff --git a/src/config/__tests__/__snapshots__/product.openshiftContainer.test.js.snap b/src/config/__tests__/__snapshots__/product.openshiftContainer.test.js.snap index c97eae4c3..53394b6d4 100644 --- a/src/config/__tests__/__snapshots__/product.openshiftContainer.test.js.snap +++ b/src/config/__tests__/__snapshots__/product.openshiftContainer.test.js.snap @@ -5,8 +5,24 @@ exports[`Product OpenShift Container config should apply graph configuration: fi "filtersSettings": [ { "settings": { + "actions": [ + { + "id": "uom", + "position": "right", + }, + { + "id": "granularity", + "position": "right", + }, + ], "color": "#06c", "fill": "#8bc1f7", + "groupMetric": [ + "Cores", + "Sockets", + ], + "isCardTitleDescription": true, + "isMetricDisplay": false, "isMultiMetric": true, "isOptional": true, "isStandalone": undefined, diff --git a/src/config/__tests__/__snapshots__/product.openshiftDedicated.test.js.snap b/src/config/__tests__/__snapshots__/product.openshiftDedicated.test.js.snap index c041d2cfc..eab21dc28 100644 --- a/src/config/__tests__/__snapshots__/product.openshiftDedicated.test.js.snap +++ b/src/config/__tests__/__snapshots__/product.openshiftDedicated.test.js.snap @@ -5,9 +5,24 @@ exports[`Product OpenShift Dedicated config should apply graph configuration: fi "filtersSettings": [ { "settings": { + "actions": [ + { + "content": [Function], + }, + { + "id": "rangedMonthly", + "position": "right", + }, + ], "chartType": "line", "color": "#06c", "fill": "#8bc1f7", + "groupMetric": [ + "Cores", + "Instance-hours", + ], + "isCardTitleDescription": true, + "isMetricDisplay": false, "isMultiMetric": true, "isStacked": false, "isStandalone": undefined, diff --git a/src/config/__tests__/__snapshots__/product.openshiftMetrics.test.js.snap b/src/config/__tests__/__snapshots__/product.openshiftMetrics.test.js.snap index 249dbce0f..14467f6e6 100644 --- a/src/config/__tests__/__snapshots__/product.openshiftMetrics.test.js.snap +++ b/src/config/__tests__/__snapshots__/product.openshiftMetrics.test.js.snap @@ -5,8 +5,22 @@ exports[`Product OpenShift Metrics config should apply graph configuration: filt "filtersSettings": [ { "settings": { + "actions": [ + { + "content": [Function], + }, + { + "id": "rangedMonthly", + "position": "right", + }, + ], "color": "#06c", "fill": "#8bc1f7", + "groupMetric": [ + "Cores", + ], + "isCardTitleDescription": true, + "isMetricDisplay": false, "isMultiMetric": false, "isStacked": false, "isStandalone": undefined, diff --git a/src/config/__tests__/__snapshots__/product.rhacs.test.js.snap b/src/config/__tests__/__snapshots__/product.rhacs.test.js.snap index cd4fbcde5..e62aba9d1 100644 --- a/src/config/__tests__/__snapshots__/product.rhacs.test.js.snap +++ b/src/config/__tests__/__snapshots__/product.rhacs.test.js.snap @@ -134,9 +134,26 @@ exports[`Product RHACS config should apply graph configuration: filters 1`] = ` "filtersSettings": [ { "settings": { + "cards": [ + { + "body": [Function], + "footer": [Function], + "header": [Function], + }, + { + "body": [Function], + "footer": [Function], + "header": [Function], + }, + ], "chartType": "line", "color": "#06c", "fill": "#8bc1f7", + "groupMetric": [ + "Cores", + ], + "isCardTitleDescription": true, + "isMetricDisplay": true, "isMultiMetric": false, "isStacked": false, "isStandalone": undefined, @@ -165,7 +182,9 @@ exports[`Product RHACS config should apply graph configuration: filters 1`] = ` }, "stringId": "Cores", "stroke": "#06c", + "xAxisChartLabel": [Function], "yAxisChartLabel": [Function], + "yAxisTickFormat": [Function], }, }, ], @@ -174,8 +193,19 @@ exports[`Product RHACS config should apply graph configuration: filters 1`] = ` exports[`Product RHACS config should apply graph configuration: settings 1`] = ` { + "cards": [ + { + "body": [Function], + "footer": [Function], + "header": [Function], + }, + { + "body": [Function], + "footer": [Function], + "header": [Function], + }, + ], "isCardTitleDescription": true, - "isMetricDisplay": true, "xAxisChartLabel": [Function], "yAxisTickFormat": [Function], } @@ -584,3 +614,14 @@ exports[`Product RHACS config should handle a custom yAxisTickFormat for floatin "9000000000000": "9T", } `; + +exports[`Product RHACS config should handle metric card display for graphs: cards 1`] = ` +[ + "t(curiosity-graph.cardHeadingMetric, {"context":"dailyTotal","testId":"graphDailyTotalCard-header"})", + "t(curiosity-graph.cardBodyMetric, {"context":"total","testId":"graphDailyTotalCard-body"}, [object Object])", + "t(curiosity-graph.cardFooterMetric, {"date":"09 Mar 2023 00:00 UTC","testId":"graphDailyTotalCard-footer"})", + "t(curiosity-graph.cardHeadingMetric, {"context":"monthlyTotal","testId":"graphMonthlyTotalCard-header"})", + "t(curiosity-graph.cardBodyMetric, {"context":"total","testId":"graphMonthlyTotalCard-body"}, [object Object])", + "t(curiosity-graph.cardFooterMetric, {"date":"09 Mar 2023 00:00 UTC","testId":"graphMonthlyTotalCard-footer"})", +] +`; diff --git a/src/config/__tests__/__snapshots__/product.rhel.test.js.snap b/src/config/__tests__/__snapshots__/product.rhel.test.js.snap index bd83a49b3..7dc819d2b 100644 --- a/src/config/__tests__/__snapshots__/product.rhel.test.js.snap +++ b/src/config/__tests__/__snapshots__/product.rhel.test.js.snap @@ -318,8 +318,19 @@ exports[`Product RHEL config should apply graph configuration: filters 1`] = ` "filtersSettings": [ { "settings": { + "actions": [ + { + "id": "granularity", + "position": "right", + }, + ], "color": "#06c", "fill": "#8bc1f7", + "groupMetric": [ + "Sockets", + ], + "isDisabledLegendClick": true, + "isMetricDisplay": false, "isMultiMetric": true, "isStandalone": undefined, "metric": undefined, diff --git a/src/config/__tests__/__snapshots__/product.rhods.test.js.snap b/src/config/__tests__/__snapshots__/product.rhods.test.js.snap index 122f959ad..514bdf25a 100644 --- a/src/config/__tests__/__snapshots__/product.rhods.test.js.snap +++ b/src/config/__tests__/__snapshots__/product.rhods.test.js.snap @@ -134,9 +134,26 @@ exports[`Product RHODS config should apply graph configuration: filters 1`] = ` "filtersSettings": [ { "settings": { + "cards": [ + { + "body": [Function], + "footer": [Function], + "header": [Function], + }, + { + "body": [Function], + "footer": [Function], + "header": [Function], + }, + ], "chartType": "line", "color": "#06c", "fill": "#8bc1f7", + "groupMetric": [ + "Cores", + ], + "isCardTitleDescription": true, + "isMetricDisplay": true, "isMultiMetric": false, "isStacked": false, "isStandalone": undefined, @@ -165,7 +182,9 @@ exports[`Product RHODS config should apply graph configuration: filters 1`] = ` }, "stringId": "Cores", "stroke": "#06c", + "xAxisChartLabel": [Function], "yAxisChartLabel": [Function], + "yAxisTickFormat": [Function], }, }, ], @@ -174,8 +193,19 @@ exports[`Product RHODS config should apply graph configuration: filters 1`] = ` exports[`Product RHODS config should apply graph configuration: settings 1`] = ` { + "cards": [ + { + "body": [Function], + "footer": [Function], + "header": [Function], + }, + { + "body": [Function], + "footer": [Function], + "header": [Function], + }, + ], "isCardTitleDescription": true, - "isMetricDisplay": true, "xAxisChartLabel": [Function], "yAxisTickFormat": [Function], } @@ -584,3 +614,14 @@ exports[`Product RHODS config should handle a custom yAxisTickFormat for floatin "9000000000000": "9T", } `; + +exports[`Product RHODS config should handle metric card display for graphs: cards 1`] = ` +[ + "t(curiosity-graph.cardHeadingMetric, {"context":"dailyTotal","testId":"graphDailyTotalCard-header"})", + "t(curiosity-graph.cardBodyMetric, {"context":"total","testId":"graphDailyTotalCard-body"}, [object Object])", + "t(curiosity-graph.cardFooterMetric, {"date":"09 Mar 2023 00:00 UTC","testId":"graphDailyTotalCard-footer"})", + "t(curiosity-graph.cardHeadingMetric, {"context":"monthlyTotal","testId":"graphMonthlyTotalCard-header"})", + "t(curiosity-graph.cardBodyMetric, {"context":"total","testId":"graphMonthlyTotalCard-body"}, [object Object])", + "t(curiosity-graph.cardFooterMetric, {"date":"09 Mar 2023 00:00 UTC","testId":"graphMonthlyTotalCard-footer"})", +] +`; diff --git a/src/config/__tests__/__snapshots__/product.rhosak.test.js.snap b/src/config/__tests__/__snapshots__/product.rhosak.test.js.snap index e9c6614af..a0ccdba0b 100644 --- a/src/config/__tests__/__snapshots__/product.rhosak.test.js.snap +++ b/src/config/__tests__/__snapshots__/product.rhosak.test.js.snap @@ -226,9 +226,26 @@ exports[`Product RHOSAK config should apply graph configuration: filters 1`] = ` "filtersSettings": [ { "settings": { + "cards": [ + { + "body": [Function], + "footer": [Function], + "header": [Function], + }, + { + "body": [Function], + "footer": [Function], + "header": [Function], + }, + ], "chartType": "line", "color": "#06c", "fill": "#8bc1f7", + "groupMetric": [ + "Transfer-gibibytes", + ], + "isCardTitleDescription": true, + "isMetricDisplay": true, "isMultiMetric": false, "isStacked": false, "isStandalone": undefined, @@ -257,14 +274,33 @@ exports[`Product RHOSAK config should apply graph configuration: filters 1`] = ` }, "stringId": "Transfer-gibibytes", "stroke": "#06c", + "xAxisChartLabel": [Function], "yAxisChartLabel": [Function], + "yAxisTickFormat": [Function], }, }, { "settings": { + "cards": [ + { + "body": [Function], + "footer": [Function], + "header": [Function], + }, + { + "body": [Function], + "footer": [Function], + "header": [Function], + }, + ], "chartType": "line", "color": "#5752d1", "fill": "#b2b0ea", + "groupMetric": [ + "Storage-gibibyte-months", + ], + "isCardTitleDescription": true, + "isMetricDisplay": true, "isMultiMetric": false, "isStacked": false, "isStandalone": undefined, @@ -293,14 +329,33 @@ exports[`Product RHOSAK config should apply graph configuration: filters 1`] = ` }, "stringId": "Storage-gibibyte-months", "stroke": "#5752d1", + "xAxisChartLabel": [Function], "yAxisChartLabel": [Function], + "yAxisTickFormat": [Function], }, }, { "settings": { + "cards": [ + { + "body": [Function], + "footer": [Function], + "header": [Function], + }, + { + "body": [Function], + "footer": [Function], + "header": [Function], + }, + ], "chartType": "line", "color": "#009596", "fill": "#a2d9d9", + "groupMetric": [ + "Instance-hours", + ], + "isCardTitleDescription": true, + "isMetricDisplay": true, "isMultiMetric": false, "isStacked": false, "isStandalone": undefined, @@ -329,7 +384,9 @@ exports[`Product RHOSAK config should apply graph configuration: filters 1`] = ` }, "stringId": "Instance-hours", "stroke": "#009596", + "xAxisChartLabel": [Function], "yAxisChartLabel": [Function], + "yAxisTickFormat": [Function], }, }, ], @@ -338,8 +395,19 @@ exports[`Product RHOSAK config should apply graph configuration: filters 1`] = ` exports[`Product RHOSAK config should apply graph configuration: settings 1`] = ` { + "cards": [ + { + "body": [Function], + "footer": [Function], + "header": [Function], + }, + { + "body": [Function], + "footer": [Function], + "header": [Function], + }, + ], "isCardTitleDescription": true, - "isMetricDisplay": true, "xAxisChartLabel": [Function], "yAxisTickFormat": [Function], } @@ -748,3 +816,26 @@ exports[`Product RHOSAK config should handle a custom yAxisTickFormat for floati "9000000000000": "9T", } `; + +exports[`Product RHOSAK config should handle metric card display for graphs: cards 1`] = ` +[ + "t(curiosity-graph.cardHeadingMetric, {"context":"dailyTotal","testId":"graphDailyTotalCard-header"})", + "t(curiosity-graph.cardBodyMetric, {"context":"total","testId":"graphDailyTotalCard-body"}, [object Object])", + "t(curiosity-graph.cardFooterMetric, {"date":"09 Mar 2023 00:00 UTC","testId":"graphDailyTotalCard-footer"})", + "t(curiosity-graph.cardHeadingMetric, {"context":"monthlyTotal","testId":"graphMonthlyTotalCard-header"})", + "t(curiosity-graph.cardBodyMetric, {"context":"total","testId":"graphMonthlyTotalCard-body"}, [object Object])", + "t(curiosity-graph.cardFooterMetric, {"date":"09 Mar 2023 00:00 UTC","testId":"graphMonthlyTotalCard-footer"})", + "t(curiosity-graph.cardHeadingMetric, {"context":"dailyTotal","testId":"graphDailyTotalCard-header"})", + "t(curiosity-graph.cardBodyMetric, {"context":"total","testId":"graphDailyTotalCard-body"}, [object Object])", + "t(curiosity-graph.cardFooterMetric, {"date":"09 Mar 2023 00:00 UTC","testId":"graphDailyTotalCard-footer"})", + "t(curiosity-graph.cardHeadingMetric, {"context":"monthlyTotal","testId":"graphMonthlyTotalCard-header"})", + "t(curiosity-graph.cardBodyMetric, {"context":"total","testId":"graphMonthlyTotalCard-body"}, [object Object])", + "t(curiosity-graph.cardFooterMetric, {"date":"09 Mar 2023 00:00 UTC","testId":"graphMonthlyTotalCard-footer"})", + "t(curiosity-graph.cardHeadingMetric, {"context":"dailyTotal","testId":"graphDailyTotalCard-header"})", + "t(curiosity-graph.cardBodyMetric, {"context":"total","testId":"graphDailyTotalCard-body"}, [object Object])", + "t(curiosity-graph.cardFooterMetric, {"date":"09 Mar 2023 00:00 UTC","testId":"graphDailyTotalCard-footer"})", + "t(curiosity-graph.cardHeadingMetric, {"context":"monthlyTotal","testId":"graphMonthlyTotalCard-header"})", + "t(curiosity-graph.cardBodyMetric, {"context":"total","testId":"graphMonthlyTotalCard-body"}, [object Object])", + "t(curiosity-graph.cardFooterMetric, {"date":"09 Mar 2023 00:00 UTC","testId":"graphMonthlyTotalCard-footer"})", +] +`; diff --git a/src/config/__tests__/__snapshots__/product.satellite.test.js.snap b/src/config/__tests__/__snapshots__/product.satellite.test.js.snap index 42254a4bb..73b35f622 100644 --- a/src/config/__tests__/__snapshots__/product.satellite.test.js.snap +++ b/src/config/__tests__/__snapshots__/product.satellite.test.js.snap @@ -318,8 +318,19 @@ exports[`Product Satellite config should apply graph configuration: filters 1`] "filtersSettings": [ { "settings": { + "actions": [ + { + "id": "granularity", + "position": "right", + }, + ], "color": "#06c", "fill": "#8bc1f7", + "groupMetric": [ + "Sockets", + ], + "isDisabledLegendClick": true, + "isMetricDisplay": false, "isMultiMetric": true, "isStandalone": undefined, "metric": undefined, diff --git a/src/config/__tests__/product.openshiftContainer.test.js b/src/config/__tests__/product.openshiftContainer.test.js index 75e5ea8b0..db278586a 100644 --- a/src/config/__tests__/product.openshiftContainer.test.js +++ b/src/config/__tests__/product.openshiftContainer.test.js @@ -12,7 +12,9 @@ describe('Product OpenShift Container config', () => { it('should apply graph configuration', () => { const { initialGraphFilters, initialGraphSettings } = config; - expect(generateChartSettings({ filters: initialGraphFilters })).toMatchSnapshot('filters'); + expect(generateChartSettings({ filters: initialGraphFilters, settings: initialGraphSettings })).toMatchSnapshot( + 'filters' + ); expect(initialGraphSettings).toMatchSnapshot('settings'); }); diff --git a/src/config/__tests__/product.openshiftDedicated.test.js b/src/config/__tests__/product.openshiftDedicated.test.js index e707e8466..61fbfadeb 100644 --- a/src/config/__tests__/product.openshiftDedicated.test.js +++ b/src/config/__tests__/product.openshiftDedicated.test.js @@ -12,7 +12,9 @@ describe('Product OpenShift Dedicated config', () => { it('should apply graph configuration', () => { const { initialGraphFilters, initialGraphSettings } = config; - expect(generateChartSettings({ filters: initialGraphFilters })).toMatchSnapshot('filters'); + expect(generateChartSettings({ filters: initialGraphFilters, settings: initialGraphSettings })).toMatchSnapshot( + 'filters' + ); expect(initialGraphSettings).toMatchSnapshot('settings'); expect({ diff --git a/src/config/__tests__/product.openshiftMetrics.test.js b/src/config/__tests__/product.openshiftMetrics.test.js index 0bccd8b50..716fe55f8 100644 --- a/src/config/__tests__/product.openshiftMetrics.test.js +++ b/src/config/__tests__/product.openshiftMetrics.test.js @@ -12,7 +12,9 @@ describe('Product OpenShift Metrics config', () => { it('should apply graph configuration', () => { const { initialGraphFilters, initialGraphSettings } = config; - expect(generateChartSettings({ filters: initialGraphFilters })).toMatchSnapshot('filters'); + expect(generateChartSettings({ filters: initialGraphFilters, settings: initialGraphSettings })).toMatchSnapshot( + 'filters' + ); expect(initialGraphSettings).toMatchSnapshot('settings'); expect({ diff --git a/src/config/__tests__/product.rhacs.test.js b/src/config/__tests__/product.rhacs.test.js index 479e292d3..8e89a17b3 100644 --- a/src/config/__tests__/product.rhacs.test.js +++ b/src/config/__tests__/product.rhacs.test.js @@ -14,10 +14,44 @@ describe('Product RHACS config', () => { it('should apply graph configuration', () => { const { initialGraphFilters, initialGraphSettings } = config; - expect(generateChartSettings({ filters: initialGraphFilters })).toMatchSnapshot('filters'); + expect(generateChartSettings({ filters: initialGraphFilters, settings: initialGraphSettings })).toMatchSnapshot( + 'filters' + ); expect(initialGraphSettings).toMatchSnapshot('settings'); }); + it('should handle metric card display for graphs', () => { + const { initialGraphFilters, initialGraphSettings } = config; + const { filtersSettings } = generateChartSettings({ filters: initialGraphFilters, settings: initialGraphSettings }); + const cardOutput = []; + + filtersSettings.forEach(({ settings }) => { + if (Array.isArray(settings.cards)) { + settings.cards.forEach(({ header, body, footer }) => { + if (typeof header === 'function') { + cardOutput.push(header()); + } else { + cardOutput.push(header); + } + + if (typeof body === 'function') { + cardOutput.push(body()); + } else { + cardOutput.push(body); + } + + if (typeof footer === 'function') { + cardOutput.push(footer({ dailyDate: '09 Mar 2023', monthlyDate: '09 Mar 2023' })); + } else { + cardOutput.push(footer); + } + }); + } + }); + + expect(cardOutput).toMatchSnapshot('cards'); + }); + it('should handle a custom yAxisTickFormat for floating points', () => { const generateTicks = (method = config.initialGraphSettings.yAxisTickFormat) => { const ticks = {}; diff --git a/src/config/__tests__/product.rhel.test.js b/src/config/__tests__/product.rhel.test.js index 352ca8bb3..41daa1494 100644 --- a/src/config/__tests__/product.rhel.test.js +++ b/src/config/__tests__/product.rhel.test.js @@ -13,7 +13,9 @@ describe('Product RHEL config', () => { it('should apply graph configuration', () => { const { initialGraphFilters, initialGraphSettings } = config; - expect(generateChartSettings({ filters: initialGraphFilters })).toMatchSnapshot('filters'); + expect(generateChartSettings({ filters: initialGraphFilters, settings: initialGraphSettings })).toMatchSnapshot( + 'filters' + ); expect(initialGraphSettings).toMatchSnapshot('settings'); }); diff --git a/src/config/__tests__/product.rhods.test.js b/src/config/__tests__/product.rhods.test.js index fb3d6dba7..52664a61f 100644 --- a/src/config/__tests__/product.rhods.test.js +++ b/src/config/__tests__/product.rhods.test.js @@ -14,10 +14,44 @@ describe('Product RHODS config', () => { it('should apply graph configuration', () => { const { initialGraphFilters, initialGraphSettings } = config; - expect(generateChartSettings({ filters: initialGraphFilters })).toMatchSnapshot('filters'); + expect(generateChartSettings({ filters: initialGraphFilters, settings: initialGraphSettings })).toMatchSnapshot( + 'filters' + ); expect(initialGraphSettings).toMatchSnapshot('settings'); }); + it('should handle metric card display for graphs', () => { + const { initialGraphFilters, initialGraphSettings } = config; + const { filtersSettings } = generateChartSettings({ filters: initialGraphFilters, settings: initialGraphSettings }); + const cardOutput = []; + + filtersSettings.forEach(({ settings }) => { + if (Array.isArray(settings.cards)) { + settings.cards.forEach(({ header, body, footer }) => { + if (typeof header === 'function') { + cardOutput.push(header()); + } else { + cardOutput.push(header); + } + + if (typeof body === 'function') { + cardOutput.push(body()); + } else { + cardOutput.push(body); + } + + if (typeof footer === 'function') { + cardOutput.push(footer({ dailyDate: '09 Mar 2023', monthlyDate: '09 Mar 2023' })); + } else { + cardOutput.push(footer); + } + }); + } + }); + + expect(cardOutput).toMatchSnapshot('cards'); + }); + it('should handle a custom yAxisTickFormat for floating points', () => { const generateTicks = (method = config.initialGraphSettings.yAxisTickFormat) => { const ticks = {}; diff --git a/src/config/__tests__/product.rhosak.test.js b/src/config/__tests__/product.rhosak.test.js index d2c4ca19d..92daa0cbd 100644 --- a/src/config/__tests__/product.rhosak.test.js +++ b/src/config/__tests__/product.rhosak.test.js @@ -14,10 +14,44 @@ describe('Product RHOSAK config', () => { it('should apply graph configuration', () => { const { initialGraphFilters, initialGraphSettings } = config; - expect(generateChartSettings({ filters: initialGraphFilters })).toMatchSnapshot('filters'); + expect(generateChartSettings({ filters: initialGraphFilters, settings: initialGraphSettings })).toMatchSnapshot( + 'filters' + ); expect(initialGraphSettings).toMatchSnapshot('settings'); }); + it('should handle metric card display for graphs', () => { + const { initialGraphFilters, initialGraphSettings } = config; + const { filtersSettings } = generateChartSettings({ filters: initialGraphFilters, settings: initialGraphSettings }); + const cardOutput = []; + + filtersSettings.forEach(({ settings }) => { + if (Array.isArray(settings.cards)) { + settings.cards.forEach(({ header, body, footer }) => { + if (typeof header === 'function') { + cardOutput.push(header()); + } else { + cardOutput.push(header); + } + + if (typeof body === 'function') { + cardOutput.push(body()); + } else { + cardOutput.push(body); + } + + if (typeof footer === 'function') { + cardOutput.push(footer({ dailyDate: '09 Mar 2023', monthlyDate: '09 Mar 2023' })); + } else { + cardOutput.push(footer); + } + }); + } + }); + + expect(cardOutput).toMatchSnapshot('cards'); + }); + it('should handle a custom yAxisTickFormat for floating points', () => { const generateTicks = (method = config.initialGraphSettings.yAxisTickFormat) => { const ticks = {}; diff --git a/src/config/__tests__/product.satellite.test.js b/src/config/__tests__/product.satellite.test.js index 15efa1e36..d7d1a1484 100644 --- a/src/config/__tests__/product.satellite.test.js +++ b/src/config/__tests__/product.satellite.test.js @@ -13,7 +13,9 @@ describe('Product Satellite config', () => { it('should apply graph configuration', () => { const { initialGraphFilters, initialGraphSettings } = config; - expect(generateChartSettings({ filters: initialGraphFilters })).toMatchSnapshot('filters'); + expect(generateChartSettings({ filters: initialGraphFilters, settings: initialGraphSettings })).toMatchSnapshot( + 'filters' + ); expect(initialGraphSettings).toMatchSnapshot('settings'); }); diff --git a/src/config/product.rhacs.js b/src/config/product.rhacs.js index c5ee01036..506fde766 100644 --- a/src/config/product.rhacs.js +++ b/src/config/product.rhacs.js @@ -74,7 +74,63 @@ const config = { } ], initialGraphSettings: { - isMetricDisplay: true, + cards: [ + { + header: ({ metricId } = {}) => + translate('curiosity-graph.cardHeadingMetric', { + context: ['dailyTotal', metricId], + testId: 'graphDailyTotalCard-header' + }), + body: ({ dailyHasData, dailyValue, metricId } = {}) => + translate( + 'curiosity-graph.cardBodyMetric', + { + context: ['total', dailyHasData && metricId], + testId: 'graphDailyTotalCard-body', + total: helpers + .numberDisplay(dailyValue) + ?.format({ + average: true, + mantissa: 5, + trimMantissa: true, + lowPrecision: false + }) + ?.toUpperCase() + }, + [] + ), + footer: ({ dailyDate } = {}) => + translate('curiosity-graph.cardFooterMetric', { + date: moment.utc(dailyDate).format(dateHelpers.timestampUTCTimeFormats.yearTimeShort), + testId: 'graphDailyTotalCard-footer' + }) + }, + { + header: ({ metricId } = {}) => + translate('curiosity-graph.cardHeadingMetric', { + context: ['monthlyTotal', metricId], + testId: 'graphMonthlyTotalCard-header' + }), + body: ({ metricId, monthlyHasData, monthlyValue } = {}) => + translate( + 'curiosity-graph.cardBodyMetric', + { + context: ['total', monthlyHasData && metricId], + testId: 'graphMonthlyTotalCard-body', + total: helpers + .numberDisplay(monthlyValue) + ?.format({ average: true, mantissa: 5, trimMantissa: true, lowPrecision: false }) + ?.toUpperCase() + }, + [] + ), + footer: ({ monthlyDate } = {}) => + translate('curiosity-graph.cardFooterMetric', { + date: moment.utc(monthlyDate).format(dateHelpers.timestampUTCTimeFormats.yearTimeShort), + testId: 'graphMonthlyTotalCard-footer' + }) + } + ], isCardTitleDescription: true, xAxisChartLabel: () => translate('curiosity-graph.label_axisX', { context: GRANULARITY_TYPES.DAILY }), yAxisTickFormat: ({ tick }) => { diff --git a/src/config/product.rhods.js b/src/config/product.rhods.js index abba8747a..96814c360 100644 --- a/src/config/product.rhods.js +++ b/src/config/product.rhods.js @@ -69,7 +69,63 @@ const config = { } ], initialGraphSettings: { - isMetricDisplay: true, + cards: [ + { + header: ({ metricId } = {}) => + translate('curiosity-graph.cardHeadingMetric', { + context: ['dailyTotal', metricId], + testId: 'graphDailyTotalCard-header' + }), + body: ({ dailyHasData, dailyValue, metricId } = {}) => + translate( + 'curiosity-graph.cardBodyMetric', + { + context: ['total', dailyHasData && metricId], + testId: 'graphDailyTotalCard-body', + total: helpers + .numberDisplay(dailyValue) + ?.format({ + average: true, + mantissa: 5, + trimMantissa: true, + lowPrecision: false + }) + ?.toUpperCase() + }, + [] + ), + footer: ({ dailyDate } = {}) => + translate('curiosity-graph.cardFooterMetric', { + date: moment.utc(dailyDate).format(dateHelpers.timestampUTCTimeFormats.yearTimeShort), + testId: 'graphDailyTotalCard-footer' + }) + }, + { + header: ({ metricId } = {}) => + translate('curiosity-graph.cardHeadingMetric', { + context: ['monthlyTotal', metricId], + testId: 'graphMonthlyTotalCard-header' + }), + body: ({ metricId, monthlyHasData, monthlyValue } = {}) => + translate( + 'curiosity-graph.cardBodyMetric', + { + context: ['total', monthlyHasData && metricId], + testId: 'graphMonthlyTotalCard-body', + total: helpers + .numberDisplay(monthlyValue) + ?.format({ average: true, mantissa: 5, trimMantissa: true, lowPrecision: false }) + ?.toUpperCase() + }, + [] + ), + footer: ({ monthlyDate } = {}) => + translate('curiosity-graph.cardFooterMetric', { + date: moment.utc(monthlyDate).format(dateHelpers.timestampUTCTimeFormats.yearTimeShort), + testId: 'graphMonthlyTotalCard-footer' + }) + } + ], isCardTitleDescription: true, xAxisChartLabel: () => translate('curiosity-graph.label_axisX', { context: GRANULARITY_TYPES.DAILY }), yAxisTickFormat: ({ tick }) => { diff --git a/src/config/product.rhosak.js b/src/config/product.rhosak.js index 047b643dc..67bacd32a 100644 --- a/src/config/product.rhosak.js +++ b/src/config/product.rhosak.js @@ -96,7 +96,63 @@ const config = { } ], initialGraphSettings: { - isMetricDisplay: true, + cards: [ + { + header: ({ metricId } = {}) => + translate('curiosity-graph.cardHeadingMetric', { + context: ['dailyTotal', metricId], + testId: 'graphDailyTotalCard-header' + }), + body: ({ dailyHasData, dailyValue, metricId } = {}) => + translate( + 'curiosity-graph.cardBodyMetric', + { + context: ['total', dailyHasData && metricId], + testId: 'graphDailyTotalCard-body', + total: helpers + .numberDisplay(dailyValue) + ?.format({ + average: true, + mantissa: 5, + trimMantissa: true, + lowPrecision: false + }) + ?.toUpperCase() + }, + [] + ), + footer: ({ dailyDate } = {}) => + translate('curiosity-graph.cardFooterMetric', { + date: moment.utc(dailyDate).format(dateHelpers.timestampUTCTimeFormats.yearTimeShort), + testId: 'graphDailyTotalCard-footer' + }) + }, + { + header: ({ metricId } = {}) => + translate('curiosity-graph.cardHeadingMetric', { + context: ['monthlyTotal', metricId], + testId: 'graphMonthlyTotalCard-header' + }), + body: ({ metricId, monthlyHasData, monthlyValue } = {}) => + translate( + 'curiosity-graph.cardBodyMetric', + { + context: ['total', monthlyHasData && metricId], + testId: 'graphMonthlyTotalCard-body', + total: helpers + .numberDisplay(monthlyValue) + ?.format({ average: true, mantissa: 5, trimMantissa: true, lowPrecision: false }) + ?.toUpperCase() + }, + [] + ), + footer: ({ monthlyDate } = {}) => + translate('curiosity-graph.cardFooterMetric', { + date: moment.utc(monthlyDate).format(dateHelpers.timestampUTCTimeFormats.yearTimeShort), + testId: 'graphMonthlyTotalCard-footer' + }) + } + ], isCardTitleDescription: true, xAxisChartLabel: () => translate('curiosity-graph.label_axisX', { context: GRANULARITY_TYPES.DAILY }), yAxisTickFormat: ({ tick }) => {