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

Add loading indicator for select #1716

Merged
merged 11 commits into from
Nov 5, 2019
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

### Added
- Add statereducer function to Select component: Scrolls to last selected item [#1715](https://github.com/greenbone/gsa/pull/1715)
- Add loading indicator to select [#1716](https://github.com/greenbone/gsa/pull/1716)
- Add loading indicator to svg icon [#1701](https://github.com/greenbone/gsa/pull/1701)
- Update German Translation [#1689](https://github.com/greenbone/gsa/pull/1689)
- List NVT of the found CVEs at the report details page [#1673](https://github.com/greenbone/gsa/pull/1673)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,12 @@ exports[`DatePicker component tests should render 2`] = `
class="react-datepicker__input-container"
>
<div
class="sc-iBEsjs jPgHBa"
class="sc-hzNEM gqYbXA"
width="auto"
>
2018/11/11
<span
class="sc-LKuAh kEybis sc-jzJRlG lcpYA sc-fjdhpX fEEsMp"
class="sc-iBEsjs hwafBF sc-jzJRlG lcpYA sc-fjdhpX fEEsMp"
data-testid="svg-icon"
>
<svg>
Expand Down
27 changes: 27 additions & 0 deletions gsa/src/web/components/form/__tests__/multiselect.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,14 @@
*/
import React from 'react';

import {setLocale} from 'gmp/locale/lang';

import {render, fireEvent} from 'web/utils/testing';

import MultiSelect from '../multiselect.js';

setLocale('en');

const openInputElement = element => {
const button = element.querySelector('[type="button"]');
fireEvent.click(button);
Expand Down Expand Up @@ -64,6 +68,29 @@ describe('MultiSelect component tests', () => {
expect(domItems[1]).toHaveTextContent('Foo');
});

test('should render loading', () => {
const items = [
{
value: '0',
label: '--',
},
];

const {element, baseElement} = render(
<MultiSelect items={items} isLoading={true} />,
);

expect(element).toHaveTextContent('Loading...');

let domItems = getItemElements(baseElement);
expect(domItems.length).toEqual(0);

openInputElement(element);

domItems = getItemElements(baseElement);
expect(domItems.length).toEqual(0);
});

test('should call onChange handler', () => {
const items = [
{
Expand Down
27 changes: 27 additions & 0 deletions gsa/src/web/components/form/__tests__/select.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
*/
import React from 'react';

import {setLocale} from 'gmp/locale/lang';

import {
render,
fireEvent,
Expand All @@ -27,6 +29,8 @@ import {

import Select from '../select.js';

setLocale('en');

export const openSelectElement = element => {
const openButton = getByTestId(element, 'select-open-button');
fireEvent.click(openButton);
Expand Down Expand Up @@ -75,6 +79,29 @@ describe('Select component tests', () => {
expect(domItems[1]).toHaveTextContent('Foo');
});

test('should render loading', () => {
const items = [
{
value: '0',
label: '--',
},
];

const {element, baseElement} = render(
<Select items={items} isLoading={true} />,
);

expect(element).toHaveTextContent('Loading...');

let domItems = getItemElements(baseElement);
expect(domItems.length).toEqual(0);

openSelectElement(element);

domItems = getItemElements(baseElement);
expect(domItems.length).toEqual(0);
});

test('should call onChange handler', () => {
const items = [
{
Expand Down
11 changes: 9 additions & 2 deletions gsa/src/web/components/form/multiselect.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import styled from 'styled-components';

import Downshift from 'downshift';

import _ from 'gmp/locale';

import {arraysEqual} from 'gmp/utils/array';
import {isDefined, isArray} from 'gmp/utils/identity';

Expand Down Expand Up @@ -178,11 +180,12 @@ class MultiSelect extends React.Component {
menuPosition = 'adjust',
width = DEFAULT_WIDTH,
grow,
isLoading = false,
} = this.props;

const {search, selectedItems} = this.state;

disabled = disabled || !isDefined(items) || items.length === 0;
disabled = disabled || !isDefined(items) || items.length === 0 || isLoading;

const displayedItems = isDefined(items)
? items.filter(caseInsensitiveFilter(search))
Expand Down Expand Up @@ -215,7 +218,9 @@ class MultiSelect extends React.Component {
>
<Box isOpen={isOpen} disabled={disabled} ref={this.box}>
<Layout grow="1" wrap>
{selectedItems.map(item => this.renderItem(item, items))}
{isLoading
? _('Loading...')
: selectedItems.map(item => this.renderItem(item, items))}
</Layout>
<Layout align={['center', 'center']}>
<ArrowIcon
Expand All @@ -233,6 +238,7 @@ class MultiSelect extends React.Component {
},
})}
size="small"
isLoading={isLoading}
/>
</Layout>
</Box>
Expand Down Expand Up @@ -285,6 +291,7 @@ class MultiSelect extends React.Component {
MultiSelect.propTypes = {
disabled: PropTypes.bool,
grow: PropTypes.number,
isLoading: PropTypes.bool,
items: PropTypes.arrayOf(PropTypes.object),
menuPosition: PropTypes.oneOf(['left', 'right', 'adjust']),
name: PropTypes.string,
Expand Down
11 changes: 9 additions & 2 deletions gsa/src/web/components/form/select.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import React from 'react';

import Downshift from 'downshift';

import _ from 'gmp/locale';

import {isDefined, isArray} from 'gmp/utils/identity';

import PropTypes, {mayRequire} from 'web/utils/proptypes';
Expand Down Expand Up @@ -142,11 +144,12 @@ class Select extends React.Component {
value,
toolTipTitle,
width = DEFAULT_WIDTH,
isLoading = false,
} = this.props;

const {search} = this.state;

disabled = disabled || !isDefined(items) || items.length === 0;
disabled = disabled || !isDefined(items) || items.length === 0 || isLoading;

const displayedItems = isDefined(items)
? items.filter(caseInsensitiveFilter(search))
Expand Down Expand Up @@ -184,7 +187,9 @@ class Select extends React.Component {
selectItem,
selectedItem,
}) => {
const label = find_label(items, selectedItem);
const label = isLoading
? _('Loading...')
: find_label(items, selectedItem);
return (
<SelectContainer
{...getRootProps({})}
Expand Down Expand Up @@ -222,6 +227,7 @@ class Select extends React.Component {
data-testid="select-open-button"
down={!isOpen}
size="small"
isLoading={isLoading}
/>
</Layout>
</Box>
Expand Down Expand Up @@ -278,6 +284,7 @@ class Select extends React.Component {

Select.propTypes = {
disabled: PropTypes.bool,
isLoading: PropTypes.bool,
itemToString: PropTypes.func,
items: PropTypes.arrayOf(
PropTypes.shape({
Expand Down
15 changes: 12 additions & 3 deletions gsa/src/web/components/icon/arrowicon.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ import styled from 'styled-components';

import PropTypes from 'web/utils/proptypes.js';

import withIconSize from 'web/components/icon/withIconSize';
import withIconSize, {
ICON_SIZE_SMALL_PIXELS,
} from 'web/components/icon/withIconSize';

const Styled = styled.span`
background-color: transparent;
Expand All @@ -37,12 +39,19 @@ const Styled = styled.span`
cursor: ${props => (props.disabled ? 'not-allowed' : 'pointer')};
`;

const ArrowIcon = ({down = false, ...props}) => (
<Styled {...props}>{down ? '▼' : '▲'}</Styled>
const Loading = styled.span`
height: ${ICON_SIZE_SMALL_PIXELS + 'px'};
width: ${ICON_SIZE_SMALL_PIXELS + 'px'};
background: url(/img/loading.gif) center center no-repeat;
`;

const ArrowIcon = ({down = false, isLoading = false, ...props}) => (
<Styled {...props}>{isLoading ? <Loading /> : down ? '▼' : '▲'}</Styled>
);

ArrowIcon.propTypes = {
down: PropTypes.bool,
isLoading: PropTypes.bool,
};

export default withIconSize()(ArrowIcon);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -792,6 +792,9 @@ exports[`GlobalStyles tests should render global styles 1`] = `
/* sc-component-id: sc-iYUSvU */


/* sc-component-id: sc-cHSUfg */


/* sc-component-id: sc-global-2342249302 */
html{box-sizing:border-box;} *,*:before,*:after{box-sizing:inherit;} body{margin:0;font-family:Verdana,sans-serif;font-size:12px;color:#000;} a:link{color:#0000ff;-webkit-text-decoration:none;text-decoration:none;} a:hover,a:focus{color:blue;-webkit-text-decoration:underline;text-decoration:underline;} pre{white-space:pre-wrap;word-wrap:break-word;} img{border:0;} svg{overflow:hidden;} h1{font-size:20px;} h2{font-size:18px;} h3{font-size:16px;} h4{font-size:14px;margin-bottom:0;} p{margin:0 0 10px;}
</style>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ exports[`Relation Selector Tests should render 1`] = `
<div
aria-expanded="false"
aria-haspopup="listbox"
aria-labelledby="downshift-6-label"
aria-labelledby="downshift-7-label"
class="c0"
role="combobox"
width="180px"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,7 @@ exports[`Severity Values Group Tests should render 1`] = `
<div
aria-expanded="false"
aria-haspopup="listbox"
aria-labelledby="downshift-6-label"
aria-labelledby="downshift-7-label"
class="c5"
role="combobox"
width="180px"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ exports[`Task Trend Selector Tests should render 1`] = `
<div
aria-expanded="false"
aria-haspopup="listbox"
aria-labelledby="downshift-6-label"
aria-labelledby="downshift-7-label"
class="c3"
role="combobox"
width="180px"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ exports[`TicketStatusGroup tests should render 1`] = `
<div
aria-expanded="false"
aria-haspopup="listbox"
aria-labelledby="downshift-6-label"
aria-labelledby="downshift-7-label"
class="c3"
role="combobox"
width="180px"
Expand Down
3 changes: 3 additions & 0 deletions gsa/src/web/components/powerfilter/powerfilter.js
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ class PowerFilter extends React.Component {
filter,
filters,
isLoading = false,
isLoadingFilters,
onEditClick,
onRemoveClick,
onResetClick,
Expand Down Expand Up @@ -243,6 +244,7 @@ class PowerFilter extends React.Component {
{capabilities.mayAccess('filters') && (
<Select
items={renderSelectItems(filters, DEFAULT_FILTER_ID)}
isLoading={isLoadingFilters}
menuPosition="right"
toolTipTitle={_('Loaded filter')}
value={
Expand All @@ -267,6 +269,7 @@ PowerFilter.propTypes = {
filters: PropTypes.array,
gmp: PropTypes.gmp.isRequired,
isLoading: PropTypes.bool,
isLoadingFilters: PropTypes.bool,
onEditClick: PropTypes.func,
onError: PropTypes.func,
onFilterCreated: PropTypes.func,
Expand Down
7 changes: 6 additions & 1 deletion gsa/src/web/entities/page.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*/

import React from 'react';

import {connect} from 'react-redux';
Expand Down Expand Up @@ -184,6 +183,7 @@ class EntitiesPage extends React.Component {
filterEditDialog,
filters,
isLoading,
isLoadingFilters,
powerfilter = PowerFilter,
onError,
onFilterChanged,
Expand All @@ -207,6 +207,7 @@ class EntitiesPage extends React.Component {
filter={filter}
filters={filters}
isLoading={isLoading}
isLoadingFilters={isLoadingFilters}
onEditClick={handler}
onError={onError}
onRemoveClick={onFilterRemoved}
Expand Down Expand Up @@ -292,6 +293,7 @@ EntitiesPage.propTypes = {
filters: PropTypes.array,
filtersFilter: PropTypes.filter,
isLoading: PropTypes.bool,
isLoadingFilters: PropTypes.bool,
loadFilters: PropTypes.func.isRequired,
powerfilter: PropTypes.componentOrFalse,
section: PropTypes.componentOrFalse,
Expand All @@ -318,13 +320,16 @@ const mapStateToProps = (state, {filtersFilter}) => {
if (!isDefined(filtersFilter)) {
return {
filters: [],
isLoadingFilters: false,
};
}

const filterSelector = selector(state);
const filters = filterSelector.getAllEntities(filtersFilter);

return {
filters: hasValue(filters) ? filters : [],
isLoadingFilters: filterSelector.isLoadingAllEntities(filtersFilter),
};
};

Expand Down
16 changes: 9 additions & 7 deletions gsa/src/web/pages/audits/__tests__/listpage.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,13 +75,15 @@ const getSetting = jest.fn().mockResolvedValue({
filter: null,
});

const getFilters = jest.fn().mockResolvedValue({
data: [],
meta: {
filter: Filter.fromString(),
counts: new CollectionCounts(),
},
});
const getFilters = jest.fn().mockReturnValue(
Promise.resolve({
data: [],
meta: {
filter: Filter.fromString(),
counts: new CollectionCounts(),
},
}),
);

const getAudits = jest.fn().mockResolvedValue({
data: [audit],
Expand Down
Loading