Change ask_job_slicing_on_launch to ask_job_slice_count_on_launch to match api

Adds support for prompting labels on launch in the UI

Fix execution environment prompting in UI

Round out support for prompting all the things on JT launch

Adds timeout to job details

Adds fetchAllLabels to JT/WFJT data models

Moves labels methods out to a mixin so they can be shared across JTs/WFJTs/Schedules

Fixes bug where ee was not being sent on launch

Adds the ability to prompt for ee's, ig's, labels, timeout and job slicing to schedules

Fixes bug where saving schedule form without opening the prompt would throw errors

Adds support for IGs and labels to workflow node prompting

Adds support for label prompting to node modal

Fix job template form tests
This commit is contained in:
mabashian
2022-08-17 10:57:30 -04:00
committed by Alan Rominger
parent 33c0fb79d6
commit 4e665ca77f
27 changed files with 556 additions and 69 deletions

View File

@@ -0,0 +1,35 @@
const LabelsMixin = (parent) =>
class extends parent {
readLabels(id, params) {
return this.http.get(`${this.baseUrl}${id}/labels/`, {
params,
});
}
readAllLabels(id) {
const fetchLabels = async (pageNo = 1, labels = []) => {
try {
const { data } = await this.http.get(`${this.baseUrl}${id}/labels/`, {
params: {
page: pageNo,
page_size: 200,
},
});
if (data?.next) {
return fetchLabels(pageNo + 1, labels.concat(data.results));
}
return Promise.resolve({
data: {
results: labels.concat(data.results),
},
});
} catch (error) {
return Promise.reject(error);
}
};
return fetchLabels();
}
};
export default LabelsMixin;

View File

