Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(bannerMessages): issues/502 cloud meter messaging
 #503

Merged
merged 3 commits into from
Nov 12, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ PUBLIC_URL=${UI_DEPLOY_PATH_PREFIX}/apps/subscriptions/

REACT_APP_UI_LINK_CONTACT_US=https://access.redhat.com/account-team
REACT_APP_UI_LINK_LEARN_MORE=https://access.redhat.com/documentation/en-us/subscription_central/2020-10/html/getting_started_with_subscription_watch/con-how-does-subscriptionwatch-show-data_assembly-opening-subscriptionwatch-ctxt/
REACT_APP_UI_LINK_REPORT_ACCURACY_RECOMMENDATIONS=

REACT_APP_UI_DISABLED=false
REACT_APP_UI_DISABLED_TOOLBAR=false
Expand Down
5 changes: 5 additions & 0 deletions public/locales/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
"pending": "Authenticating...",
"maintenanceCopy": "We are currently undergoing scheduled maintenance and will be back shortly. Thank you for your patience."
},
"curiosity-banner": {
"dataMismatchTitle": "Improve reporting accuracy",
"dataMismatchMessage": "Action required in order to improve {{appName}} reporting.",
"dataMismatchMessage_cloudigradeMismatch": "<0>View recommmend actions</0> to take in order to improve {{appName}} reporting."
},
"curiosity-graph": {
"cardHeading": "CPU usage",
"coresHeading": "CPU core usage",
Expand Down
3 changes: 3 additions & 0 deletions src/common/__tests__/__snapshots__/helpers.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Object {
"UI_DISPLAY_START_NAME": "Subscription Watch",
"UI_LINK_CONTACT_US": "https://access.redhat.com/account-team",
"UI_LINK_LEARN_MORE": "https://access.redhat.com/documentation/en-us/subscription_central/2020-10/html/getting_started_with_subscription_watch/con-how-does-subscriptionwatch-show-data_assembly-opening-subscriptionwatch-ctxt/",
"UI_LINK_REPORT_ACCURACY_RECOMMENDATIONS": "",
"UI_LOCALE_DEFAULT": "en-US",
"UI_LOCALE_DEFAULT_DESC": "English",
"UI_LOGGER_ID": "curiosity",
Expand Down Expand Up @@ -50,6 +51,7 @@ Object {
"UI_DISPLAY_START_NAME": "Subscription Watch",
"UI_LINK_CONTACT_US": "https://access.redhat.com/account-team",
"UI_LINK_LEARN_MORE": "https://access.redhat.com/documentation/en-us/subscription_central/2020-10/html/getting_started_with_subscription_watch/con-how-does-subscriptionwatch-show-data_assembly-opening-subscriptionwatch-ctxt/",
"UI_LINK_REPORT_ACCURACY_RECOMMENDATIONS": "",
"UI_LOCALE_DEFAULT": "en-US",
"UI_LOCALE_DEFAULT_DESC": "English",
"UI_LOGGER_ID": "curiosity",
Expand Down Expand Up @@ -84,6 +86,7 @@ Object {
"UI_DISPLAY_START_NAME": "Subscription Watch",
"UI_LINK_CONTACT_US": "https://access.redhat.com/account-team",
"UI_LINK_LEARN_MORE": "https://access.redhat.com/documentation/en-us/subscription_central/2020-10/html/getting_started_with_subscription_watch/con-how-does-subscriptionwatch-show-data_assembly-opening-subscriptionwatch-ctxt/",
"UI_LINK_REPORT_ACCURACY_RECOMMENDATIONS": "",
"UI_LOCALE_DEFAULT": "en-US",
"UI_LOCALE_DEFAULT_DESC": "English",
"UI_LOGGER_ID": "curiosity",
Expand Down
8 changes: 8 additions & 0 deletions src/common/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,13 @@ const UI_LINK_CONTACT_US = process.env.REACT_APP_UI_LINK_CONTACT_US;
*/
const UI_LINK_LEARN_MORE = process.env.REACT_APP_UI_LINK_LEARN_MORE;

/**
* A url, or uri, for "recommend actions"
*
* @type {string}
*/
const UI_LINK_REPORT_ACCURACY_RECOMMENDATIONS = process.env.REACT_APP_UI_LINK_REPORT_ACCURACY_RECOMMENDATIONS;

/**
* UI locale default.
*
Expand Down Expand Up @@ -252,6 +259,7 @@ const helpers = {
UI_DISPLAY_START_NAME,
UI_LINK_CONTACT_US,
UI_LINK_LEARN_MORE,
UI_LINK_REPORT_ACCURACY_RECOMMENDATIONS,
UI_LOCALE_DEFAULT,
UI_LOCALE_DEFAULT_DESC,
UI_LOGGER_ID,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`BannerMessages Component should handle closing messages from state: state messages, OFF 1`] = `""`;

exports[`BannerMessages Component should handle closing messages from state: state messages, ON 1`] = `
<div
className="curiosity-banner-messages"
>
<Alert
actionClose={
<AlertActionCloseButton
onClose={[Function]}
/>
}
key="loremIpsum"
title="Lorem ipsum title"
variant="info"
>
Lorem ipsum message
</Alert>
</div>
`;

exports[`BannerMessages Component should render a non-connected component: non-connected 1`] = `
<div
className="curiosity-banner-messages"
>
<Alert
actionClose={
<AlertActionCloseButton
onClose={[Function]}
/>
}
key="loremIpsum"
title="Lorem ipsum title"
variant="info"
>
Lorem ipsum message
</Alert>
</div>
`;

exports[`BannerMessages Component should render specific messages when the appMessages prop is used: specific messages, OFF 1`] = `""`;

exports[`BannerMessages Component should render specific messages when the appMessages prop is used: specific messages, ON 1`] = `
<div
className="curiosity-banner-messages"
>
<Alert
actionClose={
<AlertActionCloseButton
onClose={[Function]}
/>
}
key="loremIpsum"
title="Lorem ipsum title"
variant="info"
>
Lorem ipsum message
</Alert>
</div>
`;
76 changes: 76 additions & 0 deletions src/components/bannerMessages/__tests__/bannerMessages.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import React from 'react';
import { shallow } from 'enzyme';
import { BannerMessages } from '../bannerMessages';

describe('BannerMessages Component', () => {
it('should render a non-connected component', () => {
const props = {
appMessages: {
loremIpsum: true
},
messages: [
{
id: 'loremIpsum',
title: 'Lorem ipsum title',
message: 'Lorem ipsum message'
}
]
};
const component = shallow(<BannerMessages {...props} />);

expect(component).toMatchSnapshot('non-connected');
});

it('should render specific messages when the appMessages prop is used', () => {
const props = {
appMessages: {
loremIpsum: false,
dolorSit: false
},
messages: [
{
id: 'loremIpsum',
title: 'Lorem ipsum title',
message: 'Lorem ipsum message'
},
{
id: 'dolorSit',
title: 'Dolor sit title',
message: 'Dolor sit message'
}
]
};
const component = shallow(<BannerMessages {...props} />);

expect(component).toMatchSnapshot('specific messages, OFF');

component.setProps({
...props,
appMessages: {
loremIpsum: true,
dolorSit: false
}
});
expect(component).toMatchSnapshot('specific messages, ON');
});

it('should handle closing messages from state', () => {
const props = {
appMessages: {
loremIpsum: true
},
messages: [
{
id: 'loremIpsum',
title: 'Lorem ipsum title',
message: 'Lorem ipsum message'
}
]
};
const component = shallow(<BannerMessages {...props} />);
expect(component).toMatchSnapshot('state messages, ON');

component.setState({ loremIpsum: true });
expect(component).toMatchSnapshot('state messages, OFF');
});
});
127 changes: 127 additions & 0 deletions src/components/bannerMessages/bannerMessages.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
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 { connect, reduxSelectors } from '../../redux';
import { translate } from '../i18n/i18n';
import { helpers } from '../../common';

/**
* Render banner messages.
*
* @augments React.Component
*/
class BannerMessages extends React.Component {
state = {};

/**
* Apply messages' configuration to alerts.
*
* @returns {Node}
*/
renderAlerts() {
const { state } = this;
const { appMessages, messages } = this.props;
const updatedMessages = [];

if (messages.length) {
Object.entries(appMessages).forEach(([key, value]) => {
if (state[key] !== true && value === true) {
const message = messages.find(({ id }) => id === key);

if (message) {
updatedMessages.push({
key,
...message
});
}
}
});
}

return updatedMessages.map(({ key, message, title, variant = AlertVariant.info }) => {
const actionClose = <AlertActionCloseButton onClose={() => this.setState({ [key]: true })} />;

return (
<Alert actionClose={actionClose} key={key} title={title} variant={variant}>
{message}
</Alert>
);
});
}

/**
* Render a banner messages container.
*
* @returns {Node}
*/
render() {
const alerts = this.renderAlerts();

if (alerts.length) {
return <div className="curiosity-banner-messages">{alerts}</div>;
}

return null;
}
}

/**
* Prop types.
*
* @type {{appMessages: object, messages: Array}}
*/
BannerMessages.propTypes = {
appMessages: PropTypes.object.isRequired,
messages: PropTypes.arrayOf(
PropTypes.shape({
id: PropTypes.string.isRequired,
title: PropTypes.node.isRequired,
message: PropTypes.node.isRequired,
variant: PropTypes.oneOf([...Object.values(AlertVariant)])
})
)
};

/**
* Default props.
*
* @type {{messages: Array}}
*/
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
},
[
<Button
isInline
component="a"
variant="link"
icon={<ExternalLinkAltIcon />}
iconPosition="right"
target="_blank"
href={helpers.UI_LINK_REPORT_ACCURACY_RECOMMENDATIONS}
/>
]
)
}
]
};

