diff --git a/src/components/README.md b/src/components/README.md
index fe87b71a2..011df2437 100644
--- a/src/components/README.md
+++ b/src/components/README.md
@@ -369,9 +369,9 @@ Render banner messages.
props object
- props.messages Array
+ props.useBannerMessages function
- props.useGetAppMessages function
+ props.useRemoveBannerMessages function
@@ -395,10 +395,18 @@ Default props.
## BannerMessagesContext
-
-### BannerMessagesContext~useGetAppMessages(options) ⇒ Object
-Get app messages.
+* [BannerMessagesContext](#BannerMessages.module_BannerMessagesContext)
+ * [~useBannerMessages(options)](#BannerMessages.module_BannerMessagesContext..useBannerMessages) ⇒ Object
+ * [~useRemoveBannerMessages(options)](#BannerMessages.module_BannerMessagesContext..useRemoveBannerMessages) ⇒ function
+ * [~useSetBannerMessages(options)](#BannerMessages.module_BannerMessagesContext..useSetBannerMessages) ⇒ function
+ * [~removeBannerMessages](#BannerMessages.module_BannerMessagesContext..removeBannerMessages) : function
+ * [~setBannerMessages](#BannerMessages.module_BannerMessagesContext..setBannerMessages) : function
+
+
+
+### BannerMessagesContext~useBannerMessages(options) ⇒ Object
+Retrieve, set and remove application banner messages from state.
**Kind**: inner method of [BannerMessagesContext
](#BannerMessages.module_BannerMessagesContext)
@@ -411,15 +419,93 @@ Get app messages.
options object
- options.getMessageReports function
+ options.useProduct function
+
+ options.useSelector function
+
+
+
+
+
+### BannerMessagesContext~useRemoveBannerMessages(options) ⇒ function
+Provide a callback for removing application banner messages from state.
+
+**Kind**: inner method of [BannerMessagesContext
](#BannerMessages.module_BannerMessagesContext)
+
+
+
+ Param Type
+
+
+
+
+ options object
options.useDispatch function
options.useProduct function
- options.useProductQuery function
+ options.useBannerMessages function
+
+
+
+
+
+### BannerMessagesContext~useSetBannerMessages(options) ⇒ function
+Provide a callback for setting application banner messages from state.
+
+**Kind**: inner method of [BannerMessagesContext
](#BannerMessages.module_BannerMessagesContext)
+
+
+
+ Param Type
+
+
+
+
+ options object
- options.useSelectorsResponse function
+ options.useDispatch function
+
+ options.useProduct function
+
+ options.useBannerMessages function
+
+
+
+
+
+### BannerMessagesContext~removeBannerMessages : function
+Remove a banner message from state.
+
+**Kind**: inner typedef of [BannerMessagesContext
](#BannerMessages.module_BannerMessagesContext)
+
+
+
+ Param Type
+
+
+
+
+ idTitle string
+
+
+
+
+
+### BannerMessagesContext~setBannerMessages : function
+Set application messages for banner display
+
+**Kind**: inner typedef of [BannerMessagesContext
](#BannerMessages.module_BannerMessagesContext)
+
+
+
+ Param Type
+
+
+
+
+ messages Array.<{id: string, message: string, title: string, variant: string}>
| Object
diff --git a/src/components/bannerMessages/__tests__/__snapshots__/bannerMessages.test.js.snap b/src/components/bannerMessages/__tests__/__snapshots__/bannerMessages.test.js.snap
index 975a03186..888c643a7 100644
--- a/src/components/bannerMessages/__tests__/__snapshots__/bannerMessages.test.js.snap
+++ b/src/components/bannerMessages/__tests__/__snapshots__/bannerMessages.test.js.snap
@@ -1,295 +1,323 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`BannerMessages Component should handle closing messages from state: state messages, OFF 1`] = `null`;
+exports[`BannerMessages Component should handle closing messages from state: state messages, OFF id 1`] = `
+[
+ [
+ "loremIpsum",
+ ],
+]
+`;
exports[`BannerMessages Component should handle closing messages from state: state messages, ON 1`] = `
-
- }
- key="dolorSit"
- title="Dolor sit title"
- variant="info"
+
-
-
-
-
-
-
- Info alert:
-
- Dolor sit title
-
-
+
+
+
+ Info alert:
+
+ Lorem ipsum title
+
+
-
- Dolor sit message
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Lorem ipsum message
+
+
+
+
+
+
+
`;
exports[`BannerMessages Component should render a basic component: basic 1`] = `
-
- }
- key="loremIpsum"
- title="Lorem ipsum title"
- variant="info"
+
-
-
-
-
-
-
- Info alert:
-
- Lorem ipsum title
-
-
+
+
+
+ Info alert:
+
+ Lorem ipsum title
+
+
-
- Lorem ipsum message
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Lorem ipsum message
+
+
+
+
+
+
+
`;
diff --git a/src/components/bannerMessages/__tests__/__snapshots__/bannerMessagesContext.test.js.snap b/src/components/bannerMessages/__tests__/__snapshots__/bannerMessagesContext.test.js.snap
index 7d6f3c91c..0622a31d6 100644
--- a/src/components/bannerMessages/__tests__/__snapshots__/bannerMessagesContext.test.js.snap
+++ b/src/components/bannerMessages/__tests__/__snapshots__/bannerMessagesContext.test.js.snap
@@ -1,51 +1,51 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`BannerMessagesContext should apply a hook for retrieving messages data from a selectors: error response 1`] = `
-{
- "data": {
- "cloudigradeMismatch": false,
- },
- "error": true,
- "fulfilled": undefined,
- "pending": undefined,
-}
+exports[`BannerMessagesContext should apply a hook for retrieving messages data from a selector and apply new messages: dispatch 1`] = `
+[
+ [
+ {
+ "bannerMessages": [
+ {
+ "id": "lorem",
+ "title": "ipsum",
+ },
+ {
+ "id": "new message",
+ "title": "new message",
+ },
+ ],
+ "type": "SET_BANNER_MESSAGES",
+ "viewId": "dolorSit",
+ },
+ ],
+]
`;
-exports[`BannerMessagesContext should apply a hook for retrieving messages data from a selectors: mock store error response 1`] = `
-{
- "data": {
- "cloudigradeMismatch": false,
- },
- "error": true,
- "fulfilled": false,
- "pending": false,
-}
+exports[`BannerMessagesContext should apply a hook for retrieving messages data from a selector and remove messages: dispatch 1`] = `
+[
+ [
+ {
+ "bannerMessages": [],
+ "type": "SET_BANNER_MESSAGES",
+ "viewId": "dolorSit",
+ },
+ ],
+]
`;
-exports[`BannerMessagesContext should apply a hook for retrieving messages data from a selectors: mock store success response 1`] = `
-{
- "data": {
- "cloudigradeMismatch": true,
+exports[`BannerMessagesContext should apply a hook for retrieving messages data from a selector: banner messages 1`] = `
+[
+ {
+ "id": "lorem",
+ "title": "ipsum",
},
- "error": false,
- "fulfilled": true,
- "pending": false,
-}
-`;
-
-exports[`BannerMessagesContext should apply a hook for retrieving messages data from a selectors: success response 1`] = `
-{
- "data": {
- "cloudigradeMismatch": false,
- },
- "error": undefined,
- "fulfilled": true,
- "pending": undefined,
-}
+]
`;
exports[`BannerMessagesContext should return specific properties: specific properties 1`] = `
{
- "useGetAppMessages": [Function],
+ "useBannerMessages": [Function],
+ "useRemoveBannerMessages": [Function],
+ "useSetBannerMessages": [Function],
}
`;
diff --git a/src/components/bannerMessages/__tests__/bannerMessages.test.js b/src/components/bannerMessages/__tests__/bannerMessages.test.js
index 844f2ac5e..18b432327 100644
--- a/src/components/bannerMessages/__tests__/bannerMessages.test.js
+++ b/src/components/bannerMessages/__tests__/bannerMessages.test.js
@@ -5,18 +5,13 @@ import { BannerMessages } from '../bannerMessages';
describe('BannerMessages Component', () => {
it('should render a basic component', async () => {
const props = {
- messages: [
+ useBannerMessages: () => [
{
id: 'loremIpsum',
title: 'Lorem ipsum title',
message: 'Lorem ipsum message'
}
- ],
- useGetAppMessages: () => ({
- data: {
- loremIpsum: true
- }
- })
+ ]
};
const component = await mountHookComponent( );
@@ -24,15 +19,16 @@ describe('BannerMessages Component', () => {
});
it('should handle closing messages from state', async () => {
+ const mockRemove = jest.fn();
const props = {
- messages: [
+ useBannerMessages: () => [
{
- id: 'dolorSit',
- title: 'Dolor sit title',
- message: 'Dolor sit message'
+ id: 'loremIpsum',
+ title: 'Lorem ipsum title',
+ message: 'Lorem ipsum message'
}
],
- useGetAppMessages: () => ({ data: { dolorSit: true } })
+ useRemoveBannerMessages: () => mockRemove
};
const component = await mountHookComponent( );
@@ -40,6 +36,6 @@ describe('BannerMessages Component', () => {
component.find(AlertActionCloseButton).first().simulate('click');
- expect(component.render()).toMatchSnapshot('state messages, OFF');
+ expect(mockRemove.mock.calls).toMatchSnapshot('state messages, OFF id');
});
});
diff --git a/src/components/bannerMessages/__tests__/bannerMessagesContext.test.js b/src/components/bannerMessages/__tests__/bannerMessagesContext.test.js
index a9045c1cc..884de7a78 100644
--- a/src/components/bannerMessages/__tests__/bannerMessagesContext.test.js
+++ b/src/components/bannerMessages/__tests__/bannerMessagesContext.test.js
@@ -1,86 +1,60 @@
-import { context, useGetAppMessages } from '../bannerMessagesContext';
-import { rhsmConstants } from '../../../services/rhsm/rhsmConstants';
+import { context, useBannerMessages, useRemoveBannerMessages, useSetBannerMessages } from '../bannerMessagesContext';
describe('BannerMessagesContext', () => {
it('should return specific properties', () => {
expect(context).toMatchSnapshot('specific properties');
});
- it('should apply a hook for retrieving messages data from a selectors', () => {
- const { result: errorResponse } = shallowHook(() =>
- useGetAppMessages({
- useSelectorsResponse: () => ({
- error: true,
- data: {
- messages: {}
+ it('should apply a hook for retrieving messages data from a selector', async () => {
+ const { result } = await shallowHook(() =>
+ useBannerMessages({
+ useSelector: () => [
+ {
+ id: 'lorem',
+ title: 'ipsum'
}
- })
+ ]
})
);
- expect(errorResponse).toMatchSnapshot('error response');
+ expect(result).toMatchSnapshot('banner messages');
+ });
- const { result: successResponse } = shallowHook(() =>
- useGetAppMessages({
- useSelectorsResponse: () => ({
- fulfilled: true,
- data: {
- messages: {}
+ it('should apply a hook for retrieving messages data from a selector and apply new messages', async () => {
+ const mockDispatch = jest.fn();
+ const { result } = await mountHook(() =>
+ useSetBannerMessages({
+ useDispatch: () => mockDispatch,
+ useProduct: () => ({ productId: 'dolorSit' }),
+ useBannerMessages: () => [
+ {
+ id: 'lorem',
+ title: 'ipsum'
}
- })
+ ]
})
);
- expect(successResponse).toMatchSnapshot('success response');
-
- const { result: mockStoreSuccessResponse } = shallowHook(
- () =>
- useGetAppMessages({
- useProduct: () => ({ productId: 'loremIpsum' })
- }),
- {
- state: {
- messages: {
- report: {
- loremIpsum: {
- fulfilled: true,
- data: {
- data: [
- {
- [rhsmConstants.RHSM_API_RESPONSE_TALLY_CAPACITY_META_TYPES.HAS_CLOUDIGRADE_MISMATCH]: true
- }
- ]
- }
- }
- }
- }
- }
- }
- );
-
- expect(mockStoreSuccessResponse).toMatchSnapshot('mock store success response');
+ result('new message');
+ expect(mockDispatch.mock.calls).toMatchSnapshot('dispatch');
+ });
- const { result: mockStoreErrorResponse } = shallowHook(
- () =>
- useGetAppMessages({
- useProduct: () => ({ productId: 'loremIpsum' })
- }),
- {
- state: {
- messages: {
- report: {
- loremIpsum: {
- error: true,
- data: {
- data: []
- }
- }
- }
+ it('should apply a hook for retrieving messages data from a selector and remove messages', async () => {
+ const mockDispatch = jest.fn();
+ const { result } = await mountHook(() =>
+ useRemoveBannerMessages({
+ useDispatch: () => mockDispatch,
+ useProduct: () => ({ productId: 'dolorSit' }),
+ useBannerMessages: () => [
+ {
+ id: 'lorem',
+ title: 'ipsum'
}
- }
- }
+ ]
+ })
);
- expect(mockStoreErrorResponse).toMatchSnapshot('mock store error response');
+ result('ipsum');
+ expect(mockDispatch.mock.calls).toMatchSnapshot('dispatch');
});
});
diff --git a/src/components/bannerMessages/bannerMessages.js b/src/components/bannerMessages/bannerMessages.js
index f4c82e5f9..3cdb0185b 100644
--- a/src/components/bannerMessages/bannerMessages.js
+++ b/src/components/bannerMessages/bannerMessages.js
@@ -1,11 +1,7 @@
-import React, { useState } from 'react';
+import React from 'react';
import PropTypes from 'prop-types';
-import { Alert, AlertActionCloseButton, AlertVariant, Button } from '@patternfly/react-core';
-import { ExternalLinkAltIcon } from '@patternfly/react-icons';
-import { useShallowCompareEffect } from 'react-use';
-import { useGetAppMessages } from './bannerMessagesContext';
-import { helpers } from '../../common';
-import { translate } from '../i18n/i18n';
+import { Alert, AlertActionCloseButton, AlertGroup, AlertVariant } from '@patternfly/react-core';
+import { useBannerMessages, useRemoveBannerMessages } from './bannerMessagesContext';
/**
* Banner alert messages for a product view.
@@ -19,48 +15,33 @@ import { translate } from '../i18n/i18n';
* Render banner messages.
*
* @param {object} props
- * @param {Array} props.messages
- * @param {Function} props.useGetAppMessages
+ * @param {Function} props.useBannerMessages
+ * @param {Function} props.useRemoveBannerMessages
* @returns {React.ReactNode}
*/
-const BannerMessages = ({ messages, useGetAppMessages: useAliasGetAppMessages }) => {
- const [hideAlerts, setHideAlerts] = useState({});
- const [alerts, setAlerts] = useState([]);
- const { data: appMessages } = useAliasGetAppMessages();
+const BannerMessages = ({
+ useBannerMessages: useAliasBannerMessages,
+ useRemoveBannerMessages: useAliasRemoveBannerMessages
+}) => {
+ const bannerMessages = useAliasBannerMessages();
+ const removeBannerMessages = useAliasRemoveBannerMessages();
- useShallowCompareEffect(() => {
- const updatedMessages = [];
+ if (bannerMessages?.length) {
+ return (
+
+
+ {bannerMessages?.map(({ id, message, title, variant = AlertVariant.info }) => {
+ const actionClose = removeBannerMessages(id || title)} />;
- if (messages.length) {
- Object.entries(appMessages).forEach(([key, value]) => {
- if (hideAlerts[key] !== true && value === true) {
- const message = messages.find(({ id }) => id === key);
-
- if (message) {
- updatedMessages.push({
- key,
- ...message
- });
- }
- }
- });
- }
-
- setAlerts(
- updatedMessages.map(({ key, message, title, variant = AlertVariant.info }) => {
- const actionClose = setHideAlerts({ ...hideAlerts, [key]: true })} />;
-
- return (
-
- {message}
-
- );
- })
+ return (
+
+ {message}
+
+ );
+ })}
+
+
);
- }, [appMessages, hideAlerts, messages]);
-
- if (alerts?.length) {
- return {alerts}
;
}
return null;
@@ -69,51 +50,21 @@ const BannerMessages = ({ messages, useGetAppMessages: useAliasGetAppMessages })
/**
* Prop types.
*
- * @type {{useGetAppMessages: Function, messages: Array}}
+ * @type {{useBannerMessages: Function, useRemoveBannerMessages: Function}}
*/
BannerMessages.propTypes = {
- messages: PropTypes.arrayOf(
- PropTypes.shape({
- id: PropTypes.string.isRequired,
- title: PropTypes.node.isRequired,
- message: PropTypes.node.isRequired,
- variant: PropTypes.oneOf([...Object.values(AlertVariant)])
- })
- ),
- useGetAppMessages: PropTypes.func
+ useBannerMessages: PropTypes.func,
+ useRemoveBannerMessages: PropTypes.func
};
/**
* Default props.
*
- * @type {{useGetAppMessages: Function, messages: Array}}
+ * @type {{useBannerMessages: Function, useRemoveBannerMessages: Function}}
*/
BannerMessages.defaultProps = {
- messages: [
- {
- id: 'cloudigradeMismatch',
- title: translate('curiosity-banner.dataMismatchTitle'),
- message: translate(
- 'curiosity-banner.dataMismatchMessage',
- {
- context: helpers.UI_LINK_REPORT_ACCURACY_RECOMMENDATIONS !== '' && 'cloudigradeMismatch',
- appName: helpers.UI_DISPLAY_NAME
- },
- [
- }
- iconPosition="right"
- target="_blank"
- href={helpers.UI_LINK_REPORT_ACCURACY_RECOMMENDATIONS}
- />
- ]
- )
- }
- ],
- useGetAppMessages
+ useBannerMessages,
+ useRemoveBannerMessages
};
export { BannerMessages as default, BannerMessages };
diff --git a/src/components/bannerMessages/bannerMessagesContext.js b/src/components/bannerMessages/bannerMessagesContext.js
index a9a0ee01b..fc2d86a52 100644
--- a/src/components/bannerMessages/bannerMessagesContext.js
+++ b/src/components/bannerMessages/bannerMessagesContext.js
@@ -1,12 +1,7 @@
-import { useShallowCompareEffect } from 'react-use';
-import { reduxActions, storeHooks } from '../../redux';
-import { useProduct, useProductQuery } from '../productView/productViewContext';
-import { dateHelpers } from '../../common';
-import {
- rhsmConstants,
- RHSM_API_QUERY_GRANULARITY_TYPES as GRANULARITY_TYPES,
- RHSM_API_QUERY_SET_TYPES
-} from '../../services/rhsm/rhsmConstants';
+import { useCallback } from 'react';
+import { reduxTypes, storeHooks } from '../../redux';
+import { useProduct } from '../productView/productViewContext';
+import { helpers } from '../../common/helpers';
/**
* @memberof BannerMessages
@@ -14,78 +9,127 @@ import {
*/
/**
- * ToDo: useGetAppMessages is setup to work with existing Tally response, pre-metrics
- * Banner messages scans the returned Tally listing for the HAS_CLOUDIGRADE_MISMATCH. In the future
- * this may need to be updated to pull from the "meta" object part of the Tally response.
+ * Retrieve, set and remove application banner messages from state.
+ *
+ * @param {object} options
+ * @param {Function} options.useProduct
+ * @param {Function} options.useSelector
+ * @returns {{ bannerMessages: Array, setBannerMessages: Function, removeBannerMessages: Function }}
*/
+const useBannerMessages = ({
+ useProduct: useAliasProduct = useProduct,
+ useSelector: useAliasSelector = storeHooks.reactRedux.useSelector
+} = {}) => {
+ const { productId } = useAliasProduct();
+ return useAliasSelector(({ messages }) => messages?.bannerMessages?.[productId], []);
+};
+
/**
- * Get app messages.
+ * Provide a callback for removing application banner messages from state.
*
* @param {object} options
- * @param {Function} options.getMessageReports
* @param {Function} options.useDispatch
* @param {Function} options.useProduct
- * @param {Function} options.useProductQuery
- * @param {Function} options.useSelectorsResponse
- * @returns {{data: {cloudigradeMismatch: boolean}, pending: boolean, fulfilled: boolean, error: boolean}}
+ * @param {Function} options.useBannerMessages
+ * @returns {Function}
*/
-const useGetAppMessages = ({
- getMessageReports = reduxActions.rhsm.getMessageReports,
+const useRemoveBannerMessages = ({
useDispatch: useAliasDispatch = storeHooks.reactRedux.useDispatch,
useProduct: useAliasProduct = useProduct,
- useProductQuery: useAliasProductQuery = useProductQuery,
- useSelectorsResponse: useAliasSelectorsResponse = storeHooks.reactRedux.useSelectorsResponse
+ useBannerMessages: useAliasBannerMessages = useBannerMessages
} = {}) => {
- const { productId } = useAliasProduct();
- const query = useAliasProductQuery();
const dispatch = useAliasDispatch();
- const { error, fulfilled, pending, data } = useAliasSelectorsResponse({
- id: 'messages',
- selector: ({ messages }) => messages?.report?.[productId]
- });
+ const { productId } = useAliasProduct();
+ const bannerMessages = useAliasBannerMessages();
+
+ /**
+ * Remove a banner message from state.
+ *
+ * @callback removeBannerMessages
+ * @param {string} idTitle
+ */
+ return useCallback(
+ idTitle => {
+ if (productId && Array.isArray(bannerMessages) && bannerMessages.length) {
+ const filteredMessages = bannerMessages.filter(({ id, title }) => id !== idTitle && title !== idTitle);
- useShallowCompareEffect(() => {
- if (productId) {
- const { startDate, endDate } = dateHelpers.getRangedDateTime('CURRENT');
- const updatedQuery = {
- ...query,
- [RHSM_API_QUERY_SET_TYPES.GRANULARITY]: GRANULARITY_TYPES.DAILY,
- [RHSM_API_QUERY_SET_TYPES.START_DATE]: startDate.toISOString(),
- [RHSM_API_QUERY_SET_TYPES.END_DATE]: endDate.toISOString()
- };
+ dispatch({
+ type: reduxTypes.message.SET_BANNER_MESSAGES,
+ viewId: productId,
+ bannerMessages: filteredMessages || []
+ });
+ }
+ },
+ [bannerMessages, dispatch, productId]
+ );
+};
- getMessageReports(productId, updatedQuery)(dispatch);
- }
- }, [productId, query]);
+/**
+ * Provide a callback for setting application banner messages from state.
+ *
+ * @param {object} options
+ * @param {Function} options.useDispatch
+ * @param {Function} options.useProduct
+ * @param {Function} options.useBannerMessages
+ * @returns {Function}
+ */
+const useSetBannerMessages = ({
+ useDispatch: useAliasDispatch = storeHooks.reactRedux.useDispatch,
+ useProduct: useAliasProduct = useProduct,
+ useBannerMessages: useAliasBannerMessages = useBannerMessages
+} = {}) => {
+ const dispatch = useAliasDispatch();
+ const { productId } = useAliasProduct();
+ const bannerMessages = useAliasBannerMessages();
- const updatedData = {
- cloudigradeMismatch: false
- };
+ /**
+ * Set application messages for banner display
+ *
+ * @callback setBannerMessages
+ * @param {Array<{ id: string, message: string, title: string, variant: string }>|{ id: string, message: string, title: string, variant: string }} messages
+ */
+ return useCallback(
+ messages => {
+ if (productId) {
+ const updatedMessages = (Array.isArray(messages) && messages) || [messages];
- if (fulfilled) {
- const { messages = {} } = data || {};
+ dispatch({
+ type: reduxTypes.message.SET_BANNER_MESSAGES,
+ viewId: productId,
+ bannerMessages: [
+ ...(bannerMessages || []),
+ ...updatedMessages
+ .map(value => {
+ if (value?.id || value?.title || value?.message || value?.variant) {
+ return value;
+ }
- updatedData.cloudigradeMismatch =
- messages?.data
- ?.reverse()
- ?.find(
- ({ [rhsmConstants.RHSM_API_RESPONSE_TALLY_CAPACITY_META_TYPES.HAS_CLOUDIGRADE_MISMATCH]: mismatch }) =>
- mismatch === true
- ) !== undefined;
- }
+ if (typeof value === 'string' || typeof value === 'number') {
+ return {
+ id: value,
+ title: value
+ };
+ }
- return {
- error,
- fulfilled,
- pending,
- data: {
- ...updatedData
- }
- };
+ return undefined;
+ })
+ .filter(value => value !== undefined)
+ ]
+ });
+ } else if (helpers.DEV_MODE) {
+ console.warn(
+ 'Banner messages currently require the use of "product id". Product context is unavailable, try moving your banner message "set" lower in the component order.'
+ );
+ }
+ },
+ [bannerMessages, dispatch, productId]
+ );
};
const context = {
- useGetAppMessages
+ useBannerMessages,
+ useRemoveBannerMessages,
+ useSetBannerMessages
};
-export { context as default, context, useGetAppMessages };
+export { context as default, context, useBannerMessages, useRemoveBannerMessages, useSetBannerMessages };
diff --git a/src/components/i18n/__tests__/__snapshots__/i18n.test.js.snap b/src/components/i18n/__tests__/__snapshots__/i18n.test.js.snap
index 98210daea..5aae095d9 100644
--- a/src/components/i18n/__tests__/__snapshots__/i18n.test.js.snap
+++ b/src/components/i18n/__tests__/__snapshots__/i18n.test.js.snap
@@ -28,19 +28,6 @@ exports[`I18n Component should generate a predictable locale key output snapshot
},
],
},
- {
- "file": "./src/components/bannerMessages/bannerMessages.js",
- "keys": [
- {
- "key": "curiosity-banner.dataMismatchTitle",
- "match": "translate('curiosity-banner.dataMismatchTitle')",
- },
- {
- "key": "curiosity-banner.dataMismatchMessage",
- "match": "translate( 'curiosity-banner.dataMismatchMessage', { context: helpers.UI_LINK_REPORT_ACCURACY_RECOMMENDATIONS !== '' && 'cloudigradeMismatch', appName: helpers.UI_DISPLAY_NAME }, [ } iconPosition="right" target="_blank" href={helpers.UI_LINK_REPORT_ACCURACY_RECOMMENDATIONS} /> ] )",
- },
- ],
- },
{
"file": "./src/components/graphCard/graphCardChart.js",
"keys": [
diff --git a/src/components/productView/__tests__/__snapshots__/productView.test.js.snap b/src/components/productView/__tests__/__snapshots__/productView.test.js.snap
index 1f83cd254..c0719f128 100644
--- a/src/components/productView/__tests__/__snapshots__/productView.test.js.snap
+++ b/src/components/productView/__tests__/__snapshots__/productView.test.js.snap
@@ -28,16 +28,8 @@ exports[`ProductView Component should allow custom inventory displays via config
className=""
>
+ >
+
+
@@ -350,16 +331,8 @@ exports[`ProductView Component should allow custom product views via productDisp
className=""
>
{
return (
- {productDisplay !== DISPLAY_TYPES.HOURLY && }
+
+
+
diff --git a/src/redux/README.md b/src/redux/README.md
index 9f280a98a..c09e78029 100644
--- a/src/redux/README.md
+++ b/src/redux/README.md
@@ -48,6 +48,8 @@
InventoryTypes
+MessageTypes
+
PlatformTypes
QueryTypes
@@ -189,7 +191,6 @@ RHSM service wrappers for dispatch, state update.
* [~getHostsInventory(id, query)](#Actions.module_RhsmActions..getHostsInventory) ⇒ function
* [~getHostsInventoryGuests(id, query)](#Actions.module_RhsmActions..getHostsInventoryGuests) ⇒ function
* [~getInstancesInventory(id, query)](#Actions.module_RhsmActions..getInstancesInventory) ⇒ function
- * [~getMessageReports(id, query)](#Actions.module_RhsmActions..getMessageReports) ⇒ function
* [~getSubscriptionsInventory(id, query)](#Actions.module_RhsmActions..getSubscriptionsInventory) ⇒ function
@@ -277,26 +278,6 @@ Get an instances response listing from RHSM subscriptions.
-
-
-### RhsmActions~getMessageReports(id, query) ⇒ function
-Get a RHSM response from message reporting.
-
-**Kind**: inner method of [RhsmActions
](#Actions.module_RhsmActions)
-
-
-
- Param Type Default
-
-
-
-
- id string
null
-
- query object
-
-
-
### RhsmActions~getSubscriptionsInventory(id, query) ⇒ function
@@ -1107,7 +1088,7 @@ Banner messages related API state reducer.
### MessagesReducer~messagesReducer(state, action) ⇒ object
\| Object
-Generated daily observer/reducer for report to state,
+Generated daily observer/reducer for messages to state,
against actions.
**Kind**: inner method of [MessagesReducer
](#Reducers.module_MessagesReducer)
@@ -1238,6 +1219,15 @@ Graph action, reducer types.
Inventory action, reducer types.
**Kind**: inner constant of [InventoryTypes
](#Types.module_InventoryTypes)
+
+
+## MessageTypes
+
+
+### MessageTypes~messageTypes : Object
+User action, reducer types.
+
+**Kind**: inner constant of [MessageTypes
](#Types.module_MessageTypes)
## PlatformTypes
diff --git a/src/redux/actions/__tests__/rhsmActions.test.js b/src/redux/actions/__tests__/rhsmActions.test.js
index d1c6a3d9c..7aa1a4416 100644
--- a/src/redux/actions/__tests__/rhsmActions.test.js
+++ b/src/redux/actions/__tests__/rhsmActions.test.js
@@ -2,7 +2,7 @@ import promiseMiddleware from 'redux-promise-middleware';
import { applyMiddleware, combineReducers, legacy_createStore as createStore } from 'redux';
import moxios from 'moxios';
import { multiActionMiddleware } from '../../middleware/multiActionMiddleware';
-import { graphReducer, inventoryReducer, messagesReducer, viewReducer } from '../../reducers';
+import { graphReducer, inventoryReducer, viewReducer } from '../../reducers';
import { rhsmConstants } from '../../../services/rhsm/rhsmConstants';
import { rhsmActions } from '../rhsmActions';
@@ -13,7 +13,6 @@ describe('RhsmActions', () => {
combineReducers({
graph: graphReducer,
inventory: inventoryReducer,
- messages: messagesReducer,
view: viewReducer
}),
applyMiddleware(...middleware)
@@ -92,17 +91,6 @@ describe('RhsmActions', () => {
});
});
- it('Should return response content for getMessageReports method', done => {
- const store = generateStore();
- const dispatcher = rhsmActions.getMessageReports();
-
- dispatcher(store.dispatch).then(() => {
- const response = store.getState().messages;
- expect(response.report.fulfilled).toBe(true);
- done();
- });
- });
-
it('Should return response content for getSubscriptionsInventory method', done => {
const store = generateStore();
const dispatcher = rhsmActions.getSubscriptionsInventory();
diff --git a/src/redux/actions/rhsmActions.js b/src/redux/actions/rhsmActions.js
index d42dfe475..b5cd38c3a 100644
--- a/src/redux/actions/rhsmActions.js
+++ b/src/redux/actions/rhsmActions.js
@@ -111,26 +111,6 @@ const getInstancesInventory =
}
});
-/**
- * Get a RHSM response from message reporting.
- *
- * @param {string} id
- * @param {object} query
- * @returns {Function}
- */
-const getMessageReports =
- (id = null, query = {}) =>
- dispatch =>
- dispatch({
- type: rhsmTypes.GET_MESSAGE_REPORTS_RHSM,
- payload: rhsmServices.getGraphReports(id, query, { cancelId: 'messageReport' }),
- meta: {
- id,
- query,
- notifications: {}
- }
- });
-
/**
* Get a subscriptions response from RHSM subscriptions.
*
@@ -156,7 +136,6 @@ const rhsmActions = {
getHostsInventory,
getHostsInventoryGuests,
getInstancesInventory,
- getMessageReports,
getSubscriptionsInventory
};
@@ -167,6 +146,5 @@ export {
getHostsInventory,
getHostsInventoryGuests,
getInstancesInventory,
- getMessageReports,
getSubscriptionsInventory
};
diff --git a/src/redux/reducers/__tests__/__snapshots__/messagesReducer.test.js.snap b/src/redux/reducers/__tests__/__snapshots__/messagesReducer.test.js.snap
index 4dd32b0c0..dfba83713 100644
--- a/src/redux/reducers/__tests__/__snapshots__/messagesReducer.test.js.snap
+++ b/src/redux/reducers/__tests__/__snapshots__/messagesReducer.test.js.snap
@@ -1,52 +1,14 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`MessagesReducer should handle all defined error types: rejected types GET_MESSAGE_REPORTS_RHSM 1`] = `
+exports[`MessagesReducer should handle specific defined types: defined type SET_BANNER_MESSAGES 1`] = `
{
"result": {
- "report": {
- "error": true,
- "errorMessage": "MESSAGE",
- "fulfilled": false,
- "meta": {},
- "pending": false,
- "status": 0,
+ "bannerMessages": {
+ "test_id": [
+ "lorem",
+ ],
},
},
- "type": "GET_MESSAGE_REPORTS_RHSM_REJECTED",
-}
-`;
-
-exports[`MessagesReducer should handle all defined fulfilled types: fulfilled types GET_MESSAGE_REPORTS_RHSM 1`] = `
-{
- "result": {
- "report": {
- "data": {
- "test": "success",
- },
- "date": null,
- "error": false,
- "errorMessage": "",
- "fulfilled": true,
- "meta": {},
- "pending": false,
- "status": 0,
- },
- },
- "type": "GET_MESSAGE_REPORTS_RHSM_FULFILLED",
-}
-`;
-
-exports[`MessagesReducer should handle all defined pending types: pending types GET_MESSAGE_REPORTS_RHSM 1`] = `
-{
- "result": {
- "report": {
- "error": false,
- "errorMessage": "",
- "fulfilled": false,
- "meta": {},
- "pending": true,
- },
- },
- "type": "GET_MESSAGE_REPORTS_RHSM_PENDING",
+ "type": "SET_BANNER_MESSAGES",
}
`;
diff --git a/src/redux/reducers/__tests__/messagesReducer.test.js b/src/redux/reducers/__tests__/messagesReducer.test.js
index 67fbb7b1e..072df4993 100644
--- a/src/redux/reducers/__tests__/messagesReducer.test.js
+++ b/src/redux/reducers/__tests__/messagesReducer.test.js
@@ -1,73 +1,24 @@
import messagesReducer from '../messagesReducer';
-import { rhsmTypes as types } from '../../types';
-import { reduxHelpers } from '../../common/reduxHelpers';
+import { messageTypes as types } from '../../types';
describe('MessagesReducer', () => {
it('should return the initial state', () => {
expect(messagesReducer.initialState).toBeDefined();
});
- it('should handle all defined error types', () => {
- const specificTypes = [types.GET_MESSAGE_REPORTS_RHSM];
+ it('should handle specific defined types', () => {
+ const specificTypes = [types.SET_BANNER_MESSAGES];
specificTypes.forEach(value => {
const dispatched = {
- type: reduxHelpers.REJECTED_ACTION(value),
- error: true,
- payload: {
- message: 'MESSAGE',
- response: {
- status: 0,
- statusText: 'ERROR TEST',
- data: {
- detail: 'ERROR'
- }
- }
- }
+ type: value,
+ bannerMessages: ['lorem'],
+ viewId: 'test_id'
};
const resultState = messagesReducer(undefined, dispatched);
- expect({ type: reduxHelpers.REJECTED_ACTION(value), result: resultState }).toMatchSnapshot(
- `rejected types ${value}`
- );
- });
- });
-
- it('should handle all defined pending types', () => {
- const specificTypes = [types.GET_MESSAGE_REPORTS_RHSM];
-
- specificTypes.forEach(value => {
- const dispatched = {
- type: reduxHelpers.PENDING_ACTION(value)
- };
-
- const resultState = messagesReducer(undefined, dispatched);
-
- expect({ type: reduxHelpers.PENDING_ACTION(value), result: resultState }).toMatchSnapshot(
- `pending types ${value}`
- );
- });
- });
-
- it('should handle all defined fulfilled types', () => {
- const specificTypes = [types.GET_MESSAGE_REPORTS_RHSM];
-
- specificTypes.forEach(value => {
- const dispatched = {
- type: reduxHelpers.FULFILLED_ACTION(value),
- payload: {
- data: {
- test: 'success'
- }
- }
- };
-
- const resultState = messagesReducer(undefined, dispatched);
-
- expect({ type: reduxHelpers.FULFILLED_ACTION(value), result: resultState }).toMatchSnapshot(
- `fulfilled types ${value}`
- );
+ expect({ type: value, result: resultState }).toMatchSnapshot(`defined type ${value}`);
});
});
});
diff --git a/src/redux/reducers/messagesReducer.js b/src/redux/reducers/messagesReducer.js
index d3b982221..3c2f5d086 100644
--- a/src/redux/reducers/messagesReducer.js
+++ b/src/redux/reducers/messagesReducer.js
@@ -1,4 +1,4 @@
-import { rhsmTypes } from '../types';
+import { reduxTypes } from '../types';
import { reduxHelpers } from '../common/reduxHelpers';
/**
@@ -15,23 +15,34 @@ import { reduxHelpers } from '../common/reduxHelpers';
* @type {{report: {}}}
*/
const initialState = {
- report: {}
+ bannerMessages: {}
};
/**
- * Generated daily observer/reducer for report to state,
+ * Generated daily observer/reducer for messages to state,
* against actions.
*
* @param {object} state
* @param {object} action
* @returns {object|{}}
*/
-const messagesReducer = (state = initialState, action) =>
- reduxHelpers.generatedPromiseActionReducer(
- [{ ref: 'report', type: rhsmTypes.GET_MESSAGE_REPORTS_RHSM }],
- state,
- action
- );
+const messagesReducer = (state = initialState, action) => {
+ switch (action.type) {
+ case reduxTypes.message.SET_BANNER_MESSAGES:
+ return reduxHelpers.setStateProp(
+ 'bannerMessages',
+ {
+ [action.viewId]: action.bannerMessages
+ },
+ {
+ state,
+ reset: false
+ }
+ );
+ default:
+ return state;
+ }
+};
messagesReducer.initialState = initialState;
diff --git a/src/redux/types/__tests__/__snapshots__/index.test.js.snap b/src/redux/types/__tests__/__snapshots__/index.test.js.snap
index 77f303c42..58496f41c 100644
--- a/src/redux/types/__tests__/__snapshots__/index.test.js.snap
+++ b/src/redux/types/__tests__/__snapshots__/index.test.js.snap
@@ -20,6 +20,9 @@ exports[`ReduxTypes should have specific type properties: all redux types 1`] =
"CLEAR_INVENTORY_GUESTS": "CLEAR_INVENTORY_GUESTS",
"SET_INVENTORY_TAB": "SET_INVENTORY_TAB",
},
+ "message": {
+ "SET_BANNER_MESSAGES": "SET_BANNER_MESSAGES",
+ },
"platform": {
"PLATFORM_ADD_NOTIFICATION": "@@INSIGHTS-CORE/NOTIFICATIONS/ADD_NOTIFICATION",
"PLATFORM_CLEAR_NOTIFICATIONS": "@@INSIGHTS-CORE/NOTIFICATIONS/CLEAR_NOTIFICATIONS",
@@ -68,7 +71,6 @@ exports[`ReduxTypes should have specific type properties: all redux types 1`] =
"GET_HOSTS_INVENTORY_GUESTS_RHSM": "GET_HOSTS_INVENTORY_GUESTS_RHSM",
"GET_HOSTS_INVENTORY_RHSM": "GET_HOSTS_INVENTORY_RHSM",
"GET_INSTANCES_INVENTORY_RHSM": "GET_INSTANCES_INVENTORY_RHSM",
- "GET_MESSAGE_REPORTS_RHSM": "GET_MESSAGE_REPORTS_RHSM",
"GET_SUBSCRIPTIONS_INVENTORY_RHSM": "GET_SUBSCRIPTIONS_INVENTORY_RHSM",
},
"toolbar": {
@@ -90,6 +92,9 @@ exports[`ReduxTypes should have specific type properties: all redux types 1`] =
"CLEAR_INVENTORY_GUESTS": "CLEAR_INVENTORY_GUESTS",
"SET_INVENTORY_TAB": "SET_INVENTORY_TAB",
},
+ "messageTypes": {
+ "SET_BANNER_MESSAGES": "SET_BANNER_MESSAGES",
+ },
"platformTypes": {
"PLATFORM_ADD_NOTIFICATION": "@@INSIGHTS-CORE/NOTIFICATIONS/ADD_NOTIFICATION",
"PLATFORM_CLEAR_NOTIFICATIONS": "@@INSIGHTS-CORE/NOTIFICATIONS/CLEAR_NOTIFICATIONS",
@@ -144,6 +149,9 @@ exports[`ReduxTypes should have specific type properties: all redux types 1`] =
"CLEAR_INVENTORY_GUESTS": "CLEAR_INVENTORY_GUESTS",
"SET_INVENTORY_TAB": "SET_INVENTORY_TAB",
},
+ "message": {
+ "SET_BANNER_MESSAGES": "SET_BANNER_MESSAGES",
+ },
"platform": {
"PLATFORM_ADD_NOTIFICATION": "@@INSIGHTS-CORE/NOTIFICATIONS/ADD_NOTIFICATION",
"PLATFORM_CLEAR_NOTIFICATIONS": "@@INSIGHTS-CORE/NOTIFICATIONS/CLEAR_NOTIFICATIONS",
@@ -192,7 +200,6 @@ exports[`ReduxTypes should have specific type properties: all redux types 1`] =
"GET_HOSTS_INVENTORY_GUESTS_RHSM": "GET_HOSTS_INVENTORY_GUESTS_RHSM",
"GET_HOSTS_INVENTORY_RHSM": "GET_HOSTS_INVENTORY_RHSM",
"GET_INSTANCES_INVENTORY_RHSM": "GET_INSTANCES_INVENTORY_RHSM",
- "GET_MESSAGE_REPORTS_RHSM": "GET_MESSAGE_REPORTS_RHSM",
"GET_SUBSCRIPTIONS_INVENTORY_RHSM": "GET_SUBSCRIPTIONS_INVENTORY_RHSM",
},
"toolbar": {
@@ -214,7 +221,6 @@ exports[`ReduxTypes should have specific type properties: all redux types 1`] =
"GET_HOSTS_INVENTORY_GUESTS_RHSM": "GET_HOSTS_INVENTORY_GUESTS_RHSM",
"GET_HOSTS_INVENTORY_RHSM": "GET_HOSTS_INVENTORY_RHSM",
"GET_INSTANCES_INVENTORY_RHSM": "GET_INSTANCES_INVENTORY_RHSM",
- "GET_MESSAGE_REPORTS_RHSM": "GET_MESSAGE_REPORTS_RHSM",
"GET_SUBSCRIPTIONS_INVENTORY_RHSM": "GET_SUBSCRIPTIONS_INVENTORY_RHSM",
},
"toolbarTypes": {
@@ -245,6 +251,9 @@ exports[`ReduxTypes should have specific type properties: specific types 1`] = `
"CLEAR_INVENTORY_GUESTS": "CLEAR_INVENTORY_GUESTS",
"SET_INVENTORY_TAB": "SET_INVENTORY_TAB",
},
+ "message": {
+ "SET_BANNER_MESSAGES": "SET_BANNER_MESSAGES",
+ },
"platform": {
"PLATFORM_ADD_NOTIFICATION": "@@INSIGHTS-CORE/NOTIFICATIONS/ADD_NOTIFICATION",
"PLATFORM_CLEAR_NOTIFICATIONS": "@@INSIGHTS-CORE/NOTIFICATIONS/CLEAR_NOTIFICATIONS",
@@ -293,7 +302,6 @@ exports[`ReduxTypes should have specific type properties: specific types 1`] = `
"GET_HOSTS_INVENTORY_GUESTS_RHSM": "GET_HOSTS_INVENTORY_GUESTS_RHSM",
"GET_HOSTS_INVENTORY_RHSM": "GET_HOSTS_INVENTORY_RHSM",
"GET_INSTANCES_INVENTORY_RHSM": "GET_INSTANCES_INVENTORY_RHSM",
- "GET_MESSAGE_REPORTS_RHSM": "GET_MESSAGE_REPORTS_RHSM",
"GET_SUBSCRIPTIONS_INVENTORY_RHSM": "GET_SUBSCRIPTIONS_INVENTORY_RHSM",
},
"toolbar": {
diff --git a/src/redux/types/index.js b/src/redux/types/index.js
index d5803d7f3..9e4d8ab05 100644
--- a/src/redux/types/index.js
+++ b/src/redux/types/index.js
@@ -1,6 +1,7 @@
import { appTypes } from './appTypes';
import { graphTypes } from './graphTypes';
import { inventoryTypes } from './inventoryTypes';
+import { messageTypes } from './messageTypes';
import { platformTypes } from './platformTypes';
import { queryTypes } from './queryTypes';
import { rhsmTypes } from './rhsmTypes';
@@ -11,6 +12,7 @@ const reduxTypes = {
app: appTypes,
graph: graphTypes,
inventory: inventoryTypes,
+ message: messageTypes,
platform: platformTypes,
query: queryTypes,
rhsm: rhsmTypes,
@@ -24,6 +26,7 @@ export {
appTypes,
graphTypes,
inventoryTypes,
+ messageTypes,
platformTypes,
queryTypes,
rhsmTypes,
diff --git a/src/redux/types/messageTypes.js b/src/redux/types/messageTypes.js
new file mode 100644
index 000000000..26268dd5c
--- /dev/null
+++ b/src/redux/types/messageTypes.js
@@ -0,0 +1,15 @@
+/**
+ * @memberof Types
+ * @module MessageTypes
+ */
+
+const SET_BANNER_MESSAGES = 'SET_BANNER_MESSAGES';
+
+/**
+ * User action, reducer types.
+ *
+ * @type {{SET_BANNER_MESSAGES: string}}
+ */
+const messageTypes = { SET_BANNER_MESSAGES };
+
+export { messageTypes as default, messageTypes, SET_BANNER_MESSAGES };
diff --git a/src/redux/types/rhsmTypes.js b/src/redux/types/rhsmTypes.js
index c5697774e..caff52dc5 100644
--- a/src/redux/types/rhsmTypes.js
+++ b/src/redux/types/rhsmTypes.js
@@ -9,13 +9,12 @@ const GET_GRAPH_TALLY_RHSM = 'GET_GRAPH_TALLY_RHSM';
const GET_HOSTS_INVENTORY_RHSM = 'GET_HOSTS_INVENTORY_RHSM';
const GET_HOSTS_INVENTORY_GUESTS_RHSM = 'GET_HOSTS_INVENTORY_GUESTS_RHSM';
const GET_INSTANCES_INVENTORY_RHSM = 'GET_INSTANCES_INVENTORY_RHSM';
-const GET_MESSAGE_REPORTS_RHSM = 'GET_MESSAGE_REPORTS_RHSM';
const GET_SUBSCRIPTIONS_INVENTORY_RHSM = 'GET_SUBSCRIPTIONS_INVENTORY_RHSM';
/**
* RHSM API action, reducer types.
*
- * @type {{GET_GRAPH_REPORT_CAPACITY_RHSM: string, GET_MESSAGE_REPORTS_RHSM: string, GET_HOSTS_INVENTORY_GUESTS_RHSM: string,
+ * @type {{GET_GRAPH_REPORT_CAPACITY_RHSM: string, GET_HOSTS_INVENTORY_GUESTS_RHSM: string,
* GET_GRAPH_CAPACITY_RHSM: string, GET_SUBSCRIPTIONS_INVENTORY_RHSM: string, GET_HOSTS_INVENTORY_RHSM: string,
* GET_INSTANCES_INVENTORY_RHSM: string, GET_GRAPH_TALLY_RHSM: string}}
*/
@@ -26,7 +25,6 @@ const rhsmTypes = {
GET_HOSTS_INVENTORY_RHSM,
GET_HOSTS_INVENTORY_GUESTS_RHSM,
GET_INSTANCES_INVENTORY_RHSM,
- GET_MESSAGE_REPORTS_RHSM,
GET_SUBSCRIPTIONS_INVENTORY_RHSM
};
@@ -39,6 +37,5 @@ export {
GET_HOSTS_INVENTORY_RHSM,
GET_HOSTS_INVENTORY_GUESTS_RHSM,
GET_INSTANCES_INVENTORY_RHSM,
- GET_MESSAGE_REPORTS_RHSM,
GET_SUBSCRIPTIONS_INVENTORY_RHSM
};
diff --git a/tests/__snapshots__/code.test.js.snap b/tests/__snapshots__/code.test.js.snap
index 2484618bb..4876a5e10 100644
--- a/tests/__snapshots__/code.test.js.snap
+++ b/tests/__snapshots__/code.test.js.snap
@@ -2,6 +2,7 @@
exports[`General code checks should only have specific console.[warn|log|info|error] methods: console methods 1`] = `
[
+ "components/bannerMessages/bannerMessagesContext.js:120: console.warn(",
"components/inventoryCard/inventoryCardContext.js:172: console.warn(\`Sorting can only be performed on select fields, confirm field \${id} is allowed.\`);",
"components/inventoryCard/inventoryCardContext.js:234: console.warn(\`Sorting can only be performed on select fields, confirm field \${id} is allowed.\`);",
"components/inventoryCard/inventoryCardHelpers.js:92: console.warn(\`Warning: Filter "\${id}" not found in "table row" response data.\`, cellData);",