refactoring for adding modal

This commit is contained in:
Alex Corey
2020-10-14 15:49:08 -04:00
committed by mabashian
parent 20231041e6
commit 2545f14a93
10 changed files with 139 additions and 132 deletions

View File

@@ -107,16 +107,22 @@ function LaunchPrompt({ config, resource = {}, onLaunch, onCancel, i18n }) {
return ( return (
<Formik <Formik
initialValues={{ initialValues={{
verbosity: resource.verbosity || 0, verbosity: config.ask_verbosity_on_launch && (resource.verbosity || 0),
inventory: resource.summary_fields?.inventory || null, inventory:
credentials: resource.summary_fields?.credentials || null, config.ask_inventoryon_launch && resource.summary_fields?.inventory,
diff_mode: resource.diff_mode || false, credentials:
extra_vars: resource.extra_vars || '---', config.ask_credential_on_launch &&
job_type: resource.job_type || '', resource.summary_fields?.credentials,
job_tags: resource.job_tags || '', diff_mode:
skip_tags: resource.skip_tags || '', config.ask_diff_mode_on_launch && (resource.diff_mode || false),
scm_branch: resource.scm_branch || '', extra_vars:
limit: resource.limit || '', config.ask_variables_on_launch && (resource.extra_vars || '---'),
job_type: config.ask_job_type_on_launch && (resource.job_type || ''),
job_tags: config.ask_job_tags_on_launch && (resource.job_tags || ''),
skip_tags: config.ask_skip_tags_on_launch && (resource.skip_tags || ''),
scm_branch:
config.ask_scm_branch_on_launch && (resource.scm_branch || ''),
limit: config.ask_limit_on_launch && (resource.limit || ''),
}} }}
onSubmit={values => onLaunch(values)} onSubmit={values => onLaunch(values)}
> >

View File

@@ -1,20 +1,64 @@
import React from 'react'; import React, { useCallback, useEffect } from 'react';
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
import useRequest from '../../../util/useRequest';
import {
WorkflowJobTemplateNodesAPI,
JobTemplatesAPI,
WorkflowJobTemplatesAPI,
} from '../../../api';
import CredentialsStep from './CredentialsStep'; import CredentialsStep from './CredentialsStep';
const STEP_ID = 'credentials'; const STEP_ID = 'credentials';
export default function useCredentialsStep(config, i18n, resource) { export default function useCredentialsStep(
config,
i18n,
selectedResource,
nodeToEdit
) {
const resource = nodeToEdit || selectedResource;
const { request: fetchCredentials, result, error, isLoading } = useRequest(
useCallback(async () => {
let credentials;
if (!nodeToEdit?.related?.credentials) {
return {};
}
const {
data: { results },
} = await WorkflowJobTemplateNodesAPI.readCredentials(nodeToEdit.id);
credentials = results;
if (results.length === 0 && config?.defaults?.credentials) {
const fetchCreds = config.job_template_data
? JobTemplatesAPI.readDetail(config.job_template_data.id)
: WorkflowJobTemplatesAPI.readDetail(
config.workflow_job_template_data.id
);
const {
data: {
summary_fields: { credentials: defaultCreds },
},
} = await fetchCreds;
credentials = defaultCreds;
}
return credentials;
}, [nodeToEdit, config])
);
useEffect(() => {
fetchCredentials();
}, [fetchCredentials, nodeToEdit]);
const validate = () => { const validate = () => {
return {}; return {};
}; };
return { return {
step: getStep(config, i18n), step: getStep(config, i18n),
initialValues: getInitialValues(config, resource), initialValues: getInitialValues(config, resource, result),
validate, validate,
isReady: true, isReady: !isLoading && !!result,
contentError: null, contentError: error,
formError: null, formError: null,
setTouched: setFieldsTouched => { setTouched: setFieldsTouched => {
setFieldsTouched({ setFieldsTouched({
@@ -37,11 +81,11 @@ function getStep(config, i18n) {
}; };
} }
function getInitialValues(config, resource) { function getInitialValues(config, resource, result) {
if (!config.ask_credential_on_launch) { if (!config.ask_credential_on_launch) {
return {}; return {};
} }
return { return {
credentials: resource?.summary_fields?.credentials || [], credentials: resource?.summary_fields?.credentials || result || [],
}; };
} }

View File

@@ -6,8 +6,15 @@ import StepName from './StepName';
const STEP_ID = 'inventory'; const STEP_ID = 'inventory';
export default function useInventoryStep(config, i18n, visitedSteps, resource) { export default function useInventoryStep(
config,
i18n,
visitedSteps,
selectedResource,
nodeToEdit
) {
const [, meta] = useField('inventory'); const [, meta] = useField('inventory');
const resource = nodeToEdit || selectedResource;
const formError = const formError =
Object.keys(visitedSteps).includes(STEP_ID) && (!meta.value || meta.error); Object.keys(visitedSteps).includes(STEP_ID) && (!meta.value || meta.error);

View File

@@ -5,7 +5,13 @@ import OtherPromptsStep from './OtherPromptsStep';
const STEP_ID = 'other'; const STEP_ID = 'other';
export default function useOtherPrompt(config, i18n, resource) { export default function useOtherPrompt(
config,
i18n,
selectedResource,
nodeToEdit
) {
const resource = nodeToEdit || selectedResource;
return { return {
step: getStep(config, i18n), step: getStep(config, i18n),
initialValues: getInitialValues(config, resource), initialValues: getInitialValues(config, resource),

View File

@@ -12,7 +12,8 @@ export default function usePreviewStep(
hasErrors, hasErrors,
needsPreviewStep needsPreviewStep
) { ) {
const showStep = needsPreviewStep && resource && Object.keys(config).length > 0; const showStep =
needsPreviewStep && resource && Object.keys(config).length > 0;
return { return {
step: showStep step: showStep
? { ? {

View File

@@ -9,10 +9,10 @@ import usePreviewStep from './steps/usePreviewStep';
export default function useLaunchSteps(config, resource, i18n) { export default function useLaunchSteps(config, resource, i18n) {
const [visited, setVisited] = useState({}); const [visited, setVisited] = useState({});
const steps = [ const steps = [
useInventoryStep(config, i18n, visited ), useInventoryStep(config, i18n, visited),
useCredentialsStep(config, i18n), useCredentialsStep(config, i18n),
useOtherPromptsStep(config, i18n), useOtherPromptsStep(config, i18n),
useSurveyStep(config, i18n, visited ), useSurveyStep(config, i18n, visited),
]; ];
const { resetForm, values: formikValues } = useFormikContext(); const { resetForm, values: formikValues } = useFormikContext();
const hasErrors = steps.some(step => step.formError); const hasErrors = steps.some(step => step.formError);
@@ -25,7 +25,7 @@ export default function useLaunchSteps(config, resource, i18n) {
resource, resource,
steps[surveyStepIndex]?.survey, steps[surveyStepIndex]?.survey,
hasErrors, hasErrors,
true
) )
); );

View File

@@ -24,6 +24,7 @@ function NodeAddModal({ i18n }) {
values.addedCredentials = added; values.addedCredentials = added;
values.removedCredentials = removed; values.removedCredentials = removed;
} }
let node; let node;
if (values.nodeType === 'approval') { if (values.nodeType === 'approval') {
node = { node = {

View File

@@ -22,11 +22,7 @@ import {
WorkflowDispatchContext, WorkflowDispatchContext,
WorkflowStateContext, WorkflowStateContext,
} from '../../../../../contexts/Workflow'; } from '../../../../../contexts/Workflow';
import { import { JobTemplatesAPI, WorkflowJobTemplatesAPI } from '../../../../../api';
JobTemplatesAPI,
WorkflowJobTemplatesAPI,
WorkflowJobTemplateNodesAPI,
} from '../../../../../api';
import Wizard from '../../../../../components/Wizard'; import Wizard from '../../../../../components/Wizard';
import useWorkflowNodeSteps from './useWorkflowNodeSteps'; import useWorkflowNodeSteps from './useWorkflowNodeSteps';
import AlertModal from '../../../../../components/AlertModal'; import AlertModal from '../../../../../components/AlertModal';
@@ -57,8 +53,6 @@ function NodeModalForm({ askLinkType, i18n, onSave, title, credentialError }) {
values, values,
setTouched, setTouched,
validateForm, validateForm,
setFieldValue,
resetForm,
} = useFormikContext(); } = useFormikContext();
const [triggerNext, setTriggerNext] = useState(0); const [triggerNext, setTriggerNext] = useState(0);
@@ -72,21 +66,6 @@ function NodeModalForm({ askLinkType, i18n, onSave, title, credentialError }) {
); );
history.replace(`${history.location.pathname}?${otherParts.join('&')}`); history.replace(`${history.location.pathname}?${otherParts.join('&')}`);
}; };
useEffect(() => {
if (values?.nodeResource?.summary_fields?.credentials?.length > 0) {
setFieldValue(
'credentials',
values.nodeResource.summary_fields.credentials
);
}
if (nodeToEdit?.unified_job_type === 'workflow_job') {
setFieldValue('nodeType', 'workflow_job_template');
}
if (nodeToEdit?.unified_job_type === 'job') {
setFieldValue('nodeType', 'job_template');
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [nodeToEdit, values.nodeResource]);
const { const {
request: readLaunchConfig, request: readLaunchConfig,
@@ -120,6 +99,7 @@ function NodeModalForm({ askLinkType, i18n, onSave, title, credentialError }) {
return data; return data;
} }
} }
return {}; return {};
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [values.nodeResource, values.nodeType]), }, [values.nodeResource, values.nodeType]),
@@ -132,7 +112,6 @@ function NodeModalForm({ askLinkType, i18n, onSave, title, credentialError }) {
const { const {
steps: promptSteps, steps: promptSteps,
initialValues,
isReady, isReady,
visitStep, visitStep,
visitAllSteps, visitAllSteps,
@@ -142,7 +121,8 @@ function NodeModalForm({ askLinkType, i18n, onSave, title, credentialError }) {
i18n, i18n,
values.nodeResource, values.nodeResource,
askLinkType, askLinkType,
!canLaunchWithoutPrompt(values.nodeType, launchConfig) !canLaunchWithoutPrompt(values.nodeType, launchConfig),
nodeToEdit
); );
const handleSaveNode = () => { const handleSaveNode = () => {
@@ -158,21 +138,17 @@ function NodeModalForm({ askLinkType, i18n, onSave, title, credentialError }) {
const { error, dismissError } = useDismissableError( const { error, dismissError } = useDismissableError(
launchConfigError || contentError || credentialError launchConfigError || contentError || credentialError
); );
useEffect(() => {
if (isReady) { const steps = [
resetForm({ ...(isReady
values: { ? [...promptSteps]
...initialValues, : [
nodeResource: values.nodeResource, {
nodeType: values.nodeType || 'job_template', name: i18n._(t`Content Loading`),
linkType: values.linkType || 'success', component: <ContentLoading />,
verbosity: initialValues?.verbosity?.toString(), },
}, ]),
}); ];
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [launchConfig, values.nodeType, isReady, values.nodeResource]);
const steps = [...(isReady ? [...promptSteps] : [])];
const CustomFooter = ( const CustomFooter = (
<WizardFooter> <WizardFooter>
@@ -243,16 +219,7 @@ function NodeModalForm({ askLinkType, i18n, onSave, title, credentialError }) {
} }
await validateForm(); await validateForm();
}} }}
steps={ steps={steps}
isReady
? steps
: [
{
name: i18n._(t`Content Loading`),
component: <ContentLoading />,
},
]
}
css="overflow: scroll" css="overflow: scroll"
title={wizardTitle} title={wizardTitle}
onNext={async (nextStep, prevStep) => { onNext={async (nextStep, prevStep) => {
@@ -272,42 +239,13 @@ const NodeModal = ({ onSave, i18n, askLinkType, title }) => {
const onSaveForm = (values, linkType, config) => { const onSaveForm = (values, linkType, config) => {
onSave(values, linkType, config); onSave(values, linkType, config);
}; };
const { request: fetchCredentials, result, error } = useRequest(
useCallback(async () => {
const {
data: { results },
} = await WorkflowJobTemplateNodesAPI.readCredentials(
nodeToEdit.originalNodeObject.id
);
return results;
}, [nodeToEdit])
);
useEffect(() => {
if (nodeToEdit?.originalNodeObject?.related?.credentials) {
fetchCredentials();
}
}, [fetchCredentials, nodeToEdit]);
return ( return (
<Formik <Formik
initialValues={{ initialValues={{
linkType: 'success',
nodeResource: nodeResource:
nodeToEdit?.originalNodeObject?.summary_fields nodeToEdit?.originalNodeObject?.summary_fields
?.unified_job_template || null, ?.unified_job_template || null,
inventory:
nodeToEdit?.originalNodeObject?.summary_fields?.inventory || null,
credentials: result || null,
verbosity: nodeToEdit?.originalNodeObject?.verbosity || 0,
diff_mode: nodeToEdit?.originalNodeObject?.verbosty,
skip_tags: nodeToEdit?.originalNodeObject?.skip_tags || '',
job_tags: nodeToEdit?.originalNodeObject?.job_tags || '',
scm_branch:
nodeToEdit?.originalNodeObject?.scm_branch !== null
? nodeToEdit?.originalNodeObject?.scm_branch
: '',
job_type: nodeToEdit?.originalNodeObject?.job_type || 'run',
extra_vars: nodeToEdit?.originalNodeObject?.extra_vars || '---',
}} }}
onSave={() => onSaveForm} onSave={() => onSaveForm}
> >
@@ -317,7 +255,6 @@ const NodeModal = ({ onSave, i18n, askLinkType, title }) => {
onSave={onSaveForm} onSave={onSaveForm}
i18n={i18n} i18n={i18n}
title={title} title={title}
credentialError={error}
askLinkType={askLinkType} askLinkType={askLinkType}
/> />
</Form> </Form>

View File

@@ -5,7 +5,7 @@ import NodeTypeStep from './NodeTypeStep';
const STEP_ID = 'nodeType'; const STEP_ID = 'nodeType';
export default function useNodeTypeStep(i18n, resource) { export default function useNodeTypeStep(i18n, resource, 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');
@@ -13,13 +13,12 @@ export default function useNodeTypeStep(i18n, resource) {
return { return {
step: getStep( step: getStep(
meta,
i18n, i18n,
nodeTypeField, nodeTypeField,
approvalNameField, approvalNameField,
nodeResouceField nodeResouceField
), ),
initialValues: getInitialValues(resource), initialValues: getInitialValues(nodeToEdit),
isReady: true, isReady: true,
contentError: null, contentError: null,
formError: meta.error, formError: meta.error,
@@ -31,7 +30,6 @@ export default function useNodeTypeStep(i18n, resource) {
}; };
} }
function getStep( function getStep(
meta,
i18n, i18n,
nodeTypeField, nodeTypeField,
approvalNameField, approvalNameField,
@@ -56,24 +54,24 @@ function getStep(
}; };
} }
function getInitialValues(resource) { function getInitialValues(nodeToEdit) {
let typeOfNode; let typeOfNode;
if ( if (
!resource?.unifiedJobTemplate?.type && !nodeToEdit?.unifiedJobTemplate?.type &&
!resource?.unifiedJobTemplate?.unified_job_type !nodeToEdit?.unifiedJobTemplate?.unified_job_type
) { ) {
return { nodeType: 'job_template' }; return { nodeType: 'job_template' };
} }
const { const {
unifiedJobTemplate: { type, unified_job_type }, unifiedJobTemplate: { type, unified_job_type },
} = resource; } = nodeToEdit;
const unifiedType = type || unified_job_type; const unifiedType = type || unified_job_type;
if (unifiedType === 'job' || unifiedType === 'job_template') if (unifiedType === 'job' || unifiedType === 'job_template')
typeOfNode = { typeOfNode = {
nodeType: 'job_template', nodeType: 'job_template',
nodeResource: nodeResource:
resource.originalNodeObject.summary_fields.unified_job_template, nodeToEdit.originalNodeObject.summary_fields.unified_job_template,
}; };
if (unifiedType === 'project' || unifiedType === 'project_update') { if (unifiedType === 'project' || unifiedType === 'project_update') {
typeOfNode = { nodeType: 'project_sync' }; typeOfNode = { nodeType: 'project_sync' };
@@ -88,7 +86,9 @@ function getInitialValues(resource) {
unifiedType === 'workflow_job' || unifiedType === 'workflow_job' ||
unifiedType === 'workflow_job_template' unifiedType === 'workflow_job_template'
) { ) {
typeOfNode = { nodeType: 'workflow_job_template' }; typeOfNode = {
nodeType: 'workflow_job_template',
};
} }
if ( if (
unifiedType === 'workflow_approval_template' || unifiedType === 'workflow_approval_template' ||

View File

@@ -1,10 +1,5 @@
import { import { useState, useEffect } from 'react';
useState, import { useFormikContext } from 'formik';
useEffect
} from 'react';
import {
useFormikContext
} from 'formik';
import useInventoryStep from '../../../../../components/LaunchPrompt/steps/useInventoryStep'; import useInventoryStep from '../../../../../components/LaunchPrompt/steps/useInventoryStep';
import useCredentialsStep from '../../../../../components/LaunchPrompt/steps/useCredentialsStep'; import useCredentialsStep from '../../../../../components/LaunchPrompt/steps/useCredentialsStep';
import useOtherPromptsStep from '../../../../../components/LaunchPrompt/steps/useOtherPromptsStep'; import useOtherPromptsStep from '../../../../../components/LaunchPrompt/steps/useOtherPromptsStep';
@@ -18,21 +13,25 @@ export default function useWorkflowNodeSteps(
i18n, i18n,
resource, resource,
askLinkType, askLinkType,
needsPreviewStep needsPreviewStep,
nodeToEdit
) { ) {
const [visited, setVisited] = useState({}); const [visited, setVisited] = useState({});
const steps = [ const steps = [
useRunTypeStep(i18n, askLinkType), useRunTypeStep(i18n, askLinkType),
useNodeTypeStep(i18n, resource), useNodeTypeStep(i18n, nodeToEdit),
useInventoryStep(config, i18n, visited, resource), useInventoryStep(
useCredentialsStep(config, i18n, resource), config,
useOtherPromptsStep(config, i18n, resource), i18n,
visited,
resource,
nodeToEdit?.originalNodeObject
),
useCredentialsStep(config, i18n, resource, nodeToEdit?.originalNodeObject),
useOtherPromptsStep(config, i18n, resource, nodeToEdit?.originalNodeObject),
useSurveyStep(config, i18n, visited, resource), useSurveyStep(config, i18n, visited, resource),
]; ];
const { const { resetForm, values: formikValues } = useFormikContext();
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);
steps.push( steps.push(
@@ -55,16 +54,22 @@ export default function useWorkflowNodeSteps(
}; };
}, {}); }, {});
useEffect(() => { useEffect(() => {
if (surveyStepIndex > -1 && isReady) { if (isReady) {
resetForm({ resetForm({
values: { values: {
...formikValues, ...initialValues,
...steps[surveyStepIndex].initialValues, nodeResource: formikValues.nodeResource,
nodeType: formikValues.nodeType || initialValues.nodeType,
linkType: formikValues.linkType || 'success',
verbosity: initialValues?.verbosity?.toString(),
}, },
}); });
} }
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [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;