@@ -1,10 +1,11 @@
import Base from '../Base'; import Base from '../Base';
import NotificationsMixin from '../mixins/Notifications.mixin'; import NotificationsMixin from '../mixins/Notifications.mixin';
import InstanceGroupsMixin from '../mixins/InstanceGroups.mixin'; import InstanceGroupsMixin from '../mixins/InstanceGroups.mixin';
import LabelsMixin from '../mixins/Labels.mixin';
import SchedulesMixin from '../mixins/Schedules.mixin'; import SchedulesMixin from '../mixins/Schedules.mixin';
class JobTemplates extends SchedulesMixin( class JobTemplates extends SchedulesMixin(
InstanceGroupsMixin(NotificationsMixin(Base)) InstanceGroupsMixin(NotificationsMixin(LabelsMixin(Base)))
) { ) {
constructor(http) { constructor(http) {
super(http); super(http);

View File

@@ -1,6 +1,7 @@
import Base from '../Base'; import Base from '../Base';
import LabelsMixin from '../mixins/Labels.mixin';
class Schedules extends Base { class Schedules extends LabelsMixin(Base) {
constructor(http) { constructor(http) {
super(http); super(http);
this.baseUrl = 'api/v2/schedules/'; this.baseUrl = 'api/v2/schedules/';

View File

@@ -1,8 +1,11 @@
import Base from '../Base'; import Base from '../Base';
import SchedulesMixin from '../mixins/Schedules.mixin'; import SchedulesMixin from '../mixins/Schedules.mixin';
import NotificationsMixin from '../mixins/Notifications.mixin'; import NotificationsMixin from '../mixins/Notifications.mixin';
import LabelsMixin from '../mixins/Labels.mixin';
class WorkflowJobTemplates extends SchedulesMixin(NotificationsMixin(Base)) { class WorkflowJobTemplates extends SchedulesMixin(
NotificationsMixin(LabelsMixin(Base))
) {
constructor(http) { constructor(http) {
super(http); super(http);
this.baseUrl = 'api/v2/workflow_job_templates/'; this.baseUrl = 'api/v2/workflow_job_templates/';

View File

@@ -1,9 +1,7 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import { useHistory } from 'react-router-dom'; import { useHistory } from 'react-router-dom';
import { number, shape } from 'prop-types'; import { number, shape } from 'prop-types';
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
import { import {
AdHocCommandsAPI, AdHocCommandsAPI,
InventorySourcesAPI, InventorySourcesAPI,
@@ -27,7 +25,7 @@ function canLaunchWithoutPrompt(launchData) {
!launchData.ask_execution_environment_on_launch && !launchData.ask_execution_environment_on_launch &&
!launchData.ask_labels_on_launch && !launchData.ask_labels_on_launch &&
!launchData.ask_forks_on_launch && !launchData.ask_forks_on_launch &&
!launchData.ask_job_slicing_on_launch && !launchData.ask_job_slice_count_on_launch &&
!launchData.ask_timeout_on_launch && !launchData.ask_timeout_on_launch &&
!launchData.ask_instance_groups_on_launch && !launchData.ask_instance_groups_on_launch &&
!launchData.survey_enabled && !launchData.survey_enabled &&
@@ -43,6 +41,7 @@ function LaunchButton({ resource, children }) {
const [showLaunchPrompt, setShowLaunchPrompt] = useState(false); const [showLaunchPrompt, setShowLaunchPrompt] = useState(false);
const [launchConfig, setLaunchConfig] = useState(null); const [launchConfig, setLaunchConfig] = useState(null);
const [surveyConfig, setSurveyConfig] = useState(null); const [surveyConfig, setSurveyConfig] = useState(null);
const [labels, setLabels] = useState([]);
const [isLaunching, setIsLaunching] = useState(false); const [isLaunching, setIsLaunching] = useState(false);
const [error, setError] = useState(null); const [error, setError] = useState(null);
@@ -56,6 +55,11 @@ function LaunchButton({ resource, children }) {
resource.type === 'workflow_job_template' resource.type === 'workflow_job_template'
? WorkflowJobTemplatesAPI.readSurvey(resource.id) ? WorkflowJobTemplatesAPI.readSurvey(resource.id)
: JobTemplatesAPI.readSurvey(resource.id); : JobTemplatesAPI.readSurvey(resource.id);
const readLabels =
resource.type === 'workflow_job_template'
? WorkflowJobTemplatesAPI.readAllLabels(resource.id)
: JobTemplatesAPI.readAllLabels(resource.id);
try { try {
const { data: launch } = await readLaunch; const { data: launch } = await readLaunch;
setLaunchConfig(launch); setLaunchConfig(launch);
@@ -66,6 +70,14 @@ function LaunchButton({ resource, children }) {
setSurveyConfig(data); setSurveyConfig(data);
} }
if (launch.ask_labels_on_launch) {
const {
data: { results },
} = await readLabels;
setLabels(results);
}
if (canLaunchWithoutPrompt(launch)) { if (canLaunchWithoutPrompt(launch)) {
await launchWithParams({}); await launchWithParams({});
} else { } else {
@@ -177,6 +189,7 @@ function LaunchButton({ resource, children }) {
launchConfig={launchConfig} launchConfig={launchConfig}
surveyConfig={surveyConfig} surveyConfig={surveyConfig}
resource={resource} resource={resource}
labels={labels}
onLaunch={launchWithParams} onLaunch={launchWithParams}
onCancel={() => setShowLaunchPrompt(false)} onCancel={() => setShowLaunchPrompt(false)}
/> />

View File

@@ -2,6 +2,7 @@ import React, { useState } from 'react';
import { ExpandableSection, Wizard } from '@patternfly/react-core'; import { ExpandableSection, Wizard } from '@patternfly/react-core';
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
import { Formik, useFormikContext } from 'formik'; import { Formik, useFormikContext } from 'formik';
import { LabelsAPI, OrganizationsAPI } from 'api';
import { useDismissableError } from 'hooks/useRequest'; import { useDismissableError } from 'hooks/useRequest';
import mergeExtraVars from 'util/prompt/mergeExtraVars'; import mergeExtraVars from 'util/prompt/mergeExtraVars';
import getSurveyValues from 'util/prompt/getSurveyValues'; import getSurveyValues from 'util/prompt/getSurveyValues';
@@ -15,6 +16,7 @@ function PromptModalForm({
onCancel, onCancel,
onSubmit, onSubmit,
resource, resource,
labels,
surveyConfig, surveyConfig,
}) { }) {
const { setFieldTouched, values } = useFormikContext(); const { setFieldTouched, values } = useFormikContext();
@@ -27,9 +29,9 @@ function PromptModalForm({
visitStep, visitStep,
visitAllSteps, visitAllSteps,
contentError, contentError,
} = useLaunchSteps(launchConfig, surveyConfig, resource); } = useLaunchSteps(launchConfig, surveyConfig, resource, labels);
const handleSubmit = () => { const handleSubmit = async () => {
const postValues = {}; const postValues = {};
const setValue = (key, value) => { const setValue = (key, value) => {
if (typeof value !== 'undefined' && value !== null) { if (typeof value !== 'undefined' && value !== null) {
@@ -53,6 +55,61 @@ function PromptModalForm({
setValue('extra_vars', mergeExtraVars(extraVars, surveyValues)); setValue('extra_vars', mergeExtraVars(extraVars, surveyValues));
setValue('scm_branch', values.scm_branch); setValue('scm_branch', values.scm_branch);
setValue('verbosity', values.verbosity); 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); onSubmit(postValues);
}; };
@@ -137,6 +194,7 @@ function LaunchPrompt({
onCancel, onCancel,
onLaunch, onLaunch,
resource = {}, resource = {},
labels = [],
surveyConfig, surveyConfig,
resourceDefaultCredentials = [], resourceDefaultCredentials = [],
}) { }) {
@@ -148,6 +206,7 @@ function LaunchPrompt({
launchConfig={launchConfig} launchConfig={launchConfig}
surveyConfig={surveyConfig} surveyConfig={surveyConfig}
resource={resource} resource={resource}
labels={labels}
resourceDefaultCredentials={resourceDefaultCredentials} resourceDefaultCredentials={resourceDefaultCredentials}
/> />
</Formik> </Formik>

View File

@@ -108,7 +108,7 @@ function ExecutionEnvironmentStep() {
qsConfig={QS_CONFIG} qsConfig={QS_CONFIG}
readOnly readOnly
selectItem={helpers.setValue} selectItem={helpers.setValue}
deselectItem={() => field.onChange(null)} deselectItem={() => helpers.setValue(null)}
/> />
); );
} }

View File

@@ -0,0 +1,106 @@
import React, { useCallback, useEffect } from 'react';
import { useHistory } from 'react-router-dom';
import { t } from '@lingui/macro';
import { useField } from 'formik';
import { InstanceGroupsAPI } from 'api';
import { getSearchableKeys } from 'components/PaginatedTable';
import { getQSConfig, parseQueryString } from 'util/qs';
import useRequest from 'hooks/useRequest';
import useSelected from 'hooks/useSelected';
import OptionsList from '../../OptionsList';
import ContentLoading from '../../ContentLoading';
import ContentError from '../../ContentError';
const QS_CONFIG = getQSConfig('instance-groups', {
page: 1,
page_size: 5,
order_by: 'name',
});
function InstanceGroupsStep() {
const [field, , helpers] = useField('instance_groups');
const { selected, handleSelect, setSelected } = useSelected([]);
const history = useHistory();
const {
result: { instance_groups, count, relatedSearchableKeys, searchableKeys },
request: fetchInstanceGroups,
error,
isLoading,
} = useRequest(
useCallback(async () => {
const params = parseQueryString(QS_CONFIG, history.location.search);
const [{ data }, actionsResponse] = await Promise.all([
InstanceGroupsAPI.read(params),
InstanceGroupsAPI.readOptions(),
]);
return {
instance_groups: data.results,
count: data.count,
relatedSearchableKeys: (
actionsResponse?.data?.related_search_fields || []
).map((val) => val.slice(0, -8)),
searchableKeys: getSearchableKeys(actionsResponse.data.actions?.GET),
};
}, [history.location]),
{
instance_groups: [],
count: 0,
relatedSearchableKeys: [],
searchableKeys: [],
}
);
useEffect(() => {
fetchInstanceGroups();
}, [fetchInstanceGroups]);
useEffect(() => {
helpers.setValue(selected);
}, [selected]); // eslint-disable-line react-hooks/exhaustive-deps
if (isLoading) {
return <ContentLoading />;
}
if (error) {
return <ContentError error={error} />;
}
return (
<OptionsList
value={field.value}
options={instance_groups}
optionCount={count}
searchColumns={[
{
name: t`Name`,
key: 'name__icontains',
isDefault: true,
},
{
name: t`Credential Name`,
key: 'credential__name__icontains',
},
]}
sortColumns={[
{
name: t`Name`,
key: 'name',
},
]}
searchableKeys={searchableKeys}
relatedSearchableKeys={relatedSearchableKeys}
multiple
header={t`Instance Groups`}
name="instanceGroups"
qsConfig={QS_CONFIG}
selectItem={handleSelect}
deselectItem={handleSelect}
sortSelectedItems={(selectedItems) => setSelected(selectedItems)}
isSelectedDraggable
/>
);
}
export default InstanceGroupsStep;

View File

@@ -1,9 +1,9 @@
import React from 'react'; import React from 'react';
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
import { useField } from 'formik'; import { useField } from 'formik';
import { Form, FormGroup, Switch } from '@patternfly/react-core'; import { Form, FormGroup, Switch } from '@patternfly/react-core';
import styled from 'styled-components'; import styled from 'styled-components';
import LabelSelect from '../../LabelSelect';
import FormField from '../../FormField'; import FormField from '../../FormField';
import { TagMultiSelect } from '../../MultiSelect'; import { TagMultiSelect } from '../../MultiSelect';
import AnsibleSelect from '../../AnsibleSelect'; import AnsibleSelect from '../../AnsibleSelect';
@@ -37,6 +37,7 @@ function OtherPromptsStep({ launchConfig, variablesMode, onVarModeChange }) {
tooltip={t`Select a branch for the workflow. This branch is applied to all job template nodes that prompt for a branch`} tooltip={t`Select a branch for the workflow. This branch is applied to all job template nodes that prompt for a branch`}
/> />
)} )}
{launchConfig.ask_labels_on_launch && <LabelsField />}
{launchConfig.ask_forks_on_launch && ( {launchConfig.ask_forks_on_launch && (
<FormField <FormField
id="prompt-forks" id="prompt-forks"
@@ -58,7 +59,7 @@ function OtherPromptsStep({ launchConfig, variablesMode, onVarModeChange }) {
/> />
)} )}
{launchConfig.ask_verbosity_on_launch && <VerbosityField />} {launchConfig.ask_verbosity_on_launch && <VerbosityField />}
{launchConfig.ask_job_slicing_on_launch && ( {launchConfig.ask_job_slice_count_on_launch && (
<FormField <FormField
id="prompt-job-slicing" id="prompt-job-slicing"
name="job_slice_count" name="job_slice_count"
@@ -213,4 +214,27 @@ function TagField({ id, name, label, tooltip }) {
); );
} }
function LabelsField() {
const [field, , helpers] = useField('labels');
return (
<FormGroup
fieldId="propmt-labels"
label={t`Labels`}
labelIcon={
<Popover
content={t`Optional labels that describe this job, such as 'dev' or 'test'. Labels can be used to group and filter completed jobs.`}
/>
}
>
<LabelSelect
value={field.value}
onChange={(labels) => helpers.setValue(labels)}
createText={t`Create`}
onError={() => alert('error')}
/>
</FormGroup>
);
}
export default OtherPromptsStep; export default OtherPromptsStep;

View File

@@ -19,7 +19,7 @@ export default function useExecutionEnvironmentStep(launchConfig, resource) {
}; };
} }
function getStep(launchConfig) { function getStep(launchConfig) {
if (!launchConfig.ask_inventory_on_launch) { if (!launchConfig.ask_execution_environment_on_launch) {
return null; return null;
} }
return { return {
@@ -40,6 +40,7 @@ function getInitialValues(launchConfig, resource) {
} }
return { return {
inventory: resource?.summary_fields?.execution_environment || null, execution_environment:
resource?.summary_fields?.execution_environment || null,
}; };
} }

View File

@@ -0,0 +1,45 @@
import React from 'react';
import { t } from '@lingui/macro';
import InstanceGroupsStep from './InstanceGroupsStep';
import StepName from './StepName';
const STEP_ID = 'instanceGroups';
export default function useInstanceGroupsStep(
launchConfig,
resource,
instanceGroups
) {
return {
step: getStep(launchConfig, resource),
initialValues: getInitialValues(launchConfig, instanceGroups),
isReady: true,
contentError: null,
hasError: false,
setTouched: (setFieldTouched) => {
setFieldTouched('instance_groups', true, false);
},
validate: () => {},
};
}
function getStep(launchConfig) {
if (!launchConfig.ask_instance_groups_on_launch) {
return null;
}
return {
id: STEP_ID,
name: <StepName id="instance-groups-step">{t`Instance Groups`}</StepName>,
component: <InstanceGroupsStep />,
enableNext: true,
};
}
function getInitialValues(launchConfig, instanceGroups) {
if (!launchConfig.ask_instance_groups_on_launch) {
return {};
}
return {
instance_groups: instanceGroups || [],
};
}

View File

@@ -31,9 +31,10 @@ const FIELD_NAMES = [
'timeout', 'timeout',
'job_slice_count', 'job_slice_count',
'forks', 'forks',
'labels',
]; ];
export default function useOtherPromptsStep(launchConfig, resource) { export default function useOtherPromptsStep(launchConfig, resource, labels) {
const [variablesField] = useField('extra_vars'); const [variablesField] = useField('extra_vars');
const [variablesMode, setVariablesMode] = useState(null); const [variablesMode, setVariablesMode] = useState(null);
const [isTouched, setIsTouched] = useState(false); const [isTouched, setIsTouched] = useState(false);
@@ -63,7 +64,7 @@ export default function useOtherPromptsStep(launchConfig, resource) {
return { return {
step: getStep(launchConfig, hasError, variablesMode, handleModeChange), step: getStep(launchConfig, hasError, variablesMode, handleModeChange),
initialValues: getInitialValues(launchConfig, resource), initialValues: getInitialValues(launchConfig, resource, labels),
isReady: true, isReady: true,
contentError: null, contentError: null,
hasError, hasError,
@@ -112,12 +113,12 @@ function shouldShowPrompt(launchConfig) {
launchConfig.ask_diff_mode_on_launch || launchConfig.ask_diff_mode_on_launch ||
launchConfig.ask_labels_on_launch || launchConfig.ask_labels_on_launch ||
launchConfig.ask_forks_on_launch || launchConfig.ask_forks_on_launch ||
launchConfig.ask_job_slicing_on_launch || launchConfig.ask_job_slice_count_on_launch ||
launchConfig.ask_timeout_on_launch launchConfig.ask_timeout_on_launch
); );
} }
function getInitialValues(launchConfig, resource) { function getInitialValues(launchConfig, resource, labels) {
const initialValues = {}; const initialValues = {};
if (!launchConfig) { if (!launchConfig) {
@@ -151,11 +152,14 @@ function getInitialValues(launchConfig, resource) {
if (launchConfig.ask_forks_on_launch) { if (launchConfig.ask_forks_on_launch) {
initialValues.forks = resource?.forks || 0; initialValues.forks = resource?.forks || 0;
} }
if (launchConfig.ask_job_slicing_on_launch) { if (launchConfig.ask_job_slice_count_on_launch) {
initialValues.job_slice_count = resource?.job_slice_count || 1; initialValues.job_slice_count = resource?.job_slice_count || 1;
} }
if (launchConfig.ask_timeout_on_launch) { if (launchConfig.ask_timeout_on_launch) {
initialValues.timeout = resource?.timeout || 0; initialValues.timeout = resource?.timeout || 0;
} }
if (launchConfig.ask_labels_on_launch) {
initialValues.labels = labels || [];
}
return initialValues; return initialValues;
} }

View File

@@ -7,6 +7,7 @@ import useExecutionEnvironmentStep from './steps/useExecutionEnvironmentStep';
import useOtherPromptsStep from './steps/useOtherPromptsStep'; import useOtherPromptsStep from './steps/useOtherPromptsStep';
import useSurveyStep from './steps/useSurveyStep'; import useSurveyStep from './steps/useSurveyStep';
import usePreviewStep from './steps/usePreviewStep'; import usePreviewStep from './steps/usePreviewStep';
import useInstanceGroupsStep from './steps/useInstanceGroupsStep';
function showCredentialPasswordsStep(launchConfig, credentials = []) { function showCredentialPasswordsStep(launchConfig, credentials = []) {
if ( if (
@@ -40,7 +41,12 @@ function showCredentialPasswordsStep(launchConfig, credentials = []) {
return credentialPasswordStepRequired; return credentialPasswordStepRequired;
} }
export default function useLaunchSteps(launchConfig, surveyConfig, resource) { export default function useLaunchSteps(
launchConfig,
surveyConfig,
resource,
labels
) {
const [visited, setVisited] = useState({}); const [visited, setVisited] = useState({});
const [isReady, setIsReady] = useState(false); const [isReady, setIsReady] = useState(false);
const { touched, values: formikValues } = useFormikContext(); const { touched, values: formikValues } = useFormikContext();
@@ -58,7 +64,8 @@ export default function useLaunchSteps(launchConfig, surveyConfig, resource) {
visited visited
), ),
useExecutionEnvironmentStep(launchConfig, resource), useExecutionEnvironmentStep(launchConfig, resource),
useOtherPromptsStep(launchConfig, resource), useInstanceGroupsStep(launchConfig, resource),
useOtherPromptsStep(launchConfig, resource, labels),
useSurveyStep(launchConfig, surveyConfig, resource, visited), useSurveyStep(launchConfig, surveyConfig, resource, visited),
]; ];
const { resetForm } = useFormikContext(); const { resetForm } = useFormikContext();
@@ -146,6 +153,7 @@ export default function useLaunchSteps(launchConfig, surveyConfig, resource) {
credentials: true, credentials: true,
credentialPasswords: true, credentialPasswords: true,
executionEnvironment: true, executionEnvironment: true,
instanceGroups: true,
other: true, other: true,
survey: true, survey: true,
preview: true, preview: true,

View File

@@ -75,7 +75,7 @@ function hasPromptData(launchData) {
launchData.ask_execution_environment_on_launch || launchData.ask_execution_environment_on_launch ||
launchData.ask_labels_on_launch || launchData.ask_labels_on_launch ||
launchData.ask_forks_on_launch || launchData.ask_forks_on_launch ||
launchData.ask_job_slicing_on_launch || launchData.ask_job_slice_count_on_launch ||
launchData.ask_timeout_on_launch || launchData.ask_timeout_on_launch ||
launchData.ask_instance_groups_on_launch launchData.ask_instance_groups_on_launch
); );
@@ -341,7 +341,7 @@ function PromptDetail({
{launchConfig.ask_forks_on_launch && ( {launchConfig.ask_forks_on_launch && (
<Detail label={t`Forks`} value={overrides.forks} /> <Detail label={t`Forks`} value={overrides.forks} />
)} )}
{launchConfig.ask_job_slicing_on_launch && ( {launchConfig.ask_job_slice_count_on_launch && (
<Detail <Detail
label={t`Job Slicing`} label={t`Job Slicing`}
value={overrides.job_slice_count} value={overrides.job_slice_count}

View File

@@ -1,12 +1,10 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import { func, shape } from 'prop-types'; import { func, shape } from 'prop-types';
import { useHistory, useLocation } from 'react-router-dom'; import { useHistory, useLocation } from 'react-router-dom';
import { Card } from '@patternfly/react-core'; import { Card } from '@patternfly/react-core';
import yaml from 'js-yaml'; import yaml from 'js-yaml';
import { parseVariableField } from 'util/yaml'; import { parseVariableField } from 'util/yaml';
import { LabelsAPI, OrganizationsAPI, SchedulesAPI } from 'api';
import { SchedulesAPI } from 'api';
import mergeExtraVars from 'util/prompt/mergeExtraVars'; import mergeExtraVars from 'util/prompt/mergeExtraVars';
import getSurveyValues from 'util/prompt/getSurveyValues'; import getSurveyValues from 'util/prompt/getSurveyValues';
import { getAddedAndRemoved } from 'util/lists'; import { getAddedAndRemoved } from 'util/lists';
@@ -34,6 +32,8 @@ function ScheduleAdd({
surveyConfiguration surveyConfiguration
) => { ) => {
const { const {
execution_environment,
instance_groups,
inventory, inventory,
frequency, frequency,
frequencyOptions, frequencyOptions,
@@ -72,7 +72,60 @@ function ScheduleAdd({
submitValues.inventory = inventory.id; submitValues.inventory = inventory.id;
} }
if (execution_environment) {
submitValues.execution_environment = execution_environment.id;
}
submitValues.instance_groups = instance_groups
? instance_groups.map((s) => s.id)
: [];
try { try {
if (launchConfiguration?.ask_labels_on_launch) {
const labelIds = [];
const newLabels = [];
const labelRequests = [];
let organizationId = resource.organization;
if (values.labels) {
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);
submitValues.labels = labelIds;
}
const ruleSet = buildRuleSet(values); const ruleSet = buildRuleSet(values);
const requestData = { const requestData = {
...submitValues, ...submitValues,

View File

@@ -193,7 +193,7 @@ function ScheduleDetail({ hasDaysToKeepField, schedule, surveyConfig }) {
ask_execution_environment_on_launch, ask_execution_environment_on_launch,
ask_labels_on_launch, ask_labels_on_launch,
ask_forks_on_launch, ask_forks_on_launch,
ask_job_slicing_on_launch, ask_job_slice_count_on_launch,
ask_timeout_on_launch, ask_timeout_on_launch,
survey_enabled, survey_enabled,
} = launchData || {}; } = launchData || {};
@@ -253,7 +253,7 @@ function ScheduleDetail({ hasDaysToKeepField, schedule, surveyConfig }) {
ask_execution_environment_on_launch && execution_environment; ask_execution_environment_on_launch && execution_environment;
const showLabelsDetail = ask_labels_on_launch && labels && labels.length > 0; const showLabelsDetail = ask_labels_on_launch && labels && labels.length > 0;
const showForksDetail = ask_forks_on_launch; const showForksDetail = ask_forks_on_launch;
const showJobSlicingDetail = ask_job_slicing_on_launch; const showJobSlicingDetail = ask_job_slice_count_on_launch;
const showTimeoutDetail = ask_timeout_on_launch; const showTimeoutDetail = ask_timeout_on_launch;
const showPromptedFields = const showPromptedFields =
@@ -468,7 +468,7 @@ function ScheduleDetail({ hasDaysToKeepField, schedule, surveyConfig }) {
dataCy="schedule-show-changes" dataCy="schedule-show-changes"
/> />
)} )}
{ask_job_slicing_on_launch && ( {ask_job_slice_count_on_launch && (
<Detail label={t`Job Slicing`} value={job_slice_count} /> <Detail label={t`Job Slicing`} value={job_slice_count} />
)} )}
{showCredentialsDetail && ( {showCredentialsDetail && (

View File

@@ -1,12 +1,10 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import { useHistory, useLocation } from 'react-router-dom'; import { useHistory, useLocation } from 'react-router-dom';
import { shape } from 'prop-types'; import { shape } from 'prop-types';
import { Card } from '@patternfly/react-core'; import { Card } from '@patternfly/react-core';
import yaml from 'js-yaml'; import yaml from 'js-yaml';
import { SchedulesAPI } from 'api'; import { LabelsAPI, OrganizationsAPI, SchedulesAPI } from 'api';
import { getAddedAndRemoved } from 'util/lists'; import { getAddedAndRemoved } from 'util/lists';
import { parseVariableField } from 'util/yaml'; import { parseVariableField } from 'util/yaml';
import mergeExtraVars from 'util/prompt/mergeExtraVars'; import mergeExtraVars from 'util/prompt/mergeExtraVars';
import getSurveyValues from 'util/prompt/getSurveyValues'; import getSurveyValues from 'util/prompt/getSurveyValues';
@@ -35,6 +33,8 @@ function ScheduleEdit({
scheduleCredentials = [] scheduleCredentials = []
) => { ) => {
const { const {
execution_environment,
instance_groups,
inventory, inventory,
credentials = [], credentials = [],
frequency, frequency,
@@ -82,7 +82,60 @@ function ScheduleEdit({
submitValues.inventory = inventory.id; submitValues.inventory = inventory.id;
} }
if (execution_environment) {
submitValues.execution_environment = execution_environment.id;
}
submitValues.instance_groups = instance_groups
? instance_groups.map((s) => s.id)
: [];
try { try {
if (launchConfiguration?.ask_labels_on_launch) {
const labelIds = [];
const newLabels = [];
const labelRequests = [];
let organizationId = resource.organization;
if (values.labels) {
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);
submitValues.labels = labelIds;
}
const ruleSet = buildRuleSet(values); const ruleSet = buildRuleSet(values);
const requestData = { const requestData = {
...submitValues, ...submitValues,

View File

@@ -1,13 +1,12 @@
import React, { useEffect, useCallback, useState } from 'react'; import React, { useEffect, useCallback, useState } from 'react';
import { shape, func } from 'prop-types'; import { shape, func } from 'prop-types';
import { DateTime } from 'luxon'; import { DateTime } from 'luxon';
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
import { Formik } from 'formik'; import { Formik } from 'formik';
import { RRule } from 'rrule'; import { RRule } from 'rrule';
import { Button, Form, ActionGroup } from '@patternfly/react-core'; import { Button, Form, ActionGroup } from '@patternfly/react-core';
import { Config } from 'contexts/Config'; import { Config } from 'contexts/Config';
import { SchedulesAPI } from 'api'; import { JobTemplatesAPI, SchedulesAPI, WorkflowJobTemplatesAPI } from 'api';
import { dateToInputDateTime } from 'util/dates'; import { dateToInputDateTime } from 'util/dates';
import useRequest from 'hooks/useRequest'; import useRequest from 'hooks/useRequest';
import { parseVariableField } from 'util/yaml'; import { parseVariableField } from 'util/yaml';
@@ -31,7 +30,7 @@ const NUM_DAYS_PER_FREQUENCY = {
function ScheduleForm({ function ScheduleForm({
hasDaysToKeepField, hasDaysToKeepField,
handleCancel, handleCancel,
handleSubmit, handleSubmit: submitSchedule,
schedule, schedule,
submitError, submitError,
resource, resource,
@@ -55,17 +54,48 @@ function ScheduleForm({
request: loadScheduleData, request: loadScheduleData,
error: contentError, error: contentError,
isLoading: contentLoading, isLoading: contentLoading,
result: { zoneOptions, zoneLinks, credentials }, result: { zoneOptions, zoneLinks, credentials, labels },
} = useRequest( } = useRequest(
useCallback(async () => { useCallback(async () => {
const { data } = await SchedulesAPI.readZoneInfo(); const { data } = await SchedulesAPI.readZoneInfo();
let creds; let creds;
let allLabels;
if (schedule.id) { if (schedule.id) {
const { if (
data: { results }, resource.type === 'job_template' &&
} = await SchedulesAPI.readCredentials(schedule.id); launchConfig.ask_credential_on_launch
creds = results; ) {
const {
data: { results },
} = await SchedulesAPI.readCredentials(schedule.id);
creds = results;
}
if (launchConfig.ask_labels_on_launch) {
const {
data: { results },
} = await SchedulesAPI.readAllLabels(schedule.id);
allLabels = results;
}
} else {
if (
resource.type === 'job_template' &&
launchConfig.ask_labels_on_launch
) {
const {
data: { results },
} = await JobTemplatesAPI.readAllLabels(resource.id);
allLabels = results;
}
if (
resource.type === 'workflow_job_template' &&
launchConfig.ask_labels_on_launch
) {
const {
data: { results },
} = await WorkflowJobTemplatesAPI.readAllLabels(resource.id);
allLabels = results;
}
} }
const zones = (data.zones || []).map((zone) => ({ const zones = (data.zones || []).map((zone) => ({
@@ -78,13 +108,21 @@ function ScheduleForm({
zoneOptions: zones, zoneOptions: zones,
zoneLinks: data.links, zoneLinks: data.links,
credentials: creds || [], credentials: creds || [],
labels: allLabels || [],
}; };
}, [schedule]), }, [
schedule,
resource.id,
resource.type,
launchConfig.ask_labels_on_launch,
launchConfig.ask_credential_on_launch,
]),
{ {
zonesOptions: [], zonesOptions: [],
zoneLinks: {}, zoneLinks: {},
credentials: [], credentials: [],
isLoading: true, isLoading: true,
labels: [],
} }
); );
@@ -228,7 +266,7 @@ function ScheduleForm({
launchConfig.ask_execution_environment_on_launch || launchConfig.ask_execution_environment_on_launch ||
launchConfig.ask_labels_on_launch || launchConfig.ask_labels_on_launch ||
launchConfig.ask_forks_on_launch || launchConfig.ask_forks_on_launch ||
launchConfig.ask_job_slicing_on_launch || launchConfig.ask_job_slice_count_on_launch ||
launchConfig.ask_timeout_on_launch || launchConfig.ask_timeout_on_launch ||
launchConfig.ask_instance_groups_on_launch || launchConfig.ask_instance_groups_on_launch ||
launchConfig.survey_enabled || launchConfig.survey_enabled ||
@@ -307,19 +345,6 @@ function ScheduleForm({
startTime: time, startTime: time,
timezone: schedule.timezone || now.zoneName, timezone: schedule.timezone || now.zoneName,
}; };
const submitSchedule = (
values,
launchConfiguration,
surveyConfiguration,
scheduleCredentials
) => {
handleSubmit(
values,
launchConfiguration,
surveyConfiguration,
scheduleCredentials
);
};
if (hasDaysToKeepField) { if (hasDaysToKeepField) {
let initialDaysToKeep = 30; let initialDaysToKeep = 30;
@@ -469,6 +494,7 @@ function ScheduleForm({
setIsSaveDisabled(false); setIsSaveDisabled(false);
}} }}
resourceDefaultCredentials={resourceDefaultCredentials} resourceDefaultCredentials={resourceDefaultCredentials}
labels={labels}
/> />
)} )}
<FormSubmitError error={submitError} /> <FormSubmitError error={submitError} />

View File

@@ -17,6 +17,7 @@ function SchedulePromptableFields({
credentials, credentials,
resource, resource,
resourceDefaultCredentials, resourceDefaultCredentials,
labels,
}) { }) {
const { setFieldTouched, values, initialValues, resetForm } = const { setFieldTouched, values, initialValues, resetForm } =
useFormikContext(); useFormikContext();
@@ -33,7 +34,8 @@ function SchedulePromptableFields({
schedule, schedule,
resource, resource,
credentials, credentials,
resourceDefaultCredentials resourceDefaultCredentials,
labels
); );
const [showDescription, setShowDescription] = useState(false); const [showDescription, setShowDescription] = useState(false);
const { error, dismissError } = useDismissableError(contentError); const { error, dismissError } = useDismissableError(contentError);

View File

@@ -3,6 +3,8 @@ import { useFormikContext } from 'formik';
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
import useInventoryStep from '../../LaunchPrompt/steps/useInventoryStep'; import useInventoryStep from '../../LaunchPrompt/steps/useInventoryStep';
import useCredentialsStep from '../../LaunchPrompt/steps/useCredentialsStep'; import useCredentialsStep from '../../LaunchPrompt/steps/useCredentialsStep';
import useExecutionEnvironmentStep from '../../LaunchPrompt/steps/useExecutionEnvironmentStep';
import useInstanceGroupsStep from '../../LaunchPrompt/steps/useInstanceGroupsStep';
import useOtherPromptsStep from '../../LaunchPrompt/steps/useOtherPromptsStep'; import useOtherPromptsStep from '../../LaunchPrompt/steps/useOtherPromptsStep';
import useSurveyStep from '../../LaunchPrompt/steps/useSurveyStep'; import useSurveyStep from '../../LaunchPrompt/steps/useSurveyStep';
import usePreviewStep from '../../LaunchPrompt/steps/usePreviewStep'; import usePreviewStep from '../../LaunchPrompt/steps/usePreviewStep';
@@ -12,9 +14,9 @@ export default function useSchedulePromptSteps(
launchConfig, launchConfig,
schedule, schedule,
resource, resource,
scheduleCredentials, scheduleCredentials,
resourceDefaultCredentials resourceDefaultCredentials,
labels
) { ) {
const sourceOfValues = const sourceOfValues =
(Object.keys(schedule).length > 0 && schedule) || resource; (Object.keys(schedule).length > 0 && schedule) || resource;
@@ -28,7 +30,9 @@ export default function useSchedulePromptSteps(
sourceOfValues, sourceOfValues,
resourceDefaultCredentials resourceDefaultCredentials
), ),
useOtherPromptsStep(launchConfig, sourceOfValues), useExecutionEnvironmentStep(launchConfig, resource),
useInstanceGroupsStep(launchConfig, resource),
useOtherPromptsStep(launchConfig, sourceOfValues, labels),
useSurveyStep(launchConfig, surveyConfig, sourceOfValues, visited), useSurveyStep(launchConfig, surveyConfig, sourceOfValues, visited),
]; ];
@@ -37,7 +41,6 @@ export default function useSchedulePromptSteps(
steps.push( steps.push(
usePreviewStep( usePreviewStep(
launchConfig, launchConfig,
resource, resource,
surveyConfig, surveyConfig,
hasErrors, hasErrors,
@@ -130,6 +133,8 @@ export default function useSchedulePromptSteps(
setVisited({ setVisited({
inventory: true, inventory: true,
credentials: true, credentials: true,
executionEnvironment: true,
instanceGroups: true,
other: true, other: true,
survey: true, survey: true,
preview: true, preview: true,

View File

@@ -391,6 +391,16 @@ function JobDetail({ job, inventorySourceLabels }) {
helpText={jobHelpText.forks} helpText={jobHelpText.forks}
/> />
)} )}
{typeof job.timeout === 'number' && (
<Detail
dataCy="timeout"
label={t`Timeout`}
value={
job.timeout ? t`${job.timeout} seconds` : t`No timeout specified`
}
helpText={jobHelpText.timeout}
/>
)}
{credential && ( {credential && (
<Detail <Detail
dataCy="job-machine-credential" dataCy="job-machine-credential"

View File

@@ -30,6 +30,12 @@ const jobTemplateData = {
ask_tags_on_launch: false, ask_tags_on_launch: false,
ask_variables_on_launch: false, ask_variables_on_launch: false,
ask_verbosity_on_launch: false, ask_verbosity_on_launch: false,
ask_execution_environment_on_launch: false,
ask_forks_on_launch: false,
ask_instance_groups_on_launch: false,
ask_job_slice_count_on_launch: false,
ask_labels_on_launch: false,
ask_timeout_on_launch: false,
become_enabled: false, become_enabled: false,
description: '', description: '',
diff_mode: false, diff_mode: false,

View File

@@ -43,6 +43,12 @@ const mockJobTemplate = {
ask_verbosity_on_launch: false, ask_verbosity_on_launch: false,
ask_inventory_on_launch: false, ask_inventory_on_launch: false,
ask_credential_on_launch: false, ask_credential_on_launch: false,
ask_execution_environment_on_launch: false,
ask_forks_on_launch: false,
ask_instance_groups_on_launch: false,
ask_job_slice_count_on_launch: false,
ask_labels_on_launch: false,
ask_timeout_on_launch: false,
become_enabled: false, become_enabled: false,
description: 'Bar', description: 'Bar',
diff_mode: false, diff_mode: false,

View File

@@ -38,6 +38,7 @@ function NodeModalForm({
surveyConfig, surveyConfig,
isLaunchLoading, isLaunchLoading,
resourceDefaultCredentials, resourceDefaultCredentials,
labels,
}) { }) {
const history = useHistory(); const history = useHistory();
const dispatch = useContext(WorkflowDispatchContext); const dispatch = useContext(WorkflowDispatchContext);
@@ -66,7 +67,8 @@ function NodeModalForm({
surveyConfig, surveyConfig,
values.nodeResource, values.nodeResource,
askLinkType, askLinkType,
resourceDefaultCredentials resourceDefaultCredentials,
labels
); );
const handleSaveNode = () => { const handleSaveNode = () => {
@@ -241,7 +243,7 @@ const NodeModalInner = ({ title, ...rest }) => {
const { const {
request: readLaunchConfigs, request: readLaunchConfigs,
error: launchConfigError, error: launchConfigError,
result: { launchConfig, surveyConfig, resourceDefaultCredentials }, result: { launchConfig, surveyConfig, resourceDefaultCredentials, labels },
isLoading, isLoading,
} = useRequest( } = useRequest(
useCallback(async () => { useCallback(async () => {
@@ -260,9 +262,15 @@ const NodeModalInner = ({ title, ...rest }) => {
launchConfig: {}, launchConfig: {},
surveyConfig: {}, surveyConfig: {},
resourceDefaultCredentials: [], resourceDefaultCredentials: [],
labels: [],
}; };
} }
const readLabels =
values.nodeType === 'workflow_job_template'
? WorkflowJobTemplatesAPI.readAllLabels(values.nodeResource.id)
: JobTemplatesAPI.readAllLabels(values.nodeResource.id);
const { data: launch } = await readLaunch( const { data: launch } = await readLaunch(
values.nodeType, values.nodeType,
values?.nodeResource?.id values?.nodeResource?.id
@@ -291,10 +299,21 @@ const NodeModalInner = ({ title, ...rest }) => {
defaultCredentials = results; defaultCredentials = results;
} }
let defaultLabels = [];
if (launch.ask_labels_on_launch) {
const {
data: { results },
} = await readLabels;
defaultLabels = results;
}
return { return {
launchConfig: launch, launchConfig: launch,
surveyConfig: survey, surveyConfig: survey,
resourceDefaultCredentials: defaultCredentials, resourceDefaultCredentials: defaultCredentials,
labels: defaultLabels,
}; };
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
@@ -347,11 +366,12 @@ const NodeModalInner = ({ title, ...rest }) => {
resourceDefaultCredentials={resourceDefaultCredentials} resourceDefaultCredentials={resourceDefaultCredentials}
isLaunchLoading={isLoading} isLaunchLoading={isLoading}
title={wizardTitle} title={wizardTitle}
labels={labels}
/> />
); );
}; };
const NodeModal = ({ onSave, askLinkType, title }) => { const NodeModal = ({ onSave, askLinkType, title, labels }) => {
const { nodeToEdit } = useContext(WorkflowStateContext); const { nodeToEdit } = useContext(WorkflowStateContext);
const onSaveForm = (values, config) => { const onSaveForm = (values, config) => {
onSave(values, config); onSave(values, config);
@@ -378,6 +398,7 @@ const NodeModal = ({ onSave, askLinkType, title }) => {
onSave={onSaveForm} onSave={onSaveForm}
title={title} title={title}
askLinkType={askLinkType} askLinkType={askLinkType}
labels={labels}
/> />
</Form> </Form>
)} )}

View File

@@ -165,7 +165,7 @@ function NodeViewModal({ readOnly }) {
if (launchConfig.ask_forks_on_launch) { if (launchConfig.ask_forks_on_launch) {
overrides.forks = originalNodeObject.forks; overrides.forks = originalNodeObject.forks;
} }
if (launchConfig.ask_job_slicing_on_launch) { if (launchConfig.ask_job_slice_count_on_launch) {
overrides.job_slice_count = originalNodeObject.job_slice_count; overrides.job_slice_count = originalNodeObject.job_slice_count;
} }
if (launchConfig.ask_timeout_on_launch) { if (launchConfig.ask_timeout_on_launch) {

View File

@@ -7,6 +7,7 @@ import useExecutionEnvironmentStep from 'components/LaunchPrompt/steps/useExecut
import useOtherPromptsStep from 'components/LaunchPrompt/steps/useOtherPromptsStep'; import useOtherPromptsStep from 'components/LaunchPrompt/steps/useOtherPromptsStep';
import useSurveyStep from 'components/LaunchPrompt/steps/useSurveyStep'; import useSurveyStep from 'components/LaunchPrompt/steps/useSurveyStep';
import usePreviewStep from 'components/LaunchPrompt/steps/usePreviewStep'; import usePreviewStep from 'components/LaunchPrompt/steps/usePreviewStep';
import useInstanceGroupsStep from 'components/LaunchPrompt/steps/useInstanceGroupsStep';
import { WorkflowStateContext } from 'contexts/Workflow'; import { WorkflowStateContext } from 'contexts/Workflow';
import { jsonToYaml } from 'util/yaml'; import { jsonToYaml } from 'util/yaml';
import { stringIsUUID } from 'util/strings'; import { stringIsUUID } from 'util/strings';
@@ -30,7 +31,7 @@ function showPreviewStep(nodeType, launchConfig) {
launchConfig.ask_execution_environment_on_launch || launchConfig.ask_execution_environment_on_launch ||
launchConfig.ask_labels_on_launch || launchConfig.ask_labels_on_launch ||
launchConfig.ask_forks_on_launch || launchConfig.ask_forks_on_launch ||
launchConfig.ask_job_slicing_on_launch || launchConfig.ask_job_slice_count_on_launch ||
launchConfig.ask_timeout_on_launch || launchConfig.ask_timeout_on_launch ||
launchConfig.ask_instance_groups_on_launch || launchConfig.ask_instance_groups_on_launch ||
launchConfig.survey_enabled || launchConfig.survey_enabled ||
@@ -221,7 +222,7 @@ const getNodeToEditDefaultValues = (
if (launchConfig.ask_forks_on_launch) { if (launchConfig.ask_forks_on_launch) {
initialValues.forks = sourceOfValues?.forks || 0; initialValues.forks = sourceOfValues?.forks || 0;
} }
if (launchConfig.ask_job_slicing_on_launch) { if (launchConfig.ask_job_slice_count_on_launch) {
initialValues.job_slice_count = sourceOfValues?.job_slice_count || 1; initialValues.job_slice_count = sourceOfValues?.job_slice_count || 1;
} }
if (launchConfig.ask_timeout_on_launch) { if (launchConfig.ask_timeout_on_launch) {
@@ -272,7 +273,8 @@ export default function useWorkflowNodeSteps(
surveyConfig, surveyConfig,
resource, resource,
askLinkType, askLinkType,
resourceDefaultCredentials resourceDefaultCredentials,
labels
) { ) {
const { nodeToEdit } = useContext(WorkflowStateContext); const { nodeToEdit } = useContext(WorkflowStateContext);
const { const {
@@ -289,7 +291,8 @@ export default function useWorkflowNodeSteps(
useInventoryStep(launchConfig, resource, visited), useInventoryStep(launchConfig, resource, visited),
useCredentialsStep(launchConfig, resource, resourceDefaultCredentials), useCredentialsStep(launchConfig, resource, resourceDefaultCredentials),
useExecutionEnvironmentStep(launchConfig, resource), useExecutionEnvironmentStep(launchConfig, resource),
useOtherPromptsStep(launchConfig, resource), useInstanceGroupsStep(launchConfig, resource),
useOtherPromptsStep(launchConfig, resource, labels),
useSurveyStep(launchConfig, surveyConfig, resource, visited), useSurveyStep(launchConfig, surveyConfig, resource, visited),
]; ];
@@ -380,6 +383,7 @@ export default function useWorkflowNodeSteps(
inventory: true, inventory: true,
credentials: true, credentials: true,
executionEnvironment: true, executionEnvironment: true,
instanceGroups: true,
other: true, other: true,
survey: true, survey: true,
preview: true, preview: true,

View File

@@ -452,7 +452,7 @@ function JobTemplateForm({
fieldId="template-job-slicing" fieldId="template-job-slicing"
label={t`Job Slicing`} label={t`Job Slicing`}
promptId="template-ask-job-slicing-on-launch" promptId="template-ask-job-slicing-on-launch"
promptName="ask_job_slicing_on_launch" promptName="ask_job_slice_count_on_launch"
tooltip={helpText.jobSlicing} tooltip={helpText.jobSlicing}
> >
<TextInput <TextInput
@@ -703,7 +703,8 @@ const FormikApp = withFormik({
ask_instance_groups_on_launch: ask_instance_groups_on_launch:
template.ask_instance_groups_on_launch || false, template.ask_instance_groups_on_launch || false,
ask_inventory_on_launch: template.ask_inventory_on_launch || false, ask_inventory_on_launch: template.ask_inventory_on_launch || false,
ask_job_slicing_on_launch: template.ask_job_slicing_on_launch || false, ask_job_slice_count_on_launch:
template.ask_job_slice_count_on_launch || false,
ask_job_type_on_launch: template.ask_job_type_on_launch || false, ask_job_type_on_launch: template.ask_job_type_on_launch || false,
ask_labels_on_launch: template.ask_labels_on_launch || false, ask_labels_on_launch: template.ask_labels_on_launch || false,
ask_limit_on_launch: template.ask_limit_on_launch || false, ask_limit_on_launch: template.ask_limit_on_launch || false,