diff --git a/MAC/APL/MainCU/src/MACScheduler/MACScheduler.cc b/MAC/APL/MainCU/src/MACScheduler/MACScheduler.cc index b1a3291432c4bab42e94be7b2ef657c857bb15aa..f86bd02c2d3611ea51f0a0ff50eb0eb43b5bb173 100644 --- a/MAC/APL/MainCU/src/MACScheduler/MACScheduler.cc +++ b/MAC/APL/MainCU/src/MACScheduler/MACScheduler.cc @@ -793,7 +793,7 @@ void MACScheduler::_updatePlannedList() // NOTE: do not exit routine on emptylist: we need to write an empty list to clear the DB #endif - Json::Value upcomingSubTasks = itsTMSSconnection->getSubTasksStartingInThreeMinutes(); + Json::Value upcomingSubTasks = itsTMSSconnection->getObservationSubTasksStartingInThreeMinutes(); if (!upcomingSubTasks.empty()) { LOG_DEBUG(formatString("TMSSCheck:First planned observation (%s) is at %s", @@ -1058,7 +1058,7 @@ void MACScheduler::_updateActiveList() // get new list (list is/should_be ordered on starttime) - Json::Value activeSubTasks = itsTMSSconnection->getActiveSubTasks(); + Json::Value activeSubTasks = itsTMSSconnection->getActiveObservationSubTasks(); if (activeSubTasks.empty()) { LOG_DEBUG ("No active TMSS Observations"); // NOTE: do not exit routine on emptylist: we need to write an empty list to clear the DB @@ -1150,7 +1150,7 @@ void MACScheduler::_updateFinishedList() freeSpace = MAX_CONCURRENT_OBSERVATIONS - itsNrPlanned - itsNrActive; // get new list (list is/should_be ordered on starttime) - Json::Value finishingSubTasks = itsTMSSconnection->getFinishingSubTasks(); + Json::Value finishingSubTasks = itsTMSSconnection->getFinishingObservationSubTasks(); if (finishingSubTasks.empty()) { LOG_DEBUG ("No finishing TMSS Observations"); // NOTE: do not exit routine on emptylist: we need to write an empty list to clear the DB diff --git a/MAC/APL/MainCU/src/MACScheduler/TMSSBridge.cc b/MAC/APL/MainCU/src/MACScheduler/TMSSBridge.cc index b0d0e6e2c0fd4220230c40d76e61720cfbc3581c..b7bb9816fc8b6c013939e099ddb1d2247143018e 100644 --- a/MAC/APL/MainCU/src/MACScheduler/TMSSBridge.cc +++ b/MAC/APL/MainCU/src/MACScheduler/TMSSBridge.cc @@ -76,14 +76,14 @@ Json::Value TMSSBridge::getSubTask(int subtask_id) // get all subTaskIDS that should run within three minutes (ordered in time if multiple are found) // for given cluster // -Json::Value TMSSBridge::getSubTasksStartingInThreeMinutes() +Json::Value TMSSBridge::getObservationSubTasksStartingInThreeMinutes() { time_t now = time(0); ptime lower_limit = from_time_t(now); ptime upper_limit = from_time_t(now+3*60); //TODO: make exact query as in SAS/OTDB/sql/getTreeGroup_func.sql with OR'd states and exact timewindow - string queryStr = "/api/subtask/?state__value=scheduled&scheduled_on_sky_start_time__gt=" + to_iso_extended_string(lower_limit) + "&scheduled_on_sky_start_time__lt=" + to_iso_extended_string(upper_limit) + "&ordering=scheduled_on_sky_start_time"; + string queryStr = "/api/subtask/?subtask_type=observation&state__value=scheduled&scheduled_on_sky_start_time__gt=" + to_iso_extended_string(lower_limit) + "&scheduled_on_sky_start_time__lt=" + to_iso_extended_string(upper_limit) + "&ordering=scheduled_on_sky_start_time"; Json::Value result; if(httpGETAsJson(queryStr, result)) @@ -91,11 +91,11 @@ Json::Value TMSSBridge::getSubTasksStartingInThreeMinutes() return Json::Value(""); } -Json::Value TMSSBridge::getActiveSubTasks() +Json::Value TMSSBridge::getActiveObservationSubTasks() { ptime now = from_time_t(time(0)); //TODO: make exact query as in SAS/OTDB/sql/getTreeGroup_func.sql with OR'd states and exact timewindow - string queryStr = "/api/subtask/?state__value=started&scheduled_on_sky_start_time__lt=" + to_iso_extended_string(now) + "&scheduled_on_sky_stop_time__gt=" + to_iso_extended_string(now) + "&ordering=scheduled_on_sky_start_time"; + string queryStr = "/api/subtask/?subtask_type=observation&state__value=started&scheduled_on_sky_start_time__lt=" + to_iso_extended_string(now) + "&scheduled_on_sky_stop_time__gt=" + to_iso_extended_string(now) + "&&ordering=scheduled_on_sky_start_time"; Json::Value result; if(httpGETAsJson(queryStr, result)) @@ -103,11 +103,11 @@ Json::Value TMSSBridge::getActiveSubTasks() return Json::Value(""); } -Json::Value TMSSBridge::getFinishingSubTasks() +Json::Value TMSSBridge::getFinishingObservationSubTasks() { ptime justnow = from_time_t(time(0)-3*60); //TODO: make exact query as in SAS/OTDB/sql/getTreeGroup_func.sql with OR'd states and exact timewindow - string queryStr = "/api/subtask/?state__value=finishing&scheduled_on_sky_stop_time__gt=" + to_iso_extended_string(justnow) + "&ordering=scheduled_on_sky_start_time"; + string queryStr = "/api/subtask/?subtask_type=observation&state__value=finishing&scheduled_on_sky_stop_time__gt=" + to_iso_extended_string(justnow) + "&ordering=scheduled_on_sky_start_time"; Json::Value result; if(httpGETAsJson(queryStr, result)) diff --git a/MAC/APL/MainCU/src/MACScheduler/TMSSBridge.h b/MAC/APL/MainCU/src/MACScheduler/TMSSBridge.h index 3658bd59f75134036c05156b5d46a6c50da952f6..736bbc5d836ca0852e9eddfde2df6604bda95da1 100644 --- a/MAC/APL/MainCU/src/MACScheduler/TMSSBridge.h +++ b/MAC/APL/MainCU/src/MACScheduler/TMSSBridge.h @@ -38,9 +38,9 @@ public: Json::Value getSubTask(int subtask_id); - Json::Value getSubTasksStartingInThreeMinutes(); - Json::Value getActiveSubTasks(); - Json::Value getFinishingSubTasks(); + Json::Value getObservationSubTasksStartingInThreeMinutes(); + Json::Value getActiveObservationSubTasks(); + Json::Value getFinishingObservationSubTasks(); std::string getParsetAsText(int subtask_id); bool setSubtaskState(int subtask_id, const std::string& state); diff --git a/SAS/TMSS/backend/src/tmss/tmssapp/viewsets/scheduling.py b/SAS/TMSS/backend/src/tmss/tmssapp/viewsets/scheduling.py index eecfea0ab5133fbca074cb3d41f43eeb8a915e8f..5ab6c1e51a1a535c129b8b895f456bf046e20eba 100644 --- a/SAS/TMSS/backend/src/tmss/tmssapp/viewsets/scheduling.py +++ b/SAS/TMSS/backend/src/tmss/tmssapp/viewsets/scheduling.py @@ -152,6 +152,7 @@ class SubTaskFilter(property_filters.PropertyFilterSet): actual_process_stop_time__lt = filters.IsoDateTimeFilter(field_name='actual_process_stop_time', lookup_expr='lt') actual_process_stop_time__gt = filters.IsoDateTimeFilter(field_name='actual_process_stop_time', lookup_expr='gt') + subtask_type = filters.ModelMultipleChoiceFilter(field_name='specifications_template__type', queryset=models.SubtaskType.objects.all()) class Meta: model = Subtask @@ -539,4 +540,4 @@ class SAPTemplateViewSet(AbstractTemplateViewSet): class SIPidentifierViewSet(LOFARViewSet): queryset = models.SIPidentifier.objects.all() - serializer_class = serializers.SIPidentifierSerializer \ No newline at end of file + serializer_class = serializers.SIPidentifierSerializer diff --git a/SAS/TMSS/backend/test/t_subtasks.py b/SAS/TMSS/backend/test/t_subtasks.py index 370d0fc20fa54a8adf76fb75172ff1ab3b80e5c1..9323947f44de942291823bbf2d8440085f532a4c 100755 --- a/SAS/TMSS/backend/test/t_subtasks.py +++ b/SAS/TMSS/backend/test/t_subtasks.py @@ -828,6 +828,26 @@ class SubtaskAllowedStateTransitionsTest(unittest.TestCase): subtask.refresh_from_db() self.assertEqual(state_value, subtask.state.value) +class SubTaskFilterOnRestAPITest(unittest.TestCase): + + def test_filter_for_subtask_type(self): + # setup + observation_task_blueprint = create_task_blueprint_object_for_testing(task_template_name="target observation") + + # trigger + subtask = create_observation_control_subtask_from_task_blueprint(observation_task_blueprint) + obs_subtask_id = subtask.id + + with tmss_test_env.create_tmss_client() as client: + subtasks = client.get_subtasks(subtask_type='observation') + ids = [s['id'] for s in subtasks] + self.assertIn(obs_subtask_id, ids) + + subtasks = client.get_subtasks(subtask_type='pipeline') + ids = [s['id'] for s in subtasks] + self.assertNotIn(obs_subtask_id, ids) + + if __name__ == "__main__": os.environ['TZ'] = 'UTC' unittest.main() diff --git a/SAS/TMSS/client/lib/tmss_http_rest_client.py b/SAS/TMSS/client/lib/tmss_http_rest_client.py index bb174a684c6b243ba3a27fe40056efbe1d7854e1..dcb1d5ebf971540a0251440b539beeb3c980b5f6 100644 --- a/SAS/TMSS/client/lib/tmss_http_rest_client.py +++ b/SAS/TMSS/client/lib/tmss_http_rest_client.py @@ -217,7 +217,7 @@ class TMSSsession(object): path = 'subtask/%s' % (subtask_id,) return self.get_path_as_json_object(path) - def get_subtasks(self, state: str=None, + def get_subtasks(self, state: str=None, subtask_type: str=None, cluster: str=None, scheduled_on_sky_start_time_less_then: datetime=None, scheduled_on_sky_start_time_greater_then: datetime=None, scheduled_on_sky_stop_time_less_then: datetime = None, scheduled_on_sky_stop_time_greater_then: datetime = None) -> list: @@ -225,6 +225,8 @@ class TMSSsession(object): clauses = {} if state is not None: clauses["state__value"] = state + if subtask_type is not None: + clauses["subtask_type"] = subtask_type if cluster is not None: clauses["cluster__name"] = cluster if scheduled_on_sky_start_time_less_then is not None: diff --git a/SAS/TMSS/frontend/tmss_webapp/src/layout/_overrides.scss b/SAS/TMSS/frontend/tmss_webapp/src/layout/_overrides.scss index 2a04b2b456b5b95988df99015cd835abc6663431..b41bf3b7ab750dc1d13f79c60bbb9309b11c05fa 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/layout/_overrides.scss +++ b/SAS/TMSS/frontend/tmss_webapp/src/layout/_overrides.scss @@ -309,7 +309,7 @@ In Excel View the for Accordion background color override /** Below classes for JSON Editor- Begin */ -.row { +.je-object__container .row { margin-left: 2em !important; max-width: 100% !important; } diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/Scheduling.Constraints.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/Scheduling.Constraints.js index 6acbc47fb72a90b6cffa8ecb99cd14718f0a4604..7d3d75168efb723d5cace6bedfd73a041e16f610 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/Scheduling.Constraints.js +++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/Scheduling.Constraints.js @@ -121,29 +121,8 @@ export default (props) => { } } - //Disable 'AT' field when schedular -> online + // Callback function to pass the constraints JSON output to parent component const onEditForm = (jsonOutput, errors, ref) => { - if (ref.editors['root.scheduler'] && ref.editors['root.scheduler'].value.toLowerCase()!== 'manual') { - if (ref.editors['root.time.at']) { - const list = ref.editors['root.time.at'].container.className.split(' '); - if (!list.includes('disable-field')) { - list.push('disable-field'); - } - ref.editors['root.time.at'].container.className = list.join(' '); - if (ref.editors['root.time.at'].control) { - Array.prototype.slice.call(ref.editors['root.time.at'].control.getElementsByTagName('input')).forEach(input => input.disabled = true); - Array.prototype.slice.call(ref.editors['root.time.at'].control.getElementsByTagName('button')).forEach(button => button.disabled = true); - } - } - } else { - if (ref.editors['root.time.at']) { - ref.editors['root.time.at'].container.className = ref.editors['root.time.at'].container.className.replace('disable-field', ''); - if (ref.editors['root.time.at'].control) { - Array.prototype.slice.call(ref.editors['root.time.at'].control.getElementsByTagName('input')).forEach(input => input.disabled = false); - Array.prototype.slice.call(ref.editors['root.time.at'].control.getElementsByTagName('button')).forEach(button => button.disabled = false); - } - } - } if (props.callback) { // Remove 'time' fields if it is empty for (const key of _.keys(jsonOutput.time)) { 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 75b3e2a92aa2e5d6812c534347d45b992b879f08..322fcd84946e037c4f7efd92d7df4b6dceb4e1d8 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/create.js +++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/create.js @@ -370,7 +370,7 @@ export class SchedulingUnitCreate extends Component { const constStrategy = _.cloneDeep(this.state.constraintParamsOutput); for (let type in constStrategy.time) { if (constStrategy.scheduler === 'online' || constStrategy.scheduler === 'dynamic') { - delete constStrategy.time.at; + // delete constStrategy.time.at; } if (!constStrategy.time.after) { delete constStrategy.time.after; diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/excelview.schedulingset.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/excelview.schedulingset.js index ce1ca88b1de9c53d46165c8e9fa0613836a3a6eb..5257f7da8b288b420891ca5da2495c7f6b9ee185 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/excelview.schedulingset.js +++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/excelview.schedulingset.js @@ -825,7 +825,7 @@ export class SchedulingSetCreate extends Component { const keys = Object.keys(lastRow); for (const key of keys) { if (key === 'daily') { - console.log("key =>",key,lastRow[key], observationProps[key]) + // console.log("key =>",key,lastRow[key], observationProps[key]) } if ( !_.isEqual(lastRow[key], observationProps[key])) { defaultCommonRowData[key] = ''; @@ -1588,7 +1588,7 @@ export class SchedulingSetCreate extends Component { isValidRow = false; errorMsg += column.colDef.headerName+", "; } - } else if ((column.colId === 'timeat') && isManualScheduler && rowData[column.colId] === ''){ + } else if (isManualScheduler && (column.colId === 'timeat') && rowData[column.colId] === ''){ isValidRow = false; errorMsg += column.colDef.headerName+", "; // column.colDef.cellStyle = { backgroundColor: BG_COLOR}; @@ -1657,6 +1657,12 @@ export class SchedulingSetCreate extends Component { } } } + // When no values entered or if the field doesn't have value for existing record, AG-grid API returns undefined. + // So added validation message for manual scheduler. + if (isManualScheduler && rowData['timeat'] === undefined) { + isValidRow = false; + errorMsg += "At, "; + } } } if(hasData) { @@ -1801,42 +1807,21 @@ export class SchedulingSetCreate extends Component { } //If No SU Constraint create default ( maintain default struc) constraint['scheduler'] = suRow.scheduler; - if (suRow.scheduler === 'dynamic' || suRow.scheduler === 'online'){ - if (constraint.time) { - delete constraint.time.at; - delete constraint.time.after; - delete constraint.time.before; - delete constraint.time.between; - delete constraint.time.not_between; - } - /* - if (this.isNotEmpty(suRow.timeat)) { - delete constraint.time.at; - } - - if (!this.isNotEmpty(suRow.timeafter) && constraint.time) { - delete constraint.time.after; - } - - if (!this.isNotEmpty(suRow.timebefore) && constraint.time) { - delete constraint.time.before; - } */ - } - else { - //mandatory + // Remove empty time constraint properties + if (this.isNotEmpty(suRow.timeat)) { constraint.time.at = `${moment(suRow.timeat).format(UIConstants.UTC_DATE_TIME_MS_FORMAT, { trim: false })}Z`; - //optional - if (!this.isNotEmpty(suRow.timeafter)) { - delete constraint.time.after; - } else { - constraint.time.after = `${moment(suRow.timeafter).format(UIConstants.UTC_DATE_TIME_MS_FORMAT, { trim: false })}Z`; - } - - if (!this.isNotEmpty(suRow.timebefore)) { - delete constraint.time.before; - } else { - constraint.time.before = `${moment(suRow.timebefore).format(UIConstants.UTC_DATE_TIME_MS_FORMAT, { trim: false })}Z`; - } + } else { + delete constraint.time.at; + } + if (this.isNotEmpty(suRow.timeafter)) { + constraint.time.after = `${moment(suRow.timeafter).format(UIConstants.UTC_DATE_TIME_MS_FORMAT, { trim: false })}Z`; + } else { + delete constraint.time.after; + } + if (this.isNotEmpty(suRow.timebefore)) { + constraint.time.before = `${moment(suRow.timebefore).format(UIConstants.UTC_DATE_TIME_MS_FORMAT, { trim: false })}Z`; + } else { + delete constraint.time.before; } if (this.isNotEmpty(between)){