mirror of
https://github.com/ansible/awx.git
synced 2026-05-15 05:17:36 -02:30
add searchable keys support for AssociateModal and SelectResourceStep lists
This commit is contained in:
@@ -11,8 +11,12 @@ import { TeamsAPI, UsersAPI } from '../../api';
|
|||||||
const readUsers = async queryParams =>
|
const readUsers = async queryParams =>
|
||||||
UsersAPI.read(Object.assign(queryParams, { is_superuser: false }));
|
UsersAPI.read(Object.assign(queryParams, { is_superuser: false }));
|
||||||
|
|
||||||
|
const readUsersOptions = async () => UsersAPI.readOptions();
|
||||||
|
|
||||||
const readTeams = async queryParams => TeamsAPI.read(queryParams);
|
const readTeams = async queryParams => TeamsAPI.read(queryParams);
|
||||||
|
|
||||||
|
const readTeamsOptions = async () => TeamsAPI.readOptions();
|
||||||
|
|
||||||
class AddResourceRole extends React.Component {
|
class AddResourceRole extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
@@ -259,6 +263,7 @@ class AddResourceRole extends React.Component {
|
|||||||
displayKey="username"
|
displayKey="username"
|
||||||
onRowClick={this.handleResourceCheckboxClick}
|
onRowClick={this.handleResourceCheckboxClick}
|
||||||
fetchItems={readUsers}
|
fetchItems={readUsers}
|
||||||
|
fetchOptions={readUsersOptions}
|
||||||
selectedLabel={i18n._(t`Selected`)}
|
selectedLabel={i18n._(t`Selected`)}
|
||||||
selectedResourceRows={selectedResourceRows}
|
selectedResourceRows={selectedResourceRows}
|
||||||
sortedColumnKey="username"
|
sortedColumnKey="username"
|
||||||
@@ -270,6 +275,7 @@ class AddResourceRole extends React.Component {
|
|||||||
sortColumns={teamSortColumns}
|
sortColumns={teamSortColumns}
|
||||||
onRowClick={this.handleResourceCheckboxClick}
|
onRowClick={this.handleResourceCheckboxClick}
|
||||||
fetchItems={readTeams}
|
fetchItems={readTeams}
|
||||||
|
fetchOptions={readTeamsOptions}
|
||||||
selectedLabel={i18n._(t`Selected`)}
|
selectedLabel={i18n._(t`Selected`)}
|
||||||
selectedResourceRows={selectedResourceRows}
|
selectedResourceRows={selectedResourceRows}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ function SelectResourceStep({
|
|||||||
selectedLabel,
|
selectedLabel,
|
||||||
selectedResourceRows,
|
selectedResourceRows,
|
||||||
fetchItems,
|
fetchItems,
|
||||||
|
fetchOptions,
|
||||||
i18n,
|
i18n,
|
||||||
}) {
|
}) {
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
@@ -37,7 +38,7 @@ function SelectResourceStep({
|
|||||||
isLoading,
|
isLoading,
|
||||||
error,
|
error,
|
||||||
request: readResourceList,
|
request: readResourceList,
|
||||||
result: { resources, itemCount },
|
result: { resources, itemCount, relatedSearchableKeys, searchableKeys },
|
||||||
} = useRequest(
|
} = useRequest(
|
||||||
useCallback(async () => {
|
useCallback(async () => {
|
||||||
const queryParams = parseQueryString(
|
const queryParams = parseQueryString(
|
||||||
@@ -45,14 +46,28 @@ function SelectResourceStep({
|
|||||||
location.search
|
location.search
|
||||||
);
|
);
|
||||||
|
|
||||||
const {
|
const [
|
||||||
data: { count, results },
|
{
|
||||||
} = await fetchItems(queryParams);
|
data: { count, results },
|
||||||
return { resources: results, itemCount: count };
|
},
|
||||||
}, [location, fetchItems, sortColumns]),
|
actionsResponse,
|
||||||
|
] = await Promise.all([fetchItems(queryParams), fetchOptions()]);
|
||||||
|
return {
|
||||||
|
resources: results,
|
||||||
|
itemCount: count,
|
||||||
|
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),
|
||||||
|
};
|
||||||
|
}, [location, fetchItems, fetchOptions, sortColumns]),
|
||||||
{
|
{
|
||||||
resources: [],
|
resources: [],
|
||||||
itemCount: 0,
|
itemCount: 0,
|
||||||
|
relatedSearchableKeys: [],
|
||||||
|
searchableKeys: [],
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -84,6 +99,8 @@ function SelectResourceStep({
|
|||||||
onRowClick={onRowClick}
|
onRowClick={onRowClick}
|
||||||
toolbarSearchColumns={searchColumns}
|
toolbarSearchColumns={searchColumns}
|
||||||
toolbarSortColumns={sortColumns}
|
toolbarSortColumns={sortColumns}
|
||||||
|
toolbarSearchableKeys={searchableKeys}
|
||||||
|
toolbarRelatedSearchableKeys={relatedSearchableKeys}
|
||||||
renderItem={item => (
|
renderItem={item => (
|
||||||
<CheckboxListItem
|
<CheckboxListItem
|
||||||
isSelected={selectedResourceRows.some(i => i.id === item.id)}
|
isSelected={selectedResourceRows.some(i => i.id === item.id)}
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ describe('<SelectResourceStep />', () => {
|
|||||||
displayKey="username"
|
displayKey="username"
|
||||||
onRowClick={() => {}}
|
onRowClick={() => {}}
|
||||||
fetchItems={() => {}}
|
fetchItems={() => {}}
|
||||||
|
fetchOptions={() => {}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -49,6 +50,15 @@ describe('<SelectResourceStep />', () => {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
const options = jest.fn().mockResolvedValue({
|
||||||
|
data: {
|
||||||
|
actions: {
|
||||||
|
GET: {},
|
||||||
|
POST: {},
|
||||||
|
},
|
||||||
|
related_search_fields: [],
|
||||||
|
},
|
||||||
|
});
|
||||||
let wrapper;
|
let wrapper;
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
wrapper = mountWithContexts(
|
wrapper = mountWithContexts(
|
||||||
@@ -58,6 +68,7 @@ describe('<SelectResourceStep />', () => {
|
|||||||
displayKey="username"
|
displayKey="username"
|
||||||
onRowClick={() => {}}
|
onRowClick={() => {}}
|
||||||
fetchItems={handleSearch}
|
fetchItems={handleSearch}
|
||||||
|
fetchOptions={options}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -78,6 +89,15 @@ describe('<SelectResourceStep />', () => {
|
|||||||
{ id: 2, username: 'bar', url: 'item/2' },
|
{ id: 2, username: 'bar', url: 'item/2' },
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
const options = jest.fn().mockResolvedValue({
|
||||||
|
data: {
|
||||||
|
actions: {
|
||||||
|
GET: {},
|
||||||
|
POST: {},
|
||||||
|
},
|
||||||
|
related_search_fields: [],
|
||||||
|
},
|
||||||
|
});
|
||||||
let wrapper;
|
let wrapper;
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
wrapper = mountWithContexts(
|
wrapper = mountWithContexts(
|
||||||
@@ -87,6 +107,7 @@ describe('<SelectResourceStep />', () => {
|
|||||||
displayKey="username"
|
displayKey="username"
|
||||||
onRowClick={handleRowClick}
|
onRowClick={handleRowClick}
|
||||||
fetchItems={() => ({ data })}
|
fetchItems={() => ({ data })}
|
||||||
|
fetchOptions={options}
|
||||||
selectedResourceRows={[]}
|
selectedResourceRows={[]}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ function AssociateModal({
|
|||||||
onClose,
|
onClose,
|
||||||
onAssociate,
|
onAssociate,
|
||||||
fetchRequest,
|
fetchRequest,
|
||||||
|
optionsRequest,
|
||||||
isModalOpen = false,
|
isModalOpen = false,
|
||||||
}) {
|
}) {
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
@@ -28,24 +29,35 @@ function AssociateModal({
|
|||||||
|
|
||||||
const {
|
const {
|
||||||
request: fetchItems,
|
request: fetchItems,
|
||||||
result: { items, itemCount },
|
result: { items, itemCount, relatedSearchableKeys, searchableKeys },
|
||||||
error: contentError,
|
error: contentError,
|
||||||
isLoading,
|
isLoading,
|
||||||
} = useRequest(
|
} = useRequest(
|
||||||
useCallback(async () => {
|
useCallback(async () => {
|
||||||
const params = parseQueryString(QS_CONFIG, history.location.search);
|
const params = parseQueryString(QS_CONFIG, history.location.search);
|
||||||
const {
|
const [
|
||||||
data: { count, results },
|
{
|
||||||
} = await fetchRequest(params);
|
data: { count, results },
|
||||||
|
},
|
||||||
|
actionsResponse,
|
||||||
|
] = await Promise.all([fetchRequest(params), optionsRequest()]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
items: results,
|
items: results,
|
||||||
itemCount: count,
|
itemCount: count,
|
||||||
|
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),
|
||||||
};
|
};
|
||||||
}, [fetchRequest, history.location.search]),
|
}, [fetchRequest, optionsRequest, history.location.search]),
|
||||||
{
|
{
|
||||||
items: [],
|
items: [],
|
||||||
itemCount: 0,
|
itemCount: 0,
|
||||||
|
relatedSearchableKeys: [],
|
||||||
|
searchableKeys: [],
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -132,6 +144,8 @@ function AssociateModal({
|
|||||||
key: 'name',
|
key: 'name',
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
|
searchableKeys={searchableKeys}
|
||||||
|
relatedSearchableKeys={relatedSearchableKeys}
|
||||||
/>
|
/>
|
||||||
</Modal>
|
</Modal>
|
||||||
</Fragment>
|
</Fragment>
|
||||||
|
|||||||
@@ -15,6 +15,15 @@ describe('<AssociateModal />', () => {
|
|||||||
const onClose = jest.fn();
|
const onClose = jest.fn();
|
||||||
const onAssociate = jest.fn().mockResolvedValue();
|
const onAssociate = jest.fn().mockResolvedValue();
|
||||||
const fetchRequest = jest.fn().mockReturnValue({ data: { ...mockHosts } });
|
const fetchRequest = jest.fn().mockReturnValue({ data: { ...mockHosts } });
|
||||||
|
const optionsRequest = jest.fn().mockResolvedValue({
|
||||||
|
data: {
|
||||||
|
actions: {
|
||||||
|
GET: {},
|
||||||
|
POST: {},
|
||||||
|
},
|
||||||
|
related_search_fields: [],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
@@ -23,6 +32,7 @@ describe('<AssociateModal />', () => {
|
|||||||
onClose={onClose}
|
onClose={onClose}
|
||||||
onAssociate={onAssociate}
|
onAssociate={onAssociate}
|
||||||
fetchRequest={fetchRequest}
|
fetchRequest={fetchRequest}
|
||||||
|
optionsRequest={optionsRequest}
|
||||||
isModalOpen
|
isModalOpen
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -96,6 +96,7 @@ function UserAndTeamAccessAdd({
|
|||||||
displayKey="name"
|
displayKey="name"
|
||||||
onRowClick={handleResourceSelect}
|
onRowClick={handleResourceSelect}
|
||||||
fetchItems={selectedResourceType.fetchItems}
|
fetchItems={selectedResourceType.fetchItems}
|
||||||
|
fetchOptions={selectedResourceType.fetchOptions}
|
||||||
selectedLabel={i18n._(t`Selected`)}
|
selectedLabel={i18n._(t`Selected`)}
|
||||||
selectedResourceRows={resourcesSelected}
|
selectedResourceRows={resourcesSelected}
|
||||||
sortedColumnKey="username"
|
sortedColumnKey="username"
|
||||||
|
|||||||
@@ -43,6 +43,15 @@ describe('<UserAndTeamAccessAdd/>', () => {
|
|||||||
count: 1,
|
count: 1,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
const options = {
|
||||||
|
data: {
|
||||||
|
actions: {
|
||||||
|
GET: {},
|
||||||
|
POST: {},
|
||||||
|
},
|
||||||
|
related_search_fields: [],
|
||||||
|
},
|
||||||
|
};
|
||||||
let wrapper;
|
let wrapper;
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
@@ -111,11 +120,13 @@ describe('<UserAndTeamAccessAdd/>', () => {
|
|||||||
|
|
||||||
test('should call api to associate role', async () => {
|
test('should call api to associate role', async () => {
|
||||||
JobTemplatesAPI.read.mockResolvedValue(resources);
|
JobTemplatesAPI.read.mockResolvedValue(resources);
|
||||||
|
JobTemplatesAPI.readOptions.mockResolvedValue(options);
|
||||||
UsersAPI.associateRole.mockResolvedValue({});
|
UsersAPI.associateRole.mockResolvedValue({});
|
||||||
|
|
||||||
await act(async () =>
|
await act(async () =>
|
||||||
wrapper.find('SelectableCard[label="Job templates"]').prop('onClick')({
|
wrapper.find('SelectableCard[label="Job templates"]').prop('onClick')({
|
||||||
fetchItems: JobTemplatesAPI.read,
|
fetchItems: JobTemplatesAPI.read,
|
||||||
|
fetchOptions: JobTemplatesAPI.readOptions,
|
||||||
label: 'Job template',
|
label: 'Job template',
|
||||||
selectedResource: 'jobTemplate',
|
selectedResource: 'jobTemplate',
|
||||||
searchColumns: [
|
searchColumns: [
|
||||||
@@ -169,6 +180,7 @@ describe('<UserAndTeamAccessAdd/>', () => {
|
|||||||
|
|
||||||
test('should throw error', async () => {
|
test('should throw error', async () => {
|
||||||
JobTemplatesAPI.read.mockResolvedValue(resources);
|
JobTemplatesAPI.read.mockResolvedValue(resources);
|
||||||
|
JobTemplatesAPI.readOptions.mockResolvedValue(options);
|
||||||
UsersAPI.associateRole.mockRejectedValue(
|
UsersAPI.associateRole.mockRejectedValue(
|
||||||
new Error({
|
new Error({
|
||||||
response: {
|
response: {
|
||||||
@@ -192,6 +204,7 @@ describe('<UserAndTeamAccessAdd/>', () => {
|
|||||||
await act(async () =>
|
await act(async () =>
|
||||||
wrapper.find('SelectableCard[label="Job templates"]').prop('onClick')({
|
wrapper.find('SelectableCard[label="Job templates"]').prop('onClick')({
|
||||||
fetchItems: JobTemplatesAPI.read,
|
fetchItems: JobTemplatesAPI.read,
|
||||||
|
fetchOptions: JobTemplatesAPI.readOptions,
|
||||||
label: 'Job template',
|
label: 'Job template',
|
||||||
selectedResource: 'jobTemplate',
|
selectedResource: 'jobTemplate',
|
||||||
searchColumns: [
|
searchColumns: [
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ export default function getResourceAccessConfig(i18n) {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
fetchItems: queryParams => JobTemplatesAPI.read(queryParams),
|
fetchItems: queryParams => JobTemplatesAPI.read(queryParams),
|
||||||
|
fetchOptions: () => JobTemplatesAPI.readOptions(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
selectedResource: 'workflowJobTemplate',
|
selectedResource: 'workflowJobTemplate',
|
||||||
@@ -69,6 +70,7 @@ export default function getResourceAccessConfig(i18n) {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
fetchItems: queryParams => WorkflowJobTemplatesAPI.read(queryParams),
|
fetchItems: queryParams => WorkflowJobTemplatesAPI.read(queryParams),
|
||||||
|
fetchOptions: () => WorkflowJobTemplatesAPI.readOptions(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
selectedResource: 'credential',
|
selectedResource: 'credential',
|
||||||
@@ -110,6 +112,7 @@ export default function getResourceAccessConfig(i18n) {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
fetchItems: queryParams => CredentialsAPI.read(queryParams),
|
fetchItems: queryParams => CredentialsAPI.read(queryParams),
|
||||||
|
fetchOptions: () => CredentialsAPI.readOptions(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
selectedResource: 'inventory',
|
selectedResource: 'inventory',
|
||||||
@@ -136,6 +139,7 @@ export default function getResourceAccessConfig(i18n) {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
fetchItems: queryParams => InventoriesAPI.read(queryParams),
|
fetchItems: queryParams => InventoriesAPI.read(queryParams),
|
||||||
|
fetchOptions: () => InventoriesAPI.readOptions(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
selectedResource: 'project',
|
selectedResource: 'project',
|
||||||
@@ -177,6 +181,7 @@ export default function getResourceAccessConfig(i18n) {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
fetchItems: queryParams => ProjectsAPI.read(queryParams),
|
fetchItems: queryParams => ProjectsAPI.read(queryParams),
|
||||||
|
fetchOptions: () => ProjectsAPI.readOptions(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
selectedResource: 'organization',
|
selectedResource: 'organization',
|
||||||
@@ -203,6 +208,7 @@ export default function getResourceAccessConfig(i18n) {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
fetchItems: queryParams => OrganizationsAPI.read(queryParams),
|
fetchItems: queryParams => OrganizationsAPI.read(queryParams),
|
||||||
|
fetchOptions: () => OrganizationsAPI.readOptions(),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -118,6 +118,11 @@ function HostGroupsList({ i18n, host }) {
|
|||||||
[invId, hostId]
|
[invId, hostId]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const fetchGroupsOptions = useCallback(
|
||||||
|
() => InventoriesAPI.readGroupsOptions(invId),
|
||||||
|
[invId]
|
||||||
|
);
|
||||||
|
|
||||||
const { request: handleAssociate, error: associateError } = useRequest(
|
const { request: handleAssociate, error: associateError } = useRequest(
|
||||||
useCallback(
|
useCallback(
|
||||||
async groupsToAssociate => {
|
async groupsToAssociate => {
|
||||||
@@ -224,6 +229,7 @@ function HostGroupsList({ i18n, host }) {
|
|||||||
<AssociateModal
|
<AssociateModal
|
||||||
header={i18n._(t`Groups`)}
|
header={i18n._(t`Groups`)}
|
||||||
fetchRequest={fetchGroupsToAssociate}
|
fetchRequest={fetchGroupsToAssociate}
|
||||||
|
optionsRequest={fetchGroupsOptions}
|
||||||
isModalOpen={isModalOpen}
|
isModalOpen={isModalOpen}
|
||||||
onAssociate={handleAssociate}
|
onAssociate={handleAssociate}
|
||||||
onClose={() => setIsModalOpen(false)}
|
onClose={() => setIsModalOpen(false)}
|
||||||
|
|||||||
@@ -207,6 +207,15 @@ describe('<HostGroupsList />', () => {
|
|||||||
results: [{ id: 123, name: 'foo', url: '/api/v2/groups/123/' }],
|
results: [{ id: 123, name: 'foo', url: '/api/v2/groups/123/' }],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
InventoriesAPI.readGroupsOptions.mockResolvedValue({
|
||||||
|
data: {
|
||||||
|
actions: {
|
||||||
|
GET: {},
|
||||||
|
POST: {},
|
||||||
|
},
|
||||||
|
related_search_fields: [],
|
||||||
|
},
|
||||||
|
});
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
wrapper.find('ToolbarAddButton').simulate('click');
|
wrapper.find('ToolbarAddButton').simulate('click');
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -111,6 +111,11 @@ function InventoryGroupHostList({ i18n }) {
|
|||||||
[groupId, inventoryId]
|
[groupId, inventoryId]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const fetchHostsOptions = useCallback(
|
||||||
|
() => InventoriesAPI.readHostsOptions(inventoryId),
|
||||||
|
[inventoryId]
|
||||||
|
);
|
||||||
|
|
||||||
const { request: handleAssociate, error: associateErr } = useRequest(
|
const { request: handleAssociate, error: associateErr } = useRequest(
|
||||||
useCallback(
|
useCallback(
|
||||||
async hostsToAssociate => {
|
async hostsToAssociate => {
|
||||||
@@ -227,6 +232,7 @@ function InventoryGroupHostList({ i18n }) {
|
|||||||
<AssociateModal
|
<AssociateModal
|
||||||
header={i18n._(t`Hosts`)}
|
header={i18n._(t`Hosts`)}
|
||||||
fetchRequest={fetchHostsToAssociate}
|
fetchRequest={fetchHostsToAssociate}
|
||||||
|
optionsRequest={fetchHostsOptions}
|
||||||
isModalOpen={isModalOpen}
|
isModalOpen={isModalOpen}
|
||||||
onAssociate={handleAssociate}
|
onAssociate={handleAssociate}
|
||||||
onClose={() => setIsModalOpen(false)}
|
onClose={() => setIsModalOpen(false)}
|
||||||
|
|||||||
@@ -116,6 +116,11 @@ function InventoryHostGroupsList({ i18n }) {
|
|||||||
[invId, hostId]
|
[invId, hostId]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const fetchGroupsOptions = useCallback(
|
||||||
|
() => InventoriesAPI.readGroupsOptions(invId),
|
||||||
|
[invId]
|
||||||
|
);
|
||||||
|
|
||||||
const { request: handleAssociate, error: associateError } = useRequest(
|
const { request: handleAssociate, error: associateError } = useRequest(
|
||||||
useCallback(
|
useCallback(
|
||||||
async groupsToAssociate => {
|
async groupsToAssociate => {
|
||||||
@@ -221,6 +226,7 @@ function InventoryHostGroupsList({ i18n }) {
|
|||||||
<AssociateModal
|
<AssociateModal
|
||||||
header={i18n._(t`Groups`)}
|
header={i18n._(t`Groups`)}
|
||||||
fetchRequest={fetchGroupsToAssociate}
|
fetchRequest={fetchGroupsToAssociate}
|
||||||
|
optionsRequest={fetchGroupsOptions}
|
||||||
isModalOpen={isModalOpen}
|
isModalOpen={isModalOpen}
|
||||||
onAssociate={handleAssociate}
|
onAssociate={handleAssociate}
|
||||||
onClose={() => setIsModalOpen(false)}
|
onClose={() => setIsModalOpen(false)}
|
||||||
|
|||||||
@@ -199,6 +199,15 @@ describe('<InventoryHostGroupsList />', () => {
|
|||||||
results: [{ id: 123, name: 'foo', url: '/api/v2/groups/123/' }],
|
results: [{ id: 123, name: 'foo', url: '/api/v2/groups/123/' }],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
InventoriesAPI.readGroupsOptions.mockResolvedValue({
|
||||||
|
data: {
|
||||||
|
actions: {
|
||||||
|
GET: {},
|
||||||
|
POST: {},
|
||||||
|
},
|
||||||
|
related_search_fields: [],
|
||||||
|
},
|
||||||
|
});
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
wrapper.find('ToolbarAddButton').simulate('click');
|
wrapper.find('ToolbarAddButton').simulate('click');
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user