mirror of
https://github.com/ansible/awx.git
synced 2026-01-17 20:51:21 -03:30
Merge pull request #10798 from keithjgrant/7834-advanced-search-fix
Only allow legal/logical match types in advanced search
This commit is contained in:
commit
cdce745c55
@ -9,6 +9,7 @@ import { CredentialsAPI } from 'api';
|
||||
import { getQSConfig, parseQueryString, mergeParams } from 'util/qs';
|
||||
import useRequest from 'hooks/useRequest';
|
||||
import { required } from 'util/validators';
|
||||
import { getSearchableKeys } from 'components/PaginatedTable';
|
||||
import Popover from '../Popover';
|
||||
|
||||
import ContentError from '../ContentError';
|
||||
@ -59,9 +60,7 @@ function AdHocCredentialStep({ credentialTypeId }) {
|
||||
relatedSearchableKeys: (
|
||||
actionsResponse?.data?.related_search_fields || []
|
||||
).map((val) => val.slice(0, -8)),
|
||||
searchableKeys: Object.keys(
|
||||
actionsResponse.data.actions?.GET || {}
|
||||
).filter((key) => actionsResponse.data.actions?.GET[key].filterable),
|
||||
searchableKeys: getSearchableKeys(actionsResponse.data.actions?.GET),
|
||||
};
|
||||
}, [credentialTypeId, history.location.search]),
|
||||
{
|
||||
|
||||
@ -6,6 +6,7 @@ import { Form, FormGroup } from '@patternfly/react-core';
|
||||
import { ExecutionEnvironmentsAPI } from 'api';
|
||||
|
||||
import { parseQueryString, getQSConfig, mergeParams } from 'util/qs';
|
||||
import { getSearchableKeys } from 'components/PaginatedTable';
|
||||
import useRequest from 'hooks/useRequest';
|
||||
import Popover from '../Popover';
|
||||
import ContentError from '../ContentError';
|
||||
@ -60,9 +61,7 @@ function AdHocExecutionEnvironmentStep({ organizationId }) {
|
||||
relatedSearchableKeys: (
|
||||
actionsResponse?.data?.related_search_fields || []
|
||||
).map((val) => val.slice(0, -8)),
|
||||
searchableKeys: Object.keys(
|
||||
actionsResponse.data.actions?.GET || {}
|
||||
).filter((key) => actionsResponse.data.actions?.GET[key].filterable),
|
||||
searchableKeys: getSearchableKeys(actionsResponse.data.actions?.GET),
|
||||
};
|
||||
}, [history.location.search, organizationId]),
|
||||
{
|
||||
|
||||
@ -8,7 +8,11 @@ import { getQSConfig, parseQueryString } from 'util/qs';
|
||||
import DataListToolbar from '../DataListToolbar';
|
||||
import CheckboxListItem from '../CheckboxListItem';
|
||||
import { SelectedList } from '../SelectedList';
|
||||
import PaginatedTable, { HeaderCell, HeaderRow } from '../PaginatedTable';
|
||||
import PaginatedTable, {
|
||||
HeaderCell,
|
||||
HeaderRow,
|
||||
getSearchableKeys,
|
||||
} from '../PaginatedTable';
|
||||
|
||||
const QS_Config = (sortColumns) =>
|
||||
getQSConfig('resource', {
|
||||
@ -56,9 +60,7 @@ function SelectResourceStep({
|
||||
relatedSearchableKeys: (
|
||||
actionsResponse?.data?.related_search_fields || []
|
||||
).map((val) => val.slice(0, -8)),
|
||||
searchableKeys: Object.keys(
|
||||
actionsResponse.data.actions?.GET || {}
|
||||
).filter((key) => actionsResponse.data.actions?.GET[key].filterable),
|
||||
searchableKeys: getSearchableKeys(actionsResponse.data.actions?.GET),
|
||||
};
|
||||
}, [location, fetchItems, fetchOptions, sortColumns]),
|
||||
{
|
||||
|
||||
@ -3,6 +3,7 @@ import { useHistory } from 'react-router-dom';
|
||||
|
||||
import { t } from '@lingui/macro';
|
||||
import { Button, Modal } from '@patternfly/react-core';
|
||||
import { getSearchableKeys } from 'components/PaginatedTable';
|
||||
import useRequest from 'hooks/useRequest';
|
||||
import { getQSConfig, parseQueryString } from 'util/qs';
|
||||
import useSelected from 'hooks/useSelected';
|
||||
@ -53,9 +54,7 @@ function AssociateModal({
|
||||
relatedSearchableKeys: (
|
||||
actionsResponse?.data?.related_search_fields || []
|
||||
).map((val) => val.slice(0, -8)),
|
||||
searchableKeys: Object.keys(
|
||||
actionsResponse.data.actions?.GET || {}
|
||||
).filter((key) => actionsResponse.data.actions?.GET[key].filterable),
|
||||
searchableKeys: getSearchableKeys(actionsResponse.data.actions?.GET),
|
||||
};
|
||||
}, [fetchRequest, optionsRequest, history.location.search, displayKey]),
|
||||
{
|
||||
|
||||
@ -20,7 +20,7 @@ import {
|
||||
AngleRightIcon,
|
||||
SearchIcon,
|
||||
} from '@patternfly/react-icons';
|
||||
import { SearchColumns, SortColumns, QSConfig } from 'types';
|
||||
import { SearchColumns, SortColumns, QSConfig, SearchableKeys } from 'types';
|
||||
import { KebabifiedProvider } from 'contexts/Kebabified';
|
||||
import ExpandCollapse from '../ExpandCollapse';
|
||||
import Search from '../Search';
|
||||
@ -200,7 +200,7 @@ DataListToolbar.propTypes = {
|
||||
clearAllFilters: PropTypes.func,
|
||||
qsConfig: QSConfig.isRequired,
|
||||
searchColumns: SearchColumns.isRequired,
|
||||
searchableKeys: PropTypes.arrayOf(PropTypes.string),
|
||||
searchableKeys: SearchableKeys,
|
||||
relatedSearchableKeys: PropTypes.arrayOf(PropTypes.string),
|
||||
sortColumns: SortColumns,
|
||||
isAllSelected: PropTypes.bool,
|
||||
|
||||
@ -20,6 +20,7 @@ import PaginatedTable, {
|
||||
HeaderRow,
|
||||
HeaderCell,
|
||||
ToolbarDeleteButton,
|
||||
getSearchableKeys,
|
||||
} from '../PaginatedTable';
|
||||
import JobListItem from './JobListItem';
|
||||
import JobListCancelButton from './JobListCancelButton';
|
||||
@ -80,9 +81,7 @@ function JobList({ defaultParams, showTypeColumn = false }) {
|
||||
relatedSearchableKeys: (
|
||||
actionsResponse?.data?.related_search_fields || []
|
||||
).map((val) => val.slice(0, -8)),
|
||||
searchableKeys: Object.keys(
|
||||
actionsResponse.data.actions?.GET || {}
|
||||
).filter((key) => actionsResponse.data.actions?.GET[key].filterable),
|
||||
searchableKeys: getSearchableKeys(actionsResponse.data.actions?.GET),
|
||||
};
|
||||
},
|
||||
[location] // eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
@ -7,6 +7,7 @@ import { useField } from 'formik';
|
||||
import styled from 'styled-components';
|
||||
import { Alert, ToolbarItem } from '@patternfly/react-core';
|
||||
import { CredentialsAPI, CredentialTypesAPI } from 'api';
|
||||
import { getSearchableKeys } from 'components/PaginatedTable';
|
||||
import { getQSConfig, parseQueryString } from 'util/qs';
|
||||
import useRequest from 'hooks/useRequest';
|
||||
import AnsibleSelect from '../../AnsibleSelect';
|
||||
@ -88,9 +89,7 @@ function CredentialsStep({
|
||||
relatedSearchableKeys: (
|
||||
actionsResponse?.data?.related_search_fields || []
|
||||
).map((val) => val.slice(0, -8)),
|
||||
searchableKeys: Object.keys(
|
||||
actionsResponse.data.actions?.GET || {}
|
||||
).filter((key) => actionsResponse.data.actions?.GET[key].filterable),
|
||||
searchableKeys: getSearchableKeys(actionsResponse.data.actions?.GET),
|
||||
};
|
||||
}, [selectedType, history.location.search]),
|
||||
{ credentials: [], count: 0, relatedSearchableKeys: [], searchableKeys: [] }
|
||||
|
||||
@ -6,6 +6,7 @@ import { useField } from 'formik';
|
||||
import styled from 'styled-components';
|
||||
import { Alert } from '@patternfly/react-core';
|
||||
import { InventoriesAPI } from 'api';
|
||||
import { getSearchableKeys } from 'components/PaginatedTable';
|
||||
import { getQSConfig, parseQueryString } from 'util/qs';
|
||||
import useRequest from 'hooks/useRequest';
|
||||
import OptionsList from '../../OptionsList';
|
||||
@ -45,9 +46,7 @@ function InventoryStep({ warningMessage = null }) {
|
||||
relatedSearchableKeys: (
|
||||
actionsResponse?.data?.related_search_fields || []
|
||||
).map((val) => val.slice(0, -8)),
|
||||
searchableKeys: Object.keys(
|
||||
actionsResponse.data.actions?.GET || {}
|
||||
).filter((key) => actionsResponse.data.actions?.GET[key].filterable),
|
||||
searchableKeys: getSearchableKeys(actionsResponse.data.actions?.GET),
|
||||
};
|
||||
}, [history.location]),
|
||||
{
|
||||
|
||||
@ -10,7 +10,7 @@ import {
|
||||
removeParams,
|
||||
updateQueryString,
|
||||
} from 'util/qs';
|
||||
import { QSConfig, SearchColumns, SortColumns } from 'types';
|
||||
import { QSConfig, SearchColumns, SortColumns, SearchableKeys } from 'types';
|
||||
import DataListToolbar from '../DataListToolbar';
|
||||
|
||||
const EmptyStateControlsWrapper = styled.div`
|
||||
@ -146,7 +146,7 @@ ListHeader.propTypes = {
|
||||
itemCount: PropTypes.number.isRequired,
|
||||
qsConfig: QSConfig.isRequired,
|
||||
searchColumns: SearchColumns.isRequired,
|
||||
searchableKeys: PropTypes.arrayOf(PropTypes.string),
|
||||
searchableKeys: SearchableKeys,
|
||||
relatedSearchableKeys: PropTypes.arrayOf(PropTypes.string),
|
||||
sortColumns: SortColumns,
|
||||
renderToolbar: PropTypes.func,
|
||||
|
||||
@ -5,6 +5,7 @@ import { t } from '@lingui/macro';
|
||||
import { FormGroup } from '@patternfly/react-core';
|
||||
import { ApplicationsAPI } from 'api';
|
||||
import { Application } from 'types';
|
||||
import { getSearchableKeys } from 'components/PaginatedTable';
|
||||
import { getQSConfig, parseQueryString } from 'util/qs';
|
||||
import useRequest from 'hooks/useRequest';
|
||||
import Lookup from './Lookup';
|
||||
@ -42,9 +43,7 @@ function ApplicationLookup({ onChange, value, label, fieldName, validate }) {
|
||||
relatedSearchableKeys: (
|
||||
actionsResponse?.data?.related_search_fields || []
|
||||
).map((val) => val.slice(0, -8)),
|
||||
searchableKeys: Object.keys(
|
||||
actionsResponse?.data?.actions?.GET || {}
|
||||
).filter((key) => actionsResponse.data.actions?.GET[key].filterable),
|
||||
searchableKeys: getSearchableKeys(actionsResponse?.data?.actions?.GET),
|
||||
};
|
||||
}, [location]),
|
||||
{
|
||||
|
||||
@ -14,6 +14,7 @@ import { t } from '@lingui/macro';
|
||||
import { FormGroup } from '@patternfly/react-core';
|
||||
import { CredentialsAPI } from 'api';
|
||||
import { Credential } from 'types';
|
||||
import { getSearchableKeys } from 'components/PaginatedTable';
|
||||
import { getQSConfig, parseQueryString, mergeParams } from 'util/qs';
|
||||
import useAutoPopulateLookup from 'hooks/useAutoPopulateLookup';
|
||||
import useRequest from 'hooks/useRequest';
|
||||
@ -82,12 +83,10 @@ function CredentialLookup({
|
||||
autoPopulateLookup(data.results);
|
||||
}
|
||||
|
||||
const searchKeys = Object.keys(
|
||||
actionsResponse.data.actions?.GET || {}
|
||||
).filter((key) => actionsResponse.data.actions?.GET[key].filterable);
|
||||
const item = searchKeys.indexOf('type');
|
||||
const searchKeys = getSearchableKeys(actionsResponse.data.actions?.GET);
|
||||
const item = searchKeys.find((k) => k.key === 'type');
|
||||
if (item) {
|
||||
searchKeys[item] = 'credential_type__kind';
|
||||
item.key = 'credential_type__kind';
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
@ -4,6 +4,7 @@ import { useLocation } from 'react-router-dom';
|
||||
import { t } from '@lingui/macro';
|
||||
import { FormGroup, Tooltip } from '@patternfly/react-core';
|
||||
import { ExecutionEnvironmentsAPI, ProjectsAPI } from 'api';
|
||||
import { getSearchableKeys } from 'components/PaginatedTable';
|
||||
import { ExecutionEnvironment } from 'types';
|
||||
import { getQSConfig, parseQueryString, mergeParams } from 'util/qs';
|
||||
import useRequest from 'hooks/useRequest';
|
||||
@ -109,9 +110,7 @@ function ExecutionEnvironmentLookup({
|
||||
relatedSearchableKeys: (
|
||||
actionsResponse?.data?.related_search_fields || []
|
||||
).map((val) => val.slice(0, -8)),
|
||||
searchableKeys: Object.keys(
|
||||
actionsResponse.data.actions?.GET || {}
|
||||
).filter((key) => actionsResponse.data.actions?.GET[key].filterable),
|
||||
searchableKeys: getSearchableKeys(actionsResponse.data.actions?.GET),
|
||||
};
|
||||
}, [
|
||||
location,
|
||||
|
||||
@ -21,7 +21,11 @@ import ChipGroup from '../ChipGroup';
|
||||
import Popover from '../Popover';
|
||||
import DataListToolbar from '../DataListToolbar';
|
||||
import LookupErrorMessage from './shared/LookupErrorMessage';
|
||||
import PaginatedTable, { HeaderCell, HeaderRow } from '../PaginatedTable';
|
||||
import PaginatedTable, {
|
||||
HeaderCell,
|
||||
HeaderRow,
|
||||
getSearchableKeys,
|
||||
} from '../PaginatedTable';
|
||||
import HostListItem from './HostListItem';
|
||||
import {
|
||||
removeDefaultParams,
|
||||
@ -157,9 +161,7 @@ function HostFilterLookup({
|
||||
relatedSearchableKeys: (actions?.related_search_fields || []).map(
|
||||
parseRelatedSearchFields
|
||||
),
|
||||
searchableKeys: Object.keys(actions?.actions.GET || {}).filter(
|
||||
(key) => actions.actions?.GET[key].filterable
|
||||
),
|
||||
searchableKeys: getSearchableKeys(actions?.actions.GET),
|
||||
};
|
||||
},
|
||||
[location.search]
|
||||
|
||||
@ -6,6 +6,7 @@ import { t, Trans } from '@lingui/macro';
|
||||
import { FormGroup } from '@patternfly/react-core';
|
||||
import { InstanceGroupsAPI } from 'api';
|
||||
import { InstanceGroup } from 'types';
|
||||
import { getSearchableKeys } from 'components/PaginatedTable';
|
||||
import { getQSConfig, parseQueryString } from 'util/qs';
|
||||
import useRequest from 'hooks/useRequest';
|
||||
import Popover from '../Popover';
|
||||
@ -47,9 +48,7 @@ function InstanceGroupsLookup({
|
||||
relatedSearchableKeys: (
|
||||
actionsResponse?.data?.related_search_fields || []
|
||||
).map((val) => val.slice(0, -8)),
|
||||
searchableKeys: Object.keys(
|
||||
actionsResponse.data.actions?.GET || {}
|
||||
).filter((key) => actionsResponse.data.actions?.GET[key].filterable),
|
||||
searchableKeys: getSearchableKeys(actionsResponse.data.actions?.GET),
|
||||
};
|
||||
}, [history.location]),
|
||||
{
|
||||
|
||||
@ -74,14 +74,17 @@ function InventoryLookup({
|
||||
relatedSearchableKeys: (
|
||||
actionsResponse?.data?.related_search_fields || []
|
||||
).map((val) => val.slice(0, -8)),
|
||||
searchableKeys: Object.keys(
|
||||
actionsResponse.data.actions?.GET || {}
|
||||
).filter((key) => {
|
||||
if (['kind', 'host_filter'].includes(key) && hideSmartInventories) {
|
||||
return false;
|
||||
}
|
||||
return actionsResponse.data.actions?.GET[key].filterable;
|
||||
}),
|
||||
searchableKeys: Object.keys(actionsResponse.data.actions?.GET || {})
|
||||
.filter((key) => {
|
||||
if (['kind', 'host_filter'].includes(key) && hideSmartInventories) {
|
||||
return false;
|
||||
}
|
||||
return actionsResponse.data.actions?.GET[key].filterable;
|
||||
})
|
||||
.map((key) => ({
|
||||
key,
|
||||
type: actionsResponse.data.actions?.GET[key].type,
|
||||
})),
|
||||
canEdit:
|
||||
Boolean(actionsResponse.data.actions.POST) || isOverrideDisabled,
|
||||
};
|
||||
|
||||
@ -5,6 +5,7 @@ import PropTypes from 'prop-types';
|
||||
import { t } from '@lingui/macro';
|
||||
import { ToolbarItem, Alert } from '@patternfly/react-core';
|
||||
import { CredentialsAPI, CredentialTypesAPI } from 'api';
|
||||
import { getSearchableKeys } from 'components/PaginatedTable';
|
||||
import useRequest from 'hooks/useRequest';
|
||||
import { getQSConfig, parseQueryString } from 'util/qs';
|
||||
import useIsMounted from 'hooks/useIsMounted';
|
||||
@ -100,9 +101,7 @@ function MultiCredentialsLookup({
|
||||
relatedSearchableKeys: (
|
||||
actionsResponse?.data?.related_search_fields || []
|
||||
).map((val) => val.slice(0, -8)),
|
||||
searchableKeys: Object.keys(
|
||||
actionsResponse.data.actions?.GET || {}
|
||||
).filter((key) => actionsResponse.data.actions?.GET[key].filterable),
|
||||
searchableKeys: getSearchableKeys(actionsResponse.data.actions?.GET),
|
||||
};
|
||||
}, [selectedType, history.location]),
|
||||
{
|
||||
|
||||
@ -6,6 +6,7 @@ import { FormGroup } from '@patternfly/react-core';
|
||||
import { OrganizationsAPI } from 'api';
|
||||
import { Organization } from 'types';
|
||||
import { getQSConfig, parseQueryString } from 'util/qs';
|
||||
import { getSearchableKeys } from 'components/PaginatedTable';
|
||||
import useRequest from 'hooks/useRequest';
|
||||
import useAutoPopulateLookup from 'hooks/useAutoPopulateLookup';
|
||||
import OptionsList from '../OptionsList';
|
||||
@ -57,9 +58,7 @@ function OrganizationLookup({
|
||||
relatedSearchableKeys: (
|
||||
actionsResponse?.data?.related_search_fields || []
|
||||
).map((val) => val.slice(0, -8)),
|
||||
searchableKeys: Object.keys(
|
||||
actionsResponse.data.actions?.GET || {}
|
||||
).filter((key) => actionsResponse.data.actions?.GET[key].filterable),
|
||||
searchableKeys: getSearchableKeys(actionsResponse.data.actions?.GET),
|
||||
};
|
||||
}, [autoPopulate, autoPopulateLookup, history.location.search]),
|
||||
{
|
||||
|
||||
@ -7,6 +7,7 @@ import { ProjectsAPI } from 'api';
|
||||
import { Project } from 'types';
|
||||
import useAutoPopulateLookup from 'hooks/useAutoPopulateLookup';
|
||||
import useRequest from 'hooks/useRequest';
|
||||
import { getSearchableKeys } from 'components/PaginatedTable';
|
||||
import { getQSConfig, parseQueryString } from 'util/qs';
|
||||
import OptionsList from '../OptionsList';
|
||||
import Popover from '../Popover';
|
||||
@ -56,9 +57,7 @@ function ProjectLookup({
|
||||
relatedSearchableKeys: (
|
||||
actionsResponse?.data?.related_search_fields || []
|
||||
).map((val) => val.slice(0, -8)),
|
||||
searchableKeys: Object.keys(
|
||||
actionsResponse.data.actions?.GET || {}
|
||||
).filter((key) => actionsResponse.data.actions?.GET[key].filterable),
|
||||
searchableKeys: getSearchableKeys(actionsResponse.data.actions?.GET),
|
||||
canEdit:
|
||||
Boolean(actionsResponse.data.actions.POST) || isOverrideDisabled,
|
||||
};
|
||||
|
||||
@ -9,7 +9,11 @@ import { NotificationTemplatesAPI } from 'api';
|
||||
import AlertModal from '../AlertModal';
|
||||
import ErrorDetail from '../ErrorDetail';
|
||||
import NotificationListItem from './NotificationListItem';
|
||||
import PaginatedTable, { HeaderRow, HeaderCell } from '../PaginatedTable';
|
||||
import PaginatedTable, {
|
||||
HeaderRow,
|
||||
HeaderCell,
|
||||
getSearchableKeys,
|
||||
} from '../PaginatedTable';
|
||||
|
||||
const QS_CONFIG = getQSConfig('notification', {
|
||||
page: 1,
|
||||
@ -89,9 +93,7 @@ function NotificationList({
|
||||
relatedSearchableKeys: (
|
||||
actionsResponse?.data?.related_search_fields || []
|
||||
).map((val) => val.slice(0, -8)),
|
||||
searchableKeys: Object.keys(
|
||||
actionsResponse.data.actions?.GET || {}
|
||||
).filter((key) => actionsResponse.data.actions?.GET[key].filterable),
|
||||
searchableKeys: getSearchableKeys(actionsResponse.data.actions?.GET),
|
||||
};
|
||||
|
||||
if (showApprovalsToggle) {
|
||||
|
||||
@ -7,7 +7,7 @@ import { t } from '@lingui/macro';
|
||||
import { useLocation, useHistory } from 'react-router-dom';
|
||||
|
||||
import { parseQueryString, updateQueryString } from 'util/qs';
|
||||
import { QSConfig, SearchColumns } from 'types';
|
||||
import { QSConfig, SearchColumns, SearchableKeys } from 'types';
|
||||
import ListHeader from '../ListHeader';
|
||||
import ContentEmpty from '../ContentEmpty';
|
||||
import ContentError from '../ContentError';
|
||||
@ -184,7 +184,7 @@ PaginatedTable.propTypes = {
|
||||
qsConfig: QSConfig.isRequired,
|
||||
renderRow: PropTypes.func.isRequired,
|
||||
toolbarSearchColumns: SearchColumns,
|
||||
toolbarSearchableKeys: PropTypes.arrayOf(PropTypes.string),
|
||||
toolbarSearchableKeys: SearchableKeys,
|
||||
toolbarRelatedSearchableKeys: PropTypes.arrayOf(PropTypes.string),
|
||||
showPageSizeOptions: PropTypes.bool,
|
||||
renderToolbar: PropTypes.func,
|
||||
|
||||
@ -0,0 +1,8 @@
|
||||
export default function getSearchableKeys(keys = {}) {
|
||||
return Object.keys(keys)
|
||||
.filter((key) => keys[key].filterable)
|
||||
.map((key) => ({
|
||||
key,
|
||||
type: keys[key].type,
|
||||
}));
|
||||
}
|
||||
@ -5,3 +5,4 @@ export { default as ActionItem } from './ActionItem';
|
||||
export { default as ToolbarDeleteButton } from './ToolbarDeleteButton';
|
||||
export { default as ToolbarAddButton } from './ToolbarAddButton';
|
||||
export { default as ToolbarSyncSourceButton } from './ToolbarSyncSourceButton';
|
||||
export { default as getSearchableKeys } from './getSearchableKeys';
|
||||
|
||||
@ -11,6 +11,7 @@ import PaginatedTable, {
|
||||
HeaderRow,
|
||||
HeaderCell,
|
||||
ToolbarAddButton,
|
||||
getSearchableKeys,
|
||||
} from '../PaginatedTable';
|
||||
import DeleteRoleConfirmationModal from './DeleteRoleConfirmationModal';
|
||||
import ResourceAccessListItem from './ResourceAccessListItem';
|
||||
@ -89,9 +90,7 @@ function ResourceAccessList({ apiModel, resource }) {
|
||||
relatedSearchableKeys: (
|
||||
actionsResponse?.data?.related_search_fields || []
|
||||
).map((val) => val.slice(0, -8)),
|
||||
searchableKeys: Object.keys(
|
||||
actionsResponse.data.actions?.GET || {}
|
||||
).filter((key) => actionsResponse.data.actions?.GET[key].filterable),
|
||||
searchableKeys: getSearchableKeys(actionsResponse.data.actions?.GET),
|
||||
organizationRoles: orgRoles,
|
||||
};
|
||||
}, [apiModel, location, resource]),
|
||||
|
||||
@ -14,6 +14,7 @@ import PaginatedTable, {
|
||||
HeaderCell,
|
||||
ToolbarAddButton,
|
||||
ToolbarDeleteButton,
|
||||
getSearchableKeys,
|
||||
} from '../../PaginatedTable';
|
||||
import DataListToolbar from '../../DataListToolbar';
|
||||
import ScheduleListItem from './ScheduleListItem';
|
||||
@ -61,9 +62,7 @@ function ScheduleList({
|
||||
relatedSearchableKeys: (
|
||||
scheduleActions?.data?.related_search_fields || []
|
||||
).map((val) => val.slice(0, -8)),
|
||||
searchableKeys: Object.keys(
|
||||
scheduleActions.data.actions?.GET || {}
|
||||
).filter((key) => scheduleActions.data.actions?.GET[key].filterable),
|
||||
searchableKeys: getSearchableKeys(scheduleActions.data.actions?.GET),
|
||||
};
|
||||
}, [location.search, loadSchedules, loadScheduleOptions]),
|
||||
{
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import 'styled-components/macro';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { string, func, bool, arrayOf } from 'prop-types';
|
||||
import { t } from '@lingui/macro';
|
||||
import {
|
||||
Button,
|
||||
@ -16,6 +16,9 @@ import { SearchIcon, QuestionCircleIcon } from '@patternfly/react-icons';
|
||||
import styled from 'styled-components';
|
||||
import { useConfig } from 'contexts/Config';
|
||||
import getDocsBaseUrl from 'util/getDocsBaseUrl';
|
||||
import { SearchableKeys } from 'types';
|
||||
import RelatedLookupTypeInput from './RelatedLookupTypeInput';
|
||||
import LookupTypeInput from './LookupTypeInput';
|
||||
|
||||
const AdvancedGroup = styled.div`
|
||||
display: flex;
|
||||
@ -42,31 +45,33 @@ function AdvancedSearch({
|
||||
// for now, I'm spreading set to get rid of duplicate keys...when they are grouped
|
||||
// we might want to revisit that.
|
||||
const allKeys = [
|
||||
...new Set([...(searchableKeys || []), ...(relatedSearchableKeys || [])]),
|
||||
...new Set([
|
||||
...(searchableKeys.map((k) => k.key) || []),
|
||||
...(relatedSearchableKeys || []),
|
||||
]),
|
||||
];
|
||||
|
||||
const [isPrefixDropdownOpen, setIsPrefixDropdownOpen] = useState(false);
|
||||
const [isLookupDropdownOpen, setIsLookupDropdownOpen] = useState(false);
|
||||
const [isKeyDropdownOpen, setIsKeyDropdownOpen] = useState(false);
|
||||
const [prefixSelection, setPrefixSelection] = useState(null);
|
||||
const [lookupSelection, setLookupSelection] = useState(null);
|
||||
const [keySelection, setKeySelection] = useState(null);
|
||||
const [searchValue, setSearchValue] = useState('');
|
||||
const [relatedSearchKeySelected, setRelatedSearchKeySelected] =
|
||||
useState(false);
|
||||
const config = useConfig();
|
||||
|
||||
const selectedKey = searchableKeys.find((k) => k.key === keySelection);
|
||||
const relatedSearchKeySelected =
|
||||
keySelection &&
|
||||
relatedSearchableKeys.indexOf(keySelection) > -1 &&
|
||||
!selectedKey;
|
||||
const lookupKeyType =
|
||||
keySelection && !relatedSearchKeySelected ? selectedKey?.type : null;
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
keySelection &&
|
||||
relatedSearchableKeys.indexOf(keySelection) > -1 &&
|
||||
searchableKeys.indexOf(keySelection) === -1
|
||||
) {
|
||||
if (relatedSearchKeySelected) {
|
||||
setLookupSelection('name__icontains');
|
||||
setRelatedSearchKeySelected(true);
|
||||
} else {
|
||||
setLookupSelection(null);
|
||||
setRelatedSearchKeySelected(false);
|
||||
}
|
||||
}, [keySelection]); // eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
@ -136,160 +141,6 @@ function AdvancedSearch({
|
||||
</Select>
|
||||
);
|
||||
|
||||
const renderRelatedLookupType = () => (
|
||||
<Select
|
||||
ouiaId="set-lookup-typeahead"
|
||||
aria-label={t`Related search type`}
|
||||
className="lookupSelect"
|
||||
variant={SelectVariant.typeahead}
|
||||
typeAheadAriaLabel={t`Related search type typeahead`}
|
||||
onToggle={setIsLookupDropdownOpen}
|
||||
onSelect={(event, selection) => setLookupSelection(selection)}
|
||||
selections={lookupSelection}
|
||||
isOpen={isLookupDropdownOpen}
|
||||
placeholderText={t`Related search type`}
|
||||
maxHeight={maxSelectHeight}
|
||||
noResultsFoundText={t`No results found`}
|
||||
>
|
||||
<SelectOption
|
||||
id="name-option-select"
|
||||
key="name__icontains"
|
||||
value="name__icontains"
|
||||
description={t`Fuzzy search on name field.`}
|
||||
/>
|
||||
<SelectOption
|
||||
id="id-option-select"
|
||||
key="id"
|
||||
value="id"
|
||||
description={t`Exact search on id field.`}
|
||||
/>
|
||||
{enableRelatedFuzzyFiltering && (
|
||||
<SelectOption
|
||||
id="search-option-select"
|
||||
key="search"
|
||||
value="search"
|
||||
description={t`Fuzzy search on id, name or description fields.`}
|
||||
/>
|
||||
)}
|
||||
</Select>
|
||||
);
|
||||
|
||||
const renderLookupType = () => (
|
||||
<Select
|
||||
ouiaId="set-lookup-typeahead"
|
||||
aria-label={t`Lookup select`}
|
||||
className="lookupSelect"
|
||||
variant={SelectVariant.typeahead}
|
||||
typeAheadAriaLabel={t`Lookup typeahead`}
|
||||
onToggle={setIsLookupDropdownOpen}
|
||||
onSelect={(event, selection) => setLookupSelection(selection)}
|
||||
onClear={() => setLookupSelection(null)}
|
||||
selections={lookupSelection}
|
||||
isOpen={isLookupDropdownOpen}
|
||||
placeholderText={t`Lookup type`}
|
||||
maxHeight={maxSelectHeight}
|
||||
noResultsFoundText={t`No results found`}
|
||||
>
|
||||
<SelectOption
|
||||
id="exact-option-select"
|
||||
key="exact"
|
||||
value="exact"
|
||||
description={t`Exact match (default lookup if not specified).`}
|
||||
/>
|
||||
<SelectOption
|
||||
id="iexact-option-select"
|
||||
key="iexact"
|
||||
value="iexact"
|
||||
description={t`Case-insensitive version of exact.`}
|
||||
/>
|
||||
|
||||
<SelectOption
|
||||
id="contains-option-select"
|
||||
key="contains"
|
||||
value="contains"
|
||||
description={t`Field contains value.`}
|
||||
/>
|
||||
<SelectOption
|
||||
id="icontains-option-select"
|
||||
key="icontains"
|
||||
value="icontains"
|
||||
description={t`Case-insensitive version of contains`}
|
||||
/>
|
||||
<SelectOption
|
||||
id="startswith-option-select"
|
||||
key="startswith"
|
||||
value="startswith"
|
||||
description={t`Field starts with value.`}
|
||||
/>
|
||||
<SelectOption
|
||||
id="istartswith-option-select"
|
||||
key="istartswith"
|
||||
value="istartswith"
|
||||
description={t`Case-insensitive version of startswith.`}
|
||||
/>
|
||||
<SelectOption
|
||||
id="endswith-option-select"
|
||||
key="endswith"
|
||||
value="endswith"
|
||||
description={t`Field ends with value.`}
|
||||
/>
|
||||
<SelectOption
|
||||
id="iendswith-option-select"
|
||||
key="iendswith"
|
||||
value="iendswith"
|
||||
description={t`Case-insensitive version of endswith.`}
|
||||
/>
|
||||
<SelectOption
|
||||
id="regex-option-select"
|
||||
key="regex"
|
||||
value="regex"
|
||||
description={t`Field matches the given regular expression.`}
|
||||
/>
|
||||
<SelectOption
|
||||
id="iregex-option-select"
|
||||
key="iregex"
|
||||
value="iregex"
|
||||
description={t`Case-insensitive version of regex.`}
|
||||
/>
|
||||
<SelectOption
|
||||
id="gt-option-select"
|
||||
key="gt"
|
||||
value="gt"
|
||||
description={t`Greater than comparison.`}
|
||||
/>
|
||||
<SelectOption
|
||||
id="gte-option-select"
|
||||
key="gte"
|
||||
value="gte"
|
||||
description={t`Greater than or equal to comparison.`}
|
||||
/>
|
||||
<SelectOption
|
||||
id="lt-option-select"
|
||||
key="lt"
|
||||
value="lt"
|
||||
description={t`Less than comparison.`}
|
||||
/>
|
||||
<SelectOption
|
||||
id="lte-option-select"
|
||||
key="lte"
|
||||
value="lte"
|
||||
description={t`Less than or equal to comparison.`}
|
||||
/>
|
||||
<SelectOption
|
||||
id="isnull-option-select"
|
||||
key="isnull"
|
||||
value="isnull"
|
||||
description={t`Check whether the given field or related object is null; expects a boolean value.`}
|
||||
/>
|
||||
<SelectOption
|
||||
id="in-option-select"
|
||||
key="in"
|
||||
value="in"
|
||||
description={t`Check whether the given field's value is present in the list provided; expects a comma-separated list of items.`}
|
||||
/>
|
||||
</Select>
|
||||
);
|
||||
|
||||
return (
|
||||
<AdvancedGroup>
|
||||
{lookupSelection === 'search' ? (
|
||||
@ -328,9 +179,21 @@ function AdvancedSearch({
|
||||
</SelectOption>
|
||||
))}
|
||||
</Select>
|
||||
{relatedSearchKeySelected
|
||||
? renderRelatedLookupType()
|
||||
: renderLookupType()}
|
||||
{relatedSearchKeySelected ? (
|
||||
<RelatedLookupTypeInput
|
||||
value={lookupSelection}
|
||||
setValue={setLookupSelection}
|
||||
maxSelectHeight={maxSelectHeight}
|
||||
enableFuzzyFiltering={enableRelatedFuzzyFiltering}
|
||||
/>
|
||||
) : (
|
||||
<LookupTypeInput
|
||||
value={lookupSelection}
|
||||
type={lookupKeyType}
|
||||
setValue={setLookupSelection}
|
||||
maxSelectHeight={maxSelectHeight}
|
||||
/>
|
||||
)}
|
||||
<InputGroup>
|
||||
<TextInput
|
||||
data-cy="advanced-search-text-input"
|
||||
@ -369,12 +232,12 @@ function AdvancedSearch({
|
||||
}
|
||||
|
||||
AdvancedSearch.propTypes = {
|
||||
onSearch: PropTypes.func.isRequired,
|
||||
searchableKeys: PropTypes.arrayOf(PropTypes.string),
|
||||
relatedSearchableKeys: PropTypes.arrayOf(PropTypes.string),
|
||||
maxSelectHeight: PropTypes.string,
|
||||
enableNegativeFiltering: PropTypes.bool,
|
||||
enableRelatedFuzzyFiltering: PropTypes.bool,
|
||||
onSearch: func.isRequired,
|
||||
searchableKeys: SearchableKeys,
|
||||
relatedSearchableKeys: arrayOf(string),
|
||||
maxSelectHeight: string,
|
||||
enableNegativeFiltering: bool,
|
||||
enableRelatedFuzzyFiltering: bool,
|
||||
};
|
||||
|
||||
AdvancedSearch.defaultProps = {
|
||||
|
||||
@ -10,22 +10,14 @@ describe('<AdvancedSearch />', () => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
test('initially renders without crashing', () => {
|
||||
wrapper = mountWithContexts(
|
||||
<AdvancedSearch
|
||||
onSearch={jest.fn}
|
||||
searchableKeys={[]}
|
||||
relatedSearchableKeys={[]}
|
||||
/>
|
||||
);
|
||||
expect(wrapper.length).toBe(1);
|
||||
});
|
||||
|
||||
test('Remove duplicates from searchableKeys/relatedSearchableKeys list', () => {
|
||||
wrapper = mountWithContexts(
|
||||
<AdvancedSearch
|
||||
onSearch={jest.fn}
|
||||
searchableKeys={['foo', 'bar']}
|
||||
searchableKeys={[
|
||||
{ key: 'foo', type: 'string' },
|
||||
{ key: 'bar', type: 'string' },
|
||||
]}
|
||||
relatedSearchableKeys={['bar', 'baz']}
|
||||
/>
|
||||
);
|
||||
@ -42,7 +34,10 @@ describe('<AdvancedSearch />', () => {
|
||||
wrapper = mountWithContexts(
|
||||
<AdvancedSearch
|
||||
onSearch={advancedSearchMock}
|
||||
searchableKeys={['foo', 'bar']}
|
||||
searchableKeys={[
|
||||
{ key: 'foo', type: 'string' },
|
||||
{ key: 'bar', type: 'string' },
|
||||
]}
|
||||
relatedSearchableKeys={['bar', 'baz']}
|
||||
/>
|
||||
);
|
||||
@ -155,7 +150,10 @@ describe('<AdvancedSearch />', () => {
|
||||
wrapper = mountWithContexts(
|
||||
<AdvancedSearch
|
||||
onSearch={advancedSearchMock}
|
||||
searchableKeys={['foo', 'bar']}
|
||||
searchableKeys={[
|
||||
{ key: 'foo', type: 'string' },
|
||||
{ key: 'bar', type: 'string' },
|
||||
]}
|
||||
relatedSearchableKeys={['bar', 'baz']}
|
||||
/>
|
||||
);
|
||||
@ -239,7 +237,7 @@ describe('<AdvancedSearch />', () => {
|
||||
wrapper = mountWithContexts(
|
||||
<AdvancedSearch
|
||||
onSearch={advancedSearchMock}
|
||||
searchableKeys={['foo']}
|
||||
searchableKeys={[{ key: 'foo', type: 'string' }]}
|
||||
relatedSearchableKeys={[]}
|
||||
/>
|
||||
);
|
||||
@ -278,7 +276,7 @@ describe('<AdvancedSearch />', () => {
|
||||
wrapper = mountWithContexts(
|
||||
<AdvancedSearch
|
||||
onSearch={advancedSearchMock}
|
||||
searchableKeys={['foo']}
|
||||
searchableKeys={[{ key: 'foo', type: 'string' }]}
|
||||
relatedSearchableKeys={[]}
|
||||
/>
|
||||
);
|
||||
@ -375,7 +373,10 @@ describe('<AdvancedSearch />', () => {
|
||||
wrapper = mountWithContexts(
|
||||
<AdvancedSearch
|
||||
onSearch={jest.fn}
|
||||
searchableKeys={['foo', 'bar']}
|
||||
searchableKeys={[
|
||||
{ key: 'foo', type: 'string' },
|
||||
{ key: 'bar', type: 'string' },
|
||||
]}
|
||||
relatedSearchableKeys={['bar', 'baz']}
|
||||
enableNegativeFiltering={false}
|
||||
/>
|
||||
@ -399,7 +400,10 @@ describe('<AdvancedSearch />', () => {
|
||||
wrapper = mountWithContexts(
|
||||
<AdvancedSearch
|
||||
onSearch={jest.fn}
|
||||
searchableKeys={['foo', 'bar']}
|
||||
searchableKeys={[
|
||||
{ key: 'foo', type: 'string' },
|
||||
{ key: 'bar', type: 'string' },
|
||||
]}
|
||||
relatedSearchableKeys={['bar', 'baz']}
|
||||
enableRelatedFuzzyFiltering={false}
|
||||
/>
|
||||
|
||||
157
awx/ui/src/components/Search/LookupTypeInput.js
Normal file
157
awx/ui/src/components/Search/LookupTypeInput.js
Normal file
@ -0,0 +1,157 @@
|
||||
import React, { useState } from 'react';
|
||||
import { string, oneOfType, arrayOf, func } from 'prop-types';
|
||||
import { t } from '@lingui/macro';
|
||||
import { Select, SelectOption, SelectVariant } from '@patternfly/react-core';
|
||||
|
||||
function Option({ show, ...props }) {
|
||||
if (!show) {
|
||||
return null;
|
||||
}
|
||||
return <SelectOption {...props} />;
|
||||
}
|
||||
Option.defaultProps = {
|
||||
show: true,
|
||||
};
|
||||
|
||||
function LookupTypeInput({ value, type, setValue, maxSelectHeight }) {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<Select
|
||||
ouiaId="set-lookup-typeahead"
|
||||
aria-label={t`Lookup select`}
|
||||
className="lookupSelect"
|
||||
variant={SelectVariant.typeahead}
|
||||
typeAheadAriaLabel={t`Lookup typeahead`}
|
||||
onToggle={setIsOpen}
|
||||
onSelect={(event, selection) => setValue(selection)}
|
||||
onClear={() => setValue(null)}
|
||||
selections={value}
|
||||
isOpen={isOpen}
|
||||
placeholderText={t`Lookup type`}
|
||||
maxHeight={maxSelectHeight}
|
||||
noResultsFoundText={t`No results found`}
|
||||
>
|
||||
<Option
|
||||
id="exact-option-select"
|
||||
key="exact"
|
||||
value="exact"
|
||||
description={t`Exact match (default lookup if not specified).`}
|
||||
/>
|
||||
<Option
|
||||
id="iexact-option-select"
|
||||
key="iexact"
|
||||
value="iexact"
|
||||
description={t`Case-insensitive version of exact.`}
|
||||
show={type === 'string'}
|
||||
/>
|
||||
<Option
|
||||
id="contains-option-select"
|
||||
key="contains"
|
||||
value="contains"
|
||||
description={t`Field contains value.`}
|
||||
show={type === 'string'}
|
||||
/>
|
||||
<Option
|
||||
id="icontains-option-select"
|
||||
key="icontains"
|
||||
value="icontains"
|
||||
description={t`Case-insensitive version of contains`}
|
||||
show={type === 'string'}
|
||||
/>
|
||||
<Option
|
||||
id="startswith-option-select"
|
||||
key="startswith"
|
||||
value="startswith"
|
||||
description={t`Field starts with value.`}
|
||||
show={type !== 'datetime'}
|
||||
/>
|
||||
<Option
|
||||
id="istartswith-option-select"
|
||||
key="istartswith"
|
||||
value="istartswith"
|
||||
description={t`Case-insensitive version of startswith.`}
|
||||
show={type !== 'datetime'}
|
||||
/>
|
||||
<Option
|
||||
id="endswith-option-select"
|
||||
key="endswith"
|
||||
value="endswith"
|
||||
description={t`Field ends with value.`}
|
||||
show={type !== 'datetime'}
|
||||
/>
|
||||
<Option
|
||||
id="iendswith-option-select"
|
||||
key="iendswith"
|
||||
value="iendswith"
|
||||
description={t`Case-insensitive version of endswith.`}
|
||||
show={type !== 'datetime'}
|
||||
/>
|
||||
<Option
|
||||
id="regex-option-select"
|
||||
key="regex"
|
||||
value="regex"
|
||||
description={t`Field matches the given regular expression.`}
|
||||
/>
|
||||
<Option
|
||||
id="iregex-option-select"
|
||||
key="iregex"
|
||||
value="iregex"
|
||||
description={t`Case-insensitive version of regex.`}
|
||||
/>
|
||||
<Option
|
||||
id="gt-option-select"
|
||||
key="gt"
|
||||
value="gt"
|
||||
description={t`Greater than comparison.`}
|
||||
show={type !== 'json'}
|
||||
/>
|
||||
<Option
|
||||
id="gte-option-select"
|
||||
key="gte"
|
||||
value="gte"
|
||||
description={t`Greater than or equal to comparison.`}
|
||||
show={type !== 'json'}
|
||||
/>
|
||||
<Option
|
||||
id="lt-option-select"
|
||||
key="lt"
|
||||
value="lt"
|
||||
description={t`Less than comparison.`}
|
||||
show={type !== 'json'}
|
||||
/>
|
||||
<Option
|
||||
id="lte-option-select"
|
||||
key="lte"
|
||||
value="lte"
|
||||
description={t`Less than or equal to comparison.`}
|
||||
show={type !== 'json'}
|
||||
/>
|
||||
<Option
|
||||
id="isnull-option-select"
|
||||
key="isnull"
|
||||
value="isnull"
|
||||
description={t`Check whether the given field or related object is null; expects a boolean value.`}
|
||||
/>
|
||||
<Option
|
||||
id="in-option-select"
|
||||
key="in"
|
||||
value="in"
|
||||
description={t`Check whether the given field's value is present in the list provided; expects a comma-separated list of items.`}
|
||||
/>
|
||||
</Select>
|
||||
);
|
||||
}
|
||||
LookupTypeInput.propTypes = {
|
||||
type: string,
|
||||
value: oneOfType([string, arrayOf(string)]),
|
||||
setValue: func.isRequired,
|
||||
maxSelectHeight: string,
|
||||
};
|
||||
LookupTypeInput.defaultProps = {
|
||||
type: 'string',
|
||||
value: '',
|
||||
maxSelectHeight: '300px',
|
||||
};
|
||||
|
||||
export default LookupTypeInput;
|
||||
52
awx/ui/src/components/Search/RelatedLookupTypeInput.js
Normal file
52
awx/ui/src/components/Search/RelatedLookupTypeInput.js
Normal file
@ -0,0 +1,52 @@
|
||||
import React, { useState } from 'react';
|
||||
import { t } from '@lingui/macro';
|
||||
import { Select, SelectOption, SelectVariant } from '@patternfly/react-core';
|
||||
|
||||
function RelatedLookupTypeInput({
|
||||
value,
|
||||
setValue,
|
||||
maxSelectHeight,
|
||||
enableFuzzyFiltering,
|
||||
}) {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<Select
|
||||
ouiaId="set-lookup-typeahead"
|
||||
aria-label={t`Related search type`}
|
||||
className="lookupSelect"
|
||||
variant={SelectVariant.typeahead}
|
||||
typeAheadAriaLabel={t`Related search type typeahead`}
|
||||
onToggle={setIsOpen}
|
||||
onSelect={(event, selection) => setValue(selection)}
|
||||
selections={value}
|
||||
isOpen={isOpen}
|
||||
placeholderText={t`Related search type`}
|
||||
maxHeight={maxSelectHeight}
|
||||
noResultsFoundText={t`No results found`}
|
||||
>
|
||||
<SelectOption
|
||||
id="name-option-select"
|
||||
key="name__icontains"
|
||||
value="name__icontains"
|
||||
description={t`Fuzzy search on name field.`}
|
||||
/>
|
||||
<SelectOption
|
||||
id="id-option-select"
|
||||
key="id"
|
||||
value="id"
|
||||
description={t`Exact search on id field.`}
|
||||
/>
|
||||
{enableFuzzyFiltering && (
|
||||
<SelectOption
|
||||
id="search-option-select"
|
||||
key="search"
|
||||
value="search"
|
||||
description={t`Fuzzy search on id, name or description fields.`}
|
||||
/>
|
||||
)}
|
||||
</Select>
|
||||
);
|
||||
}
|
||||
|
||||
export default RelatedLookupTypeInput;
|
||||
@ -19,7 +19,7 @@ import {
|
||||
import { SearchIcon } from '@patternfly/react-icons';
|
||||
import styled from 'styled-components';
|
||||
import { parseQueryString } from 'util/qs';
|
||||
import { QSConfig, SearchColumns } from 'types';
|
||||
import { QSConfig, SearchColumns, SearchableKeys } from 'types';
|
||||
import AdvancedSearch from './AdvancedSearch';
|
||||
import getChipsByKey from './getChipsByKey';
|
||||
|
||||
@ -276,6 +276,7 @@ Search.propTypes = {
|
||||
maxSelectHeight: PropTypes.string,
|
||||
enableNegativeFiltering: PropTypes.bool,
|
||||
enableRelatedFuzzyFiltering: PropTypes.bool,
|
||||
searchableKeys: SearchableKeys,
|
||||
};
|
||||
|
||||
Search.defaultProps = {
|
||||
@ -285,6 +286,7 @@ Search.defaultProps = {
|
||||
maxSelectHeight: '300px',
|
||||
enableNegativeFiltering: true,
|
||||
enableRelatedFuzzyFiltering: true,
|
||||
searchableKeys: [],
|
||||
};
|
||||
|
||||
export default Search;
|
||||
|
||||
@ -20,6 +20,7 @@ import PaginatedTable, {
|
||||
HeaderRow,
|
||||
HeaderCell,
|
||||
ToolbarDeleteButton,
|
||||
getSearchableKeys,
|
||||
} from '../PaginatedTable';
|
||||
import AddDropDownButton from '../AddDropDownButton';
|
||||
import TemplateListItem from './TemplateListItem';
|
||||
@ -69,9 +70,7 @@ function TemplateList({ defaultParams }) {
|
||||
relatedSearchableKeys: (
|
||||
responses[3]?.data?.related_search_fields || []
|
||||
).map((val) => val.slice(0, -8)),
|
||||
searchableKeys: Object.keys(
|
||||
responses[3].data.actions?.GET || {}
|
||||
).filter((key) => responses[3].data.actions?.GET[key].filterable),
|
||||
searchableKeys: getSearchableKeys(responses[3].data.actions?.GET),
|
||||
};
|
||||
}, [location]), // eslint-disable-line react-hooks/exhaustive-deps
|
||||
{
|
||||
|
||||
@ -17,6 +17,7 @@ import DatalistToolbar from 'components/DataListToolbar';
|
||||
import PaginatedTable, {
|
||||
HeaderRow,
|
||||
HeaderCell,
|
||||
getSearchableKeys,
|
||||
} from 'components/PaginatedTable';
|
||||
import useRequest from 'hooks/useRequest';
|
||||
import { getQSConfig, parseQueryString, updateQueryString } from 'util/qs';
|
||||
@ -72,9 +73,7 @@ function ActivityStream() {
|
||||
relatedSearchableKeys: (
|
||||
actionsResponse?.data?.related_search_fields || []
|
||||
).map((val) => val.slice(0, -8)),
|
||||
searchableKeys: Object.keys(
|
||||
actionsResponse.data.actions?.GET || {}
|
||||
).filter((key) => actionsResponse.data.actions?.GET[key].filterable),
|
||||
searchableKeys: getSearchableKeys(actionsResponse.data.actions?.GET),
|
||||
};
|
||||
},
|
||||
[location] // eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
@ -6,6 +6,7 @@ import PaginatedTable, {
|
||||
HeaderCell,
|
||||
HeaderRow,
|
||||
ToolbarDeleteButton,
|
||||
getSearchableKeys,
|
||||
} from 'components/PaginatedTable';
|
||||
import { getQSConfig, parseQueryString } from 'util/qs';
|
||||
import { TokensAPI, ApplicationsAPI } from 'api';
|
||||
@ -57,9 +58,7 @@ function ApplicationTokenList() {
|
||||
relatedSearchableKeys: (
|
||||
actionsResponse?.data?.related_search_fields || []
|
||||
).map((val) => val.slice(0, -8)),
|
||||
searchableKeys: Object.keys(
|
||||
actionsResponse.data.actions?.GET || {}
|
||||
).filter((key) => actionsResponse.data.actions?.GET[key].filterable),
|
||||
searchableKeys: getSearchableKeys(actionsResponse.data.actions?.GET),
|
||||
};
|
||||
}, [id, location.search]),
|
||||
{ tokens: [], itemCount: 0, relatedSearchableKeys: [], searchableKeys: [] }
|
||||
|
||||
@ -16,6 +16,7 @@ import PaginatedTable, {
|
||||
HeaderCell,
|
||||
ToolbarDeleteButton,
|
||||
ToolbarAddButton,
|
||||
getSearchableKeys,
|
||||
} from 'components/PaginatedTable';
|
||||
import useSelected from 'hooks/useSelected';
|
||||
|
||||
@ -57,9 +58,7 @@ function ApplicationsList() {
|
||||
relatedSearchableKeys: (
|
||||
actionsResponse?.data?.related_search_fields || []
|
||||
).map((val) => val.slice(0, -8)),
|
||||
searchableKeys: Object.keys(
|
||||
actionsResponse.data.actions?.GET || {}
|
||||
).filter((key) => actionsResponse.data.actions?.GET[key].filterable),
|
||||
searchableKeys: getSearchableKeys(actionsResponse.data.actions?.GET),
|
||||
};
|
||||
}, [location]),
|
||||
{
|
||||
|
||||
@ -12,6 +12,7 @@ import PaginatedTable, {
|
||||
HeaderCell,
|
||||
ToolbarAddButton,
|
||||
ToolbarDeleteButton,
|
||||
getSearchableKeys,
|
||||
} from 'components/PaginatedTable';
|
||||
import useRequest, { useDeleteItems } from 'hooks/useRequest';
|
||||
import { getQSConfig, parseQueryString } from 'util/qs';
|
||||
@ -44,9 +45,7 @@ function CredentialList() {
|
||||
CredentialsAPI.read(params),
|
||||
CredentialsAPI.readOptions(),
|
||||
]);
|
||||
const searchKeys = Object.keys(
|
||||
credActions.data.actions?.GET || {}
|
||||
).filter((key) => credActions.data.actions?.GET[key].filterable);
|
||||
const searchKeys = getSearchableKeys(credActions.data.actions?.GET);
|
||||
const item = searchKeys.indexOf('type');
|
||||
if (item) {
|
||||
searchKeys[item] = 'credential_type__kind';
|
||||
|
||||
@ -12,6 +12,7 @@ import useRequest from 'hooks/useRequest';
|
||||
import PaginatedTable, {
|
||||
HeaderCell,
|
||||
HeaderRow,
|
||||
getSearchableKeys,
|
||||
} from 'components/PaginatedTable';
|
||||
|
||||
const QS_CONFIG = getQSConfig('credential', {
|
||||
@ -44,9 +45,7 @@ function CredentialsStep() {
|
||||
relatedSearchableKeys: (
|
||||
actionsResponse?.data?.related_search_fields || []
|
||||
).map((val) => val.slice(0, -8)),
|
||||
searchableKeys: Object.keys(
|
||||
actionsResponse.data.actions?.GET || {}
|
||||
).filter((key) => actionsResponse.data.actions?.GET[key].filterable),
|
||||
searchableKeys: getSearchableKeys(actionsResponse.data.actions?.GET),
|
||||
};
|
||||
}, [history.location.search]),
|
||||
{ credentials: [], count: 0, relatedSearchableKeys: [], searchableKeys: [] }
|
||||
|
||||
@ -13,6 +13,7 @@ import PaginatedTable, {
|
||||
HeaderCell,
|
||||
ToolbarDeleteButton,
|
||||
ToolbarAddButton,
|
||||
getSearchableKeys,
|
||||
} from 'components/PaginatedTable';
|
||||
import ErrorDetail from 'components/ErrorDetail';
|
||||
import AlertModal from 'components/AlertModal';
|
||||
@ -57,9 +58,7 @@ function CredentialTypeList() {
|
||||
relatedSearchableKeys: (
|
||||
responseActions?.data?.related_search_fields || []
|
||||
).map((val) => val.slice(0, -8)),
|
||||
searchableKeys: Object.keys(
|
||||
responseActions.data.actions?.GET || {}
|
||||
).filter((key) => responseActions.data.actions?.GET[key].filterable),
|
||||
searchableKeys: getSearchableKeys(responseActions.data.actions?.GET),
|
||||
};
|
||||
}, [location]),
|
||||
{
|
||||
|
||||
@ -12,6 +12,7 @@ import PaginatedTable, {
|
||||
HeaderCell,
|
||||
ToolbarDeleteButton,
|
||||
ToolbarAddButton,
|
||||
getSearchableKeys,
|
||||
} from 'components/PaginatedTable';
|
||||
import ErrorDetail from 'components/ErrorDetail';
|
||||
import AlertModal from 'components/AlertModal';
|
||||
@ -56,9 +57,7 @@ function ExecutionEnvironmentList() {
|
||||
relatedSearchableKeys: (
|
||||
responseActions?.data?.related_search_fields || []
|
||||
).map((val) => val.slice(0, -8)),
|
||||
searchableKeys: Object.keys(
|
||||
responseActions.data.actions?.GET || {}
|
||||
).filter((key) => responseActions.data.actions?.GET[key].filterable),
|
||||
searchableKeys: getSearchableKeys(responseActions.data.actions?.GET),
|
||||
};
|
||||
}, [location]),
|
||||
{
|
||||
|
||||
@ -11,6 +11,7 @@ import DatalistToolbar from 'components/DataListToolbar';
|
||||
import PaginatedTable, {
|
||||
HeaderCell,
|
||||
HeaderRow,
|
||||
getSearchableKeys,
|
||||
} from 'components/PaginatedTable';
|
||||
|
||||
import ExecutionEnvironmentTemplateListItem from './ExecutionEnvironmentTemplateListItem';
|
||||
@ -56,9 +57,7 @@ function ExecutionEnvironmentTemplateList({ executionEnvironment }) {
|
||||
relatedSearchableKeys: (
|
||||
responseActions?.data?.related_search_fields || []
|
||||
).map((val) => val.slice(0, -8)),
|
||||
searchableKeys: Object.keys(
|
||||
responseActions.data.actions?.GET || {}
|
||||
).filter((key) => responseActions.data.actions?.GET[key].filterable),
|
||||
searchableKeys: getSearchableKeys(responseActions.data.actions?.GET),
|
||||
};
|
||||
}, [location, id]),
|
||||
{
|
||||
|
||||
@ -15,6 +15,7 @@ import PaginatedTable, {
|
||||
HeaderCell,
|
||||
HeaderRow,
|
||||
ToolbarAddButton,
|
||||
getSearchableKeys,
|
||||
} from 'components/PaginatedTable';
|
||||
import AssociateModal from 'components/AssociateModal';
|
||||
import DisassociateButton from 'components/DisassociateButton';
|
||||
@ -66,9 +67,7 @@ function HostGroupsList({ host }) {
|
||||
relatedSearchableKeys: (
|
||||
actionsResponse?.data?.related_search_fields || []
|
||||
).map((val) => val.slice(0, -8)),
|
||||
searchableKeys: Object.keys(
|
||||
actionsResponse.data.actions?.GET || {}
|
||||
).filter((key) => actionsResponse.data.actions?.GET[key].filterable),
|
||||
searchableKeys: getSearchableKeys(actionsResponse.data.actions?.GET),
|
||||
};
|
||||
}, [hostId, search]),
|
||||
{
|
||||
|
||||
@ -11,6 +11,7 @@ import PaginatedTable, {
|
||||
HeaderCell,
|
||||
ToolbarAddButton,
|
||||
ToolbarDeleteButton,
|
||||
getSearchableKeys,
|
||||
} from 'components/PaginatedTable';
|
||||
import useRequest, { useDeleteItems } from 'hooks/useRequest';
|
||||
import useSelected from 'hooks/useSelected';
|
||||
@ -68,9 +69,7 @@ function HostList() {
|
||||
relatedSearchableKeys: (
|
||||
results[1]?.data?.related_search_fields || []
|
||||
).map((val) => val.slice(0, -8)),
|
||||
searchableKeys: Object.keys(results[1].data.actions?.GET || {}).filter(
|
||||
(key) => results[1].data.actions?.GET[key].filterable
|
||||
),
|
||||
searchableKeys: getSearchableKeys(results[1].data.actions?.GET),
|
||||
};
|
||||
}, [location]),
|
||||
{
|
||||
|
||||
@ -13,6 +13,7 @@ import PaginatedTable, {
|
||||
HeaderCell,
|
||||
ToolbarAddButton,
|
||||
ToolbarDeleteButton,
|
||||
getSearchableKeys,
|
||||
} from 'components/PaginatedTable';
|
||||
import ErrorDetail from 'components/ErrorDetail';
|
||||
import AlertModal from 'components/AlertModal';
|
||||
@ -107,9 +108,7 @@ function InstanceGroupList({
|
||||
relatedSearchableKeys: (
|
||||
responseActions?.data?.related_search_fields || []
|
||||
).map((val) => val.slice(0, -8)),
|
||||
searchableKeys: Object.keys(
|
||||
responseActions.data.actions?.GET || {}
|
||||
).filter((key) => responseActions.data.actions?.GET[key].filterable),
|
||||
searchableKeys: getSearchableKeys(responseActions.data.actions?.GET),
|
||||
};
|
||||
}, [location]),
|
||||
{
|
||||
|
||||
@ -9,6 +9,7 @@ import PaginatedTable, {
|
||||
HeaderRow,
|
||||
HeaderCell,
|
||||
ToolbarAddButton,
|
||||
getSearchableKeys,
|
||||
} from 'components/PaginatedTable';
|
||||
import DisassociateButton from 'components/DisassociateButton';
|
||||
import AssociateModal from 'components/AssociateModal';
|
||||
@ -61,9 +62,7 @@ function InstanceList() {
|
||||
relatedSearchableKeys: (
|
||||
responseActions?.data?.related_search_fields || []
|
||||
).map((val) => val.slice(0, -8)),
|
||||
searchableKeys: Object.keys(
|
||||
responseActions.data.actions?.GET || {}
|
||||
).filter((key) => responseActions.data.actions?.GET[key].filterable),
|
||||
searchableKeys: getSearchableKeys(responseActions.data.actions?.GET),
|
||||
};
|
||||
}, [location.search, instanceGroupId]),
|
||||
{
|
||||
|
||||
@ -17,6 +17,7 @@ import ErrorDetail from 'components/ErrorDetail';
|
||||
import PaginatedTable, {
|
||||
HeaderCell,
|
||||
HeaderRow,
|
||||
getSearchableKeys,
|
||||
} from 'components/PaginatedTable';
|
||||
import AssociateModal from 'components/AssociateModal';
|
||||
import DisassociateButton from 'components/DisassociateButton';
|
||||
@ -67,9 +68,7 @@ function InventoryGroupHostList() {
|
||||
relatedSearchableKeys: (
|
||||
actionsResponse?.data?.related_search_fields || []
|
||||
).map((val) => val.slice(0, -8)),
|
||||
searchableKeys: Object.keys(
|
||||
actionsResponse.data.actions?.GET || {}
|
||||
).filter((key) => actionsResponse.data.actions?.GET[key].filterable),
|
||||
searchableKeys: getSearchableKeys(actionsResponse.data.actions?.GET),
|
||||
};
|
||||
}, [groupId, inventoryId, location.search]),
|
||||
{
|
||||
|
||||
@ -11,6 +11,7 @@ import PaginatedTable, {
|
||||
HeaderRow,
|
||||
HeaderCell,
|
||||
ToolbarAddButton,
|
||||
getSearchableKeys,
|
||||
} from 'components/PaginatedTable';
|
||||
import AdHocCommands from 'components/AdHocCommands/AdHocCommands';
|
||||
import InventoryGroupItem from './InventoryGroupItem';
|
||||
@ -62,9 +63,7 @@ function InventoryGroupsList() {
|
||||
relatedSearchableKeys: (
|
||||
groupOptions?.data?.related_search_fields || []
|
||||
).map((val) => val.slice(0, -8)),
|
||||
searchableKeys: Object.keys(
|
||||
groupOptions.data.actions?.GET || {}
|
||||
).filter((key) => groupOptions.data.actions?.GET[key].filterable),
|
||||
searchableKeys: getSearchableKeys(groupOptions.data.actions?.GET),
|
||||
};
|
||||
}, [inventoryId, location]),
|
||||
{
|
||||
|
||||
@ -16,6 +16,7 @@ import PaginatedTable, {
|
||||
HeaderRow,
|
||||
HeaderCell,
|
||||
ToolbarAddButton,
|
||||
getSearchableKeys,
|
||||
} from 'components/PaginatedTable';
|
||||
import AssociateModal from 'components/AssociateModal';
|
||||
import DisassociateButton from 'components/DisassociateButton';
|
||||
@ -72,9 +73,7 @@ function InventoryHostGroupsList() {
|
||||
relatedSearchableKeys: (
|
||||
hostGroupOptions?.data?.related_search_fields || []
|
||||
).map((val) => val.slice(0, -8)),
|
||||
searchableKeys: Object.keys(
|
||||
hostGroupOptions.data.actions?.GET || {}
|
||||
).filter((key) => hostGroupOptions.data.actions?.GET[key].filterable),
|
||||
searchableKeys: getSearchableKeys(hostGroupOptions.data.actions?.GET),
|
||||
};
|
||||
}, [hostId, search]), // eslint-disable-line react-hooks/exhaustive-deps
|
||||
{
|
||||
|
||||
@ -12,6 +12,7 @@ import PaginatedTable, {
|
||||
HeaderCell,
|
||||
ToolbarAddButton,
|
||||
ToolbarDeleteButton,
|
||||
getSearchableKeys,
|
||||
} from 'components/PaginatedTable';
|
||||
import useSelected from 'hooks/useSelected';
|
||||
import AdHocCommands from 'components/AdHocCommands/AdHocCommands';
|
||||
@ -59,9 +60,7 @@ function InventoryHostList() {
|
||||
relatedSearchableKeys: (
|
||||
hostOptions?.data?.related_search_fields || []
|
||||
).map((val) => val.slice(0, -8)),
|
||||
searchableKeys: Object.keys(hostOptions.data.actions?.GET || {}).filter(
|
||||
(key) => hostOptions.data.actions?.GET[key].filterable
|
||||
),
|
||||
searchableKeys: getSearchableKeys(hostOptions.data.actions?.GET),
|
||||
};
|
||||
}, [id, search]),
|
||||
{
|
||||
|
||||
@ -12,6 +12,7 @@ import PaginatedTable, {
|
||||
HeaderRow,
|
||||
HeaderCell,
|
||||
ToolbarDeleteButton,
|
||||
getSearchableKeys,
|
||||
} from 'components/PaginatedTable';
|
||||
import { getQSConfig, parseQueryString } from 'util/qs';
|
||||
import AddDropDownButton from 'components/AddDropDownButton';
|
||||
@ -54,9 +55,7 @@ function InventoryList() {
|
||||
relatedSearchableKeys: (
|
||||
actionsResponse?.data?.related_search_fields || []
|
||||
).map((val) => val.slice(0, -8)),
|
||||
searchableKeys: Object.keys(
|
||||
actionsResponse.data.actions?.GET || {}
|
||||
).filter((key) => actionsResponse.data.actions?.GET[key].filterable),
|
||||
searchableKeys: getSearchableKeys(actionsResponse.data.actions?.GET),
|
||||
};
|
||||
}, [location]),
|
||||
{
|
||||
|
||||
@ -13,6 +13,7 @@ import DataListToolbar from 'components/DataListToolbar';
|
||||
import PaginatedTable, {
|
||||
HeaderCell,
|
||||
HeaderRow,
|
||||
getSearchableKeys,
|
||||
} from 'components/PaginatedTable';
|
||||
import AddDropDownButton from 'components/AddDropDownButton';
|
||||
import AdHocCommands from 'components/AdHocCommands/AdHocCommands';
|
||||
@ -65,9 +66,7 @@ function InventoryRelatedGroupList() {
|
||||
relatedSearchableKeys: (actions?.data?.related_search_fields || []).map(
|
||||
(val) => val.slice(0, -8)
|
||||
),
|
||||
searchableKeys: Object.keys(actions.data.actions?.GET || {}).filter(
|
||||
(key) => actions.data.actions?.GET[key].filterable
|
||||
),
|
||||
searchableKeys: getSearchableKeys(actions.data.actions?.GET),
|
||||
canAdd:
|
||||
actions.data.actions &&
|
||||
Object.prototype.hasOwnProperty.call(actions.data.actions, 'POST'),
|
||||
|
||||
@ -15,6 +15,7 @@ import { InventorySourcesAPI } from 'api';
|
||||
import ContentError from 'components/ContentError';
|
||||
import ContentLoading from 'components/ContentLoading';
|
||||
import RoutedTabs from 'components/RoutedTabs';
|
||||
import { getSearchableKeys } from 'components/PaginatedTable';
|
||||
import useRequest from 'hooks/useRequest';
|
||||
import { getJobModel } from 'util/jobs';
|
||||
import JobDetail from './JobDetail';
|
||||
@ -83,9 +84,7 @@ function Job({ setBreadcrumb }) {
|
||||
eventRelatedSearchableKeys: (
|
||||
eventOptions?.related_search_fields || []
|
||||
).map((val) => val.slice(0, -8)),
|
||||
eventSearchableKeys: Object.keys(
|
||||
eventOptions?.actions?.GET || {}
|
||||
).filter((key) => eventOptions?.actions?.GET[key].filterable),
|
||||
eventSearchableKeys: getSearchableKeys(eventOptions?.actions?.GET),
|
||||
};
|
||||
}, [id, type, setBreadcrumb]),
|
||||
{
|
||||
|
||||
@ -11,6 +11,7 @@ import ErrorDetail from 'components/ErrorDetail';
|
||||
import PaginatedTable, {
|
||||
HeaderRow,
|
||||
HeaderCell,
|
||||
getSearchableKeys,
|
||||
} from 'components/PaginatedTable';
|
||||
import { useConfig } from 'contexts/Config';
|
||||
import { parseQueryString, getQSConfig } from 'util/qs';
|
||||
@ -25,9 +26,7 @@ const QS_CONFIG = getQSConfig('system_job_templates', {
|
||||
|
||||
const buildSearchKeys = (options) => {
|
||||
const actions = options?.data?.actions?.GET || {};
|
||||
const searchableKeys = Object.keys(actions).filter(
|
||||
(key) => actions[key].filterable
|
||||
);
|
||||
const searchableKeys = getSearchableKeys(actions);
|
||||
const relatedSearchableKeys = options?.data?.related_search_fields || [];
|
||||
|
||||
return { searchableKeys, relatedSearchableKeys };
|
||||
|
||||
@ -15,6 +15,7 @@ import PaginatedTable, {
|
||||
HeaderCell,
|
||||
ToolbarAddButton,
|
||||
ToolbarDeleteButton,
|
||||
getSearchableKeys,
|
||||
} from 'components/PaginatedTable';
|
||||
import AlertModal from 'components/AlertModal';
|
||||
import ErrorDetail from 'components/ErrorDetail';
|
||||
@ -62,9 +63,7 @@ function NotificationTemplatesList() {
|
||||
relatedSearchableKeys: (
|
||||
actionsResponse.data?.related_search_fields || []
|
||||
).map((val) => val.slice(0, -8)),
|
||||
searchableKeys: Object.keys(
|
||||
actionsResponse.data.actions?.GET || {}
|
||||
).filter((key) => actionsResponse.data.actions?.GET[key].filterable),
|
||||
searchableKeys: getSearchableKeys(actionsResponse.data.actions?.GET),
|
||||
};
|
||||
}, [location]),
|
||||
{
|
||||
|
||||
@ -5,6 +5,7 @@ import { mountWithContexts } from '../../../../testUtils/enzymeHelpers';
|
||||
import NotificationTemplateListItem from './NotificationTemplateListItem';
|
||||
|
||||
jest.mock('../../../api/models/NotificationTemplates');
|
||||
jest.mock('../../../api/models/Notifications');
|
||||
|
||||
const template = {
|
||||
id: 3,
|
||||
|
||||
@ -10,6 +10,7 @@ import useRequest from 'hooks/useRequest';
|
||||
import PaginatedTable, {
|
||||
HeaderRow,
|
||||
HeaderCell,
|
||||
getSearchableKeys,
|
||||
} from 'components/PaginatedTable';
|
||||
import DatalistToolbar from 'components/DataListToolbar';
|
||||
|
||||
@ -51,9 +52,7 @@ function OrganizationExecEnvList({ organization }) {
|
||||
relatedSearchableKeys: (
|
||||
responseActions?.data?.related_search_fields || []
|
||||
).map((val) => val.slice(0, -8)),
|
||||
searchableKeys: Object.keys(
|
||||
responseActions.data.actions?.GET || {}
|
||||
).filter((key) => responseActions.data.actions?.GET[key].filterable),
|
||||
searchableKeys: getSearchableKeys(responseActions.data.actions?.GET),
|
||||
};
|
||||
}, [location, id]),
|
||||
{
|
||||
|
||||
@ -13,6 +13,7 @@ import PaginatedTable, {
|
||||
HeaderCell,
|
||||
ToolbarAddButton,
|
||||
ToolbarDeleteButton,
|
||||
getSearchableKeys,
|
||||
} from 'components/PaginatedTable';
|
||||
import { getQSConfig, parseQueryString } from 'util/qs';
|
||||
import useSelected from 'hooks/useSelected';
|
||||
@ -56,9 +57,7 @@ function OrganizationsList() {
|
||||
relatedSearchableKeys: (
|
||||
orgActions?.data?.related_search_fields || []
|
||||
).map((val) => val.slice(0, -8)),
|
||||
searchableKeys: Object.keys(orgActions.data.actions?.GET || {}).filter(
|
||||
(key) => orgActions.data.actions?.GET[key].filterable
|
||||
),
|
||||
searchableKeys: getSearchableKeys(orgActions.data.actions?.GET),
|
||||
};
|
||||
}, [location]),
|
||||
{
|
||||
|
||||
@ -7,6 +7,7 @@ import { OrganizationsAPI } from 'api';
|
||||
import PaginatedTable, {
|
||||
HeaderRow,
|
||||
HeaderCell,
|
||||
getSearchableKeys,
|
||||
} from 'components/PaginatedTable';
|
||||
import { getQSConfig, parseQueryString } from 'util/qs';
|
||||
import useRequest from 'hooks/useRequest';
|
||||
@ -39,9 +40,7 @@ function OrganizationTeamList({ id }) {
|
||||
relatedSearchableKeys: (
|
||||
actionsResponse?.data?.related_search_fields || []
|
||||
).map((val) => val.slice(0, -8)),
|
||||
searchableKeys: Object.keys(
|
||||
actionsResponse.data.actions?.GET || {}
|
||||
).filter((key) => actionsResponse.data.actions?.GET[key].filterable),
|
||||
searchableKeys: getSearchableKeys(actionsResponse.data.actions?.GET),
|
||||
};
|
||||
}, [id, location]),
|
||||
{
|
||||
|
||||
@ -12,6 +12,7 @@ import PaginatedTable, {
|
||||
HeaderCell,
|
||||
ToolbarAddButton,
|
||||
ToolbarDeleteButton,
|
||||
getSearchableKeys,
|
||||
} from 'components/PaginatedTable';
|
||||
import { getQSConfig, parseQueryString } from 'util/qs';
|
||||
import useSelected from 'hooks/useSelected';
|
||||
@ -54,9 +55,7 @@ function ProjectJobTemplatesList() {
|
||||
relatedSearchableKeys: (
|
||||
actionsResponse?.data?.related_search_fields || []
|
||||
).map((val) => val.slice(0, -8)),
|
||||
searchableKeys: Object.keys(
|
||||
actionsResponse.data.actions?.GET || {}
|
||||
).filter((key) => actionsResponse.data.actions?.GET[key].filterable),
|
||||
searchableKeys: getSearchableKeys(actionsResponse.data.actions?.GET),
|
||||
};
|
||||
}, [location, projectId]),
|
||||
{
|
||||
|
||||
@ -15,6 +15,7 @@ import PaginatedTable, {
|
||||
HeaderCell,
|
||||
ToolbarAddButton,
|
||||
ToolbarDeleteButton,
|
||||
getSearchableKeys,
|
||||
} from 'components/PaginatedTable';
|
||||
import useSelected from 'hooks/useSelected';
|
||||
import useExpanded from 'hooks/useExpanded';
|
||||
@ -75,9 +76,7 @@ function ProjectList() {
|
||||
relatedSearchableKeys: (
|
||||
actionsResponse?.data?.related_search_fields || []
|
||||
).map((val) => val.slice(0, -8)),
|
||||
searchableKeys: Object.keys(
|
||||
actionsResponse.data.actions?.GET || {}
|
||||
).filter((key) => actionsResponse.data.actions?.GET[key].filterable),
|
||||
searchableKeys: getSearchableKeys(actionsResponse.data.actions?.GET),
|
||||
};
|
||||
}, [location]),
|
||||
{
|
||||
|
||||
@ -14,6 +14,7 @@ import PaginatedTable, {
|
||||
HeaderCell,
|
||||
ToolbarAddButton,
|
||||
ToolbarDeleteButton,
|
||||
getSearchableKeys,
|
||||
} from 'components/PaginatedTable';
|
||||
import useSelected from 'hooks/useSelected';
|
||||
import { getQSConfig, parseQueryString } from 'util/qs';
|
||||
@ -55,9 +56,7 @@ function TeamList() {
|
||||
relatedSearchableKeys: (
|
||||
actionsResponse?.data?.related_search_fields || []
|
||||
).map((val) => val.slice(0, -8)),
|
||||
searchableKeys: Object.keys(
|
||||
actionsResponse.data.actions?.GET || {}
|
||||
).filter((key) => actionsResponse.data.actions?.GET[key].filterable),
|
||||
searchableKeys: getSearchableKeys(actionsResponse.data.actions?.GET),
|
||||
};
|
||||
}, [location]),
|
||||
{
|
||||
|
||||
@ -16,6 +16,7 @@ import PaginatedTable, {
|
||||
HeaderCell,
|
||||
HeaderRow,
|
||||
ToolbarAddButton,
|
||||
getSearchableKeys,
|
||||
} from 'components/PaginatedTable';
|
||||
import { getQSConfig, parseQueryString } from 'util/qs';
|
||||
import ErrorDetail from 'components/ErrorDetail';
|
||||
@ -69,9 +70,7 @@ function TeamRolesList({ me, team }) {
|
||||
relatedSearchableKeys: (
|
||||
actionsResponse?.data?.related_search_fields || []
|
||||
).map((val) => val.slice(0, -8)),
|
||||
searchableKeys: Object.keys(
|
||||
actionsResponse.data.actions?.GET || {}
|
||||
).filter((key) => actionsResponse.data.actions?.GET[key].filterable),
|
||||
searchableKeys: getSearchableKeys(actionsResponse.data.actions?.GET),
|
||||
};
|
||||
}, [me.id, team.id, team.organization, search]),
|
||||
{
|
||||
|
||||
@ -11,6 +11,7 @@ import CheckboxListItem from 'components/CheckboxListItem';
|
||||
import PaginatedTable, {
|
||||
HeaderCell,
|
||||
HeaderRow,
|
||||
getSearchableKeys,
|
||||
} from 'components/PaginatedTable';
|
||||
|
||||
const QS_CONFIG = getQSConfig('inventory-sources', {
|
||||
@ -40,9 +41,7 @@ function InventorySourcesList({ nodeResource, onUpdateNodeResource }) {
|
||||
relatedSearchableKeys: (
|
||||
actionsResponse?.data?.related_search_fields || []
|
||||
).map((val) => val.slice(0, -8)),
|
||||
searchableKeys: Object.keys(
|
||||
actionsResponse.data.actions?.GET || {}
|
||||
).filter((key) => actionsResponse.data.actions?.GET[key].filterable),
|
||||
searchableKeys: getSearchableKeys(actionsResponse.data.actions?.GET),
|
||||
};
|
||||
}, [location]),
|
||||
{
|
||||
|
||||
@ -11,6 +11,7 @@ import CheckboxListItem from 'components/CheckboxListItem';
|
||||
import PaginatedTable, {
|
||||
HeaderCell,
|
||||
HeaderRow,
|
||||
getSearchableKeys,
|
||||
} from 'components/PaginatedTable';
|
||||
|
||||
const QS_CONFIG = getQSConfig('job-templates', {
|
||||
@ -42,9 +43,7 @@ function JobTemplatesList({ nodeResource, onUpdateNodeResource }) {
|
||||
relatedSearchableKeys: (
|
||||
actionsResponse?.data?.related_search_fields || []
|
||||
).map((val) => val.slice(0, -8)),
|
||||
searchableKeys: Object.keys(
|
||||
actionsResponse.data.actions?.GET || {}
|
||||
).filter((key) => actionsResponse.data.actions?.GET[key].filterable),
|
||||
searchableKeys: getSearchableKeys(actionsResponse.data.actions?.GET),
|
||||
};
|
||||
}, [location]),
|
||||
{
|
||||
|
||||
@ -11,6 +11,7 @@ import CheckboxListItem from 'components/CheckboxListItem';
|
||||
import PaginatedTable, {
|
||||
HeaderCell,
|
||||
HeaderRow,
|
||||
getSearchableKeys,
|
||||
} from 'components/PaginatedTable';
|
||||
|
||||
const QS_CONFIG = getQSConfig('projects', {
|
||||
@ -40,9 +41,7 @@ function ProjectsList({ nodeResource, onUpdateNodeResource }) {
|
||||
relatedSearchableKeys: (
|
||||
actionsResponse?.data?.related_search_fields || []
|
||||
).map((val) => val.slice(0, -8)),
|
||||
searchableKeys: Object.keys(
|
||||
actionsResponse.data.actions?.GET || {}
|
||||
).filter((key) => actionsResponse.data.actions?.GET[key].filterable),
|
||||
searchableKeys: getSearchableKeys(actionsResponse.data.actions?.GET),
|
||||
};
|
||||
}, [location]),
|
||||
{
|
||||
|
||||
@ -10,6 +10,7 @@ import CheckboxListItem from 'components/CheckboxListItem';
|
||||
import PaginatedTable, {
|
||||
HeaderCell,
|
||||
HeaderRow,
|
||||
getSearchableKeys,
|
||||
} from 'components/PaginatedTable';
|
||||
|
||||
const QS_CONFIG = getQSConfig('system-job-templates', {
|
||||
@ -46,9 +47,7 @@ function SystemJobTemplatesList({ nodeResource, onUpdateNodeResource }) {
|
||||
relatedSearchableKeys: (
|
||||
actionsResponse?.data?.related_search_fields || []
|
||||
).map((val) => val.slice(0, -8)),
|
||||
searchableKeys: Object.keys(
|
||||
actionsResponse.data.actions?.GET || {}
|
||||
).filter((key) => actionsResponse.data.actions?.GET[key].filterable),
|
||||
searchableKeys: getSearchableKeys(actionsResponse.data.actions?.GET),
|
||||
};
|
||||
}, [location]),
|
||||
{
|
||||
|
||||
@ -11,6 +11,7 @@ import CheckboxListItem from 'components/CheckboxListItem';
|
||||
import PaginatedTable, {
|
||||
HeaderCell,
|
||||
HeaderRow,
|
||||
getSearchableKeys,
|
||||
} from 'components/PaginatedTable';
|
||||
|
||||
const QS_CONFIG = getQSConfig('workflow-job-templates', {
|
||||
@ -47,9 +48,7 @@ function WorkflowJobTemplatesList({ nodeResource, onUpdateNodeResource }) {
|
||||
relatedSearchableKeys: (
|
||||
actionsResponse?.data?.related_search_fields || []
|
||||
).map((val) => val.slice(0, -8)),
|
||||
searchableKeys: Object.keys(
|
||||
actionsResponse.data.actions?.GET || {}
|
||||
).filter((key) => actionsResponse.data.actions?.GET[key].filterable),
|
||||
searchableKeys: getSearchableKeys(actionsResponse.data.actions?.GET),
|
||||
};
|
||||
}, [location]),
|
||||
{
|
||||
|
||||
@ -12,6 +12,7 @@ import PaginatedTable, {
|
||||
HeaderCell,
|
||||
ToolbarAddButton,
|
||||
ToolbarDeleteButton,
|
||||
getSearchableKeys,
|
||||
} from 'components/PaginatedTable';
|
||||
import useRequest, { useDeleteItems } from 'hooks/useRequest';
|
||||
import useSelected from 'hooks/useSelected';
|
||||
@ -53,9 +54,7 @@ function UserList() {
|
||||
relatedSearchableKeys: (
|
||||
actionsResponse?.data?.related_search_fields || []
|
||||
).map((val) => val.slice(0, -8)),
|
||||
searchableKeys: Object.keys(
|
||||
actionsResponse.data.actions?.GET || {}
|
||||
).filter((key) => actionsResponse.data.actions?.GET[key].filterable),
|
||||
searchableKeys: getSearchableKeys(actionsResponse.data.actions?.GET),
|
||||
};
|
||||
}, [location]),
|
||||
{
|
||||
|
||||
@ -16,6 +16,7 @@ import PaginatedTable, {
|
||||
HeaderRow,
|
||||
HeaderCell,
|
||||
ToolbarAddButton,
|
||||
getSearchableKeys,
|
||||
} from 'components/PaginatedTable';
|
||||
import ErrorDetail from 'components/ErrorDetail';
|
||||
import AlertModal from 'components/AlertModal';
|
||||
@ -67,9 +68,7 @@ function UserRolesList({ user }) {
|
||||
relatedSearchableKeys: (
|
||||
actionsResponse?.data?.related_search_fields || []
|
||||
).map((val) => val.slice(0, -8)),
|
||||
searchableKeys: Object.keys(
|
||||
actionsResponse.data.actions?.GET || {}
|
||||
).filter((key) => actionsResponse.data.actions?.GET[key].filterable),
|
||||
searchableKeys: getSearchableKeys(actionsResponse.data.actions?.GET),
|
||||
};
|
||||
}, [user.id, search]),
|
||||
{
|
||||
|
||||
@ -6,6 +6,7 @@ import PaginatedTable, {
|
||||
HeaderRow,
|
||||
HeaderCell,
|
||||
ToolbarAddButton,
|
||||
getSearchableKeys,
|
||||
} from 'components/PaginatedTable';
|
||||
import DataListToolbar from 'components/DataListToolbar';
|
||||
import DisassociateButton from 'components/DisassociateButton';
|
||||
@ -66,9 +67,7 @@ function UserTeamList() {
|
||||
relatedSearchableKeys: (
|
||||
actionsResponse?.data?.related_search_fields || []
|
||||
).map((val) => val.slice(0, -8)),
|
||||
searchableKeys: Object.keys(
|
||||
actionsResponse.data.actions?.GET || {}
|
||||
).filter((key) => actionsResponse.data.actions?.GET[key].filterable),
|
||||
searchableKeys: getSearchableKeys(actionsResponse.data.actions?.GET),
|
||||
};
|
||||
}, [userId, location.search]),
|
||||
{
|
||||
|
||||
@ -8,6 +8,7 @@ import PaginatedTable, {
|
||||
HeaderCell,
|
||||
ToolbarAddButton,
|
||||
ToolbarDeleteButton,
|
||||
getSearchableKeys,
|
||||
} from 'components/PaginatedTable';
|
||||
import useSelected from 'hooks/useSelected';
|
||||
import useRequest, { useDeleteItems } from 'hooks/useRequest';
|
||||
@ -58,9 +59,7 @@ function UserTokenList() {
|
||||
relatedSearchableKeys: (
|
||||
actionsResponse?.data?.related_search_fields || []
|
||||
).map((val) => val.slice(0, -8)),
|
||||
searchableKeys: Object.keys(
|
||||
actionsResponse.data.actions?.GET || {}
|
||||
).filter((key) => actionsResponse.data.actions?.GET[key].filterable),
|
||||
searchableKeys: getSearchableKeys(actionsResponse.data.actions?.GET),
|
||||
};
|
||||
}, [id, location.search]),
|
||||
{ tokens: [], itemCount: 0, relatedSearchableKeys: [], searchableKeys: [] }
|
||||
|
||||
@ -7,6 +7,7 @@ import PaginatedTable, {
|
||||
HeaderRow,
|
||||
HeaderCell,
|
||||
ToolbarDeleteButton,
|
||||
getSearchableKeys,
|
||||
} from 'components/PaginatedTable';
|
||||
import AlertModal from 'components/AlertModal';
|
||||
import ErrorDetail from 'components/ErrorDetail';
|
||||
@ -50,9 +51,7 @@ function WorkflowApprovalsList() {
|
||||
relatedSearchableKeys: (
|
||||
actionsResponse?.data?.related_search_fields || []
|
||||
).map((val) => val.slice(0, -8)),
|
||||
searchableKeys: Object.keys(
|
||||
actionsResponse.data.actions?.GET || {}
|
||||
).filter((key) => actionsResponse.data.actions?.GET[key].filterable),
|
||||
searchableKeys: getSearchableKeys(actionsResponse.data.actions?.GET),
|
||||
};
|
||||
}, [location]),
|
||||
{
|
||||
|
||||
@ -421,3 +421,10 @@ export const ExecutionEnvironment = shape({
|
||||
description: string,
|
||||
pull: string,
|
||||
});
|
||||
|
||||
export const SearchableKeys = arrayOf(
|
||||
shape({
|
||||
key: string.isRequired,
|
||||
type: string.isRequired,
|
||||
})
|
||||
);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user