diff --git a/SAS/TMSS/frontend/frontend_poc/src/App.css b/SAS/TMSS/frontend/frontend_poc/src/App.css index afc3885715f4a69457fdfccdb9aa4220c30ec1f5..9ecb272f6298180d506a00ba79ddc587e154b9fe 100644 --- a/SAS/TMSS/frontend/frontend_poc/src/App.css +++ b/SAS/TMSS/frontend/frontend_poc/src/App.css @@ -20,3 +20,8 @@ .App-link { color: #09d3ac; } + +.jsonform { + border-left: 3px solid #007bff; + padding-left: 10pt; +} \ No newline at end of file diff --git a/SAS/TMSS/frontend/frontend_poc/src/UC1.js b/SAS/TMSS/frontend/frontend_poc/src/UC1.js index 9e5e6be3b6241a366026db91d3cf114d26370d2c..8d0130e0e390647d0cdd2c1531d6ab2d5fe9154d 100644 --- a/SAS/TMSS/frontend/frontend_poc/src/UC1.js +++ b/SAS/TMSS/frontend/frontend_poc/src/UC1.js @@ -13,235 +13,235 @@ import Form from 'react-jsonschema-form-bs4'; // todo: use main line "react-json const additionalMetaSchemas = require("ajv/lib/refs/json-schema-draft-06.json"); // todo: read from referenced template -const schema = { - "$id": "http://example.com/example.json", - "type": "object", - "$schema": "http://json-schema.org/draft-06/schema#", - "definitions": { - "pointing": { - "type": "object", - "additionalProperties": false, - "properties": { - "direction_type": { - "type": "string", - "title": "Reference frame", - "description": "", - "default": "J2000", - "enum": [ - "J2000", - "SUN", - "MOON", - "MERCURY", - "VENUS", - "MARS", - "JUPITER", - "SATURN", - "URANUS", - "NEPTUNE", - "PLUTO" - ] - }, - "angle1": { - "type": "number", - "title": "Angle 1", - "description": "First angle (f.e. RA)", - "default": 0 - }, - "angle2": { - "type": "number", - "title": "Angle 2", - "description": "Second angle (f.e. DEC)", - "default": 0 - } - } - } - }, - "additionalProperties": false, - "properties": { - "stations": { - "title": "Station list", - "oneOf": [ - { - "type": "array", - "title": "Fixed list", - "additionalItems": false, - "additionalProperties": false, - "items": { - "type": "string", - "enum": [ - "CS001", - "CS002", - "CS003", - "CS004", - "CS005", - "CS006", - "CS007", - "CS011", - "CS013", - "CS017", - "CS021", - "CS024", - "CS026", - "CS028", - "CS030", - "CS031", - "CS032", - "CS101", - "CS103", - "CS201", - "CS301", - "CS302", - "CS401", - "CS501", - "RS104", - "RS106", - "RS205", - "RS208", - "RS210", - "RS305", - "RS306", - "RS307", - "RS310", - "RS406", - "RS407", - "RS409", - "RS410", - "RS503", - "RS508", - "RS509", - "DE601", - "DE602", - "DE603", - "DE604", - "DE605", - "FR606", - "SE607", - "UK608", - "DE609", - "PL610", - "PL611", - "PL612", - "IE613", - "LV614" - ], - "title": "Station", - "description": "" - }, - "minItems": 1, - "uniqueItems": true - }, - { - "title": "Dynamic list", - "type": "array", - "additionalItems": false, - "items": { - "type": "object", - "title": "Station set", - "headerTemplate": "{{ self.group }}", - "additionalProperties": false, - "properties": { - "group": { - "type": "string", - "title": "Group/station", - "description": "Which (group of) station(s) to select from", - "default": "ALL", - "enum": [ - "ALL", - "SUPERTERP", - "CORE", - "REMOTE", - "DUTCH", - "INTERNATIONAL" - ] - }, - "min_stations": { - "type": "integer", - "title": "Minimum nr of stations", - "description": "Number of stations to use within group/station", - "default": 1, - "minimum": 0 - } - } - } - } - ] - }, - "antenna_set": { - "type": "string", - "title": "Antenna set", - "description": "Fields & antennas to use", - "default": "HBA_DUAL", - "enum": [ - "HBA_DUAL", - "HBA_DUAL_INNER", - "HBA_JOINED", - "HBA_JOINED_INNER", - "HBA_ONE", - "HBA_ONE_INNER", - "HBA_ZERO", - "HBA_ZERO_INNER", - "LBA_INNER", - "LBA_OUTER", - "LBA_SPARSE_EVEN", - "LBA_SPARSE_ODD", - "LBA_ALL" - ] - }, - "filter": { - "type": "string", - "title": "Band-pass filter", - "description": "Must match antenna type", - "default": "HBA_110_190", - "enum": [ - "LBA_10_70", - "LBA_30_70", - "LBA_10_90", - "LBA_30_90", - "HBA_110_190", - "HBA_210_250" - ] - }, - "analog_pointing": { - "title": "Analog pointing", - "description": "HBA only", - "$ref": "#/definitions/pointing" - }, - "beams": { - "type": "array", - "title": "Beams", - "additionalItems": false, - "items": { - "title": "Beam", - "headerTemplate": "{{ i0 }} - {{ self.name }}", - "type": "object", - "additionalProperties": false, - "properties": { - "name": { - "type": "string", - "title": "Name/target", - "description": "Identifier for this beam", - "default": "" - }, - "digital_pointing": { - "title": "Digital pointing", - "$ref": "#/definitions/pointing" - }, - "subbands": { - "type": "array", - "title": "Subband list", - "additionalItems": false, - "items": { - "type": "integer", - "title": "Subband", - "minimum": 0, - "maximum": 511 - } - } - } - } - } - } -}; +//const schema = { +// "$id": "http://example.com/example.json", +// "type": "object", +// "$schema": "http://json-schema.org/draft-06/schema#", +// "definitions": { +// "pointing": { +// "type": "object", +// "additionalProperties": false, +// "properties": { +// "direction_type": { +// "type": "string", +// "title": "Reference frame", +// "description": "", +// "default": "J2000", +// "enum": [ +// "J2000", +// "SUN", +// "MOON", +// "MERCURY", +// "VENUS", +// "MARS", +// "JUPITER", +// "SATURN", +// "URANUS", +// "NEPTUNE", +// "PLUTO" +// ] +// }, +// "angle1": { +// "type": "number", +// "title": "Angle 1", +// "description": "First angle (f.e. RA)", +// "default": 0 +// }, +// "angle2": { +// "type": "number", +// "title": "Angle 2", +// "description": "Second angle (f.e. DEC)", +// "default": 0 +// } +// } +// } +// }, +// "additionalProperties": false, +// "properties": { +// "stations": { +// "title": "Station list", +// "oneOf": [ +// { +// "type": "array", +// "title": "Fixed list", +// "additionalItems": false, +// "additionalProperties": false, +// "items": { +// "type": "string", +// "enum": [ +// "CS001", +// "CS002", +// "CS003", +// "CS004", +// "CS005", +// "CS006", +// "CS007", +// "CS011", +// "CS013", +// "CS017", +// "CS021", +// "CS024", +// "CS026", +// "CS028", +// "CS030", +// "CS031", +// "CS032", +// "CS101", +// "CS103", +// "CS201", +// "CS301", +// "CS302", +// "CS401", +// "CS501", +// "RS104", +// "RS106", +// "RS205", +// "RS208", +// "RS210", +// "RS305", +// "RS306", +// "RS307", +// "RS310", +// "RS406", +// "RS407", +// "RS409", +// "RS410", +// "RS503", +// "RS508", +// "RS509", +// "DE601", +// "DE602", +// "DE603", +// "DE604", +// "DE605", +// "FR606", +// "SE607", +// "UK608", +// "DE609", +// "PL610", +// "PL611", +// "PL612", +// "IE613", +// "LV614" +// ], +// "title": "Station", +// "description": "" +// }, +// "minItems": 1, +// "uniqueItems": true +// }, +// { +// "title": "Dynamic list", +// "type": "array", +// "additionalItems": false, +// "items": { +// "type": "object", +// "title": "Station set", +// "headerTemplate": "{{ self.group }}", +// "additionalProperties": false, +// "properties": { +// "group": { +// "type": "string", +// "title": "Group/station", +// "description": "Which (group of) station(s) to select from", +// "default": "ALL", +// "enum": [ +// "ALL", +// "SUPERTERP", +// "CORE", +// "REMOTE", +// "DUTCH", +// "INTERNATIONAL" +// ] +// }, +// "min_stations": { +// "type": "integer", +// "title": "Minimum nr of stations", +// "description": "Number of stations to use within group/station", +// "default": 1, +// "minimum": 0 +// } +// } +// } +// } +// ] +// }, +// "antenna_set": { +// "type": "string", +// "title": "Antenna set", +// "description": "Fields & antennas to use", +// "default": "HBA_DUAL", +// "enum": [ +// "HBA_DUAL", +// "HBA_DUAL_INNER", +// "HBA_JOINED", +// "HBA_JOINED_INNER", +// "HBA_ONE", +// "HBA_ONE_INNER", +// "HBA_ZERO", +// "HBA_ZERO_INNER", +// "LBA_INNER", +// "LBA_OUTER", +// "LBA_SPARSE_EVEN", +// "LBA_SPARSE_ODD", +// "LBA_ALL" +// ] +// }, +// "filter": { +// "type": "string", +// "title": "Band-pass filter", +// "description": "Must match antenna type", +// "default": "HBA_110_190", +// "enum": [ +// "LBA_10_70", +// "LBA_30_70", +// "LBA_10_90", +// "LBA_30_90", +// "HBA_110_190", +// "HBA_210_250" +// ] +// }, +// "analog_pointing": { +// "title": "Analog pointing", +// "description": "HBA only", +// "$ref": "#/definitions/pointing" +// }, +// "beams": { +// "type": "array", +// "title": "Beams", +// "additionalItems": false, +// "items": { +// "title": "Beam", +// "headerTemplate": "{{ i0 }} - {{ self.name }}", +// "type": "object", +// "additionalProperties": false, +// "properties": { +// "name": { +// "type": "string", +// "title": "Name/target", +// "description": "Identifier for this beam", +// "default": "" +// }, +// "digital_pointing": { +// "title": "Digital pointing", +// "$ref": "#/definitions/pointing" +// }, +// "subbands": { +// "type": "array", +// "title": "Subband list", +// "additionalItems": false, +// "items": { +// "type": "integer", +// "title": "Subband", +// "minimum": 0, +// "maximum": 511 +// } +// } +// } +// } +// } +// } +//}; // Procedures // todo: revise and put these somewhere so they can be shared by entire frontend @@ -256,8 +256,7 @@ var api_url = 'http://localhost:8008/api/'; // todo: this is just a fixture for development. Handle schemas in individual states of task drafts. -//fetch(api_url + "task_template/1/", {headers: headers}) -// .then(response => {const schema = response.json()}) + function tmssGetList(url, component){ @@ -271,7 +270,7 @@ function tmssGetList(url, component){ // React cannot handle deep states, so we have to stringify nested objects before setState() response.results.forEach(result => {result.specifications_doc = JSON.stringify(result.specifications_doc);}); component.setState({items:response.results});}) - .catch(err => console.log(err)) + .catch(err => alert(err)) } function tmssGet(url, component){ @@ -283,13 +282,26 @@ function tmssGet(url, component){ .then(response => response.json()) .then(response => {console.log(response); component.setState(response); - // todo: update the schema based on template reference, something like: - // fetch(response.specifications_template, {headers: headers}) - // .then(response => component.setState(schema: response.json()) + component.updateSchema(); }) - .catch(err => console.log(err)) + .catch(err => alert(err)) } +function tmssGetReferenceList(url, state_name, component){ + console.log('Getting references '+ url); + if(!url.startsWith('http')){ + url = api_url+url; + } + fetch(url, {headers: headers}) + .then(response => {return response.json();}) + .then(response => { + var references = response.results.map((reference) => {return reference.url}); + console.log(references); + component.setState({ + [state_name]: references + }); + })} + function tmssPost(url, data, component){ console.log('Posting '+ url); if(!url.startsWith('http')){ @@ -297,7 +309,7 @@ function tmssPost(url, data, component){ } fetch(url, {headers: headers, method: 'POST', body: data}) .then(ReactDOM.render(<TaskDraftList />, document.getElementById('root'))) - .catch(err => console.log(err)) + .catch(err => alert(err)) } function tmssPut(url, data, component){ @@ -308,7 +320,7 @@ function tmssPut(url, data, component){ console.log(data); fetch(url, {headers: headers, method: 'PUT', body: data}) .then(ReactDOM.render(<TaskDraftList />, document.getElementById('root'))) - .catch(err => console.log(err)) + .catch(err => alert(err)) } function tmssPatch(url, data, component){ @@ -319,7 +331,7 @@ function tmssPatch(url, data, component){ console.log(data); fetch(url, {headers: headers, method: 'PATCH', body: data}) .then(ReactDOM.render(<TaskDraftList />, document.getElementById('root'))) - .catch(err => console.log(err)) + .catch(err => alert(err)) } function tmssDelete(url){ @@ -328,7 +340,7 @@ function tmssDelete(url){ url = api_url+url; } fetch(url, {headers: headers, method: 'DELETE'}) - .catch(err => console.log(err)) + .catch(err => alert(err)) } @@ -375,10 +387,14 @@ class EditTaskDraft extends Component { this.onChangeSchedulingUnitDraft = this.onChangeSchedulingUnitDraft.bind(this); this.onChangeSpecificationsTemplate = this.onChangeSpecificationsTemplate.bind(this); this.onSubmit = this.onSubmit.bind(this); + this.updateSchema = this.updateSchema.bind(this); this.state = { isnew: props.isnew, id: props.id, + schema: {}, + templates: [], + drafts: [], // default values for new item (state gets overwritten by componentDidMount for non-new): name: "my_name", tags: ["test"], @@ -425,8 +441,34 @@ class EditTaskDraft extends Component { componentDidMount() { if(!this.state.isnew){ + // update state with db info of the represented entity tmssGet(this.state.id, this); } + //update list entities for UI elements + tmssGetReferenceList('task_template/', 'templates', this) + tmssGetReferenceList('scheduling_unit_draft/', 'drafts', this) + + +// fetch(api_url + "task_template/", {headers: headers}) +// .then(response => {return response.json();}) +// .then(response => { +// new_templates = response.results.map((template) => {return template.url}); +// console.log(new_templates); +// this.setState({ +// templates: new_templates +// }); +// }) + } + + updateSchema(){ + console.log('updateSchema') + fetch(this.state.specifications_template, {headers: headers}) + .then(response => response.json()) + .then(response => { + this.setState({ + schema: response.schema + }); + }) } onChangeName(e) { @@ -470,6 +512,7 @@ class EditTaskDraft extends Component { this.setState({ specifications_template: e.target.value }); + this.updateSchema(); } onSubmit(e) { @@ -497,13 +540,6 @@ class EditTaskDraft extends Component { } } - updateSpec(formData) { - console.log('updateSpec'); - console.log(formData); - // do not use setState to prevent infinite loop - this.state.specifications_doc = formData; - } - render() { return ( <div> @@ -545,25 +581,28 @@ class EditTaskDraft extends Component { </div> <div className="form-group"> <label>SchedulingUnitDraft: </label> - <input - type="text" + <select className="form-control" value={this.state.scheduling_unit_draft} onChange={this.onChangeSchedulingUnitDraft} - /> + > + {this.state.drafts.map((opt) => {return <option key={opt} value={opt}>{opt}</option>;})} + </select> </div> <div className="form-group"> <label>SpecificationsTemplate: </label> - <input - type="text" + <select className="form-control" value={this.state.specifications_template} onChange={this.onChangeSpecificationsTemplate} - /> + > + {this.state.templates.map((opt) => {return <option key={opt} value={opt}>{opt}</option>;})} + </select> </div> <div className="form-group"> <label>SpecificationsDoc: </label> - <Form schema={schema} + <Form className="jsonform" + schema={this.state.schema} additionalMetaSchemas={[additionalMetaSchemas]} liveValidate={true} show_opt_in={true}