diff --git a/SAS/TMSS/frontend/tmss_webapp/debug.log b/SAS/TMSS/frontend/tmss_webapp/debug.log new file mode 100644 index 0000000000000000000000000000000000000000..01dc4fc16fca435bb7bf306a049f61afa6fb3e73 --- /dev/null +++ b/SAS/TMSS/frontend/tmss_webapp/debug.log @@ -0,0 +1,160 @@ +[1013/111617.035:ERROR:directory_reader_win.cc(43)] FindFirstFile: The system cannot find the path specified. (0x3) +[1015/122332.151:ERROR:directory_reader_win.cc(43)] FindFirstFile: The system cannot find the path specified. (0x3) +[1016/161237.331:ERROR:directory_reader_win.cc(43)] FindFirstFile: The system cannot find the path specified. (0x3) +[1017/012451.442:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.443:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.443:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.443:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.443:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.477:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.477:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.477:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.477:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.477:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.480:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.480:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.481:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.481:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.481:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.444:ERROR:process_reader_win.cc(123)] NtOpenThread: {Access Denied} A process has requested access to an object, but has not been granted those access rights. (0xc0000022) +[1017/012451.482:ERROR:exception_snapshot_win.cc(99)] thread ID 12524 not found in process +[1017/012451.481:ERROR:process_reader_win.cc(123)] NtOpenThread: {Access Denied} A process has requested access to an object, but has not been granted those access rights. (0xc0000022) +[1017/012451.490:ERROR:exception_snapshot_win.cc(99)] thread ID 17560 not found in process +[1017/012451.477:ERROR:process_reader_win.cc(123)] NtOpenThread: {Access Denied} A process has requested access to an object, but has not been granted those access rights. (0xc0000022) +[1017/012451.495:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.495:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.495:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.495:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.495:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.495:ERROR:process_reader_win.cc(123)] NtOpenThread: {Access Denied} A process has requested access to an object, but has not been granted those access rights. (0xc0000022) +[1017/012451.496:ERROR:exception_snapshot_win.cc(99)] thread ID 13540 not found in process +[1017/012451.501:ERROR:exception_snapshot_win.cc(99)] thread ID 5380 not found in process +[1017/012451.510:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.510:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.510:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.510:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.510:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.510:ERROR:process_reader_win.cc(123)] NtOpenThread: {Access Denied} A process has requested access to an object, but has not been granted those access rights. (0xc0000022) +[1017/012451.511:ERROR:exception_snapshot_win.cc(99)] thread ID 17600 not found in process +[1017/012451.519:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.519:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.519:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.519:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.519:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.519:ERROR:process_reader_win.cc(123)] NtOpenThread: {Access Denied} A process has requested access to an object, but has not been granted those access rights. (0xc0000022) +[1017/012451.519:ERROR:exception_snapshot_win.cc(99)] thread ID 6792 not found in process +[1017/012451.558:ERROR:process_reader_win.cc(123)] NtOpenThread: {Access Denied} A process has requested access to an object, but has not been granted those access rights. (0xc0000022) +[1017/012451.558:ERROR:exception_snapshot_win.cc(99)] thread ID 17732 not found in process +[1017/012451.560:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.560:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.560:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.561:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.561:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.561:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.561:ERROR:process_reader_win.cc(123)] NtOpenThread: {Access Denied} A process has requested access to an object, but has not been granted those access rights. (0xc0000022) +[1017/012451.561:ERROR:exception_snapshot_win.cc(99)] thread ID 14508 not found in process +[1017/012451.439:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.565:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.566:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.566:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.566:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.566:ERROR:process_reader_win.cc(123)] NtOpenThread: {Access Denied} A process has requested access to an object, but has not been granted those access rights. (0xc0000022) +[1017/012451.566:ERROR:exception_snapshot_win.cc(99)] thread ID 7752 not found in process +[1017/012451.672:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.672:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.672:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.672:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.672:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.672:ERROR:process_reader_win.cc(123)] NtOpenThread: {Access Denied} A process has requested access to an object, but has not been granted those access rights. (0xc0000022) +[1017/012451.674:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.674:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.674:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.674:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.674:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.675:ERROR:process_reader_win.cc(123)] NtOpenThread: {Access Denied} A process has requested access to an object, but has not been granted those access rights. (0xc0000022) +[1017/012451.726:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.726:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.726:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.726:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.726:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.726:ERROR:process_reader_win.cc(123)] NtOpenThread: {Access Denied} A process has requested access to an object, but has not been granted those access rights. (0xc0000022) +[1017/012451.726:ERROR:exception_snapshot_win.cc(99)] thread ID 7336 not found in process +[1017/012451.727:ERROR:exception_snapshot_win.cc(99)] thread ID 14456 not found in process +[1017/012451.730:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.730:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.730:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.730:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.730:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.730:ERROR:process_reader_win.cc(123)] NtOpenThread: {Access Denied} A process has requested access to an object, but has not been granted those access rights. (0xc0000022) +[1017/012451.730:ERROR:exception_snapshot_win.cc(99)] thread ID 13340 not found in process +[1017/012451.731:ERROR:exception_snapshot_win.cc(99)] thread ID 14340 not found in process +[1017/012451.733:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.733:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.733:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.733:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.733:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.733:ERROR:process_reader_win.cc(123)] NtOpenThread: {Access Denied} A process has requested access to an object, but has not been granted those access rights. (0xc0000022) +[1017/012451.734:ERROR:exception_snapshot_win.cc(99)] thread ID 12364 not found in process +[1017/012451.738:ERROR:process_reader_win.cc(123)] NtOpenThread: {Access Denied} A process has requested access to an object, but has not been granted those access rights. (0xc0000022) +[1017/012451.738:ERROR:exception_snapshot_win.cc(99)] thread ID 8776 not found in process +[1017/012451.742:ERROR:process_reader_win.cc(123)] NtOpenThread: {Access Denied} A process has requested access to an object, but has not been granted those access rights. (0xc0000022) +[1017/012451.742:ERROR:exception_snapshot_win.cc(99)] thread ID 2456 not found in process +[1017/012451.744:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.744:ERROR:process_reader_win.cc(123)] NtOpenThread: {Access Denied} A process has requested access to an object, but has not been granted those access rights. (0xc0000022) +[1017/012451.744:ERROR:exception_snapshot_win.cc(99)] thread ID 17716 not found in process +[1017/012451.748:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.748:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.749:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.749:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.749:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.749:ERROR:process_reader_win.cc(123)] NtOpenThread: {Access Denied} A process has requested access to an object, but has not been granted those access rights. (0xc0000022) +[1017/012451.749:ERROR:exception_snapshot_win.cc(99)] thread ID 17540 not found in process +[1017/012451.759:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.759:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.759:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.759:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.759:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.759:ERROR:process_reader_win.cc(123)] NtOpenThread: {Access Denied} A process has requested access to an object, but has not been granted those access rights. (0xc0000022) +[1017/012451.760:ERROR:exception_snapshot_win.cc(99)] thread ID 2544 not found in process +[1017/012451.763:ERROR:process_reader_win.cc(123)] NtOpenThread: {Access Denied} A process has requested access to an object, but has not been granted those access rights. (0xc0000022) +[1017/012451.763:ERROR:exception_snapshot_win.cc(99)] thread ID 1492 not found in process +[1017/012451.769:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.769:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.769:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.769:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.769:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.769:ERROR:process_reader_win.cc(123)] NtOpenThread: {Access Denied} A process has requested access to an object, but has not been granted those access rights. (0xc0000022) +[1017/012451.769:ERROR:exception_snapshot_win.cc(99)] thread ID 18068 not found in process +[1017/012451.772:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.772:ERROR:process_reader_win.cc(123)] NtOpenThread: {Access Denied} A process has requested access to an object, but has not been granted those access rights. (0xc0000022) +[1017/012451.772:ERROR:exception_snapshot_win.cc(99)] thread ID 15228 not found in process +[1017/012451.773:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.773:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.774:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.774:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.774:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.774:ERROR:process_reader_win.cc(123)] NtOpenThread: {Access Denied} A process has requested access to an object, but has not been granted those access rights. (0xc0000022) +[1017/012451.774:ERROR:exception_snapshot_win.cc(99)] thread ID 14676 not found in process +[1017/012451.775:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.776:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.776:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.776:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.776:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.776:ERROR:process_reader_win.cc(123)] NtOpenThread: {Access Denied} A process has requested access to an object, but has not been granted those access rights. (0xc0000022) +[1017/012451.776:ERROR:exception_snapshot_win.cc(99)] thread ID 13992 not found in process +[1017/012451.773:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.776:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.776:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.776:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.776:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.777:ERROR:process_reader_win.cc(123)] NtOpenThread: {Access Denied} A process has requested access to an object, but has not been granted those access rights. (0xc0000022) +[1017/012451.777:ERROR:exception_snapshot_win.cc(99)] thread ID 14776 not found in process +[1017/012451.777:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.777:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.777:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.777:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.777:ERROR:process_reader_win.cc(151)] SuspendThread: Access is denied. (0x5) +[1017/012451.777:ERROR:process_reader_win.cc(123)] NtOpenThread: {Access Denied} A process has requested access to an object, but has not been granted those access rights. (0xc0000022) +[1017/012451.778:ERROR:exception_snapshot_win.cc(99)] thread ID 17500 not found in process +[1017/012451.781:ERROR:process_reader_win.cc(123)] NtOpenThread: {Access Denied} A process has requested access to an object, but has not been granted those access rights. (0xc0000022) +[1017/012451.781:ERROR:exception_snapshot_win.cc(99)] thread ID 10344 not found in process diff --git a/SAS/TMSS/frontend/tmss_webapp/src/components/JSONEditor/JEditor.js b/SAS/TMSS/frontend/tmss_webapp/src/components/JSONEditor/JEditor.js index 06f9ead9e0cfceb602f0f859e4c249c958cbeb9f..a4e78c074972ee04665d97dec5ea6cd95adb67e7 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/components/JSONEditor/JEditor.js +++ b/SAS/TMSS/frontend/tmss_webapp/src/components/JSONEditor/JEditor.js @@ -98,7 +98,7 @@ function Jeditor(props) { } } - // Customize datatype of certain properties like subbands, duration, etc., + // Customize datatype of certain properties like subbands, duration, etc., getCustomProperties(schema.properties); schema.title = props.title; const subbandValidator = validateSubbandOutput; @@ -130,6 +130,30 @@ function Jeditor(props) { message: 'Not a valid input. Mimimum: 00:00:00, Maximum:90:00:00' }); } + } else if (schema.validationType === "distanceOnSky") { + if (!value || isNaN(value) || value < 0 || value > 180) { + errors.push({ + path: path, + property: 'validationType', + message: 'Not a valid input.Must be number between 0 - 180' + }); + } + } else if (schema.validationType === "elevation") { + if (!value || isNaN(value) || value < 0 || value > 90) { + errors.push({ + path: path, + property: 'validationType', + message: 'Not a valid input.Must be number between 0 - 90' + }); + } + } else if (schema.validationType === "transit_offset") { + if (!value || isNaN(value) || value < 0 || value > 60) { + errors.push({ + path: path, + property: 'validationType', + message: 'Not a valid input.Must be number between 0 - 60' + }); + } } return errors; }); @@ -181,7 +205,7 @@ function Jeditor(props) { const formattedOutput = updateOutput(_.cloneDeep(editorOutput)); const editorValidationErrors = editorRef.current.validate(); if (props.callback) { - props.callback(formattedOutput, editorValidationErrors); + props.callback(formattedOutput, editorValidationErrors, editorRef.current); } } @@ -265,7 +289,7 @@ function Jeditor(props) { properties[propertyKey] = newProperty; } else if (propertyValue instanceof Object) { - if (propertyKey !== 'properties' && propertyKey !== 'default') { + if (propertyKey !== 'properties' && propertyKey !== 'default' && !propertyValue.skipFormat) { propertyValue.format = "grid"; } if (propertyKey === 'average' || propertyKey === 'calibrator' || propertyKey === 'stations') { @@ -287,7 +311,8 @@ function Jeditor(props) { if (propertyValue['$ref'] && propertyValue['$ref'].endsWith("/pointing")) { pointingProps.push(propertyKey); } - getCustomProperties(propertyValue); + + getCustomProperties(propertyValue); } } } diff --git a/SAS/TMSS/frontend/tmss_webapp/src/layout/_overrides.scss b/SAS/TMSS/frontend/tmss_webapp/src/layout/_overrides.scss index 03b42a5aeb25770e4dc82919a4ee85d33cec416d..9a861b9b449a070207a892aff01a2d76c6186f84 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/layout/_overrides.scss +++ b/SAS/TMSS/frontend/tmss_webapp/src/layout/_overrides.scss @@ -50,4 +50,13 @@ display: none !important; } } +.form-group .form-control #specification[scheduler]{ + width: 250px; +} +.disable-field { + pointer-events: none; +} +.hide { + display: none !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 new file mode 100644 index 0000000000000000000000000000000000000000..e0dc8709503000f748175d3a9d6cf98f5b26cdf2 --- /dev/null +++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/Scheduling.Constraints.js @@ -0,0 +1,204 @@ +import React, { useState, useEffect } from 'react'; +import moment from 'moment'; +import Jeditor from '../../components/JSONEditor/JEditor'; + +export default (props) => { + const [constraintSchema, setConstraintSchema] = useState(); + const [initialValue, setInitialValue] = useState(); + //SU Constraint Editor Property Order,format and validation + const configureProperties = (properties) => { + for (const propertyKey in properties) { + const propertyValue = properties[propertyKey]; + if (propertyValue instanceof Object) { + configureProperties(propertyValue) + } + if(propertyKey === 'scheduler'){ + propertyValue.propertyOrder=1; + } + if(propertyKey === 'time'){ + propertyValue.propertyOrder=2; + } + if(propertyKey === 'at' || propertyKey === 'after' || propertyKey === 'before'){ + propertyValue.propertyOrder=3; + setDateTimeOption(propertyValue); + } + if(propertyKey === 'between' || propertyKey === 'not_between' ){ + propertyValue.propertyOrder=4; + } + if(propertyKey === 'daily'){ + propertyValue.propertyOrder=5; + propertyValue.format= 'checkbox'; + propertyValue.skipFormat = true; + } + if (propertyKey === 'require_night' || propertyKey === 'require_day' || propertyKey === 'avoid_twilight' ){ + propertyValue.propertyOrder=6; + } + if(propertyKey === 'sky'){ + propertyValue.propertyOrder=7; + } + if(propertyKey === 'min_calibrator_elevation' ){ + propertyValue.propertyOrder=8; + propertyValue.validationType= 'elevation'; + } + if(propertyKey === 'min_target_elevation'){ + propertyValue.propertyOrder=9; + propertyValue.validationType= 'elevation'; + } + if(propertyKey === 'transit_offset'){ + propertyValue.propertyOrder=10; + } + if(propertyKey === 'from' ){ + propertyValue.propertyOrder=11; + } + if(propertyKey === 'to'){ + propertyValue.propertyOrder=12; + } + if(propertyKey === 'sun' || propertyKey === 'moon' || propertyKey === 'jupiter'){ + propertyValue.propertyOrder=13; + propertyValue.validationType= 'distanceOnSky'; + } + if(propertyKey === 'avoid_twilight' || propertyKey === 'require_day' || propertyKey === 'require_night'){ + propertyValue.format= 'checkbox'; + propertyValue.skipFormat = true; + } + } + }; + //DateTime flatPicker component enabled with seconds + const setDateTimeOption = (propertyValue) => { + propertyValue.format = 'datetime-local'; + propertyValue.validationType = 'dateTime'; + propertyValue.skipFormat = true; + propertyValue.options = { + "inputAttributes": { + "placeholder": "mm/dd/yyyy,--:--:--" + }, + "flatpickr": { + "inlineHideInput": true, + "wrap": true, + "enableSeconds": true, + + } + }; + }; + //Configuring Schema Definitions + const configureDefinitions = (schema) => { + for (const definitionName in schema.definitions) { + if (definitionName === 'timestamp') { + schema.definitions.timestamp ={ + validationType: 'datetime', + type: schema.definitions.timestamp.type + }; + } else if (definitionName !== 'timewindow' && definitionName !== 'timestamp') { + schema.definitions[definitionName] = { + type: schema.definitions[definitionName].type + }; + } else if(definitionName === 'timewindow') { + for (let property in schema.definitions.timewindow.properties) { + if(property === 'to' || property === 'from'){ + setDateTimeOption(schema.definitions.timewindow.properties[property]); + if (property === 'from') { + schema.definitions.timewindow.properties[property].propertyOrder = 1; + } else { + schema.definitions.timewindow.properties[property].propertyOrder = 2; + schema.definitions.timewindow.properties[property].title = 'until'; + } + } + } + } + } + } + + //Disable 'AT' field when schedular -> online + const onEditForm = (jsonOutput, errors, ref) => { + if (ref.editors['root.scheduler'] && ref.editors['root.scheduler'].value !== 'manual') { + 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(' '); + } else { + ref.editors['root.time.at'].container.className = ref.editors['root.time.at'].container.className.replace('disable-field', ''); + } + if (props.callback) { + props.callback(jsonOutput, errors); + } + } + + const constraintStrategy = () => { + const constraintTemplate = { ...props.constraintTemplate } + if (constraintTemplate.schema) { + configureProperties(constraintTemplate.schema.properties); + configureDefinitions(constraintTemplate.schema); + } + setConstraintSchema(constraintTemplate); + }; + + //Radians to Degree Conversion + const radiansToDegree = (object) => { + for(let type in object) { + if (typeof object[type] === 'object') { + radiansToDegree(object[type]); + } else { + object[type] = (object[type] * 180) / Math.PI; + } + } + } + + const modifyInitiValue = () => { + const initValue = { ...props.initValue } + // For DateTime + for (let key in initValue.time) { + if (typeof initValue.time[key] === 'string') { + initValue.time[key] = moment(new Date((initValue.time[key] || '').replace('Z', ''))).format("YYYY-MM-DD hh:mm:ss"); + } else { + initValue.time[key].map(time => { + for (let subKey in time) { + time[subKey] = moment(new Date((time[subKey] || '').replace('Z', ''))).format("YYYY-MM-DD hh:mm:ss"); + } + }) + } + } + if (!initValue.time.at) { + initValue.time.at= ''; + } + if (!initValue.time.before) { + initValue.time.before= ''; + } + if (!initValue.time.after) { + initValue.time.after= ''; + } + if (!initValue.time.between) { + initValue.time.between= ''; + } + if (!initValue.time.not_between) { + initValue.time.not_between= ''; + } + for (let type in initValue.sky.transit_offset) { + initValue.sky.transit_offset[type] = initValue.sky.transit_offset[type] / 60; + } + radiansToDegree(initValue.sky); + setInitialValue(initValue); + } + + useEffect(() => { + if (!props.constraintTemplate) { + return; + } + if (props.initValue) { + modifyInitiValue(); + } + constraintStrategy(); + }, [props.constraintTemplate, props.initValue]); + + return ( + <> + {constraintSchema && React.createElement(Jeditor, { + title: "Scheduling Constraints specification", + schema: constraintSchema.schema, + callback: onEditForm, + initValue: initialValue, + disabled: props.disable, + })} + </> + ); +}; diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/ViewSchedulingUnit.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/ViewSchedulingUnit.js index c57445b61784420eceb8a9f538d5c113fea84909..b64fae974ef8fb5f287eec83cd8db0693ad2bc1c 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/ViewSchedulingUnit.js +++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/ViewSchedulingUnit.js @@ -9,6 +9,7 @@ import PageHeader from '../../layout/components/PageHeader'; import ViewTable from './../../components/ViewTable'; import ScheduleService from '../../services/schedule.service'; import moment from 'moment'; +import SchedulingConstraint from './Scheduling.Constraints'; class ViewSchedulingUnit extends Component{ constructor(props){ @@ -55,6 +56,7 @@ class ViewSchedulingUnit extends Component{ this.actions = [ {icon: 'fa-window-close',title:'Click to Close Scheduling Unit View', link: this.props.history.goBack} ]; + this.constraintTemplates = []; if (this.props.match.params.type === 'draft') { this.actions.unshift({icon: 'fa-edit', title: 'Click to edit', props : { pathname:`/schedulingunit/edit/${ this.props.match.params.id}` } }); @@ -76,6 +78,10 @@ class ViewSchedulingUnit extends Component{ this.getScheduleUnit(schedule_type, schedule_id) .then(schedulingUnit =>{ if (schedulingUnit) { + ScheduleService.getSchedulingConstraints().then((response) => { + this.constraintTemplates = response; + this.setState({ constraintSchema: this.constraintTemplates.find(i => i.id === schedulingUnit.scheduling_constraints_template_id) }) + }); this.getScheduleUnitTasks(schedule_type, schedulingUnit) .then(tasks =>{ /* tasks.map(task => { @@ -170,6 +176,7 @@ class ViewSchedulingUnit extends Component{ </> } + {this.state.scheduleunit && this.state.scheduleunit.scheduling_constraints_doc && <SchedulingConstraint disable constraintTemplate={this.state.constraintSchema} initValue={this.state.scheduleunit.scheduling_constraints_doc} />} <div> <h3>Tasks Details</h3> </div> @@ -202,4 +209,4 @@ class ViewSchedulingUnit extends Component{ } } -export default ViewSchedulingUnit \ No newline at end of file +export default ViewSchedulingUnit 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 62db24996287f74d5e98fc1c816d7d519f944898..1421a13a1b9bd79759f1e9ee8ec2050030d69ba1 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/create.js +++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/create.js @@ -1,8 +1,8 @@ import React, {Component} from 'react'; -import { Link, Redirect } from 'react-router-dom'; +import { Redirect } from 'react-router-dom'; import _ from 'lodash'; import $RefParser from "@apidevtools/json-schema-ref-parser"; - +import moment from 'moment'; import {InputText} from 'primereact/inputtext'; import {InputTextarea} from 'primereact/inputtextarea'; import {Dropdown} from 'primereact/dropdown'; @@ -18,7 +18,7 @@ import ScheduleService from '../../services/schedule.service'; import TaskService from '../../services/task.service'; import UIConstants from '../../utils/ui.constants'; import PageHeader from '../../layout/components/PageHeader'; - +import SchedulingConstraint from './Scheduling.Constraints'; /** * Component to create a new SchedulingUnit from Observation strategy template */ @@ -37,6 +37,7 @@ export class SchedulingUnitCreate extends Component { 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 + constraintSchema:null, validEditor: false, // For JSON editor validation validFields: {}, // For Form Validation } @@ -45,6 +46,7 @@ export class SchedulingUnitCreate extends Component { 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.constraintTemplates = []; 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"}, @@ -54,8 +56,10 @@ export class SchedulingUnitCreate extends Component { }; this.setEditorOutput = this.setEditorOutput.bind(this); + this.setEditorOutputConstraint = this.setEditorOutputConstraint.bind(this); this.changeProject = this.changeProject.bind(this); this.changeStrategy = this.changeStrategy.bind(this); + this.constraintStrategy = this.constraintStrategy.bind(this); this.setSchedUnitParams = this.setSchedUnitParams.bind(this); this.validateForm = this.validateForm.bind(this); this.validateEditor = this.validateEditor.bind(this); @@ -63,18 +67,23 @@ export class SchedulingUnitCreate extends Component { this.saveSchedulingUnit = this.saveSchedulingUnit.bind(this); this.cancelCreate = this.cancelCreate.bind(this); this.reset = this.reset.bind(this); + this.degreeToRadians = this.degreeToRadians.bind(this); } componentDidMount() { const promises = [ ProjectService.getProjectList(), ScheduleService.getSchedulingSets(), ScheduleService.getObservationStrategies(), - TaskService.getTaskTemplates()] + TaskService.getTaskTemplates(), + ScheduleService.getSchedulingConstraints()] Promise.all(promises).then(responses => { this.projects = responses[0]; this.schedulingSets = responses[1]; this.observStrategies = responses[2]; this.taskTemplates = responses[3]; + this.constraintTemplates = responses[4]; + // Setting first value as constraint template + this.constraintStrategy(this.constraintTemplates[0]); if (this.state.schedulingUnit.project) { const projectSchedSets = _.filter(this.schedulingSets, {'project_id': this.state.schedulingUnit.project}); this.setState({isLoading: false, schedulingSets: projectSchedSets}); @@ -138,14 +147,6 @@ export class SchedulingUnitCreate extends Component { } property = tempProperty; } - /* if (property['$ref'] && !property['$ref'].startsWith("#")) { - const $propDefinition = await $RefParser.resolve(property['$ref']); - const propDefinitions = $propDefinition.get("#/definitions"); - for (const propDefinition in propDefinitions) { - schema.definitions[propDefinition] = propDefinitions[propDefinition]; - property['$ref'] = "#/definitions/"+ propDefinition ; - } - } */ property.title = param.name; property.default = $taskRefs.get(param.refs[0].replace(`#/tasks/${taskName}`, '#')); paramsOutput[`param_${index}`] = property.default; @@ -183,11 +184,24 @@ export class SchedulingUnitCreate extends Component { validForm: this.validateForm()}); } + setEditorOutputConstraint(jsonOutput, errors) { + let err = [ ...errors ]; + if (jsonOutput.scheduler === 'online') { + err = err.filter(e => e.path !== 'root.time.at'); + } + this.constraintParamsOutput = jsonOutput; + // condition goes here.. + this.constraintValidEditor = err.length === 0; + this.setState({ constraintParamsOutput: jsonOutput, + constraintValidEditor: err.length === 0, + validForm: this.validateForm()}); + } + /** * This function is mainly added for Unit Tests. If this function is removed Unit Tests will fail. */ validateEditor() { - return this.validEditor?true:false; + return this.validEditor && this.constraintValidEditor ? true : false; } /** @@ -255,17 +269,49 @@ export class SchedulingUnitCreate extends Component { return validForm; } + degreeToRadians(object) { + for(let type in object) { + if (typeof object[type] === 'object') { + this.degreeToRadians(object[type]); + } else { + object[type] = object[type] * (Math.PI/180); + } + } + } + /** * Function to create Scheduling unit */ async saveSchedulingUnit() { + const constStrategy = _.cloneDeep(this.state.constraintParamsOutput); + if (constStrategy.scheduler === 'online') { + // For deleting property + delete constStrategy.time; + } + for (let type in constStrategy.time) { + if (constStrategy.time[type] && constStrategy.time[type].length) { + if (typeof constStrategy.time[type] === 'string') { + constStrategy.time[type] = `${moment(constStrategy.time[type]).format("YYYY-MM-DDTh:mm:ss.SSSSS")}Z`; + } else { + constStrategy.time[type].map(time => { + for (let key in time) { + time[key] = `${moment(time[key] ).format("YYYY-MM-DDTh:mm:ss.SSSSS")}Z`; + } + }) + } + } + } + for (let type in constStrategy.sky.transit_offset) { + constStrategy.sky.transit_offset[type] = constStrategy.sky.transit_offset[type] * 60; + } + this.degreeToRadians(constStrategy.sky); let observStrategy = _.cloneDeep(this.state.observStrategy); const $refs = await $RefParser.resolve(observStrategy.template); observStrategy.template.parameters.forEach(async(param, index) => { $refs.set(observStrategy.template.parameters[index]['refs'][0], this.state.paramsOutput['param_' + index]); }); - - const schedulingUnit = await ScheduleService.saveSUDraftFromObservStrategy(observStrategy, this.state.schedulingUnit); + const const_strategy = {scheduling_constraints_doc: constStrategy, id: this.constraintTemplates[0].id, constraint: this.constraintTemplates[0]}; + const schedulingUnit = await ScheduleService.saveSUDraftFromObservStrategy(observStrategy, this.state.schedulingUnit, const_strategy); if (schedulingUnit) { // this.growl.show({severity: 'success', summary: 'Success', detail: 'Scheduling Unit and tasks created successfully!'}); const dialog = {header: 'Success', detail: 'Scheduling Unit and Tasks are created successfully. Do you want to create another Scheduling Unit?'}; @@ -282,6 +328,12 @@ export class SchedulingUnitCreate extends Component { this.props.history.goBack(); } + constraintStrategy(e){ + let schedulingUnit = { ...this.state.schedulingUnit }; + schedulingUnit.scheduling_constraints_template_id = e.id; + this.setState({ constraintSchema: this.constraintTemplates[0], schedulingUnit}); + } + /** * Reset function to be called when user wants to create new SU */ @@ -396,7 +448,18 @@ export class SchedulingUnitCreate extends Component { onChange={(e) => {this.changeStrategy(e.value)}} placeholder="Select Strategy" /> </div> - <div className="col-lg-1 col-md-1 col-sm-12"></div> + <div className="col-lg-1 col-md-1 col-sm-12"></div> + <label htmlFor="schedulingConstraintsTemp" className="col-lg-2 col-md-2 col-sm-12 hide">Scheduling Constraints Template</label> + <div className="col-lg-3 col-md-3 col-sm-12 hide" data-testid="schedulingConstraintsTemp"> + <Dropdown inputId="schedulingConstraintsTemp" optionLabel="name" optionValue="id" + tooltip="Scheduling Constraints Template to add scheduling constraints to a scheduling unit" tooltipOptions={this.tooltipOptions} + value={this.state.schedulingUnit.scheduling_constraints_template_id} + disabled + options={this.constraintTemplates} + //onChange={(e) => { this.constraintStrategy(e);}} + placeholder="Select Constraints Template"/> + + </div> </div> </div> @@ -407,11 +470,18 @@ export class SchedulingUnitCreate extends Component { </div> </div> </div> + {this.state.constraintSchema && <div className="p-fluid"> + <div className="p-grid"> + <div className="p-col-12"> + <SchedulingConstraint constraintTemplate={this.state.constraintSchema} callback={this.setEditorOutputConstraint} /> + </div> + </div> + </div>} <div className="p-grid p-justify-start"> <div className="p-col-1"> <Button label="Save" className="p-button-primary" icon="pi pi-check" onClick={this.saveSchedulingUnit} - disabled={!this.state.validEditor || !this.state.validForm} data-testid="save-btn" /> + disabled={!this.state.constraintValidEditor || !this.state.validEditor || !this.state.validForm} data-testid="save-btn" /> </div> <div className="p-col-1"> <Button label="Cancel" className="p-button-danger" icon="pi pi-times" onClick={this.cancelCreate} /> diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/edit.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/edit.js index 23c61c0f6fb0d6893913e3275699ea54224b2acb..65c9c021de1f62460cb8fa8c9e95f2b24472cd03 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/edit.js +++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/edit.js @@ -1,5 +1,6 @@ import React, {Component} from 'react'; import { Redirect } from 'react-router-dom'; +import moment from 'moment'; import _ from 'lodash'; import $RefParser from "@apidevtools/json-schema-ref-parser"; @@ -9,7 +10,6 @@ import {Dropdown} from 'primereact/dropdown'; import { Button } from 'primereact/button'; import {Growl} from 'primereact/components/growl/Growl'; - import AppLoader from '../../layout/components/AppLoader'; import PageHeader from '../../layout/components/PageHeader'; import Jeditor from '../../components/JSONEditor/JEditor'; @@ -18,6 +18,7 @@ import ProjectService from '../../services/project.service'; import ScheduleService from '../../services/schedule.service'; import TaskService from '../../services/task.service'; import UIConstants from '../../utils/ui.constants'; +import SchedulingConstraint from './Scheduling.Constraints'; /** * Compoenent to edit scheduling unit draft @@ -31,19 +32,20 @@ export class EditSchedulingUnit extends Component { redirect: null, errors: [], schedulingSets: [], - schedulingUnit: { - }, + schedulingUnit: {}, projectDisabled: (props.match?(props.match.params.project? true:false):false), - observStrategy: {}, - paramsSchema: null, + observStrategy: {}, + paramsSchema: null, + constraintSchema:null, validEditor: false, validFields: {}, observStrategyVisible: false } - this.projects = []; + this.projects = []; this.schedulingSets = []; - this.observStrategies = []; + this.observStrategies = []; this.taskTemplates = []; + this.constraintTemplates = []; this.tooltipOptions = UIConstants.tooltipOptions; this.nameInput = React.createRef(); this.formRules = { @@ -53,17 +55,17 @@ export class EditSchedulingUnit extends Component { this.setEditorOutput = this.setEditorOutput.bind(this); this.changeStrategy = this.changeStrategy.bind(this); + this.constraintStrategy = this.constraintStrategy.bind(this); this.setSchedUnitParams = this.setSchedUnitParams.bind(this); this.validateForm = this.validateForm.bind(this); this.validateEditor = this.validateEditor.bind(this); this.setEditorFunction = this.setEditorFunction.bind(this); this.saveSchedulingUnit = this.saveSchedulingUnit.bind(this); this.cancelCreate = this.cancelCreate.bind(this); + this.setEditorOutputConstraint = this.setEditorOutputConstraint.bind(this); } - - /** * 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 @@ -136,13 +138,15 @@ export class EditSchedulingUnit extends Component { ScheduleService.getObservationStrategies(), TaskService.getTaskTemplates(), ScheduleService.getSchedulingUnitDraftById(this.props.match.params.id), - ScheduleService.getTasksDraftBySchedulingUnitId(this.props.match.params.id) + ScheduleService.getTasksDraftBySchedulingUnitId(this.props.match.params.id), + ScheduleService.getSchedulingConstraints() ]; Promise.all(promises).then(responses => { this.projects = responses[0]; this.schedulingSets = responses[1]; this.observStrategies = responses[2]; this.taskTemplates = responses[3]; + this.constraintTemplates = responses[6]; responses[4].project = this.schedulingSets.find(i => i.id === responses[4].scheduling_set_id).project_id; this.setState({ schedulingUnit: responses[4], taskDrafts: responses[5].data.results, observStrategyVisible: responses[4].observation_strategy_template_id?true:false }); @@ -155,6 +159,7 @@ export class EditSchedulingUnit extends Component { } else { this.setState({isLoading: false}); } + this.constraintStrategy(this.constraintTemplates[0], this.state.schedulingUnit.scheduling_constraints_doc) }); } @@ -172,6 +177,18 @@ export class EditSchedulingUnit extends Component { validForm: this.validateForm()}); } + setEditorOutputConstraint(jsonOutput, errors) { + let err = [ ...errors ]; + if (jsonOutput.scheduler === 'online') { + err = err.filter(e => e.path !== 'root.time.at'); + } + this.constraintParamsOutput = jsonOutput || {}; + this.constraintValidEditor = err.length === 0; + this.setState({ constraintParamsOutput: jsonOutput, + constraintValidEditor: err.length === 0, + validForm: this.validateForm()}); + } + /** * This function is mainly added for Unit Tests. If this function is removed Unit Tests will fail. */ @@ -244,17 +261,51 @@ export class EditSchedulingUnit extends Component { return validForm; } + degreeToRadians(object) { + for(let type in object) { + if (typeof object[type] === 'object') { + this.degreeToRadians(object[type]); + } else { + object[type] = object[type] * (Math.PI/180); + } + } + } + /** * Function to create Scheduling unit */ async saveSchedulingUnit() { if (this.state.schedulingUnit.observation_strategy_template_id) { + const constStrategy = _.cloneDeep(this.state.constraintParamsOutput); + if (constStrategy.scheduler === 'online') { + // For deleting property + delete constStrategy.time; + } + for (let type in constStrategy.time) { + if (constStrategy.time[type] && constStrategy.time[type].length) { + if (typeof constStrategy.time[type] === 'string') { + constStrategy.time[type] = `${moment(constStrategy.time[type]).format("YYYY-MM-DDTh:mm:ss.SSSSS")}Z`; + } else { + constStrategy.time[type].map(time => { + for (let key in time) { + time[key] = `${moment(time[key] ).format("YYYY-MM-DDTh:mm:ss.SSSSS")}Z`; + } + }) + } + } + } + for (let type in constStrategy.sky.transit_offset) { + constStrategy.sky.transit_offset[type] = constStrategy.sky.transit_offset[type] * 60; + } + this.degreeToRadians(constStrategy.sky); let observStrategy = _.cloneDeep(this.state.observStrategy); const $refs = await $RefParser.resolve(observStrategy.template); observStrategy.template.parameters.forEach(async(param, index) => { $refs.set(observStrategy.template.parameters[index]['refs'][0], this.state.paramsOutput['param_' + index]); }); - const schedulingUnit = await ScheduleService.updateSUDraftFromObservStrategy(observStrategy, this.state.schedulingUnit, this.state.taskDrafts, this.state.tasksToUpdate); + const schUnit = { ...this.state.schedulingUnit }; + schUnit.scheduling_constraints_doc = constStrategy; + const schedulingUnit = await ScheduleService.updateSUDraftFromObservStrategy(observStrategy,schUnit,this.state.taskDrafts, this.state.tasksToUpdate); if (schedulingUnit) { // this.growl.show({severity: 'success', summary: 'Success', detail: 'Scheduling Unit and tasks edited successfully!'}); this.props.history.push({ @@ -275,23 +326,27 @@ export class EditSchedulingUnit extends Component { this.props.history.goBack(); } + constraintStrategy(schema, initValue){ + this.setState({ constraintSchema: schema, initValue: initValue}); + } + render() { if (this.state.redirect) { return <Redirect to={ {pathname: this.state.redirect} }></Redirect> } const schema = this.state.paramsSchema; - let jeditor = null; if (schema) { - jeditor = React.createElement(Jeditor, {title: "Task Parameters", + jeditor = React.createElement(Jeditor, {title: "Task Parameters", schema: schema, initValue: this.state.paramsOutput, callback: this.setEditorOutput, parentFunction: this.setEditorFunction }); } - return ( + + return ( <React.Fragment> <Growl ref={el => (this.growl = el)} /> <PageHeader location={this.props.location} title={'Scheduling Unit - Edit'} @@ -356,14 +411,24 @@ export class EditSchedulingUnit extends Component { value={this.state.schedulingUnit.observation_strategy_template_id} disabled={this.state.schedulingUnit.observation_strategy_template_id?true:false} options={this.observStrategies} - onChange={(e) => {this.changeStrategy(e.value)}} + onChange={(e) => {this.changeStrategy(e)}} placeholder="Select Strategy" /> </div> </> } <div className="col-lg-1 col-md-1 col-sm-12"></div> + <label htmlFor="schedulingConstraintsTemp" className="col-lg-2 col-md-2 col-sm-12 hide">Scheduling Constraints Template</label> + <div className="col-lg-3 col-md-3 col-sm-12 hide" data-testid="schedulingConstraintsTemp"> + <Dropdown inputId="schedulingConstraintsTemp" optionLabel="name" optionValue="id" + tooltip="Scheduling Constraints Template to add scheduling constraints to a scheduling unit" tooltipOptions={this.tooltipOptions} + value={this.state.schedulingUnit.scheduling_constraints_template_id} + disabled + options={this.constraintTemplates} + //onChange={(e) => { this.constraintStrategy(e);}} + placeholder="Select Constraints Template"/> + + </div> </div> - </div> <div className="p-fluid"> <div className="p-grid"> @@ -372,6 +437,13 @@ export class EditSchedulingUnit extends Component { </div> </div> </div> + {this.state.constraintSchema && <div className="p-fluid"> + <div className="p-grid"> + <div className="p-col-12"> + <SchedulingConstraint initValue={this.state.initValue} constraintTemplate={this.state.constraintSchema} callback={this.setEditorOutputConstraint} /> + </div> + </div> + </div>} <div className="p-grid p-justify-start"> <div className="p-col-1"> @@ -391,5 +463,4 @@ export class EditSchedulingUnit extends Component { ); } } - -export default EditSchedulingUnit; \ No newline at end of file +export default EditSchedulingUnit 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 30a2c0db09bf506a44b47f156ba4f8b26ec2c3f6..6a961d6c8028272d486b5418a064b7ad4dea6add 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/services/schedule.service.js +++ b/SAS/TMSS/frontend/tmss_webapp/src/services/schedule.service.js @@ -191,7 +191,16 @@ const ScheduleService = { return []; }; }, - saveSUDraftFromObservStrategy: async function(observStrategy, schedulingUnit) { + getSchedulingConstraints: async function(){ + try { + const response = await axios.get('/api/scheduling_constraints_template/'); + return response.data.results; + } catch(error) { + console.error(error); + return []; + }; + }, + saveSUDraftFromObservStrategy: async function(observStrategy, schedulingUnit, constraint) { 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}` @@ -200,6 +209,9 @@ const ScheduleService = { if (schedulingUnit && schedulingUnit.id) { // Update the newly created SU draft requirement_doc with captured parameter values schedulingUnit.requirements_doc = observStrategy.template; + schedulingUnit.scheduling_constraints_doc = constraint.scheduling_constraints_doc; + schedulingUnit.scheduling_constraints_template_id = constraint.id; + schedulingUnit.scheduling_constraints_template = constraint.constraint.url; delete schedulingUnit['duration']; schedulingUnit = await this.updateSchedulingUnitDraft(schedulingUnit); if (!schedulingUnit || !schedulingUnit.id) { @@ -218,7 +230,7 @@ const ScheduleService = { }; }, - updateSUDraftFromObservStrategy: async function(observStrategy, schedulingUnit,tasks,tasksToUpdate) { + updateSUDraftFromObservStrategy: async function(observStrategy,schedulingUnit,tasks,tasksToUpdate) { try { delete schedulingUnit['duration']; schedulingUnit = await this.updateSchedulingUnitDraft(schedulingUnit); @@ -303,4 +315,4 @@ const ScheduleService = { } -export default ScheduleService; +export default ScheduleService; \ No newline at end of file