From 4d15df2b4853c25a32d244c5131ee9c260ecf4cf Mon Sep 17 00:00:00 2001 From: Keith Grant Date: Wed, 6 Mar 2019 14:30:21 -0500 Subject: [PATCH 1/6] fix pagination text when items displayed matches number of items per page --- __tests__/components/Pagination.test.jsx | 57 ++++++++++++++++++++++++ src/components/Pagination/Pagination.jsx | 9 +++- 2 files changed, 64 insertions(+), 2 deletions(-) diff --git a/__tests__/components/Pagination.test.jsx b/__tests__/components/Pagination.test.jsx index b2ca6727e8..552642665c 100644 --- a/__tests__/components/Pagination.test.jsx +++ b/__tests__/components/Pagination.test.jsx @@ -119,6 +119,63 @@ describe('', () => { pageSizeDropdownItems.at(1).simulate('click'); }); + test('itemCount displays correctly', () => { + const onSetPage = jest.fn(); + + pagination = mount( + + + + ); + const itemCount = pagination.find('.awx-pagination__item-count'); + expect(itemCount.text()).toEqual('Items 1 – 5 of 7'); + }); + + test('itemCount matching pageSize displays correctly', () => { + const onSetPage = jest.fn(); + + pagination = mount( + + + + ); + const itemCount = pagination.find('.awx-pagination__item-count'); + expect(itemCount.text()).toEqual('Items 1 – 5 of 5'); + }); + + test('itemCount less than pageSize displays correctly', () => { + const onSetPage = jest.fn(); + + pagination = mount( + + + + ); + const itemCount = pagination.find('.awx-pagination__item-count'); + expect(itemCount.text()).toEqual('Items 1 – 3 of 3'); + }); + test('submit a new page by typing in input works', () => { const textInputSelector = '.awx-pagination__page-input.pf-c-form-control'; const submitFormSelector = '.awx-pagination__page-input-form'; diff --git a/src/components/Pagination/Pagination.jsx b/src/components/Pagination/Pagination.jsx index 98a03b8e8c..a3eba1ca3e 100644 --- a/src/components/Pagination/Pagination.jsx +++ b/src/components/Pagination/Pagination.jsx @@ -116,7 +116,12 @@ class Pagination extends Component { const isOnFirst = page === 1; const isOnLast = page === pageCount; - const itemCount = isOnLast ? count % page_size : page_size; + let itemCount; + if (!isOnLast || count === page_size) { + itemCount = page_size; + } else { + itemCount = count % page_size; + } const itemMin = ((page - 1) * page_size) + 1; const itemMax = itemMin + itemCount - 1; @@ -154,7 +159,7 @@ class Pagination extends Component { )}
- {`Items ${itemMin} - ${itemMax} of ${count}`} + {`Items ${itemMin} – ${itemMax} of ${count}`}
{pageCount !== 1 && (
From ecb7306c4670196f03e3d215168527721277f00c Mon Sep 17 00:00:00 2001 From: Keith Grant Date: Mon, 11 Mar 2019 14:41:46 -0400 Subject: [PATCH 2/6] Adding organization: add inputs helper text --- src/pages/Organizations/screens/OrganizationAdd.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/Organizations/screens/OrganizationAdd.jsx b/src/pages/Organizations/screens/OrganizationAdd.jsx index 5f38a237f8..181c8dcd73 100644 --- a/src/pages/Organizations/screens/OrganizationAdd.jsx +++ b/src/pages/Organizations/screens/OrganizationAdd.jsx @@ -135,7 +135,7 @@ class OrganizationAdd extends React.Component { onChange={this.onFieldChange} /> - + {({ custom_virtualenvs }) => ( custom_virtualenvs && custom_virtualenvs.length > 1 && ( - + Date: Tue, 12 Mar 2019 08:58:12 -0400 Subject: [PATCH 3/6] add tooltips to add organization form --- .../Organizations/screens/OrganizationAdd.jsx | 36 +++++++++++++++++-- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/src/pages/Organizations/screens/OrganizationAdd.jsx b/src/pages/Organizations/screens/OrganizationAdd.jsx index 181c8dcd73..05cbd6fb23 100644 --- a/src/pages/Organizations/screens/OrganizationAdd.jsx +++ b/src/pages/Organizations/screens/OrganizationAdd.jsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { Fragment } from 'react'; import PropTypes from 'prop-types'; import { withRouter } from 'react-router-dom'; import { I18n, i18nMark } from '@lingui/react'; @@ -11,7 +11,9 @@ import { Gallery, Card, CardBody, + Tooltip, } from '@patternfly/react-core'; +import { QuestionCircleIcon } from '@patternfly/react-icons'; import { ConfigContext } from '../../../context'; import Lookup from '../../../components/Lookup'; @@ -135,7 +137,21 @@ class OrganizationAdd extends React.Component { onChange={this.onFieldChange} /> - + + {i18n._(t`Instance Groups`)} + {' '} + + + + + )} + fieldId="add-org-form-instance-groups" + > {({ custom_virtualenvs }) => ( custom_virtualenvs && custom_virtualenvs.length > 1 && ( - + + {i18n._(t`Ansible Environment`)} + {' '} + + + + + )} + fieldId="add-org-custom-virtualenv" + > Date: Tue, 12 Mar 2019 11:48:29 -0400 Subject: [PATCH 4/6] add close (x) button to Add Org screen --- .../screens/OrganizationAdd.test.jsx | 24 ++++++++- src/app.scss | 15 ++++++ .../Organizations/screens/OrganizationAdd.jsx | 50 ++++++++++++------- 3 files changed, 71 insertions(+), 18 deletions(-) diff --git a/__tests__/pages/Organizations/screens/OrganizationAdd.test.jsx b/__tests__/pages/Organizations/screens/OrganizationAdd.test.jsx index 9d5079ce70..6a1c919ce3 100644 --- a/__tests__/pages/Organizations/screens/OrganizationAdd.test.jsx +++ b/__tests__/pages/Organizations/screens/OrganizationAdd.test.jsx @@ -1,6 +1,6 @@ import React from 'react'; import { mount } from 'enzyme'; -import { MemoryRouter } from 'react-router-dom'; +import { MemoryRouter, Router } from 'react-router-dom'; import { I18nProvider } from '@lingui/react'; import { ConfigContext } from '../../../../src/context'; import OrganizationAdd from '../../../../src/pages/Organizations/screens/OrganizationAdd'; @@ -18,6 +18,7 @@ describe('', () => { ); }); + test('calls "onFieldChange" when input values change', () => { const spy = jest.spyOn(OrganizationAdd.WrappedComponent.prototype, 'onFieldChange'); const wrapper = mount( @@ -35,6 +36,7 @@ describe('', () => { wrapper.find('input#add-org-form-description').simulate('change', { target: { value: 'bar' } }); expect(spy).toHaveBeenCalledTimes(2); }); + test('calls "onSubmit" when Save button is clicked', () => { const spy = jest.spyOn(OrganizationAdd.WrappedComponent.prototype, 'onSubmit'); const wrapper = mount( @@ -51,6 +53,7 @@ describe('', () => { wrapper.find('button[aria-label="Save"]').prop('onClick')(); expect(spy).toBeCalled(); }); + test('calls "onCancel" when Cancel button is clicked', () => { const spy = jest.spyOn(OrganizationAdd.WrappedComponent.prototype, 'onCancel'); const wrapper = mount( @@ -68,6 +71,25 @@ describe('', () => { expect(spy).toBeCalled(); }); + test('calls "onCancel" when close button (x) is clicked', () => { + const wrapper = mount( + + + + + + ); + const history = wrapper.find(Router).prop('history'); + expect(history.length).toBe(1); + expect(history.location.pathname).toEqual('/organizations/add'); + wrapper.find('button[aria-label="Close"]').prop('onClick')(); + expect(history.length).toBe(2); + expect(history.location.pathname).toEqual('/organizations'); + }); + test('Successful form submission triggers redirect', (done) => { const onSuccess = jest.spyOn(OrganizationAdd.WrappedComponent.prototype, 'onSuccess'); const mockedResp = { data: { id: 1, related: { instance_groups: '/bar' } } }; diff --git a/src/app.scss b/src/app.scss index 934240376c..5d984dcbd5 100644 --- a/src/app.scss +++ b/src/app.scss @@ -206,6 +206,17 @@ --pf-c-card__body--PaddingTop: 24px; } +// +// pf tooltip overrides +// + +.pf-c-tooltip__content { + --pf-c-tooltip__content--PaddingTop: 0.71rem; + --pf-c-tooltip__content--PaddingRight: 0.71rem; + --pf-c-tooltip__content--PaddingBottom: 0.71rem; + --pf-c-tooltip__content--PaddingLeft: 0.71rem; +} + // // pf empty state overrides // @@ -238,3 +249,7 @@ --pf-c-card__body--PaddingX: 0; --pf-c-card__body--PaddingY: 0; } + +.at-u-textRight { + text-align: right; +} diff --git a/src/pages/Organizations/screens/OrganizationAdd.jsx b/src/pages/Organizations/screens/OrganizationAdd.jsx index 05cbd6fb23..9a1f8e6c01 100644 --- a/src/pages/Organizations/screens/OrganizationAdd.jsx +++ b/src/pages/Organizations/screens/OrganizationAdd.jsx @@ -10,10 +10,12 @@ import { TextInput, Gallery, Card, + CardHeader, CardBody, + Button, Tooltip, } from '@patternfly/react-core'; -import { QuestionCircleIcon } from '@patternfly/react-icons'; +import { QuestionCircleIcon, TimesIcon } from '@patternfly/react-icons'; import { ConfigContext } from '../../../context'; import Lookup from '../../../components/Lookup'; @@ -110,11 +112,25 @@ class OrganizationAdd extends React.Component { return ( - - -
- - {({ i18n }) => ( + + {({ i18n }) => ( + + + + + + + + - )} - - - {error ?
error
: ''} - -
-
+ + {error ?
error
: ''} + + + + )} +
); } From 188eaede43fcf79504f76537164ab3931fe3b6c5 Mon Sep 17 00:00:00 2001 From: Keith Grant Date: Tue, 12 Mar 2019 15:24:36 -0400 Subject: [PATCH 5/6] switch to PatternFly Tooltip everywhere --- __tests__/components/Tooltip.test.jsx | 69 ------------- src/app.scss | 4 + .../DataListToolbar/DataListToolbar.jsx | 4 +- src/components/Tabs/Tabs.jsx | 5 +- src/components/Tooltip/Tooltip.jsx | 96 ------------------- src/components/Tooltip/index.js | 3 - 6 files changed, 8 insertions(+), 173 deletions(-) delete mode 100644 __tests__/components/Tooltip.test.jsx delete mode 100644 src/components/Tooltip/Tooltip.jsx delete mode 100644 src/components/Tooltip/index.js diff --git a/__tests__/components/Tooltip.test.jsx b/__tests__/components/Tooltip.test.jsx deleted file mode 100644 index 9a78ae5fa0..0000000000 --- a/__tests__/components/Tooltip.test.jsx +++ /dev/null @@ -1,69 +0,0 @@ -import React from 'react'; -import { mount } from 'enzyme'; -import Tooltip from '../../src/components/Tooltip'; - -describe('', () => { - let elem; - let content; - let mouseOverHandler; - let mouseOutHandler; - const child = (foo); - const message = 'hi'; - - test('initially renders without crashing', () => { - elem = mount( - - {child} - - ); - expect(elem.length).toBe(1); - }); - - test('shows/hides with mouse over and leave', () => { - elem = mount( - - {child} - - ); - mouseOverHandler = elem.find('.mouseOverHandler'); - mouseOutHandler = elem.find('.mouseOutHandler'); - expect(elem.state().isDisplayed).toBe(false); - elem.update(); - content = elem.find('.pf-c-tooltip__content'); - expect(content.length).toBe(0); - mouseOverHandler.props().onMouseOver(); - expect(elem.state().isDisplayed).toBe(true); - elem.update(); - content = elem.find('.pf-c-tooltip__content'); - expect(content.length).toBe(1); - mouseOutHandler.props().onMouseLeave(); - expect(elem.state().isDisplayed).toBe(false); - elem.update(); - content = elem.find('.pf-c-tooltip__content'); - expect(content.length).toBe(0); - }); - - test('shows/hides with focus and blur', () => { - elem = mount( - - {child} - - ); - mouseOverHandler = elem.find('.mouseOverHandler'); - mouseOutHandler = elem.find('.mouseOutHandler'); - expect(elem.state().isDisplayed).toBe(false); - elem.update(); - content = elem.find('.pf-c-tooltip__content'); - expect(content.length).toBe(0); - mouseOverHandler.props().onFocus(); - expect(elem.state().isDisplayed).toBe(true); - elem.update(); - content = elem.find('.pf-c-tooltip__content'); - expect(content.length).toBe(1); - mouseOutHandler.props().onBlur(); - expect(elem.state().isDisplayed).toBe(false); - elem.update(); - content = elem.find('.pf-c-tooltip__content'); - expect(content.length).toBe(0); - }); -}); diff --git a/src/app.scss b/src/app.scss index 5d984dcbd5..1f0d7ee0c2 100644 --- a/src/app.scss +++ b/src/app.scss @@ -216,6 +216,10 @@ --pf-c-tooltip__content--PaddingBottom: 0.71rem; --pf-c-tooltip__content--PaddingLeft: 0.71rem; } +// higher specificity needed to override PF styles added dynamically to page +.pf-c-tooltip .pf-c-tooltip__content { + text-align: left; +} // // pf empty state overrides diff --git a/src/components/DataListToolbar/DataListToolbar.jsx b/src/components/DataListToolbar/DataListToolbar.jsx index 2810a52435..efa66c1a70 100644 --- a/src/components/DataListToolbar/DataListToolbar.jsx +++ b/src/components/DataListToolbar/DataListToolbar.jsx @@ -15,6 +15,7 @@ import { Toolbar, ToolbarGroup, ToolbarItem, + Tooltip, } from '@patternfly/react-core'; import { BarsIcon, @@ -30,7 +31,6 @@ import { Link } from 'react-router-dom'; -import Tooltip from '../Tooltip'; import VerticalSeparator from '../VerticalSeparator'; const flexGrowStyling = { @@ -291,7 +291,7 @@ class DataListToolbar extends React.Component { { showDelete && (