diff --git a/awx/ui/src/components/AdHocCommands/AdHocCredentialStep.js b/awx/ui/src/components/AdHocCommands/AdHocCredentialStep.js index 225630a106..1042f082c8 100644 --- a/awx/ui/src/components/AdHocCommands/AdHocCredentialStep.js +++ b/awx/ui/src/components/AdHocCommands/AdHocCredentialStep.js @@ -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]), { diff --git a/awx/ui/src/components/AdHocCommands/AdHocExecutionEnvironmentStep.js b/awx/ui/src/components/AdHocCommands/AdHocExecutionEnvironmentStep.js index 7cd6c7453b..3ced0adbe8 100644 --- a/awx/ui/src/components/AdHocCommands/AdHocExecutionEnvironmentStep.js +++ b/awx/ui/src/components/AdHocCommands/AdHocExecutionEnvironmentStep.js @@ -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]), { diff --git a/awx/ui/src/components/AddRole/SelectResourceStep.js b/awx/ui/src/components/AddRole/SelectResourceStep.js index f41f179554..b0e8897320 100644 --- a/awx/ui/src/components/AddRole/SelectResourceStep.js +++ b/awx/ui/src/components/AddRole/SelectResourceStep.js @@ -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]), { diff --git a/awx/ui/src/components/AssociateModal/AssociateModal.js b/awx/ui/src/components/AssociateModal/AssociateModal.js index c009b52356..5ccd6e59c8 100644 --- a/awx/ui/src/components/AssociateModal/AssociateModal.js +++ b/awx/ui/src/components/AssociateModal/AssociateModal.js @@ -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]), { diff --git a/awx/ui/src/components/DataListToolbar/DataListToolbar.js b/awx/ui/src/components/DataListToolbar/DataListToolbar.js index 2bcc0a1721..bd3eca8b04 100644 --- a/awx/ui/src/components/DataListToolbar/DataListToolbar.js +++ b/awx/ui/src/components/DataListToolbar/DataListToolbar.js @@ -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, diff --git a/awx/ui/src/components/JobList/JobList.js b/awx/ui/src/components/JobList/JobList.js index d312113339..f86c848cc6 100644 --- a/awx/ui/src/components/JobList/JobList.js +++ b/awx/ui/src/components/JobList/JobList.js @@ -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 diff --git a/awx/ui/src/components/LaunchPrompt/steps/CredentialsStep.js b/awx/ui/src/components/LaunchPrompt/steps/CredentialsStep.js index caf2827c7f..78694db0f5 100644 --- a/awx/ui/src/components/LaunchPrompt/steps/CredentialsStep.js +++ b/awx/ui/src/components/LaunchPrompt/steps/CredentialsStep.js @@ -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: [] } diff --git a/awx/ui/src/components/LaunchPrompt/steps/InventoryStep.js b/awx/ui/src/components/LaunchPrompt/steps/InventoryStep.js index 4c5b50679f..7ee3c5b834 100644 --- a/awx/ui/src/components/LaunchPrompt/steps/InventoryStep.js +++ b/awx/ui/src/components/LaunchPrompt/steps/InventoryStep.js @@ -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]), { diff --git a/awx/ui/src/components/ListHeader/ListHeader.js b/awx/ui/src/components/ListHeader/ListHeader.js index 965a6551ff..27055f1c45 100644 --- a/awx/ui/src/components/ListHeader/ListHeader.js +++ b/awx/ui/src/components/ListHeader/ListHeader.js @@ -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, diff --git a/awx/ui/src/components/Lookup/ApplicationLookup.js b/awx/ui/src/components/Lookup/ApplicationLookup.js index 51c4bc23a5..6d23625453 100644 --- a/awx/ui/src/components/Lookup/ApplicationLookup.js +++ b/awx/ui/src/components/Lookup/ApplicationLookup.js @@ -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]), { diff --git a/awx/ui/src/components/Lookup/CredentialLookup.js b/awx/ui/src/components/Lookup/CredentialLookup.js index ece127175f..e99507f56f 100644 --- a/awx/ui/src/components/Lookup/CredentialLookup.js +++ b/awx/ui/src/components/Lookup/CredentialLookup.js @@ -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 { diff --git a/awx/ui/src/components/Lookup/ExecutionEnvironmentLookup.js b/awx/ui/src/components/Lookup/ExecutionEnvironmentLookup.js index 8ab4ad0203..52a4aab23b 100644 --- a/awx/ui/src/components/Lookup/ExecutionEnvironmentLookup.js +++ b/awx/ui/src/components/Lookup/ExecutionEnvironmentLookup.js @@ -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, diff --git a/awx/ui/src/components/Lookup/HostFilterLookup.js b/awx/ui/src/components/Lookup/HostFilterLookup.js index 4b5d3a324e..3468d5d4b7 100644 --- a/awx/ui/src/components/Lookup/HostFilterLookup.js +++ b/awx/ui/src/components/Lookup/HostFilterLookup.js @@ -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] diff --git a/awx/ui/src/components/Lookup/InstanceGroupsLookup.js b/awx/ui/src/components/Lookup/InstanceGroupsLookup.js index d790626884..88647b68c5 100644 --- a/awx/ui/src/components/Lookup/InstanceGroupsLookup.js +++ b/awx/ui/src/components/Lookup/InstanceGroupsLookup.js @@ -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]), { diff --git a/awx/ui/src/components/Lookup/InventoryLookup.js b/awx/ui/src/components/Lookup/InventoryLookup.js index 71a92108f4..41991a0c1d 100644 --- a/awx/ui/src/components/Lookup/InventoryLookup.js +++ b/awx/ui/src/components/Lookup/InventoryLookup.js @@ -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, }; diff --git a/awx/ui/src/components/Lookup/MultiCredentialsLookup.js b/awx/ui/src/components/Lookup/MultiCredentialsLookup.js index 037455ea25..617b454288 100644 --- a/awx/ui/src/components/Lookup/MultiCredentialsLookup.js +++ b/awx/ui/src/components/Lookup/MultiCredentialsLookup.js @@ -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]), { diff --git a/awx/ui/src/components/Lookup/OrganizationLookup.js b/awx/ui/src/components/Lookup/OrganizationLookup.js index 88a50ee6bd..94844aadfe 100644 --- a/awx/ui/src/components/Lookup/OrganizationLookup.js +++ b/awx/ui/src/components/Lookup/OrganizationLookup.js @@ -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]), { diff --git a/awx/ui/src/components/Lookup/ProjectLookup.js b/awx/ui/src/components/Lookup/ProjectLookup.js index c443df047d..55749fcc25 100644 --- a/awx/ui/src/components/Lookup/ProjectLookup.js +++ b/awx/ui/src/components/Lookup/ProjectLookup.js @@ -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, }; diff --git a/awx/ui/src/components/NotificationList/NotificationList.js b/awx/ui/src/components/NotificationList/NotificationList.js index 6d3a05f682..3b4171ec90 100644 --- a/awx/ui/src/components/NotificationList/NotificationList.js +++ b/awx/ui/src/components/NotificationList/NotificationList.js @@ -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) { diff --git a/awx/ui/src/components/PaginatedTable/PaginatedTable.js b/awx/ui/src/components/PaginatedTable/PaginatedTable.js index c80b9d7ef8..37ac22c4a9 100644 --- a/awx/ui/src/components/PaginatedTable/PaginatedTable.js +++ b/awx/ui/src/components/PaginatedTable/PaginatedTable.js @@ -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, diff --git a/awx/ui/src/components/PaginatedTable/getSearchableKeys.js b/awx/ui/src/components/PaginatedTable/getSearchableKeys.js new file mode 100644 index 0000000000..ed9fe0fe0c --- /dev/null +++ b/awx/ui/src/components/PaginatedTable/getSearchableKeys.js @@ -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, + })); +} diff --git a/awx/ui/src/components/PaginatedTable/index.js b/awx/ui/src/components/PaginatedTable/index.js index e30c1e1711..67b83c87c2 100644 --- a/awx/ui/src/components/PaginatedTable/index.js +++ b/awx/ui/src/components/PaginatedTable/index.js @@ -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'; diff --git a/awx/ui/src/components/ResourceAccessList/ResourceAccessList.js b/awx/ui/src/components/ResourceAccessList/ResourceAccessList.js index c8b0254386..e4892e0371 100644 --- a/awx/ui/src/components/ResourceAccessList/ResourceAccessList.js +++ b/awx/ui/src/components/ResourceAccessList/ResourceAccessList.js @@ -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]), diff --git a/awx/ui/src/components/Schedule/ScheduleList/ScheduleList.js b/awx/ui/src/components/Schedule/ScheduleList/ScheduleList.js index 97b7e4ec3b..d74d9f64f7 100644 --- a/awx/ui/src/components/Schedule/ScheduleList/ScheduleList.js +++ b/awx/ui/src/components/Schedule/ScheduleList/ScheduleList.js @@ -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]), { diff --git a/awx/ui/src/components/Search/AdvancedSearch.js b/awx/ui/src/components/Search/AdvancedSearch.js index 16e3c0bce8..861c0cd33a 100644 --- a/awx/ui/src/components/Search/AdvancedSearch.js +++ b/awx/ui/src/components/Search/AdvancedSearch.js @@ -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({ ); - const renderRelatedLookupType = () => ( - - ); - - const renderLookupType = () => ( - - ); - return ( {lookupSelection === 'search' ? ( @@ -328,9 +179,21 @@ function AdvancedSearch({ ))} - {relatedSearchKeySelected - ? renderRelatedLookupType() - : renderLookupType()} + {relatedSearchKeySelected ? ( + + ) : ( + + )} ', () => { jest.clearAllMocks(); }); - test('initially renders without crashing', () => { - wrapper = mountWithContexts( - - ); - expect(wrapper.length).toBe(1); - }); - test('Remove duplicates from searchableKeys/relatedSearchableKeys list', () => { wrapper = mountWithContexts( ); @@ -42,7 +34,10 @@ describe('', () => { wrapper = mountWithContexts( ); @@ -155,7 +150,10 @@ describe('', () => { wrapper = mountWithContexts( ); @@ -239,7 +237,7 @@ describe('', () => { wrapper = mountWithContexts( ); @@ -278,7 +276,7 @@ describe('', () => { wrapper = mountWithContexts( ); @@ -375,7 +373,10 @@ describe('', () => { wrapper = mountWithContexts( @@ -399,7 +400,10 @@ describe('', () => { wrapper = mountWithContexts( diff --git a/awx/ui/src/components/Search/LookupTypeInput.js b/awx/ui/src/components/Search/LookupTypeInput.js new file mode 100644 index 0000000000..bb5eea7106 --- /dev/null +++ b/awx/ui/src/components/Search/LookupTypeInput.js @@ -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 ; +} +Option.defaultProps = { + show: true, +}; + +function LookupTypeInput({ value, type, setValue, maxSelectHeight }) { + const [isOpen, setIsOpen] = useState(false); + + return ( + + ); +} +LookupTypeInput.propTypes = { + type: string, + value: oneOfType([string, arrayOf(string)]), + setValue: func.isRequired, + maxSelectHeight: string, +}; +LookupTypeInput.defaultProps = { + type: 'string', + value: '', + maxSelectHeight: '300px', +}; + +export default LookupTypeInput; diff --git a/awx/ui/src/components/Search/RelatedLookupTypeInput.js b/awx/ui/src/components/Search/RelatedLookupTypeInput.js new file mode 100644 index 0000000000..effbc4199a --- /dev/null +++ b/awx/ui/src/components/Search/RelatedLookupTypeInput.js @@ -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 ( + + ); +} + +export default RelatedLookupTypeInput; diff --git a/awx/ui/src/components/Search/Search.js b/awx/ui/src/components/Search/Search.js index 3cd1fac4a4..e614314305 100644 --- a/awx/ui/src/components/Search/Search.js +++ b/awx/ui/src/components/Search/Search.js @@ -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; diff --git a/awx/ui/src/components/TemplateList/TemplateList.js b/awx/ui/src/components/TemplateList/TemplateList.js index b07b57048c..0b3144bb22 100644 --- a/awx/ui/src/components/TemplateList/TemplateList.js +++ b/awx/ui/src/components/TemplateList/TemplateList.js @@ -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 { diff --git a/awx/ui/src/screens/ActivityStream/ActivityStream.js b/awx/ui/src/screens/ActivityStream/ActivityStream.js index 88304a96c0..e11549f0b9 100644 --- a/awx/ui/src/screens/ActivityStream/ActivityStream.js +++ b/awx/ui/src/screens/ActivityStream/ActivityStream.js @@ -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 diff --git a/awx/ui/src/screens/Application/ApplicationTokens/ApplicationTokenList.js b/awx/ui/src/screens/Application/ApplicationTokens/ApplicationTokenList.js index e9fe845deb..84ff13fed0 100644 --- a/awx/ui/src/screens/Application/ApplicationTokens/ApplicationTokenList.js +++ b/awx/ui/src/screens/Application/ApplicationTokens/ApplicationTokenList.js @@ -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: [] } diff --git a/awx/ui/src/screens/Application/ApplicationsList/ApplicationsList.js b/awx/ui/src/screens/Application/ApplicationsList/ApplicationsList.js index 407a79a8f0..8737f1d340 100644 --- a/awx/ui/src/screens/Application/ApplicationsList/ApplicationsList.js +++ b/awx/ui/src/screens/Application/ApplicationsList/ApplicationsList.js @@ -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]), { diff --git a/awx/ui/src/screens/Credential/CredentialList/CredentialList.js b/awx/ui/src/screens/Credential/CredentialList/CredentialList.js index 81bbf27485..928a725cce 100644 --- a/awx/ui/src/screens/Credential/CredentialList/CredentialList.js +++ b/awx/ui/src/screens/Credential/CredentialList/CredentialList.js @@ -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'; diff --git a/awx/ui/src/screens/Credential/shared/CredentialPlugins/CredentialPluginPrompt/CredentialsStep.js b/awx/ui/src/screens/Credential/shared/CredentialPlugins/CredentialPluginPrompt/CredentialsStep.js index 620ea56cdd..636e7751b8 100644 --- a/awx/ui/src/screens/Credential/shared/CredentialPlugins/CredentialPluginPrompt/CredentialsStep.js +++ b/awx/ui/src/screens/Credential/shared/CredentialPlugins/CredentialPluginPrompt/CredentialsStep.js @@ -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: [] } diff --git a/awx/ui/src/screens/CredentialType/CredentialTypeList/CredentialTypeList.js b/awx/ui/src/screens/CredentialType/CredentialTypeList/CredentialTypeList.js index 2dd528200a..d70dddb852 100644 --- a/awx/ui/src/screens/CredentialType/CredentialTypeList/CredentialTypeList.js +++ b/awx/ui/src/screens/CredentialType/CredentialTypeList/CredentialTypeList.js @@ -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]), { diff --git a/awx/ui/src/screens/ExecutionEnvironment/ExecutionEnvironmentList/ExecutionEnvironmentList.js b/awx/ui/src/screens/ExecutionEnvironment/ExecutionEnvironmentList/ExecutionEnvironmentList.js index 7f6838d17d..547dd28507 100644 --- a/awx/ui/src/screens/ExecutionEnvironment/ExecutionEnvironmentList/ExecutionEnvironmentList.js +++ b/awx/ui/src/screens/ExecutionEnvironment/ExecutionEnvironmentList/ExecutionEnvironmentList.js @@ -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]), { diff --git a/awx/ui/src/screens/ExecutionEnvironment/ExecutionEnvironmentTemplate/ExecutionEnvironmentTemplateList.js b/awx/ui/src/screens/ExecutionEnvironment/ExecutionEnvironmentTemplate/ExecutionEnvironmentTemplateList.js index a9929d9319..0ecdcb9404 100644 --- a/awx/ui/src/screens/ExecutionEnvironment/ExecutionEnvironmentTemplate/ExecutionEnvironmentTemplateList.js +++ b/awx/ui/src/screens/ExecutionEnvironment/ExecutionEnvironmentTemplate/ExecutionEnvironmentTemplateList.js @@ -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]), { diff --git a/awx/ui/src/screens/Host/HostGroups/HostGroupsList.js b/awx/ui/src/screens/Host/HostGroups/HostGroupsList.js index 2aab687c76..26f214e941 100644 --- a/awx/ui/src/screens/Host/HostGroups/HostGroupsList.js +++ b/awx/ui/src/screens/Host/HostGroups/HostGroupsList.js @@ -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]), { diff --git a/awx/ui/src/screens/Host/HostList/HostList.js b/awx/ui/src/screens/Host/HostList/HostList.js index da270228ec..8e24d847d8 100644 --- a/awx/ui/src/screens/Host/HostList/HostList.js +++ b/awx/ui/src/screens/Host/HostList/HostList.js @@ -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]), { diff --git a/awx/ui/src/screens/InstanceGroup/InstanceGroupList/InstanceGroupList.js b/awx/ui/src/screens/InstanceGroup/InstanceGroupList/InstanceGroupList.js index a7549fd6d8..096d818014 100644 --- a/awx/ui/src/screens/InstanceGroup/InstanceGroupList/InstanceGroupList.js +++ b/awx/ui/src/screens/InstanceGroup/InstanceGroupList/InstanceGroupList.js @@ -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]), { diff --git a/awx/ui/src/screens/InstanceGroup/Instances/InstanceList.js b/awx/ui/src/screens/InstanceGroup/Instances/InstanceList.js index c8cf075436..d4c86af647 100644 --- a/awx/ui/src/screens/InstanceGroup/Instances/InstanceList.js +++ b/awx/ui/src/screens/InstanceGroup/Instances/InstanceList.js @@ -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]), { diff --git a/awx/ui/src/screens/Inventory/InventoryGroupHosts/InventoryGroupHostList.js b/awx/ui/src/screens/Inventory/InventoryGroupHosts/InventoryGroupHostList.js index 4365abaa79..1830c22a67 100644 --- a/awx/ui/src/screens/Inventory/InventoryGroupHosts/InventoryGroupHostList.js +++ b/awx/ui/src/screens/Inventory/InventoryGroupHosts/InventoryGroupHostList.js @@ -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]), { diff --git a/awx/ui/src/screens/Inventory/InventoryGroups/InventoryGroupsList.js b/awx/ui/src/screens/Inventory/InventoryGroups/InventoryGroupsList.js index 17309143b7..ed7a8c5359 100644 --- a/awx/ui/src/screens/Inventory/InventoryGroups/InventoryGroupsList.js +++ b/awx/ui/src/screens/Inventory/InventoryGroups/InventoryGroupsList.js @@ -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]), { diff --git a/awx/ui/src/screens/Inventory/InventoryHostGroups/InventoryHostGroupsList.js b/awx/ui/src/screens/Inventory/InventoryHostGroups/InventoryHostGroupsList.js index 925e607ccd..6eeb5618f5 100644 --- a/awx/ui/src/screens/Inventory/InventoryHostGroups/InventoryHostGroupsList.js +++ b/awx/ui/src/screens/Inventory/InventoryHostGroups/InventoryHostGroupsList.js @@ -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 { diff --git a/awx/ui/src/screens/Inventory/InventoryHosts/InventoryHostList.js b/awx/ui/src/screens/Inventory/InventoryHosts/InventoryHostList.js index edded93990..a04a196fd5 100644 --- a/awx/ui/src/screens/Inventory/InventoryHosts/InventoryHostList.js +++ b/awx/ui/src/screens/Inventory/InventoryHosts/InventoryHostList.js @@ -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]), { diff --git a/awx/ui/src/screens/Inventory/InventoryList/InventoryList.js b/awx/ui/src/screens/Inventory/InventoryList/InventoryList.js index 51b61cb914..b1c6bcd032 100644 --- a/awx/ui/src/screens/Inventory/InventoryList/InventoryList.js +++ b/awx/ui/src/screens/Inventory/InventoryList/InventoryList.js @@ -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]), { diff --git a/awx/ui/src/screens/Inventory/InventoryRelatedGroups/InventoryRelatedGroupList.js b/awx/ui/src/screens/Inventory/InventoryRelatedGroups/InventoryRelatedGroupList.js index c1c6cdfbe6..1fae0da610 100644 --- a/awx/ui/src/screens/Inventory/InventoryRelatedGroups/InventoryRelatedGroupList.js +++ b/awx/ui/src/screens/Inventory/InventoryRelatedGroups/InventoryRelatedGroupList.js @@ -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'), diff --git a/awx/ui/src/screens/Job/Job.js b/awx/ui/src/screens/Job/Job.js index e13a935669..ccc3bc3b97 100644 --- a/awx/ui/src/screens/Job/Job.js +++ b/awx/ui/src/screens/Job/Job.js @@ -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]), { diff --git a/awx/ui/src/screens/ManagementJob/ManagementJobList/ManagementJobList.js b/awx/ui/src/screens/ManagementJob/ManagementJobList/ManagementJobList.js index 3bb955d09d..b910a24729 100644 --- a/awx/ui/src/screens/ManagementJob/ManagementJobList/ManagementJobList.js +++ b/awx/ui/src/screens/ManagementJob/ManagementJobList/ManagementJobList.js @@ -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 }; diff --git a/awx/ui/src/screens/NotificationTemplate/NotificationTemplateList/NotificationTemplateList.js b/awx/ui/src/screens/NotificationTemplate/NotificationTemplateList/NotificationTemplateList.js index cfdc705157..81c3845e42 100644 --- a/awx/ui/src/screens/NotificationTemplate/NotificationTemplateList/NotificationTemplateList.js +++ b/awx/ui/src/screens/NotificationTemplate/NotificationTemplateList/NotificationTemplateList.js @@ -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]), { diff --git a/awx/ui/src/screens/NotificationTemplate/NotificationTemplateList/NotificationTemplateListItem.test.js b/awx/ui/src/screens/NotificationTemplate/NotificationTemplateList/NotificationTemplateListItem.test.js index 59d417763f..660d974d5f 100644 --- a/awx/ui/src/screens/NotificationTemplate/NotificationTemplateList/NotificationTemplateListItem.test.js +++ b/awx/ui/src/screens/NotificationTemplate/NotificationTemplateList/NotificationTemplateListItem.test.js @@ -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, diff --git a/awx/ui/src/screens/Organization/OrganizationExecEnvList/OrganizationExecEnvList.js b/awx/ui/src/screens/Organization/OrganizationExecEnvList/OrganizationExecEnvList.js index ef3c0f354f..a717f62767 100644 --- a/awx/ui/src/screens/Organization/OrganizationExecEnvList/OrganizationExecEnvList.js +++ b/awx/ui/src/screens/Organization/OrganizationExecEnvList/OrganizationExecEnvList.js @@ -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]), { diff --git a/awx/ui/src/screens/Organization/OrganizationList/OrganizationList.js b/awx/ui/src/screens/Organization/OrganizationList/OrganizationList.js index 01be552a4f..1f40abf0a0 100644 --- a/awx/ui/src/screens/Organization/OrganizationList/OrganizationList.js +++ b/awx/ui/src/screens/Organization/OrganizationList/OrganizationList.js @@ -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]), { diff --git a/awx/ui/src/screens/Organization/OrganizationTeams/OrganizationTeamList.js b/awx/ui/src/screens/Organization/OrganizationTeams/OrganizationTeamList.js index d7dc663102..92566f94b4 100644 --- a/awx/ui/src/screens/Organization/OrganizationTeams/OrganizationTeamList.js +++ b/awx/ui/src/screens/Organization/OrganizationTeams/OrganizationTeamList.js @@ -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]), { diff --git a/awx/ui/src/screens/Project/ProjectJobTemplatesList/ProjectJobTemplatesList.js b/awx/ui/src/screens/Project/ProjectJobTemplatesList/ProjectJobTemplatesList.js index f3c5cb2701..eb8d690d96 100644 --- a/awx/ui/src/screens/Project/ProjectJobTemplatesList/ProjectJobTemplatesList.js +++ b/awx/ui/src/screens/Project/ProjectJobTemplatesList/ProjectJobTemplatesList.js @@ -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]), { diff --git a/awx/ui/src/screens/Project/ProjectList/ProjectList.js b/awx/ui/src/screens/Project/ProjectList/ProjectList.js index 3ca3ec0d23..e71571f2c6 100644 --- a/awx/ui/src/screens/Project/ProjectList/ProjectList.js +++ b/awx/ui/src/screens/Project/ProjectList/ProjectList.js @@ -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]), { diff --git a/awx/ui/src/screens/Team/TeamList/TeamList.js b/awx/ui/src/screens/Team/TeamList/TeamList.js index de0ca9f94d..0c99de6b65 100644 --- a/awx/ui/src/screens/Team/TeamList/TeamList.js +++ b/awx/ui/src/screens/Team/TeamList/TeamList.js @@ -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]), { diff --git a/awx/ui/src/screens/Team/TeamRoles/TeamRolesList.js b/awx/ui/src/screens/Team/TeamRoles/TeamRolesList.js index 8ca522f203..2f66d12d6c 100644 --- a/awx/ui/src/screens/Team/TeamRoles/TeamRolesList.js +++ b/awx/ui/src/screens/Team/TeamRoles/TeamRolesList.js @@ -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]), { diff --git a/awx/ui/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeTypeStep/InventorySourcesList.js b/awx/ui/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeTypeStep/InventorySourcesList.js index 31468dd055..2fa0871a92 100644 --- a/awx/ui/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeTypeStep/InventorySourcesList.js +++ b/awx/ui/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeTypeStep/InventorySourcesList.js @@ -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]), { diff --git a/awx/ui/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeTypeStep/JobTemplatesList.js b/awx/ui/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeTypeStep/JobTemplatesList.js index 7ef820e547..4f94bdb398 100644 --- a/awx/ui/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeTypeStep/JobTemplatesList.js +++ b/awx/ui/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeTypeStep/JobTemplatesList.js @@ -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]), { diff --git a/awx/ui/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeTypeStep/ProjectsList.js b/awx/ui/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeTypeStep/ProjectsList.js index 8466327100..891986d88e 100644 --- a/awx/ui/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeTypeStep/ProjectsList.js +++ b/awx/ui/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeTypeStep/ProjectsList.js @@ -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]), { diff --git a/awx/ui/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeTypeStep/SystemJobTemplatesList.jsx b/awx/ui/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeTypeStep/SystemJobTemplatesList.jsx index f83614426d..d623cff0a1 100644 --- a/awx/ui/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeTypeStep/SystemJobTemplatesList.jsx +++ b/awx/ui/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeTypeStep/SystemJobTemplatesList.jsx @@ -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]), { diff --git a/awx/ui/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeTypeStep/WorkflowJobTemplatesList.js b/awx/ui/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeTypeStep/WorkflowJobTemplatesList.js index 5829688dd8..a8f15ef9fe 100644 --- a/awx/ui/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeTypeStep/WorkflowJobTemplatesList.js +++ b/awx/ui/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeTypeStep/WorkflowJobTemplatesList.js @@ -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]), { diff --git a/awx/ui/src/screens/User/UserList/UserList.js b/awx/ui/src/screens/User/UserList/UserList.js index b66a057813..1852c78e6d 100644 --- a/awx/ui/src/screens/User/UserList/UserList.js +++ b/awx/ui/src/screens/User/UserList/UserList.js @@ -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]), { diff --git a/awx/ui/src/screens/User/UserRoles/UserRolesList.js b/awx/ui/src/screens/User/UserRoles/UserRolesList.js index 59002effee..49f3a1784f 100644 --- a/awx/ui/src/screens/User/UserRoles/UserRolesList.js +++ b/awx/ui/src/screens/User/UserRoles/UserRolesList.js @@ -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]), { diff --git a/awx/ui/src/screens/User/UserTeams/UserTeamList.js b/awx/ui/src/screens/User/UserTeams/UserTeamList.js index 374ddbfe75..38773eb2b6 100644 --- a/awx/ui/src/screens/User/UserTeams/UserTeamList.js +++ b/awx/ui/src/screens/User/UserTeams/UserTeamList.js @@ -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]), { diff --git a/awx/ui/src/screens/User/UserTokenList/UserTokenList.js b/awx/ui/src/screens/User/UserTokenList/UserTokenList.js index 44bdd55442..14d659f020 100644 --- a/awx/ui/src/screens/User/UserTokenList/UserTokenList.js +++ b/awx/ui/src/screens/User/UserTokenList/UserTokenList.js @@ -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: [] } diff --git a/awx/ui/src/screens/WorkflowApproval/WorkflowApprovalList/WorkflowApprovalList.js b/awx/ui/src/screens/WorkflowApproval/WorkflowApprovalList/WorkflowApprovalList.js index 929d442aa4..7e44d3f7c8 100644 --- a/awx/ui/src/screens/WorkflowApproval/WorkflowApprovalList/WorkflowApprovalList.js +++ b/awx/ui/src/screens/WorkflowApproval/WorkflowApprovalList/WorkflowApprovalList.js @@ -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]), { diff --git a/awx/ui/src/types.js b/awx/ui/src/types.js index 3be7f55bc5..f0f95b1aa6 100644 --- a/awx/ui/src/types.js +++ b/awx/ui/src/types.js @@ -421,3 +421,10 @@ export const ExecutionEnvironment = shape({ description: string, pull: string, }); + +export const SearchableKeys = arrayOf( + shape({ + key: string.isRequired, + type: string.isRequired, + }) +);