mirror of
https://github.com/ansible/awx.git
synced 2026-05-10 02:47:36 -02:30
Refactors to add warning icon and disable save if schedule has missing values
This commit is contained in:
@@ -19,7 +19,13 @@ import ScheduleEdit from './ScheduleEdit';
|
|||||||
import { SchedulesAPI } from '../../api';
|
import { SchedulesAPI } from '../../api';
|
||||||
import useRequest from '../../util/useRequest';
|
import useRequest from '../../util/useRequest';
|
||||||
|
|
||||||
function Schedule({ i18n, setBreadcrumb, resource }) {
|
function Schedule({
|
||||||
|
i18n,
|
||||||
|
setBreadcrumb,
|
||||||
|
resource,
|
||||||
|
launchConfig,
|
||||||
|
surveyConfig,
|
||||||
|
}) {
|
||||||
const { scheduleId } = useParams();
|
const { scheduleId } = useParams();
|
||||||
|
|
||||||
const { pathname } = useLocation();
|
const { pathname } = useLocation();
|
||||||
@@ -100,13 +106,18 @@ function Schedule({ i18n, setBreadcrumb, resource }) {
|
|||||||
/>
|
/>
|
||||||
{schedule && [
|
{schedule && [
|
||||||
<Route key="edit" path={`${pathRoot}schedules/:id/edit`}>
|
<Route key="edit" path={`${pathRoot}schedules/:id/edit`}>
|
||||||
<ScheduleEdit schedule={schedule} resource={resource} />
|
<ScheduleEdit
|
||||||
|
schedule={schedule}
|
||||||
|
resource={resource}
|
||||||
|
launchConfig={launchConfig}
|
||||||
|
surveyConfig={surveyConfig}
|
||||||
|
/>
|
||||||
</Route>,
|
</Route>,
|
||||||
<Route
|
<Route
|
||||||
key="details"
|
key="details"
|
||||||
path={`${pathRoot}schedules/:scheduleId/details`}
|
path={`${pathRoot}schedules/:scheduleId/details`}
|
||||||
>
|
>
|
||||||
<ScheduleDetail schedule={schedule} />
|
<ScheduleDetail schedule={schedule} surveyConfig={surveyConfig} />
|
||||||
</Route>,
|
</Route>,
|
||||||
]}
|
]}
|
||||||
<Route key="not-found" path="*">
|
<Route key="not-found" path="*">
|
||||||
|
|||||||
@@ -15,14 +15,18 @@ 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';
|
||||||
|
|
||||||
function ScheduleAdd({ i18n, resource, apiModel }) {
|
function ScheduleAdd({ i18n, resource, apiModel, launchConfig, surveyConfig }) {
|
||||||
const [formSubmitError, setFormSubmitError] = useState(null);
|
const [formSubmitError, setFormSubmitError] = useState(null);
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const { pathname } = location;
|
const { pathname } = location;
|
||||||
const pathRoot = pathname.substr(0, pathname.indexOf('schedules'));
|
const pathRoot = pathname.substr(0, pathname.indexOf('schedules'));
|
||||||
|
|
||||||
const handleSubmit = async (values, launchConfig, surveyConfig) => {
|
const handleSubmit = async (
|
||||||
|
values,
|
||||||
|
launchConfiguration,
|
||||||
|
surveyConfiguration
|
||||||
|
) => {
|
||||||
const {
|
const {
|
||||||
inventory,
|
inventory,
|
||||||
extra_vars,
|
extra_vars,
|
||||||
@@ -51,8 +55,9 @@ function ScheduleAdd({ i18n, resource, apiModel }) {
|
|||||||
let extraVars;
|
let extraVars;
|
||||||
const surveyValues = getSurveyValues(values);
|
const surveyValues = getSurveyValues(values);
|
||||||
const initialExtraVars =
|
const initialExtraVars =
|
||||||
launchConfig?.ask_variables_on_launch && (values.extra_vars || '---');
|
launchConfiguration?.ask_variables_on_launch &&
|
||||||
if (surveyConfig?.spec) {
|
(values.extra_vars || '---');
|
||||||
|
if (surveyConfiguration?.spec) {
|
||||||
extraVars = yaml.safeDump(mergeExtraVars(initialExtraVars, surveyValues));
|
extraVars = yaml.safeDump(mergeExtraVars(initialExtraVars, surveyValues));
|
||||||
} else {
|
} else {
|
||||||
extraVars = yaml.safeDump(mergeExtraVars(initialExtraVars, {}));
|
extraVars = yaml.safeDump(mergeExtraVars(initialExtraVars, {}));
|
||||||
@@ -92,6 +97,8 @@ function ScheduleAdd({ i18n, resource, apiModel }) {
|
|||||||
handleCancel={() => history.push(`${pathRoot}schedules`)}
|
handleCancel={() => history.push(`${pathRoot}schedules`)}
|
||||||
handleSubmit={handleSubmit}
|
handleSubmit={handleSubmit}
|
||||||
submitError={formSubmitError}
|
submitError={formSubmitError}
|
||||||
|
launchConfig={launchConfig}
|
||||||
|
surveyConfig={surveyConfig}
|
||||||
resource={resource}
|
resource={resource}
|
||||||
/>
|
/>
|
||||||
</CardBody>
|
</CardBody>
|
||||||
|
|||||||
@@ -19,45 +19,45 @@ SchedulesAPI.readZoneInfo.mockResolvedValue({
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
JobTemplatesAPI.readLaunch.mockResolvedValue({
|
|
||||||
data: {
|
const launchConfig = {
|
||||||
can_start_without_user_input: false,
|
can_start_without_user_input: false,
|
||||||
passwords_needed_to_start: [],
|
passwords_needed_to_start: [],
|
||||||
ask_scm_branch_on_launch: false,
|
ask_scm_branch_on_launch: false,
|
||||||
ask_variables_on_launch: false,
|
ask_variables_on_launch: false,
|
||||||
ask_tags_on_launch: false,
|
ask_tags_on_launch: false,
|
||||||
ask_diff_mode_on_launch: false,
|
ask_diff_mode_on_launch: false,
|
||||||
ask_skip_tags_on_launch: false,
|
ask_skip_tags_on_launch: false,
|
||||||
ask_job_type_on_launch: false,
|
ask_job_type_on_launch: false,
|
||||||
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: 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,
|
||||||
inventory_needed_to_start: true,
|
inventory_needed_to_start: true,
|
||||||
job_template_data: {
|
job_template_data: {
|
||||||
name: 'Demo Job Template',
|
name: 'Demo Job Template',
|
||||||
id: 7,
|
id: 7,
|
||||||
description: '',
|
description: '',
|
||||||
},
|
|
||||||
defaults: {
|
|
||||||
extra_vars: '---',
|
|
||||||
diff_mode: false,
|
|
||||||
limit: '',
|
|
||||||
job_tags: '',
|
|
||||||
skip_tags: '',
|
|
||||||
job_type: 'run',
|
|
||||||
verbosity: 0,
|
|
||||||
inventory: {
|
|
||||||
name: null,
|
|
||||||
id: null,
|
|
||||||
},
|
|
||||||
scm_branch: '',
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
});
|
defaults: {
|
||||||
|
extra_vars: '---',
|
||||||
|
diff_mode: false,
|
||||||
|
limit: '',
|
||||||
|
job_tags: '',
|
||||||
|
skip_tags: '',
|
||||||
|
job_type: 'run',
|
||||||
|
verbosity: 0,
|
||||||
|
inventory: {
|
||||||
|
name: null,
|
||||||
|
id: null,
|
||||||
|
},
|
||||||
|
scm_branch: '',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
JobTemplatesAPI.createSchedule.mockResolvedValue({ data: { id: 3 } });
|
JobTemplatesAPI.createSchedule.mockResolvedValue({ data: { id: 3 } });
|
||||||
|
|
||||||
let wrapper;
|
let wrapper;
|
||||||
@@ -74,6 +74,7 @@ describe('<ScheduleAdd />', () => {
|
|||||||
inventory: 2,
|
inventory: 2,
|
||||||
summary_fields: { credentials: [] },
|
summary_fields: { credentials: [] },
|
||||||
}}
|
}}
|
||||||
|
launchConfig={launchConfig}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -377,7 +378,6 @@ describe('<ScheduleAdd />', () => {
|
|||||||
);
|
);
|
||||||
wrapper.update();
|
wrapper.update();
|
||||||
expect(wrapper.find('Wizard').length).toBe(0);
|
expect(wrapper.find('Wizard').length).toBe(0);
|
||||||
// console.log(wrapper.debug());
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
wrapper.find('Formik').invoke('onSubmit')({
|
wrapper.find('Formik').invoke('onSubmit')({
|
||||||
name: 'Schedule',
|
name: 'Schedule',
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ const PromptDetailList = styled(DetailList)`
|
|||||||
padding: 0px 20px;
|
padding: 0px 20px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
function ScheduleDetail({ schedule, i18n }) {
|
function ScheduleDetail({ schedule, i18n, surveyConfig }) {
|
||||||
const {
|
const {
|
||||||
id,
|
id,
|
||||||
created,
|
created,
|
||||||
@@ -148,6 +148,7 @@ function ScheduleDetail({ schedule, i18n }) {
|
|||||||
|
|
||||||
const {
|
const {
|
||||||
ask_credential_on_launch,
|
ask_credential_on_launch,
|
||||||
|
inventory_needed_to_start,
|
||||||
ask_diff_mode_on_launch,
|
ask_diff_mode_on_launch,
|
||||||
ask_inventory_on_launch,
|
ask_inventory_on_launch,
|
||||||
ask_job_type_on_launch,
|
ask_job_type_on_launch,
|
||||||
@@ -160,6 +161,41 @@ function ScheduleDetail({ schedule, i18n }) {
|
|||||||
survey_enabled,
|
survey_enabled,
|
||||||
} = launchData || {};
|
} = launchData || {};
|
||||||
|
|
||||||
|
const missingRequiredInventory = () => {
|
||||||
|
if (!inventory_needed_to_start || schedule?.summary_fields?.inventory?.id) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const hasMissingSurveyValue = () => {
|
||||||
|
let missingValues = false;
|
||||||
|
if (survey_enabled) {
|
||||||
|
surveyConfig.spec.forEach(question => {
|
||||||
|
const hasDefaultValue = Boolean(question.default);
|
||||||
|
if (question.required && !hasDefaultValue) {
|
||||||
|
const extraDataKeys = Object.keys(schedule?.extra_data);
|
||||||
|
|
||||||
|
const hasMatchingKey = extraDataKeys.includes(question.variable);
|
||||||
|
Object.values(schedule?.extra_data).forEach(value => {
|
||||||
|
if (!value || !hasMatchingKey) {
|
||||||
|
missingValues = true;
|
||||||
|
} else {
|
||||||
|
missingValues = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (!Object.values(schedule.extra_data).length) {
|
||||||
|
missingValues = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return missingValues;
|
||||||
|
};
|
||||||
|
const isDisabled = Boolean(
|
||||||
|
missingRequiredInventory() || hasMissingSurveyValue()
|
||||||
|
);
|
||||||
|
|
||||||
const showCredentialsDetail =
|
const showCredentialsDetail =
|
||||||
ask_credential_on_launch && credentials.length > 0;
|
ask_credential_on_launch && credentials.length > 0;
|
||||||
const showInventoryDetail = ask_inventory_on_launch && inventory;
|
const showInventoryDetail = ask_inventory_on_launch && inventory;
|
||||||
@@ -189,14 +225,6 @@ function ScheduleDetail({ schedule, i18n }) {
|
|||||||
showVerbosityDetail ||
|
showVerbosityDetail ||
|
||||||
showVariablesDetail;
|
showVariablesDetail;
|
||||||
|
|
||||||
const VERBOSITY = {
|
|
||||||
0: i18n._(t`0 (Normal)`),
|
|
||||||
1: i18n._(t`1 (Verbose)`),
|
|
||||||
2: i18n._(t`2 (More Verbose)`),
|
|
||||||
3: i18n._(t`3 (Debug)`),
|
|
||||||
4: i18n._(t`4 (Connection Debug)`),
|
|
||||||
};
|
|
||||||
|
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
return <ContentLoading />;
|
return <ContentLoading />;
|
||||||
}
|
}
|
||||||
@@ -207,7 +235,11 @@ function ScheduleDetail({ schedule, i18n }) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<CardBody>
|
<CardBody>
|
||||||
<ScheduleToggle schedule={schedule} css="padding-bottom: 40px" />
|
<ScheduleToggle
|
||||||
|
schedule={schedule}
|
||||||
|
css="padding-bottom: 40px"
|
||||||
|
isDisabled={isDisabled}
|
||||||
|
/>
|
||||||
<DetailList gutter="sm">
|
<DetailList gutter="sm">
|
||||||
<Detail label={i18n._(t`Name`)} value={name} />
|
<Detail label={i18n._(t`Name`)} value={name} />
|
||||||
<Detail label={i18n._(t`Description`)} value={description} />
|
<Detail label={i18n._(t`Description`)} value={description} />
|
||||||
@@ -279,12 +311,6 @@ function ScheduleDetail({ schedule, i18n }) {
|
|||||||
{ask_limit_on_launch && (
|
{ask_limit_on_launch && (
|
||||||
<Detail label={i18n._(t`Limit`)} value={limit} />
|
<Detail label={i18n._(t`Limit`)} value={limit} />
|
||||||
)}
|
)}
|
||||||
{ask_verbosity_on_launch && (
|
|
||||||
<Detail
|
|
||||||
label={i18n._(t`Verbosity`)}
|
|
||||||
value={VERBOSITY[verbosity]}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{showDiffModeDetail && (
|
{showDiffModeDetail && (
|
||||||
<Detail
|
<Detail
|
||||||
label={i18n._(t`Show Changes`)}
|
label={i18n._(t`Show Changes`)}
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ const allPrompts = {
|
|||||||
ask_variables_on_launch: true,
|
ask_variables_on_launch: true,
|
||||||
ask_verbosity_on_launch: true,
|
ask_verbosity_on_launch: true,
|
||||||
survey_enabled: true,
|
survey_enabled: true,
|
||||||
|
inventory_needed_to_start: true,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -489,4 +490,39 @@ describe('<ScheduleDetail />', () => {
|
|||||||
);
|
);
|
||||||
expect(SchedulesAPI.destroy).toHaveBeenCalledTimes(1);
|
expect(SchedulesAPI.destroy).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
test('should have disabled toggle', async () => {
|
||||||
|
SchedulesAPI.readCredentials.mockResolvedValueOnce({
|
||||||
|
data: {
|
||||||
|
count: 0,
|
||||||
|
results: [],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
JobTemplatesAPI.readLaunch.mockResolvedValueOnce(allPrompts);
|
||||||
|
await act(async () => {
|
||||||
|
wrapper = mountWithContexts(
|
||||||
|
<Route
|
||||||
|
path="/templates/job_template/:id/schedules/:scheduleId"
|
||||||
|
component={() => (
|
||||||
|
<ScheduleDetail schedule={schedule} surveyConfig={{ spec: [] }} />
|
||||||
|
)}
|
||||||
|
/>,
|
||||||
|
{
|
||||||
|
context: {
|
||||||
|
router: {
|
||||||
|
history,
|
||||||
|
route: {
|
||||||
|
location: history.location,
|
||||||
|
match: { params: { id: 1 } },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
await waitForElement(
|
||||||
|
wrapper,
|
||||||
|
'ScheduleToggle',
|
||||||
|
el => el.prop('isDisabled') === true
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -15,7 +15,13 @@ 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';
|
||||||
|
|
||||||
function ScheduleEdit({ i18n, schedule, resource }) {
|
function ScheduleEdit({
|
||||||
|
i18n,
|
||||||
|
schedule,
|
||||||
|
resource,
|
||||||
|
launchConfig,
|
||||||
|
surveyConfig,
|
||||||
|
}) {
|
||||||
const [formSubmitError, setFormSubmitError] = useState(null);
|
const [formSubmitError, setFormSubmitError] = useState(null);
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
@@ -24,8 +30,8 @@ function ScheduleEdit({ i18n, schedule, resource }) {
|
|||||||
|
|
||||||
const handleSubmit = async (
|
const handleSubmit = async (
|
||||||
values,
|
values,
|
||||||
launchConfig,
|
launchConfiguration,
|
||||||
surveyConfig,
|
surveyConfiguration,
|
||||||
scheduleCredentials = []
|
scheduleCredentials = []
|
||||||
) => {
|
) => {
|
||||||
const {
|
const {
|
||||||
@@ -36,32 +42,40 @@ function ScheduleEdit({ i18n, schedule, resource }) {
|
|||||||
interval,
|
interval,
|
||||||
startDateTime,
|
startDateTime,
|
||||||
timezone,
|
timezone,
|
||||||
occurrences,
|
occurences,
|
||||||
runOn,
|
runOn,
|
||||||
runOnTheDay,
|
runOnTheDay,
|
||||||
runOnTheMonth,
|
runOnTheMonth,
|
||||||
runOnDayMonth,
|
runOnDayMonth,
|
||||||
runOnDayNumber,
|
runOnDayNumber,
|
||||||
endDateTime,
|
endDateTime,
|
||||||
runOnTheOccurrence,
|
runOnTheOccurence,
|
||||||
daysOfWeek,
|
daysOfWeek,
|
||||||
...submitValues
|
...submitValues
|
||||||
} = values;
|
} = values;
|
||||||
const { added, removed } = getAddedAndRemoved(
|
const { added, removed } = getAddedAndRemoved(
|
||||||
[...resource?.summary_fields.credentials, ...scheduleCredentials],
|
[...(resource?.summary_fields.credentials || []), ...scheduleCredentials],
|
||||||
credentials
|
credentials
|
||||||
);
|
);
|
||||||
|
|
||||||
let extraVars;
|
let extraVars;
|
||||||
const surveyValues = getSurveyValues(values);
|
const surveyValues = getSurveyValues(values);
|
||||||
const initialExtraVars =
|
const initialExtraVars =
|
||||||
launchConfig?.ask_variables_on_launch && (values.extra_vars || '---');
|
launchConfiguration?.ask_variables_on_launch &&
|
||||||
if (surveyConfig?.spec) {
|
(values.extra_vars || '---');
|
||||||
|
if (surveyConfiguration?.spec) {
|
||||||
extraVars = yaml.safeDump(mergeExtraVars(initialExtraVars, surveyValues));
|
extraVars = yaml.safeDump(mergeExtraVars(initialExtraVars, surveyValues));
|
||||||
} else {
|
} else {
|
||||||
extraVars = yaml.safeDump(mergeExtraVars(initialExtraVars, {}));
|
extraVars = yaml.safeDump(mergeExtraVars(initialExtraVars, {}));
|
||||||
}
|
}
|
||||||
submitValues.extra_data = extraVars && parseVariableField(extraVars);
|
submitValues.extra_data = extraVars && parseVariableField(extraVars);
|
||||||
|
|
||||||
|
if (
|
||||||
|
Object.keys(submitValues.extra_data).length === 0 &&
|
||||||
|
Object.keys(schedule.extra_data).length > 0
|
||||||
|
) {
|
||||||
|
submitValues.extra_data = schedule.extra_data;
|
||||||
|
}
|
||||||
delete values.extra_vars;
|
delete values.extra_vars;
|
||||||
if (inventory) {
|
if (inventory) {
|
||||||
submitValues.inventory = inventory.id;
|
submitValues.inventory = inventory.id;
|
||||||
@@ -103,6 +117,8 @@ function ScheduleEdit({ i18n, schedule, resource }) {
|
|||||||
handleSubmit={handleSubmit}
|
handleSubmit={handleSubmit}
|
||||||
submitError={formSubmitError}
|
submitError={formSubmitError}
|
||||||
resource={resource}
|
resource={resource}
|
||||||
|
launchConfig={launchConfig}
|
||||||
|
surveyConfig={surveyConfig}
|
||||||
/>
|
/>
|
||||||
</CardBody>
|
</CardBody>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import {
|
|||||||
} from '../../../../testUtils/enzymeHelpers';
|
} from '../../../../testUtils/enzymeHelpers';
|
||||||
import {
|
import {
|
||||||
SchedulesAPI,
|
SchedulesAPI,
|
||||||
JobTemplatesAPI,
|
|
||||||
InventoriesAPI,
|
InventoriesAPI,
|
||||||
CredentialsAPI,
|
CredentialsAPI,
|
||||||
CredentialTypesAPI,
|
CredentialTypesAPI,
|
||||||
@@ -28,46 +27,6 @@ SchedulesAPI.readZoneInfo.mockResolvedValue({
|
|||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
JobTemplatesAPI.readLaunch.mockResolvedValue({
|
|
||||||
data: {
|
|
||||||
can_start_without_user_input: false,
|
|
||||||
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: true,
|
|
||||||
ask_credential_on_launch: true,
|
|
||||||
survey_enabled: false,
|
|
||||||
variables_needed_to_start: [],
|
|
||||||
credential_needed_to_start: true,
|
|
||||||
inventory_needed_to_start: true,
|
|
||||||
job_template_data: {
|
|
||||||
name: 'Demo Job Template',
|
|
||||||
id: 7,
|
|
||||||
description: '',
|
|
||||||
},
|
|
||||||
defaults: {
|
|
||||||
extra_vars: '---',
|
|
||||||
diff_mode: false,
|
|
||||||
limit: '',
|
|
||||||
job_tags: '',
|
|
||||||
skip_tags: '',
|
|
||||||
job_type: 'run',
|
|
||||||
verbosity: 0,
|
|
||||||
inventory: {
|
|
||||||
name: null,
|
|
||||||
id: null,
|
|
||||||
},
|
|
||||||
scm_branch: '',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
SchedulesAPI.readCredentials.mockResolvedValue({
|
SchedulesAPI.readCredentials.mockResolvedValue({
|
||||||
data: {
|
data: {
|
||||||
results: [
|
results: [
|
||||||
@@ -156,6 +115,44 @@ describe('<ScheduleEdit />', () => {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
|
launchConfig={{
|
||||||
|
can_start_without_user_input: false,
|
||||||
|
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: true,
|
||||||
|
ask_credential_on_launch: true,
|
||||||
|
survey_enabled: false,
|
||||||
|
variables_needed_to_start: [],
|
||||||
|
credential_needed_to_start: true,
|
||||||
|
inventory_needed_to_start: true,
|
||||||
|
job_template_data: {
|
||||||
|
name: 'Demo Job Template',
|
||||||
|
id: 7,
|
||||||
|
description: '',
|
||||||
|
},
|
||||||
|
defaults: {
|
||||||
|
extra_vars: '---',
|
||||||
|
diff_mode: false,
|
||||||
|
limit: '',
|
||||||
|
job_tags: '',
|
||||||
|
skip_tags: '',
|
||||||
|
job_type: 'run',
|
||||||
|
verbosity: 0,
|
||||||
|
inventory: {
|
||||||
|
name: null,
|
||||||
|
id: null,
|
||||||
|
},
|
||||||
|
scm_branch: '',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
surveyConfig={{}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -202,6 +199,7 @@ describe('<ScheduleEdit />', () => {
|
|||||||
description: 'test description',
|
description: 'test description',
|
||||||
name: 'Run every 10 minutes 10 times',
|
name: 'Run every 10 minutes 10 times',
|
||||||
extra_data: {},
|
extra_data: {},
|
||||||
|
occurrences: 10,
|
||||||
rrule:
|
rrule:
|
||||||
'DTSTART;TZID=America/New_York:20200325T103000 RRULE:INTERVAL=10;FREQ=MINUTELY;COUNT=10',
|
'DTSTART;TZID=America/New_York:20200325T103000 RRULE:INTERVAL=10;FREQ=MINUTELY;COUNT=10',
|
||||||
});
|
});
|
||||||
@@ -265,6 +263,7 @@ describe('<ScheduleEdit />', () => {
|
|||||||
description: 'test description',
|
description: 'test description',
|
||||||
name: 'Run weekly on mon/wed/fri',
|
name: 'Run weekly on mon/wed/fri',
|
||||||
extra_data: {},
|
extra_data: {},
|
||||||
|
occurrences: 1,
|
||||||
rrule: `DTSTART;TZID=America/New_York:20200325T104500 RRULE:INTERVAL=1;FREQ=WEEKLY;BYDAY=${RRule.MO},${RRule.WE},${RRule.FR}`,
|
rrule: `DTSTART;TZID=America/New_York:20200325T104500 RRULE:INTERVAL=1;FREQ=WEEKLY;BYDAY=${RRule.MO},${RRule.WE},${RRule.FR}`,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -287,6 +286,7 @@ describe('<ScheduleEdit />', () => {
|
|||||||
description: 'test description',
|
description: 'test description',
|
||||||
name: 'Run on the first day of the month',
|
name: 'Run on the first day of the month',
|
||||||
extra_data: {},
|
extra_data: {},
|
||||||
|
occurrences: 1,
|
||||||
rrule:
|
rrule:
|
||||||
'DTSTART;TZID=America/New_York:20200401T104500 RRULE:INTERVAL=1;FREQ=MONTHLY;BYMONTHDAY=1',
|
'DTSTART;TZID=America/New_York:20200401T104500 RRULE:INTERVAL=1;FREQ=MONTHLY;BYMONTHDAY=1',
|
||||||
});
|
});
|
||||||
@@ -312,6 +312,8 @@ describe('<ScheduleEdit />', () => {
|
|||||||
description: 'test description',
|
description: 'test description',
|
||||||
name: 'Run monthly on the last Tuesday',
|
name: 'Run monthly on the last Tuesday',
|
||||||
extra_data: {},
|
extra_data: {},
|
||||||
|
occurrences: 1,
|
||||||
|
runOnTheOccurrence: -1,
|
||||||
rrule:
|
rrule:
|
||||||
'DTSTART;TZID=America/New_York:20200331T110000 RRULE:INTERVAL=1;FREQ=MONTHLY;BYSETPOS=-1;BYDAY=TU',
|
'DTSTART;TZID=America/New_York:20200331T110000 RRULE:INTERVAL=1;FREQ=MONTHLY;BYSETPOS=-1;BYDAY=TU',
|
||||||
});
|
});
|
||||||
@@ -336,6 +338,7 @@ describe('<ScheduleEdit />', () => {
|
|||||||
description: 'test description',
|
description: 'test description',
|
||||||
name: 'Yearly on the first day of March',
|
name: 'Yearly on the first day of March',
|
||||||
extra_data: {},
|
extra_data: {},
|
||||||
|
occurrences: 1,
|
||||||
rrule:
|
rrule:
|
||||||
'DTSTART;TZID=America/New_York:20200301T000000 RRULE:INTERVAL=1;FREQ=YEARLY;BYMONTH=3;BYMONTHDAY=1',
|
'DTSTART;TZID=America/New_York:20200301T000000 RRULE:INTERVAL=1;FREQ=YEARLY;BYMONTH=3;BYMONTHDAY=1',
|
||||||
});
|
});
|
||||||
@@ -361,6 +364,8 @@ describe('<ScheduleEdit />', () => {
|
|||||||
description: 'test description',
|
description: 'test description',
|
||||||
name: 'Yearly on the second Friday in April',
|
name: 'Yearly on the second Friday in April',
|
||||||
extra_data: {},
|
extra_data: {},
|
||||||
|
occurrences: 1,
|
||||||
|
runOnTheOccurrence: 2,
|
||||||
rrule:
|
rrule:
|
||||||
'DTSTART;TZID=America/New_York:20200410T111500 RRULE:INTERVAL=1;FREQ=YEARLY;BYSETPOS=2;BYDAY=FR;BYMONTH=4',
|
'DTSTART;TZID=America/New_York:20200410T111500 RRULE:INTERVAL=1;FREQ=YEARLY;BYSETPOS=2;BYDAY=FR;BYMONTH=4',
|
||||||
});
|
});
|
||||||
@@ -386,6 +391,8 @@ describe('<ScheduleEdit />', () => {
|
|||||||
description: 'test description',
|
description: 'test description',
|
||||||
name: 'Yearly on the first weekday in October',
|
name: 'Yearly on the first weekday in October',
|
||||||
extra_data: {},
|
extra_data: {},
|
||||||
|
occurrences: 1,
|
||||||
|
runOnTheOccurrence: 1,
|
||||||
rrule:
|
rrule:
|
||||||
'DTSTART;TZID=America/New_York:20200410T111500 RRULE:INTERVAL=1;FREQ=YEARLY;BYSETPOS=1;BYDAY=MO,TU,WE,TH,FR;BYMONTH=10',
|
'DTSTART;TZID=America/New_York:20200410T111500 RRULE:INTERVAL=1;FREQ=YEARLY;BYSETPOS=1;BYDAY=MO,TU,WE,TH,FR;BYMONTH=10',
|
||||||
});
|
});
|
||||||
@@ -515,6 +522,8 @@ describe('<ScheduleEdit />', () => {
|
|||||||
expect(SchedulesAPI.update).toBeCalledWith(27, {
|
expect(SchedulesAPI.update).toBeCalledWith(27, {
|
||||||
extra_data: {},
|
extra_data: {},
|
||||||
name: 'mock schedule',
|
name: 'mock schedule',
|
||||||
|
occurrences: 1,
|
||||||
|
runOnTheOccurrence: 1,
|
||||||
rrule:
|
rrule:
|
||||||
'DTSTART;TZID=America/New_York:20210128T141500 RRULE:COUNT=1;FREQ=MINUTELY',
|
'DTSTART;TZID=America/New_York:20210128T141500 RRULE:COUNT=1;FREQ=MINUTELY',
|
||||||
skip_tags: '',
|
skip_tags: '',
|
||||||
@@ -590,8 +599,10 @@ describe('<ScheduleEdit />', () => {
|
|||||||
expect(SchedulesAPI.update).toBeCalledWith(27, {
|
expect(SchedulesAPI.update).toBeCalledWith(27, {
|
||||||
description: '',
|
description: '',
|
||||||
extra_data: {},
|
extra_data: {},
|
||||||
inventory: 702,
|
occurrences: 1,
|
||||||
|
runOnTheOccurrence: 1,
|
||||||
name: 'foo',
|
name: 'foo',
|
||||||
|
inventory: 702,
|
||||||
rrule:
|
rrule:
|
||||||
'DTSTART;TZID=America/New_York:20200402T144500 RRULE:INTERVAL=1;COUNT=1;FREQ=MINUTELY',
|
'DTSTART;TZID=America/New_York:20200402T144500 RRULE:INTERVAL=1;COUNT=1;FREQ=MINUTELY',
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -24,6 +24,9 @@ function ScheduleList({
|
|||||||
loadSchedules,
|
loadSchedules,
|
||||||
loadScheduleOptions,
|
loadScheduleOptions,
|
||||||
hideAddButton,
|
hideAddButton,
|
||||||
|
resource,
|
||||||
|
launchConfig,
|
||||||
|
surveyConfig,
|
||||||
}) {
|
}) {
|
||||||
const [selected, setSelected] = useState([]);
|
const [selected, setSelected] = useState([]);
|
||||||
|
|
||||||
@@ -114,6 +117,47 @@ function ScheduleList({
|
|||||||
actions &&
|
actions &&
|
||||||
Object.prototype.hasOwnProperty.call(actions, 'POST') &&
|
Object.prototype.hasOwnProperty.call(actions, 'POST') &&
|
||||||
!hideAddButton;
|
!hideAddButton;
|
||||||
|
const isTemplate =
|
||||||
|
resource?.type === 'workflow_job_template' ||
|
||||||
|
resource?.type === 'job_template';
|
||||||
|
|
||||||
|
const missingRequiredInventory = schedule => {
|
||||||
|
if (
|
||||||
|
!launchConfig.inventory_needed_to_start ||
|
||||||
|
schedule?.summary_fields?.inventory?.id
|
||||||
|
) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return i18n._(t`This schedule is missing an Inventory`);
|
||||||
|
};
|
||||||
|
|
||||||
|
const hasMissingSurveyValue = schedule => {
|
||||||
|
let missingValues;
|
||||||
|
if (launchConfig.survey_enabled) {
|
||||||
|
surveyConfig.spec.forEach(question => {
|
||||||
|
const hasDefaultValue = Boolean(question.default);
|
||||||
|
if (question.required && !hasDefaultValue) {
|
||||||
|
const extraDataKeys = Object.keys(schedule?.extra_data);
|
||||||
|
|
||||||
|
const hasMatchingKey = extraDataKeys.includes(question.variable);
|
||||||
|
Object.values(schedule?.extra_data).forEach(value => {
|
||||||
|
if (!value || !hasMatchingKey) {
|
||||||
|
missingValues = true;
|
||||||
|
} else {
|
||||||
|
missingValues = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (!Object.values(schedule.extra_data).length) {
|
||||||
|
missingValues = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
missingValues &&
|
||||||
|
i18n._(t`This schedule is missing required survey values`)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -139,6 +183,8 @@ function ScheduleList({
|
|||||||
onSelect={() => handleSelect(item)}
|
onSelect={() => handleSelect(item)}
|
||||||
schedule={item}
|
schedule={item}
|
||||||
rowIndex={index}
|
rowIndex={index}
|
||||||
|
isMissingInventory={isTemplate && missingRequiredInventory(item)}
|
||||||
|
isMissingSurvey={isTemplate && hasMissingSurveyValue(item)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
toolbarSearchColumns={[
|
toolbarSearchColumns={[
|
||||||
|
|||||||
@@ -32,19 +32,22 @@ describe('ScheduleList', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('read call successful', () => {
|
describe('read call successful', () => {
|
||||||
beforeAll(async () => {
|
beforeEach(async () => {
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
wrapper = mountWithContexts(
|
wrapper = mountWithContexts(
|
||||||
<ScheduleList
|
<ScheduleList
|
||||||
loadSchedules={loadSchedules}
|
loadSchedules={loadSchedules}
|
||||||
loadScheduleOptions={loadScheduleOptions}
|
loadScheduleOptions={loadScheduleOptions}
|
||||||
|
resource={{ type: 'job_template', inventory: 1 }}
|
||||||
|
launchConfig={{ survey_enabled: false }}
|
||||||
|
surveyConfig={{}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
wrapper.update();
|
wrapper.update();
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(() => {
|
afterEach(() => {
|
||||||
wrapper.unmount();
|
wrapper.unmount();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -203,6 +206,60 @@ describe('ScheduleList', () => {
|
|||||||
wrapper.update();
|
wrapper.update();
|
||||||
expect(wrapper.find('ToolbarAddButton').length).toBe(0);
|
expect(wrapper.find('ToolbarAddButton').length).toBe(0);
|
||||||
});
|
});
|
||||||
|
test('should show missing resource icon and disabled toggle', async () => {
|
||||||
|
await act(async () => {
|
||||||
|
wrapper = mountWithContexts(
|
||||||
|
<ScheduleList
|
||||||
|
loadSchedules={loadSchedules}
|
||||||
|
loadScheduleOptions={loadScheduleOptions}
|
||||||
|
hideAddButton
|
||||||
|
resource={{ type: 'job_template', inventory: 1 }}
|
||||||
|
launchConfig={{ survey_enabled: true }}
|
||||||
|
surveyConfig={{ spec: [{ required: true, default: null }] }}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
wrapper.update();
|
||||||
|
expect(
|
||||||
|
wrapper
|
||||||
|
.find('ScheduleListItem')
|
||||||
|
.at(4)
|
||||||
|
.prop('isMissingSurvey')
|
||||||
|
).toBe('This schedule is missing required survey values');
|
||||||
|
expect(wrapper.find('ExclamationTriangleIcon').length).toBe(5);
|
||||||
|
expect(wrapper.find('Switch#schedule-5-toggle').prop('isDisabled')).toBe(
|
||||||
|
true
|
||||||
|
);
|
||||||
|
});
|
||||||
|
test('should show missing resource icon and disabled toggle', async () => {
|
||||||
|
await act(async () => {
|
||||||
|
wrapper = mountWithContexts(
|
||||||
|
<ScheduleList
|
||||||
|
loadSchedules={loadSchedules}
|
||||||
|
loadScheduleOptions={loadScheduleOptions}
|
||||||
|
hideAddButton
|
||||||
|
resource={{ type: 'job_template' }}
|
||||||
|
launchConfig={{
|
||||||
|
survey_enabled: true,
|
||||||
|
inventory_needed_to_start: true,
|
||||||
|
}}
|
||||||
|
surveyConfig={{ spec: [] }}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
wrapper.update();
|
||||||
|
|
||||||
|
expect(
|
||||||
|
wrapper
|
||||||
|
.find('ScheduleListItem')
|
||||||
|
.at(3)
|
||||||
|
.prop('isMissingInventory')
|
||||||
|
).toBe('This schedule is missing an Inventory');
|
||||||
|
expect(wrapper.find('ExclamationTriangleIcon').length).toBe(4);
|
||||||
|
expect(wrapper.find('Switch#schedule-3-toggle').prop('isDisabled')).toBe(
|
||||||
|
true
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('read call unsuccessful', () => {
|
describe('read call unsuccessful', () => {
|
||||||
|
|||||||
@@ -4,16 +4,33 @@ import { bool, func } from 'prop-types';
|
|||||||
import { withI18n } from '@lingui/react';
|
import { withI18n } from '@lingui/react';
|
||||||
import { t } from '@lingui/macro';
|
import { t } from '@lingui/macro';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import { Button } from '@patternfly/react-core';
|
import { Button, Tooltip } from '@patternfly/react-core';
|
||||||
import { Tr, Td } from '@patternfly/react-table';
|
import { Tr, Td } from '@patternfly/react-table';
|
||||||
import { PencilAltIcon } from '@patternfly/react-icons';
|
import {
|
||||||
|
PencilAltIcon,
|
||||||
|
ExclamationTriangleIcon as PFExclamationTriangleIcon,
|
||||||
|
} from '@patternfly/react-icons';
|
||||||
|
import styled from 'styled-components';
|
||||||
import { DetailList, Detail } from '../../DetailList';
|
import { DetailList, Detail } from '../../DetailList';
|
||||||
import { ActionsTd, ActionItem } from '../../PaginatedTable';
|
import { ActionsTd, ActionItem } from '../../PaginatedTable';
|
||||||
import { ScheduleToggle } from '..';
|
import { ScheduleToggle } from '..';
|
||||||
import { Schedule } from '../../../types';
|
import { Schedule } from '../../../types';
|
||||||
import { formatDateString } from '../../../util/dates';
|
import { formatDateString } from '../../../util/dates';
|
||||||
|
|
||||||
function ScheduleListItem({ i18n, isSelected, onSelect, schedule, rowIndex }) {
|
const ExclamationTriangleIcon = styled(PFExclamationTriangleIcon)`
|
||||||
|
color: #c9190b;
|
||||||
|
margin-left: 20px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
function ScheduleListItem({
|
||||||
|
i18n,
|
||||||
|
rowIndex,
|
||||||
|
isSelected,
|
||||||
|
onSelect,
|
||||||
|
schedule,
|
||||||
|
isMissingInventory,
|
||||||
|
isMissingSurvey,
|
||||||
|
}) {
|
||||||
const labelId = `check-action-${schedule.id}`;
|
const labelId = `check-action-${schedule.id}`;
|
||||||
|
|
||||||
const jobTypeLabels = {
|
const jobTypeLabels = {
|
||||||
@@ -45,6 +62,7 @@ function ScheduleListItem({ i18n, isSelected, onSelect, schedule, rowIndex }) {
|
|||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
const isDisabled = Boolean(isMissingInventory || isMissingSurvey);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tr id={`schedule-row-${schedule.id}`}>
|
<Tr id={`schedule-row-${schedule.id}`}>
|
||||||
@@ -61,6 +79,18 @@ function ScheduleListItem({ i18n, isSelected, onSelect, schedule, rowIndex }) {
|
|||||||
<Link to={`${scheduleBaseUrl}/details`}>
|
<Link to={`${scheduleBaseUrl}/details`}>
|
||||||
<b>{schedule.name}</b>
|
<b>{schedule.name}</b>
|
||||||
</Link>
|
</Link>
|
||||||
|
{Boolean(isMissingInventory || isMissingSurvey) && (
|
||||||
|
<span>
|
||||||
|
<Tooltip
|
||||||
|
content={[isMissingInventory, isMissingSurvey].map(message => (
|
||||||
|
<div key={message}>{message}</div>
|
||||||
|
))}
|
||||||
|
position="right"
|
||||||
|
>
|
||||||
|
<ExclamationTriangleIcon />
|
||||||
|
</Tooltip>
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
</Td>
|
</Td>
|
||||||
<Td dataLabel={i18n._(t`Type`)}>
|
<Td dataLabel={i18n._(t`Type`)}>
|
||||||
{
|
{
|
||||||
@@ -80,7 +110,7 @@ function ScheduleListItem({ i18n, isSelected, onSelect, schedule, rowIndex }) {
|
|||||||
)}
|
)}
|
||||||
</Td>
|
</Td>
|
||||||
<ActionsTd dataLabel={i18n._(t`Actions`)} gridColumns="auto 40px">
|
<ActionsTd dataLabel={i18n._(t`Actions`)} gridColumns="auto 40px">
|
||||||
<ScheduleToggle schedule={schedule} />
|
<ScheduleToggle schedule={schedule} isDisabled={isDisabled} />
|
||||||
<ActionItem
|
<ActionItem
|
||||||
visible={schedule.summary_fields.user_capabilities.edit}
|
visible={schedule.summary_fields.user_capabilities.edit}
|
||||||
tooltip={i18n._(t`Edit Schedule`)}
|
tooltip={i18n._(t`Edit Schedule`)}
|
||||||
|
|||||||
@@ -50,15 +50,13 @@ describe('ScheduleListItem', () => {
|
|||||||
describe('User has edit permissions', () => {
|
describe('User has edit permissions', () => {
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
wrapper = mountWithContexts(
|
wrapper = mountWithContexts(
|
||||||
<table>
|
<ScheduleListItem
|
||||||
<tbody>
|
isSelected={false}
|
||||||
<ScheduleListItem
|
onSelect={onSelect}
|
||||||
isSelected={false}
|
schedule={mockSchedule}
|
||||||
onSelect={onSelect}
|
isMissingSurvey={false}
|
||||||
schedule={mockSchedule}
|
isMissingInventory={false}
|
||||||
/>
|
/>
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -118,6 +116,9 @@ describe('ScheduleListItem', () => {
|
|||||||
.simulate('change');
|
.simulate('change');
|
||||||
expect(onSelect).toHaveBeenCalledTimes(1);
|
expect(onSelect).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
test('Toggle button is enabled', () => {
|
||||||
|
expect(wrapper.find('ScheduleToggle').prop('isDisabled')).toBe(false);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('User has read-only permissions', () => {
|
describe('User has read-only permissions', () => {
|
||||||
@@ -186,4 +187,35 @@ describe('ScheduleListItem', () => {
|
|||||||
).toBe(true);
|
).toBe(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
describe('schedule has missing prompt data', () => {
|
||||||
|
beforeAll(() => {
|
||||||
|
wrapper = mountWithContexts(
|
||||||
|
<ScheduleListItem
|
||||||
|
isSelected={false}
|
||||||
|
onSelect={onSelect}
|
||||||
|
schedule={{
|
||||||
|
...mockSchedule,
|
||||||
|
summary_fields: {
|
||||||
|
...mockSchedule.summary_fields,
|
||||||
|
user_capabilities: {
|
||||||
|
edit: false,
|
||||||
|
delete: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
isMissingInventory="Inventory Error"
|
||||||
|
isMissingSurvey="Survey Error"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(() => {
|
||||||
|
wrapper.unmount();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should show missing resource icon', () => {
|
||||||
|
expect(wrapper.find('ExclamationTriangleIcon').length).toBe(1);
|
||||||
|
expect(wrapper.find('ScheduleToggle').prop('isDisabled')).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import ErrorDetail from '../../ErrorDetail';
|
|||||||
import useRequest from '../../../util/useRequest';
|
import useRequest from '../../../util/useRequest';
|
||||||
import { SchedulesAPI } from '../../../api';
|
import { SchedulesAPI } from '../../../api';
|
||||||
|
|
||||||
function ScheduleToggle({ schedule, onToggle, className, i18n }) {
|
function ScheduleToggle({ schedule, onToggle, className, i18n, isDisabled }) {
|
||||||
const [isEnabled, setIsEnabled] = useState(schedule.enabled);
|
const [isEnabled, setIsEnabled] = useState(schedule.enabled);
|
||||||
const [showError, setShowError] = useState(false);
|
const [showError, setShowError] = useState(false);
|
||||||
|
|
||||||
@@ -55,7 +55,9 @@ function ScheduleToggle({ schedule, onToggle, className, i18n }) {
|
|||||||
labelOff={i18n._(t`Off`)}
|
labelOff={i18n._(t`Off`)}
|
||||||
isChecked={isEnabled}
|
isChecked={isEnabled}
|
||||||
isDisabled={
|
isDisabled={
|
||||||
isLoading || !schedule.summary_fields.user_capabilities.edit
|
isLoading ||
|
||||||
|
!schedule.summary_fields.user_capabilities.edit ||
|
||||||
|
isDisabled
|
||||||
}
|
}
|
||||||
onChange={toggleSchedule}
|
onChange={toggleSchedule}
|
||||||
aria-label={i18n._(t`Toggle schedule`)}
|
aria-label={i18n._(t`Toggle schedule`)}
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ function Schedules({
|
|||||||
loadScheduleOptions,
|
loadScheduleOptions,
|
||||||
loadSchedules,
|
loadSchedules,
|
||||||
setBreadcrumb,
|
setBreadcrumb,
|
||||||
|
launchConfig,
|
||||||
|
surveyConfig,
|
||||||
resource,
|
resource,
|
||||||
}) {
|
}) {
|
||||||
const match = useRouteMatch();
|
const match = useRouteMatch();
|
||||||
@@ -17,14 +19,27 @@ function Schedules({
|
|||||||
return (
|
return (
|
||||||
<Switch>
|
<Switch>
|
||||||
<Route path={`${match.path}/add`}>
|
<Route path={`${match.path}/add`}>
|
||||||
<ScheduleAdd apiModel={apiModel} resource={resource} />
|
<ScheduleAdd
|
||||||
|
apiModel={apiModel}
|
||||||
|
resource={resource}
|
||||||
|
launchConfig={launchConfig}
|
||||||
|
surveyConfig={surveyConfig}
|
||||||
|
/>
|
||||||
</Route>
|
</Route>
|
||||||
<Route key="details" path={`${match.path}/:scheduleId`}>
|
<Route key="details" path={`${match.path}/:scheduleId`}>
|
||||||
<Schedule setBreadcrumb={setBreadcrumb} resource={resource} />
|
<Schedule
|
||||||
|
setBreadcrumb={setBreadcrumb}
|
||||||
|
resource={resource}
|
||||||
|
launchConfig={launchConfig}
|
||||||
|
surveyConfig={surveyConfig}
|
||||||
|
/>
|
||||||
</Route>
|
</Route>
|
||||||
<Route key="list" path={`${match.path}`}>
|
<Route key="list" path={`${match.path}`}>
|
||||||
<ScheduleList
|
<ScheduleList
|
||||||
|
resource={resource}
|
||||||
loadSchedules={loadSchedules}
|
loadSchedules={loadSchedules}
|
||||||
|
launchConfig={launchConfig}
|
||||||
|
surveyConfig={surveyConfig}
|
||||||
loadScheduleOptions={loadScheduleOptions}
|
loadScheduleOptions={loadScheduleOptions}
|
||||||
/>
|
/>
|
||||||
</Route>
|
</Route>
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
"rrule":
|
"rrule":
|
||||||
"DTSTART;TZID=America/New_York:20200220T000000 RRULE:FREQ=DAILY;INTERVAL=1;COUNT=1",
|
"DTSTART;TZID=America/New_York:20200220T000000 RRULE:FREQ=DAILY;INTERVAL=1;COUNT=1",
|
||||||
"id": 1,
|
"id": 1,
|
||||||
|
"extra_data":{},
|
||||||
"summary_fields": {
|
"summary_fields": {
|
||||||
"unified_job_template": {
|
"unified_job_template": {
|
||||||
"id": 6,
|
"id": 6,
|
||||||
@@ -27,6 +28,7 @@
|
|||||||
"rrule":
|
"rrule":
|
||||||
"DTSTART;TZID=America/New_York:20200220T000000 RRULE:FREQ=DAILY;INTERVAL=1;COUNT=1",
|
"DTSTART;TZID=America/New_York:20200220T000000 RRULE:FREQ=DAILY;INTERVAL=1;COUNT=1",
|
||||||
"id": 2,
|
"id": 2,
|
||||||
|
"extra_data":{},
|
||||||
"summary_fields": {
|
"summary_fields": {
|
||||||
"unified_job_template": {
|
"unified_job_template": {
|
||||||
"id": 7,
|
"id": 7,
|
||||||
@@ -46,6 +48,7 @@
|
|||||||
"rrule":
|
"rrule":
|
||||||
"DTSTART;TZID=America/New_York:20200220T000000 RRULE:FREQ=DAILY;INTERVAL=1;COUNT=1",
|
"DTSTART;TZID=America/New_York:20200220T000000 RRULE:FREQ=DAILY;INTERVAL=1;COUNT=1",
|
||||||
"id": 3,
|
"id": 3,
|
||||||
|
"extra_data":{},
|
||||||
"summary_fields": {
|
"summary_fields": {
|
||||||
"unified_job_template": {
|
"unified_job_template": {
|
||||||
"id": 8,
|
"id": 8,
|
||||||
@@ -65,6 +68,7 @@
|
|||||||
"rrule":
|
"rrule":
|
||||||
"DTSTART;TZID=America/New_York:20200220T000000 RRULE:FREQ=DAILY;INTERVAL=1;COUNT=1",
|
"DTSTART;TZID=America/New_York:20200220T000000 RRULE:FREQ=DAILY;INTERVAL=1;COUNT=1",
|
||||||
"id": 4,
|
"id": 4,
|
||||||
|
"extra_data":{},
|
||||||
"summary_fields": {
|
"summary_fields": {
|
||||||
"unified_job_template": {
|
"unified_job_template": {
|
||||||
"id": 9,
|
"id": 9,
|
||||||
@@ -84,6 +88,7 @@
|
|||||||
"rrule":
|
"rrule":
|
||||||
"DTSTART;TZID=America/New_York:20200220T000000 RRULE:FREQ=DAILY;INTERVAL=1;COUNT=1",
|
"DTSTART;TZID=America/New_York:20200220T000000 RRULE:FREQ=DAILY;INTERVAL=1;COUNT=1",
|
||||||
"id": 5,
|
"id": 5,
|
||||||
|
"extra_data":{"novalue":null},
|
||||||
"summary_fields": {
|
"summary_fields": {
|
||||||
"unified_job_template": {
|
"unified_job_template": {
|
||||||
"id": 10,
|
"id": 10,
|
||||||
|
|||||||
@@ -12,11 +12,7 @@ import {
|
|||||||
ActionGroup,
|
ActionGroup,
|
||||||
} from '@patternfly/react-core';
|
} from '@patternfly/react-core';
|
||||||
import { Config } from '../../../contexts/Config';
|
import { Config } from '../../../contexts/Config';
|
||||||
import {
|
import { SchedulesAPI } from '../../../api';
|
||||||
SchedulesAPI,
|
|
||||||
JobTemplatesAPI,
|
|
||||||
WorkflowJobTemplatesAPI,
|
|
||||||
} from '../../../api';
|
|
||||||
import AnsibleSelect from '../../AnsibleSelect';
|
import AnsibleSelect from '../../AnsibleSelect';
|
||||||
import ContentError from '../../ContentError';
|
import ContentError from '../../ContentError';
|
||||||
import ContentLoading from '../../ContentLoading';
|
import ContentLoading from '../../ContentLoading';
|
||||||
@@ -194,6 +190,8 @@ function ScheduleForm({
|
|||||||
schedule,
|
schedule,
|
||||||
submitError,
|
submitError,
|
||||||
resource,
|
resource,
|
||||||
|
launchConfig,
|
||||||
|
surveyConfig,
|
||||||
...rest
|
...rest
|
||||||
}) {
|
}) {
|
||||||
const [isWizardOpen, setIsWizardOpen] = useState(false);
|
const [isWizardOpen, setIsWizardOpen] = useState(false);
|
||||||
@@ -210,37 +208,15 @@ function ScheduleForm({
|
|||||||
const isTemplate =
|
const isTemplate =
|
||||||
resource.type === 'workflow_job_template' ||
|
resource.type === 'workflow_job_template' ||
|
||||||
resource.type === 'job_template';
|
resource.type === 'job_template';
|
||||||
const isWorkflowJobTemplate =
|
|
||||||
isTemplate && resource.type === 'workflow_job_template';
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
request: loadScheduleData,
|
request: loadScheduleData,
|
||||||
error: contentError,
|
error: contentError,
|
||||||
contentLoading,
|
contentLoading,
|
||||||
result: { zoneOptions, surveyConfig, launchConfig, credentials },
|
result: { zoneOptions, credentials },
|
||||||
} = useRequest(
|
} = useRequest(
|
||||||
useCallback(async () => {
|
useCallback(async () => {
|
||||||
const readLaunch =
|
const { data } = await SchedulesAPI.readZoneInfo();
|
||||||
isTemplate &&
|
|
||||||
(isWorkflowJobTemplate
|
|
||||||
? WorkflowJobTemplatesAPI.readLaunch(resource.id)
|
|
||||||
: JobTemplatesAPI.readLaunch(resource.id));
|
|
||||||
const [{ data }, { data: launchConfiguration }] = await Promise.all([
|
|
||||||
SchedulesAPI.readZoneInfo(),
|
|
||||||
readLaunch,
|
|
||||||
]);
|
|
||||||
|
|
||||||
const readSurvey = isWorkflowJobTemplate
|
|
||||||
? WorkflowJobTemplatesAPI.readSurvey(resource.id)
|
|
||||||
: JobTemplatesAPI.readSurvey(resource.id);
|
|
||||||
|
|
||||||
let surveyConfiguration = null;
|
|
||||||
|
|
||||||
if (isTemplate && launchConfiguration.survey_enabled) {
|
|
||||||
const { data: survey } = await readSurvey;
|
|
||||||
|
|
||||||
surveyConfiguration = survey;
|
|
||||||
}
|
|
||||||
let creds;
|
let creds;
|
||||||
if (schedule.id) {
|
if (schedule.id) {
|
||||||
const {
|
const {
|
||||||
@@ -249,37 +225,6 @@ function ScheduleForm({
|
|||||||
creds = results;
|
creds = results;
|
||||||
}
|
}
|
||||||
|
|
||||||
const missingRequiredInventory = Boolean(
|
|
||||||
!resource.inventory && !schedule?.summary_fields?.inventory.id
|
|
||||||
);
|
|
||||||
let missingRequiredSurvey = false;
|
|
||||||
|
|
||||||
if (
|
|
||||||
schedule.id &&
|
|
||||||
isTemplate &&
|
|
||||||
!launchConfiguration?.can_start_without_user_input
|
|
||||||
) {
|
|
||||||
missingRequiredSurvey = surveyConfiguration?.spec?.every(question => {
|
|
||||||
let hasValue;
|
|
||||||
if (Object.keys(schedule)?.length === 0) {
|
|
||||||
hasValue = true;
|
|
||||||
}
|
|
||||||
Object.entries(schedule?.extra_data).forEach(([key, value]) => {
|
|
||||||
if (
|
|
||||||
question.required &&
|
|
||||||
question.variable === key &&
|
|
||||||
value.length > 0
|
|
||||||
) {
|
|
||||||
hasValue = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return hasValue;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (missingRequiredInventory || missingRequiredSurvey) {
|
|
||||||
setIsSaveDisabled(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
const zones = data.map(zone => {
|
const zones = data.map(zone => {
|
||||||
return {
|
return {
|
||||||
value: zone.name,
|
value: zone.name,
|
||||||
@@ -290,18 +235,61 @@ function ScheduleForm({
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
zoneOptions: zones,
|
zoneOptions: zones,
|
||||||
surveyConfig: surveyConfiguration || {},
|
|
||||||
launchConfig: launchConfiguration,
|
|
||||||
credentials: creds || [],
|
credentials: creds || [],
|
||||||
};
|
};
|
||||||
}, [isTemplate, isWorkflowJobTemplate, resource, schedule]),
|
}, [schedule]),
|
||||||
{
|
{
|
||||||
zonesOptions: [],
|
zonesOptions: [],
|
||||||
surveyConfig: {},
|
|
||||||
launchConfig: {},
|
|
||||||
credentials: [],
|
credentials: [],
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
const missingRequiredInventory = useCallback(() => {
|
||||||
|
let missingInventory = false;
|
||||||
|
if (
|
||||||
|
launchConfig.inventory_needed_to_start &&
|
||||||
|
!schedule?.summary_fields?.inventory?.id
|
||||||
|
) {
|
||||||
|
missingInventory = true;
|
||||||
|
}
|
||||||
|
return missingInventory;
|
||||||
|
}, [launchConfig, schedule]);
|
||||||
|
|
||||||
|
const hasMissingSurveyValue = useCallback(() => {
|
||||||
|
let missingValues = false;
|
||||||
|
if (launchConfig?.survey_enabled) {
|
||||||
|
surveyConfig.spec.forEach(question => {
|
||||||
|
const hasDefaultValue = Boolean(question.default);
|
||||||
|
const hasSchedule = Object.keys(schedule).length;
|
||||||
|
const isRequired = question.required;
|
||||||
|
if (isRequired && !hasDefaultValue) {
|
||||||
|
if (!hasSchedule) {
|
||||||
|
missingValues = true;
|
||||||
|
} else {
|
||||||
|
const hasMatchingKey = Object.keys(schedule?.extra_data).includes(
|
||||||
|
question.variable
|
||||||
|
);
|
||||||
|
Object.values(schedule?.extra_data).forEach(value => {
|
||||||
|
if (!value || !hasMatchingKey) {
|
||||||
|
missingValues = true;
|
||||||
|
} else {
|
||||||
|
missingValues = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (!Object.values(schedule.extra_data).length) {
|
||||||
|
missingValues = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return missingValues;
|
||||||
|
}, [launchConfig, schedule, surveyConfig]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isTemplate && (missingRequiredInventory() || hasMissingSurveyValue())) {
|
||||||
|
setIsSaveDisabled(true);
|
||||||
|
}
|
||||||
|
}, [isTemplate, hasMissingSurveyValue, missingRequiredInventory]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
loadScheduleData();
|
loadScheduleData();
|
||||||
@@ -532,6 +520,7 @@ function ScheduleForm({
|
|||||||
>
|
>
|
||||||
{i18n._(t`Save`)}
|
{i18n._(t`Save`)}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
{isTemplate && showPromptButton && (
|
{isTemplate && showPromptButton && (
|
||||||
<Button
|
<Button
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
|
|||||||
@@ -12,24 +12,6 @@ jest.mock('../../../api/models/Schedules');
|
|||||||
jest.mock('../../../api/models/JobTemplates');
|
jest.mock('../../../api/models/JobTemplates');
|
||||||
jest.mock('../../../api/models/Inventories');
|
jest.mock('../../../api/models/Inventories');
|
||||||
|
|
||||||
const survey = {
|
|
||||||
name: '',
|
|
||||||
description: '',
|
|
||||||
spec: [
|
|
||||||
{
|
|
||||||
question_name: 'new survey',
|
|
||||||
question_description: '',
|
|
||||||
required: true,
|
|
||||||
type: 'text',
|
|
||||||
variable: 'newsurveyquestion',
|
|
||||||
min: 0,
|
|
||||||
max: 1024,
|
|
||||||
default: '',
|
|
||||||
choices: '',
|
|
||||||
new_question: false,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
const credentials = {
|
const credentials = {
|
||||||
data: {
|
data: {
|
||||||
results: [
|
results: [
|
||||||
@@ -145,6 +127,29 @@ describe('<ScheduleForm />', () => {
|
|||||||
<ScheduleForm
|
<ScheduleForm
|
||||||
handleSubmit={jest.fn()}
|
handleSubmit={jest.fn()}
|
||||||
handleCancel={jest.fn()}
|
handleCancel={jest.fn()}
|
||||||
|
launchConfig={{
|
||||||
|
can_start_without_user_input: false,
|
||||||
|
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: true,
|
||||||
|
ask_credential_on_launch: false,
|
||||||
|
survey_enabled: false,
|
||||||
|
variables_needed_to_start: [],
|
||||||
|
credential_needed_to_start: false,
|
||||||
|
inventory_needed_to_start: true,
|
||||||
|
job_template_data: {
|
||||||
|
name: 'Demo Job Template',
|
||||||
|
id: 7,
|
||||||
|
description: '',
|
||||||
|
},
|
||||||
|
}}
|
||||||
resource={{ id: 23, type: 'job_template' }}
|
resource={{ id: 23, type: 'job_template' }}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
@@ -158,7 +163,6 @@ describe('<ScheduleForm />', () => {
|
|||||||
const handleCancel = jest.fn();
|
const handleCancel = jest.fn();
|
||||||
JobTemplatesAPI.readLaunch.mockResolvedValue(launchData);
|
JobTemplatesAPI.readLaunch.mockResolvedValue(launchData);
|
||||||
|
|
||||||
JobTemplatesAPI.readSurvey.mockResolvedValue(survey);
|
|
||||||
SchedulesAPI.readCredentials.mockResolvedValue(credentials);
|
SchedulesAPI.readCredentials.mockResolvedValue(credentials);
|
||||||
SchedulesAPI.readZoneInfo.mockResolvedValue({
|
SchedulesAPI.readZoneInfo.mockResolvedValue({
|
||||||
data: [
|
data: [
|
||||||
@@ -172,7 +176,30 @@ describe('<ScheduleForm />', () => {
|
|||||||
<ScheduleForm
|
<ScheduleForm
|
||||||
handleSubmit={jest.fn()}
|
handleSubmit={jest.fn()}
|
||||||
handleCancel={handleCancel}
|
handleCancel={handleCancel}
|
||||||
resource={{ id: 23, type: 'job_template' }}
|
launchConfig={{
|
||||||
|
can_start_without_user_input: false,
|
||||||
|
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: true,
|
||||||
|
ask_credential_on_launch: false,
|
||||||
|
survey_enabled: false,
|
||||||
|
variables_needed_to_start: [],
|
||||||
|
credential_needed_to_start: false,
|
||||||
|
inventory_needed_to_start: true,
|
||||||
|
job_template_data: {
|
||||||
|
name: 'Demo Job Template',
|
||||||
|
id: 7,
|
||||||
|
description: '',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
resource={{ id: 23, type: 'job_template', inventory: 1 }}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -186,31 +213,6 @@ describe('<ScheduleForm />', () => {
|
|||||||
describe('Prompted Schedule', () => {
|
describe('Prompted Schedule', () => {
|
||||||
let promptWrapper;
|
let promptWrapper;
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
JobTemplatesAPI.readLaunch.mockResolvedValue({
|
|
||||||
data: {
|
|
||||||
can_start_without_user_input: false,
|
|
||||||
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: true,
|
|
||||||
ask_credential_on_launch: false,
|
|
||||||
survey_enabled: false,
|
|
||||||
variables_needed_to_start: [],
|
|
||||||
credential_needed_to_start: false,
|
|
||||||
inventory_needed_to_start: true,
|
|
||||||
job_template_data: {
|
|
||||||
name: 'Demo Job Template',
|
|
||||||
id: 7,
|
|
||||||
description: '',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
SchedulesAPI.readZoneInfo.mockResolvedValue({
|
SchedulesAPI.readZoneInfo.mockResolvedValue({
|
||||||
data: [
|
data: [
|
||||||
{
|
{
|
||||||
@@ -231,6 +233,30 @@ describe('<ScheduleForm />', () => {
|
|||||||
credentials: [],
|
credentials: [],
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
|
launchConfig={{
|
||||||
|
can_start_without_user_input: false,
|
||||||
|
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: true,
|
||||||
|
ask_credential_on_launch: false,
|
||||||
|
survey_enabled: false,
|
||||||
|
variables_needed_to_start: [],
|
||||||
|
credential_needed_to_start: false,
|
||||||
|
inventory_needed_to_start: true,
|
||||||
|
job_template_data: {
|
||||||
|
name: 'Demo Job Template',
|
||||||
|
id: 7,
|
||||||
|
description: '',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
surveyConfig={{ spec: [{ required: true, default: '' }] }}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -257,6 +283,12 @@ describe('<ScheduleForm />', () => {
|
|||||||
expect(promptWrapper.find('WizardNavItem').length).toBe(2);
|
expect(promptWrapper.find('WizardNavItem').length).toBe(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should render disabled save button due to missing required surevy values', () => {
|
||||||
|
expect(
|
||||||
|
promptWrapper.find('Button[aria-label="Save"]').prop('isDisabled')
|
||||||
|
).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
test('should update prompt modal data', async () => {
|
test('should update prompt modal data', async () => {
|
||||||
InventoriesAPI.read.mockResolvedValue({
|
InventoriesAPI.read.mockResolvedValue({
|
||||||
data: {
|
data: {
|
||||||
@@ -337,6 +369,29 @@ describe('<ScheduleForm />', () => {
|
|||||||
id: 23,
|
id: 23,
|
||||||
type: 'job_template',
|
type: 'job_template',
|
||||||
}}
|
}}
|
||||||
|
launchConfig={{
|
||||||
|
can_start_without_user_input: false,
|
||||||
|
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: true,
|
||||||
|
ask_credential_on_launch: false,
|
||||||
|
survey_enabled: false,
|
||||||
|
variables_needed_to_start: [],
|
||||||
|
credential_needed_to_start: false,
|
||||||
|
inventory_needed_to_start: true,
|
||||||
|
job_template_data: {
|
||||||
|
name: 'Demo Job Template',
|
||||||
|
id: 7,
|
||||||
|
description: '',
|
||||||
|
},
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -359,31 +414,6 @@ describe('<ScheduleForm />', () => {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
JobTemplatesAPI.readLaunch.mockResolvedValue({
|
|
||||||
data: {
|
|
||||||
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,
|
|
||||||
survey_enabled: false,
|
|
||||||
variables_needed_to_start: [],
|
|
||||||
credential_needed_to_start: false,
|
|
||||||
inventory_needed_to_start: false,
|
|
||||||
job_template_data: {
|
|
||||||
name: 'Demo Job Template',
|
|
||||||
id: 7,
|
|
||||||
description: '',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
wrapper = mountWithContexts(
|
wrapper = mountWithContexts(
|
||||||
@@ -391,6 +421,29 @@ describe('<ScheduleForm />', () => {
|
|||||||
handleSubmit={jest.fn()}
|
handleSubmit={jest.fn()}
|
||||||
handleCancel={jest.fn()}
|
handleCancel={jest.fn()}
|
||||||
resource={{ id: 23, type: 'job_template', inventory: 1 }}
|
resource={{ id: 23, type: 'job_template', inventory: 1 }}
|
||||||
|
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,
|
||||||
|
survey_enabled: false,
|
||||||
|
variables_needed_to_start: [],
|
||||||
|
credential_needed_to_start: false,
|
||||||
|
inventory_needed_to_start: false,
|
||||||
|
job_template_data: {
|
||||||
|
name: 'Demo Job Template',
|
||||||
|
id: 7,
|
||||||
|
description: '',
|
||||||
|
},
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -687,32 +740,7 @@ describe('<ScheduleForm />', () => {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
JobTemplatesAPI.readLaunch.mockResolvedValue({
|
|
||||||
data: {
|
|
||||||
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,
|
|
||||||
survey_enabled: false,
|
|
||||||
variables_needed_to_start: [],
|
|
||||||
credential_needed_to_start: false,
|
|
||||||
inventory_needed_to_start: false,
|
|
||||||
job_template_data: {
|
|
||||||
name: 'Demo Job Template',
|
|
||||||
id: 7,
|
|
||||||
description: '',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
JobTemplatesAPI.readSurvey.mockResolvedValue({});
|
|
||||||
SchedulesAPI.readCredentials.mockResolvedValue(credentials);
|
SchedulesAPI.readCredentials.mockResolvedValue(credentials);
|
||||||
});
|
});
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
@@ -728,21 +756,65 @@ describe('<ScheduleForm />', () => {
|
|||||||
handleCancel={jest.fn()}
|
handleCancel={jest.fn()}
|
||||||
schedule={{ inventory: null, ...mockSchedule }}
|
schedule={{ inventory: null, ...mockSchedule }}
|
||||||
resource={{ id: 23, type: 'job_template' }}
|
resource={{ id: 23, type: 'job_template' }}
|
||||||
|
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,
|
||||||
|
survey_enabled: false,
|
||||||
|
variables_needed_to_start: [],
|
||||||
|
credential_needed_to_start: false,
|
||||||
|
inventory_needed_to_start: false,
|
||||||
|
job_template_data: {
|
||||||
|
name: 'Demo Job Template',
|
||||||
|
id: 7,
|
||||||
|
description: '',
|
||||||
|
},
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
expect(JobTemplatesAPI.readLaunch).toBeCalledWith(23);
|
|
||||||
expect(JobTemplatesAPI.readSurvey).toBeCalledWith(23);
|
|
||||||
expect(SchedulesAPI.readCredentials).toBeCalledWith(27);
|
expect(SchedulesAPI.readCredentials).toBeCalledWith(27);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should not call API to get credentials ', async () => {
|
test('should not call API to get credentials ', async () => {
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
wrapper = mountWithContexts(
|
wrapper = mountWithContexts(
|
||||||
<ScheduleForm
|
<ScheduleForm
|
||||||
handleSubmit={jest.fn()}
|
handleSubmit={jest.fn()}
|
||||||
handleCancel={jest.fn()}
|
handleCancel={jest.fn()}
|
||||||
resource={{ id: 23, type: 'job_template' }}
|
resource={{ id: 23, type: 'job_template' }}
|
||||||
|
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,
|
||||||
|
survey_enabled: false,
|
||||||
|
variables_needed_to_start: [],
|
||||||
|
credential_needed_to_start: false,
|
||||||
|
inventory_needed_to_start: false,
|
||||||
|
job_template_data: {
|
||||||
|
name: 'Demo Job Template',
|
||||||
|
id: 7,
|
||||||
|
description: '',
|
||||||
|
},
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -782,6 +854,7 @@ describe('<ScheduleForm />', () => {
|
|||||||
handleSubmit={jest.fn()}
|
handleSubmit={jest.fn()}
|
||||||
handleCancel={jest.fn()}
|
handleCancel={jest.fn()}
|
||||||
schedule={mockSchedule}
|
schedule={mockSchedule}
|
||||||
|
launchConfig={{ inventory_needed_to_start: false }}
|
||||||
resource={{ id: 23, type: 'job_template' }}
|
resource={{ id: 23, type: 'job_template' }}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
@@ -806,6 +879,7 @@ describe('<ScheduleForm />', () => {
|
|||||||
<ScheduleForm
|
<ScheduleForm
|
||||||
handleSubmit={jest.fn()}
|
handleSubmit={jest.fn()}
|
||||||
handleCancel={jest.fn()}
|
handleCancel={jest.fn()}
|
||||||
|
launchConfig={{ inventory_needed_to_start: false }}
|
||||||
schedule={Object.assign(mockSchedule, {
|
schedule={Object.assign(mockSchedule, {
|
||||||
rrule:
|
rrule:
|
||||||
'DTSTART;TZID=America/New_York:20200402T144500 RRULE:INTERVAL=10;FREQ=MINUTELY',
|
'DTSTART;TZID=America/New_York:20200402T144500 RRULE:INTERVAL=10;FREQ=MINUTELY',
|
||||||
@@ -839,6 +913,7 @@ describe('<ScheduleForm />', () => {
|
|||||||
<ScheduleForm
|
<ScheduleForm
|
||||||
handleSubmit={jest.fn()}
|
handleSubmit={jest.fn()}
|
||||||
handleCancel={jest.fn()}
|
handleCancel={jest.fn()}
|
||||||
|
launchConfig={{ inventory_needed_to_start: false }}
|
||||||
schedule={Object.assign(mockSchedule, {
|
schedule={Object.assign(mockSchedule, {
|
||||||
rrule:
|
rrule:
|
||||||
'DTSTART;TZID=America/New_York:20200402T144500 RRULE:INTERVAL=1;FREQ=HOURLY;COUNT=10',
|
'DTSTART;TZID=America/New_York:20200402T144500 RRULE:INTERVAL=1;FREQ=HOURLY;COUNT=10',
|
||||||
@@ -874,6 +949,7 @@ describe('<ScheduleForm />', () => {
|
|||||||
<ScheduleForm
|
<ScheduleForm
|
||||||
handleSubmit={jest.fn()}
|
handleSubmit={jest.fn()}
|
||||||
handleCancel={jest.fn()}
|
handleCancel={jest.fn()}
|
||||||
|
launchConfig={{ inventory_needed_to_start: false }}
|
||||||
schedule={Object.assign(mockSchedule, {
|
schedule={Object.assign(mockSchedule, {
|
||||||
rrule:
|
rrule:
|
||||||
'DTSTART;TZID=America/New_York:20200402T144500 RRULE:INTERVAL=1;FREQ=DAILY',
|
'DTSTART;TZID=America/New_York:20200402T144500 RRULE:INTERVAL=1;FREQ=DAILY',
|
||||||
@@ -908,6 +984,7 @@ describe('<ScheduleForm />', () => {
|
|||||||
<ScheduleForm
|
<ScheduleForm
|
||||||
handleSubmit={jest.fn()}
|
handleSubmit={jest.fn()}
|
||||||
handleCancel={jest.fn()}
|
handleCancel={jest.fn()}
|
||||||
|
launchConfig={{ inventory_needed_to_start: false }}
|
||||||
schedule={Object.assign(mockSchedule, {
|
schedule={Object.assign(mockSchedule, {
|
||||||
rrule:
|
rrule:
|
||||||
'DTSTART;TZID=America/New_York:20200402T144500 RRULE:INTERVAL=1;FREQ=WEEKLY;BYDAY=MO,WE,FR;UNTIL=20210101T050000Z',
|
'DTSTART;TZID=America/New_York:20200402T144500 RRULE:INTERVAL=1;FREQ=WEEKLY;BYDAY=MO,WE,FR;UNTIL=20210101T050000Z',
|
||||||
@@ -966,6 +1043,7 @@ describe('<ScheduleForm />', () => {
|
|||||||
<ScheduleForm
|
<ScheduleForm
|
||||||
handleSubmit={jest.fn()}
|
handleSubmit={jest.fn()}
|
||||||
handleCancel={jest.fn()}
|
handleCancel={jest.fn()}
|
||||||
|
launchConfig={{ inventory_needed_to_start: false }}
|
||||||
schedule={Object.assign(mockSchedule, {
|
schedule={Object.assign(mockSchedule, {
|
||||||
rrule:
|
rrule:
|
||||||
'DTSTART;TZID=America/New_York:20200402T144500 RRULE:INTERVAL=1;FREQ=MONTHLY;BYSETPOS=-1;BYDAY=MO,TU,WE,TH,FR',
|
'DTSTART;TZID=America/New_York:20200402T144500 RRULE:INTERVAL=1;FREQ=MONTHLY;BYSETPOS=-1;BYDAY=MO,TU,WE,TH,FR',
|
||||||
@@ -1012,6 +1090,7 @@ describe('<ScheduleForm />', () => {
|
|||||||
<ScheduleForm
|
<ScheduleForm
|
||||||
handleSubmit={jest.fn()}
|
handleSubmit={jest.fn()}
|
||||||
handleCancel={jest.fn()}
|
handleCancel={jest.fn()}
|
||||||
|
launchConfig={{ inventory_needed_to_start: false }}
|
||||||
schedule={Object.assign(mockSchedule, {
|
schedule={Object.assign(mockSchedule, {
|
||||||
rrule:
|
rrule:
|
||||||
'DTSTART;TZID=America/New_York:20200402T144500 RRULE:INTERVAL=1;FREQ=YEARLY;BYMONTH=5;BYMONTHDAY=6',
|
'DTSTART;TZID=America/New_York:20200402T144500 RRULE:INTERVAL=1;FREQ=YEARLY;BYMONTH=5;BYMONTHDAY=6',
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ export default function useSchedulePromptSteps(
|
|||||||
(Object.keys(schedule).length > 0 && schedule) || resource;
|
(Object.keys(schedule).length > 0 && schedule) || resource;
|
||||||
|
|
||||||
sourceOfValues.summary_fields = {
|
sourceOfValues.summary_fields = {
|
||||||
credentials: [...resourceCredentials, ...scheduleCredentials],
|
credentials: [...(resourceCredentials || []), ...scheduleCredentials],
|
||||||
...sourceOfValues.summary_fields,
|
...sourceOfValues.summary_fields,
|
||||||
};
|
};
|
||||||
const { resetForm, values } = useFormikContext();
|
const { resetForm, values } = useFormikContext();
|
||||||
|
|||||||
@@ -326,11 +326,6 @@ function JobDetail({ job, i18n }) {
|
|||||||
user={created_by}
|
user={created_by}
|
||||||
/>
|
/>
|
||||||
<UserDateDetail label={i18n._(t`Last Modified`)} date={job.modified} />
|
<UserDateDetail label={i18n._(t`Last Modified`)} date={job.modified} />
|
||||||
<Detail
|
|
||||||
fullWidth
|
|
||||||
label={i18n._(t`Explanation`)}
|
|
||||||
value={job.job_explanation}
|
|
||||||
/>
|
|
||||||
</DetailList>
|
</DetailList>
|
||||||
{job.extra_vars && (
|
{job.extra_vars && (
|
||||||
<VariablesInput
|
<VariablesInput
|
||||||
|
|||||||
@@ -40,7 +40,6 @@ describe('<JobDetail />', () => {
|
|||||||
name: 'Test Source Workflow',
|
name: 'Test Source Workflow',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
job_explanation: 'It failed, bummer!',
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
@@ -70,7 +69,6 @@ describe('<JobDetail />', () => {
|
|||||||
assertDetail('Job Slice', '0/1');
|
assertDetail('Job Slice', '0/1');
|
||||||
assertDetail('Credentials', 'SSH: Demo Credential');
|
assertDetail('Credentials', 'SSH: Demo Credential');
|
||||||
assertDetail('Machine Credential', 'SSH: Machine cred');
|
assertDetail('Machine Credential', 'SSH: Machine cred');
|
||||||
assertDetail('Explanation', 'It failed, bummer!');
|
|
||||||
|
|
||||||
const credentialChip = wrapper.find(
|
const credentialChip = wrapper.find(
|
||||||
`Detail[label="Credentials"] CredentialChip`
|
`Detail[label="Credentials"] CredentialChip`
|
||||||
|
|||||||
@@ -32,20 +32,33 @@ function Template({ i18n, setBreadcrumb }) {
|
|||||||
const { me = {} } = useConfig();
|
const { me = {} } = useConfig();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
result: { isNotifAdmin, template },
|
result: { isNotifAdmin, template, surveyConfig, launchConfig },
|
||||||
isLoading,
|
isLoading,
|
||||||
error: contentError,
|
error: contentError,
|
||||||
request: loadTemplateAndRoles,
|
request: loadTemplateAndRoles,
|
||||||
} = useRequest(
|
} = useRequest(
|
||||||
useCallback(async () => {
|
useCallback(async () => {
|
||||||
const [{ data }, actions, notifAdminRes] = await Promise.all([
|
const [
|
||||||
|
{ data },
|
||||||
|
actions,
|
||||||
|
notifAdminRes,
|
||||||
|
{ data: launchConfiguration },
|
||||||
|
] = await Promise.all([
|
||||||
JobTemplatesAPI.readDetail(templateId),
|
JobTemplatesAPI.readDetail(templateId),
|
||||||
JobTemplatesAPI.readTemplateOptions(templateId),
|
JobTemplatesAPI.readTemplateOptions(templateId),
|
||||||
OrganizationsAPI.read({
|
OrganizationsAPI.read({
|
||||||
page_size: 1,
|
page_size: 1,
|
||||||
role_level: 'notification_admin_role',
|
role_level: 'notification_admin_role',
|
||||||
}),
|
}),
|
||||||
|
JobTemplatesAPI.readLaunch(templateId),
|
||||||
]);
|
]);
|
||||||
|
let surveyConfiguration = null;
|
||||||
|
|
||||||
|
if (data.survey_enabled) {
|
||||||
|
const { data: survey } = await JobTemplatesAPI.readSurvey(templateId);
|
||||||
|
|
||||||
|
surveyConfiguration = survey;
|
||||||
|
}
|
||||||
if (data.summary_fields.credentials) {
|
if (data.summary_fields.credentials) {
|
||||||
const params = {
|
const params = {
|
||||||
page: 1,
|
page: 1,
|
||||||
@@ -71,6 +84,8 @@ function Template({ i18n, setBreadcrumb }) {
|
|||||||
return {
|
return {
|
||||||
template: data,
|
template: data,
|
||||||
isNotifAdmin: notifAdminRes.data.results.length > 0,
|
isNotifAdmin: notifAdminRes.data.results.length > 0,
|
||||||
|
surveyConfig: surveyConfiguration,
|
||||||
|
launchConfig: launchConfiguration,
|
||||||
};
|
};
|
||||||
}, [templateId]),
|
}, [templateId]),
|
||||||
{ isNotifAdmin: false, template: null }
|
{ isNotifAdmin: false, template: null }
|
||||||
@@ -204,6 +219,8 @@ function Template({ i18n, setBreadcrumb }) {
|
|||||||
resource={template}
|
resource={template}
|
||||||
loadSchedules={loadSchedules}
|
loadSchedules={loadSchedules}
|
||||||
loadScheduleOptions={loadScheduleOptions}
|
loadScheduleOptions={loadScheduleOptions}
|
||||||
|
surveyConfig={surveyConfig}
|
||||||
|
launchConfig={launchConfig}
|
||||||
/>
|
/>
|
||||||
</Route>
|
</Route>
|
||||||
{canSeeNotificationsTab && (
|
{canSeeNotificationsTab && (
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ describe('<Template />', () => {
|
|||||||
let wrapper;
|
let wrapper;
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
JobTemplatesAPI.readDetail.mockResolvedValue({
|
JobTemplatesAPI.readDetail.mockResolvedValue({
|
||||||
data: mockJobTemplateData,
|
data: { ...mockJobTemplateData, survey_enabled: false },
|
||||||
});
|
});
|
||||||
JobTemplatesAPI.readTemplateOptions.mockResolvedValue({
|
JobTemplatesAPI.readTemplateOptions.mockResolvedValue({
|
||||||
data: {
|
data: {
|
||||||
@@ -56,6 +56,7 @@ describe('<Template />', () => {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
JobTemplatesAPI.readLaunch.mockResolvedValue({ data: {} });
|
||||||
JobTemplatesAPI.readWebhookKey.mockResolvedValue({
|
JobTemplatesAPI.readWebhookKey.mockResolvedValue({
|
||||||
data: {
|
data: {
|
||||||
webhook_key: 'key',
|
webhook_key: 'key',
|
||||||
|
|||||||
@@ -36,21 +36,37 @@ function WorkflowJobTemplate({ i18n, setBreadcrumb }) {
|
|||||||
const { me = {} } = useConfig();
|
const { me = {} } = useConfig();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
result: { isNotifAdmin, template },
|
result: { isNotifAdmin, template, surveyConfig, launchConfig },
|
||||||
isLoading: hasRolesandTemplateLoading,
|
isLoading: hasRolesandTemplateLoading,
|
||||||
error: rolesAndTemplateError,
|
error: rolesAndTemplateError,
|
||||||
request: loadTemplateAndRoles,
|
request: loadTemplateAndRoles,
|
||||||
} = useRequest(
|
} = useRequest(
|
||||||
useCallback(async () => {
|
useCallback(async () => {
|
||||||
const [{ data }, actions, notifAdminRes] = await Promise.all([
|
const [
|
||||||
|
{ data },
|
||||||
|
actions,
|
||||||
|
notifAdminRes,
|
||||||
|
{ data: launchConfiguration },
|
||||||
|
] = await Promise.all([
|
||||||
WorkflowJobTemplatesAPI.readDetail(templateId),
|
WorkflowJobTemplatesAPI.readDetail(templateId),
|
||||||
WorkflowJobTemplatesAPI.readWorkflowJobTemplateOptions(templateId),
|
WorkflowJobTemplatesAPI.readWorkflowJobTemplateOptions(templateId),
|
||||||
OrganizationsAPI.read({
|
OrganizationsAPI.read({
|
||||||
page_size: 1,
|
page_size: 1,
|
||||||
role_level: 'notification_admin_role',
|
role_level: 'notification_admin_role',
|
||||||
}),
|
}),
|
||||||
|
WorkflowJobTemplatesAPI.readLaunch(templateId),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
let surveyConfiguration = null;
|
||||||
|
|
||||||
|
if (data.survey_enabled) {
|
||||||
|
const { data: survey } = await WorkflowJobTemplatesAPI.readSurvey(
|
||||||
|
templateId
|
||||||
|
);
|
||||||
|
|
||||||
|
surveyConfiguration = survey;
|
||||||
|
}
|
||||||
|
|
||||||
if (actions.data.actions.PUT) {
|
if (actions.data.actions.PUT) {
|
||||||
if (data.webhook_service && data?.related?.webhook_key) {
|
if (data.webhook_service && data?.related?.webhook_key) {
|
||||||
const {
|
const {
|
||||||
@@ -65,6 +81,8 @@ function WorkflowJobTemplate({ i18n, setBreadcrumb }) {
|
|||||||
return {
|
return {
|
||||||
template: data,
|
template: data,
|
||||||
isNotifAdmin: notifAdminRes.data.results.length > 0,
|
isNotifAdmin: notifAdminRes.data.results.length > 0,
|
||||||
|
launchConfig: launchConfiguration,
|
||||||
|
surveyConfig: surveyConfiguration,
|
||||||
};
|
};
|
||||||
}, [setBreadcrumb, templateId]),
|
}, [setBreadcrumb, templateId]),
|
||||||
{ isNotifAdmin: false, template: null }
|
{ isNotifAdmin: false, template: null }
|
||||||
@@ -207,6 +225,8 @@ function WorkflowJobTemplate({ i18n, setBreadcrumb }) {
|
|||||||
resource={template}
|
resource={template}
|
||||||
loadSchedules={loadSchedules}
|
loadSchedules={loadSchedules}
|
||||||
loadScheduleOptions={loadScheduleOptions}
|
loadScheduleOptions={loadScheduleOptions}
|
||||||
|
surveyConfig={surveyConfig}
|
||||||
|
launchConfig={launchConfig}
|
||||||
/>
|
/>
|
||||||
</Route>
|
</Route>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ describe('<WorkflowJobTemplate />', () => {
|
|||||||
let wrapper;
|
let wrapper;
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
WorkflowJobTemplatesAPI.readDetail.mockResolvedValue({
|
WorkflowJobTemplatesAPI.readDetail.mockResolvedValue({
|
||||||
data: mockWorkflowJobTemplateData,
|
data: { ...mockWorkflowJobTemplateData, survey_enabled: false },
|
||||||
});
|
});
|
||||||
WorkflowJobTemplatesAPI.readWorkflowJobTemplateOptions.mockResolvedValue({
|
WorkflowJobTemplatesAPI.readWorkflowJobTemplateOptions.mockResolvedValue({
|
||||||
data: {
|
data: {
|
||||||
@@ -45,6 +45,7 @@ describe('<WorkflowJobTemplate />', () => {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
WorkflowJobTemplatesAPI.readLaunch.mockResolvedValue({ data: {} });
|
||||||
WorkflowJobTemplatesAPI.readWebhookKey.mockResolvedValue({
|
WorkflowJobTemplatesAPI.readWebhookKey.mockResolvedValue({
|
||||||
data: {
|
data: {
|
||||||
webhook_key: 'key',
|
webhook_key: 'key',
|
||||||
|
|||||||
Reference in New Issue
Block a user