mirror of
https://github.com/ansible/awx.git
synced 2026-01-11 01:57:35 -03:30
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:
parent
663ef2cc64
commit
d5d24e421b
@ -30,6 +30,20 @@ const LabelsMixin = (parent) =>
|
||||
|
||||
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;
|
||||
|
||||
@ -34,20 +34,6 @@ class JobTemplates extends SchedulesMixin(
|
||||
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) {
|
||||
return this.http.get(`${this.baseUrl}${id}/credentials/`, {
|
||||
params,
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
import Base from '../Base';
|
||||
import InstanceGroupsMixin from '../mixins/InstanceGroups.mixin';
|
||||
import LabelsMixin from '../mixins/Labels.mixin';
|
||||
|
||||
class Schedules extends LabelsMixin(Base) {
|
||||
class Schedules extends InstanceGroupsMixin(LabelsMixin(Base)) {
|
||||
constructor(http) {
|
||||
super(http);
|
||||
this.baseUrl = 'api/v2/schedules/';
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
import React from 'react';
|
||||
import { act, isElementOfType } from 'react-dom/test-utils';
|
||||
import {
|
||||
ExecutionEnvironmentsAPI,
|
||||
InstanceGroupsAPI,
|
||||
InventoriesAPI,
|
||||
CredentialsAPI,
|
||||
CredentialTypesAPI,
|
||||
@ -16,15 +18,15 @@ import CredentialsStep from './steps/CredentialsStep';
|
||||
import CredentialPasswordsStep from './steps/CredentialPasswordsStep';
|
||||
import OtherPromptsStep from './steps/OtherPromptsStep';
|
||||
import PreviewStep from './steps/PreviewStep';
|
||||
import executionEnvironmentHelpTextStrings from 'screens/ExecutionEnvironment/shared/ExecutionEnvironment.helptext';
|
||||
import { ExecutionEnvironment } from 'types';
|
||||
import ExecutionEnvironmentStep from './steps/ExecutionEnvironmentStep';
|
||||
import InstanceGroupsStep from './steps/InstanceGroupsStep';
|
||||
|
||||
jest.mock('../../api/models/Inventories');
|
||||
jest.mock('../../api/models/ExecutionEnvironments');
|
||||
jest.mock('../../api/models/CredentialTypes');
|
||||
jest.mock('../../api/models/Credentials');
|
||||
jest.mock('../../api/models/JobTemplates');
|
||||
jest.mock('../../api/models/InstanceGroups');
|
||||
|
||||
let config;
|
||||
const resource = {
|
||||
@ -66,6 +68,79 @@ describe('LaunchPrompt', () => {
|
||||
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 = {
|
||||
can_start_without_user_input: false,
|
||||
@ -80,6 +155,12 @@ describe('LaunchPrompt', () => {
|
||||
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,
|
||||
@ -100,6 +181,8 @@ describe('LaunchPrompt', () => {
|
||||
ask_inventory_on_launch: true,
|
||||
ask_credential_on_launch: true,
|
||||
ask_scm_branch_on_launch: true,
|
||||
ask_execution_environment_on_launch: true,
|
||||
ask_instance_groups_on_launch: true,
|
||||
survey_enabled: true,
|
||||
passwords_needed_to_start: ['ssh_password'],
|
||||
defaults: {
|
||||
@ -154,14 +237,15 @@ describe('LaunchPrompt', () => {
|
||||
const wizard = await waitForElement(wrapper, 'Wizard');
|
||||
const steps = wizard.prop('steps');
|
||||
|
||||
expect(steps).toHaveLength(7);
|
||||
expect(steps).toHaveLength(8);
|
||||
expect(steps[0].name.props.children).toEqual('Inventory');
|
||||
expect(steps[1].name.props.children).toEqual('Credentials');
|
||||
expect(steps[2].name.props.children).toEqual('Credential passwords');
|
||||
expect(steps[3].name.props.children).toEqual('Execution Environment');
|
||||
expect(steps[4].name.props.children).toEqual('Other prompts');
|
||||
expect(steps[5].name.props.children).toEqual('Survey');
|
||||
expect(steps[6].name.props.children).toEqual('Preview');
|
||||
expect(steps[4].name.props.children).toEqual('Instance Groups');
|
||||
expect(steps[5].name.props.children).toEqual('Other prompts');
|
||||
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('description')).toBe(
|
||||
'Foo Description'
|
||||
@ -219,6 +303,58 @@ describe('LaunchPrompt', () => {
|
||||
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 () => {
|
||||
let wrapper;
|
||||
await act(async () => {
|
||||
|
||||
@ -231,7 +231,7 @@ function LabelsField() {
|
||||
value={field.value}
|
||||
onChange={(labels) => helpers.setValue(labels)}
|
||||
createText={t`Create`}
|
||||
onError={() => alert('error')}
|
||||
onError={() => {}}
|
||||
/>
|
||||
</FormGroup>
|
||||
);
|
||||
|
||||
@ -10,7 +10,7 @@ const STEP_ID = 'credentials';
|
||||
export default function useCredentialsStep(
|
||||
launchConfig,
|
||||
resource,
|
||||
resourceDefaultCredentials,
|
||||
resourceDefaultCredentials = [],
|
||||
allowCredentialsWithPasswords = false
|
||||
) {
|
||||
const [field, meta, helpers] = useField('credentials');
|
||||
@ -78,6 +78,6 @@ function getInitialValues(launchConfig, resourceDefaultCredentials) {
|
||||
}
|
||||
|
||||
return {
|
||||
credentials: resourceDefaultCredentials || [],
|
||||
credentials: resourceDefaultCredentials,
|
||||
};
|
||||
}
|
||||
|
||||
@ -4,7 +4,7 @@ import { useHistory, useLocation } from 'react-router-dom';
|
||||
import { Card } from '@patternfly/react-core';
|
||||
import yaml from 'js-yaml';
|
||||
import { parseVariableField } from 'util/yaml';
|
||||
import { LabelsAPI, OrganizationsAPI, SchedulesAPI } from 'api';
|
||||
import { OrganizationsAPI, SchedulesAPI } from 'api';
|
||||
import mergeExtraVars from 'util/prompt/mergeExtraVars';
|
||||
import getSurveyValues from 'util/prompt/getSurveyValues';
|
||||
import { getAddedAndRemoved } from 'util/lists';
|
||||
@ -41,6 +41,7 @@ function ScheduleAdd({
|
||||
exceptionOptions,
|
||||
timezone,
|
||||
credentials,
|
||||
labels,
|
||||
...submitValues
|
||||
} = values;
|
||||
const { added } = getAddedAndRemoved(
|
||||
@ -76,56 +77,7 @@ function ScheduleAdd({
|
||||
submitValues.execution_environment = execution_environment.id;
|
||||
}
|
||||
|
||||
submitValues.instance_groups = instance_groups
|
||||
? instance_groups.map((s) => s.id)
|
||||
: [];
|
||||
|
||||
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 requestData = {
|
||||
...submitValues,
|
||||
@ -147,13 +99,46 @@ function ScheduleAdd({
|
||||
const {
|
||||
data: { id: scheduleId },
|
||||
} = await apiModel.createSchedule(resource.id, requestData);
|
||||
if (credentials?.length > 0) {
|
||||
await Promise.all(
|
||||
added.map(({ id: credentialId }) =>
|
||||
SchedulesAPI.associateCredential(scheduleId, credentialId)
|
||||
)
|
||||
|
||||
let labelsPromises = [];
|
||||
let credentialsPromises = [];
|
||||
|
||||
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}`);
|
||||
} catch (err) {
|
||||
setFormSubmitError(err);
|
||||
|
||||
@ -1,11 +1,21 @@
|
||||
import React from 'react';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import { RRule } from 'rrule';
|
||||
import { SchedulesAPI, JobTemplatesAPI, InventoriesAPI } from 'api';
|
||||
import {
|
||||
CredentialsAPI,
|
||||
CredentialTypesAPI,
|
||||
SchedulesAPI,
|
||||
JobTemplatesAPI,
|
||||
InventoriesAPI,
|
||||
} from 'api';
|
||||
import { mountWithContexts } from '../../../../testUtils/enzymeHelpers';
|
||||
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 = {
|
||||
can_start_without_user_input: false,
|
||||
@ -19,7 +29,7 @@ const launchConfig = {
|
||||
ask_limit_on_launch: false,
|
||||
ask_verbosity_on_launch: false,
|
||||
ask_inventory_on_launch: true,
|
||||
ask_credential_on_launch: false,
|
||||
ask_credential_on_launch: true,
|
||||
survey_enabled: false,
|
||||
variables_needed_to_start: [],
|
||||
credential_needed_to_start: false,
|
||||
@ -57,6 +67,33 @@ describe('<ScheduleAdd />', () => {
|
||||
],
|
||||
});
|
||||
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 () => {
|
||||
wrapper = mountWithContexts(
|
||||
<ScheduleAdd
|
||||
@ -70,6 +107,7 @@ describe('<ScheduleAdd />', () => {
|
||||
description: '',
|
||||
}}
|
||||
launchConfig={launchConfig}
|
||||
surveyConfig={{}}
|
||||
/>
|
||||
);
|
||||
});
|
||||
@ -390,6 +428,7 @@ describe('<ScheduleAdd />', () => {
|
||||
wrapper.find('Button[aria-label="Prompt"]').prop('onClick')()
|
||||
);
|
||||
wrapper.update();
|
||||
// Inventory step
|
||||
expect(wrapper.find('WizardNavItem').at(0).prop('isCurrent')).toBe(true);
|
||||
await act(async () => {
|
||||
wrapper.find('td#check-action-item-1').find('input').simulate('click');
|
||||
@ -402,7 +441,21 @@ describe('<ScheduleAdd />', () => {
|
||||
wrapper.find('WizardFooterInternal').prop('onNext')()
|
||||
);
|
||||
wrapper.update();
|
||||
// Credential step
|
||||
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 () =>
|
||||
wrapper.find('WizardFooterInternal').prop('onNext')()
|
||||
);
|
||||
@ -414,10 +467,7 @@ describe('<ScheduleAdd />', () => {
|
||||
frequency: [],
|
||||
skip_tags: '',
|
||||
inventory: { name: 'inventory', id: 45 },
|
||||
credentials: [
|
||||
{ name: 'cred 1', id: 10 },
|
||||
{ name: 'cred 2', id: 20 },
|
||||
],
|
||||
credentials: [{ name: 'cred 1', id: 10 }],
|
||||
startDate: '2021-01-28',
|
||||
startTime: '2:15 PM',
|
||||
timezone: 'America/New_York',
|
||||
@ -434,7 +484,6 @@ describe('<ScheduleAdd />', () => {
|
||||
skip_tags: '',
|
||||
});
|
||||
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 () => {
|
||||
|
||||
@ -30,7 +30,8 @@ function ScheduleEdit({
|
||||
values,
|
||||
launchConfiguration,
|
||||
surveyConfiguration,
|
||||
scheduleCredentials = []
|
||||
scheduleCredentials = [],
|
||||
originalLabels = []
|
||||
) => {
|
||||
const {
|
||||
execution_environment,
|
||||
@ -42,13 +43,9 @@ function ScheduleEdit({
|
||||
exceptionFrequency,
|
||||
exceptionOptions,
|
||||
timezone,
|
||||
labels,
|
||||
...submitValues
|
||||
} = values;
|
||||
const { added, removed } = getAddedAndRemoved(
|
||||
[...(resource?.summary_fields.credentials || []), ...scheduleCredentials],
|
||||
credentials
|
||||
);
|
||||
|
||||
let extraVars;
|
||||
const surveyValues = getSurveyValues(values);
|
||||
|
||||
@ -86,10 +83,6 @@ function ScheduleEdit({
|
||||
submitValues.execution_environment = execution_environment.id;
|
||||
}
|
||||
|
||||
submitValues.instance_groups = instance_groups
|
||||
? instance_groups.map((s) => s.id)
|
||||
: [];
|
||||
|
||||
try {
|
||||
if (launchConfiguration?.ask_labels_on_launch) {
|
||||
const labelIds = [];
|
||||
@ -157,17 +150,52 @@ function ScheduleEdit({
|
||||
const {
|
||||
data: { id: scheduleId },
|
||||
} = await SchedulesAPI.update(schedule.id, requestData);
|
||||
if (values.credentials?.length > 0) {
|
||||
await Promise.all([
|
||||
...removed.map(({ id }) =>
|
||||
SchedulesAPI.disassociateCredential(scheduleId, id)
|
||||
),
|
||||
...added.map(({ id }) =>
|
||||
SchedulesAPI.associateCredential(scheduleId, id)
|
||||
),
|
||||
]);
|
||||
|
||||
const { added: addedCredentials, removed: removedCredentials } =
|
||||
getAddedAndRemoved(
|
||||
[
|
||||
...(resource?.summary_fields.credentials || []),
|
||||
...scheduleCredentials,
|
||||
],
|
||||
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`);
|
||||
} catch (err) {
|
||||
setFormSubmitError(err);
|
||||
|
||||
@ -59,7 +59,7 @@ function ScheduleForm({
|
||||
useCallback(async () => {
|
||||
const { data } = await SchedulesAPI.readZoneInfo();
|
||||
|
||||
let creds;
|
||||
let creds = [];
|
||||
let allLabels;
|
||||
if (schedule.id) {
|
||||
if (
|
||||
@ -107,7 +107,7 @@ function ScheduleForm({
|
||||
return {
|
||||
zoneOptions: zones,
|
||||
zoneLinks: data.links,
|
||||
credentials: creds || [],
|
||||
credentials: creds,
|
||||
labels: allLabels || [],
|
||||
};
|
||||
}, [
|
||||
@ -467,7 +467,13 @@ function ScheduleForm({
|
||||
},
|
||||
}}
|
||||
onSubmit={(values) => {
|
||||
submitSchedule(values, launchConfig, surveyConfig, credentials);
|
||||
submitSchedule(
|
||||
values,
|
||||
launchConfig,
|
||||
surveyConfig,
|
||||
credentials,
|
||||
labels
|
||||
);
|
||||
}}
|
||||
validate={validate}
|
||||
>
|
||||
|
||||
@ -17,11 +17,35 @@ jest.mock('../../../api/models/Inventories');
|
||||
const credentials = {
|
||||
data: {
|
||||
results: [
|
||||
{ id: 1, kind: 'cloud', name: 'Cred 1', url: 'www.google.com' },
|
||||
{ id: 2, kind: 'ssh', name: 'Cred 2', url: 'www.google.com' },
|
||||
{ id: 3, kind: 'Ansible', name: 'Cred 3', url: 'www.google.com' },
|
||||
{ id: 4, kind: 'Machine', name: 'Cred 4', url: 'www.google.com' },
|
||||
{ id: 5, kind: 'Machine', name: 'Cred 5', url: 'www.google.com' },
|
||||
{
|
||||
id: 1,
|
||||
kind: 'cloud',
|
||||
name: 'Cred 1',
|
||||
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_inventory_on_launch: true,
|
||||
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,
|
||||
@ -153,6 +183,12 @@ describe('<ScheduleForm />', () => {
|
||||
ask_verbosity_on_launch: false,
|
||||
ask_inventory_on_launch: true,
|
||||
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,
|
||||
@ -208,6 +244,12 @@ describe('<ScheduleForm />', () => {
|
||||
ask_verbosity_on_launch: false,
|
||||
ask_inventory_on_launch: true,
|
||||
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,
|
||||
@ -275,6 +317,12 @@ describe('<ScheduleForm />', () => {
|
||||
ask_verbosity_on_launch: false,
|
||||
ask_inventory_on_launch: true,
|
||||
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,
|
||||
@ -406,6 +454,12 @@ describe('<ScheduleForm />', () => {
|
||||
ask_verbosity_on_launch: false,
|
||||
ask_inventory_on_launch: true,
|
||||
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,
|
||||
@ -465,6 +519,12 @@ describe('<ScheduleForm />', () => {
|
||||
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,
|
||||
@ -894,7 +954,7 @@ describe('<ScheduleForm />', () => {
|
||||
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 () => {
|
||||
wrapper = mountWithContexts(
|
||||
<ScheduleForm
|
||||
@ -906,6 +966,9 @@ describe('<ScheduleForm />', () => {
|
||||
type: 'job_template',
|
||||
name: 'Foo Job Template',
|
||||
description: '',
|
||||
summary_fields: {
|
||||
credentials: [],
|
||||
},
|
||||
}}
|
||||
launchConfig={{
|
||||
can_start_without_user_input: true,
|
||||
@ -919,7 +982,13 @@ describe('<ScheduleForm />', () => {
|
||||
ask_limit_on_launch: false,
|
||||
ask_verbosity_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,
|
||||
variables_needed_to_start: [],
|
||||
credential_needed_to_start: false,
|
||||
@ -933,7 +1002,9 @@ describe('<ScheduleForm />', () => {
|
||||
/>
|
||||
);
|
||||
});
|
||||
expect(SchedulesAPI.readZoneInfo).toBeCalled();
|
||||
expect(SchedulesAPI.readCredentials).toBeCalledWith(27);
|
||||
expect(SchedulesAPI.readAllLabels).toBeCalledWith(27);
|
||||
});
|
||||
|
||||
test('should not call API to get credentials ', async () => {
|
||||
@ -961,6 +1032,12 @@ describe('<ScheduleForm />', () => {
|
||||
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,
|
||||
@ -991,6 +1068,30 @@ describe('<ScheduleForm />', () => {
|
||||
name: 'Foo Project',
|
||||
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,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user