update newly useRequested lists to get advanced searchableKeys

This commit is contained in:
John Mitchell
2020-08-13 15:30:00 -04:00
committed by John Mitchell
parent a659b9d994
commit aee2a81b27
26 changed files with 367 additions and 42 deletions

View File

@@ -6,6 +6,7 @@ class Credentials extends Base {
this.baseUrl = '/api/v2/credentials/'; this.baseUrl = '/api/v2/credentials/';
this.readAccessList = this.readAccessList.bind(this); this.readAccessList = this.readAccessList.bind(this);
this.readAccessOptions = this.readAccessOptions.bind(this);
this.readInputSources = this.readInputSources.bind(this); this.readInputSources = this.readInputSources.bind(this);
} }
@@ -15,6 +16,10 @@ class Credentials extends Base {
}); });
} }
readAccessOptions(id) {
return this.http.options(`${this.baseUrl}${id}/access_list/`);
}
readInputSources(id, params) { readInputSources(id, params) {
return this.http.get(`${this.baseUrl}${id}/input_sources/`, { return this.http.get(`${this.baseUrl}${id}/input_sources/`, {
params, params,

View File

@@ -7,6 +7,7 @@ class Inventories extends InstanceGroupsMixin(Base) {
this.baseUrl = '/api/v2/inventories/'; this.baseUrl = '/api/v2/inventories/';
this.readAccessList = this.readAccessList.bind(this); this.readAccessList = this.readAccessList.bind(this);
this.readAccessOptions = this.readAccessOptions.bind(this);
this.readHosts = this.readHosts.bind(this); this.readHosts = this.readHosts.bind(this);
this.readHostDetail = this.readHostDetail.bind(this); this.readHostDetail = this.readHostDetail.bind(this);
this.readGroups = this.readGroups.bind(this); this.readGroups = this.readGroups.bind(this);
@@ -20,6 +21,10 @@ class Inventories extends InstanceGroupsMixin(Base) {
}); });
} }
readAccessOptions(id) {
return this.http.options(`${this.baseUrl}${id}/access_list/`);
}
createHost(id, data) { createHost(id, data) {
return this.http.post(`${this.baseUrl}${id}/hosts/`, data); return this.http.post(`${this.baseUrl}${id}/hosts/`, data);
} }

View File

@@ -16,6 +16,7 @@ class JobTemplates extends SchedulesMixin(
this.disassociateLabel = this.disassociateLabel.bind(this); this.disassociateLabel = this.disassociateLabel.bind(this);
this.readCredentials = this.readCredentials.bind(this); this.readCredentials = this.readCredentials.bind(this);
this.readAccessList = this.readAccessList.bind(this); this.readAccessList = this.readAccessList.bind(this);
this.readAccessOptions = this.readAccessOptions.bind(this);
this.readWebhookKey = this.readWebhookKey.bind(this); this.readWebhookKey = this.readWebhookKey.bind(this);
} }
@@ -66,6 +67,10 @@ class JobTemplates extends SchedulesMixin(
}); });
} }
readAccessOptions(id) {
return this.http.options(`${this.baseUrl}${id}/access_list/`);
}
readScheduleList(id, params) { readScheduleList(id, params) {
return this.http.get(`${this.baseUrl}${id}/schedules/`, { return this.http.get(`${this.baseUrl}${id}/schedules/`, {
params, params,

View File

@@ -12,10 +12,18 @@ class Organizations extends InstanceGroupsMixin(NotificationsMixin(Base)) {
return this.http.get(`${this.baseUrl}${id}/access_list/`, { params }); return this.http.get(`${this.baseUrl}${id}/access_list/`, { params });
} }
readAccessOptions(id) {
return this.http.options(`${this.baseUrl}${id}/access_list/`);
}
readTeams(id, params) { readTeams(id, params) {
return this.http.get(`${this.baseUrl}${id}/teams/`, { params }); return this.http.get(`${this.baseUrl}${id}/teams/`, { params });
} }
readTeamsOptions(id) {
return this.http.options(`${this.baseUrl}${id}/teams/`);
}
createUser(id, data) { createUser(id, data) {
return this.http.post(`${this.baseUrl}${id}/users/`, data); return this.http.post(`${this.baseUrl}${id}/users/`, data);
} }

View File

@@ -11,6 +11,7 @@ class Projects extends SchedulesMixin(
this.baseUrl = '/api/v2/projects/'; this.baseUrl = '/api/v2/projects/';
this.readAccessList = this.readAccessList.bind(this); this.readAccessList = this.readAccessList.bind(this);
this.readAccessOptions = this.readAccessOptions.bind(this);
this.readInventories = this.readInventories.bind(this); this.readInventories = this.readInventories.bind(this);
this.readPlaybooks = this.readPlaybooks.bind(this); this.readPlaybooks = this.readPlaybooks.bind(this);
this.readSync = this.readSync.bind(this); this.readSync = this.readSync.bind(this);
@@ -21,6 +22,10 @@ class Projects extends SchedulesMixin(
return this.http.get(`${this.baseUrl}${id}/access_list/`, { params }); return this.http.get(`${this.baseUrl}${id}/access_list/`, { params });
} }
readAccessOptions(id) {
return this.http.options(`${this.baseUrl}${id}/access_list/`);
}
readInventories(id) { readInventories(id) {
return this.http.get(`${this.baseUrl}${id}/inventories/`); return this.http.get(`${this.baseUrl}${id}/inventories/`);
} }

View File

@@ -35,6 +35,10 @@ class Teams extends Base {
}); });
} }
readAccessOptions(id) {
return this.http.options(`${this.baseUrl}${id}/access_list/`);
}
readUsersAccessOptions(teamId) { readUsersAccessOptions(teamId) {
return this.http.options(`${this.baseUrl}${teamId}/users/`); return this.http.options(`${this.baseUrl}${teamId}/users/`);
} }

