mirror of
https://github.com/ansible/awx.git
synced 2026-02-18 19:50:05 -03:30
Merge pull request #10959 from AlexSCorey/10642-MisalignedTableHeaders
Fixes misalignment on template list and advanced search Key dropdown bug
This commit is contained in:
@@ -29,6 +29,12 @@ class Users extends Base {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
readOrganizationOptions(userId, params) {
|
||||||
|
return this.http.options(`${this.baseUrl}${userId}/organizations/`, {
|
||||||
|
params,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
readRoles(userId, params) {
|
readRoles(userId, params) {
|
||||||
return this.http.get(`${this.baseUrl}${userId}/roles/`, {
|
return this.http.get(`${this.baseUrl}${userId}/roles/`, {
|
||||||
params,
|
params,
|
||||||
|
|||||||
@@ -68,7 +68,6 @@ export function HeaderCell({
|
|||||||
columnIndex,
|
columnIndex,
|
||||||
idPrefix,
|
idPrefix,
|
||||||
className,
|
className,
|
||||||
alignRight,
|
|
||||||
children,
|
children,
|
||||||
}) {
|
}) {
|
||||||
const sort = sortKey
|
const sort = sortKey
|
||||||
@@ -83,7 +82,7 @@ export function HeaderCell({
|
|||||||
id={sortKey ? `${idPrefix}-${sortKey}` : null}
|
id={sortKey ? `${idPrefix}-${sortKey}` : null}
|
||||||
className={className}
|
className={className}
|
||||||
sort={sort}
|
sort={sort}
|
||||||
css={alignRight ? 'text-align: right' : null}
|
css={children === 'Actions' ? 'text-align: right' : null}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</Th>
|
</Th>
|
||||||
|
|||||||
@@ -144,7 +144,7 @@ function CredentialList() {
|
|||||||
<HeaderRow qsConfig={QS_CONFIG}>
|
<HeaderRow qsConfig={QS_CONFIG}>
|
||||||
<HeaderCell sortKey="name">{t`Name`}</HeaderCell>
|
<HeaderCell sortKey="name">{t`Name`}</HeaderCell>
|
||||||
<HeaderCell>{t`Type`}</HeaderCell>
|
<HeaderCell>{t`Type`}</HeaderCell>
|
||||||
<HeaderCell alignRight>{t`Actions`}</HeaderCell>
|
<HeaderCell>{t`Actions`}</HeaderCell>
|
||||||
</HeaderRow>
|
</HeaderRow>
|
||||||
}
|
}
|
||||||
renderRow={(item, index) => (
|
renderRow={(item, index) => (
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ function HostList() {
|
|||||||
actions: results[1].data.actions,
|
actions: results[1].data.actions,
|
||||||
relatedSearchableKeys: (
|
relatedSearchableKeys: (
|
||||||
results[1]?.data?.related_search_fields || []
|
results[1]?.data?.related_search_fields || []
|
||||||
).map((val) => val.slice(0, -8)),
|
).map((val) => (val.endsWith('search') ? val.slice(0, -8) : val)),
|
||||||
searchableKeys: getSearchableKeys(results[1].data.actions?.GET),
|
searchableKeys: getSearchableKeys(results[1].data.actions?.GET),
|
||||||
};
|
};
|
||||||
}, [location]),
|
}, [location]),
|
||||||
|
|||||||
@@ -95,6 +95,7 @@ describe('<HostList />', () => {
|
|||||||
GET: {},
|
GET: {},
|
||||||
POST: {},
|
POST: {},
|
||||||
},
|
},
|
||||||
|
related_search_fields: ['first_key__search', 'ansible_facts'],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -121,6 +122,10 @@ describe('<HostList />', () => {
|
|||||||
});
|
});
|
||||||
await waitForLoaded(wrapper);
|
await waitForLoaded(wrapper);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
wrapper.find('PaginatedTable').props().toolbarRelatedSearchableKeys
|
||||||
|
).toStrictEqual(['first_key', 'ansible_facts']);
|
||||||
|
|
||||||
expect(HostsAPI.read).toHaveBeenCalled();
|
expect(HostsAPI.read).toHaveBeenCalled();
|
||||||
expect(wrapper.find('HostListItem')).toHaveLength(3);
|
expect(wrapper.find('HostListItem')).toHaveLength(3);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ function InventoryHostList() {
|
|||||||
actions: hostOptions.data.actions,
|
actions: hostOptions.data.actions,
|
||||||
relatedSearchableKeys: (
|
relatedSearchableKeys: (
|
||||||
hostOptions?.data?.related_search_fields || []
|
hostOptions?.data?.related_search_fields || []
|
||||||
).map((val) => val.slice(0, -8)),
|
).map((val) => (val.endsWith('search') ? val.slice(0, -8) : val)),
|
||||||
searchableKeys: getSearchableKeys(hostOptions.data.actions?.GET),
|
searchableKeys: getSearchableKeys(hostOptions.data.actions?.GET),
|
||||||
};
|
};
|
||||||
}, [id, search]),
|
}, [id, search]),
|
||||||
|
|||||||
@@ -91,6 +91,7 @@ describe('<InventoryHostList />', () => {
|
|||||||
GET: {},
|
GET: {},
|
||||||
POST: {},
|
POST: {},
|
||||||
},
|
},
|
||||||
|
related_search_fields: ['first_key__search', 'ansible_facts'],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -123,6 +124,9 @@ describe('<InventoryHostList />', () => {
|
|||||||
test('should fetch hosts from api and render them in the list', async () => {
|
test('should fetch hosts from api and render them in the list', async () => {
|
||||||
expect(InventoriesAPI.readHosts).toHaveBeenCalled();
|
expect(InventoriesAPI.readHosts).toHaveBeenCalled();
|
||||||
expect(wrapper.find('InventoryHostItem').length).toBe(3);
|
expect(wrapper.find('InventoryHostItem').length).toBe(3);
|
||||||
|
expect(
|
||||||
|
wrapper.find('PaginatedTable').props().toolbarRelatedSearchableKeys
|
||||||
|
).toStrictEqual(['first_key', 'ansible_facts']);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should render Run Commands button', async () => {
|
test('should render Run Commands button', async () => {
|
||||||
|
|||||||
@@ -36,7 +36,14 @@ function InventorySourceList() {
|
|||||||
const {
|
const {
|
||||||
isLoading,
|
isLoading,
|
||||||
error: fetchError,
|
error: fetchError,
|
||||||
result: { result, sourceCount, sourceChoices, sourceChoicesOptions },
|
result: {
|
||||||
|
result,
|
||||||
|
sourceCount,
|
||||||
|
sourceChoices,
|
||||||
|
sourceChoicesOptions,
|
||||||
|
searchableKeys,
|
||||||
|
relatedSearchableKeys,
|
||||||
|
},
|
||||||
request: fetchSources,
|
request: fetchSources,
|
||||||
} = useRequest(
|
} = useRequest(
|
||||||
useCallback(async () => {
|
useCallback(async () => {
|
||||||
@@ -50,12 +57,20 @@ function InventorySourceList() {
|
|||||||
sourceCount: results[0].data.count,
|
sourceCount: results[0].data.count,
|
||||||
sourceChoices: results[1].data.actions.GET.source.choices,
|
sourceChoices: results[1].data.actions.GET.source.choices,
|
||||||
sourceChoicesOptions: results[1].data.actions,
|
sourceChoicesOptions: results[1].data.actions,
|
||||||
|
searchableKeys: Object.keys(results[1].data.actions?.GET || {}).filter(
|
||||||
|
(key) => results[1].data.actions?.GET[key].filterable
|
||||||
|
),
|
||||||
|
relatedSearchableKeys: (
|
||||||
|
results[1]?.data?.related_search_fields || []
|
||||||
|
).map((val) => val.slice(0, -8)),
|
||||||
};
|
};
|
||||||
}, [id, search]),
|
}, [id, search]),
|
||||||
{
|
{
|
||||||
result: [],
|
result: [],
|
||||||
sourceCount: 0,
|
sourceCount: 0,
|
||||||
sourceChoices: [],
|
sourceChoices: [],
|
||||||
|
searchableKeys: [],
|
||||||
|
relatedSearchableKeys: [],
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -149,6 +164,8 @@ function InventorySourceList() {
|
|||||||
<>
|
<>
|
||||||
<PaginatedTable
|
<PaginatedTable
|
||||||
contentError={fetchError}
|
contentError={fetchError}
|
||||||
|
toolbarSearchableKeys={searchableKeys}
|
||||||
|
toolbarRelatedSearchableKeys={relatedSearchableKeys}
|
||||||
hasContentLoading={
|
hasContentLoading={
|
||||||
isLoading ||
|
isLoading ||
|
||||||
isDeleteLoading ||
|
isDeleteLoading ||
|
||||||
|
|||||||
@@ -27,7 +27,10 @@ const QS_CONFIG = getQSConfig('system_job_templates', {
|
|||||||
const buildSearchKeys = (options) => {
|
const buildSearchKeys = (options) => {
|
||||||
const actions = options?.data?.actions?.GET || {};
|
const actions = options?.data?.actions?.GET || {};
|
||||||
const searchableKeys = getSearchableKeys(actions);
|
const searchableKeys = getSearchableKeys(actions);
|
||||||
const relatedSearchableKeys = options?.data?.related_search_fields || [];
|
|
||||||
|
const relatedSearchableKeys = (
|
||||||
|
options?.data?.related_search_fields || []
|
||||||
|
).map((val) => val.slice(0, -8));
|
||||||
|
|
||||||
return { searchableKeys, relatedSearchableKeys };
|
return { searchableKeys, relatedSearchableKeys };
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -23,17 +23,29 @@ function UserOrganizationList() {
|
|||||||
const { id: userId } = useParams();
|
const { id: userId } = useParams();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
result: { organizations, count },
|
result: { organizations, count, searchableKeys, relatedSearchableKeys },
|
||||||
error: contentError,
|
error: contentError,
|
||||||
isLoading,
|
isLoading,
|
||||||
request: fetchOrgs,
|
request: fetchOrgs,
|
||||||
} = useRequest(
|
} = useRequest(
|
||||||
useCallback(async () => {
|
useCallback(async () => {
|
||||||
const params = parseQueryString(QS_CONFIG, location.search);
|
const params = parseQueryString(QS_CONFIG, location.search);
|
||||||
const {
|
const [
|
||||||
data: { results, count: orgCount },
|
{
|
||||||
} = await UsersAPI.readOrganizations(userId, params);
|
data: { results, count: orgCount },
|
||||||
|
},
|
||||||
|
actions,
|
||||||
|
] = await Promise.all([
|
||||||
|
UsersAPI.readOrganizations(userId, params),
|
||||||
|
UsersAPI.readOrganizationOptions(),
|
||||||
|
]);
|
||||||
return {
|
return {
|
||||||
|
searchableKeys: Object.keys(actions.data.actions?.GET || {}).filter(
|
||||||
|
(key) => actions.data.actions?.GET[key].filterable
|
||||||
|
),
|
||||||
|
relatedSearchableKeys: (actions?.data?.related_search_fields || []).map(
|
||||||
|
(val) => val.slice(0, -8)
|
||||||
|
),
|
||||||
organizations: results,
|
organizations: results,
|
||||||
count: orgCount,
|
count: orgCount,
|
||||||
};
|
};
|
||||||
@@ -41,6 +53,8 @@ function UserOrganizationList() {
|
|||||||
{
|
{
|
||||||
organizations: [],
|
organizations: [],
|
||||||
count: 0,
|
count: 0,
|
||||||
|
searchableKeys: [],
|
||||||
|
relatedSearchableKeys: [],
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -52,6 +66,8 @@ function UserOrganizationList() {
|
|||||||
<PaginatedTable
|
<PaginatedTable
|
||||||
items={organizations}
|
items={organizations}
|
||||||
contentError={contentError}
|
contentError={contentError}
|
||||||
|
toolbarSearchableKeys={searchableKeys}
|
||||||
|
toolbarRelatedSearchableKeys={relatedSearchableKeys}
|
||||||
hasContentLoading={isLoading}
|
hasContentLoading={isLoading}
|
||||||
itemCount={count}
|
itemCount={count}
|
||||||
pluralizedItemName={t`Organizations`}
|
pluralizedItemName={t`Organizations`}
|
||||||
|
|||||||
@@ -33,6 +33,9 @@ describe('<UserOrganizationlist />', () => {
|
|||||||
count: 1,
|
count: 1,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
UsersAPI.readOrganizationOptions.mockResolvedValue({
|
||||||
|
data: { actions: { GET: {} } },
|
||||||
|
});
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
wrapper = mountWithContexts(
|
wrapper = mountWithContexts(
|
||||||
<Route
|
<Route
|
||||||
@@ -69,5 +72,6 @@ describe('<UserOrganizationlist />', () => {
|
|||||||
page_size: 20,
|
page_size: 20,
|
||||||
type: 'organization',
|
type: 'organization',
|
||||||
});
|
});
|
||||||
|
expect(UsersAPI.readOrganizationOptions).toBeCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user