mirror of
https://github.com/ansible/awx.git
synced 2026-01-16 12:20:45 -03:30
more ui_next search pr feedback:
- updae .filter().length calls to .find() - fix ProjectList errors
This commit is contained in:
parent
3cdf274bdb
commit
1e344bdf8a
@ -146,7 +146,7 @@ class AddResourceRole extends React.Component {
|
||||
{
|
||||
name: i18n._(t`Username`),
|
||||
key: 'username',
|
||||
isDefault: true
|
||||
isDefault: true,
|
||||
},
|
||||
{
|
||||
name: i18n._(t`First Name`),
|
||||
@ -155,7 +155,7 @@ class AddResourceRole extends React.Component {
|
||||
{
|
||||
name: i18n._(t`Last Name`),
|
||||
key: 'last_name',
|
||||
}
|
||||
},
|
||||
];
|
||||
|
||||
const userSortColumns = [
|
||||
@ -170,14 +170,14 @@ class AddResourceRole extends React.Component {
|
||||
{
|
||||
name: i18n._(t`Last Name`),
|
||||
key: 'last_name',
|
||||
}
|
||||
},
|
||||
];
|
||||
|
||||
const teamSearchColumns = [
|
||||
{
|
||||
name: i18n._(t`Name`),
|
||||
key: 'name',
|
||||
isDefault: true
|
||||
isDefault: true,
|
||||
},
|
||||
{
|
||||
name: i18n._(t`Created By (Username)`),
|
||||
|
||||
@ -24,7 +24,11 @@ class SelectResourceStep extends React.Component {
|
||||
this.qsConfig = getQSConfig('resource', {
|
||||
page: 1,
|
||||
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'
|
||||
}`,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -10,14 +10,14 @@ describe('<SelectResourceStep />', () => {
|
||||
{
|
||||
name: 'Username',
|
||||
key: 'username',
|
||||
isDefault: true
|
||||
isDefault: true,
|
||||
},
|
||||
];
|
||||
|
||||
const sortColumns = [
|
||||
{
|
||||
name: 'Username',
|
||||
key: 'username'
|
||||
key: 'username',
|
||||
},
|
||||
];
|
||||
afterEach(() => {
|
||||
|
||||
@ -2,12 +2,16 @@ import React, { Fragment } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { withI18n } from '@lingui/react';
|
||||
import { t } from '@lingui/macro';
|
||||
import {
|
||||
Checkbox,
|
||||
} from '@patternfly/react-core';
|
||||
import { Checkbox } from '@patternfly/react-core';
|
||||
import styled from 'styled-components';
|
||||
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 Search from '../Search';
|
||||
import Sort from '../Sort';
|
||||
@ -60,7 +64,8 @@ class DataListToolbar extends React.Component {
|
||||
|
||||
const showExpandCollapse = onCompact && onExpand;
|
||||
return (
|
||||
<DataToolbar id={`${qsConfig.namespace}-list-toolbar`}
|
||||
<DataToolbar
|
||||
id={`${qsConfig.namespace}-list-toolbar`}
|
||||
clearAllFilters={clearAllFilters}
|
||||
collapseListedFiltersBreakpoint="xl"
|
||||
>
|
||||
@ -89,11 +94,7 @@ class DataListToolbar extends React.Component {
|
||||
/>
|
||||
</DataToolbarItem>
|
||||
<DataToolbarItem>
|
||||
<Sort
|
||||
qsConfig={qsConfig}
|
||||
columns={sortColumns}
|
||||
onSort={onSort}
|
||||
/>
|
||||
<Sort qsConfig={qsConfig} columns={sortColumns} onSort={onSort} />
|
||||
</DataToolbarItem>
|
||||
</DataToolbarToggleGroup>
|
||||
<DataToolbarGroup>
|
||||
|
||||
@ -25,12 +25,8 @@ describe('<DataListToolbar />', () => {
|
||||
const onSelectAll = jest.fn();
|
||||
|
||||
test('it triggers the expected callbacks', () => {
|
||||
const searchColumns = [
|
||||
{ name: 'Name', key: 'name', isDefault: true }
|
||||
];
|
||||
const sortColumns = [
|
||||
{ name: 'Name', key: 'name' }
|
||||
];
|
||||
const searchColumns = [{ name: 'Name', key: 'name', isDefault: true }];
|
||||
const sortColumns = [{ name: 'Name', key: 'name' }];
|
||||
const search = 'button[aria-label="Search submit button"]';
|
||||
const searchTextInput = 'input[aria-label="Search text input"]';
|
||||
const selectAll = 'input[aria-label="Select all"]';
|
||||
@ -86,12 +82,12 @@ describe('<DataListToolbar />', () => {
|
||||
|
||||
const searchColumns = [
|
||||
{ name: 'Foo', key: 'foo', isDefault: true },
|
||||
{ name: 'Bar', key: 'bar' }
|
||||
{ name: 'Bar', key: 'bar' },
|
||||
];
|
||||
const sortColumns = [
|
||||
{ name: 'Foo', key: 'foo' },
|
||||
{ name: 'Bar', key: 'bar' },
|
||||
{ name: 'Bakery', key: 'Bakery' }
|
||||
{ name: 'Bakery', key: 'Bakery' },
|
||||
];
|
||||
|
||||
toolbar = mountWithContexts(
|
||||
@ -189,17 +185,13 @@ describe('<DataListToolbar />', () => {
|
||||
const downAlphaIconSelector = 'SortAlphaDownIcon';
|
||||
const upAlphaIconSelector = 'SortAlphaUpIcon';
|
||||
|
||||
const numericColumns = [
|
||||
{ name: 'ID', key: 'id' },
|
||||
];
|
||||
const numericColumns = [{ name: 'ID', key: 'id' }];
|
||||
|
||||
const alphaColumns = [
|
||||
{ name: 'Name', key: 'name' },
|
||||
];
|
||||
const alphaColumns = [{ name: 'Name', key: 'name' }];
|
||||
|
||||
const searchColumns = [
|
||||
{ name: 'Name', key: 'name', isDefault: true },
|
||||
{ name: 'ID', key: 'id' }
|
||||
{ name: 'ID', key: 'id' },
|
||||
];
|
||||
|
||||
toolbar = mountWithContexts(
|
||||
@ -248,12 +240,8 @@ describe('<DataListToolbar />', () => {
|
||||
});
|
||||
|
||||
test('should render additionalControls', () => {
|
||||
const searchColumns = [
|
||||
{ name: 'Name', key: 'name', isDefault: true }
|
||||
];
|
||||
const sortColumns = [
|
||||
{ name: 'Name', key: 'name' }
|
||||
];
|
||||
const searchColumns = [{ name: 'Name', key: 'name', isDefault: true }];
|
||||
const sortColumns = [{ name: 'Name', key: 'name' }];
|
||||
|
||||
toolbar = mountWithContexts(
|
||||
<DataListToolbar
|
||||
@ -278,12 +266,8 @@ describe('<DataListToolbar />', () => {
|
||||
});
|
||||
|
||||
test('it triggers the expected callbacks', () => {
|
||||
const searchColumns = [
|
||||
{ name: 'Name', key: 'name', isDefault: true }
|
||||
];
|
||||
const sortColumns = [
|
||||
{ name: 'Name', key: 'name' }
|
||||
];
|
||||
const searchColumns = [{ name: 'Name', key: 'name', isDefault: true }];
|
||||
const sortColumns = [{ name: 'Name', key: 'name' }];
|
||||
toolbar = mountWithContexts(
|
||||
<DataListToolbar
|
||||
qsConfig={QS_CONFIG}
|
||||
|
||||
@ -2,7 +2,10 @@ import React, { Fragment } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { withRouter } from 'react-router-dom';
|
||||
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 {
|
||||
@ -40,7 +43,7 @@ class ListHeader extends React.Component {
|
||||
const { location, qsConfig } = this.props;
|
||||
let params = parseQueryString(qsConfig, location.search);
|
||||
params = mergeParams(params, { [key]: value });
|
||||
params = replaceParams(params, { 'page' : 1 })
|
||||
params = replaceParams(params, { page: 1 });
|
||||
this.pushHistoryState(params);
|
||||
}
|
||||
|
||||
@ -54,7 +57,9 @@ class ListHeader extends React.Component {
|
||||
const { location, qsConfig } = this.props;
|
||||
let oldParams = parseQueryString(qsConfig, location.search);
|
||||
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 }));
|
||||
}
|
||||
@ -96,7 +101,8 @@ class ListHeader extends React.Component {
|
||||
return (
|
||||
<Fragment>
|
||||
{isEmpty ? (
|
||||
<DataToolbar id={`${qsConfig.namespace}-list-toolbar`}
|
||||
<DataToolbar
|
||||
id={`${qsConfig.namespace}-list-toolbar`}
|
||||
clearAllFilters={this.handleRemoveAll}
|
||||
collapseListedFiltersBreakpoint="md"
|
||||
>
|
||||
|
||||
@ -16,12 +16,8 @@ describe('ListHeader', () => {
|
||||
<ListHeader
|
||||
itemCount={50}
|
||||
qsConfig={qsConfig}
|
||||
searchColumns={[
|
||||
{ name: 'foo', key: 'foo', isDefault: true},
|
||||
]}
|
||||
sortColumns={[
|
||||
{ name: 'foo', key: 'foo'},
|
||||
]}
|
||||
searchColumns={[{ name: 'foo', key: 'foo', isDefault: true }]}
|
||||
sortColumns={[{ name: 'foo', key: 'foo' }]}
|
||||
renderToolbar={renderToolbarFn}
|
||||
/>
|
||||
);
|
||||
@ -37,12 +33,8 @@ describe('ListHeader', () => {
|
||||
<ListHeader
|
||||
itemCount={7}
|
||||
qsConfig={qsConfig}
|
||||
searchColumns={[
|
||||
{ name: 'foo', key: 'foo', isDefault: true},
|
||||
]}
|
||||
sortColumns={[
|
||||
{ name: 'foo', key: 'foo'},
|
||||
]}
|
||||
searchColumns={[{ name: 'foo', key: 'foo', isDefault: true }]}
|
||||
sortColumns={[{ name: 'foo', key: 'foo' }]}
|
||||
/>,
|
||||
{ context: { router: { history } } }
|
||||
);
|
||||
|
||||
@ -27,7 +27,7 @@ function CredentialLookup({
|
||||
credentialTypeId,
|
||||
value,
|
||||
history,
|
||||
i18n
|
||||
i18n,
|
||||
}) {
|
||||
const [credentials, setCredentials] = useState([]);
|
||||
const [count, setCount] = useState(0);
|
||||
@ -79,7 +79,7 @@ function CredentialLookup({
|
||||
{
|
||||
name: i18n._(t`Name`),
|
||||
key: 'name',
|
||||
isDefault: true
|
||||
isDefault: true,
|
||||
},
|
||||
{
|
||||
name: i18n._(t`Created By (Username)`),
|
||||
@ -88,12 +88,14 @@ function CredentialLookup({
|
||||
{
|
||||
name: i18n._(t`Modified By (Username)`),
|
||||
key: 'modified_by__username',
|
||||
}
|
||||
},
|
||||
]}
|
||||
sortColumns={[
|
||||
{
|
||||
name: i18n._(t`Name`),
|
||||
key: 'name',
|
||||
},
|
||||
]}
|
||||
sortColumns={[{
|
||||
name: i18n._(t`Name`),
|
||||
key: 'name'
|
||||
}]}
|
||||
readOnly={!canDelete}
|
||||
selectItem={item => dispatch({ type: 'SELECT_ITEM', item })}
|
||||
deselectItem={item => dispatch({ type: 'DESELECT_ITEM', item })}
|
||||
|
||||
@ -68,11 +68,11 @@ function InstanceGroupsLookup(props) {
|
||||
{
|
||||
name: i18n._(t`Name`),
|
||||
key: 'name',
|
||||
isDefault: true
|
||||
isDefault: true,
|
||||
},
|
||||
{
|
||||
name: i18n._(t`Credential Name`),
|
||||
key: 'credential__name'
|
||||
key: 'credential__name',
|
||||
},
|
||||
{
|
||||
name: i18n._(t`Created By (Username)`),
|
||||
@ -83,10 +83,12 @@ function InstanceGroupsLookup(props) {
|
||||
key: 'modified_by__username',
|
||||
},
|
||||
]}
|
||||
sortColumns={[{
|
||||
name: i18n._(t`Name`),
|
||||
key: 'name'
|
||||
}]}
|
||||
sortColumns={[
|
||||
{
|
||||
name: i18n._(t`Name`),
|
||||
key: 'name',
|
||||
},
|
||||
]}
|
||||
multiple={state.multiple}
|
||||
header={i18n._(t`Instance Groups`)}
|
||||
name="instanceGroups"
|
||||
|
||||
@ -72,7 +72,7 @@ function InventoryLookup({
|
||||
{
|
||||
name: i18n._(t`Name`),
|
||||
key: 'name',
|
||||
isDefault: true
|
||||
isDefault: true,
|
||||
},
|
||||
{
|
||||
name: i18n._(t`Created By (Username)`),
|
||||
|
||||
@ -126,7 +126,7 @@ function MultiCredentialsLookup(props) {
|
||||
{
|
||||
name: i18n._(t`Name`),
|
||||
key: 'name',
|
||||
isDefault: true
|
||||
isDefault: true,
|
||||
},
|
||||
{
|
||||
name: i18n._(t`Created By (Username)`),
|
||||
@ -137,10 +137,12 @@ function MultiCredentialsLookup(props) {
|
||||
key: 'modified_by__username',
|
||||
},
|
||||
]}
|
||||
sortColumns={[{
|
||||
name: i18n._(t`Name`),
|
||||
key: 'name'
|
||||
}]}
|
||||
sortColumns={[
|
||||
{
|
||||
name: i18n._(t`Name`),
|
||||
key: 'name',
|
||||
},
|
||||
]}
|
||||
multiple={isMultiple}
|
||||
header={i18n._(t`Credentials`)}
|
||||
name="credentials"
|
||||
|
||||
@ -74,7 +74,7 @@ function OrganizationLookup({
|
||||
{
|
||||
name: i18n._(t`Name`),
|
||||
key: 'name',
|
||||
isDefault: true
|
||||
isDefault: true,
|
||||
},
|
||||
{
|
||||
name: i18n._(t`Created By (Username)`),
|
||||
@ -85,10 +85,12 @@ function OrganizationLookup({
|
||||
key: 'modified_by__username',
|
||||
},
|
||||
]}
|
||||
sortColumns={[{
|
||||
name: i18n._(t`Name`),
|
||||
key: 'name'
|
||||
}]}
|
||||
sortColumns={[
|
||||
{
|
||||
name: i18n._(t`Name`),
|
||||
key: 'name',
|
||||
},
|
||||
]}
|
||||
readOnly={!canDelete}
|
||||
selectItem={item => dispatch({ type: 'SELECT_ITEM', item })}
|
||||
deselectItem={item => dispatch({ type: 'DESELECT_ITEM', item })}
|
||||
|
||||
@ -74,32 +74,17 @@ function ProjectLookup({
|
||||
{
|
||||
name: i18n._(t`Name`),
|
||||
key: 'name',
|
||||
isDefault: true
|
||||
isDefault: true,
|
||||
},
|
||||
{
|
||||
name: i18n._(t`Type`),
|
||||
options: [
|
||||
[
|
||||
``,
|
||||
i18n._(t`Manual`)
|
||||
],
|
||||
[
|
||||
`git`,
|
||||
i18n._(t`Git`)
|
||||
],
|
||||
[
|
||||
`hg`,
|
||||
i18n._(t`Mercurial`)
|
||||
],
|
||||
[
|
||||
`svn`,
|
||||
i18n._(t`Subversion`)
|
||||
],
|
||||
[
|
||||
`insights`,
|
||||
i18n._(t`Red Hat Insights`)
|
||||
]
|
||||
]
|
||||
[``, i18n._(t`Manual`)],
|
||||
[`git`, i18n._(t`Git`)],
|
||||
[`hg`, i18n._(t`Mercurial`)],
|
||||
[`svn`, i18n._(t`Subversion`)],
|
||||
[`insights`, i18n._(t`Red Hat Insights`)],
|
||||
],
|
||||
},
|
||||
{
|
||||
name: i18n._(t`SCM URL`),
|
||||
@ -118,7 +103,7 @@ function ProjectLookup({
|
||||
{
|
||||
name: i18n._(t`Name`),
|
||||
key: 'name',
|
||||
}
|
||||
},
|
||||
]}
|
||||
options={projects}
|
||||
optionCount={count}
|
||||
|
||||
@ -101,7 +101,7 @@ OptionsList.defaultProps = {
|
||||
multiple: false,
|
||||
renderItemChip: null,
|
||||
searchColumns: [],
|
||||
sortColumns: []
|
||||
sortColumns: [],
|
||||
};
|
||||
|
||||
export default withI18n()(OptionsList);
|
||||
|
||||
@ -17,7 +17,7 @@ describe('<OptionsList />', () => {
|
||||
value={[]}
|
||||
options={options}
|
||||
optionCount={3}
|
||||
searchColumns={[{name: 'Foo', key: 'foo', isDefault: true}]}
|
||||
searchColumns={[{ name: 'Foo', key: 'foo', isDefault: true }]}
|
||||
sortColumns={[{ name: 'Foo', key: 'foo' }]}
|
||||
qsConfig={qsConfig}
|
||||
selectItem={() => {}}
|
||||
@ -40,7 +40,7 @@ describe('<OptionsList />', () => {
|
||||
value={[options[1]]}
|
||||
options={options}
|
||||
optionCount={3}
|
||||
searchColumns={[{name: 'Foo', key: 'foo', isDefault: true}]}
|
||||
searchColumns={[{ name: 'Foo', key: 'foo', isDefault: true }]}
|
||||
sortColumns={[{ name: 'Foo', key: 'foo' }]}
|
||||
qsConfig={qsConfig}
|
||||
selectItem={() => {}}
|
||||
|
||||
@ -202,7 +202,7 @@ class NotificationList extends Component {
|
||||
{
|
||||
name: i18n._(t`Name`),
|
||||
key: 'name',
|
||||
isDefault: true
|
||||
isDefault: true,
|
||||
},
|
||||
{
|
||||
name: i18n._(t`Type`),
|
||||
@ -218,7 +218,7 @@ class NotificationList extends Component {
|
||||
['slack', i18n._(t`Slack`)],
|
||||
['twilio', i18n._(t`Twilio`)],
|
||||
['webhook', i18n._(t`Webhook`)],
|
||||
]
|
||||
],
|
||||
},
|
||||
{
|
||||
name: i18n._(t`Created By (Username)`),
|
||||
|
||||
@ -80,7 +80,7 @@ class PaginatedDataList extends React.Component {
|
||||
{
|
||||
name: i18n._(t`Name`),
|
||||
key: 'name',
|
||||
isDefault: true
|
||||
isDefault: true,
|
||||
},
|
||||
];
|
||||
const sortColumns = toolbarSortColumns.length
|
||||
|
||||
@ -166,7 +166,7 @@ class ResourceAccessList extends React.Component {
|
||||
{
|
||||
name: i18n._(t`Username`),
|
||||
key: 'username',
|
||||
isDefault: true
|
||||
isDefault: true,
|
||||
},
|
||||
{
|
||||
name: i18n._(t`First Name`),
|
||||
|
||||
@ -19,7 +19,7 @@ import {
|
||||
import {
|
||||
DataToolbarGroup,
|
||||
DataToolbarItem,
|
||||
DataToolbarFilter
|
||||
DataToolbarFilter,
|
||||
} from '@patternfly/react-core/dist/umd/experimental';
|
||||
import { SearchIcon } from '@patternfly/react-icons';
|
||||
import { parseQueryString } from '@util/qs';
|
||||
@ -44,7 +44,7 @@ class Search extends React.Component {
|
||||
isSearchDropdownOpen: false,
|
||||
searchKey: columns.find(col => col.isDefault).key,
|
||||
searchValue: '',
|
||||
isFilterDropdownOpen: false
|
||||
isFilterDropdownOpen: false,
|
||||
};
|
||||
|
||||
this.handleSearchInputChange = this.handleSearchInputChange.bind(this);
|
||||
@ -52,8 +52,12 @@ class Search extends React.Component {
|
||||
this.handleDropdownSelect = this.handleDropdownSelect.bind(this);
|
||||
this.handleSearch = this.handleSearch.bind(this);
|
||||
this.handleTextKeyDown = this.handleTextKeyDown.bind(this);
|
||||
this.handleFilterDropdownToggle = this.handleFilterDropdownToggle.bind(this);
|
||||
this.handleFilterDropdownSelect = this.handleFilterDropdownSelect.bind(this);
|
||||
this.handleFilterDropdownToggle = this.handleFilterDropdownToggle.bind(
|
||||
this
|
||||
);
|
||||
this.handleFilterDropdownSelect = this.handleFilterDropdownSelect.bind(
|
||||
this
|
||||
);
|
||||
this.handleFilterBooleanSelect = this.handleFilterBooleanSelect.bind(this);
|
||||
}
|
||||
|
||||
@ -77,8 +81,8 @@ class Search extends React.Component {
|
||||
const { onSearch, qsConfig } = this.props;
|
||||
|
||||
const isNonStringField =
|
||||
qsConfig.integerFields.filter(field => field === searchKey).length ||
|
||||
qsConfig.dateFields.filter(field => field === searchKey).length;
|
||||
qsConfig.integerFields.find(field => field === searchKey) ||
|
||||
qsConfig.dateFields.find(field => field === searchKey);
|
||||
|
||||
const actualSearchKey = isNonStringField
|
||||
? searchKey
|
||||
@ -121,7 +125,12 @@ class Search extends React.Component {
|
||||
render() {
|
||||
const { up } = DropdownPosition;
|
||||
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(
|
||||
({ key }) => key === searchKey
|
||||
);
|
||||
@ -143,8 +152,8 @@ class Search extends React.Component {
|
||||
const queryParams = parseQueryString(qsConfig, location.search);
|
||||
|
||||
const queryParamsByKey = {};
|
||||
columns.forEach(({name, key}) => {
|
||||
queryParamsByKey[key] = {key, label: name, chips: []};
|
||||
columns.forEach(({ name, key }) => {
|
||||
queryParamsByKey[key] = { key, label: name, chips: [] };
|
||||
});
|
||||
const nonDefaultParams = filterDefaultParams(
|
||||
Object.keys(queryParams || {}),
|
||||
@ -152,12 +161,13 @@ class Search extends React.Component {
|
||||
);
|
||||
|
||||
nonDefaultParams.forEach(key => {
|
||||
const columnKey = key
|
||||
.replace('__icontains', '')
|
||||
.replace('or__', '');
|
||||
const label = columns
|
||||
.filter(({key: keyToCheck}) => columnKey === keyToCheck).length ? columns
|
||||
.filter(({key: keyToCheck}) => columnKey === keyToCheck)[0].name : columnKey;
|
||||
const columnKey = key.replace('__icontains', '').replace('or__', '');
|
||||
const label = columns.filter(
|
||||
({ key: keyToCheck }) => columnKey === keyToCheck
|
||||
).length
|
||||
? columns.filter(({ key: keyToCheck }) => columnKey === keyToCheck)[0]
|
||||
.name
|
||||
: columnKey;
|
||||
|
||||
queryParamsByKey[columnKey] = { key, label, chips: [] };
|
||||
|
||||
@ -171,7 +181,7 @@ class Search extends React.Component {
|
||||
});
|
||||
|
||||
return queryParamsByKey;
|
||||
}
|
||||
};
|
||||
|
||||
const chipsByKey = getChipsByKey();
|
||||
|
||||
@ -179,7 +189,7 @@ class Search extends React.Component {
|
||||
<DataToolbarGroup variant="filter-group">
|
||||
<DataToolbarItem>
|
||||
{searchDropdownItems.length > 0 ? (
|
||||
<Dropdown
|
||||
<Dropdown
|
||||
onToggle={this.handleDropdownToggle}
|
||||
onSelect={this.handleDropdownSelect}
|
||||
direction={up}
|
||||
@ -195,68 +205,90 @@ class Search extends React.Component {
|
||||
isOpen={isSearchDropdownOpen}
|
||||
dropdownItems={searchDropdownItems}
|
||||
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}
|
||||
aria-label={i18n._(t`Search submit button`)}
|
||||
onClick={this.handleSearch}
|
||||
>
|
||||
<SearchIcon />
|
||||
</Button>
|
||||
</InputGroup>)}
|
||||
</DataToolbarFilter>))}
|
||||
) : (
|
||||
<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.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>
|
||||
);
|
||||
}
|
||||
@ -266,12 +298,12 @@ Search.propTypes = {
|
||||
qsConfig: QSConfig.isRequired,
|
||||
columns: SearchColumns.isRequired,
|
||||
onSearch: PropTypes.func,
|
||||
onRemove: PropTypes.func
|
||||
onRemove: PropTypes.func,
|
||||
};
|
||||
|
||||
Search.defaultProps = {
|
||||
onSearch: null,
|
||||
onRemove: null
|
||||
onRemove: null,
|
||||
};
|
||||
|
||||
export default withI18n()(withRouter(Search));
|
||||
|
||||
@ -1,5 +1,8 @@
|
||||
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 Search from './Search';
|
||||
|
||||
@ -20,9 +23,7 @@ describe('<Search />', () => {
|
||||
});
|
||||
|
||||
test('it triggers the expected callbacks', () => {
|
||||
const columns = [
|
||||
{ name: 'Name', key: 'name', isDefault: true }
|
||||
];
|
||||
const columns = [{ name: 'Name', key: 'name', isDefault: true }];
|
||||
|
||||
const searchBtn = 'button[aria-label="Search submit button"]';
|
||||
const searchTextInput = 'input[aria-label="Search text input"]';
|
||||
@ -30,16 +31,13 @@ describe('<Search />', () => {
|
||||
const onSearch = jest.fn();
|
||||
|
||||
search = mountWithContexts(
|
||||
<DataToolbar id={`${QS_CONFIG.namespace}-list-toolbar`}
|
||||
<DataToolbar
|
||||
id={`${QS_CONFIG.namespace}-list-toolbar`}
|
||||
clearAllFilters={() => {}}
|
||||
collapseListedFiltersBreakpoint="md"
|
||||
>
|
||||
<DataToolbarContent>
|
||||
<Search
|
||||
qsConfig={QS_CONFIG}
|
||||
columns={columns}
|
||||
onSearch={onSearch}
|
||||
/>
|
||||
<Search qsConfig={QS_CONFIG} columns={columns} onSearch={onSearch} />
|
||||
</DataToolbarContent>
|
||||
</DataToolbar>
|
||||
);
|
||||
@ -53,21 +51,16 @@ describe('<Search />', () => {
|
||||
});
|
||||
|
||||
test('handleDropdownToggle properly updates state', async () => {
|
||||
const columns = [
|
||||
{ name: 'Name', key: 'name', isDefault: true }
|
||||
];
|
||||
const columns = [{ name: 'Name', key: 'name', isDefault: true }];
|
||||
const onSearch = jest.fn();
|
||||
const wrapper = mountWithContexts(
|
||||
<DataToolbar id={`${QS_CONFIG.namespace}-list-toolbar`}
|
||||
<DataToolbar
|
||||
id={`${QS_CONFIG.namespace}-list-toolbar`}
|
||||
clearAllFilters={() => {}}
|
||||
collapseListedFiltersBreakpoint="md"
|
||||
>
|
||||
<DataToolbarContent>
|
||||
<Search
|
||||
qsConfig={QS_CONFIG}
|
||||
columns={columns}
|
||||
onSearch={onSearch}
|
||||
/>
|
||||
<Search qsConfig={QS_CONFIG} columns={columns} onSearch={onSearch} />
|
||||
</DataToolbarContent>
|
||||
</DataToolbar>
|
||||
).find('Search');
|
||||
@ -83,16 +76,13 @@ describe('<Search />', () => {
|
||||
];
|
||||
const onSearch = jest.fn();
|
||||
const wrapper = mountWithContexts(
|
||||
<DataToolbar id={`${QS_CONFIG.namespace}-list-toolbar`}
|
||||
<DataToolbar
|
||||
id={`${QS_CONFIG.namespace}-list-toolbar`}
|
||||
clearAllFilters={() => {}}
|
||||
collapseListedFiltersBreakpoint="md"
|
||||
>
|
||||
<DataToolbarContent>
|
||||
<Search
|
||||
qsConfig={QS_CONFIG}
|
||||
columns={columns}
|
||||
onSearch={onSearch}
|
||||
/>
|
||||
<Search qsConfig={QS_CONFIG} columns={columns} onSearch={onSearch} />
|
||||
</DataToolbarContent>
|
||||
</DataToolbar>
|
||||
).find('Search');
|
||||
|
||||
@ -19,9 +19,7 @@ import {
|
||||
SortNumericUpIcon,
|
||||
} from '@patternfly/react-icons';
|
||||
|
||||
import {
|
||||
parseQueryString
|
||||
} from '@util/qs';
|
||||
import { parseQueryString } from '@util/qs';
|
||||
import { SortColumns, QSConfig } from '@types';
|
||||
import styled from 'styled-components';
|
||||
|
||||
@ -51,7 +49,7 @@ class Sort extends React.Component {
|
||||
sortOrder = 'ascending';
|
||||
}
|
||||
|
||||
if (qsConfig.integerFields.filter(field => field === sortKey).length) {
|
||||
if (qsConfig.integerFields.find(field => field === sortKey)) {
|
||||
isNumeric = true;
|
||||
} else {
|
||||
isNumeric = false;
|
||||
@ -61,7 +59,7 @@ class Sort extends React.Component {
|
||||
isSortDropdownOpen: false,
|
||||
sortKey,
|
||||
sortOrder,
|
||||
isNumeric
|
||||
isNumeric,
|
||||
};
|
||||
|
||||
this.handleDropdownToggle = this.handleDropdownToggle.bind(this);
|
||||
@ -78,13 +76,11 @@ class Sort extends React.Component {
|
||||
const { sortOrder } = this.state;
|
||||
const { innerText } = target;
|
||||
|
||||
const [{ key: sortKey }] = columns.filter(
|
||||
({ name }) => name === innerText
|
||||
);
|
||||
const [{ key: sortKey }] = columns.filter(({ name }) => name === innerText);
|
||||
|
||||
let isNumeric;
|
||||
|
||||
if (qsConfig.integerFields.filter(field => field === sortKey).length) {
|
||||
if (qsConfig.integerFields.find(field => field === sortKey)) {
|
||||
isNumeric = true;
|
||||
} else {
|
||||
isNumeric = false;
|
||||
@ -131,23 +127,23 @@ class Sort extends React.Component {
|
||||
<Fragment>
|
||||
{sortedColumnName && (
|
||||
<InputGroup>
|
||||
{sortDropdownItems.length > 0 && (<Dropdown
|
||||
onToggle={this.handleDropdownToggle}
|
||||
onSelect={this.handleDropdownSelect}
|
||||
direction={up}
|
||||
isOpen={isSortDropdownOpen}
|
||||
toggle={
|
||||
<DropdownToggle
|
||||
id="awx-sort"
|
||||
onToggle={this.handleDropdownToggle}
|
||||
>
|
||||
{sortedColumnName}
|
||||
</DropdownToggle>
|
||||
}
|
||||
dropdownItems={sortDropdownItems}
|
||||
/>) || (
|
||||
<NoOptionDropdown>{sortedColumnName}</NoOptionDropdown>
|
||||
)}
|
||||
{(sortDropdownItems.length > 0 && (
|
||||
<Dropdown
|
||||
onToggle={this.handleDropdownToggle}
|
||||
onSelect={this.handleDropdownSelect}
|
||||
direction={up}
|
||||
isOpen={isSortDropdownOpen}
|
||||
toggle={
|
||||
<DropdownToggle
|
||||
id="awx-sort"
|
||||
onToggle={this.handleDropdownToggle}
|
||||
>
|
||||
{sortedColumnName}
|
||||
</DropdownToggle>
|
||||
}
|
||||
dropdownItems={sortDropdownItems}
|
||||
/>
|
||||
)) || <NoOptionDropdown>{sortedColumnName}</NoOptionDropdown>}
|
||||
<Button
|
||||
variant={ButtonVariant.control}
|
||||
aria-label={i18n._(t`Sort`)}
|
||||
@ -165,11 +161,11 @@ class Sort extends React.Component {
|
||||
Sort.propTypes = {
|
||||
qsConfig: QSConfig.isRequired,
|
||||
columns: SortColumns.isRequired,
|
||||
onSort: PropTypes.func
|
||||
onSort: PropTypes.func,
|
||||
};
|
||||
|
||||
Sort.defaultProps = {
|
||||
onSort: null
|
||||
onSort: null,
|
||||
};
|
||||
|
||||
export default withI18n()(withRouter(Sort));
|
||||
|
||||
@ -30,11 +30,7 @@ describe('<Sort />', () => {
|
||||
const onSort = jest.fn();
|
||||
|
||||
const wrapper = mountWithContexts(
|
||||
<Sort
|
||||
qsConfig={qsConfig}
|
||||
columns={columns}
|
||||
onSort={onSort}
|
||||
/>
|
||||
<Sort qsConfig={qsConfig} columns={columns} onSort={onSort} />
|
||||
).find('Sort');
|
||||
|
||||
wrapper.find(sortBtn).simulate('click');
|
||||
@ -62,17 +58,13 @@ describe('<Sort />', () => {
|
||||
{
|
||||
name: 'Bakery',
|
||||
key: 'bakery',
|
||||
}
|
||||
},
|
||||
];
|
||||
|
||||
const onSort = jest.fn();
|
||||
|
||||
const wrapper = mountWithContexts(
|
||||
<Sort
|
||||
qsConfig={qsConfig}
|
||||
columns={columns}
|
||||
onSort={onSort}
|
||||
/>
|
||||
<Sort qsConfig={qsConfig} columns={columns} onSort={onSort} />
|
||||
).find('Sort');
|
||||
const sortDropdownToggle = wrapper.find('Button');
|
||||
expect(sortDropdownToggle.length).toBe(1);
|
||||
@ -99,17 +91,13 @@ describe('<Sort />', () => {
|
||||
{
|
||||
name: 'Bakery',
|
||||
key: 'bakery',
|
||||
}
|
||||
},
|
||||
];
|
||||
|
||||
const onSort = jest.fn();
|
||||
|
||||
const wrapper = mountWithContexts(
|
||||
<Sort
|
||||
qsConfig={qsConfig}
|
||||
columns={columns}
|
||||
onSort={onSort}
|
||||
/>
|
||||
<Sort qsConfig={qsConfig} columns={columns} onSort={onSort} />
|
||||
).find('Sort');
|
||||
const sortDropdownToggle = wrapper.find('Button');
|
||||
expect(sortDropdownToggle.length).toBe(1);
|
||||
@ -136,17 +124,13 @@ describe('<Sort />', () => {
|
||||
{
|
||||
name: 'Bakery',
|
||||
key: 'bakery',
|
||||
}
|
||||
},
|
||||
];
|
||||
|
||||
const onSort = jest.fn();
|
||||
|
||||
const wrapper = mountWithContexts(
|
||||
<Sort
|
||||
qsConfig={qsConfig}
|
||||
columns={columns}
|
||||
onSort={onSort}
|
||||
/>
|
||||
<Sort qsConfig={qsConfig} columns={columns} onSort={onSort} />
|
||||
).find('Sort');
|
||||
|
||||
wrapper.instance().handleDropdownSelect({ target: { innerText: 'Bar' } });
|
||||
@ -172,17 +156,13 @@ describe('<Sort />', () => {
|
||||
{
|
||||
name: 'Bakery',
|
||||
key: 'bakery',
|
||||
}
|
||||
},
|
||||
];
|
||||
|
||||
const onSort = jest.fn();
|
||||
|
||||
const wrapper = mountWithContexts(
|
||||
<Sort
|
||||
qsConfig={qsConfig}
|
||||
columns={columns}
|
||||
onSort={onSort}
|
||||
/>
|
||||
<Sort qsConfig={qsConfig} columns={columns} onSort={onSort} />
|
||||
).find('Sort');
|
||||
expect(wrapper.state('isSortDropdownOpen')).toEqual(false);
|
||||
wrapper.instance().handleDropdownToggle(true);
|
||||
@ -216,12 +196,8 @@ describe('<Sort />', () => {
|
||||
integerFields: ['page', 'page_size'],
|
||||
};
|
||||
|
||||
const numericColumns = [
|
||||
{ name: 'ID', key: 'id' },
|
||||
];
|
||||
const alphaColumns = [
|
||||
{ name: 'Name', key: 'name' },
|
||||
];
|
||||
const numericColumns = [{ name: 'ID', key: 'id' }];
|
||||
const alphaColumns = [{ name: 'Name', key: 'name' }];
|
||||
const onSort = jest.fn();
|
||||
|
||||
sort = mountWithContexts(
|
||||
@ -236,11 +212,7 @@ describe('<Sort />', () => {
|
||||
expect(downNumericIcon.length).toBe(1);
|
||||
|
||||
sort = mountWithContexts(
|
||||
<Sort
|
||||
qsConfig={qsConfigNumUp}
|
||||
columns={numericColumns}
|
||||
onSort={onSort}
|
||||
/>
|
||||
<Sort qsConfig={qsConfigNumUp} columns={numericColumns} onSort={onSort} />
|
||||
);
|
||||
|
||||
const upNumericIcon = sort.find(upNumericIconSelector);
|
||||
@ -258,11 +230,7 @@ describe('<Sort />', () => {
|
||||
expect(downAlphaIcon.length).toBe(1);
|
||||
|
||||
sort = mountWithContexts(
|
||||
<Sort
|
||||
qsConfig={qsConfigAlphaUp}
|
||||
columns={alphaColumns}
|
||||
onSort={onSort}
|
||||
/>
|
||||
<Sort qsConfig={qsConfigAlphaUp} columns={alphaColumns} onSort={onSort} />
|
||||
);
|
||||
|
||||
const upAlphaIcon = sort.find(upAlphaIconSelector);
|
||||
|
||||
@ -194,7 +194,7 @@ class HostsList extends Component {
|
||||
{
|
||||
name: i18n._(t`Name`),
|
||||
key: 'name',
|
||||
isDefault: true
|
||||
isDefault: true,
|
||||
},
|
||||
{
|
||||
name: i18n._(t`Created By (Username)`),
|
||||
|
||||
@ -181,12 +181,12 @@ function InventoryGroupsList({ i18n, location, match }) {
|
||||
{
|
||||
name: i18n._(t`Name`),
|
||||
key: 'name',
|
||||
isDefault: true
|
||||
isDefault: true,
|
||||
},
|
||||
{
|
||||
name: i18n._(t`Is Root Group`),
|
||||
key: 'parents__isnull',
|
||||
isBoolean: true
|
||||
isBoolean: true,
|
||||
},
|
||||
{
|
||||
name: i18n._(t`Created By (Username)`),
|
||||
@ -200,8 +200,8 @@ function InventoryGroupsList({ i18n, location, match }) {
|
||||
toolbarSortColumns={[
|
||||
{
|
||||
name: i18n._(t`Name`),
|
||||
key: 'name'
|
||||
}
|
||||
key: 'name',
|
||||
},
|
||||
]}
|
||||
renderItem={item => (
|
||||
<InventoryGroupItem
|
||||
|
||||
@ -161,7 +161,9 @@ describe('<InventoryGroupsList />', () => {
|
||||
});
|
||||
wrapper.update();
|
||||
await act(async () => {
|
||||
wrapper.find('DataToolbar Button[aria-label="Delete"]').invoke('onClick')();
|
||||
wrapper
|
||||
.find('DataToolbar Button[aria-label="Delete"]')
|
||||
.invoke('onClick')();
|
||||
});
|
||||
await waitForElement(
|
||||
wrapper,
|
||||
@ -193,7 +195,9 @@ describe('<InventoryGroupsList />', () => {
|
||||
});
|
||||
wrapper.update();
|
||||
await act(async () => {
|
||||
wrapper.find('DataToolbar Button[aria-label="Delete"]').invoke('onClick')();
|
||||
wrapper
|
||||
.find('DataToolbar Button[aria-label="Delete"]')
|
||||
.invoke('onClick')();
|
||||
});
|
||||
await waitForElement(
|
||||
wrapper,
|
||||
|
||||
@ -136,7 +136,7 @@ function InventoryHosts({ i18n, location, match }) {
|
||||
{
|
||||
name: i18n._(t`Name`),
|
||||
key: 'name',
|
||||
isDefault: true
|
||||
isDefault: true,
|
||||
},
|
||||
{
|
||||
name: i18n._(t`Created By (Username)`),
|
||||
@ -150,8 +150,8 @@ function InventoryHosts({ i18n, location, match }) {
|
||||
toolbarSortColumns={[
|
||||
{
|
||||
name: i18n._(t`Name`),
|
||||
key: 'name'
|
||||
}
|
||||
key: 'name',
|
||||
},
|
||||
]}
|
||||
renderToolbar={props => (
|
||||
<DataListToolbar
|
||||
|
||||
@ -178,7 +178,7 @@ class InventoriesList extends Component {
|
||||
{
|
||||
name: i18n._(t`Name`),
|
||||
key: 'name',
|
||||
isDefault: true
|
||||
isDefault: true,
|
||||
},
|
||||
{
|
||||
name: i18n._(t`Created By (Username)`),
|
||||
|
||||
@ -23,12 +23,16 @@ import { getQSConfig, parseQueryString } from '@util/qs';
|
||||
|
||||
import JobListItem from './JobListItem';
|
||||
|
||||
const QS_CONFIG = getQSConfig('job', {
|
||||
page: 1,
|
||||
page_size: 20,
|
||||
order_by: '-finished',
|
||||
not__launch_type: 'sync',
|
||||
}, ['page', 'page_size', 'id']);
|
||||
const QS_CONFIG = getQSConfig(
|
||||
'job',
|
||||
{
|
||||
page: 1,
|
||||
page_size: 20,
|
||||
order_by: '-finished',
|
||||
not__launch_type: 'sync',
|
||||
},
|
||||
['page', 'page_size', 'id']
|
||||
);
|
||||
|
||||
class JobList extends Component {
|
||||
constructor(props) {
|
||||
@ -167,88 +171,46 @@ class JobList extends Component {
|
||||
{
|
||||
name: i18n._(t`Name`),
|
||||
key: 'name',
|
||||
isDefault: true
|
||||
isDefault: true,
|
||||
},
|
||||
{
|
||||
name: i18n._(t`ID`),
|
||||
key: 'id'
|
||||
key: 'id',
|
||||
},
|
||||
{
|
||||
name: i18n._(t`Label Name`),
|
||||
key: 'labels__name'
|
||||
key: 'labels__name',
|
||||
},
|
||||
{
|
||||
name: i18n._(t`Job Type`),
|
||||
key: `type`,
|
||||
options: [
|
||||
[
|
||||
`project_update`,
|
||||
i18n._(t`SCM Update`)
|
||||
],
|
||||
[
|
||||
`inventory_update`,
|
||||
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`)
|
||||
]
|
||||
]
|
||||
[`project_update`, i18n._(t`SCM Update`)],
|
||||
[`inventory_update`, 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)`),
|
||||
key: 'created_by__username'
|
||||
key: 'created_by__username',
|
||||
},
|
||||
{
|
||||
name: i18n._(t`Status`),
|
||||
key: 'status',
|
||||
options: [
|
||||
[
|
||||
`new`,
|
||||
i18n._(t`New`)
|
||||
],
|
||||
[
|
||||
`pending`,
|
||||
i18n._(t`Pending`)
|
||||
],
|
||||
[
|
||||
`waiting`,
|
||||
i18n._(t`Waiting`)
|
||||
],
|
||||
[
|
||||
`running`,
|
||||
i18n._(t`Running`)
|
||||
],
|
||||
[
|
||||
`successful`,
|
||||
i18n._(t`Successful`)
|
||||
],
|
||||
[
|
||||
`failed`,
|
||||
i18n._(t`Failed`)
|
||||
],
|
||||
[
|
||||
`error`,
|
||||
i18n._(t`Error`)
|
||||
],
|
||||
[
|
||||
`canceled`,
|
||||
i18n._(t`Canceled`)
|
||||
]
|
||||
]
|
||||
}
|
||||
[`new`, i18n._(t`New`)],
|
||||
[`pending`, i18n._(t`Pending`)],
|
||||
[`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={[
|
||||
{
|
||||
|
||||
@ -123,7 +123,7 @@ function OrganizationsList({ i18n }) {
|
||||
{
|
||||
name: i18n._(t`Name`),
|
||||
key: 'name',
|
||||
isDefault: true
|
||||
isDefault: true,
|
||||
},
|
||||
{
|
||||
name: i18n._(t`Created By (Username)`),
|
||||
|
||||
@ -51,7 +51,7 @@ function OrganizationTeams({ id, i18n }) {
|
||||
{
|
||||
name: i18n._(t`Name`),
|
||||
key: 'name',
|
||||
isDefault: true
|
||||
isDefault: true,
|
||||
},
|
||||
{
|
||||
name: i18n._(t`Created by (username)`),
|
||||
|
||||
@ -160,32 +160,18 @@ class ProjectsList extends Component {
|
||||
{
|
||||
name: i18n._(t`Name`),
|
||||
key: 'name',
|
||||
isDefault: true
|
||||
isDefault: true,
|
||||
},
|
||||
{
|
||||
name: i18n._(t`Type`),
|
||||
key: 'type',
|
||||
options: [
|
||||
[
|
||||
``,
|
||||
i18n._(t`Manual`)
|
||||
],
|
||||
[
|
||||
`git`,
|
||||
i18n._(t`Git`)
|
||||
],
|
||||
[
|
||||
`hg`,
|
||||
i18n._(t`Mercurial`)
|
||||
],
|
||||
[
|
||||
`svn`,
|
||||
i18n._(t`Subversion`)
|
||||
],
|
||||
[
|
||||
`insights`,
|
||||
i18n._(t`Red Hat Insights`)
|
||||
]
|
||||
]
|
||||
[``, i18n._(t`Manual`)],
|
||||
[`git`, i18n._(t`Git`)],
|
||||
[`hg`, i18n._(t`Mercurial`)],
|
||||
[`svn`, i18n._(t`Subversion`)],
|
||||
[`insights`, i18n._(t`Red Hat Insights`)],
|
||||
],
|
||||
},
|
||||
{
|
||||
name: i18n._(t`SCM URL`),
|
||||
@ -204,7 +190,7 @@ class ProjectsList extends Component {
|
||||
{
|
||||
name: i18n._(t`Name`),
|
||||
key: 'name',
|
||||
}
|
||||
},
|
||||
]}
|
||||
renderToolbar={props => (
|
||||
<DataListToolbar
|
||||
|
||||
@ -158,7 +158,7 @@ class TeamsList extends Component {
|
||||
{
|
||||
name: i18n._(t`Name`),
|
||||
key: 'name',
|
||||
isDefault: true
|
||||
isDefault: true,
|
||||
},
|
||||
{
|
||||
name: i18n._(t`Organization Name`),
|
||||
|
||||
@ -218,21 +218,15 @@ class TemplatesList extends Component {
|
||||
{
|
||||
name: i18n._(t`Name`),
|
||||
key: 'name',
|
||||
isDefault: true
|
||||
isDefault: true,
|
||||
},
|
||||
{
|
||||
name: i18n._(t`Type`),
|
||||
key: 'type',
|
||||
options: [
|
||||
[
|
||||
`job_template`,
|
||||
i18n._(t`Job Template`)
|
||||
],
|
||||
[
|
||||
`workflow_job_template`,
|
||||
i18n._(t`Workflow Template`)
|
||||
],
|
||||
]
|
||||
[`job_template`, i18n._(t`Job Template`)],
|
||||
[`workflow_job_template`, i18n._(t`Workflow Template`)],
|
||||
],
|
||||
},
|
||||
{
|
||||
name: i18n._(t`Playbook name`),
|
||||
|
||||
@ -158,7 +158,7 @@ class UsersList extends Component {
|
||||
{
|
||||
name: i18n._(t`Username`),
|
||||
key: 'username',
|
||||
isDefault: true
|
||||
isDefault: true,
|
||||
},
|
||||
{
|
||||
name: i18n._(t`First Name`),
|
||||
@ -167,7 +167,7 @@ class UsersList extends Component {
|
||||
{
|
||||
name: i18n._(t`Last Name`),
|
||||
key: 'last_name',
|
||||
}
|
||||
},
|
||||
]}
|
||||
toolbarSortColumns={[
|
||||
{
|
||||
|
||||
@ -257,7 +257,7 @@ export const SearchColumns = arrayOf(
|
||||
key: string.isRequired,
|
||||
isDefault: bool,
|
||||
isBoolean: bool,
|
||||
options: arrayOf(arrayOf(string, string))
|
||||
options: arrayOf(arrayOf(string, string)),
|
||||
})
|
||||
);
|
||||
|
||||
|
||||
@ -15,7 +15,7 @@ export function getQSConfig(
|
||||
throw new Error('a QS namespace is required');
|
||||
}
|
||||
// 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';
|
||||
}
|
||||
return {
|
||||
@ -193,7 +193,6 @@ function removeParam(oldVal, deleteVal) {
|
||||
* @return {object} merged namespaced params object
|
||||
*/
|
||||
export function mergeParams(oldParams, newParams) {
|
||||
debugger;
|
||||
const merged = {};
|
||||
Object.keys(oldParams).forEach(key => {
|
||||
merged[key] = mergeParam(oldParams[key], newParams[key]);
|
||||
|
||||
@ -122,10 +122,12 @@ describe('qs (qs.js)', () => {
|
||||
});
|
||||
|
||||
test('should set order_by in defaultParams if it is not passed', () => {
|
||||
expect(getQSConfig('organization', {
|
||||
page: 1,
|
||||
page_size: 5,
|
||||
})).toEqual({
|
||||
expect(
|
||||
getQSConfig('organization', {
|
||||
page: 1,
|
||||
page_size: 5,
|
||||
})
|
||||
).toEqual({
|
||||
namespace: 'organization',
|
||||
defaultParams: { page: 1, page_size: 5, order_by: 'name' },
|
||||
integerFields: ['page', 'page_size'],
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user