Files
awx/awx/ui/src/components/LaunchPrompt/LaunchPrompt.js
mabashian e05eaeccab Fixes for various prompt related ui issues
Fixes bug where Forks showed up in both default values and prompted values in launch summary

Fixes prompting IGs with defaults on launch

Make job tags and skip tags full width on workflow form

Fixes bug where we attempted to fetch instance groups for workflows

Fetch default instance groups from jt/schedule for schedule form prompt

Grab default IGs when adding a node that prompts for them

Adds support for saving labels on a new wf node

Fix linting errors

Fixes for various prompt on launch related issues

Adds support for saving instance groups on a new node

Adds support for saving instance groups when editing an existing node

Fix workflowReducer test

Updates useSelected to handle a non-empty starting state

Fixes visualizerNode tests

Fix visualizer test

Second batch of prompt related ui issues:

Fixes bug saving existing node when instance groups is not promptable

Fixes bug removing newly added label

Adds onError function to label prompt

Fixes tooltips on the other prompts step

Properly fetch all labels to show on schedule details
2022-09-22 15:55:02 -04:00

227 lines
6.0 KiB
JavaScript

import React, { useState } from 'react';
import { ExpandableSection, Wizard } from '@patternfly/react-core';
import { t } from '@lingui/macro';
import { Formik, useFormikContext } from 'formik';
import { LabelsAPI, OrganizationsAPI } from 'api';
import { useDismissableError } from 'hooks/useRequest';
import mergeExtraVars from 'util/prompt/mergeExtraVars';
import getSurveyValues from 'util/prompt/getSurveyValues';
import ContentLoading from '../ContentLoading';
import ContentError from '../ContentError';
import useLaunchSteps from './useLaunchSteps';
import AlertModal from '../AlertModal';
function PromptModalForm({
launchConfig,
onCancel,
onSubmit,
resource,
labels,
surveyConfig,
instanceGroups,
}) {
const { setFieldTouched, values } = useFormikContext();
const [showDescription, setShowDescription] = useState(false);
const {
steps,
isReady,
validateStep,
visitStep,
visitAllSteps,
contentError,
} = useLaunchSteps(
launchConfig,
surveyConfig,
resource,
labels,
instanceGroups
);
const handleSubmit = async () => {
const postValues = {};
const setValue = (key, value) => {
if (typeof value !== 'undefined' && value !== null) {
postValues[key] = value;
}
};
const surveyValues = getSurveyValues(values);
setValue('credential_passwords', values.credential_passwords);
setValue('inventory_id', values.inventory?.id);
setValue(
'credentials',
values.credentials?.map((c) => c.id)
);
setValue('job_type', values.job_type);
setValue('limit', values.limit);
setValue('job_tags', values.job_tags);
setValue('skip_tags', values.skip_tags);
const extraVars = launchConfig.ask_variables_on_launch
? values.extra_vars || '---'
: resource.extra_vars;
setValue('extra_vars', mergeExtraVars(extraVars, surveyValues));
setValue('scm_branch', values.scm_branch);
setValue('verbosity', values.verbosity);
setValue('timeout', values.timeout);
setValue('forks', values.forks);
setValue('job_slice_count', values.job_slice_count);
setValue('execution_environment', values.execution_environment?.id);
if (launchConfig.ask_instance_groups_on_launch) {
const instanceGroupIds = [];
values.instance_groups.forEach((instance_group) => {
instanceGroupIds.push(instance_group.id);
});
setValue('instance_groups', instanceGroupIds);
}
if (launchConfig.ask_labels_on_launch) {
const labelIds = [];
const newLabels = [];
const labelRequests = [];
let organizationId = resource.organization;
values.labels.forEach((label) => {
if (typeof label.id !== 'number') {
newLabels.push(label);
} else {
labelIds.push(label.id);
}
});
if (newLabels.length > 0) {
if (!organizationId) {
// eslint-disable-next-line no-useless-catch
try {
const {
data: { results },
} = await OrganizationsAPI.read();
organizationId = results[0].id;
} catch (err) {
throw err;
}
}
}
newLabels.forEach((label) => {
labelRequests.push(
LabelsAPI.create({
name: label.name,
organization: organizationId,
}).then(({ data }) => {
labelIds.push(data.id);
})
);
});
await Promise.all(labelRequests);
setValue('labels', labelIds);
}
onSubmit(postValues);
};
const { error, dismissError } = useDismissableError(contentError);
if (error) {
return (
<AlertModal
isOpen={error}
variant="error"
title={t`Error!`}
onClose={() => {
dismissError();
}}
>
<ContentError error={error} />
</AlertModal>
);
}
return (
<Wizard
isOpen
onClose={onCancel}
onSave={handleSubmit}
onBack={async (nextStep) => {
validateStep(nextStep.id);
}}
onNext={async (nextStep, prevStep) => {
if (nextStep.id === 'preview') {
visitAllSteps(setFieldTouched);
} else {
visitStep(prevStep.prevId, setFieldTouched);
validateStep(nextStep.id);
}
}}
onGoToStep={async (nextStep, prevStep) => {
if (nextStep.id === 'preview') {
visitAllSteps(setFieldTouched);
} else {
visitStep(prevStep.prevId, setFieldTouched);
validateStep(nextStep.id);
}
}}
title={t`Launch | ${resource.name}`}
description={
resource.description.length > 512 ? (
<ExpandableSection
toggleText={
showDescription ? t`Hide description` : t`Show description`
}
onToggle={() => {
setShowDescription(!showDescription);
}}
isExpanded={showDescription}
>
{resource.description}
</ExpandableSection>
) : (
resource.description
)
}
steps={
isReady
? steps
: [
{
name: t`Content Loading`,
component: <ContentLoading />,
},
]
}
backButtonText={t`Back`}
cancelButtonText={t`Cancel`}
nextButtonText={t`Next`}
/>
);
}
function LaunchPrompt({
launchConfig,
onCancel,
onLaunch,
resource = {},
labels = [],
surveyConfig,
resourceDefaultCredentials = [],
instanceGroups = [],
}) {
return (
<Formik initialValues={{}} onSubmit={(values) => onLaunch(values)}>
<PromptModalForm
onSubmit={(values) => onLaunch(values)}
onCancel={onCancel}
launchConfig={launchConfig}
surveyConfig={surveyConfig}
resource={resource}
labels={labels}
resourceDefaultCredentials={resourceDefaultCredentials}
instanceGroups={instanceGroups}
/>
</Formik>
);
}
export { LaunchPrompt as _LaunchPrompt };
export default LaunchPrompt;