View File

@@ -54,6 +54,10 @@ class WorkflowJobTemplates extends SchedulesMixin(NotificationsMixin(Base)) {
}); });
} }
readAccessOptions(id) {
return this.http.options(`${this.baseUrl}${id}/access_list/`);
}
readSurvey(id) { readSurvey(id) {
return this.http.get(`${this.baseUrl}${id}/survey_spec/`); return this.http.get(`${this.baseUrl}${id}/survey_spec/`);
} }

View File

@@ -29,21 +29,32 @@ function OrganizationLookup({
history, history,
}) { }) {
const { const {
result: { itemCount, organizations }, result: { itemCount, organizations, relatedSearchableKeys, searchableKeys },
error: contentError, error: contentError,
request: fetchOrganizations, request: fetchOrganizations,
} = useRequest( } = useRequest(
useCallback(async () => { useCallback(async () => {
const params = parseQueryString(QS_CONFIG, history.location.search); const params = parseQueryString(QS_CONFIG, history.location.search);
const { data } = await OrganizationsAPI.read(params); const [response, actionsResponse] = await Promise.all([
OrganizationsAPI.read(params),
OrganizationsAPI.readOptions(),
]);
return { return {
organizations: data.results, organizations: response.data.results,
itemCount: data.count, itemCount: response.data.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),
}; };
}, [history.location.search]), }, [history.location.search]),
{ {
organizations: [], organizations: [],
itemCount: 0, itemCount: 0,
relatedSearchableKeys: [],
searchableKeys: [],
} }
); );
@@ -98,6 +109,8 @@ function OrganizationLookup({
key: 'name', key: 'name',
}, },
]} ]}
searchableKeys={searchableKeys}
relatedSearchableKeys={relatedSearchableKeys}
readOnly={!canDelete} readOnly={!canDelete}
selectItem={item => dispatch({ type: 'SELECT_ITEM', item })} selectItem={item => dispatch({ type: 'SELECT_ITEM', item })}
deselectItem={item => dispatch({ type: 'DESELECT_ITEM', item })} deselectItem={item => dispatch({ type: 'DESELECT_ITEM', item })}

