mirror of
https://github.com/ansible/awx.git
synced 2026-03-20 10:27:34 -02:30
Merge pull request #13873 from marshmalien/10799-bug-prompt-launch-credential-type-dropdown-complete
Fix screen crash when changing credential type in launch prompt dropdown
This commit is contained in:
@@ -43,6 +43,7 @@ function LaunchButton({ resource, children }) {
|
|||||||
const [surveyConfig, setSurveyConfig] = useState(null);
|
const [surveyConfig, setSurveyConfig] = useState(null);
|
||||||
const [labels, setLabels] = useState([]);
|
const [labels, setLabels] = useState([]);
|
||||||
const [isLaunching, setIsLaunching] = useState(false);
|
const [isLaunching, setIsLaunching] = useState(false);
|
||||||
|
const [resourceCredentials, setResourceCredentials] = useState([]);
|
||||||
const [error, setError] = useState(null);
|
const [error, setError] = useState(null);
|
||||||
|
|
||||||
const handleLaunch = async () => {
|
const handleLaunch = async () => {
|
||||||
@@ -83,6 +84,13 @@ function LaunchButton({ resource, children }) {
|
|||||||
setLabels(allLabels);
|
setLabels(allLabels);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (launch.ask_credential_on_launch) {
|
||||||
|
const {
|
||||||
|
data: { results: templateCredentials },
|
||||||
|
} = await JobTemplatesAPI.readCredentials(resource.id);
|
||||||
|
setResourceCredentials(templateCredentials);
|
||||||
|
}
|
||||||
|
|
||||||
if (canLaunchWithoutPrompt(launch)) {
|
if (canLaunchWithoutPrompt(launch)) {
|
||||||
await launchWithParams({});
|
await launchWithParams({});
|
||||||
} else {
|
} else {
|
||||||
@@ -208,6 +216,7 @@ function LaunchButton({ resource, children }) {
|
|||||||
labels={labels}
|
labels={labels}
|
||||||
onLaunch={launchWithParams}
|
onLaunch={launchWithParams}
|
||||||
onCancel={() => setShowLaunchPrompt(false)}
|
onCancel={() => setShowLaunchPrompt(false)}
|
||||||
|
resourceDefaultCredentials={resourceCredentials}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -47,6 +47,12 @@ describe('LaunchButton', () => {
|
|||||||
variables_needed_to_start: [],
|
variables_needed_to_start: [],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
JobTemplatesAPI.readCredentials.mockResolvedValue({
|
||||||
|
data: {
|
||||||
|
count: 0,
|
||||||
|
results: [],
|
||||||
|
},
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => jest.clearAllMocks());
|
afterEach(() => jest.clearAllMocks());
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ function PromptModalForm({
|
|||||||
labels,
|
labels,
|
||||||
surveyConfig,
|
surveyConfig,
|
||||||
instanceGroups,
|
instanceGroups,
|
||||||
|
resourceDefaultCredentials,
|
||||||
}) {
|
}) {
|
||||||
const { setFieldTouched, values } = useFormikContext();
|
const { setFieldTouched, values } = useFormikContext();
|
||||||
const [showDescription, setShowDescription] = useState(false);
|
const [showDescription, setShowDescription] = useState(false);
|
||||||
@@ -35,9 +36,9 @@ function PromptModalForm({
|
|||||||
surveyConfig,
|
surveyConfig,
|
||||||
resource,
|
resource,
|
||||||
labels,
|
labels,
|
||||||
instanceGroups
|
instanceGroups,
|
||||||
|
resourceDefaultCredentials
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleSubmit = async () => {
|
const handleSubmit = async () => {
|
||||||
const postValues = {};
|
const postValues = {};
|
||||||
const setValue = (key, value) => {
|
const setValue = (key, value) => {
|
||||||
|
|||||||
@@ -69,6 +69,20 @@ describe('LaunchPrompt', () => {
|
|||||||
spec: [{ type: 'text', variable: 'foo' }],
|
spec: [{ type: 'text', variable: 'foo' }],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
JobTemplatesAPI.readCredentials.mockResolvedValue({
|
||||||
|
data: {
|
||||||
|
results: [
|
||||||
|
{
|
||||||
|
id: 5,
|
||||||
|
name: 'cred that prompts',
|
||||||
|
credential_type: 1,
|
||||||
|
inputs: {
|
||||||
|
password: 'ASK',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
});
|
||||||
InstanceGroupsAPI.read.mockResolvedValue({
|
InstanceGroupsAPI.read.mockResolvedValue({
|
||||||
data: {
|
data: {
|
||||||
results: [
|
results: [
|
||||||
@@ -212,6 +226,16 @@ describe('LaunchPrompt', () => {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
|
resourceDefaultCredentials={[
|
||||||
|
{
|
||||||
|
id: 5,
|
||||||
|
name: 'cred that prompts',
|
||||||
|
credential_type: 1,
|
||||||
|
inputs: {
|
||||||
|
password: 'ASK',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]}
|
||||||
onLaunch={noop}
|
onLaunch={noop}
|
||||||
onCancel={noop}
|
onCancel={noop}
|
||||||
surveyConfig={{
|
surveyConfig={{
|
||||||
@@ -289,6 +313,16 @@ describe('LaunchPrompt', () => {
|
|||||||
resource={resource}
|
resource={resource}
|
||||||
onLaunch={noop}
|
onLaunch={noop}
|
||||||
onCancel={noop}
|
onCancel={noop}
|
||||||
|
resourceDefaultCredentials={[
|
||||||
|
{
|
||||||
|
id: 5,
|
||||||
|
name: 'cred that prompts',
|
||||||
|
credential_type: 1,
|
||||||
|
inputs: {
|
||||||
|
password: 'ASK',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import 'styled-components/macro';
|
import 'styled-components/macro';
|
||||||
import React, { useState, useCallback, useEffect } from 'react';
|
import React, { useState, useCallback, useEffect } from 'react';
|
||||||
import { useHistory } from 'react-router-dom';
|
import { useHistory, useLocation } from 'react-router-dom';
|
||||||
|
|
||||||
import { t } from '@lingui/macro';
|
import { t } from '@lingui/macro';
|
||||||
import { useField } from 'formik';
|
import { useField } from 'formik';
|
||||||
@@ -8,7 +8,7 @@ import styled from 'styled-components';
|
|||||||
import { Alert, ToolbarItem } from '@patternfly/react-core';
|
import { Alert, ToolbarItem } from '@patternfly/react-core';
|
||||||
import { CredentialsAPI, CredentialTypesAPI } from 'api';
|
import { CredentialsAPI, CredentialTypesAPI } from 'api';
|
||||||
import { getSearchableKeys } from 'components/PaginatedTable';
|
import { getSearchableKeys } from 'components/PaginatedTable';
|
||||||
import { getQSConfig, parseQueryString } from 'util/qs';
|
import { getQSConfig, parseQueryString, updateQueryString } from 'util/qs';
|
||||||
import useRequest from 'hooks/useRequest';
|
import useRequest from 'hooks/useRequest';
|
||||||
import AnsibleSelect from '../../AnsibleSelect';
|
import AnsibleSelect from '../../AnsibleSelect';
|
||||||
import OptionsList from '../../OptionsList';
|
import OptionsList from '../../OptionsList';
|
||||||
@@ -31,18 +31,18 @@ function CredentialsStep({
|
|||||||
allowCredentialsWithPasswords,
|
allowCredentialsWithPasswords,
|
||||||
defaultCredentials = [],
|
defaultCredentials = [],
|
||||||
}) {
|
}) {
|
||||||
|
const history = useHistory();
|
||||||
|
const location = useLocation();
|
||||||
const [field, meta, helpers] = useField({
|
const [field, meta, helpers] = useField({
|
||||||
name: 'credentials',
|
name: 'credentials',
|
||||||
validate: (val) =>
|
validate: (val) =>
|
||||||
credentialsValidator(
|
credentialsValidator(
|
||||||
allowCredentialsWithPasswords,
|
allowCredentialsWithPasswords,
|
||||||
val,
|
val,
|
||||||
defaultCredentials
|
defaultCredentials ?? []
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
const [selectedType, setSelectedType] = useState(null);
|
const [selectedType, setSelectedType] = useState(null);
|
||||||
const history = useHistory();
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
result: types,
|
result: types,
|
||||||
error: typesError,
|
error: typesError,
|
||||||
@@ -104,12 +104,32 @@ function CredentialsStep({
|
|||||||
credentialsValidator(
|
credentialsValidator(
|
||||||
allowCredentialsWithPasswords,
|
allowCredentialsWithPasswords,
|
||||||
field.value,
|
field.value,
|
||||||
defaultCredentials
|
defaultCredentials ?? []
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
/* eslint-disable-next-line react-hooks/exhaustive-deps */
|
/* eslint-disable-next-line react-hooks/exhaustive-deps */
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const removeAllSearchTerms = (qsConfig) => {
|
||||||
|
const oldParams = parseQueryString(qsConfig, location.search);
|
||||||
|
Object.keys(oldParams).forEach((key) => {
|
||||||
|
oldParams[key] = null;
|
||||||
|
});
|
||||||
|
const defaultParams = {
|
||||||
|
...oldParams,
|
||||||
|
page: 1,
|
||||||
|
page_size: 5,
|
||||||
|
order_by: 'name',
|
||||||
|
};
|
||||||
|
const qs = updateQueryString(qsConfig, location.search, defaultParams);
|
||||||
|
pushHistoryState(qs);
|
||||||
|
};
|
||||||
|
|
||||||
|
const pushHistoryState = (qs) => {
|
||||||
|
const { pathname } = history.location;
|
||||||
|
history.push(qs ? `${pathname}?${qs}` : pathname);
|
||||||
|
};
|
||||||
|
|
||||||
if (isTypesLoading) {
|
if (isTypesLoading) {
|
||||||
return <ContentLoading />;
|
return <ContentLoading />;
|
||||||
}
|
}
|
||||||
@@ -154,9 +174,7 @@ function CredentialsStep({
|
|||||||
value={selectedType && selectedType.id}
|
value={selectedType && selectedType.id}
|
||||||
onChange={(e, id) => {
|
onChange={(e, id) => {
|
||||||
// Reset query params when the category of credentials is changed
|
// Reset query params when the category of credentials is changed
|
||||||
history.replace({
|
removeAllSearchTerms(QS_CONFIG);
|
||||||
search: '',
|
|
||||||
});
|
|
||||||
setSelectedType(types.find((o) => o.id === parseInt(id, 10)));
|
setSelectedType(types.find((o) => o.id === parseInt(id, 10)));
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -168,7 +168,9 @@ describe('CredentialsStep', () => {
|
|||||||
test('should reset query params (credential.page) when selected credential type is changed', async () => {
|
test('should reset query params (credential.page) when selected credential type is changed', async () => {
|
||||||
let wrapper;
|
let wrapper;
|
||||||
const history = createMemoryHistory({
|
const history = createMemoryHistory({
|
||||||
initialEntries: ['?credential.page=2'],
|
initialEntries: [
|
||||||
|
'?credential.page=2&credential.page_size=5&credential.order_by=name',
|
||||||
|
],
|
||||||
});
|
});
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
wrapper = mountWithContexts(
|
wrapper = mountWithContexts(
|
||||||
|
|||||||
@@ -46,7 +46,8 @@ export default function useLaunchSteps(
|
|||||||
surveyConfig,
|
surveyConfig,
|
||||||
resource,
|
resource,
|
||||||
labels,
|
labels,
|
||||||
instanceGroups
|
instanceGroups,
|
||||||
|
resourceDefaultCredentials
|
||||||
) {
|
) {
|
||||||
const [visited, setVisited] = useState({});
|
const [visited, setVisited] = useState({});
|
||||||
const [isReady, setIsReady] = useState(false);
|
const [isReady, setIsReady] = useState(false);
|
||||||
@@ -56,7 +57,7 @@ export default function useLaunchSteps(
|
|||||||
useCredentialsStep(
|
useCredentialsStep(
|
||||||
launchConfig,
|
launchConfig,
|
||||||
resource,
|
resource,
|
||||||
resource.summary_fields.credentials || [],
|
resourceDefaultCredentials,
|
||||||
true
|
true
|
||||||
),
|
),
|
||||||
useCredentialPasswordsStep(
|
useCredentialPasswordsStep(
|
||||||
|
|||||||
Reference in New Issue
Block a user