mirror of
https://github.com/ansible/awx.git
synced 2026-05-06 08:57:35 -02:30
adds edit functionality
This commit is contained in:
@@ -6,6 +6,7 @@ import { t } from '@lingui/macro';
|
|||||||
import { useFormikContext } from 'formik';
|
import { useFormikContext } from 'formik';
|
||||||
import { withI18n } from '@lingui/react';
|
import { withI18n } from '@lingui/react';
|
||||||
import yaml from 'js-yaml';
|
import yaml from 'js-yaml';
|
||||||
|
import { parseVariableField } from '../../../util/yaml';
|
||||||
import mergeExtraVars, { maskPasswords } from '../mergeExtraVars';
|
import mergeExtraVars, { maskPasswords } from '../mergeExtraVars';
|
||||||
import getSurveyValues from '../getSurveyValues';
|
import getSurveyValues from '../getSurveyValues';
|
||||||
import PromptDetail from '../../PromptDetail';
|
import PromptDetail from '../../PromptDetail';
|
||||||
@@ -27,11 +28,12 @@ function PreviewStep({ resource, config, survey, formErrors, i18n }) {
|
|||||||
const { values } = useFormikContext();
|
const { values } = useFormikContext();
|
||||||
const surveyValues = getSurveyValues(values);
|
const surveyValues = getSurveyValues(values);
|
||||||
|
|
||||||
const overrides = { ...values };
|
const overrides = {
|
||||||
|
...values,
|
||||||
|
};
|
||||||
if (config.ask_variables_on_launch || config.survey_enabled) {
|
if (config.ask_variables_on_launch || config.survey_enabled) {
|
||||||
const initialExtraVars = config.ask_variables_on_launch
|
const initialExtraVars =
|
||||||
? overrides.extra_vars || '---'
|
config.ask_variables_on_launch && (overrides.extra_vars || '---');
|
||||||
: resource.extra_vars;
|
|
||||||
if (survey && survey.spec) {
|
if (survey && survey.spec) {
|
||||||
const passwordFields = survey.spec
|
const passwordFields = survey.spec
|
||||||
.filter(q => q.type === 'password')
|
.filter(q => q.type === 'password')
|
||||||
@@ -47,8 +49,8 @@ function PreviewStep({ resource, config, survey, formErrors, i18n }) {
|
|||||||
// Api expects extra vars to be merged with the survey data.
|
// Api expects extra vars to be merged with the survey data.
|
||||||
// We put the extra_data key/value pair on the values object here
|
// We put the extra_data key/value pair on the values object here
|
||||||
// so that we don't have to do this loop again inside of the NodeAddModal.jsx
|
// so that we don't have to do this loop again inside of the NodeAddModal.jsx
|
||||||
values.extra_data = overrides.extra_vars;
|
values.extra_data =
|
||||||
|
overrides.extra_vars && parseVariableField(overrides?.extra_vars);
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
{formErrors && (
|
{formErrors && (
|
||||||
|
|||||||
@@ -8,7 +8,13 @@ import StepName from './StepName';
|
|||||||
|
|
||||||
const STEP_ID = 'survey';
|
const STEP_ID = 'survey';
|
||||||
|
|
||||||
export default function useSurveyStep(config, i18n, visitedSteps, resource) {
|
export default function useSurveyStep(
|
||||||
|
config,
|
||||||
|
i18n,
|
||||||
|
visitedSteps,
|
||||||
|
resource,
|
||||||
|
nodeToEdit
|
||||||
|
) {
|
||||||
const { values } = useFormikContext();
|
const { values } = useFormikContext();
|
||||||
const { result: survey, request: fetchSurvey, isLoading, error } = useRequest(
|
const { result: survey, request: fetchSurvey, isLoading, error } = useRequest(
|
||||||
useCallback(async () => {
|
useCallback(async () => {
|
||||||
@@ -48,7 +54,7 @@ export default function useSurveyStep(config, i18n, visitedSteps, resource) {
|
|||||||
const formError = Object.keys(validate()).length > 0;
|
const formError = Object.keys(validate()).length > 0;
|
||||||
return {
|
return {
|
||||||
step: getStep(config, survey, validate, i18n, visitedSteps),
|
step: getStep(config, survey, validate, i18n, visitedSteps),
|
||||||
initialValues: getInitialValues(config, survey, resource),
|
initialValues: getInitialValues(config, survey, nodeToEdit),
|
||||||
validate,
|
validate,
|
||||||
survey,
|
survey,
|
||||||
isReady: !isLoading && !!survey,
|
isReady: !isLoading && !!survey,
|
||||||
@@ -113,7 +119,7 @@ function getStep(config, survey, validate, i18n, visitedSteps) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function getInitialValues(config, survey, resource) {
|
function getInitialValues(config, survey, nodeToEdit) {
|
||||||
if (!config.survey_enabled || !survey) {
|
if (!config.survey_enabled || !survey) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@@ -126,11 +132,11 @@ function getInitialValues(config, survey, resource) {
|
|||||||
} else {
|
} else {
|
||||||
values[`survey_${question.variable}`] = question.default;
|
values[`survey_${question.variable}`] = question.default;
|
||||||
}
|
}
|
||||||
if (resource?.extra_data) {
|
if (nodeToEdit?.extra_data) {
|
||||||
Object.entries(resource?.extra_data).forEach(([key, value]) => {
|
Object.entries(nodeToEdit?.extra_data).forEach(([key, value]) => {
|
||||||
if (key === question.variable) {
|
if (key === question.variable) {
|
||||||
if (question.type === 'multiselect') {
|
if (question.type === 'multiselect') {
|
||||||
values[`survey_${question.variable}`] = value.split('\n');
|
values[`survey_${question.variable}`] = value;
|
||||||
} else {
|
} else {
|
||||||
values[`survey_${question.variable}`] = value;
|
values[`survey_${question.variable}`] = value;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -143,7 +143,7 @@ function PromptDetail({ i18n, resource, launchConfig = {}, overrides = {} }) {
|
|||||||
value={toTitleCase(overrides.job_type)}
|
value={toTitleCase(overrides.job_type)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{overrides?.credentials && (
|
{overrides?.credentials?.length > 0 && (
|
||||||
<Detail
|
<Detail
|
||||||
fullWidth
|
fullWidth
|
||||||
label={i18n._(t`Credentials`)}
|
label={i18n._(t`Credentials`)}
|
||||||
|
|||||||
@@ -2,17 +2,37 @@ import React, { useContext } from 'react';
|
|||||||
import { withI18n } from '@lingui/react';
|
import { withI18n } from '@lingui/react';
|
||||||
import { t } from '@lingui/macro';
|
import { t } from '@lingui/macro';
|
||||||
import { WorkflowDispatchContext } from '../../../../../contexts/Workflow';
|
import { WorkflowDispatchContext } from '../../../../../contexts/Workflow';
|
||||||
|
import { getAddedAndRemoved } from '../../../../../util/lists';
|
||||||
import NodeModal from './NodeModal';
|
import NodeModal from './NodeModal';
|
||||||
|
|
||||||
function NodeEditModal({ i18n }) {
|
function NodeEditModal({ i18n }) {
|
||||||
const dispatch = useContext(WorkflowDispatchContext);
|
const dispatch = useContext(WorkflowDispatchContext);
|
||||||
|
|
||||||
const updateNode = resource => {
|
const updateNode = (values, linkType, config) => {
|
||||||
|
const { added, removed } = getAddedAndRemoved(
|
||||||
|
config?.defaults?.credentials,
|
||||||
|
values?.credentials
|
||||||
|
);
|
||||||
|
if (added?.length > 0) {
|
||||||
|
values.addedCredentals = added;
|
||||||
|
}
|
||||||
|
if (removed?.length > 0) {
|
||||||
|
values.removedCredentals = removed;
|
||||||
|
}
|
||||||
|
values.inventory = values?.inventory?.id;
|
||||||
|
delete values.linkType;
|
||||||
|
const node = {
|
||||||
|
nodeResource: values.nodeResource,
|
||||||
|
};
|
||||||
|
if (
|
||||||
|
values?.nodeType === 'job_template' ||
|
||||||
|
values?.nodeType === 'workflow_job_template'
|
||||||
|
) {
|
||||||
|
node.promptValues = values;
|
||||||
|
}
|
||||||
dispatch({
|
dispatch({
|
||||||
type: 'UPDATE_NODE',
|
type: 'UPDATE_NODE',
|
||||||
node: {
|
node,
|
||||||
nodeResource: resource,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -49,11 +49,7 @@ function NodeModalForm({ askLinkType, i18n, onSave, title, credentialError }) {
|
|||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
const dispatch = useContext(WorkflowDispatchContext);
|
const dispatch = useContext(WorkflowDispatchContext);
|
||||||
const { nodeToEdit } = useContext(WorkflowStateContext);
|
const { nodeToEdit } = useContext(WorkflowStateContext);
|
||||||
const {
|
const { values, setTouched, validateForm } = useFormikContext();
|
||||||
values,
|
|
||||||
setTouched,
|
|
||||||
validateForm,
|
|
||||||
} = useFormikContext();
|
|
||||||
|
|
||||||
const [triggerNext, setTriggerNext] = useState(0);
|
const [triggerNext, setTriggerNext] = useState(0);
|
||||||
|
|
||||||
@@ -149,7 +145,11 @@ function NodeModalForm({ askLinkType, i18n, onSave, title, credentialError }) {
|
|||||||
},
|
},
|
||||||
]),
|
]),
|
||||||
];
|
];
|
||||||
|
const nextButtonText = activeStep =>
|
||||||
|
activeStep.id === steps[steps?.length - 1]?.id ||
|
||||||
|
activeStep.name === 'Preview'
|
||||||
|
? i18n._(t`Save`)
|
||||||
|
: i18n._(t`Next`);
|
||||||
const CustomFooter = (
|
const CustomFooter = (
|
||||||
<WizardFooter>
|
<WizardFooter>
|
||||||
<WizardContextConsumer>
|
<WizardContextConsumer>
|
||||||
@@ -158,23 +158,25 @@ function NodeModalForm({ askLinkType, i18n, onSave, title, credentialError }) {
|
|||||||
<NodeNextButton
|
<NodeNextButton
|
||||||
triggerNext={triggerNext}
|
triggerNext={triggerNext}
|
||||||
activeStep={activeStep}
|
activeStep={activeStep}
|
||||||
|
aria-label={nextButtonText(activeStep)}
|
||||||
onNext={onNext}
|
onNext={onNext}
|
||||||
onClick={() => setTriggerNext(triggerNext + 1)}
|
onClick={() => setTriggerNext(triggerNext + 1)}
|
||||||
buttonText={
|
buttonText={nextButtonText(activeStep)}
|
||||||
activeStep.id === steps[steps?.length - 1]?.id ||
|
|
||||||
activeStep.name === 'Preview'
|
|
||||||
? i18n._(t`Save`)
|
|
||||||
: i18n._(t`Next`)
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
{activeStep && activeStep.id !== steps[0]?.id && (
|
{activeStep && activeStep.id !== steps[0]?.id && (
|
||||||
<Button id="back-node-modal" variant="secondary" onClick={onBack}>
|
<Button
|
||||||
|
id="back-node-modal"
|
||||||
|
variant="secondary"
|
||||||
|
aria-label={i18n._(t`Back`)}
|
||||||
|
onClick={onBack}
|
||||||
|
>
|
||||||
{i18n._(t`Back`)}
|
{i18n._(t`Back`)}
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
<Button
|
<Button
|
||||||
id="cancel-node-modal"
|
id="cancel-node-modal"
|
||||||
variant="link"
|
variant="link"
|
||||||
|
aria-label={i18n._(t`Cancel`)}
|
||||||
onClick={handleCancel}
|
onClick={handleCancel}
|
||||||
>
|
>
|
||||||
{i18n._(t`Cancel`)}
|
{i18n._(t`Cancel`)}
|
||||||
|
|||||||
@@ -5,19 +5,14 @@ import NodeTypeStep from './NodeTypeStep';
|
|||||||
|
|
||||||
const STEP_ID = 'nodeType';
|
const STEP_ID = 'nodeType';
|
||||||
|
|
||||||
export default function useNodeTypeStep(i18n, resource, nodeToEdit) {
|
export default function useNodeTypeStep(i18n, nodeToEdit) {
|
||||||
const [, meta] = useField('nodeType');
|
const [, meta] = useField('nodeType');
|
||||||
const [approvalNameField] = useField('approvalName');
|
const [approvalNameField] = useField('approvalName');
|
||||||
const [nodeTypeField, ,] = useField('nodeType');
|
const [nodeTypeField, ,] = useField('nodeType');
|
||||||
const [nodeResouceField] = useField('nodeResource');
|
const [nodeResouceField] = useField('nodeResource');
|
||||||
|
|
||||||
return {
|
return {
|
||||||
step: getStep(
|
step: getStep(i18n, nodeTypeField, approvalNameField, nodeResouceField),
|
||||||
i18n,
|
|
||||||
nodeTypeField,
|
|
||||||
approvalNameField,
|
|
||||||
nodeResouceField
|
|
||||||
),
|
|
||||||
initialValues: getInitialValues(nodeToEdit),
|
initialValues: getInitialValues(nodeToEdit),
|
||||||
isReady: true,
|
isReady: true,
|
||||||
contentError: null,
|
contentError: null,
|
||||||
@@ -29,12 +24,7 @@ export default function useNodeTypeStep(i18n, resource, nodeToEdit) {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
function getStep(
|
function getStep(i18n, nodeTypeField, approvalNameField, nodeResouceField) {
|
||||||
i18n,
|
|
||||||
nodeTypeField,
|
|
||||||
approvalNameField,
|
|
||||||
nodeResouceField
|
|
||||||
) {
|
|
||||||
const isEnabled = () => {
|
const isEnabled = () => {
|
||||||
if (
|
if (
|
||||||
(nodeTypeField.value !== 'approval' && nodeResouceField.value === null) ||
|
(nodeTypeField.value !== 'approval' && nodeResouceField.value === null) ||
|
||||||
|
|||||||
@@ -29,8 +29,15 @@ export default function useWorkflowNodeSteps(
|
|||||||
),
|
),
|
||||||
useCredentialsStep(config, i18n, resource, nodeToEdit?.originalNodeObject),
|
useCredentialsStep(config, i18n, resource, nodeToEdit?.originalNodeObject),
|
||||||
useOtherPromptsStep(config, i18n, resource, nodeToEdit?.originalNodeObject),
|
useOtherPromptsStep(config, i18n, resource, nodeToEdit?.originalNodeObject),
|
||||||
useSurveyStep(config, i18n, visited, resource),
|
useSurveyStep(
|
||||||
|
config,
|
||||||
|
i18n,
|
||||||
|
visited,
|
||||||
|
resource,
|
||||||
|
nodeToEdit?.originalNodeObject
|
||||||
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
const { resetForm, values: formikValues } = useFormikContext();
|
const { resetForm, values: formikValues } = useFormikContext();
|
||||||
const hasErrors = steps.some(step => step.formError);
|
const hasErrors = steps.some(step => step.formError);
|
||||||
const surveyStepIndex = steps.findIndex(step => step.survey);
|
const surveyStepIndex = steps.findIndex(step => step.survey);
|
||||||
@@ -66,10 +73,7 @@ export default function useWorkflowNodeSteps(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [
|
}, [config, isReady]);
|
||||||
config,
|
|
||||||
isReady,
|
|
||||||
]);
|
|
||||||
|
|
||||||
const stepWithError = steps.find(s => s.contentError);
|
const stepWithError = steps.find(s => s.contentError);
|
||||||
const contentError = stepWithError ? stepWithError.contentError : null;
|
const contentError = stepWithError ? stepWithError.contentError : null;
|
||||||
|
|||||||
Reference in New Issue
Block a user