diff --git a/awx/ui_next/src/components/AddRole/AddResourceRole.jsx b/awx/ui_next/src/components/AddRole/AddResourceRole.jsx index 2770afe53e..ef61d6fe27 100644 --- a/awx/ui_next/src/components/AddRole/AddResourceRole.jsx +++ b/awx/ui_next/src/components/AddRole/AddResourceRole.jsx @@ -22,6 +22,7 @@ class AddResourceRole extends React.Component { selectedResourceRows: [], selectedRoleRows: [], currentStepId: 1, + maxEnabledStep: 1, }; this.handleResourceCheckboxClick = this.handleResourceCheckboxClick.bind( @@ -31,10 +32,11 @@ class AddResourceRole extends React.Component { this.handleRoleCheckboxClick = this.handleRoleCheckboxClick.bind(this); this.handleWizardNext = this.handleWizardNext.bind(this); this.handleWizardSave = this.handleWizardSave.bind(this); + this.handleWizardGoToStep = this.handleWizardGoToStep.bind(this); } handleResourceCheckboxClick(user) { - const { selectedResourceRows } = this.state; + const { selectedResourceRows, currentStepId } = this.state; const selectedIndex = selectedResourceRows.findIndex( selectedRow => selectedRow.id === user.id @@ -42,7 +44,11 @@ class AddResourceRole extends React.Component { if (selectedIndex > -1) { selectedResourceRows.splice(selectedIndex, 1); - this.setState({ selectedResourceRows }); + let stateToUpdate = { selectedResourceRows }; + if (selectedResourceRows.length === 0) { + stateToUpdate.maxEnabledStep = currentStepId; + } + this.setState(stateToUpdate); } else { this.setState(prevState => ({ selectedResourceRows: [...prevState.selectedResourceRows, user], @@ -76,6 +82,13 @@ class AddResourceRole extends React.Component { } handleWizardNext(step) { + this.setState({ + currentStepId: step.id, + maxEnabledStep: step.id, + }); + } + + handleWizardGoToStep(step) { this.setState({ currentStepId: step.id, }); @@ -125,6 +138,7 @@ class AddResourceRole extends React.Component { selectedResourceRows, selectedRoleRows, currentStepId, + maxEnabledStep, } = this.state; const { onClose, roles, i18n } = this.props; @@ -162,9 +176,14 @@ class AddResourceRole extends React.Component { const steps = [ { id: 1, - name: i18n._(t`Select Users Or Teams`), + name: i18n._(t`Select a Resource Type`), component: ( -
+
+
+ {i18n._( + t`Choose the type of resource that will be receiving new roles. For example, if you'd like to add new roles to a set of users please choose Users and click Next. You'll be able to select the specific resources in the next step.` + )} +
{selectedResource === 'users' && ( @@ -209,10 +228,11 @@ class AddResourceRole extends React.Component { ), enableNext: selectedResourceRows.length > 0, + canJumpTo: maxEnabledStep >= 2, }, { id: 3, - name: i18n._(t`Apply roles`), + name: i18n._(t`Select Roles to Apply`), component: ( 0, + canJumpTo: maxEnabledStep >= 3, }, ]; @@ -238,6 +259,7 @@ class AddResourceRole extends React.Component { onNext={this.handleWizardNext} onClose={onClose} onSave={this.handleWizardSave} + onGoToStep={this.handleWizardGoToStep} steps={steps} title={wizardTitle} nextButtonText={currentStep.nextButtonText || undefined} diff --git a/awx/ui_next/src/components/AddRole/AddResourceRole.test.jsx b/awx/ui_next/src/components/AddRole/AddResourceRole.test.jsx index 52f222bef4..8a17a10a97 100644 --- a/awx/ui_next/src/components/AddRole/AddResourceRole.test.jsx +++ b/awx/ui_next/src/components/AddRole/AddResourceRole.test.jsx @@ -152,6 +152,7 @@ describe('<_AddResourceRole />', () => { selectedResourceRows: [], selectedRoleRows: [], currentStepId: 1, + maxEnabledStep: 1, }); wrapper.instance().handleResourceSelect('teams'); expect(wrapper.state()).toEqual({ @@ -159,6 +160,7 @@ describe('<_AddResourceRole />', () => { selectedResourceRows: [], selectedRoleRows: [], currentStepId: 1, + maxEnabledStep: 1, }); }); test('handleWizardSave makes correct api calls, calls onSave when done', async () => { diff --git a/awx/ui_next/src/components/AddRole/SelectResourceStep.jsx b/awx/ui_next/src/components/AddRole/SelectResourceStep.jsx index 2599c7fd64..f1b436f92c 100644 --- a/awx/ui_next/src/components/AddRole/SelectResourceStep.jsx +++ b/awx/ui_next/src/components/AddRole/SelectResourceStep.jsx @@ -83,6 +83,11 @@ class SelectResourceStep extends React.Component { {isLoading &&
{i18n._(t`Loading...`)}
} {isInitialized && ( +
+ {i18n._( + t`Choose the resources that will be receiving new roles. You'll be able to select the roles to apply in the next step. Note that the resources chosen here will receive all roles chosen in the next step.` + )} +
{selectedResourceRows.length > 0 && ( onRowClick(item)} /> )} - renderToolbar={props => ( - - )} + renderToolbar={props => } showPageSizeOptions={false} />
diff --git a/awx/ui_next/src/components/AddRole/SelectRoleStep.jsx b/awx/ui_next/src/components/AddRole/SelectRoleStep.jsx index 9af70da8d7..f867d0b54f 100644 --- a/awx/ui_next/src/components/AddRole/SelectRoleStep.jsx +++ b/awx/ui_next/src/components/AddRole/SelectRoleStep.jsx @@ -21,6 +21,11 @@ class RolesStep extends React.Component { return ( +
+ {i18n._( + t`Choose roles to apply to the selected resources. Note that all selected roles will be applied to all selected resources.` + )} +
{selectedResourceRows.length > 0 && ( { + test('renders the expected content', () => { + const wrapper = mount(); + expect(wrapper).toHaveLength(1); + }); +}); diff --git a/awx/ui_next/src/components/DataListCheck/index.js b/awx/ui_next/src/components/DataListCheck/index.js new file mode 100644 index 0000000000..cdb8b6137c --- /dev/null +++ b/awx/ui_next/src/components/DataListCheck/index.js @@ -0,0 +1 @@ +export { default } from './DataListCheck'; diff --git a/awx/ui_next/src/components/Lookup/Lookup.jsx b/awx/ui_next/src/components/Lookup/Lookup.jsx index b1dfc331c6..01ccd716a4 100644 --- a/awx/ui_next/src/components/Lookup/Lookup.jsx +++ b/awx/ui_next/src/components/Lookup/Lookup.jsx @@ -14,7 +14,7 @@ import { Button, ButtonVariant, InputGroup as PFInputGroup, - Modal as PFModal, + Modal, } from '@patternfly/react-core'; import { withI18n } from '@lingui/react'; import { t } from '@lingui/macro'; @@ -27,6 +27,13 @@ import SelectedList from '../SelectedList'; import { ChipGroup, Chip } from '../Chip'; import { getQSConfig, parseQueryString } from '../../util/qs'; +const SearchButton = styled(Button)` + ::after { + border: var(--pf-c-button--BorderWidth) solid + var(--pf-global--BorderColor--200); + } +`; + const InputGroup = styled(PFInputGroup)` ${props => props.multiple && @@ -36,8 +43,9 @@ const InputGroup = styled(PFInputGroup)` `} `; -const Modal = styled(PFModal)` - --pf-c-modal-box--body--MinHeight: 460px; +const ChipHolder = styled.div` + --pf-c-form-control--BorderTopColor: var(--pf-global--BorderColor--200); + --pf-c-form-control--BorderRightColor: var(--pf-global--BorderColor--200); `; class Lookup extends React.Component { @@ -211,15 +219,15 @@ class Lookup extends React.Component { return ( - -
{chips}
+ + {chips}
- User
}> + {i18n._(t`User`)}
}> span { /* text element */ width: auto; @@ -53,7 +63,7 @@ const Dropdown = styled(PFDropdown)` const NoOptionDropdown = styled.div` align-self: stretch; - border: 1px solid grey; + border: 1px solid var(--pf-global--BorderColor--200); padding: 3px 7px; white-space: nowrap; `; diff --git a/awx/ui_next/src/components/Sort/Sort.jsx b/awx/ui_next/src/components/Sort/Sort.jsx index ed22597f14..9cdf75776e 100644 --- a/awx/ui_next/src/components/Sort/Sort.jsx +++ b/awx/ui_next/src/components/Sort/Sort.jsx @@ -8,6 +8,7 @@ import { DropdownPosition, DropdownToggle, DropdownItem, + Tooltip, } from '@patternfly/react-core'; import { SortAlphaDownIcon, @@ -48,6 +49,21 @@ const IconWrapper = styled.span` } `; +const SortButton = styled(Button)` + padding: 5px 8px; + margin-top: 3px; + + &:hover { + background-color: #0166cc; + color: white; + } +`; + +const SortBy = styled.span` + margin-right: 15px; + font-size: var(--pf-global--FontSize--md); +`; + class Sort extends React.Component { constructor(props) { super(props); @@ -112,33 +128,40 @@ class Sort extends React.Component { return ( {sortDropdownItems.length > 1 && ( - - {sortedColumnName} - - } - dropdownItems={sortDropdownItems} - /> + + {i18n._(t`Sort By`)} + + {sortedColumnName} + + } + dropdownItems={sortDropdownItems} + /> + )} -
} + position="top" > - - - - + + + + + + ); } diff --git a/awx/ui_next/src/screens/Job/JobList/JobListItem.jsx b/awx/ui_next/src/screens/Job/JobList/JobListItem.jsx index 93c67e7070..144b0d187c 100644 --- a/awx/ui_next/src/screens/Job/JobList/JobListItem.jsx +++ b/awx/ui_next/src/screens/Job/JobList/JobListItem.jsx @@ -4,9 +4,9 @@ import { DataListItem, DataListItemRow, DataListItemCells, - DataListCheck, } from '@patternfly/react-core'; import DataListCell from '@components/DataListCell'; +import DataListCheck from '@components/DataListCheck'; import VerticalSeparator from '@components/VerticalSeparator'; import { toTitleCase } from '@util/strings'; import { JOB_TYPE_URL_SEGMENTS } from '../../../constants'; diff --git a/awx/ui_next/src/screens/Organization/OrganizationList/OrganizationListItem.jsx b/awx/ui_next/src/screens/Organization/OrganizationList/OrganizationListItem.jsx index e5d7c7940d..0d5675091b 100644 --- a/awx/ui_next/src/screens/Organization/OrganizationList/OrganizationListItem.jsx +++ b/awx/ui_next/src/screens/Organization/OrganizationList/OrganizationListItem.jsx @@ -7,12 +7,12 @@ import { DataListItem, DataListItemRow, DataListItemCells, - DataListCheck, } from '@patternfly/react-core'; import { Link } from 'react-router-dom'; import styled from 'styled-components'; import DataListCell from '@components/DataListCell'; +import DataListCheck from '@components/DataListCheck'; import VerticalSeparator from '@components/VerticalSeparator'; import { Organization } from '@types'; diff --git a/awx/ui_next/src/screens/Organization/OrganizationNotifications/__snapshots__/OrganizationNotifications.test.jsx.snap b/awx/ui_next/src/screens/Organization/OrganizationNotifications/__snapshots__/OrganizationNotifications.test.jsx.snap index a4d3837277..6383534902 100644 --- a/awx/ui_next/src/screens/Organization/OrganizationNotifications/__snapshots__/OrganizationNotifications.test.jsx.snap +++ b/awx/ui_next/src/screens/Organization/OrganizationNotifications/__snapshots__/OrganizationNotifications.test.jsx.snap @@ -466,9 +466,9 @@ exports[` initially renders succesfully 1`] = ` "$$typeof": Symbol(react.forward_ref), "attrs": Array [], "componentStyle": ComponentStyle { - "componentId": "sc-htpNat", + "componentId": "sc-bwzfXH", "isStatic": false, - "lastClassName": "dnOsXG", + "lastClassName": "fPRqXT", "rules": Array [ "flex-grow:1;margin-left:20px;margin-right:20px;", [Function], @@ -479,7 +479,7 @@ exports[` initially renders succesfully 1`] = ` "DataListToolbar__Toolbar-ajzso8-1", ], "render": [Function], - "styledComponentId": "sc-htpNat", + "styledComponentId": "sc-bwzfXH", "target": [Function], "toString": [Function], "warnTooManyClasses": [Function], @@ -490,11 +490,11 @@ exports[` initially renders succesfully 1`] = ` >
initially renders succesfully 1`] = ` "$$typeof": Symbol(react.forward_ref), "attrs": Array [], "componentStyle": ComponentStyle { - "componentId": "sc-bxivhb", + "componentId": "sc-htpNat", "isStatic": true, - "lastClassName": "gYEJOJ", + "lastClassName": "dqEVhr", "rules": Array [ "flex-grow: 1;", ], @@ -551,7 +551,7 @@ exports[` initially renders succesfully 1`] = ` "displayName": "Styled(ToolbarItem)", "foldedComponentIds": Array [], "render": [Function], - "styledComponentId": "sc-bxivhb", + "styledComponentId": "sc-htpNat", "target": [Function], "toString": [Function], "warnTooManyClasses": [Function], @@ -561,10 +561,10 @@ exports[` initially renders succesfully 1`] = ` forwardedRef={null} >
initially renders succesfully 1`] = ` "componentStyle": ComponentStyle { "componentId": "Search__NoOptionDropdown-sc-1dwuww3-3", "isStatic": true, - "lastClassName": "gMeiYd", + "lastClassName": "iMdtNX", "rules": Array [ - "align-self:stretch;border:1px solid grey;padding:3px 7px;white-space:nowrap;", + "align-self:stretch;border:1px solid var(--pf-global--BorderColor--200);padding:3px 7px;white-space:nowrap;", ], }, "displayName": "Search__NoOptionDropdown", @@ -661,7 +661,7 @@ exports[` initially renders succesfully 1`] = ` forwardedRef={null} >
Name
@@ -780,9 +780,9 @@ exports[` initially renders succesfully 1`] = ` "componentStyle": ComponentStyle { "componentId": "Search__TextInput-sc-1dwuww3-0", "isStatic": true, - "lastClassName": "EgkYH", + "lastClassName": "kyQbZs", "rules": Array [ - "min-height:0px;height:30px;", + "min-height:0px;height:30px;--pf-c-form-control--BorderTopColor:var(--pf-global--BorderColor--200);--pf-c-form-control--BorderLeftColor:var(--pf-global--BorderColor--200);", ], }, "displayName": "Search__TextInput", @@ -807,7 +807,7 @@ exports[` initially renders succesfully 1`] = ` > initially renders succesfully 1`] = ` initially renders succesfully 1`] = ` "componentStyle": ComponentStyle { "componentId": "Search__Button-sc-1dwuww3-1", "isStatic": true, - "lastClassName": "jtZPEu", + "lastClassName": "bLlonv", "rules": Array [ - "width:34px;padding:0px;", + "width:34px;padding:0px;::after{border:var(--pf-c-button--BorderWidth) solid var(--pf-global--BorderColor--200);}", ], }, "displayName": "Search__Button", @@ -881,7 +881,7 @@ exports[` initially renders succesfully 1`] = ` >
+ } + distance={15} + enableFlip={true} + entryDelay={500} + exitDelay={500} + flipBehavior={ + Array [ + "top", + "right", + "bottom", + "left", + "top", + "right", + "bottom", + ] + } + isAppLauncher={false} + maxWidth="18.75rem" + position="top" + trigger="mouseenter focus" + zIndex={9999} > - + +
+ Reverse Sort Order +
+
+
+ } + delay={ + Array [ + 500, + 500, + ] + } + distance={15} + flip={true} + flipBehavior={ + Array [ + "top", + "right", + "bottom", + "left", + "top", + "right", + "bottom", + ] + } + lazy={true} + maxWidth="18.75rem" + onCreate={[Function]} + performance={true} + placement="top" + popperOptions={ Object { - "$$typeof": Symbol(react.forward_ref), - "attrs": Array [], - "componentStyle": ComponentStyle { - "componentId": "sc-bwzfXH", - "isStatic": true, - "lastClassName": "iNPUwu", - "rules": Array [ - "padding: 0;", - ], + "modifiers": Object { + "hide": Object { + "enabled": true, + }, + "preventOverflow": Object { + "enabled": true, + }, }, - "displayName": "Styled(Button)", - "foldedComponentIds": Array [], - "render": [Function], - "styledComponentId": "sc-bwzfXH", - "target": [Function], - "toString": [Function], - "warnTooManyClasses": [Function], - "withComponent": [Function], } } - forwardedRef={null} - onClick={[Function]} - variant="plain" + theme="pf-tooltip" + trigger="mouseenter focus" + zIndex={9999} > - - - - + + + + + + + + + + + + + +
+
+
+ Reverse Sort Order +
+
+
+ + } + > +
+ +
+
+ Reverse Sort Order +
+
+
+
+
+ + diff --git a/awx/ui_next/src/screens/Template/TemplateList/TemplateListItem.jsx b/awx/ui_next/src/screens/Template/TemplateList/TemplateListItem.jsx index 964cc397d2..e37fd2eaee 100644 --- a/awx/ui_next/src/screens/Template/TemplateList/TemplateListItem.jsx +++ b/awx/ui_next/src/screens/Template/TemplateList/TemplateListItem.jsx @@ -4,7 +4,6 @@ import { DataListItem, DataListItemRow, DataListItemCells, - DataListCheck, Tooltip, Button as PFButton, } from '@patternfly/react-core'; @@ -14,6 +13,7 @@ import { RocketIcon } from '@patternfly/react-icons'; import styled from 'styled-components'; import DataListCell from '@components/DataListCell'; +import DataListCheck from '@components/DataListCheck'; import LaunchButton from '@components/LaunchButton'; import VerticalSeparator from '@components/VerticalSeparator'; import { Sparkline } from '@components/Sparkline'; diff --git a/awx/ui_next/src/screens/Template/TemplateList/TemplatesList.test.jsx b/awx/ui_next/src/screens/Template/TemplateList/TemplatesList.test.jsx index b94c8080f4..ab923d471d 100644 --- a/awx/ui_next/src/screens/Template/TemplateList/TemplatesList.test.jsx +++ b/awx/ui_next/src/screens/Template/TemplateList/TemplatesList.test.jsx @@ -123,7 +123,8 @@ describe('', () => { el => el.state('hasContentLoading') === false ); await wrapper - .find('DataListCheck#select-jobTemplate-1') + .find('input#select-jobTemplate-1') + .closest('DataListCheck') .props() .onChange(); expect(handleSelect).toBeCalled();