mirror of
https://github.com/ansible/awx.git
synced 2026-01-15 03:40:42 -03:30
resolves crashing details view
This commit is contained in:
parent
04839a037a
commit
9992bf03b0
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -13,7 +13,7 @@ import { CaretLeftIcon } from '@patternfly/react-icons';
|
||||
import { Card, PageSection } from '@patternfly/react-core';
|
||||
|
||||
import useRequest from '../../util/useRequest';
|
||||
import { InstanceGroupsAPI } from '../../api';
|
||||
import { InstanceGroupsAPI, SettingsAPI } from '../../api';
|
||||
import RoutedTabs from '../../components/RoutedTabs';
|
||||
import ContentError from '../../components/ContentError';
|
||||
import ContentLoading from '../../components/ContentLoading';
|
||||
@ -30,12 +30,24 @@ function ContainerGroup({ setBreadcrumb }) {
|
||||
isLoading,
|
||||
error: contentError,
|
||||
request: fetchInstanceGroups,
|
||||
result: instanceGroup,
|
||||
result: { instanceGroup, defaultExecution },
|
||||
} = useRequest(
|
||||
useCallback(async () => {
|
||||
const { data } = await InstanceGroupsAPI.readDetail(id);
|
||||
return data;
|
||||
}, [id])
|
||||
const [
|
||||
{ data },
|
||||
{
|
||||
data: { DEFAULT_EXECUTION_QUEUE_NAME },
|
||||
},
|
||||
] = await Promise.all([
|
||||
InstanceGroupsAPI.readDetail(id),
|
||||
SettingsAPI.readAll(),
|
||||
]);
|
||||
return {
|
||||
instanceGroup: data,
|
||||
defaultExecution: DEFAULT_EXECUTION_QUEUE_NAME,
|
||||
};
|
||||
}, [id]),
|
||||
{ instanceGroup: null, defaultExecution: '' }
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
@ -109,10 +121,16 @@ function ContainerGroup({ setBreadcrumb }) {
|
||||
{instanceGroup && (
|
||||
<>
|
||||
<Route path="/instance_groups/container_group/:id/edit">
|
||||
<ContainerGroupEdit instanceGroup={instanceGroup} />
|
||||
<ContainerGroupEdit
|
||||
instanceGroup={instanceGroup}
|
||||
defaultExecution={defaultExecution}
|
||||
/>
|
||||
</Route>
|
||||
<Route path="/instance_groups/container_group/:id/details">
|
||||
<ContainerGroupDetails instanceGroup={instanceGroup} />
|
||||
<ContainerGroupDetails
|
||||
instanceGroup={instanceGroup}
|
||||
defaultExecution={defaultExecution}
|
||||
/>
|
||||
</Route>
|
||||
<Route path="/instance_groups/container_group/:id/jobs">
|
||||
<JobList
|
||||
|
||||
@ -6,6 +6,7 @@ import { Button, Label } from '@patternfly/react-core';
|
||||
|
||||
import { VariablesDetail } from '../../../components/CodeEditor';
|
||||
import AlertModal from '../../../components/AlertModal';
|
||||
import ErrorDetail from '../../../components/ErrorDetail';
|
||||
import { CardBody, CardActionsRow } from '../../../components/Card';
|
||||
import DeleteButton from '../../../components/DeleteButton';
|
||||
import {
|
||||
@ -18,7 +19,7 @@ import { jsonToYaml, isJsonString } from '../../../util/yaml';
|
||||
import { InstanceGroupsAPI } from '../../../api';
|
||||
import { relatedResourceDeleteRequests } from '../../../util/getRelatedResourceDeleteDetails';
|
||||
|
||||
function ContainerGroupDetails({ instanceGroup }) {
|
||||
function ContainerGroupDetails({ instanceGroup, defaultExecution }) {
|
||||
const { id, name } = instanceGroup;
|
||||
|
||||
const history = useHistory();
|
||||
@ -102,7 +103,8 @@ function ContainerGroupDetails({ instanceGroup }) {
|
||||
{t`Edit`}
|
||||
</Button>
|
||||
)}
|
||||
{instanceGroup.summary_fields.user_capabilities &&
|
||||
{name !== defaultExecution &&
|
||||
instanceGroup.summary_fields.user_capabilities &&
|
||||
instanceGroup.summary_fields.user_capabilities.delete && (
|
||||
<DeleteButton
|
||||
ouiaId="container-group-detail-delete-button"
|
||||
@ -123,7 +125,9 @@ function ContainerGroupDetails({ instanceGroup }) {
|
||||
onClose={dismissError}
|
||||
title={t`Error`}
|
||||
variant="error"
|
||||
/>
|
||||
>
|
||||
<ErrorDetail error={error} />
|
||||
</AlertModal>
|
||||
)}
|
||||
</CardBody>
|
||||
);
|
||||
|
||||
@ -31,16 +31,13 @@ function InstanceGroup({ setBreadcrumb }) {
|
||||
isLoading,
|
||||
error: contentError,
|
||||
request: fetchInstanceGroups,
|
||||
result: { instanceGroup, defaultControlPlane, defaultExecution },
|
||||
result: { instanceGroup, defaultControlPlane },
|
||||
} = useRequest(
|
||||
useCallback(async () => {
|
||||
const [
|
||||
{ data },
|
||||
{
|
||||
data: {
|
||||
DEFAULT_CONTROL_PLANE_QUEUE_NAME,
|
||||
DEFAULT_EXECUTION_QUEUE_NAME,
|
||||
},
|
||||
data: { DEFAULT_CONTROL_PLANE_QUEUE_NAME },
|
||||
},
|
||||
] = await Promise.all([
|
||||
InstanceGroupsAPI.readDetail(id),
|
||||
@ -49,10 +46,9 @@ function InstanceGroup({ setBreadcrumb }) {
|
||||
return {
|
||||
instanceGroup: data,
|
||||
defaultControlPlane: DEFAULT_CONTROL_PLANE_QUEUE_NAME,
|
||||
defaultExecution: DEFAULT_EXECUTION_QUEUE_NAME,
|
||||
};
|
||||
}, [id]),
|
||||
{ instanceGroup: {}, defaultControlPlane: '', defaultExecution: '' }
|
||||
{ instanceGroup: null, defaultControlPlane: '' }
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
@ -133,12 +129,14 @@ function InstanceGroup({ setBreadcrumb }) {
|
||||
<Route path="/instance_groups/:id/edit">
|
||||
<InstanceGroupEdit
|
||||
instanceGroup={instanceGroup}
|
||||
defaultExecution={defaultExecution}
|
||||
defaultControlPlane={defaultControlPlane}
|
||||
/>
|
||||
</Route>
|
||||
<Route path="/instance_groups/:id/details">
|
||||
<InstanceGroupDetails instanceGroup={instanceGroup} />
|
||||
<InstanceGroupDetails
|
||||
defaultControlPlane={defaultControlPlane}
|
||||
instanceGroup={instanceGroup}
|
||||
/>
|
||||
</Route>
|
||||
<Route path="/instance_groups/:id/instances">
|
||||
<InstanceList />
|
||||
|
||||
@ -7,6 +7,7 @@ import { Button } from '@patternfly/react-core';
|
||||
|
||||
import AlertModal from '../../../components/AlertModal';
|
||||
import { CardBody, CardActionsRow } from '../../../components/Card';
|
||||
import ErrorDetail from '../../../components/ErrorDetail';
|
||||
import DeleteButton from '../../../components/DeleteButton';
|
||||
import {
|
||||
Detail,
|
||||
@ -22,7 +23,7 @@ const Unavailable = styled.span`
|
||||
color: var(--pf-global--danger-color--200);
|
||||
`;
|
||||
|
||||
function InstanceGroupDetails({ instanceGroup }) {
|
||||
function InstanceGroupDetails({ instanceGroup, defaultControlPlane }) {
|
||||
const { id, name } = instanceGroup;
|
||||
|
||||
const history = useHistory();
|
||||
@ -110,7 +111,7 @@ function InstanceGroupDetails({ instanceGroup }) {
|
||||
{t`Edit`}
|
||||
</Button>
|
||||
)}
|
||||
{name !== 'tower' &&
|
||||
{name !== defaultControlPlane &&
|
||||
instanceGroup.summary_fields.user_capabilities &&
|
||||
instanceGroup.summary_fields.user_capabilities.delete && (
|
||||
<DeleteButton
|
||||
@ -132,7 +133,9 @@ function InstanceGroupDetails({ instanceGroup }) {
|
||||
onClose={dismissError}
|
||||
title={t`Error`}
|
||||
variant="error"
|
||||
/>
|
||||
>
|
||||
<ErrorDetail error={error} />
|
||||
</AlertModal>
|
||||
)}
|
||||
</CardBody>
|
||||
);
|
||||
|
||||
@ -5,11 +5,7 @@ import { CardBody } from '../../../components/Card';
|
||||
import { InstanceGroupsAPI } from '../../../api';
|
||||
import InstanceGroupForm from '../shared/InstanceGroupForm';
|
||||
|
||||
function InstanceGroupEdit({
|
||||
instanceGroup,
|
||||
defaultExecution,
|
||||
defaultControlPlane,
|
||||
}) {
|
||||
function InstanceGroupEdit({ instanceGroup, defaultControlPlane }) {
|
||||
const history = useHistory();
|
||||
const [submitError, setSubmitError] = useState(null);
|
||||
const detailsUrl = `/instance_groups/${instanceGroup.id}/details`;
|
||||
@ -31,7 +27,6 @@ function InstanceGroupEdit({
|
||||
<CardBody>
|
||||
<InstanceGroupForm
|
||||
instanceGroup={instanceGroup}
|
||||
defaultExecution={defaultExecution}
|
||||
defaultControlPlane={defaultControlPlane}
|
||||
onSubmit={handleSubmit}
|
||||
submitError={submitError}
|
||||
|
||||
@ -56,7 +56,6 @@ describe('<InstanceGroupEdit>', () => {
|
||||
await act(async () => {
|
||||
wrapper = mountWithContexts(
|
||||
<InstanceGroupEdit
|
||||
defaultExecution="default"
|
||||
defaultControlPlane="controlplane"
|
||||
instanceGroup={instanceGroupData}
|
||||
/>,
|
||||
@ -77,7 +76,6 @@ describe('<InstanceGroupEdit>', () => {
|
||||
await act(async () => {
|
||||
towerWrapper = mountWithContexts(
|
||||
<InstanceGroupEdit
|
||||
defaultExecution="default"
|
||||
defaultControlPlane="controlplane"
|
||||
instanceGroup={{ ...instanceGroupData, name: 'controlplane' }}
|
||||
/>,
|
||||
@ -94,28 +92,6 @@ describe('<InstanceGroupEdit>', () => {
|
||||
).toEqual('controlplane');
|
||||
});
|
||||
|
||||
test('default instance group name can not be updated', async () => {
|
||||
let towerWrapper;
|
||||
await act(async () => {
|
||||
towerWrapper = mountWithContexts(
|
||||
<InstanceGroupEdit
|
||||
defaultExecution="default"
|
||||
defaultControlPlane="controlplane"
|
||||
instanceGroup={{ ...instanceGroupData, name: 'default' }}
|
||||
/>,
|
||||
{
|
||||
context: { router: { history } },
|
||||
}
|
||||
);
|
||||
});
|
||||
expect(
|
||||
towerWrapper.find('input#instance-group-name').prop('disabled')
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
towerWrapper.find('input#instance-group-name').prop('value')
|
||||
).toEqual('default');
|
||||
});
|
||||
|
||||
test('handleSubmit should call the api and redirect to details page', async () => {
|
||||
await act(async () => {
|
||||
wrapper.find('InstanceGroupForm').invoke('onSubmit')(
|
||||
|
||||
@ -55,6 +55,30 @@ function InstanceGroupList({
|
||||
}) {
|
||||
const location = useLocation();
|
||||
const match = useRouteMatch();
|
||||
const {
|
||||
error: protectedItemsError,
|
||||
isloading: isLoadingProtectedItems,
|
||||
request: fetchProtectedItems,
|
||||
result: { defaultControlPlane, defaultExecution },
|
||||
} = useRequest(
|
||||
useCallback(async () => {
|
||||
const {
|
||||
data: {
|
||||
DEFAULT_CONTROL_PLANE_QUEUE_NAME,
|
||||
DEFAULT_EXECUTION_QUEUE_NAME,
|
||||
},
|
||||
} = await SettingsAPI.readAll();
|
||||
return {
|
||||
defaultControlPlane: DEFAULT_CONTROL_PLANE_QUEUE_NAME,
|
||||
defaultExecution: DEFAULT_EXECUTION_QUEUE_NAME,
|
||||
};
|
||||
}, []),
|
||||
{ defaultControlPlane: '', defaultExecution: '' }
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
fetchProtectedItems();
|
||||
}, [fetchProtectedItems]);
|
||||
|
||||
const {
|
||||
error: contentError,
|
||||
@ -66,32 +90,18 @@ function InstanceGroupList({
|
||||
actions,
|
||||
relatedSearchableKeys,
|
||||
searchableKeys,
|
||||
defaultControlPlane,
|
||||
defaultExecution,
|
||||
},
|
||||
} = useRequest(
|
||||
useCallback(async () => {
|
||||
const params = parseQueryString(QS_CONFIG, location.search);
|
||||
|
||||
const [
|
||||
response,
|
||||
responseActions,
|
||||
{
|
||||
data: {
|
||||
DEFAULT_CONTROL_PLANE_QUEUE_NAME,
|
||||
DEFAULT_EXECUTION_QUEUE_NAME,
|
||||
},
|
||||
},
|
||||
] = await Promise.all([
|
||||
const [response, responseActions] = await Promise.all([
|
||||
InstanceGroupsAPI.read(params),
|
||||
InstanceGroupsAPI.readOptions(),
|
||||
SettingsAPI.readAll(),
|
||||
]);
|
||||
|
||||
return {
|
||||
instanceGroups: response.data.results,
|
||||
defaultControlPlane: DEFAULT_CONTROL_PLANE_QUEUE_NAME,
|
||||
defaultExecution: DEFAULT_EXECUTION_QUEUE_NAME,
|
||||
instanceGroupsCount: response.data.count,
|
||||
actions: responseActions.data.actions,
|
||||
relatedSearchableKeys: (
|
||||
@ -165,15 +175,17 @@ function InstanceGroupList({
|
||||
const pluralizedItemName = t`Instance Groups`;
|
||||
|
||||
let errorMessageDelete = '';
|
||||
const notdeletedable = selected.filter(
|
||||
i => i.name === defaultControlPlane || i.name === defaultExecution
|
||||
);
|
||||
|
||||
if (
|
||||
modifiedSelected.some(
|
||||
item =>
|
||||
item.name === defaultControlPlane || item.name === defaultExecution
|
||||
)
|
||||
) {
|
||||
errorMessageDelete = errorMessageDelete.concat(
|
||||
t`The following Instance Group cannot be deleted`
|
||||
if (notdeletedable.length) {
|
||||
errorMessageDelete = (
|
||||
<Plural
|
||||
value={notdeletedable.length}
|
||||
one="The following Instance Group cannot be deleted"
|
||||
other="The following Instance Groups cannot be deleted"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@ -227,9 +239,14 @@ function InstanceGroupList({
|
||||
<PageSection>
|
||||
<Card>
|
||||
<PaginatedTable
|
||||
contentError={contentError || settingsRequestError}
|
||||
contentError={
|
||||
contentError || settingsRequestError || protectedItemsError
|
||||
}
|
||||
hasContentLoading={
|
||||
isLoading || deleteLoading || isSettingsRequestLoading
|
||||
isLoading ||
|
||||
deleteLoading ||
|
||||
isSettingsRequestLoading ||
|
||||
isLoadingProtectedItems
|
||||
}
|
||||
items={instanceGroups}
|
||||
itemCount={instanceGroupsCount}
|
||||
|
||||
@ -27,6 +27,8 @@ function ContainerGroupFormFields({ instanceGroup }) {
|
||||
'credential'
|
||||
);
|
||||
|
||||
const [nameField] = useField('name');
|
||||
|
||||
const [overrideField] = useField('override');
|
||||
|
||||
const handleCredentialUpdate = useCallback(
|
||||
@ -45,6 +47,7 @@ function ContainerGroupFormFields({ instanceGroup }) {
|
||||
label={t`Name`}
|
||||
type="text"
|
||||
validate={required(null)}
|
||||
isDisabled={nameField.value === 'default'}
|
||||
isRequired
|
||||
/>
|
||||
<CredentialLookup
|
||||
|
||||
@ -10,7 +10,7 @@ import FormActionGroup from '../../../components/FormActionGroup';
|
||||
import { required, minMaxValue } from '../../../util/validators';
|
||||
import { FormColumnLayout } from '../../../components/FormLayout';
|
||||
|
||||
function InstanceGroupFormFields({ defaultExecution, defaultControlPlane }) {
|
||||
function InstanceGroupFormFields({ defaultControlPlane }) {
|
||||
const [instanceGroupNameField, ,] = useField('name');
|
||||
|
||||
return (
|
||||
@ -22,10 +22,7 @@ function InstanceGroupFormFields({ defaultExecution, defaultControlPlane }) {
|
||||
type="text"
|
||||
validate={required(null)}
|
||||
isRequired
|
||||
isDisabled={
|
||||
instanceGroupNameField.value === defaultExecution ||
|
||||
instanceGroupNameField.value === defaultControlPlane
|
||||
}
|
||||
isDisabled={instanceGroupNameField.value === defaultControlPlane}
|
||||
/>
|
||||
<FormField
|
||||
id="instance-group-policy-instance-minimum"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user