/**
* Create a selector from applied state, props.
*
* @type {Function}
*/
const makeMapStateToProps = reduxSelectors.appMessages.makeAppMessages();

const ConnectedBannerMessages = connect(makeMapStateToProps)(BannerMessages);

export { ConnectedBannerMessages as default, ConnectedBannerMessages, BannerMessages };
13 changes: 13 additions & 0 deletions src/components/i18n/__tests__/__snapshots__/i18n.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,19 @@ Array [
},
],
},
Object {
"file": "./src/components/bannerMessages/bannerMessages.js",
"keys": Array [
Object {
"key": "curiosity-banner.dataMismatchTitle",
"match": "translate('curiosity-banner.dataMismatchTitle')",
},
Object {
"key": "curiosity-banner.dataMismatchMessage",
"match": "translate( 'curiosity-banner.dataMismatchMessage', { context: helpers.UI_LINK_REPORT_ACCURACY_RECOMMENDATIONS !== '' && 'cloudigradeMismatch', appName: helpers.UI_DISPLAY_NAME }, [ <Button isInline component=\\"a\\" variant=\\"link\\" icon={<ExternalLinkAltIcon />} iconPosition=\\"right\\" target=\\"_blank\\" href={helpers.UI_LINK_REPORT_ACCURACY_RECOMMENDATIONS} /> ] )",
},
],
},
Object {
"file": "./src/components/c3GraphCard/c3GraphCard.js",
"keys": Array [
Expand Down
Loading