diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/create.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/create.js index 003677336ab1e9f6782ae80c34c0724b0beb8f5e..4678e5edd5d7f27759f5c69db229cb822a976479 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/create.js +++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/create.js @@ -19,33 +19,33 @@ import TaskService from '../../services/task.service'; import UIConstants from '../../utils/ui.constants'; /** - * Component to create a new SchedulingUnit + * Component to create a new SchedulingUnit from Observation strategy template */ export class SchedulingUnitCreate extends Component { constructor(props) { super(props); this.state = { - isLoading: true, - dialog: { header: '', detail: ''}, - redirect: null, - errors: [], - schedulingSets: [], + isLoading: true, // Flag for loading spinner + dialog: { header: '', detail: ''}, // Dialog properties + redirect: null, // URL to redirect + errors: [], // Form Validation errors + schedulingSets: [], // Scheduling set of the selected project schedulingUnit: { project: (props.match?props.match.params.project:null) || null, }, - projectDisabled: (props.match?(props.match.params.project? true:false):false), - observStrategy: {}, - paramsSchema: null, - validEditor: false, - validFields: {}, // For Validation + projectDisabled: (props.match?(props.match.params.project? true:false):false), // Disable project selection if + observStrategy: {}, // Selected strategy to create SU + paramsSchema: null, // JSON Schema to be generated from strategy template to pass to JSOn editor + validEditor: false, // For JSON editor validation + validFields: {}, // For Form Validation } - this.projects = []; - this.schedulingSets = []; - this.observStrategies = []; - this.taskTemplates = []; + this.projects = []; // All projects to load project dropdown + this.schedulingSets = []; // All scheduling sets to be filtered for project + this.observStrategies = []; // All Observing strategy templates + this.taskTemplates = []; // All task templates to be filtered based on tasks in selected strategy template this.tooltipOptions = UIConstants.tooltipOptions; - this.nameInput = React.createRef(); - this.formRules = { + this.nameInput = React.createRef(); // Ref to Name field for auto focus + this.formRules = { // Form validation rules name: {required: true, message: "Name can not be empty"}, description: {required: true, message: "Description can not be empty"}, project: {required: true, message: "Select project to get Scheduling Sets"}, @@ -83,6 +83,10 @@ export class SchedulingUnitCreate extends Component { }); } + /** + * Function to call on change of project and reload scheduling set dropdown + * @param {string} projectName + */ changeProject(projectName) { const projectSchedSets = _.filter(this.schedulingSets, {'project_id': projectName}); let schedulingUnit = this.state.schedulingUnit; @@ -90,8 +94,12 @@ export class SchedulingUnitCreate extends Component { this.setState({schedulingUnit: schedulingUnit, schedulingSets: projectSchedSets, validForm: this.validateForm('project')}); } + /** + * Function called when observation strategy template is changed. + * It generates the JSON schema for JSON editor and defult vales for the parameters to be captured + * @param {number} strategyId + */ async changeStrategy (strategyId) { - const observStrategy = _.find(this.observStrategies, {'id': strategyId}); const tasks = observStrategy.template.tasks; let paramsOutput = {}; @@ -99,20 +107,22 @@ export class SchedulingUnitCreate extends Component { properties: {}, definitions:{} }; - observStrategy.template.parameters.forEach(async(param, index) => { - }); - for (const taskName in tasks) { const task = tasks[taskName]; + //Resolve task from the strategy template const $taskRefs = await $RefParser.resolve(task); + + // Identify the task specification template of every task in the template const taskTemplate = _.find(this.taskTemplates, {'name': task['specifications_template']}); schema['$id'] = taskTemplate.schema['$id']; schema['$schema'] = taskTemplate.schema['$schema']; observStrategy.template.parameters.forEach(async(param, index) => { if (param.refs[0].indexOf(`/tasks/${taskName}`) > 0) { + // Resolve the identified template const $templateRefs = await $RefParser.resolve(taskTemplate); let property = { }; let tempProperty = null; + // Get the property type from the template and create new property in the schema for the parameters try { tempProperty = $templateRefs.get(param.refs[0].replace(`#/tasks/${taskName}/specifications_doc`, '#/schema/properties')) } catch(error) { @@ -127,6 +137,7 @@ export class SchedulingUnitCreate extends Component { property.default = $taskRefs.get(param.refs[0].replace(`#/tasks/${taskName}`, '#')); paramsOutput[`param_${index}`] = property.default; schema.properties[`param_${index}`] = property; + // Set property defintions taken from the task template in new schema for (const definitionName in taskTemplate.schema.definitions) { schema.definitions[definitionName] = taskTemplate.schema.definitions[definitionName]; } @@ -134,6 +145,8 @@ export class SchedulingUnitCreate extends Component { }); } this.setState({observStrategy: observStrategy, paramsSchema: schema, paramsOutput: paramsOutput}); + + // Function called to clear the JSON Editor fields and reload with new schema if (this.state.editorFunction) { this.state.editorFunction(); } @@ -160,6 +173,11 @@ export class SchedulingUnitCreate extends Component { return this.validEditor?true:false; } + /** + * Function to set form values to the SU object + * @param {string} key + * @param {object} value + */ setSchedUnitParams(key, value) { let schedulingUnit = this.state.schedulingUnit; schedulingUnit[key] = value; @@ -220,6 +238,9 @@ export class SchedulingUnitCreate extends Component { return validForm; } + /** + * Function to create Scheduling unit + */ async saveSchedulingUnit() { let observStrategy = _.cloneDeep(this.state.observStrategy); const $refs = await $RefParser.resolve(observStrategy.template); @@ -237,10 +258,16 @@ export class SchedulingUnitCreate extends Component { } } + /** + * Cancel SU creation and redirect + */ cancelCreate() { this.setState({redirect: '/schedulingunit'}) } + /** + * Reset function to be called when user wants to create new SU + */ reset() { const schedulingSets = this.state.schedulingSets; this.nameInput.element.focus(); diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/create.test.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/create.test.js index 42dca78f9223ea112e1a46e0514baad784a2e203..ccdaf6f98f69ceb13f23508624b911590cd9f148 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/create.test.js +++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/create.test.js @@ -121,8 +121,8 @@ it("creates new Scheduling Unit with default values", async() => { expect(content.queryAllByText('UC1 observation strategy template').length).toBe(3); expect(content.queryByText('Task Parameters')).toBeInTheDocument(); expect(content.queryByText('Target Pointing 0')).toBeInTheDocument(); - // expect(content.queryByText('Not a valid input. Mimimum: 00:00:00, Maximum:23:59:59.')).not.toBeInTheDocument(); - // expect(content.queryByText('Not a valid input. Mimimum: 00:00:00, Maximum:90:00:00.')).not.toBeInTheDocument(); + expect(content.queryByText('Not a valid input. Mimimum: 00:00:00, Maximum:23:59:59.')).not.toBeInTheDocument(); + expect(content.queryByText('Not a valid input. Mimimum: 00:00:00, Maximum:90:00:00.')).not.toBeInTheDocument(); /* This is set again to call the validateEditor function in the component. If this is removed, the editor validation will not occur in the test but works in browser.*/ diff --git a/SAS/TMSS/frontend/tmss_webapp/src/services/schedule.service.js b/SAS/TMSS/frontend/tmss_webapp/src/services/schedule.service.js index e2497e87c5ae0eb8841744bfef59c4c28ad1ae5e..a7e65ace0ccd24316cb5902bf1741a14cc94fddb 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/services/schedule.service.js +++ b/SAS/TMSS/frontend/tmss_webapp/src/services/schedule.service.js @@ -186,16 +186,19 @@ const ScheduleService = { }, saveSUDraftFromObservStrategy: async function(observStrategy, schedulingUnit) { try { + // Create the scheduling unit draft with observation strategy and scheduling set const url = `/api/scheduling_unit_observing_strategy_template/${observStrategy.id}/create_scheduling_unit/?scheduling_set_id=${schedulingUnit.scheduling_set_id}&name=${schedulingUnit.name}&description=${schedulingUnit.description}` const suObsResponse = await axios.get(url); schedulingUnit = suObsResponse.data; if (schedulingUnit && schedulingUnit.id) { + // Update the newly created SU draft requirement_doc with captured parameter values schedulingUnit.requirements_doc = observStrategy.template; delete schedulingUnit['duration']; schedulingUnit = await this.updateSchedulingUnitDraft(schedulingUnit); if (!schedulingUnit || !schedulingUnit.id) { return null; } + // Create task drafts with updated requirement_doc schedulingUnit = await this.createSUTaskDrafts(schedulingUnit); if (schedulingUnit && schedulingUnit.task_drafts.length > 0) { return schedulingUnit;