diff --git a/SAS/TMSS/frontend/tmss_webapp/src/App.css b/SAS/TMSS/frontend/tmss_webapp/src/App.css index 0fd3de74678b7f14f3aadbe2bb0b246362a66830..04acfc474c1fa3506e186746f08e0a62199407ef 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/App.css +++ b/SAS/TMSS/frontend/tmss_webapp/src/App.css @@ -63,6 +63,16 @@ p { list-style: none; } +.col-filter-btn { + margin-left: 15px; + padding-top: 5px; + cursor: pointer; +} + +#editor_holder label { + text-transform: capitalize; +} + @keyframes App-logo-spin { from { transform: rotate(0deg); 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 106e5c7f23a34a53d5f8c69abc04819883d108fd..dbba73d6364eb934f67e623ddca26b392f8f658b 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/components/JSONEditor/JEditor.js +++ b/SAS/TMSS/frontend/tmss_webapp/src/components/JSONEditor/JEditor.js @@ -4,12 +4,13 @@ */ import React, {useEffect, useRef} from 'react'; import _ from 'lodash'; +import flatpickr from 'flatpickr'; // Sample JSON schema. The same can be received from an API call // import SchemaDB from './task.observation.schema'; - import "@fortawesome/fontawesome-free/css/all.css"; -// import '../../styles/components/fa_all.scss'; +import "@fortawesome/fontawesome-free/css/all.css"; +import "flatpickr/dist/flatpickr.css"; const JSONEditor = require("@json-editor/json-editor").JSONEditor; function Jeditor(props) { @@ -33,6 +34,11 @@ function Jeditor(props) { let defProperty = getAngleProperty(defProperties[propName], propName === 'angle2'); defProperties[propName] = defProperty; } + if (defProperties[propName].options) { + defProperties[propName].options.grid_columns = 4; + } else { + defProperties[propName].options = {grid_columns: 4}; + } } } } @@ -41,21 +47,40 @@ function Jeditor(props) { getCustomProperties(schema.properties); schema.title = props.title; - const validator = validateSubbandOutput; + const subbandValidator = validateSubbandOutput; + const timeValidator = validateTime; + const angleValidator = validateAngle; JSONEditor.defaults.custom_validators.push((schema, value, path) => { const errors = []; - if (schema.customType === "subband_list") { - if (!validator(value)) { + if (schema.validationType === "subband_list") { + if (!subbandValidator(value)) { errors.push({ path: path, - property: 'customType', + property: 'validationType', message: 'Not a valid input for Subband List' }); } + } else if (schema.validationType === "time") { + if (!timeValidator(value)) { + errors.push({ + path: path, + property: 'validationType', + message: 'Not a valid input. Mimimum: 00:00:00, Maximum:23:59:59' + }); + } + } else if (schema.validationType === "angle") { + if (!angleValidator(value)) { + errors.push({ + path: path, + property: 'validationType', + message: 'Not a valid input. Mimimum: 00:00:00, Maximum:90:00:00' + }); + } } return errors; }); - + schema.format = "grid" + console.log(schema); const editorOptions = { form_name_root: "specification", schema: schema, @@ -110,12 +135,14 @@ function Jeditor(props) { } function getAngleProperty(defProperty, isDegree) { - let newProperty = { + /*let newProperty = { "type": "object", "additionalProperties": false, "format": "grid", - "title": defProperty.title, - "description": defProperty.description}; + // "title": defProperty.title, + // "description": defProperty.description}; + "title": "Duration", + "description": "Duration of the observation"}; let subProperties = {}; if (isDegree) { subProperties["dd"] = { "type": "number", @@ -147,7 +174,25 @@ function Jeditor(props) { "maximum": 59 }; newProperty.properties = subProperties; - newProperty.required = isDegree?["dd", "mm", "ss"]:["hh", "mm", "ss"]; + newProperty.required = isDegree?["dd", "mm", "ss"]:["hh", "mm", "ss"];*/ + let newProperty = { + type: "string", + title: defProperty.title, + description: (defProperty.description + (isDegree?'(Degrees:Minutes:Seconds)':'(Hours:Minutes:Seconds)')), + default: "00:00:00", + validationType: isDegree?'angle':'time', + "options": { + // "grid_columns": 4, + "inputAttributes": { + "placeholder": isDegree?"DD:mm:ss":"HH:mm:ss" + }, + "cleave": { + date: true, + datePattern: ['HH','mm','ss'], + delimiter: ':' + } + } + } return newProperty; } @@ -161,12 +206,84 @@ function Jeditor(props) { newProperty.type = 'string'; newProperty.default = ''; newProperty.description = "For Range enter Start and End seperated by 2 dots. Mulitple ranges can be separated by comma. Minimum should be 0 and maximum should be 511. For exmaple 11..20, 30..50"; - newProperty.customType = 'subband_list'; + newProperty.validationType = 'subband_list'; + // newProperty.options = { + // grid_columns: 4 + // }; properties[propertyKey] = newProperty; } else if (propertyKey.toLowerCase() === 'duration') { propertyValue.title = "Duration (minutes)"; - propertyValue.default = 1; + propertyValue.default = "1"; + propertyValue.description = "Duration of this observation. Enter in decimal for seconds. For example 0.5 for 30 seconds"; + propertyValue.minimum = 0.25; + propertyValue.options = { + grid_columns: 6 + }; + /*propertyValue.title = "Duration"; + propertyValue.default = "1H20M30S"; + propertyValue.type = "string"; + propertyValue.description = "Duration of the observation (H-hours,M-minutes,S-seconds & should be in the order of H, M and S respectively)"; + /*let newProperty = { + type: "string", + title: "Duration", + description: `${propertyValue.description} (Hours:Minutes:Seconds)`, + default: "00:00:00", + "options": { + "grid_columns": 5, + "inputAttributes": { + "placeholder": "HH:mm:ss" + }, + "cleave": { + date: true, + datePattern: ['HH','mm','ss'], + delimiter: ':' + } + } + }*/ + /*let newProperty = { + "type": "string", + "format": "time", + "title": "Duration", + "description": `${propertyValue.description} (Hours:Minutes:Seconds)`, + "options": { + "grid_columns": 4, + "inputAttributes": { + "placeholder": "Enter time" + }, + "flatpickr": { + "wrap": true, + "showClearButton": false, + "inlineHideInput": true, + "defaultHour": 0, + "defaultMinute": 1, + "enableSeconds": true, + "defaultSecond": 0, + "hourIncrement": 1, + "minuteIncrement": 1, + "secondIncrement": 5, + "time_24hr": true, + "allowInput": true + } + } + };*/ + + // properties[propertyKey] = newProperty; } else if (propertyValue instanceof Object) { + if (propertyKey !== 'properties' && propertyKey !== 'default') { + propertyValue.format = "grid"; + } + if (propertyKey === 'average' || propertyKey === 'calibrator' || propertyKey === 'stations') { + propertyValue.propertyOrder = 1; + } else if (propertyKey === 'demix') { + propertyValue.propertyOrder = 2; + } else if (propertyKey === 'QA' || propertyKey === 'beams') { + propertyValue.propertyOrder = 10000; + } + if (propertyKey === 'storage_cluster') { + propertyValue.options = { + grid_columns: 6 + }; + } getCustomProperties(propertyValue); } } @@ -196,8 +313,8 @@ function Jeditor(props) { let outputValue = editorOutput[outputKey]; if (outputValue instanceof Object) { if (outputKey.endsWith('pointing')) { - outputValue.angle1 = getAngleOutput(outputValue.angle1); - outputValue.angle2 = getAngleOutput(outputValue.angle2); + outputValue.angle1 = getAngleOutput(outputValue.angle1, false); + outputValue.angle2 = getAngleOutput(outputValue.angle2, true); } else { updateOutput(outputValue); } @@ -216,20 +333,22 @@ function Jeditor(props) { const dd = Math.floor(prpInput * 180 / Math.PI); const mm = Math.floor((degrees-dd) * 60); const ss = +((degrees-dd-(mm/60)) * 3600).toFixed(0); - return { + /*return { dd: dd, mm: mm, ss: ss - } + }*/ + return (dd<10?`0${dd}`:`${dd}`) + ':' + (mm<10?`0${mm}`:`${mm}`) + ':' + (ss<10?`0${ss}`:`${ss}`); } else { const hh = Math.floor(degrees/15); const mm = Math.floor((degrees - (hh*15))/15 * 60 ); const ss = +((degrees -(hh*15)-(mm*15/60))/15 * 3600).toFixed(0); - return { + /*return { hh: hh, mm: mm, ss: ss - } + }*/ + return (hh<10?`0${hh}`:`${hh}`) + ':' + (mm<10?`0${mm}`:`${mm}`) + ':' + (ss<10?`0${ss}`:`${ss}`); } } @@ -255,12 +374,44 @@ function Jeditor(props) { return subbandString; } - function getAngleOutput(prpOutput) { - if ('dd' in prpOutput) { + function getAngleOutput(prpOutput, isDegree) { + /*if ('dd' in prpOutput) { return ((prpOutput.dd + prpOutput.mm/60 + prpOutput.ss/3600)*Math.PI/180); } else { return ((prpOutput.hh*15 + prpOutput.mm/4 + prpOutput.ss/240)*Math.PI/180); + }*/ + const splitOutput = prpOutput.split(':'); + if (isDegree) { + return ((splitOutput[0]*1 + splitOutput[1]/60 + splitOutput[2]/3600)*Math.PI/180); + } else { + return ((splitOutput[0]*15 + splitOutput[1]/4 + splitOutput[2]/240)*Math.PI/180); + } + } + + function validateTime(prpOutput) { + const splitOutput = prpOutput.split(':'); + if (splitOutput.length < 3) { + return false; + } else { + const timeValue = parseInt(splitOutput[0]*60*60) + parseInt(splitOutput[1]*60) + parseInt(splitOutput[2]); + if (timeValue >= 86400) { + return false; + } + } + return true; + } + + function validateAngle(prpOutput) { + const splitOutput = prpOutput.split(':'); + if (splitOutput.length < 3) { + return false; + } else { + const timeValue = parseInt(splitOutput[0]*60*60) + parseInt(splitOutput[1]*60) + parseInt(splitOutput[2]); + if (timeValue > 324000) { + return false; + } } + return true; } function validateSubbandOutput(prpOutput){ diff --git a/SAS/TMSS/frontend/tmss_webapp/src/index.js b/SAS/TMSS/frontend/tmss_webapp/src/index.js index 76fb92e2e220af22b7f1a3afe63e967fbae4a8bd..f759ca8db089c71894c87ea754d5b786cea47a54 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/index.js +++ b/SAS/TMSS/frontend/tmss_webapp/src/index.js @@ -3,6 +3,7 @@ import ReactDOM from 'react-dom'; import './index.css'; import App from './App'; import * as serviceWorker from './serviceWorker'; +import 'cleave.js/dist/cleave.js'; ReactDOM.render( // <React.StrictMode> diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Task/edit.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Task/edit.js index ca9ecd6b48f36e4879c177d3241637548956cf3d..48edd24f644a2cb789d5614e2ef02a47cafd6c57 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Task/edit.js +++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Task/edit.js @@ -128,10 +128,17 @@ export class TaskEdit extends Component { return ( <React.Fragment> - <div style={{marginBottom: "10px"}}> - <h2>Task - Edit</h2> + <div className="p-grid"> + <div className="p-col-2"> + <h2>Task - Edit</h2> + </div> + <div className="p-col-1"> + <Link to={{ pathname: '/task', state: {taskId: this.state.task?this.state.task.id:''}}} tooltip="Close Edit" > + <i className="pi pi-times" style={{marginTop: "10px"}}></i> + </Link> + </div> </div> - <div> + <div> <div className="p-fluid"> <div className="p-field p-grid"> <label htmlFor="taskName" className="p-col-2">Name</label> diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Task/view.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Task/view.js index d44828e1edaed7803433d54c11b986db984c069c..08355ef7b7d1e720448f2847a8f9ac3dffb83e8d 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Task/view.js +++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Task/view.js @@ -89,8 +89,8 @@ export class TaskView extends Component { <React.Fragment> {/* <div style={{marginBottom: "10px"}}> */} <div className="p-grid"> - <div className="p-col-2"> - <h2>Task - View </h2> + <div className="p-col-3"> + <h2>Task - Details </h2> </div> <div className="p-col-1"> <Link to={{ pathname: '/task/edit', state: {taskId: this.state.task?this.state.task.id:''}}} tooltip="Edit Task" >