View File

@@ -23,7 +23,7 @@ function NotificationList({ apiModel, canToggleNotifications, id, i18n }) {
const [toggleError, setToggleError] = useState(null); const [toggleError, setToggleError] = useState(null);
const { const {
result: fetchNotificationsResult, result: fetchNotificationsResults,
result: { result: {
notifications, notifications,
itemCount, itemCount,
@@ -31,6 +31,8 @@ function NotificationList({ apiModel, canToggleNotifications, id, i18n }) {
successTemplateIds, successTemplateIds,
errorTemplateIds, errorTemplateIds,
typeLabels, typeLabels,
relatedSearchableKeys,
searchableKeys,
}, },
error: contentError, error: contentError,
isLoading, isLoading,
@@ -43,15 +45,13 @@ function NotificationList({ apiModel, canToggleNotifications, id, i18n }) {
{ {
data: { results: notificationsResults, count: notificationsCount }, data: { results: notificationsResults, count: notificationsCount },
}, },
{ actionsResponse,
data: { actions },
},
] = await Promise.all([ ] = await Promise.all([
NotificationTemplatesAPI.read(params), NotificationTemplatesAPI.read(params),
NotificationTemplatesAPI.readOptions(), NotificationTemplatesAPI.readOptions(),
]); ]);
const labels = actions.GET.notification_type.choices.reduce( const labels = actionsResponse.data.actions.GET.notification_type.choices.reduce(
(map, notifType) => ({ ...map, [notifType[0]]: notifType[1] }), (map, notifType) => ({ ...map, [notifType[0]]: notifType[1] }),
{} {}
); );
@@ -78,6 +78,12 @@ function NotificationList({ apiModel, canToggleNotifications, id, i18n }) {
successTemplateIds: successTemplates.results.map(su => su.id), successTemplateIds: successTemplates.results.map(su => su.id),
errorTemplateIds: errorTemplates.results.map(e => e.id), errorTemplateIds: errorTemplates.results.map(e => e.id),
typeLabels: labels, typeLabels: labels,
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),
}; };
}, [apiModel, id, location]), }, [apiModel, id, location]),
{ {
@@ -87,6 +93,8 @@ function NotificationList({ apiModel, canToggleNotifications, id, i18n }) {
successTemplateIds: [], successTemplateIds: [],
errorTemplateIds: [], errorTemplateIds: [],
typeLabels: {}, typeLabels: {},
relatedSearchableKeys: [],
searchableKeys: [],
} }
); );
@@ -108,8 +116,8 @@ function NotificationList({ apiModel, canToggleNotifications, id, i18n }) {
status status
); );
setValue({ setValue({
...fetchNotificationsResult, ...fetchNotificationsResults,
[`${status}TemplateIds`]: fetchNotificationsResult[ [`${status}TemplateIds`]: fetchNotificationsResults[
`${status}TemplateIds` `${status}TemplateIds`
].filter(i => i !== notificationId), ].filter(i => i !== notificationId),
}); });
@@ -120,8 +128,8 @@ function NotificationList({ apiModel, canToggleNotifications, id, i18n }) {
status status
); );
setValue({ setValue({
...fetchNotificationsResult, ...fetchNotificationsResults,
[`${status}TemplateIds`]: fetchNotificationsResult[ [`${status}TemplateIds`]: fetchNotificationsResults[
`${status}TemplateIds` `${status}TemplateIds`
].concat(notificationId), ].concat(notificationId),
}); });
@@ -179,6 +187,8 @@ function NotificationList({ apiModel, canToggleNotifications, id, i18n }) {
key: 'name', key: 'name',
}, },
]} ]}
toolbarSearchableKeys={searchableKeys}
toolbarRelatedSearchableKeys={relatedSearchableKeys}
renderItem={notification => ( renderItem={notification => (
<NotificationListItem <NotificationListItem
key={notification.id} key={notification.id}

View File

@@ -26,22 +26,33 @@ function ResourceAccessList({ i18n, apiModel, resource }) {
const location = useLocation(); const location = useLocation();
const { const {
result: { accessRecords, itemCount }, result: { accessRecords, itemCount, relatedSearchableKeys, searchableKeys },
error: contentError, error: contentError,
isLoading, isLoading,
request: fetchAccessRecords, request: fetchAccessRecords,
} = useRequest( } = useRequest(
useCallback(async () => { useCallback(async () => {
const params = parseQueryString(QS_CONFIG, location.search); const params = parseQueryString(QS_CONFIG, location.search);
const response = await apiModel.readAccessList(resource.id, params); const [response, actionsResponse] = await Promise.all([
apiModel.readAccessList(resource.id, params),
apiModel.readAccessOptions(resource.id),
]);
return { return {
accessRecords: response.data.results, accessRecords: response.data.results,
itemCount: response.data.count, itemCount: response.data.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),
}; };
}, [apiModel, location, resource.id]), }, [apiModel, location, resource.id]),
{ {
accessRecords: [], accessRecords: [],
itemCount: 0, itemCount: 0,
relatedSearchableKeys: [],
searchableKeys: [],
} }
); );
@@ -106,6 +117,8 @@ function ResourceAccessList({ i18n, apiModel, resource }) {
key: 'last_name', key: 'last_name',
}, },
]} ]}
toolbarSearchableKeys={searchableKeys}
toolbarRelatedSearchableKeys={relatedSearchableKeys}
renderToolbar={props => ( renderToolbar={props => (
<DataListToolbar <DataListToolbar
{...props} {...props}

View File

@@ -76,6 +76,15 @@ describe('<ResourceAccessList />', () => {
beforeEach(async () => { beforeEach(async () => {
OrganizationsAPI.readAccessList.mockResolvedValue({ data }); OrganizationsAPI.readAccessList.mockResolvedValue({ data });
OrganizationsAPI.readAccessOptions.mockResolvedValue({
data: {
actions: {
GET: {},
POST: {},
},
related_search_fields: [],
},
});
TeamsAPI.disassociateRole.mockResolvedValue({}); TeamsAPI.disassociateRole.mockResolvedValue({});
UsersAPI.disassociateRole.mockResolvedValue({}); UsersAPI.disassociateRole.mockResolvedValue({});
await act(async () => { await act(async () => {

View File

@@ -47,7 +47,13 @@ function InventoryGroupsList({ i18n }) {
const { id: inventoryId } = useParams(); const { id: inventoryId } = useParams();
const { const {
result: { groups, groupCount, actions }, result: {
groups,
groupCount,
actions,
relatedSearchableKeys,
searchableKeys,
},
error: contentError, error: contentError,
isLoading, isLoading,
request: fetchGroups, request: fetchGroups,
@@ -62,12 +68,20 @@ function InventoryGroupsList({ i18n }) {
groups: response.data.results, groups: response.data.results,
groupCount: response.data.count, groupCount: response.data.count,
actions: actionsResponse.data.actions, actions: actionsResponse.data.actions,
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),
}; };
}, [inventoryId, location]), }, [inventoryId, location]),
{ {
groups: [], groups: [],
groupCount: 0, groupCount: 0,
actions: {}, actions: {},
relatedSearchableKeys: [],
searchableKeys: [],
} }
); );
@@ -168,6 +182,8 @@ function InventoryGroupsList({ i18n }) {
key: 'name', key: 'name',
}, },
]} ]}
toolbarSearchableKeys={searchableKeys}
toolbarRelatedSearchableKeys={relatedSearchableKeys}
renderItem={item => ( renderItem={item => (
<InventoryGroupItem <InventoryGroupItem
key={item.id} key={item.id}

View File

@@ -19,22 +19,33 @@ function OrganizationTeamList({ id, i18n }) {
const location = useLocation(); const location = useLocation();
const { const {
result: { teams, count }, result: { teams, count, relatedSearchableKeys, searchableKeys },
error, error,
isLoading, isLoading,
request: fetchTeams, request: fetchTeams,
} = useRequest( } = useRequest(
useCallback(async () => { useCallback(async () => {
const params = parseQueryString(QS_CONFIG, location.search); const params = parseQueryString(QS_CONFIG, location.search);
const results = await OrganizationsAPI.readTeams(id, params); const [response, actionsResponse] = await Promise.all([
OrganizationsAPI.readTeams(id, params),
OrganizationsAPI.readTeamsOptions(id),
]);
return { return {
teams: results.data.results, teams: response.data.results,
count: results.data.count, count: response.data.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),
}; };
}, [id, location]), }, [id, location]),
{ {
teams: [], teams: [],
count: 0, count: 0,
relatedSearchableKeys: [],
searchableKeys: [],
} }
); );
@@ -71,6 +82,8 @@ function OrganizationTeamList({ id, i18n }) {
key: 'name', key: 'name',
}, },
]} ]}
toolbarSearchableKeys={searchableKeys}
toolbarRelatedSearchableKeys={relatedSearchableKeys}
renderItem={item => ( renderItem={item => (
<OrganizationTeamListItem <OrganizationTeamListItem
key={item.id} key={item.id}

View File

@@ -53,6 +53,15 @@ const listData = {
describe('<OrganizationTeamList />', () => { describe('<OrganizationTeamList />', () => {
beforeEach(() => { beforeEach(() => {
OrganizationsAPI.readTeams.mockResolvedValue(listData); OrganizationsAPI.readTeams.mockResolvedValue(listData);
OrganizationsAPI.readTeamsOptions.mockResolvedValue({
data: {
actions: {
GET: {},
POST: {},
},
related_search_fields: [],
},
});
}); });
afterEach(() => { afterEach(() => {

View File

@@ -27,7 +27,13 @@ function ProjectJobTemplatesList({ i18n }) {
const location = useLocation(); const location = useLocation();
const { const {
result: { jobTemplates, itemCount, actions }, result: {
jobTemplates,
itemCount,
actions,
relatedSearchableKeys,
searchableKeys,
},
error: contentError, error: contentError,
isLoading, isLoading,
request: fetchTemplates, request: fetchTemplates,
@@ -43,12 +49,20 @@ function ProjectJobTemplatesList({ i18n }) {
jobTemplates: response.data.results, jobTemplates: response.data.results,
itemCount: response.data.count, itemCount: response.data.count,
actions: actionsResponse.data.actions, actions: actionsResponse.data.actions,
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, projectId]), }, [location, projectId]),
{ {
jobTemplates: [], jobTemplates: [],
itemCount: 0, itemCount: 0,
actions: {}, actions: {},
relatedSearchableKeys: [],
searchableKeys: [],
} }
); );
@@ -142,6 +156,8 @@ function ProjectJobTemplatesList({ i18n }) {
key: 'type', key: 'type',
}, },
]} ]}
toolbarSearchableKeys={searchableKeys}
toolbarRelatedSearchableKeys={relatedSearchableKeys}
renderToolbar={props => ( renderToolbar={props => (
<DatalistToolbar <DatalistToolbar
{...props} {...props}

View File

@@ -40,6 +40,15 @@ describe('NodeModal', () => {
], ],
}, },
}); });
JobTemplatesAPI.readOptions.mockResolvedValue({
data: {
actions: {
GET: {},
POST: {},
},
related_search_fields: [],
},
});
ProjectsAPI.read.mockResolvedValue({ ProjectsAPI.read.mockResolvedValue({
data: { data: {
count: 1, count: 1,
@@ -53,6 +62,15 @@ describe('NodeModal', () => {
], ],
}, },
}); });
ProjectsAPI.readOptions.mockResolvedValue({
data: {
actions: {
GET: {},
POST: {},
},
related_search_fields: [],
},
});
InventorySourcesAPI.read.mockResolvedValue({ InventorySourcesAPI.read.mockResolvedValue({
data: { data: {
count: 1, count: 1,
@@ -66,6 +84,15 @@ describe('NodeModal', () => {
], ],
}, },
}); });
InventorySourcesAPI.readOptions.mockResolvedValue({
data: {
actions: {
GET: {},
POST: {},
},
related_search_fields: [],
},
});
WorkflowJobTemplatesAPI.read.mockResolvedValue({ WorkflowJobTemplatesAPI.read.mockResolvedValue({
data: { data: {
count: 1, count: 1,
@@ -79,6 +106,15 @@ describe('NodeModal', () => {
], ],
}, },
}); });
WorkflowJobTemplatesAPI.readOptions.mockResolvedValue({
data: {
actions: {
GET: {},
POST: {},
},
related_search_fields: [],
},
});
}); });
afterAll(() => { afterAll(() => {
jest.clearAllMocks(); jest.clearAllMocks();

View File

@@ -20,22 +20,33 @@ function InventorySourcesList({ i18n, nodeResource, onUpdateNodeResource }) {
const location = useLocation(); const location = useLocation();
const { const {
result: { inventorySources, count }, result: { inventorySources, count, relatedSearchableKeys, searchableKeys },
error, error,
isLoading, isLoading,
request: fetchInventorySources, request: fetchInventorySources,
} = useRequest( } = useRequest(
useCallback(async () => { useCallback(async () => {
const params = parseQueryString(QS_CONFIG, location.search); const params = parseQueryString(QS_CONFIG, location.search);
const results = await InventorySourcesAPI.read(params); const [response, actionsResponse] = await Promise.all([
InventorySourcesAPI.read(params),
InventorySourcesAPI.readOptions(),
]);
return { return {
inventorySources: results.data.results, inventorySources: response.data.results,
count: results.data.count, count: response.data.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]), }, [location]),
{ {
inventorySources: [], inventorySources: [],
count: 0, count: 0,
relatedSearchableKeys: [],
searchableKeys: [],
} }
); );
@@ -94,6 +105,8 @@ function InventorySourcesList({ i18n, nodeResource, onUpdateNodeResource }) {
key: 'name', key: 'name',
}, },
]} ]}
toolbarSearchableKeys={searchableKeys}
toolbarRelatedSearchableKeys={relatedSearchableKeys}
/> />
); );
} }

View File

@@ -38,6 +38,15 @@ describe('InventorySourcesList', () => {
], ],
}, },
}); });
InventorySourcesAPI.readOptions.mockResolvedValue({
data: {
actions: {
GET: {},
POST: {},
},
related_search_fields: [],
},
});
await act(async () => { await act(async () => {
wrapper = mountWithContexts( wrapper = mountWithContexts(
<InventorySourcesList <InventorySourcesList

View File

@@ -20,24 +20,35 @@ function JobTemplatesList({ i18n, nodeResource, onUpdateNodeResource }) {
const location = useLocation(); const location = useLocation();
const { const {
result: { jobTemplates, count }, result: { jobTemplates, count, relatedSearchableKeys, searchableKeys },
error, error,
isLoading, isLoading,
request: fetchJobTemplates, request: fetchJobTemplates,
} = useRequest( } = useRequest(
useCallback(async () => { useCallback(async () => {
const params = parseQueryString(QS_CONFIG, location.search); const params = parseQueryString(QS_CONFIG, location.search);
const results = await JobTemplatesAPI.read(params, { const [response, actionsResponse] = await Promise.all([
role_level: 'execute_role', JobTemplatesAPI.read(params, {
}); role_level: 'execute_role',
}),
JobTemplatesAPI.readOptions(),
]);
return { return {
jobTemplates: results.data.results, jobTemplates: response.data.results,
count: results.data.count, count: response.data.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]), }, [location]),
{ {
jobTemplates: [], jobTemplates: [],
count: 0, count: 0,
relatedSearchableKeys: [],
searchableKeys: [],
} }
); );
@@ -92,6 +103,8 @@ function JobTemplatesList({ i18n, nodeResource, onUpdateNodeResource }) {
key: 'name', key: 'name',
}, },
]} ]}
toolbarSearchableKeys={searchableKeys}
toolbarRelatedSearchableKeys={relatedSearchableKeys}
/> />
); );
} }

