From e2a17f2a8f1263fd4e63b1ae62f5c8e27ad08996 Mon Sep 17 00:00:00 2001 From: CD Cabrera Date: Fri, 8 Jul 2022 13:03:30 -0400 Subject: [PATCH] refactor(credentials): discovery-148 pf4 empty-state (#116) * locale, align empty-state strings * authentication, align with credentials * credentials, credentialsEmptyState, pf4 empty-state --- public/locales/en.json | 16 +- .../__snapshots__/authentication.test.js.snap | 118 +++++------ .../__tests__/authentication.test.js | 3 +- .../authentication/authentication.js | 24 ++- .../credentialsEmptyState.test.js.snap | 197 ++++++++++-------- .../__tests__/credentialsEmptyState.test.js | 4 +- src/components/credentials/credentials.js | 52 +++-- .../credentials/credentialsEmptyState.js | 45 ++-- .../__tests__/__snapshots__/i18n.test.js.snap | 89 ++++++-- src/styles/app/_emptyState.scss | 18 ++ src/styles/index.scss | 1 + tests/__snapshots__/dist.test.js.snap | 4 + 12 files changed, 356 insertions(+), 215 deletions(-) create mode 100644 src/styles/app/_emptyState.scss diff --git a/public/locales/en.json b/public/locales/en.json index 187d2524..037a5616 100644 --- a/public/locales/en.json +++ b/public/locales/en.json @@ -22,10 +22,18 @@ "aria-label-default": "Application modal" }, "view": { + "empty-state_title": "Welcome to {{name}}", + "empty-state_description_credentials": "Credentials contain authentication information needed to scan a source. A credential includes a username and a password or SSH key. {{name}} uses SSH to connect to servers on the network and uses credentials to access those servers.", + "empty-state_filter_description": "The active filters are hiding all items.", + "empty-state_filter_title": "No Results Match the Filter Criteria", + "empty-state_label_clear": "Clear Filters", + "empty-state_label_source": "Add Source", + "error_credentials": "Credentials error", + "error-message_credentials": "Error retrieving credentials: {{message}}", + "error_authentication": "Login error", + "error-message_authentication": "{{message}} Please <0>login to continue.", "loading": "Loading...", - "loading_credentials": "Loading credentials...", - "login_error": "Login error", - "login-message_error": "Please <0>login to continue.", - "login_pending": "Logging in..." + "loading_authentication": "Logging in...", + "loading_credentials": "Loading credentials..." } } diff --git a/src/components/authentication/__tests__/__snapshots__/authentication.test.js.snap b/src/components/authentication/__tests__/__snapshots__/authentication.test.js.snap index 7be661be..df1709ab 100644 --- a/src/components/authentication/__tests__/__snapshots__/authentication.test.js.snap +++ b/src/components/authentication/__tests__/__snapshots__/authentication.test.js.snap @@ -32,76 +32,68 @@ exports[`Authentication Component should render a non-connected component author `; exports[`Authentication Component should render a non-connected component error: non-connected error 1`] = ` -
- -
- -
- - - - - -
-
-

- - Danger alert: - - t(view.login, {"context":"error"}) -

-
- Authentication credentials were not provided - . - t(view.login-message, {"context":"error"}, [object Object]) + } + viewBox="0 0 512 512" + width="1em" + > + + +
+ +

+ + Danger alert: + + t(view.error, {"context":"authentication"}) +

