diff --git a/awx/ui_next/src/api/models/InventorySources.js b/awx/ui_next/src/api/models/InventorySources.js index 8d20076ba8..baa2a85cb0 100644 --- a/awx/ui_next/src/api/models/InventorySources.js +++ b/awx/ui_next/src/api/models/InventorySources.js @@ -10,6 +10,7 @@ class InventorySources extends LaunchUpdateMixin( super(http); this.baseUrl = '/api/v2/inventory_sources/'; + this.createSchedule = this.createSchedule.bind(this); this.createSyncStart = this.createSyncStart.bind(this); this.destroyGroups = this.destroyGroups.bind(this); this.destroyHosts = this.destroyHosts.bind(this); diff --git a/awx/ui_next/src/api/models/JobTemplates.js b/awx/ui_next/src/api/models/JobTemplates.js index 44281f1511..da0af7cff5 100644 --- a/awx/ui_next/src/api/models/JobTemplates.js +++ b/awx/ui_next/src/api/models/JobTemplates.js @@ -10,6 +10,7 @@ class JobTemplates extends SchedulesMixin( super(http); this.baseUrl = '/api/v2/job_templates/'; + this.createSchedule = this.createSchedule.bind(this); this.launch = this.launch.bind(this); this.readLaunch = this.readLaunch.bind(this); this.associateLabel = this.associateLabel.bind(this); diff --git a/awx/ui_next/src/api/models/Projects.js b/awx/ui_next/src/api/models/Projects.js index 38879a2bc2..1810bb33e5 100644 --- a/awx/ui_next/src/api/models/Projects.js +++ b/awx/ui_next/src/api/models/Projects.js @@ -16,6 +16,7 @@ class Projects extends SchedulesMixin( this.readPlaybooks = this.readPlaybooks.bind(this); this.readSync = this.readSync.bind(this); this.sync = this.sync.bind(this); + this.createSchedule = this.createSchedule.bind(this); } readAccessList(id, params) { diff --git a/awx/ui_next/src/api/models/Schedules.js b/awx/ui_next/src/api/models/Schedules.js index 7f20e992ae..14b982ba0d 100644 --- a/awx/ui_next/src/api/models/Schedules.js +++ b/awx/ui_next/src/api/models/Schedules.js @@ -14,6 +14,19 @@ class Schedules extends Base { return this.http.get(`${this.baseUrl}${resourceId}/credentials/`, params); } + associateCredential(resourceId, credentialId) { + return this.http.post(`${this.baseUrl}${resourceId}/credentials/`, { + id: credentialId, + }); + } + + disassociateCredential(resourceId, credentialId) { + return this.http.post(`${this.baseUrl}${resourceId}/credentials/`, { + id: credentialId, + disassociate: true, + }); + } + readZoneInfo() { return this.http.get(`${this.baseUrl}zoneinfo/`); } diff --git a/awx/ui_next/src/api/models/WorkflowJobTemplates.js b/awx/ui_next/src/api/models/WorkflowJobTemplates.js index beed5be9ad..9f868534b6 100644 --- a/awx/ui_next/src/api/models/WorkflowJobTemplates.js +++ b/awx/ui_next/src/api/models/WorkflowJobTemplates.js @@ -6,6 +6,7 @@ class WorkflowJobTemplates extends SchedulesMixin(NotificationsMixin(Base)) { constructor(http) { super(http); this.baseUrl = '/api/v2/workflow_job_templates/'; + this.createSchedule = this.createSchedule.bind(this); } readWebhookKey(id) { diff --git a/awx/ui_next/src/components/Schedule/Schedule.jsx b/awx/ui_next/src/components/Schedule/Schedule.jsx index ffa28dd35f..201841048c 100644 --- a/awx/ui_next/src/components/Schedule/Schedule.jsx +++ b/awx/ui_next/src/components/Schedule/Schedule.jsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from 'react'; +import React, { useEffect, useCallback } from 'react'; import { t } from '@lingui/macro'; import { withI18n } from '@lingui/react'; @@ -17,37 +17,39 @@ import ContentLoading from '../ContentLoading'; import ScheduleDetail from './ScheduleDetail'; import ScheduleEdit from './ScheduleEdit'; import { SchedulesAPI } from '../../api'; +import useRequest from '../../util/useRequest'; -function Schedule({ i18n, setBreadcrumb, unifiedJobTemplate }) { - const [schedule, setSchedule] = useState(null); - const [contentLoading, setContentLoading] = useState(true); - const [contentError, setContentError] = useState(null); +function Schedule({ i18n, setBreadcrumb, resource }) { const { scheduleId } = useParams(); - const location = useLocation(); - const { pathname } = location; + + const { pathname } = useLocation(); + const pathRoot = pathname.substr(0, pathname.indexOf('schedules')); - useEffect(() => { - const loadData = async () => { - try { - const { data } = await SchedulesAPI.readDetail(scheduleId); - setSchedule(data); - } catch (err) { - setContentError(err); - } finally { - setContentLoading(false); - } - }; + const { + isLoading: contentLoading, + error: contentError, + request: loadData, + result: schedule, + } = useRequest( + useCallback(async () => { + const { data } = await SchedulesAPI.readDetail(scheduleId); + return data; + }, [scheduleId]), + null + ); + + useEffect(() => { loadData(); - }, [location.pathname, scheduleId]); + }, [loadData, pathname]); useEffect(() => { if (schedule) { - setBreadcrumb(unifiedJobTemplate, schedule); + setBreadcrumb(resource, schedule); } // eslint-disable-next-line react-hooks/exhaustive-deps - }, [schedule, unifiedJobTemplate]); + }, [schedule, resource]); const tabsArray = [ { name: ( @@ -71,8 +73,8 @@ function Schedule({ i18n, setBreadcrumb, unifiedJobTemplate }) { } if ( - schedule.summary_fields.unified_job_template.id !== - parseInt(unifiedJobTemplate.id, 10) + schedule?.summary_fields.unified_job_template.id !== + parseInt(resource.id, 10) ) { return ( @@ -89,10 +91,7 @@ function Schedule({ i18n, setBreadcrumb, unifiedJobTemplate }) { let showCardHeader = true; - if ( - !location.pathname.includes('schedules/') || - location.pathname.endsWith('edit') - ) { + if (!pathname.includes('schedules/') || pathname.endsWith('edit')) { showCardHeader = false; } return ( @@ -106,7 +105,7 @@ function Schedule({ i18n, setBreadcrumb, unifiedJobTemplate }) { /> {schedule && [ - + , - {unifiedJobTemplate && ( + {resource && ( {i18n._(t`View Details`)} )} diff --git a/awx/ui_next/src/components/Schedule/Schedule.test.jsx b/awx/ui_next/src/components/Schedule/Schedule.test.jsx index e3c394cc95..280c6af6bb 100644 --- a/awx/ui_next/src/components/Schedule/Schedule.test.jsx +++ b/awx/ui_next/src/components/Schedule/Schedule.test.jsx @@ -93,10 +93,7 @@ describe('', () => { ( - {}} - unifiedJobTemplate={unifiedJobTemplate} - /> + {}} resource={unifiedJobTemplate} /> )} />, { diff --git a/awx/ui_next/src/components/Schedule/ScheduleAdd/ScheduleAdd.jsx b/awx/ui_next/src/components/Schedule/ScheduleAdd/ScheduleAdd.jsx index 7285e760a2..e6a9b81699 100644 --- a/awx/ui_next/src/components/Schedule/ScheduleAdd/ScheduleAdd.jsx +++ b/awx/ui_next/src/components/Schedule/ScheduleAdd/ScheduleAdd.jsx @@ -8,7 +8,7 @@ import { CardBody } from '../../Card'; import buildRuleObj from '../shared/buildRuleObj'; import ScheduleForm from '../shared/ScheduleForm'; -function ScheduleAdd({ i18n, createSchedule }) { +function ScheduleAdd({ i18n, resource, apiModel }) { const [formSubmitError, setFormSubmitError] = useState(null); const history = useHistory(); const location = useLocation(); @@ -18,11 +18,8 @@ function ScheduleAdd({ i18n, createSchedule }) { const handleSubmit = async values => { try { const rule = new RRule(buildRuleObj(values, i18n)); - const { - data: { id: scheduleId }, - } = await createSchedule({ - name: values.name, - description: values.description, + + const { id: scheduleId } = await apiModel.createSchedule(resource.id, { rrule: rule.toString().replace(/\n/g, ' '), }); @@ -46,7 +43,7 @@ function ScheduleAdd({ i18n, createSchedule }) { } ScheduleAdd.propTypes = { - createSchedule: func.isRequired, + apiModel: shape({ createSchedule: func.isRequired }).isRequired, }; ScheduleAdd.defaultProps = {}; diff --git a/awx/ui_next/src/components/Schedule/ScheduleDetail/ScheduleDetail.jsx b/awx/ui_next/src/components/Schedule/ScheduleDetail/ScheduleDetail.jsx index 946ac94f55..19ea0495c5 100644 --- a/awx/ui_next/src/components/Schedule/ScheduleDetail/ScheduleDetail.jsx +++ b/awx/ui_next/src/components/Schedule/ScheduleDetail/ScheduleDetail.jsx @@ -189,6 +189,14 @@ function ScheduleDetail({ schedule, i18n }) { showVerbosityDetail || 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) { return ; } @@ -256,6 +264,12 @@ function ScheduleDetail({ schedule, i18n }) { } /> )} + {ask_verbosity_on_launch && ( + + )} {ask_scm_branch_on_launch && ( - + - + - InventorySourcesAPI.createSchedule(source?.id, data); - const loadScheduleOptions = useCallback(() => { return InventorySourcesAPI.readScheduleOptions(source?.id); }, [source]); @@ -160,11 +157,11 @@ function InventorySource({ i18n, inventory, setBreadcrumb, me }) { path="/inventories/inventory/:id/sources/:sourceId/schedules" > + apiModel={InventorySourcesAPI} + setBreadcrumb={schedule => setBreadcrumb(inventory, source, schedule) } - unifiedJobTemplate={source} + resource={source} loadSchedules={loadSchedules} loadScheduleOptions={loadScheduleOptions} /> diff --git a/awx/ui_next/src/screens/Project/Project.jsx b/awx/ui_next/src/screens/Project/Project.jsx index 72341a5de9..5c3a5a7564 100644 --- a/awx/ui_next/src/screens/Project/Project.jsx +++ b/awx/ui_next/src/screens/Project/Project.jsx @@ -78,10 +78,6 @@ function Project({ i18n, setBreadcrumb }) { } }, [project, setBreadcrumb]); - function createSchedule(data) { - return ProjectsAPI.createSchedule(project.id, data); - } - const loadScheduleOptions = useCallback(() => { return ProjectsAPI.readScheduleOptions(project.id); }, [project]); @@ -188,8 +184,8 @@ function Project({ i18n, setBreadcrumb }) { diff --git a/awx/ui_next/src/screens/Template/Template.jsx b/awx/ui_next/src/screens/Template/Template.jsx index 50b238b3b7..5b8233b1af 100644 --- a/awx/ui_next/src/screens/Template/Template.jsx +++ b/awx/ui_next/src/screens/Template/Template.jsx @@ -86,10 +86,6 @@ function Template({ i18n, setBreadcrumb }) { } }, [template, setBreadcrumb]); - const createSchedule = data => { - return JobTemplatesAPI.createSchedule(template.id, data); - }; - const loadScheduleOptions = useCallback(() => { return JobTemplatesAPI.readScheduleOptions(templateId); }, [templateId]); @@ -203,9 +199,9 @@ function Template({ i18n, setBreadcrumb }) { path="/templates/:templateType/:id/schedules" > diff --git a/awx/ui_next/src/screens/Template/WorkflowJobTemplate.jsx b/awx/ui_next/src/screens/Template/WorkflowJobTemplate.jsx index ee22010983..8d50bd937c 100644 --- a/awx/ui_next/src/screens/Template/WorkflowJobTemplate.jsx +++ b/awx/ui_next/src/screens/Template/WorkflowJobTemplate.jsx @@ -73,10 +73,6 @@ function WorkflowJobTemplate({ i18n, setBreadcrumb }) { loadTemplateAndRoles(); }, [loadTemplateAndRoles, location.pathname]); - const createSchedule = data => { - return WorkflowJobTemplatesAPI.createSchedule(templateId, data); - }; - const loadScheduleOptions = useCallback(() => { return WorkflowJobTemplatesAPI.readScheduleOptions(templateId); }, [templateId]); @@ -206,9 +202,9 @@ function WorkflowJobTemplate({ i18n, setBreadcrumb }) { path="/templates/:templateType/:id/schedules" >