more ui_next search pr feedback:

- updae .filter().length calls to .find()
- fix ProjectList errors
This commit is contained in:
John Mitchell
2020-01-09 13:55:19 -05:00
parent 3cdf274bdb
commit 1e344bdf8a
37 changed files with 330 additions and 417 deletions

View File

@@ -146,7 +146,7 @@ class AddResourceRole extends React.Component {
{ {
name: i18n._(t`Username`), name: i18n._(t`Username`),
key: 'username', key: 'username',
isDefault: true isDefault: true,
}, },
{ {
name: i18n._(t`First Name`), name: i18n._(t`First Name`),
@@ -155,7 +155,7 @@ class AddResourceRole extends React.Component {
{ {
name: i18n._(t`Last Name`), name: i18n._(t`Last Name`),
key: 'last_name', key: 'last_name',
} },
]; ];
const userSortColumns = [ const userSortColumns = [
@@ -170,14 +170,14 @@ class AddResourceRole extends React.Component {
{ {
name: i18n._(t`Last Name`), name: i18n._(t`Last Name`),
key: 'last_name', key: 'last_name',
} },
]; ];
const teamSearchColumns = [ const teamSearchColumns = [
{ {
name: i18n._(t`Name`), name: i18n._(t`Name`),
key: 'name', key: 'name',
isDefault: true isDefault: true,
}, },
{ {
name: i18n._(t`Created By (Username)`), name: i18n._(t`Created By (Username)`),

View File

@@ -24,7 +24,11 @@ class SelectResourceStep extends React.Component {
this.qsConfig = getQSConfig('resource', { this.qsConfig = getQSConfig('resource', {
page: 1, page: 1,
page_size: 5, page_size: 5,
order_by: `${props.sortColumns.filter(col => col.key === 'name').length ? 'name' : 'username'}` order_by: `${
props.sortColumns.filter(col => col.key === 'name').length
? 'name'
: 'username'
}`,
}); });
} }

View File

@@ -10,14 +10,14 @@ describe('<SelectResourceStep />', () => {
{ {
name: 'Username', name: 'Username',
key: 'username', key: 'username',
isDefault: true isDefault: true,
}, },
]; ];
const sortColumns = [ const sortColumns = [
{ {
name: 'Username', name: 'Username',
key: 'username' key: 'username',
}, },
]; ];
afterEach(() => { afterEach(() => {

View File

@@ -2,12 +2,16 @@ import React, { Fragment } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { withI18n } from '@lingui/react'; import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
import { import { Checkbox } from '@patternfly/react-core';
Checkbox,
} from '@patternfly/react-core';
import styled from 'styled-components'; import styled from 'styled-components';
import { SearchIcon } from '@patternfly/react-icons'; import { SearchIcon } from '@patternfly/react-icons';
import { DataToolbar, DataToolbarContent, DataToolbarGroup, DataToolbarToggleGroup, DataToolbarItem } from '@patternfly/react-core/dist/umd/experimental'; import {
DataToolbar,
DataToolbarContent,
DataToolbarGroup,
DataToolbarToggleGroup,
DataToolbarItem,
} from '@patternfly/react-core/dist/umd/experimental';
import ExpandCollapse from '../ExpandCollapse'; import ExpandCollapse from '../ExpandCollapse';
import Search from '../Search'; import Search from '../Search';
import Sort from '../Sort'; import Sort from '../Sort';
@@ -60,7 +64,8 @@ class DataListToolbar extends React.Component {
const showExpandCollapse = onCompact && onExpand; const showExpandCollapse = onCompact && onExpand;
return ( return (
<DataToolbar id={`${qsConfig.namespace}-list-toolbar`} <DataToolbar
id={`${qsConfig.namespace}-list-toolbar`}
clearAllFilters={clearAllFilters} clearAllFilters={clearAllFilters}
collapseListedFiltersBreakpoint="xl" collapseListedFiltersBreakpoint="xl"
> >
@@ -89,11 +94,7 @@ class DataListToolbar extends React.Component {
/> />
</DataToolbarItem> </DataToolbarItem>
<DataToolbarItem> <DataToolbarItem>
<Sort <Sort qsConfig={qsConfig} columns={sortColumns} onSort={onSort} />
qsConfig={qsConfig}
columns={sortColumns}
onSort={onSort}
/>
</DataToolbarItem> </DataToolbarItem>
</DataToolbarToggleGroup> </DataToolbarToggleGroup>
<DataToolbarGroup> <DataToolbarGroup>

View File

@@ -25,12 +25,8 @@ describe('<DataListToolbar />', () => {
const onSelectAll = jest.fn(); const onSelectAll = jest.fn();
test('it triggers the expected callbacks', () => { test('it triggers the expected callbacks', () => {
const searchColumns = [ const searchColumns = [{ name: 'Name', key: 'name', isDefault: true }];
{ name: 'Name', key: 'name', isDefault: true } const sortColumns = [{ name: 'Name', key: 'name' }];
];
const sortColumns = [
{ name: 'Name', key: 'name' }
];
const search = 'button[aria-label="Search submit button"]'; const search = 'button[aria-label="Search submit button"]';
const searchTextInput = 'input[aria-label="Search text input"]'; const searchTextInput = 'input[aria-label="Search text input"]';
const selectAll = 'input[aria-label="Select all"]'; const selectAll = 'input[aria-label="Select all"]';
@@ -86,12 +82,12 @@ describe('<DataListToolbar />', () => {
const searchColumns = [ const searchColumns = [
{ name: 'Foo', key: 'foo', isDefault: true }, { name: 'Foo', key: 'foo', isDefault: true },
{ name: 'Bar', key: 'bar' } { name: 'Bar', key: 'bar' },
]; ];
const sortColumns = [ const sortColumns = [
{ name: 'Foo', key: 'foo' }, { name: 'Foo', key: 'foo' },
{ name: 'Bar', key: 'bar' }, { name: 'Bar', key: 'bar' },
{ name: 'Bakery', key: 'Bakery' } { name: 'Bakery', key: 'Bakery' },
]; ];
toolbar = mountWithContexts( toolbar = mountWithContexts(
@@ -189,17 +185,13 @@ describe('<DataListToolbar />', () => {
const downAlphaIconSelector = 'SortAlphaDownIcon'; const downAlphaIconSelector = 'SortAlphaDownIcon';
const upAlphaIconSelector = 'SortAlphaUpIcon'; const upAlphaIconSelector = 'SortAlphaUpIcon';
const numericColumns = [ const numericColumns = [{ name: 'ID', key: 'id' }];
{ name: 'ID', key: 'id' },
];
const alphaColumns = [ const alphaColumns = [{ name: 'Name', key: 'name' }];
{ name: 'Name', key: 'name' },
];
const searchColumns = [ const searchColumns = [
{ name: 'Name', key: 'name', isDefault: true }, { name: 'Name', key: 'name', isDefault: true },
{ name: 'ID', key: 'id' } { name: 'ID', key: 'id' },
]; ];
toolbar = mountWithContexts( toolbar = mountWithContexts(
@@ -248,12 +240,8 @@ describe('<DataListToolbar />', () => {
}); });
test('should render additionalControls', () => { test('should render additionalControls', () => {
const searchColumns = [ const searchColumns = [{ name: 'Name', key: 'name', isDefault: true }];
{ name: 'Name', key: 'name', isDefault: true } const sortColumns = [{ name: 'Name', key: 'name' }];
];
const sortColumns = [
{ name: 'Name', key: 'name' }
];
toolbar = mountWithContexts( toolbar = mountWithContexts(
<DataListToolbar <DataListToolbar
@@ -278,12 +266,8 @@ describe('<DataListToolbar />', () => {
}); });
test('it triggers the expected callbacks', () => { test('it triggers the expected callbacks', () => {
const searchColumns = [ const searchColumns = [{ name: 'Name', key: 'name', isDefault: true }];
{ name: 'Name', key: 'name', isDefault: true } const sortColumns = [{ name: 'Name', key: 'name' }];
];
const sortColumns = [
{ name: 'Name', key: 'name' }
];
toolbar = mountWithContexts( toolbar = mountWithContexts(
<DataListToolbar <DataListToolbar
qsConfig={QS_CONFIG} qsConfig={QS_CONFIG}

View File

@@ -2,7 +2,10 @@ import React, { Fragment } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { withRouter } from 'react-router-dom'; import { withRouter } from 'react-router-dom';
import styled from 'styled-components'; import styled from 'styled-components';
import { DataToolbar, DataToolbarContent } from '@patternfly/react-core/dist/umd/experimental'; import {
DataToolbar,
DataToolbarContent,
} from '@patternfly/react-core/dist/umd/experimental';
import DataListToolbar from '@components/DataListToolbar'; import DataListToolbar from '@components/DataListToolbar';
import { import {
@@ -40,7 +43,7 @@ class ListHeader extends React.Component {
const { location, qsConfig } = this.props; const { location, qsConfig } = this.props;
let params = parseQueryString(qsConfig, location.search); let params = parseQueryString(qsConfig, location.search);
params = mergeParams(params, { [key]: value }); params = mergeParams(params, { [key]: value });
params = replaceParams(params, { 'page' : 1 }) params = replaceParams(params, { page: 1 });
this.pushHistoryState(params); this.pushHistoryState(params);
} }
@@ -54,7 +57,9 @@ class ListHeader extends React.Component {
const { location, qsConfig } = this.props; const { location, qsConfig } = this.props;
let oldParams = parseQueryString(qsConfig, location.search); let oldParams = parseQueryString(qsConfig, location.search);
if (parseInt(value, 10)) { if (parseInt(value, 10)) {
oldParams = removeParams(qsConfig, oldParams, { [key]: parseInt(value, 10) }); oldParams = removeParams(qsConfig, oldParams, {
[key]: parseInt(value, 10),
});
} }
this.pushHistoryState(removeParams(qsConfig, oldParams, { [key]: value })); this.pushHistoryState(removeParams(qsConfig, oldParams, { [key]: value }));
} }
@@ -96,7 +101,8 @@ class ListHeader extends React.Component {
return ( return (
<Fragment> <Fragment>
{isEmpty ? ( {isEmpty ? (
<DataToolbar id={`${qsConfig.namespace}-list-toolbar`} <DataToolbar
id={`${qsConfig.namespace}-list-toolbar`}
clearAllFilters={this.handleRemoveAll} clearAllFilters={this.handleRemoveAll}
collapseListedFiltersBreakpoint="md" collapseListedFiltersBreakpoint="md"
> >

View File

@@ -16,12 +16,8 @@ describe('ListHeader', () => {
<ListHeader <ListHeader
itemCount={50} itemCount={50}
qsConfig={qsConfig} qsConfig={qsConfig}
searchColumns={[ searchColumns={[{ name: 'foo', key: 'foo', isDefault: true }]}
{ name: 'foo', key: 'foo', isDefault: true}, sortColumns={[{ name: 'foo', key: 'foo' }]}
]}
sortColumns={[
{ name: 'foo', key: 'foo'},
]}
renderToolbar={renderToolbarFn} renderToolbar={renderToolbarFn}
/> />
); );
@@ -37,12 +33,8 @@ describe('ListHeader', () => {
<ListHeader <ListHeader
itemCount={7} itemCount={7}
qsConfig={qsConfig} qsConfig={qsConfig}
searchColumns={[ searchColumns={[{ name: 'foo', key: 'foo', isDefault: true }]}
{ name: 'foo', key: 'foo', isDefault: true}, sortColumns={[{ name: 'foo', key: 'foo' }]}
]}
sortColumns={[
{ name: 'foo', key: 'foo'},
]}
/>, />,
{ context: { router: { history } } } { context: { router: { history } } }
); );

View File

@@ -27,7 +27,7 @@ function CredentialLookup({
credentialTypeId, credentialTypeId,
value, value,
history, history,
i18n i18n,
}) { }) {
const [credentials, setCredentials] = useState([]); const [credentials, setCredentials] = useState([]);
const [count, setCount] = useState(0); const [count, setCount] = useState(0);
@@ -79,7 +79,7 @@ function CredentialLookup({
{ {
name: i18n._(t`Name`), name: i18n._(t`Name`),
key: 'name', key: 'name',
isDefault: true isDefault: true,
}, },
{ {
name: i18n._(t`Created By (Username)`), name: i18n._(t`Created By (Username)`),
@@ -88,12 +88,14 @@ function CredentialLookup({
{ {
name: i18n._(t`Modified By (Username)`), name: i18n._(t`Modified By (Username)`),
key: 'modified_by__username', key: 'modified_by__username',
} },
]}
sortColumns={[
{
name: i18n._(t`Name`),
key: 'name',
},
]} ]}
sortColumns={[{
name: i18n._(t`Name`),
key: 'name'
}]}
readOnly={!canDelete} readOnly={!canDelete}
selectItem={item => dispatch({ type: 'SELECT_ITEM', item })} selectItem={item => dispatch({ type: 'SELECT_ITEM', item })}
deselectItem={item => dispatch({ type: 'DESELECT_ITEM', item })} deselectItem={item => dispatch({ type: 'DESELECT_ITEM', item })}

View File

@@ -68,11 +68,11 @@ function InstanceGroupsLookup(props) {
{ {
name: i18n._(t`Name`), name: i18n._(t`Name`),
key: 'name', key: 'name',
isDefault: true isDefault: true,
}, },
{ {
name: i18n._(t`Credential Name`), name: i18n._(t`Credential Name`),
key: 'credential__name' key: 'credential__name',
}, },
{ {
name: i18n._(t`Created By (Username)`), name: i18n._(t`Created By (Username)`),
@@ -83,10 +83,12 @@ function InstanceGroupsLookup(props) {
key: 'modified_by__username', key: 'modified_by__username',
}, },
]} ]}
sortColumns={[{ sortColumns={[
name: i18n._(t`Name`), {
key: 'name' name: i18n._(t`Name`),
}]} key: 'name',
},
]}
multiple={state.multiple} multiple={state.multiple}
header={i18n._(t`Instance Groups`)} header={i18n._(t`Instance Groups`)}
name="instanceGroups" name="instanceGroups"

View File

@@ -72,7 +72,7 @@ function InventoryLookup({
{ {
name: i18n._(t`Name`), name: i18n._(t`Name`),
key: 'name', key: 'name',
isDefault: true isDefault: true,
}, },
{ {
name: i18n._(t`Created By (Username)`), name: i18n._(t`Created By (Username)`),

View File

@@ -126,7 +126,7 @@ function MultiCredentialsLookup(props) {
{ {
name: i18n._(t`Name`), name: i18n._(t`Name`),
key: 'name', key: 'name',
isDefault: true isDefault: true,
}, },
{ {
name: i18n._(t`Created By (Username)`), name: i18n._(t`Created By (Username)`),
@@ -137,10 +137,12 @@ function MultiCredentialsLookup(props) {
key: 'modified_by__username', key: 'modified_by__username',
}, },
]} ]}
sortColumns={[{ sortColumns={[
name: i18n._(t`Name`), {
key: 'name' name: i18n._(t`Name`),
}]} key: 'name',
},
]}
multiple={isMultiple} multiple={isMultiple}
header={i18n._(t`Credentials`)} header={i18n._(t`Credentials`)}
name="credentials" name="credentials"

View File

@@ -74,7 +74,7 @@ function OrganizationLookup({
{ {
name: i18n._(t`Name`), name: i18n._(t`Name`),
key: 'name', key: 'name',
isDefault: true isDefault: true,
}, },
{ {
name: i18n._(t`Created By (Username)`), name: i18n._(t`Created By (Username)`),
@@ -85,10 +85,12 @@ function OrganizationLookup({
key: 'modified_by__username', key: 'modified_by__username',
}, },
]} ]}
sortColumns={[{ sortColumns={[
name: i18n._(t`Name`), {
key: 'name' name: i18n._(t`Name`),
}]} key: 'name',
},
]}
readOnly={!canDelete} readOnly={!canDelete}
selectItem={item => dispatch({ type: 'SELECT_ITEM', item })} selectItem={item => dispatch({ type: 'SELECT_ITEM', item })}
deselectItem={item => dispatch({ type: 'DESELECT_ITEM', item })} deselectItem={item => dispatch({ type: 'DESELECT_ITEM', item })}

View File

@@ -74,32 +74,17 @@ function ProjectLookup({
{ {
name: i18n._(t`Name`), name: i18n._(t`Name`),
key: 'name', key: 'name',
isDefault: true isDefault: true,
}, },
{ {
name: i18n._(t`Type`), name: i18n._(t`Type`),
options: [ options: [
[ [``, i18n._(t`Manual`)],
``, [`git`, i18n._(t`Git`)],
i18n._(t`Manual`) [`hg`, i18n._(t`Mercurial`)],
], [`svn`, i18n._(t`Subversion`)],
[ [`insights`, i18n._(t`Red Hat Insights`)],
`git`, ],
i18n._(t`Git`)
],
[
`hg`,
i18n._(t`Mercurial`)
],
[
`svn`,
i18n._(t`Subversion`)
],
[
`insights`,
i18n._(t`Red Hat Insights`)
]
]
}, },
{ {
name: i18n._(t`SCM URL`), name: i18n._(t`SCM URL`),
@@ -118,7 +103,7 @@ function ProjectLookup({
{ {
name: i18n._(t`Name`), name: i18n._(t`Name`),
key: 'name', key: 'name',
} },
]} ]}
options={projects} options={projects}
optionCount={count} optionCount={count}

View File

@@ -101,7 +101,7 @@ OptionsList.defaultProps = {
multiple: false, multiple: false,
renderItemChip: null, renderItemChip: null,
searchColumns: [], searchColumns: [],
sortColumns: [] sortColumns: [],
}; };
export default withI18n()(OptionsList); export default withI18n()(OptionsList);

View File

@@ -17,7 +17,7 @@ describe('<OptionsList />', () => {
value={[]} value={[]}
options={options} options={options}
optionCount={3} optionCount={3}
searchColumns={[{name: 'Foo', key: 'foo', isDefault: true}]} searchColumns={[{ name: 'Foo', key: 'foo', isDefault: true }]}
sortColumns={[{ name: 'Foo', key: 'foo' }]} sortColumns={[{ name: 'Foo', key: 'foo' }]}
qsConfig={qsConfig} qsConfig={qsConfig}
selectItem={() => {}} selectItem={() => {}}
@@ -40,7 +40,7 @@ describe('<OptionsList />', () => {
value={[options[1]]} value={[options[1]]}
options={options} options={options}
optionCount={3} optionCount={3}
searchColumns={[{name: 'Foo', key: 'foo', isDefault: true}]} searchColumns={[{ name: 'Foo', key: 'foo', isDefault: true }]}
sortColumns={[{ name: 'Foo', key: 'foo' }]} sortColumns={[{ name: 'Foo', key: 'foo' }]}
qsConfig={qsConfig} qsConfig={qsConfig}
selectItem={() => {}} selectItem={() => {}}

View File

@@ -202,7 +202,7 @@ class NotificationList extends Component {
{ {
name: i18n._(t`Name`), name: i18n._(t`Name`),
key: 'name', key: 'name',
isDefault: true isDefault: true,
}, },
{ {
name: i18n._(t`Type`), name: i18n._(t`Type`),
@@ -218,7 +218,7 @@ class NotificationList extends Component {
['slack', i18n._(t`Slack`)], ['slack', i18n._(t`Slack`)],
['twilio', i18n._(t`Twilio`)], ['twilio', i18n._(t`Twilio`)],
['webhook', i18n._(t`Webhook`)], ['webhook', i18n._(t`Webhook`)],
] ],
}, },
{ {
name: i18n._(t`Created By (Username)`), name: i18n._(t`Created By (Username)`),

View File

@@ -80,7 +80,7 @@ class PaginatedDataList extends React.Component {
{ {
name: i18n._(t`Name`), name: i18n._(t`Name`),
key: 'name', key: 'name',
isDefault: true isDefault: true,
}, },
]; ];
const sortColumns = toolbarSortColumns.length const sortColumns = toolbarSortColumns.length

View File

@@ -166,7 +166,7 @@ class ResourceAccessList extends React.Component {
{ {
name: i18n._(t`Username`), name: i18n._(t`Username`),
key: 'username', key: 'username',
isDefault: true isDefault: true,
}, },
{ {
name: i18n._(t`First Name`), name: i18n._(t`First Name`),

View File

@@ -19,7 +19,7 @@ import {
import { import {
DataToolbarGroup, DataToolbarGroup,
DataToolbarItem, DataToolbarItem,
DataToolbarFilter DataToolbarFilter,
} from '@patternfly/react-core/dist/umd/experimental'; } from '@patternfly/react-core/dist/umd/experimental';
import { SearchIcon } from '@patternfly/react-icons'; import { SearchIcon } from '@patternfly/react-icons';
import { parseQueryString } from '@util/qs'; import { parseQueryString } from '@util/qs';
@@ -44,7 +44,7 @@ class Search extends React.Component {
isSearchDropdownOpen: false, isSearchDropdownOpen: false,
searchKey: columns.find(col => col.isDefault).key, searchKey: columns.find(col => col.isDefault).key,
searchValue: '', searchValue: '',
isFilterDropdownOpen: false isFilterDropdownOpen: false,
}; };
this.handleSearchInputChange = this.handleSearchInputChange.bind(this); this.handleSearchInputChange = this.handleSearchInputChange.bind(this);
@@ -52,8 +52,12 @@ class Search extends React.Component {
this.handleDropdownSelect = this.handleDropdownSelect.bind(this); this.handleDropdownSelect = this.handleDropdownSelect.bind(this);
this.handleSearch = this.handleSearch.bind(this); this.handleSearch = this.handleSearch.bind(this);
this.handleTextKeyDown = this.handleTextKeyDown.bind(this); this.handleTextKeyDown = this.handleTextKeyDown.bind(this);
this.handleFilterDropdownToggle = this.handleFilterDropdownToggle.bind(this); this.handleFilterDropdownToggle = this.handleFilterDropdownToggle.bind(
this.handleFilterDropdownSelect = this.handleFilterDropdownSelect.bind(this); this
);
this.handleFilterDropdownSelect = this.handleFilterDropdownSelect.bind(
this
);
this.handleFilterBooleanSelect = this.handleFilterBooleanSelect.bind(this); this.handleFilterBooleanSelect = this.handleFilterBooleanSelect.bind(this);
} }
@@ -77,8 +81,8 @@ class Search extends React.Component {
const { onSearch, qsConfig } = this.props; const { onSearch, qsConfig } = this.props;
const isNonStringField = const isNonStringField =
qsConfig.integerFields.filter(field => field === searchKey).length || qsConfig.integerFields.find(field => field === searchKey) ||
qsConfig.dateFields.filter(field => field === searchKey).length; qsConfig.dateFields.find(field => field === searchKey);
const actualSearchKey = isNonStringField const actualSearchKey = isNonStringField
? searchKey ? searchKey
@@ -121,7 +125,12 @@ class Search extends React.Component {
render() { render() {
const { up } = DropdownPosition; const { up } = DropdownPosition;
const { columns, i18n, onRemove, qsConfig, location } = this.props; const { columns, i18n, onRemove, qsConfig, location } = this.props;
const { isSearchDropdownOpen, searchKey, searchValue, isFilterDropdownOpen } = this.state; const {
isSearchDropdownOpen,
searchKey,
searchValue,
isFilterDropdownOpen,
} = this.state;
const { name: searchColumnName } = columns.find( const { name: searchColumnName } = columns.find(
({ key }) => key === searchKey ({ key }) => key === searchKey
); );
@@ -143,8 +152,8 @@ class Search extends React.Component {
const queryParams = parseQueryString(qsConfig, location.search); const queryParams = parseQueryString(qsConfig, location.search);
const queryParamsByKey = {}; const queryParamsByKey = {};
columns.forEach(({name, key}) => { columns.forEach(({ name, key }) => {
queryParamsByKey[key] = {key, label: name, chips: []}; queryParamsByKey[key] = { key, label: name, chips: [] };
}); });
const nonDefaultParams = filterDefaultParams( const nonDefaultParams = filterDefaultParams(
Object.keys(queryParams || {}), Object.keys(queryParams || {}),
@@ -152,12 +161,13 @@ class Search extends React.Component {
); );
nonDefaultParams.forEach(key => { nonDefaultParams.forEach(key => {
const columnKey = key const columnKey = key.replace('__icontains', '').replace('or__', '');
.replace('__icontains', '') const label = columns.filter(
.replace('or__', ''); ({ key: keyToCheck }) => columnKey === keyToCheck
const label = columns ).length
.filter(({key: keyToCheck}) => columnKey === keyToCheck).length ? columns ? columns.filter(({ key: keyToCheck }) => columnKey === keyToCheck)[0]
.filter(({key: keyToCheck}) => columnKey === keyToCheck)[0].name : columnKey; .name
: columnKey;
queryParamsByKey[columnKey] = { key, label, chips: [] }; queryParamsByKey[columnKey] = { key, label, chips: [] };
@@ -171,7 +181,7 @@ class Search extends React.Component {
}); });
return queryParamsByKey; return queryParamsByKey;
} };
const chipsByKey = getChipsByKey(); const chipsByKey = getChipsByKey();
@@ -179,7 +189,7 @@ class Search extends React.Component {
<DataToolbarGroup variant="filter-group"> <DataToolbarGroup variant="filter-group">
<DataToolbarItem> <DataToolbarItem>
{searchDropdownItems.length > 0 ? ( {searchDropdownItems.length > 0 ? (
<Dropdown <Dropdown
onToggle={this.handleDropdownToggle} onToggle={this.handleDropdownToggle}
onSelect={this.handleDropdownSelect} onSelect={this.handleDropdownSelect}
direction={up} direction={up}
@@ -195,68 +205,90 @@ class Search extends React.Component {
isOpen={isSearchDropdownOpen} isOpen={isSearchDropdownOpen}
dropdownItems={searchDropdownItems} dropdownItems={searchDropdownItems}
style={{ width: '100%' }} style={{ width: '100%' }}
/>) : (<NoOptionDropdown>{searchColumnName}</NoOptionDropdown>)}
</DataToolbarItem>
{columns.map(({ key, name, options, isBoolean }) => (<DataToolbarFilter
chips={chipsByKey[key] ? chipsByKey[key].chips : []}
deleteChip={(unusedKey, val) => { onRemove(chipsByKey[key].key, val) }}
categoryName={chipsByKey[key] ? chipsByKey[key].label : key}
key={key}
showToolbarItem={searchKey === key}
>
{options && (<Select
variant={SelectVariant.checkbox}
aria-label={name}
onToggle={this.handleFilterDropdownToggle}
onSelect={(event, selection) => this.handleFilterDropdownSelect(key, event, selection)}
selections={chipsByKey[key].chips}
isExpanded={isFilterDropdownOpen}
placeholderText={`Filter by ${name.toLowerCase()}`}
>
{options.map(([optionKey]) => (
<Fragment key={optionKey}>
{ /* TODO: update value to being object
{ actualValue: optionKey, toString: () => label }
currently a pf bug that makes the checked logic
not work with object-based values */ }
<SelectOption key={optionKey} value={optionKey} />
</Fragment>
))}
</Select>) || isBoolean && (
<Select
aria-label={name}
onToggle={this.handleFilterDropdownToggle}
onSelect={(event, selection) => this.handleFilterBooleanSelect(key, selection)}
selections={chipsByKey[key].chips[0]}
isExpanded={isFilterDropdownOpen}
placeholderText={`Filter by ${name.toLowerCase()}`}
>
{ /* TODO: update value to being object
{ actualValue: optionKey, toString: () => label }
currently a pf bug that makes the checked logic
not work with object-based values */ }
<SelectOption key="true" value="true" />
<SelectOption key="false" value="false" />
</Select>
) || (<InputGroup>
{/* TODO: add support for dates:
qsConfig.dateFields.filter(field => field === key).length && "date" */}
<TextInput
type={qsConfig.integerFields.filter(field => field === key).length && "number" || "search"}
aria-label={i18n._(t`Search text input`)}
value={searchValue}
onChange={this.handleSearchInputChange}
onKeyDown={this.handleTextKeyDown}
/> />
<Button ) : (
variant={ButtonVariant.control} <NoOptionDropdown>{searchColumnName}</NoOptionDropdown>
aria-label={i18n._(t`Search submit button`)} )}
onClick={this.handleSearch} </DataToolbarItem>
> {columns.map(({ key, name, options, isBoolean }) => (
<SearchIcon /> <DataToolbarFilter
</Button> chips={chipsByKey[key] ? chipsByKey[key].chips : []}
</InputGroup>)} deleteChip={(unusedKey, val) => {
</DataToolbarFilter>))} onRemove(chipsByKey[key].key, val);
}}
categoryName={chipsByKey[key] ? chipsByKey[key].label : key}
key={key}
showToolbarItem={searchKey === key}
>
{(options && (
<Select
variant={SelectVariant.checkbox}
aria-label={name}
onToggle={this.handleFilterDropdownToggle}
onSelect={(event, selection) =>
this.handleFilterDropdownSelect(key, event, selection)
}
selections={chipsByKey[key].chips}
isExpanded={isFilterDropdownOpen}
placeholderText={`Filter by ${name.toLowerCase()}`}
>
{options.map(([optionKey]) => (
<Fragment key={optionKey}>
{/* TODO: update value to being object
{ actualValue: optionKey, toString: () => label }
currently a pf bug that makes the checked logic
not work with object-based values */}
<SelectOption key={optionKey} value={optionKey} />
</Fragment>
))}
</Select>
)) ||
(isBoolean && (
<Select
aria-label={name}
onToggle={this.handleFilterDropdownToggle}
onSelect={(event, selection) =>
this.handleFilterBooleanSelect(key, selection)
}
selections={chipsByKey[key].chips[0]}
isExpanded={isFilterDropdownOpen}
placeholderText={`Filter by ${name.toLowerCase()}`}
>
{/* TODO: update value to being object
{ actualValue: optionKey, toString: () => label }
currently a pf bug that makes the checked logic
not work with object-based values */}
<SelectOption key="true" value="true" />
<SelectOption key="false" value="false" />
</Select>
)) || (
<InputGroup>
{/* TODO: add support for dates:
qsConfig.dateFields.filter(field => field === key).length && "date" */}
<TextInput
type={
(qsConfig.integerFields.find(
field => field === searchKey
) &&
'number') ||
'search'
}
aria-label={i18n._(t`Search text input`)}
value={searchValue}
onChange={this.handleSearchInputChange}
onKeyDown={this.handleTextKeyDown}
/>
<Button
variant={ButtonVariant.control}
aria-label={i18n._(t`Search submit button`)}
onClick={this.handleSearch}
>
<SearchIcon />
</Button>
</InputGroup>
)}
</DataToolbarFilter>
))}
</DataToolbarGroup> </DataToolbarGroup>
); );
} }
@@ -266,12 +298,12 @@ Search.propTypes = {
qsConfig: QSConfig.isRequired, qsConfig: QSConfig.isRequired,
columns: SearchColumns.isRequired, columns: SearchColumns.isRequired,
onSearch: PropTypes.func, onSearch: PropTypes.func,
onRemove: PropTypes.func onRemove: PropTypes.func,
}; };
Search.defaultProps = { Search.defaultProps = {
onSearch: null, onSearch: null,
onRemove: null onRemove: null,
}; };
export default withI18n()(withRouter(Search)); export default withI18n()(withRouter(Search));

View File

@@ -1,5 +1,8 @@
import React from 'react'; import React from 'react';
import { DataToolbar, DataToolbarContent } from '@patternfly/react-core/dist/umd/experimental'; import {
DataToolbar,
DataToolbarContent,
} from '@patternfly/react-core/dist/umd/experimental';
import { mountWithContexts } from '../../../testUtils/enzymeHelpers'; import { mountWithContexts } from '../../../testUtils/enzymeHelpers';
import Search from './Search'; import Search from './Search';
@@ -20,9 +23,7 @@ describe('<Search />', () => {
}); });
test('it triggers the expected callbacks', () => { test('it triggers the expected callbacks', () => {
const columns = [ const columns = [{ name: 'Name', key: 'name', isDefault: true }];
{ name: 'Name', key: 'name', isDefault: true }
];
const searchBtn = 'button[aria-label="Search submit button"]'; const searchBtn = 'button[aria-label="Search submit button"]';
const searchTextInput = 'input[aria-label="Search text input"]'; const searchTextInput = 'input[aria-label="Search text input"]';
@@ -30,16 +31,13 @@ describe('<Search />', () => {
const onSearch = jest.fn(); const onSearch = jest.fn();
search = mountWithContexts( search = mountWithContexts(
<DataToolbar id={`${QS_CONFIG.namespace}-list-toolbar`} <DataToolbar
id={`${QS_CONFIG.namespace}-list-toolbar`}
clearAllFilters={() => {}} clearAllFilters={() => {}}
collapseListedFiltersBreakpoint="md" collapseListedFiltersBreakpoint="md"
> >
<DataToolbarContent> <DataToolbarContent>
<Search <Search qsConfig={QS_CONFIG} columns={columns} onSearch={onSearch} />
qsConfig={QS_CONFIG}
columns={columns}
onSearch={onSearch}
/>
</DataToolbarContent> </DataToolbarContent>
</DataToolbar> </DataToolbar>
); );
@@ -53,21 +51,16 @@ describe('<Search />', () => {
}); });
test('handleDropdownToggle properly updates state', async () => { test('handleDropdownToggle properly updates state', async () => {
const columns = [ const columns = [{ name: 'Name', key: 'name', isDefault: true }];
{ name: 'Name', key: 'name', isDefault: true }
];
const onSearch = jest.fn(); const onSearch = jest.fn();
const wrapper = mountWithContexts( const wrapper = mountWithContexts(
<DataToolbar id={`${QS_CONFIG.namespace}-list-toolbar`} <DataToolbar
id={`${QS_CONFIG.namespace}-list-toolbar`}
clearAllFilters={() => {}} clearAllFilters={() => {}}
collapseListedFiltersBreakpoint="md" collapseListedFiltersBreakpoint="md"
> >
<DataToolbarContent> <DataToolbarContent>
<Search <Search qsConfig={QS_CONFIG} columns={columns} onSearch={onSearch} />
qsConfig={QS_CONFIG}
columns={columns}
onSearch={onSearch}
/>
</DataToolbarContent> </DataToolbarContent>
</DataToolbar> </DataToolbar>
).find('Search'); ).find('Search');
@@ -83,16 +76,13 @@ describe('<Search />', () => {
]; ];
const onSearch = jest.fn(); const onSearch = jest.fn();
const wrapper = mountWithContexts( const wrapper = mountWithContexts(
<DataToolbar id={`${QS_CONFIG.namespace}-list-toolbar`} <DataToolbar
id={`${QS_CONFIG.namespace}-list-toolbar`}
clearAllFilters={() => {}} clearAllFilters={() => {}}
collapseListedFiltersBreakpoint="md" collapseListedFiltersBreakpoint="md"
> >
<DataToolbarContent> <DataToolbarContent>
<Search <Search qsConfig={QS_CONFIG} columns={columns} onSearch={onSearch} />
qsConfig={QS_CONFIG}
columns={columns}
onSearch={onSearch}
/>
</DataToolbarContent> </DataToolbarContent>
</DataToolbar> </DataToolbar>
).find('Search'); ).find('Search');

View File

@@ -19,9 +19,7 @@ import {
SortNumericUpIcon, SortNumericUpIcon,
} from '@patternfly/react-icons'; } from '@patternfly/react-icons';
import { import { parseQueryString } from '@util/qs';
parseQueryString
} from '@util/qs';
import { SortColumns, QSConfig } from '@types'; import { SortColumns, QSConfig } from '@types';
import styled from 'styled-components'; import styled from 'styled-components';
@@ -51,7 +49,7 @@ class Sort extends React.Component {
sortOrder = 'ascending'; sortOrder = 'ascending';
} }
if (qsConfig.integerFields.filter(field => field === sortKey).length) { if (qsConfig.integerFields.find(field => field === sortKey)) {
isNumeric = true; isNumeric = true;
} else { } else {
isNumeric = false; isNumeric = false;
@@ -61,7 +59,7 @@ class Sort extends React.Component {
isSortDropdownOpen: false, isSortDropdownOpen: false,
sortKey, sortKey,
sortOrder, sortOrder,
isNumeric isNumeric,
}; };
this.handleDropdownToggle = this.handleDropdownToggle.bind(this); this.handleDropdownToggle = this.handleDropdownToggle.bind(this);
@@ -78,13 +76,11 @@ class Sort extends React.Component {
const { sortOrder } = this.state; const { sortOrder } = this.state;
const { innerText } = target; const { innerText } = target;
const [{ key: sortKey }] = columns.filter( const [{ key: sortKey }] = columns.filter(({ name }) => name === innerText);
({ name }) => name === innerText
);
let isNumeric; let isNumeric;
if (qsConfig.integerFields.filter(field => field === sortKey).length) { if (qsConfig.integerFields.find(field => field === sortKey)) {
isNumeric = true; isNumeric = true;
} else { } else {
isNumeric = false; isNumeric = false;
@@ -131,23 +127,23 @@ class Sort extends React.Component {
<Fragment> <Fragment>
{sortedColumnName && ( {sortedColumnName && (
<InputGroup> <InputGroup>
{sortDropdownItems.length > 0 && (<Dropdown {(sortDropdownItems.length > 0 && (
onToggle={this.handleDropdownToggle} <Dropdown
onSelect={this.handleDropdownSelect} onToggle={this.handleDropdownToggle}
direction={up} onSelect={this.handleDropdownSelect}
isOpen={isSortDropdownOpen} direction={up}
toggle={ isOpen={isSortDropdownOpen}
<DropdownToggle toggle={
id="awx-sort" <DropdownToggle
onToggle={this.handleDropdownToggle} id="awx-sort"
> onToggle={this.handleDropdownToggle}
{sortedColumnName} >
</DropdownToggle> {sortedColumnName}
} </DropdownToggle>
dropdownItems={sortDropdownItems} }
/>) || ( dropdownItems={sortDropdownItems}
<NoOptionDropdown>{sortedColumnName}</NoOptionDropdown> />
)} )) || <NoOptionDropdown>{sortedColumnName}</NoOptionDropdown>}
<Button <Button
variant={ButtonVariant.control} variant={ButtonVariant.control}
aria-label={i18n._(t`Sort`)} aria-label={i18n._(t`Sort`)}
@@ -165,11 +161,11 @@ class Sort extends React.Component {
Sort.propTypes = { Sort.propTypes = {
qsConfig: QSConfig.isRequired, qsConfig: QSConfig.isRequired,
columns: SortColumns.isRequired, columns: SortColumns.isRequired,
onSort: PropTypes.func onSort: PropTypes.func,
}; };
Sort.defaultProps = { Sort.defaultProps = {
onSort: null onSort: null,
}; };
export default withI18n()(withRouter(Sort)); export default withI18n()(withRouter(Sort));

View File

@@ -30,11 +30,7 @@ describe('<Sort />', () => {
const onSort = jest.fn(); const onSort = jest.fn();
const wrapper = mountWithContexts( const wrapper = mountWithContexts(
<Sort <Sort qsConfig={qsConfig} columns={columns} onSort={onSort} />
qsConfig={qsConfig}
columns={columns}
onSort={onSort}
/>
).find('Sort'); ).find('Sort');
wrapper.find(sortBtn).simulate('click'); wrapper.find(sortBtn).simulate('click');
@@ -62,17 +58,13 @@ describe('<Sort />', () => {
{ {
name: 'Bakery', name: 'Bakery',
key: 'bakery', key: 'bakery',
} },
]; ];
const onSort = jest.fn(); const onSort = jest.fn();
const wrapper = mountWithContexts( const wrapper = mountWithContexts(
<Sort <Sort qsConfig={qsConfig} columns={columns} onSort={onSort} />
qsConfig={qsConfig}
columns={columns}
onSort={onSort}
/>
).find('Sort'); ).find('Sort');
const sortDropdownToggle = wrapper.find('Button'); const sortDropdownToggle = wrapper.find('Button');
expect(sortDropdownToggle.length).toBe(1); expect(sortDropdownToggle.length).toBe(1);
@@ -99,17 +91,13 @@ describe('<Sort />', () => {
{ {
name: 'Bakery', name: 'Bakery',
key: 'bakery', key: 'bakery',
} },
]; ];
const onSort = jest.fn(); const onSort = jest.fn();
const wrapper = mountWithContexts( const wrapper = mountWithContexts(
<Sort <Sort qsConfig={qsConfig} columns={columns} onSort={onSort} />
qsConfig={qsConfig}
columns={columns}
onSort={onSort}
/>
).find('Sort'); ).find('Sort');
const sortDropdownToggle = wrapper.find('Button'); const sortDropdownToggle = wrapper.find('Button');
expect(sortDropdownToggle.length).toBe(1); expect(sortDropdownToggle.length).toBe(1);
@@ -136,17 +124,13 @@ describe('<Sort />', () => {
{ {
name: 'Bakery', name: 'Bakery',
key: 'bakery', key: 'bakery',
} },
]; ];
const onSort = jest.fn(); const onSort = jest.fn();
const wrapper = mountWithContexts( const wrapper = mountWithContexts(
<Sort <Sort qsConfig={qsConfig} columns={columns} onSort={onSort} />
qsConfig={qsConfig}
columns={columns}
onSort={onSort}
/>
).find('Sort'); ).find('Sort');
wrapper.instance().handleDropdownSelect({ target: { innerText: 'Bar' } }); wrapper.instance().handleDropdownSelect({ target: { innerText: 'Bar' } });
@@ -172,17 +156,13 @@ describe('<Sort />', () => {
{ {
name: 'Bakery', name: 'Bakery',
key: 'bakery', key: 'bakery',
} },
]; ];
const onSort = jest.fn(); const onSort = jest.fn();
const wrapper = mountWithContexts( const wrapper = mountWithContexts(
<Sort <Sort qsConfig={qsConfig} columns={columns} onSort={onSort} />
qsConfig={qsConfig}
columns={columns}
onSort={onSort}
/>
).find('Sort'); ).find('Sort');
expect(wrapper.state('isSortDropdownOpen')).toEqual(false); expect(wrapper.state('isSortDropdownOpen')).toEqual(false);
wrapper.instance().handleDropdownToggle(true); wrapper.instance().handleDropdownToggle(true);
@@ -216,12 +196,8 @@ describe('<Sort />', () => {
integerFields: ['page', 'page_size'], integerFields: ['page', 'page_size'],
}; };
const numericColumns = [ const numericColumns = [{ name: 'ID', key: 'id' }];
{ name: 'ID', key: 'id' }, const alphaColumns = [{ name: 'Name', key: 'name' }];
];
const alphaColumns = [
{ name: 'Name', key: 'name' },
];
const onSort = jest.fn(); const onSort = jest.fn();
sort = mountWithContexts( sort = mountWithContexts(
@@ -236,11 +212,7 @@ describe('<Sort />', () => {
expect(downNumericIcon.length).toBe(1); expect(downNumericIcon.length).toBe(1);
sort = mountWithContexts( sort = mountWithContexts(
<Sort <Sort qsConfig={qsConfigNumUp} columns={numericColumns} onSort={onSort} />
qsConfig={qsConfigNumUp}
columns={numericColumns}
onSort={onSort}
/>
); );
const upNumericIcon = sort.find(upNumericIconSelector); const upNumericIcon = sort.find(upNumericIconSelector);
@@ -258,11 +230,7 @@ describe('<Sort />', () => {
expect(downAlphaIcon.length).toBe(1); expect(downAlphaIcon.length).toBe(1);
sort = mountWithContexts( sort = mountWithContexts(
<Sort <Sort qsConfig={qsConfigAlphaUp} columns={alphaColumns} onSort={onSort} />
qsConfig={qsConfigAlphaUp}
columns={alphaColumns}
onSort={onSort}
/>
); );
const upAlphaIcon = sort.find(upAlphaIconSelector); const upAlphaIcon = sort.find(upAlphaIconSelector);

View File

@@ -194,7 +194,7 @@ class HostsList extends Component {
{ {
name: i18n._(t`Name`), name: i18n._(t`Name`),
key: 'name', key: 'name',
isDefault: true isDefault: true,
}, },
{ {
name: i18n._(t`Created By (Username)`), name: i18n._(t`Created By (Username)`),

View File

@@ -181,12 +181,12 @@ function InventoryGroupsList({ i18n, location, match }) {
{ {
name: i18n._(t`Name`), name: i18n._(t`Name`),
key: 'name', key: 'name',
isDefault: true isDefault: true,
}, },
{ {
name: i18n._(t`Is Root Group`), name: i18n._(t`Is Root Group`),
key: 'parents__isnull', key: 'parents__isnull',
isBoolean: true isBoolean: true,
}, },
{ {
name: i18n._(t`Created By (Username)`), name: i18n._(t`Created By (Username)`),
@@ -200,8 +200,8 @@ function InventoryGroupsList({ i18n, location, match }) {
toolbarSortColumns={[ toolbarSortColumns={[
{ {
name: i18n._(t`Name`), name: i18n._(t`Name`),
key: 'name' key: 'name',
} },
]} ]}
renderItem={item => ( renderItem={item => (
<InventoryGroupItem <InventoryGroupItem

View File

@@ -161,7 +161,9 @@ describe('<InventoryGroupsList />', () => {
}); });
wrapper.update(); wrapper.update();
await act(async () => { await act(async () => {
wrapper.find('DataToolbar Button[aria-label="Delete"]').invoke('onClick')(); wrapper
.find('DataToolbar Button[aria-label="Delete"]')
.invoke('onClick')();
}); });
await waitForElement( await waitForElement(
wrapper, wrapper,
@@ -193,7 +195,9 @@ describe('<InventoryGroupsList />', () => {
}); });
wrapper.update(); wrapper.update();
await act(async () => { await act(async () => {
wrapper.find('DataToolbar Button[aria-label="Delete"]').invoke('onClick')(); wrapper
.find('DataToolbar Button[aria-label="Delete"]')
.invoke('onClick')();
}); });
await waitForElement( await waitForElement(
wrapper, wrapper,

View File

@@ -136,7 +136,7 @@ function InventoryHosts({ i18n, location, match }) {
{ {
name: i18n._(t`Name`), name: i18n._(t`Name`),
key: 'name', key: 'name',
isDefault: true isDefault: true,
}, },
{ {
name: i18n._(t`Created By (Username)`), name: i18n._(t`Created By (Username)`),
@@ -150,8 +150,8 @@ function InventoryHosts({ i18n, location, match }) {
toolbarSortColumns={[ toolbarSortColumns={[
{ {
name: i18n._(t`Name`), name: i18n._(t`Name`),
key: 'name' key: 'name',
} },
]} ]}
renderToolbar={props => ( renderToolbar={props => (
<DataListToolbar <DataListToolbar

View File

@@ -178,7 +178,7 @@ class InventoriesList extends Component {
{ {
name: i18n._(t`Name`), name: i18n._(t`Name`),
key: 'name', key: 'name',
isDefault: true isDefault: true,
}, },
{ {
name: i18n._(t`Created By (Username)`), name: i18n._(t`Created By (Username)`),

View File

@@ -23,12 +23,16 @@ import { getQSConfig, parseQueryString } from '@util/qs';
import JobListItem from './JobListItem'; import JobListItem from './JobListItem';
const QS_CONFIG = getQSConfig('job', { const QS_CONFIG = getQSConfig(
page: 1, 'job',
page_size: 20, {
order_by: '-finished', page: 1,
not__launch_type: 'sync', page_size: 20,
}, ['page', 'page_size', 'id']); order_by: '-finished',
not__launch_type: 'sync',
},
['page', 'page_size', 'id']
);
class JobList extends Component { class JobList extends Component {
constructor(props) { constructor(props) {
@@ -167,88 +171,46 @@ class JobList extends Component {
{ {
name: i18n._(t`Name`), name: i18n._(t`Name`),
key: 'name', key: 'name',
isDefault: true isDefault: true,
}, },
{ {
name: i18n._(t`ID`), name: i18n._(t`ID`),
key: 'id' key: 'id',
}, },
{ {
name: i18n._(t`Label Name`), name: i18n._(t`Label Name`),
key: 'labels__name' key: 'labels__name',
}, },
{ {
name: i18n._(t`Job Type`), name: i18n._(t`Job Type`),
key: `type`, key: `type`,
options: [ options: [
[ [`project_update`, i18n._(t`SCM Update`)],
`project_update`, [`inventory_update`, i18n._(t`Inventory Sync`)],
i18n._(t`SCM Update`) [`job`, i18n._(t`Playbook Run`)],
], [`ad_hoc_command`, i18n._(t`Command`)],
[ [`system_job`, i18n._(t`Management Job`)],
`inventory_update`, [`workflow_job`, i18n._(t`Workflow Job`)],
i18n._(t`Inventory Sync`) ],
],
[
`job`,
i18n._(t`Playbook Run`)
],
[
`ad_hoc_command`,
i18n._(t`Command`)
],
[
`system_job`,
i18n._(t`Management Job`)
],
[
`workflow_job`,
i18n._(t`Workflow Job`)
]
]
}, },
{ {
name: i18n._(t`Created By (Username)`), name: i18n._(t`Created By (Username)`),
key: 'created_by__username' key: 'created_by__username',
}, },
{ {
name: i18n._(t`Status`), name: i18n._(t`Status`),
key: 'status', key: 'status',
options: [ options: [
[ [`new`, i18n._(t`New`)],
`new`, [`pending`, i18n._(t`Pending`)],
i18n._(t`New`) [`waiting`, i18n._(t`Waiting`)],
], [`running`, i18n._(t`Running`)],
[ [`successful`, i18n._(t`Successful`)],
`pending`, [`failed`, i18n._(t`Failed`)],
i18n._(t`Pending`) [`error`, i18n._(t`Error`)],
], [`canceled`, i18n._(t`Canceled`)],
[ ],
`waiting`, },
i18n._(t`Waiting`)
],
[
`running`,
i18n._(t`Running`)
],
[
`successful`,
i18n._(t`Successful`)
],
[
`failed`,
i18n._(t`Failed`)
],
[
`error`,
i18n._(t`Error`)
],
[
`canceled`,
i18n._(t`Canceled`)
]
]
}
]} ]}
toolbarSortColumns={[ toolbarSortColumns={[
{ {

View File

@@ -123,7 +123,7 @@ function OrganizationsList({ i18n }) {
{ {
name: i18n._(t`Name`), name: i18n._(t`Name`),
key: 'name', key: 'name',
isDefault: true isDefault: true,
}, },
{ {
name: i18n._(t`Created By (Username)`), name: i18n._(t`Created By (Username)`),

View File

@@ -51,7 +51,7 @@ function OrganizationTeams({ id, i18n }) {
{ {
name: i18n._(t`Name`), name: i18n._(t`Name`),
key: 'name', key: 'name',
isDefault: true isDefault: true,
}, },
{ {
name: i18n._(t`Created by (username)`), name: i18n._(t`Created by (username)`),

View File

@@ -160,32 +160,18 @@ class ProjectsList extends Component {
{ {
name: i18n._(t`Name`), name: i18n._(t`Name`),
key: 'name', key: 'name',
isDefault: true isDefault: true,
}, },
{ {
name: i18n._(t`Type`), name: i18n._(t`Type`),
key: 'type',
options: [ options: [
[ [``, i18n._(t`Manual`)],
``, [`git`, i18n._(t`Git`)],
i18n._(t`Manual`) [`hg`, i18n._(t`Mercurial`)],
], [`svn`, i18n._(t`Subversion`)],
[ [`insights`, i18n._(t`Red Hat Insights`)],
`git`, ],
i18n._(t`Git`)
],
[
`hg`,
i18n._(t`Mercurial`)
],
[
`svn`,
i18n._(t`Subversion`)
],
[
`insights`,
i18n._(t`Red Hat Insights`)
]
]
}, },
{ {
name: i18n._(t`SCM URL`), name: i18n._(t`SCM URL`),
@@ -204,7 +190,7 @@ class ProjectsList extends Component {
{ {
name: i18n._(t`Name`), name: i18n._(t`Name`),
key: 'name', key: 'name',
} },
]} ]}
renderToolbar={props => ( renderToolbar={props => (
<DataListToolbar <DataListToolbar

View File

@@ -158,7 +158,7 @@ class TeamsList extends Component {
{ {
name: i18n._(t`Name`), name: i18n._(t`Name`),
key: 'name', key: 'name',
isDefault: true isDefault: true,
}, },
{ {
name: i18n._(t`Organization Name`), name: i18n._(t`Organization Name`),

View File

@@ -218,21 +218,15 @@ class TemplatesList extends Component {
{ {
name: i18n._(t`Name`), name: i18n._(t`Name`),
key: 'name', key: 'name',
isDefault: true isDefault: true,
}, },
{ {
name: i18n._(t`Type`), name: i18n._(t`Type`),
key: 'type', key: 'type',
options: [ options: [
[ [`job_template`, i18n._(t`Job Template`)],
`job_template`, [`workflow_job_template`, i18n._(t`Workflow Template`)],
i18n._(t`Job Template`) ],
],
[
`workflow_job_template`,
i18n._(t`Workflow Template`)
],
]
}, },
{ {
name: i18n._(t`Playbook name`), name: i18n._(t`Playbook name`),

View File

@@ -158,7 +158,7 @@ class UsersList extends Component {
{ {
name: i18n._(t`Username`), name: i18n._(t`Username`),
key: 'username', key: 'username',
isDefault: true isDefault: true,
}, },
{ {
name: i18n._(t`First Name`), name: i18n._(t`First Name`),
@@ -167,7 +167,7 @@ class UsersList extends Component {
{ {
name: i18n._(t`Last Name`), name: i18n._(t`Last Name`),
key: 'last_name', key: 'last_name',
} },
]} ]}
toolbarSortColumns={[ toolbarSortColumns={[
{ {

View File

@@ -257,7 +257,7 @@ export const SearchColumns = arrayOf(
key: string.isRequired, key: string.isRequired,
isDefault: bool, isDefault: bool,
isBoolean: bool, isBoolean: bool,
options: arrayOf(arrayOf(string, string)) options: arrayOf(arrayOf(string, string)),
}) })
); );

View File

@@ -15,7 +15,7 @@ export function getQSConfig(
throw new Error('a QS namespace is required'); throw new Error('a QS namespace is required');
} }
// if order_by isn't passed, default to name // if order_by isn't passed, default to name
if (!Object.keys(defaultParams).filter(key => key === 'order_by').length) { if (!defaultParams.order_by) {
defaultParams.order_by = 'name'; defaultParams.order_by = 'name';
} }
return { return {
@@ -193,7 +193,6 @@ function removeParam(oldVal, deleteVal) {
* @return {object} merged namespaced params object * @return {object} merged namespaced params object
*/ */
export function mergeParams(oldParams, newParams) { export function mergeParams(oldParams, newParams) {
debugger;
const merged = {}; const merged = {};
Object.keys(oldParams).forEach(key => { Object.keys(oldParams).forEach(key => {
merged[key] = mergeParam(oldParams[key], newParams[key]); merged[key] = mergeParam(oldParams[key], newParams[key]);

View File

@@ -122,10 +122,12 @@ describe('qs (qs.js)', () => {
}); });
test('should set order_by in defaultParams if it is not passed', () => { test('should set order_by in defaultParams if it is not passed', () => {
expect(getQSConfig('organization', { expect(
page: 1, getQSConfig('organization', {
page_size: 5, page: 1,
})).toEqual({ page_size: 5,
})
).toEqual({
namespace: 'organization', namespace: 'organization',
defaultParams: { page: 1, page_size: 5, order_by: 'name' }, defaultParams: { page: 1, page_size: 5, order_by: 'name' },
integerFields: ['page', 'page_size'], integerFields: ['page', 'page_size'],