From 2897ed737d9ad3cc8af8fdf59a14919032ebdeaa Mon Sep 17 00:00:00 2001 From: Jiri Tomasek Date: Thu, 25 Oct 2018 08:28:18 +0200 Subject: [PATCH] Convert SelectRolesDialog to ModalPanel Since the number of Available Roles is growing, ordinary Modal is not sufficient for showing the data. * Convert SelectRolesDialog Modal to ModalPanel * Make role cards the same height and show role detail modal on role title click * Role detail includes name, description, tags, networks and services Story: 2004253 Task: 27789 Change-Id: I68733bfb66f72caa5f48c1918962f0f3bdd15da7 --- ...ct-roles-modal-panel-185e8ae341fe6ae2.yaml | 10 ++ .../roles/AvailableRoleDetailDialog.js | 149 ++++++++++++++++++ src/js/components/roles/AvailableRoleInput.js | 30 ++-- src/js/components/roles/RoleServices.js | 2 +- src/js/components/roles/SelectRolesDialog.js | 7 +- src/js/components/roles/SelectRolesForm.js | 76 +++++---- src/js/components/ui/cards/index.js | 16 ++ src/less/utils/patternflyOverrides.less | 4 + 8 files changed, 241 insertions(+), 53 deletions(-) create mode 100644 releasenotes/notes/select-roles-modal-panel-185e8ae341fe6ae2.yaml create mode 100644 src/js/components/roles/AvailableRoleDetailDialog.js diff --git a/releasenotes/notes/select-roles-modal-panel-185e8ae341fe6ae2.yaml b/releasenotes/notes/select-roles-modal-panel-185e8ae341fe6ae2.yaml new file mode 100644 index 00000000..3619754d --- /dev/null +++ b/releasenotes/notes/select-roles-modal-panel-185e8ae341fe6ae2.yaml @@ -0,0 +1,10 @@ +features: + - | + Available Roles in Roles selection dialog are now displayed in scrollable + modal panel view, which allows to submit the form more easily. + - | + Role cards are now equal size, to make the cards more organized. Description + is truncated when needed. + - | + Clicking Role name opens Role details dialog which contains title, complete + description, tags, role networks and services diff --git a/src/js/components/roles/AvailableRoleDetailDialog.js b/src/js/components/roles/AvailableRoleDetailDialog.js new file mode 100644 index 00000000..68500110 --- /dev/null +++ b/src/js/components/roles/AvailableRoleDetailDialog.js @@ -0,0 +1,149 @@ +/** + * Copyright 2018 Red Hat Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ + +import PropTypes from 'prop-types'; +import React, { Component, Fragment } from 'react'; +import { MessageDialog, Label } from 'patternfly-react'; +import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; +import ImmutablePropTypes from 'react-immutable-proptypes'; + +const messages = defineMessages({ + dialogTitle: { + id: 'AvailableRoleDetailDialog.dialogTitle', + defaultMessage: 'Detailed Role Information' + }, + descriptionLabel: { + id: 'AvailableRoleDetailDialog.descriptionLabel', + defaultMessage: 'Description:' + }, + tagsLabel: { + id: 'AvailableRoleDetailDialog.tagsLabel', + defaultMessage: 'Tags:' + }, + networksLabel: { + id: 'AvailableRoleDetailDialog.networksLabel', + defaultMessage: 'Networks:' + }, + servicesLabel: { + id: 'AvailableRoleDetailDialog.servicesLabel', + defaultMessage: 'Services:' + }, + close: { + id: 'AvailableRoleDetailDialog.close', + defaultMessage: 'Close' + }, + disable: { + id: 'AvailableRoleDetailDialog.disable', + defaultMessage: 'Disable' + }, + enable: { + id: 'AvailableRoleDetailDialog.enable', + defaultMessage: 'Enable' + } +}); + +class AvailableRoleDetailDialog extends Component { + state = { + show: false + }; + + primaryAction = () => { + this.props.toggle(); + this.secondaryAction(); + }; + + secondaryAction = () => { + this.setState(() => ({ show: false })); + }; + + showModal = () => { + this.setState(() => ({ show: true })); + }; + + render() { + const { + enabled, + intl: { formatMessage }, + role: { name, description, networks, tags, ServicesDefault } + } = this.props; + const primaryContent =

{name}

; + const secondaryContent = ( + +

+ + + {' '} +
+ {description} +

+ {!tags.isEmpty() && ( +

+ + + {' '} + {tags.map(t => ( + + {' '} + + ))} +

+ )} + + + + + + + + +
+ ); + + return ( + + + {name} + + + + ); + } +} +AvailableRoleDetailDialog.propTypes = { + ServicesDefault: ImmutablePropTypes.list.isRequired, + enabled: PropTypes.bool.isRequired, + intl: PropTypes.object.isRequired, + role: ImmutablePropTypes.record.isRequired, + toggle: PropTypes.func.isRequired +}; + +export default injectIntl(AvailableRoleDetailDialog); diff --git a/src/js/components/roles/AvailableRoleInput.js b/src/js/components/roles/AvailableRoleInput.js index b75e3f6e..ba344ca6 100644 --- a/src/js/components/roles/AvailableRoleInput.js +++ b/src/js/components/roles/AvailableRoleInput.js @@ -14,11 +14,14 @@ * under the License. */ -import { Col } from 'react-bootstrap'; +import { Col, Card, CardTitle, CardBody } from 'patternfly-react'; import cx from 'classnames'; import ImmutablePropTypes from 'react-immutable-proptypes'; import React from 'react'; import PropTypes from 'prop-types'; +import { truncate } from 'lodash'; + +import AvailableRoleDetailDialog from './AvailableRoleDetailDialog'; const AvailableRoleInput = ({ className, @@ -27,17 +30,24 @@ const AvailableRoleInput = ({ style }) => ( -
-

{name}

-
+ + onChange(!value)} + /> + + {!role.tags.isEmpty() && (
{role.tags.map(t => ( @@ -47,8 +57,10 @@ const AvailableRoleInput = ({ ))}
)} -

{role.description}

-
+

+ {truncate(role.description, { length: 80 })} +

+
-
+ ); AvailableRoleInput.propTypes = { diff --git a/src/js/components/roles/RoleServices.js b/src/js/components/roles/RoleServices.js index 99233738..9c59b684 100644 --- a/src/js/components/roles/RoleServices.js +++ b/src/js/components/roles/RoleServices.js @@ -60,7 +60,7 @@ class RoleServices extends React.Component { isActive={service.id === this.state.selectedService} > - {service.type.split('::').pop()} + {service.type.split('OS::TripleO::Services::').pop()} )); diff --git a/src/js/components/roles/SelectRolesDialog.js b/src/js/components/roles/SelectRolesDialog.js index 22087d0b..ea332b1e 100644 --- a/src/js/components/roles/SelectRolesDialog.js +++ b/src/js/components/roles/SelectRolesDialog.js @@ -24,7 +24,7 @@ import { pickBy } from 'lodash'; import PropTypes from 'prop-types'; import AvailableRoleInput from './AvailableRoleInput'; -import { CloseModalXButton, RoutedModal } from '../ui/Modals'; +import { CloseModalXButton, RoutedModalPanel } from '../ui/Modals'; import { getMergedRoles, getRoles } from '../../selectors/roles'; import { getCurrentPlanName } from '../../selectors/plans'; import { Loader } from '../ui/Loader'; @@ -62,7 +62,7 @@ class SelectRolesDialog extends React.Component { roles } = this.props; return ( - + @@ -73,6 +73,7 @@ class SelectRolesDialog extends React.Component { height={100} loaded={availableRolesLoaded && !fetchingAvailableRoles} content={formatMessage(messages.loadingAvailableRoles)} + componentProps={{ className: 'flex-container' }} > - + ); } } diff --git a/src/js/components/roles/SelectRolesForm.js b/src/js/components/roles/SelectRolesForm.js index b9a219e0..f9a161c6 100644 --- a/src/js/components/roles/SelectRolesForm.js +++ b/src/js/components/roles/SelectRolesForm.js @@ -14,16 +14,16 @@ * under the License. */ -import { Button } from 'react-bootstrap'; import { defineMessages, FormattedMessage, injectIntl } from 'react-intl'; -import { ModalFooter } from 'react-bootstrap'; import { pickBy } from 'lodash'; import { OverlayLoader } from '../ui/Loader'; import PropTypes from 'prop-types'; import React from 'react'; import { reduxForm } from 'redux-form'; +import { Modal, Button } from 'patternfly-react'; import { CloseModalButton } from '../ui/Modals'; +import { CardGridFluid } from '../ui/cards'; import ModalFormErrorList from '../ui/forms/ModalFormErrorList'; const messages = defineMessages({ @@ -46,44 +46,40 @@ const messages = defineMessages({ } }); -class SelectRolesForm extends React.Component { - render() { - const { - children, - error, - handleSubmit, - invalid, - intl: { formatMessage }, - pristine, - submitting - } = this.props; - return ( -
- - -
-
{children}
-
-
- - - - - - -
- ); - } -} +const SelectRolesForm = ({ + children, + error, + handleSubmit, + invalid, + intl: { formatMessage }, + pristine, + submitting +}) => ( +
+ + + + {children} + + + + + + + + +
+); SelectRolesForm.propTypes = { children: PropTypes.node, currentPlanName: PropTypes.string.isRequired, diff --git a/src/js/components/ui/cards/index.js b/src/js/components/ui/cards/index.js index 24790ded..367df163 100644 --- a/src/js/components/ui/cards/index.js +++ b/src/js/components/ui/cards/index.js @@ -17,6 +17,7 @@ import cx from 'classnames'; import React from 'react'; import PropTypes from 'prop-types'; +import { Row, CardGrid } from 'patternfly-react'; export const ActionCard = ({ children, className, onClick, ...rest }) => (
( +
+ + + {children} + + +
+); +CardGridFluid.propTypes = { + children: PropTypes.node, + className: PropTypes.string, + matchHeight: PropTypes.bool.isRequired +}; diff --git a/src/less/utils/patternflyOverrides.less b/src/less/utils/patternflyOverrides.less index 6ee65d17..45770d2b 100644 --- a/src/less/utils/patternflyOverrides.less +++ b/src/less/utils/patternflyOverrides.less @@ -175,3 +175,7 @@ tbody > tr > td.blank-slate-pf { .toast-notifications-list-pf { z-index: 1060; } + +p.lead { + margin-bottom: 10px; +}