+
+ t(view.error-message, {"context":"authentication","message":"Authentication credentials were not provided."}, [object Object])
- -
+
+ `; exports[`Authentication Component should render a non-connected component pending: non-connected pending 1`] = ` @@ -123,7 +115,7 @@ exports[`Authentication Component should render a non-connected component pendin className="spinner spinner-xl" /> - t(view.login, {"context":"pending"}) + t(view.loading, {"context":"authentication"}) `; diff --git a/src/components/authentication/__tests__/authentication.test.js b/src/components/authentication/__tests__/authentication.test.js index b408d9b7..d8bcf186 100644 --- a/src/components/authentication/__tests__/authentication.test.js +++ b/src/components/authentication/__tests__/authentication.test.js @@ -2,6 +2,7 @@ import React from 'react'; import configureMockStore from 'redux-mock-store'; import { Provider } from 'react-redux'; import { shallow, mount } from 'enzyme'; +import { Alert } from '@patternfly/react-core'; import { ConnectedAuthentication, Authentication } from '../authentication'; describe('Authentication Component', () => { @@ -37,7 +38,7 @@ describe('Authentication Component', () => { ); - expect(component.find('.pf-c-modal-box__body')).toMatchSnapshot('non-connected error'); + expect(component.find(Alert)).toMatchSnapshot('non-connected error'); }); it('should render a non-connected component pending', () => { diff --git a/src/components/authentication/authentication.js b/src/components/authentication/authentication.js index 4b5db89d..1bd8dfae 100644 --- a/src/components/authentication/authentication.js +++ b/src/components/authentication/authentication.js @@ -1,9 +1,8 @@ import React from 'react'; import PropTypes from 'prop-types'; import { connect } from 'react-redux'; -import { Alert, AlertVariant, Button, Bullseye } from '@patternfly/react-core'; +import { Alert, AlertVariant, Button, Bullseye, EmptyState } from '@patternfly/react-core'; import { Modal, ModalVariant } from '../modal/modal'; -import { ConfirmationModal, ConfirmationVariant } from '../confirmationModal/confirmationModal'; import { reduxActions } from '../../redux'; import helpers from '../../common/helpers'; import { PageLayout } from '../pageLayout/pageLayout'; @@ -32,23 +31,26 @@ class Authentication extends React.Component { return (
- {t('view.login', { context: 'pending' })} + {t('view.loading', { context: 'authentication' })} ); } return ( - - - {session.errorMessage.replace(/\.$/, '')} - {session.errorMessage && '.'} + + {!session.authorized && - t('view.login-message', { context: 'error' }, [ - - +
- -
- + +
@@ -111,14 +124,16 @@ exports[`CredentialsEmptyState Component should render a basic component 1`] = ` `; exports[`CredentialsEmptyState Component should render the application name: application name 1`] = ` - -

- Welcome to - Ipsum -

-
+ t(view.empty-state, {"context":"title","name":"Ipsum"}) + + `; diff --git a/src/components/credentials/__tests__/credentialsEmptyState.test.js b/src/components/credentials/__tests__/credentialsEmptyState.test.js index 349c798c..777ae38d 100644 --- a/src/components/credentials/__tests__/credentialsEmptyState.test.js +++ b/src/components/credentials/__tests__/credentialsEmptyState.test.js @@ -1,6 +1,6 @@ import React from 'react'; import { mount } from 'enzyme'; -import { EmptyState } from 'patternfly-react'; +import { Title } from '@patternfly/react-core'; import CredentialsEmptyState from '../credentialsEmptyState'; describe('CredentialsEmptyState Component', () => { @@ -18,6 +18,6 @@ describe('CredentialsEmptyState Component', () => { }; const component = mount(); - expect(component.find(EmptyState.Title)).toMatchSnapshot('application name'); + expect(component.find(Title)).toMatchSnapshot('application name'); }); }); diff --git a/src/components/credentials/credentials.js b/src/components/credentials/credentials.js index ced3d0bb..33265e62 100644 --- a/src/components/credentials/credentials.js +++ b/src/components/credentials/credentials.js @@ -3,7 +3,21 @@ import PropTypes from 'prop-types'; import _get from 'lodash/get'; import _isEqual from 'lodash/isEqual'; import _size from 'lodash/size'; -import { Alert, Button, DropdownButton, EmptyState, Form, Grid, ListView, MenuItem } from 'patternfly-react'; +import { + Alert, + AlertVariant, + Button, + ButtonVariant, + EmptyState, + EmptyStateBody, + EmptyStateIcon, + EmptyStatePrimary, + EmptyStateVariant, + Title, + TitleSizes +} from '@patternfly/react-core'; +import { SearchIcon } from '@patternfly/react-icons'; +import { Button as ButtonPf3, DropdownButton, Form, Grid, ListView, MenuItem } from 'patternfly-react'; import { Modal, ModalVariant } from '../modal/modal'; import { connect, reduxActions, reduxTypes, store } from '../../redux'; import helpers from '../../common/helpers'; @@ -208,12 +222,12 @@ class Credentials extends React.Component { VCenter Credential - + ); } @@ -234,6 +248,8 @@ class Credentials extends React.Component { } renderCredentialsList(items) { + const { t } = this.props; + if (_size(items)) { return ( @@ -250,29 +266,35 @@ class Credentials extends React.Component { } return ( - - No Results Match the Filter Criteria - The active filters are hiding all items. - - - + ); } render() { - const { error, errorMessage, credentials, viewOptions } = this.props; + const { error, errorMessage, credentials, pending, t, viewOptions } = this.props; const { lastRefresh } = this.state; + if (pending) { + return this.renderPendingMessage(); + } + if (error) { return ( - - - Error retrieving credentials: {errorMessage} + + + {t('view.error-message', { context: ['credentials'], message: errorMessage })} - {this.renderPendingMessage()} ); } diff --git a/src/components/credentials/credentialsEmptyState.js b/src/components/credentials/credentialsEmptyState.js index b7236a28..34cc0647 100644 --- a/src/components/credentials/credentialsEmptyState.js +++ b/src/components/credentials/credentialsEmptyState.js @@ -1,20 +1,31 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { Button, DropdownButton, EmptyState, Grid, MenuItem, Row } from 'patternfly-react'; +import { + Button, + ButtonVariant, + EmptyState, + EmptyStateBody, + EmptyStateIcon, + EmptyStatePrimary, + EmptyStateSecondaryActions, + EmptyStateVariant, + Title +} from '@patternfly/react-core'; +import { AddCircleOIcon } from '@patternfly/react-icons'; +import { DropdownButton, Grid, MenuItem, Row } from 'patternfly-react'; import helpers from '../../common/helpers'; +import { translate } from '../i18n/i18n'; -const CredentialsEmptyState = ({ onAddCredential, onAddSource, uiSentenceStartName, uiShortName }) => ( +const CredentialsEmptyState = ({ onAddCredential, onAddSource, t, uiSentenceStartName, uiShortName }) => ( - - - Welcome to {uiShortName} - - Credentials contain authentication information needed to scan a source. A credential includes
a username - and a password or SSH key. {uiSentenceStartName} uses SSH to connect to servers
on the network and uses - credentials to access those servers. -
- + + + {t('view.empty-state', { context: 'title', name: uiShortName })} + + {t('view.empty-state', { context: ['description', 'credentials'], name: uiSentenceStartName })} + + onAddCredential('network')}> Network Credential @@ -26,12 +37,12 @@ const CredentialsEmptyState = ({ onAddCredential, onAddSource, uiSentenceStartNa VCenter Credential - - - - +
@@ -40,6 +51,7 @@ const CredentialsEmptyState = ({ onAddCredential, onAddSource, uiSentenceStartNa CredentialsEmptyState.propTypes = { onAddCredential: PropTypes.func, onAddSource: PropTypes.func, + t: PropTypes.func, uiSentenceStartName: PropTypes.string, uiShortName: PropTypes.string }; @@ -47,6 +59,7 @@ CredentialsEmptyState.propTypes = { CredentialsEmptyState.defaultProps = { onAddCredential: helpers.noop, onAddSource: helpers.noop, + t: translate, uiSentenceStartName: helpers.UI_SENTENCE_START_NAME, uiShortName: helpers.UI_SHORT_NAME }; diff --git a/src/components/i18n/__tests__/__snapshots__/i18n.test.js.snap b/src/components/i18n/__tests__/__snapshots__/i18n.test.js.snap index 5f0d458d..2c6b19b2 100644 --- a/src/components/i18n/__tests__/__snapshots__/i18n.test.js.snap +++ b/src/components/i18n/__tests__/__snapshots__/i18n.test.js.snap @@ -52,16 +52,16 @@ Array [ "file": "./src/components/authentication/authentication.js", "keys": Array [ Object { - "key": "view.login", - "match": "t('view.login', { context: 'pending' })", + "key": "view.loading", + "match": "t('view.loading', { context: 'authentication' })", }, Object { - "key": "view.login", - "match": "t('view.login', { context: 'error' })", + "key": "view.error", + "match": "t('view.error', { context: 'authentication' })", }, Object { - "key": "view.login-message", - "match": "t('view.login-message', { context: 'error' }, [