View File

@@ -38,6 +38,15 @@ describe('JobTemplatesList', () => {
], ],
}, },
}); });
JobTemplatesAPI.readOptions.mockResolvedValue({
data: {
actions: {
GET: {},
POST: {},
},
related_search_fields: [],
},
});
await act(async () => { await act(async () => {
wrapper = mountWithContexts( wrapper = mountWithContexts(
<JobTemplatesList <JobTemplatesList
@@ -67,6 +76,15 @@ describe('JobTemplatesList', () => {
}); });
test('Error shown when read() request errors', async () => { test('Error shown when read() request errors', async () => {
JobTemplatesAPI.read.mockRejectedValue(new Error()); JobTemplatesAPI.read.mockRejectedValue(new Error());
JobTemplatesAPI.readOptions.mockResolvedValue({
data: {
actions: {
GET: {},
POST: {},
},
related_search_fields: [],
},
});
await act(async () => { await act(async () => {
wrapper = mountWithContexts( wrapper = mountWithContexts(
<JobTemplatesList <JobTemplatesList

View File

@@ -35,6 +35,15 @@ describe('NodeTypeStep', () => {
], ],
}, },
}); });
JobTemplatesAPI.readOptions.mockResolvedValue({
data: {
actions: {
GET: {},
POST: {},
},
related_search_fields: [],
},
});
ProjectsAPI.read.mockResolvedValue({ ProjectsAPI.read.mockResolvedValue({
data: { data: {
count: 1, count: 1,
@@ -48,6 +57,15 @@ describe('NodeTypeStep', () => {
], ],
}, },
}); });
ProjectsAPI.readOptions.mockResolvedValue({
data: {
actions: {
GET: {},
POST: {},
},
related_search_fields: [],
},
});
InventorySourcesAPI.read.mockResolvedValue({ InventorySourcesAPI.read.mockResolvedValue({
data: { data: {
count: 1, count: 1,
@@ -61,6 +79,15 @@ describe('NodeTypeStep', () => {
], ],
}, },
}); });
InventorySourcesAPI.readOptions.mockResolvedValue({
data: {
actions: {
GET: {},
POST: {},
},
related_search_fields: [],
},
});
WorkflowJobTemplatesAPI.read.mockResolvedValue({ WorkflowJobTemplatesAPI.read.mockResolvedValue({
data: { data: {
count: 1, count: 1,
@@ -74,6 +101,15 @@ describe('NodeTypeStep', () => {
], ],
}, },
}); });
WorkflowJobTemplatesAPI.readOptions.mockResolvedValue({
data: {
actions: {
GET: {},
POST: {},
},
related_search_fields: [],
},
});
}); });
afterAll(() => { afterAll(() => {
jest.clearAllMocks(); jest.clearAllMocks();

View File

@@ -20,22 +20,33 @@ function ProjectsList({ i18n, nodeResource, onUpdateNodeResource }) {
const location = useLocation(); const location = useLocation();
const { const {
result: { projects, count }, result: { projects, count, relatedSearchableKeys, searchableKeys },
error, error,
isLoading, isLoading,
request: fetchProjects, request: fetchProjects,
} = useRequest( } = useRequest(
useCallback(async () => { useCallback(async () => {
const params = parseQueryString(QS_CONFIG, location.search); const params = parseQueryString(QS_CONFIG, location.search);
const results = await ProjectsAPI.read(params); const [response, actionsResponse] = await Promise.all([
ProjectsAPI.read(params),
ProjectsAPI.readOptions(),
]);
return { return {
projects: results.data.results, projects: response.data.results,
count: results.data.count, count: response.data.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]), }, [location]),
{ {
projects: [], projects: [],
count: 0, count: 0,
relatedSearchableKeys: [],
searchableKeys: [],
} }
); );
@@ -101,6 +112,8 @@ function ProjectsList({ i18n, nodeResource, onUpdateNodeResource }) {
key: 'name', key: 'name',
}, },
]} ]}
toolbarSearchableKeys={searchableKeys}
toolbarRelatedSearchableKeys={relatedSearchableKeys}
/> />
); );
} }

View File

@@ -38,6 +38,15 @@ describe('ProjectsList', () => {
], ],
}, },
}); });
ProjectsAPI.readOptions.mockResolvedValue({
data: {
actions: {
GET: {},
POST: {},
},
related_search_fields: [],
},
});
await act(async () => { await act(async () => {
wrapper = mountWithContexts( wrapper = mountWithContexts(
<ProjectsList <ProjectsList

View File

@@ -24,24 +24,40 @@ function WorkflowJobTemplatesList({
const location = useLocation(); const location = useLocation();
const { const {
result: { workflowJobTemplates, count }, result: {
workflowJobTemplates,
count,
relatedSearchableKeys,
searchableKeys,
},
error, error,
isLoading, isLoading,
request: fetchWorkflowJobTemplates, request: fetchWorkflowJobTemplates,
} = useRequest( } = useRequest(
useCallback(async () => { useCallback(async () => {
const params = parseQueryString(QS_CONFIG, location.search); const params = parseQueryString(QS_CONFIG, location.search);
const results = await WorkflowJobTemplatesAPI.read(params, { const [response, actionsResponse] = await Promise.all([
role_level: 'execute_role', WorkflowJobTemplatesAPI.read(params, {
}); role_level: 'execute_role',
}),
WorkflowJobTemplatesAPI.readOptions(),
]);
return { return {
workflowJobTemplates: results.data.results, workflowJobTemplates: response.data.results,
count: results.data.count, count: response.data.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]), }, [location]),
{ {
workflowJobTemplates: [], workflowJobTemplates: [],
count: 0, count: 0,
relatedSearchableKeys: [],
searchableKeys: [],
} }
); );
@@ -100,6 +116,8 @@ function WorkflowJobTemplatesList({
key: 'name', key: 'name',
}, },
]} ]}
toolbarSearchableKeys={searchableKeys}
toolbarRelatedSearchableKeys={relatedSearchableKeys}
/> />
); );
} }

View File

@@ -38,6 +38,15 @@ describe('WorkflowJobTemplatesList', () => {
], ],
}, },
}); });
WorkflowJobTemplatesAPI.readOptions.mockResolvedValue({
data: {
actions: {
GET: {},
POST: {},
},
related_search_fields: [],
},
});
await act(async () => { await act(async () => {
wrapper = mountWithContexts( wrapper = mountWithContexts(
<WorkflowJobTemplatesList <WorkflowJobTemplatesList

View File

@@ -27,7 +27,13 @@ function UserList({ i18n }) {
const match = useRouteMatch(); const match = useRouteMatch();
const { const {
result: { users, itemCount, actions }, result: {
users,
itemCount,
actions,
relatedSearchableKeys,
searchableKeys,
},
error: contentError, error: contentError,
isLoading, isLoading,
request: fetchUsers, request: fetchUsers,
@@ -42,12 +48,20 @@ function UserList({ i18n }) {
users: response.data.results, users: response.data.results,
itemCount: response.data.count, itemCount: response.data.count,
actions: actionsResponse.data.actions, actions: actionsResponse.data.actions,
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]), }, [location]),
{ {
users: [], users: [],
itemCount: 0, itemCount: 0,
actions: {}, actions: {},
relatedSearchableKeys: [],
searchableKeys: [],
} }
); );
@@ -124,6 +138,8 @@ function UserList({ i18n }) {
key: 'last_name', key: 'last_name',
}, },
]} ]}
toolbarSearchableKeys={searchableKeys}
toolbarRelatedSearchableKeys={relatedSearchableKeys}
renderToolbar={props => ( renderToolbar={props => (
<DataListToolbar <DataListToolbar
{...props} {...props}