Leverage the IG mixin on the schedules model

Move associate/disassociate label methods into mixin

Move label/IG saving out to related endpoints off of a schedule
This commit is contained in:
mabashian
2022-08-31 10:39:53 -04:00
committed by Alan Rominger
parent 663ef2cc64
commit d5d24e421b
11 changed files with 422 additions and 116 deletions

View File

@@ -30,6 +30,20 @@ const LabelsMixin = (parent) =>
return fetchLabels(); return fetchLabels();
} }
associateLabel(id, label, orgId) {
return this.http.post(`${this.baseUrl}${id}/labels/`, {
name: label.name,
organization: orgId,
});
}
disassociateLabel(id, label) {
return this.http.post(`${this.baseUrl}${id}/labels/`, {
id: label.id,
disassociate: true,
});
}
}; };
export default LabelsMixin; export default LabelsMixin;

View File

@@ -34,20 +34,6 @@ class JobTemplates extends SchedulesMixin(
return this.http.get(`${this.baseUrl}${id}/launch/`); return this.http.get(`${this.baseUrl}${id}/launch/`);
} }
associateLabel(id, label, orgId) {
return this.http.post(`${this.baseUrl}${id}/labels/`, {
name: label.name,
organization: orgId,
});
}
disassociateLabel(id, label) {
return this.http.post(`${this.baseUrl}${id}/labels/`, {
id: label.id,
disassociate: true,
});
}
readCredentials(id, params) { readCredentials(id, params) {
return this.http.get(`${this.baseUrl}${id}/credentials/`, { return this.http.get(`${this.baseUrl}${id}/credentials/`, {
params, params,

View File

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

View File

@@ -1,6 +1,8 @@
import React from 'react'; import React from 'react';
import { act, isElementOfType } from 'react-dom/test-utils'; import { act, isElementOfType } from 'react-dom/test-utils';
import { import {
ExecutionEnvironmentsAPI,
InstanceGroupsAPI,
InventoriesAPI, InventoriesAPI,
CredentialsAPI, CredentialsAPI,
CredentialTypesAPI, CredentialTypesAPI,
@@ -16,15 +18,15 @@ import CredentialsStep from './steps/CredentialsStep';
import CredentialPasswordsStep from './steps/CredentialPasswordsStep'; import CredentialPasswordsStep from './steps/CredentialPasswordsStep';
import OtherPromptsStep from './steps/OtherPromptsStep'; import OtherPromptsStep from './steps/OtherPromptsStep';
import PreviewStep from './steps/PreviewStep'; import PreviewStep from './steps/PreviewStep';
import executionEnvironmentHelpTextStrings from 'screens/ExecutionEnvironment/shared/ExecutionEnvironment.helptext';
import { ExecutionEnvironment } from 'types';
import ExecutionEnvironmentStep from './steps/ExecutionEnvironmentStep'; import ExecutionEnvironmentStep from './steps/ExecutionEnvironmentStep';
import InstanceGroupsStep from './steps/InstanceGroupsStep';
jest.mock('../../api/models/Inventories'); jest.mock('../../api/models/Inventories');
jest.mock('../../api/models/ExecutionEnvironments'); jest.mock('../../api/models/ExecutionEnvironments');
jest.mock('../../api/models/CredentialTypes'); jest.mock('../../api/models/CredentialTypes');
jest.mock('../../api/models/Credentials'); jest.mock('../../api/models/Credentials');
jest.mock('../../api/models/JobTemplates'); jest.mock('../../api/models/JobTemplates');
jest.mock('../../api/models/InstanceGroups');
let config; let config;
const resource = { const resource = {
@@ -66,6 +68,79 @@ describe('LaunchPrompt', () => {
spec: [{ type: 'text', variable: 'foo' }], spec: [{ type: 'text', variable: 'foo' }],
}, },
}); });
InstanceGroupsAPI.read.mockResolvedValue({
data: {
results: [
{
id: 2,
type: 'instance_group',
url: '/api/v2/instance_groups/2/',
related: {
jobs: '/api/v2/instance_groups/2/jobs/',
instances: '/api/v2/instance_groups/2/instances/',
},
name: 'default',
created: '2022-08-30T20:35:05.747132Z',
modified: '2022-08-30T20:35:05.756690Z',
capacity: 177,
consumed_capacity: 0,
percent_capacity_remaining: 100.0,
jobs_running: 0,
jobs_total: 2,
instances: 3,
is_container_group: false,
credential: null,
policy_instance_percentage: 100,
policy_instance_minimum: 0,
policy_instance_list: [],
pod_spec_override: '',
summary_fields: {
user_capabilities: {
edit: true,
delete: false,
},
},
},
],
count: 1,
},
});
ExecutionEnvironmentsAPI.read.mockResolvedValue({
data: {
results: [
{
id: 1,
type: 'execution_environment',
url: '/api/v2/execution_environments/1/',
related: {
activity_stream:
'/api/v2/execution_environments/1/activity_stream/',
unified_job_templates:
'/api/v2/execution_environments/1/unified_job_templates/',
copy: '/api/v2/execution_environments/1/copy/',
},
summary_fields: {
execution_environment: {},
user_capabilities: {
edit: true,
delete: true,
copy: true,
},
},
created: '2022-08-30T20:34:55.842997Z',
modified: '2022-08-30T20:34:55.859874Z',
name: 'AWX EE (latest)',
description: '',
organization: null,
image: 'quay.io/ansible/awx-ee:latest',
managed: false,
credential: null,
pull: '',
},
],
count: 1,
},
});
config = { config = {
can_start_without_user_input: false, can_start_without_user_input: false,
@@ -80,6 +155,12 @@ describe('LaunchPrompt', () => {
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_labels_on_launch: false,
ask_forks_on_launch: false,
ask_job_slice_count_on_launch: false,
ask_timeout_on_launch: false,
ask_instance_groups_on_launch: false,
survey_enabled: false, survey_enabled: false,
variables_needed_to_start: [], variables_needed_to_start: [],
credential_needed_to_start: false, credential_needed_to_start: false,
@@ -100,6 +181,8 @@ describe('LaunchPrompt', () => {
ask_inventory_on_launch: true, ask_inventory_on_launch: true,
ask_credential_on_launch: true, ask_credential_on_launch: true,
ask_scm_branch_on_launch: true, ask_scm_branch_on_launch: true,
ask_execution_environment_on_launch: true,
ask_instance_groups_on_launch: true,
survey_enabled: true, survey_enabled: true,
passwords_needed_to_start: ['ssh_password'], passwords_needed_to_start: ['ssh_password'],
defaults: { defaults: {
@@ -154,14 +237,15 @@ describe('LaunchPrompt', () => {
const wizard = await waitForElement(wrapper, 'Wizard'); const wizard = await waitForElement(wrapper, 'Wizard');
const steps = wizard.prop('steps'); const steps = wizard.prop('steps');
expect(steps).toHaveLength(7); expect(steps).toHaveLength(8);
expect(steps[0].name.props.children).toEqual('Inventory'); expect(steps[0].name.props.children).toEqual('Inventory');
expect(steps[1].name.props.children).toEqual('Credentials'); expect(steps[1].name.props.children).toEqual('Credentials');
expect(steps[2].name.props.children).toEqual('Credential passwords'); expect(steps[2].name.props.children).toEqual('Credential passwords');
expect(steps[3].name.props.children).toEqual('Execution Environment'); expect(steps[3].name.props.children).toEqual('Execution Environment');
expect(steps[4].name.props.children).toEqual('Other prompts'); expect(steps[4].name.props.children).toEqual('Instance Groups');
expect(steps[5].name.props.children).toEqual('Survey'); expect(steps[5].name.props.children).toEqual('Other prompts');
expect(steps[6].name.props.children).toEqual('Preview'); expect(steps[6].name.props.children).toEqual('Survey');
expect(steps[7].name.props.children).toEqual('Preview');
expect(wizard.find('WizardHeader').prop('title')).toBe('Launch | Foobar'); expect(wizard.find('WizardHeader').prop('title')).toBe('Launch | Foobar');
expect(wizard.find('WizardHeader').prop('description')).toBe( expect(wizard.find('WizardHeader').prop('description')).toBe(
'Foo Description' 'Foo Description'
@@ -219,6 +303,58 @@ describe('LaunchPrompt', () => {
expect(isElementOfType(steps[2].component, PreviewStep)).toEqual(true); expect(isElementOfType(steps[2].component, PreviewStep)).toEqual(true);
}); });
test('should add execution environment step', async () => {
let wrapper;
await act(async () => {
wrapper = mountWithContexts(
<LaunchPrompt
launchConfig={{
...config,
ask_execution_environment_on_launch: true,
}}
resource={resource}
onLaunch={noop}
onCancel={noop}
/>
);
});
const wizard = await waitForElement(wrapper, 'Wizard');
const steps = wizard.prop('steps');
expect(steps).toHaveLength(2);
expect(steps[0].name.props.children).toEqual('Execution Environment');
expect(
isElementOfType(steps[0].component, ExecutionEnvironmentStep)
).toEqual(true);
expect(isElementOfType(steps[1].component, PreviewStep)).toEqual(true);
});
test('should add instance groups step', async () => {
let wrapper;
await act(async () => {
wrapper = mountWithContexts(
<LaunchPrompt
launchConfig={{
...config,
ask_instance_groups_on_launch: true,
}}
resource={resource}
onLaunch={noop}
onCancel={noop}
/>
);
});
const wizard = await waitForElement(wrapper, 'Wizard');
const steps = wizard.prop('steps');
expect(steps).toHaveLength(2);
expect(steps[0].name.props.children).toEqual('Instance Groups');
expect(isElementOfType(steps[0].component, InstanceGroupsStep)).toEqual(
true
);
expect(isElementOfType(steps[1].component, PreviewStep)).toEqual(true);
});
test('should add other prompts step', async () => { test('should add other prompts step', async () => {
let wrapper; let wrapper;
await act(async () => { await act(async () => {

View File

@@ -231,7 +231,7 @@ function LabelsField() {
value={field.value} value={field.value}
onChange={(labels) => helpers.setValue(labels)} onChange={(labels) => helpers.setValue(labels)}
createText={t`Create`} createText={t`Create`}
onError={() => alert('error')} onError={() => {}}
/> />
</FormGroup> </FormGroup>
); );

View File

@@ -10,7 +10,7 @@ const STEP_ID = 'credentials';
export default function useCredentialsStep( export default function useCredentialsStep(
launchConfig, launchConfig,
resource, resource,
resourceDefaultCredentials, resourceDefaultCredentials = [],
allowCredentialsWithPasswords = false allowCredentialsWithPasswords = false
) { ) {
const [field, meta, helpers] = useField('credentials'); const [field, meta, helpers] = useField('credentials');
@@ -78,6 +78,6 @@ function getInitialValues(launchConfig, resourceDefaultCredentials) {
} }
return { return {
credentials: resourceDefaultCredentials || [], credentials: resourceDefaultCredentials,
}; };
} }

View File

@@ -4,7 +4,7 @@ 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 { OrganizationsAPI, 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';
@@ -41,6 +41,7 @@ function ScheduleAdd({
exceptionOptions, exceptionOptions,
timezone, timezone,
credentials, credentials,
labels,
...submitValues ...submitValues
} = values; } = values;
const { added } = getAddedAndRemoved( const { added } = getAddedAndRemoved(
@@ -76,56 +77,7 @@ function ScheduleAdd({
submitValues.execution_environment = execution_environment.id; 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,
@@ -147,13 +99,46 @@ function ScheduleAdd({
const { const {
data: { id: scheduleId }, data: { id: scheduleId },
} = await apiModel.createSchedule(resource.id, requestData); } = await apiModel.createSchedule(resource.id, requestData);
if (credentials?.length > 0) {
await Promise.all( let labelsPromises = [];
added.map(({ id: credentialId }) => let credentialsPromises = [];
SchedulesAPI.associateCredential(scheduleId, credentialId)
) if (launchConfiguration?.ask_labels_on_launch && labels) {
let organizationId = resource.organization;
if (!organizationId) {
// eslint-disable-next-line no-useless-catch
try {
const {
data: { results },
} = await OrganizationsAPI.read();
organizationId = results[0].id;
} catch (err) {
throw err;
}
}
labelsPromises = labels.map((label) =>
SchedulesAPI.associateLabel(scheduleId, label, organizationId)
); );
} }
if (launchConfiguration?.ask_credential_on_launch && added?.length > 0) {
credentialsPromises = added.map(({ id: credentialId }) =>
SchedulesAPI.associateCredential(scheduleId, credentialId)
);
}
await Promise.all([labelsPromises, credentialsPromises]);
if (
launchConfiguration?.ask_instance_groups_on_launch &&
instance_groups
) {
/* eslint-disable no-await-in-loop, no-restricted-syntax */
for (const group of instance_groups) {
await SchedulesAPI.associateInstanceGroup(scheduleId, group.id);
}
}
history.push(`${pathRoot}schedules/${scheduleId}`); history.push(`${pathRoot}schedules/${scheduleId}`);
} catch (err) { } catch (err) {
setFormSubmitError(err); setFormSubmitError(err);

View File

@@ -1,11 +1,21 @@
import React from 'react'; import React from 'react';
import { act } from 'react-dom/test-utils'; import { act } from 'react-dom/test-utils';
import { RRule } from 'rrule'; import { RRule } from 'rrule';
import { SchedulesAPI, JobTemplatesAPI, InventoriesAPI } from 'api'; import {
CredentialsAPI,
CredentialTypesAPI,
SchedulesAPI,
JobTemplatesAPI,
InventoriesAPI,
} from 'api';
import { mountWithContexts } from '../../../../testUtils/enzymeHelpers'; import { mountWithContexts } from '../../../../testUtils/enzymeHelpers';
import ScheduleAdd from './ScheduleAdd'; import ScheduleAdd from './ScheduleAdd';
jest.mock('../../../api'); jest.mock('../../../api/models/Credentials');
jest.mock('../../../api/models/CredentialTypes');
jest.mock('../../../api/models/Schedules');
jest.mock('../../../api/models/JobTemplates');
jest.mock('../../../api/models/Inventories');
const launchConfig = { const launchConfig = {
can_start_without_user_input: false, can_start_without_user_input: false,
@@ -19,7 +29,7 @@ const launchConfig = {
ask_limit_on_launch: false, ask_limit_on_launch: false,
ask_verbosity_on_launch: false, ask_verbosity_on_launch: false,
ask_inventory_on_launch: true, ask_inventory_on_launch: true,
ask_credential_on_launch: false, ask_credential_on_launch: true,
survey_enabled: false, survey_enabled: false,
variables_needed_to_start: [], variables_needed_to_start: [],
credential_needed_to_start: false, credential_needed_to_start: false,
@@ -57,6 +67,33 @@ describe('<ScheduleAdd />', () => {
], ],
}); });
JobTemplatesAPI.createSchedule.mockResolvedValue({ data: { id: 3 } }); JobTemplatesAPI.createSchedule.mockResolvedValue({ data: { id: 3 } });
CredentialTypesAPI.loadAllTypes.mockResolvedValue([
{ id: 1, name: 'ssh', kind: 'ssh' },
]);
CredentialsAPI.read.mockResolvedValue({
data: {
count: 1,
results: [
{
id: 10,
name: 'cred 1',
kind: 'ssh',
url: '',
credential_type: 1,
},
],
},
});
CredentialsAPI.readOptions.mockResolvedValue({
data: {
related_search_fields: [],
actions: { GET: { filterabled: true } },
},
});
await act(async () => { await act(async () => {
wrapper = mountWithContexts( wrapper = mountWithContexts(
<ScheduleAdd <ScheduleAdd
@@ -70,6 +107,7 @@ describe('<ScheduleAdd />', () => {
description: '', description: '',
}} }}
launchConfig={launchConfig} launchConfig={launchConfig}
surveyConfig={{}}
/> />
); );
}); });
@@ -390,6 +428,7 @@ describe('<ScheduleAdd />', () => {
wrapper.find('Button[aria-label="Prompt"]').prop('onClick')() wrapper.find('Button[aria-label="Prompt"]').prop('onClick')()
); );
wrapper.update(); wrapper.update();
// Inventory step
expect(wrapper.find('WizardNavItem').at(0).prop('isCurrent')).toBe(true); expect(wrapper.find('WizardNavItem').at(0).prop('isCurrent')).toBe(true);
await act(async () => { await act(async () => {
wrapper.find('td#check-action-item-1').find('input').simulate('click'); wrapper.find('td#check-action-item-1').find('input').simulate('click');
@@ -402,7 +441,21 @@ describe('<ScheduleAdd />', () => {
wrapper.find('WizardFooterInternal').prop('onNext')() wrapper.find('WizardFooterInternal').prop('onNext')()
); );
wrapper.update(); wrapper.update();
// Credential step
expect(wrapper.find('WizardNavItem').at(1).prop('isCurrent')).toBe(true); expect(wrapper.find('WizardNavItem').at(1).prop('isCurrent')).toBe(true);
await act(async () => {
wrapper.find('td#check-action-item-10').find('input').simulate('click');
});
wrapper.update();
expect(
wrapper.find('td#check-action-item-10').find('input').prop('checked')
).toBe(true);
await act(async () =>
wrapper.find('WizardFooterInternal').prop('onNext')()
);
wrapper.update();
// Preview step
expect(wrapper.find('WizardNavItem').at(2).prop('isCurrent')).toBe(true);
await act(async () => await act(async () =>
wrapper.find('WizardFooterInternal').prop('onNext')() wrapper.find('WizardFooterInternal').prop('onNext')()
); );
@@ -414,10 +467,7 @@ describe('<ScheduleAdd />', () => {
frequency: [], frequency: [],
skip_tags: '', skip_tags: '',
inventory: { name: 'inventory', id: 45 }, inventory: { name: 'inventory', id: 45 },
credentials: [ credentials: [{ name: 'cred 1', id: 10 }],
{ name: 'cred 1', id: 10 },
{ name: 'cred 2', id: 20 },
],
startDate: '2021-01-28', startDate: '2021-01-28',
startTime: '2:15 PM', startTime: '2:15 PM',
timezone: 'America/New_York', timezone: 'America/New_York',
@@ -434,7 +484,6 @@ describe('<ScheduleAdd />', () => {
skip_tags: '', skip_tags: '',
}); });
expect(SchedulesAPI.associateCredential).toBeCalledWith(3, 10); expect(SchedulesAPI.associateCredential).toBeCalledWith(3, 10);
expect(SchedulesAPI.associateCredential).toBeCalledWith(3, 20);
}); });
test('should submit survey with default values properly, without opening prompt wizard', async () => { test('should submit survey with default values properly, without opening prompt wizard', async () => {

View File

@@ -30,7 +30,8 @@ function ScheduleEdit({
values, values,
launchConfiguration, launchConfiguration,
surveyConfiguration, surveyConfiguration,
scheduleCredentials = [] scheduleCredentials = [],
originalLabels = []
) => { ) => {
const { const {
execution_environment, execution_environment,
@@ -42,13 +43,9 @@ function ScheduleEdit({
exceptionFrequency, exceptionFrequency,
exceptionOptions, exceptionOptions,
timezone, timezone,
labels,
...submitValues ...submitValues
} = values; } = values;
const { added, removed } = getAddedAndRemoved(
[...(resource?.summary_fields.credentials || []), ...scheduleCredentials],
credentials
);
let extraVars; let extraVars;
const surveyValues = getSurveyValues(values); const surveyValues = getSurveyValues(values);
@@ -86,10 +83,6 @@ function ScheduleEdit({
submitValues.execution_environment = execution_environment.id; 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) { if (launchConfiguration?.ask_labels_on_launch) {
const labelIds = []; const labelIds = [];
@@ -157,17 +150,52 @@ function ScheduleEdit({
const { const {
data: { id: scheduleId }, data: { id: scheduleId },
} = await SchedulesAPI.update(schedule.id, requestData); } = await SchedulesAPI.update(schedule.id, requestData);
if (values.credentials?.length > 0) {
await Promise.all([ const { added: addedCredentials, removed: removedCredentials } =
...removed.map(({ id }) => getAddedAndRemoved(
SchedulesAPI.disassociateCredential(scheduleId, id) [
), ...(resource?.summary_fields.credentials || []),
...added.map(({ id }) => ...scheduleCredentials,
SchedulesAPI.associateCredential(scheduleId, id) ],
), credentials
]); );
const { added: addedLabels, removed: removedLabels } = getAddedAndRemoved(
originalLabels,
labels
);
let organizationId = resource.organization;
if (addedLabels.length > 0) {
if (!organizationId) {
const {
data: { results },
} = await OrganizationsAPI.read();
organizationId = results[0].id;
}
} }
await Promise.all([
...removedCredentials.map(({ id }) =>
SchedulesAPI.disassociateCredential(scheduleId, id)
),
...addedCredentials.map(({ id }) =>
SchedulesAPI.associateCredential(scheduleId, id)
),
...removedLabels.map((label) =>
SchedulesAPI.disassociateLabel(scheduleId, label)
),
...addedLabels.map((label) =>
SchedulesAPI.associateLabel(scheduleId, label, organizationId)
),
SchedulesAPI.orderInstanceGroups(
scheduleId,
instance_groups,
resource?.summary_fields.instance_groups || []
),
]);
history.push(`${pathRoot}schedules/${scheduleId}/details`); history.push(`${pathRoot}schedules/${scheduleId}/details`);
} catch (err) { } catch (err) {
setFormSubmitError(err); setFormSubmitError(err);

View File

@@ -59,7 +59,7 @@ function ScheduleForm({
useCallback(async () => { useCallback(async () => {
const { data } = await SchedulesAPI.readZoneInfo(); const { data } = await SchedulesAPI.readZoneInfo();
let creds; let creds = [];
let allLabels; let allLabels;
if (schedule.id) { if (schedule.id) {
if ( if (
@@ -107,7 +107,7 @@ function ScheduleForm({
return { return {
zoneOptions: zones, zoneOptions: zones,
zoneLinks: data.links, zoneLinks: data.links,
credentials: creds || [], credentials: creds,
labels: allLabels || [], labels: allLabels || [],
}; };
}, [ }, [
@@ -467,7 +467,13 @@ function ScheduleForm({
}, },
}} }}
onSubmit={(values) => { onSubmit={(values) => {
submitSchedule(values, launchConfig, surveyConfig, credentials); submitSchedule(
values,
launchConfig,
surveyConfig,
credentials,
labels
);
}} }}
validate={validate} validate={validate}
> >

View File

@@ -17,11 +17,35 @@ jest.mock('../../../api/models/Inventories');
const credentials = { const credentials = {
data: { data: {
results: [ results: [
{ id: 1, kind: 'cloud', name: 'Cred 1', url: 'www.google.com' }, {
{ id: 2, kind: 'ssh', name: 'Cred 2', url: 'www.google.com' }, id: 1,
{ id: 3, kind: 'Ansible', name: 'Cred 3', url: 'www.google.com' }, kind: 'cloud',
{ id: 4, kind: 'Machine', name: 'Cred 4', url: 'www.google.com' }, name: 'Cred 1',
{ id: 5, kind: 'Machine', name: 'Cred 5', url: 'www.google.com' }, url: 'www.google.com',
inputs: {},
},
{ id: 2, kind: 'ssh', name: 'Cred 2', url: 'www.google.com', inputs: {} },
{
id: 3,
kind: 'Ansible',
name: 'Cred 3',
url: 'www.google.com',
inputs: {},
},
{
id: 4,
kind: 'Machine',
name: 'Cred 4',
url: 'www.google.com',
inputs: {},
},
{
id: 5,
kind: 'Machine',
name: 'Cred 5',
url: 'www.google.com',
inputs: {},
},
], ],
}, },
}; };
@@ -39,6 +63,12 @@ const launchData = {
ask_verbosity_on_launch: false, ask_verbosity_on_launch: false,
ask_inventory_on_launch: true, ask_inventory_on_launch: true,
ask_credential_on_launch: false, ask_credential_on_launch: false,
ask_execution_environment_on_launch: false,
ask_labels_on_launch: false,
ask_forks_on_launch: false,
ask_job_slice_count_on_launch: false,
ask_timeout_on_launch: false,
ask_instance_groups_on_launch: false,
survey_enabled: false, survey_enabled: false,
variables_needed_to_start: [], variables_needed_to_start: [],
credential_needed_to_start: false, credential_needed_to_start: false,
@@ -153,6 +183,12 @@ describe('<ScheduleForm />', () => {
ask_verbosity_on_launch: false, ask_verbosity_on_launch: false,
ask_inventory_on_launch: true, ask_inventory_on_launch: true,
ask_credential_on_launch: false, ask_credential_on_launch: false,
ask_execution_environment_on_launch: false,
ask_labels_on_launch: false,
ask_forks_on_launch: false,
ask_job_slice_count_on_launch: false,
ask_timeout_on_launch: false,
ask_instance_groups_on_launch: false,
survey_enabled: false, survey_enabled: false,
variables_needed_to_start: [], variables_needed_to_start: [],
credential_needed_to_start: false, credential_needed_to_start: false,
@@ -208,6 +244,12 @@ describe('<ScheduleForm />', () => {
ask_verbosity_on_launch: false, ask_verbosity_on_launch: false,
ask_inventory_on_launch: true, ask_inventory_on_launch: true,
ask_credential_on_launch: false, ask_credential_on_launch: false,
ask_execution_environment_on_launch: false,
ask_labels_on_launch: false,
ask_forks_on_launch: false,
ask_job_slice_count_on_launch: false,
ask_timeout_on_launch: false,
ask_instance_groups_on_launch: false,
survey_enabled: false, survey_enabled: false,
variables_needed_to_start: [], variables_needed_to_start: [],
credential_needed_to_start: false, credential_needed_to_start: false,
@@ -275,6 +317,12 @@ describe('<ScheduleForm />', () => {
ask_verbosity_on_launch: false, ask_verbosity_on_launch: false,
ask_inventory_on_launch: true, ask_inventory_on_launch: true,
ask_credential_on_launch: false, ask_credential_on_launch: false,
ask_execution_environment_on_launch: false,
ask_labels_on_launch: false,
ask_forks_on_launch: false,
ask_job_slice_count_on_launch: false,
ask_timeout_on_launch: false,
ask_instance_groups_on_launch: false,
survey_enabled: false, survey_enabled: false,
variables_needed_to_start: [], variables_needed_to_start: [],
credential_needed_to_start: false, credential_needed_to_start: false,
@@ -406,6 +454,12 @@ describe('<ScheduleForm />', () => {
ask_verbosity_on_launch: false, ask_verbosity_on_launch: false,
ask_inventory_on_launch: true, ask_inventory_on_launch: true,
ask_credential_on_launch: false, ask_credential_on_launch: false,
ask_execution_environment_on_launch: false,
ask_labels_on_launch: false,
ask_forks_on_launch: false,
ask_job_slice_count_on_launch: false,
ask_timeout_on_launch: false,
ask_instance_groups_on_launch: false,
survey_enabled: false, survey_enabled: false,
variables_needed_to_start: [], variables_needed_to_start: [],
credential_needed_to_start: false, credential_needed_to_start: false,
@@ -465,6 +519,12 @@ describe('<ScheduleForm />', () => {
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_labels_on_launch: false,
ask_forks_on_launch: false,
ask_job_slice_count_on_launch: false,
ask_timeout_on_launch: false,
ask_instance_groups_on_launch: false,
survey_enabled: false, survey_enabled: false,
variables_needed_to_start: [], variables_needed_to_start: [],
credential_needed_to_start: false, credential_needed_to_start: false,
@@ -894,7 +954,7 @@ describe('<ScheduleForm />', () => {
jest.clearAllMocks(); jest.clearAllMocks();
}); });
test('should make API calls to fetch credentials, launch configuration, and survey configuration', async () => { test('should make API calls to fetch credentials, labels, and zone info', async () => {
await act(async () => { await act(async () => {
wrapper = mountWithContexts( wrapper = mountWithContexts(
<ScheduleForm <ScheduleForm
@@ -906,6 +966,9 @@ describe('<ScheduleForm />', () => {
type: 'job_template', type: 'job_template',
name: 'Foo Job Template', name: 'Foo Job Template',
description: '', description: '',
summary_fields: {
credentials: [],
},
}} }}
launchConfig={{ launchConfig={{
can_start_without_user_input: true, can_start_without_user_input: true,
@@ -919,7 +982,13 @@ describe('<ScheduleForm />', () => {
ask_limit_on_launch: false, ask_limit_on_launch: false,
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: true,
ask_execution_environment_on_launch: false,
ask_labels_on_launch: true,
ask_forks_on_launch: false,
ask_job_slice_count_on_launch: false,
ask_timeout_on_launch: false,
ask_instance_groups_on_launch: false,
survey_enabled: false, survey_enabled: false,
variables_needed_to_start: [], variables_needed_to_start: [],
credential_needed_to_start: false, credential_needed_to_start: false,
@@ -933,7 +1002,9 @@ describe('<ScheduleForm />', () => {
/> />
); );
}); });
expect(SchedulesAPI.readZoneInfo).toBeCalled();
expect(SchedulesAPI.readCredentials).toBeCalledWith(27); expect(SchedulesAPI.readCredentials).toBeCalledWith(27);
expect(SchedulesAPI.readAllLabels).toBeCalledWith(27);
}); });
test('should not call API to get credentials ', async () => { test('should not call API to get credentials ', async () => {
@@ -961,6 +1032,12 @@ describe('<ScheduleForm />', () => {
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_labels_on_launch: false,
ask_forks_on_launch: false,
ask_job_slice_count_on_launch: false,
ask_timeout_on_launch: false,
ask_instance_groups_on_launch: false,
survey_enabled: false, survey_enabled: false,
variables_needed_to_start: [], variables_needed_to_start: [],
credential_needed_to_start: false, credential_needed_to_start: false,
@@ -991,6 +1068,30 @@ describe('<ScheduleForm />', () => {
name: 'Foo Project', name: 'Foo Project',
description: '', description: '',
}} }}
launchConfig={{
can_start_without_user_input: true,
passwords_needed_to_start: [],
ask_scm_branch_on_launch: false,
ask_variables_on_launch: false,
ask_tags_on_launch: false,
ask_diff_mode_on_launch: false,
ask_skip_tags_on_launch: false,
ask_job_type_on_launch: false,
ask_limit_on_launch: false,
ask_verbosity_on_launch: false,
ask_inventory_on_launch: false,
ask_credential_on_launch: false,
ask_execution_environment_on_launch: false,
ask_labels_on_launch: false,
ask_forks_on_launch: false,
ask_job_slice_count_on_launch: false,
ask_timeout_on_launch: false,
ask_instance_groups_on_launch: false,
survey_enabled: false,
variables_needed_to_start: [],
credential_needed_to_start: false,
inventory_needed_to_start: false,
}}
/> />
); );
}); });