From: ashishj1729 Date: Tue, 18 Oct 2022 09:30:16 +0000 (+0530) Subject: Create Form and Navbar Functionality X-Git-Tag: 1.0.0~11 X-Git-Url: https://gerrit.o-ran-sc.org/r/gitweb?a=commitdiff_plain;h=a3990295757f7842140ff3c0cc2454cb6c69f54c;p=portal%2Faiml-dashboard.git Create Form and Navbar Functionality Issue-Id: AIMLFW-2 Signed-off-by: ashishj1729 Change-Id: I80cfb6c814ca1331b5b426b04eb4ad71ea212dbe --- diff --git a/src/components/home/create/CreateTrainingJob.js b/src/components/home/create/CreateTrainingJob.js new file mode 100644 index 0000000..c77c319 --- /dev/null +++ b/src/components/home/create/CreateTrainingJob.js @@ -0,0 +1,88 @@ +// ================================================================================== + +// Copyright (c) 2022 Samsung Electronics Co., Ltd. All Rights Reserved. + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// ================================================================================== + +import React from 'react' +import Button from 'react-bootstrap/Button' +import OverlayTrigger from 'react-bootstrap/OverlayTrigger' +import Popover from 'react-bootstrap/Popover' +import CreateOrEditTrainingJobForm from '../form/CreateOrEditTrainingJobForm' + + +class CreateTrainingJob extends React.Component { + + popover = () =>( + + Field descriptions + + Training Job Name +

+ Name of the Training Job.

+ It must be between 3 and 63 characters long

+ It can only consist of lowercase Letters and numbers +

+ Pipeline Name +

+ Select an existing pipeline name corresponding to a ML model +

+ Experiment Name +

+ Select an existing experiment name +

+ Feature Names +

+ Select the Comma Separated KPI's from the training dataset +

+ Example --> * +

+ Example --> enb, cellNum, measTimeStampRf, pdcpBytesDl +

+ Feature Filter +

+ Filtering Clause for the Selected KPI's

+ Example --> enb > 10 +

+ Example --> cellNum => 10 and enb == 7 +

+ Hyper Parameters +

+ Comma separated, key-value pair of model tuning

+ Example --> epochs:100

+ Example --> epochs:150, optimizer:'adam' +

+ Description +

+ Description of Training-job +

+
+
+ ); + + render() { + return ( + <> + + + + + + + ); + } +} + +export default CreateTrainingJob; diff --git a/src/components/home/form/CreateOrEditTrainingJobForm.css b/src/components/home/form/CreateOrEditTrainingJobForm.css new file mode 100644 index 0000000..ede74b5 --- /dev/null +++ b/src/components/home/form/CreateOrEditTrainingJobForm.css @@ -0,0 +1,29 @@ + /* ================================================================================== + + Copyright (c) 2022 Samsung Electronics Co., Ltd. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + ================================================================================== */ +.create-form { + font-weight: bold; + width: 50%; + padding-right: 15px; + padding-left: 15px; + margin-right: auto; + margin-left: auto; + } + +.edit-form{ + font-weight: bold; +} \ No newline at end of file diff --git a/src/components/home/form/CreateOrEditTrainingJobForm.js b/src/components/home/form/CreateOrEditTrainingJobForm.js new file mode 100644 index 0000000..4aa6f52 --- /dev/null +++ b/src/components/home/form/CreateOrEditTrainingJobForm.js @@ -0,0 +1,734 @@ +// ================================================================================== + +// Copyright (c) 2022 Samsung Electronics Co., Ltd. All Rights Reserved. + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// ================================================================================== + +import React from 'react' +import Form from 'react-bootstrap/Form' +import Button from 'react-bootstrap/Button' +import axios from 'axios'; +import * as CONSTANTS from '../common/Constants' +import './CreateOrEditTrainingJobForm.css' +import {convertDatalakeDBName} from '../common/CommonMethods' + +class CreateTrainingJob extends React.Component { + constructor(props) { + super(props); + + this.state = { + ucName: '', + plName: '', + expName: '', + featureNames: '', + featureFilters: '', + hyparams: '', + versioning: false, + ucDescription: '', + plList: [], + expList: [], + UCMgr_baseUrl: CONSTANTS.UCMgr_baseUrl, + plVerList: [], + plVerName: '', + plVerDescription: '', + datalakeSourceList: ["Influx DB"], + datalakeSourceName: '', + _measurement: '', + bucket: '' + }; + + + + console.log('Initial UCM URL, ' , this.state.UCMgr_baseUrl) + console.log('All env', process.env) + console.log('ucm host port',process.env.REACT_APP_UCM_HOST ,process.env.REACT_APP_UCM_PORT); + + } + + componentDidMount() { + console.log("componentDidMount..."); + + const task = () => { + this.fetchPipelines(); + this.fetchExperiments(); + + if(this.state.plName !== ""){ + this.fetchPipelineVersions(this.state.plName, false); + } + + + + + + let shouldChangeDatalakeSourceName = true; + for(const data of this.state.datalakeSourceList){ + if(data === this.state.datalakeSourceName){ + shouldChangeDatalakeSourceName = false; + break; + } + } + if(shouldChangeDatalakeSourceName){ + this.setState({datalakeSourceName : ''},()=>console.log("current selected datalakeSourceName: ",this.state.datalakeSourceName)); + } + else{ + console.log("current selected datalakeSourceName: ",this.state.datalakeSourceName); + } + + }; + + task(); + + + + } + + + fetchPipelines() { + + axios.get( this.state.UCMgr_baseUrl + '/pipelines') + .then(res => { + console.log('Server reponded pl', res.data.pipeline_names) + //setState because this is async response from axios, so re-render + this.setState( + { + plList: res.data.pipeline_names + }, + () => { + let shouldChangePlName = true; + for(const data of this.state.plList){ + if(data === this.state.plName){ + shouldChangePlName = false; + break; + } + } + if(shouldChangePlName){ + this.setState({plName : ''},()=>console.log("current selected plName: ",this.state.plName)); + } + else{ + console.log("current selected plName: ",this.state.plName); + } + } + ); + + }) + .catch(function (error) { + console.log('Got some error' + error); + }) + .then(function () { + }) + } + + getLatestVersion(whom){ + if(whom === "plVerList"){ + let latest = ""; + for(let version of this.state.plVerList){ + if(isNaN(parseInt(version))){ + if(latest === ""){ + latest = version; + } + } + else{ + if(latest === "" || isNaN(parseInt(latest))){ + latest = version; + } + else{ + if(parseInt(latest)console.log("current selected plVerName: ",this.state.plVerName)); + } + else{ + console.log("current selected plVerName: ",this.state.plVerName); + } + } + + + fetchPipelineVersions(pipeline_name, shouldGetLatestVersion) { + + axios.get( `${this.state.UCMgr_baseUrl}/pipelines/${pipeline_name}/versions`) + .then(res => { + console.log('Server reponded pipeline versions list', res.data.versions_list) + //setState because this is async response from axios, so re-render + this.setState( + { + plVerList: res.data.versions_list + }, + () => { + + if(shouldGetLatestVersion){ + this.setState({ plVerName: this.getLatestVersion("plVerList")},() => { + this.makingCorrectPlVerIfWrong(); + }) + } + else{ + this.makingCorrectPlVerIfWrong(); + } + } + ); + + }) + .catch(function (error) { + // handle error + console.log('Got some error' + error); + }) + .then(function () { + // always executed + }) + } + + + + fetchExperiments() { + axios.get(this.state.UCMgr_baseUrl + '/experiments') + .then(res => { + console.log('Server reponded exp', res.data.experiment_names); + //setState because this is async response from axios, so re-render + this.setState( + { + expList: res.data.experiment_names + }, + () => { + let shouldChangeExpName = true; + for(const data of this.state.expList){ + if(data === this.state.expName){ + shouldChangeExpName = false; + break; + } + } + if(shouldChangeExpName){ + this.setState({expName : ''},()=>console.log("current selected expName: ",this.state.expName)); + } + else{ + console.log("current selected expName: ",this.state.expName); + } + } + ); + }) + .catch(function (error) { + // handle error + console.log('Got some error' + error); + }) + .then(function () { + // always executed + }) + + } + + handleCreateSubmit = event => { + console.log('Create TrainingJob clicked: ', + this.state.ucName, + this.state.plName, + this.state.expName, + this.state.featureNames, + this.state.featureFilters, + this.state.hyparams, + this.state.targetName, + this.state.ucDescription, + this.state.plVerName, + this.state.datalakeSourceName, + this.state._measurement, + this.state.bucket + ); + + this.invokeAddTrainingJob(event) + event.preventDefault(); + } + +invokeAddTrainingJob(event){ + let hyperParamsDict = this.buildHyperparamsDict(this.state.hyparams); + let convertedDatalakeDBName = convertDatalakeDBName(this.state.datalakeSourceName) + console.log('Add New Request is posted at ' + this.state.UCMgr_baseUrl + '/trainingjobs/' + this.state.ucName) + axios.post(this.state.UCMgr_baseUrl + '/trainingjobs/' + this.state.ucName,{ + "trainingjob_name" : this.state.ucName, + "pipeline_name" : this.state.plName, + "experiment_name" : this.state.expName, + "feature_list": this.state.featureNames, + "query_filter": this.state.featureFilters, + "arguments" : hyperParamsDict, + "enable_versioning" : this.state.versioning, + "description" : this.state.ucDescription, + "pipeline_version": this.state.plVerName, + "datalake_source": convertedDatalakeDBName, + "_measurement": this.state._measurement, + "bucket": this.state.bucket + }).then(res => { + console.log('UC created ', res.data) + this.invokeStartTrainingForCreate(); + }) + .catch(function (error) { + + console.log('Error creating Training Job', error); + alert("Failed: " + error.response.data.Exception) + event.preventDefault(); + }) + .then(function () { + + }) + +} + + + + invokeStartTrainingForCreate(event){ + console.log('Training called ') + axios.post(this.state.UCMgr_baseUrl + + '/trainingjobs/' + this.state.ucName + '/training', + { + "trainingjob_name" : this.state.ucName, + } + ).then(res => { + console.log('Training responsed ', res) + if(res.status === 200) { + alert("Training Job created and training initiated") + this.resetFrom() + + } else { + console.log('Training issue: ' , res) + } + + }) + .catch(error => { + console.log('Error in training api,response',error.response.data) + alert("Training failed: " + error.response.data.Exception) + }) + .then(function () { + // always executed + }) + } + + + + + + buildFeatureNameList(f_names) { + + console.log("before changing in buildFeatureNameList: ",f_names); + console.log("after changing in buildFeatureNameList: ",String(f_names).split(",")) + return String(f_names).split(","); + //return ["Time", "DL PRB UTILIZATION %"]; + } + + buildFeatureFilterDict(filters){ + + console.log("before changing in buildFeatureFilterDict: ",filters) + + if(filters === ""){ + return {}; + } + + let fil_list = String(filters).split(","); + let filtDict = {} + for ( const filter of fil_list) { + let token = filter.split(":"); + let key = token[0].trim(); + let value = this.getIntOrStringValue(token[1].trim()); + + filtDict[key] = value; + } + + console.log('after changing in buildFeatureFilterDict: ',filtDict); + return filtDict; + + } + + //Fix : Code dumplication merge in common function + buildHyperparamsDict(hyperArgs){ + + console.log("before changing in buildHyperparamsDict: ",hyperArgs); + + if(hyperArgs === ""){ + return { + 'trainingjob_name' : this.state.ucName + }; + } + + let paramList = String(hyperArgs).split(","); + let paramDict = {} + for ( const param of paramList) { + let token = param.split(":"); + let key = token[0].trim(); + let value = token[1].trim(); + + paramDict[key] = value; + } + paramDict["trainingjob_name"] = this.state.ucName; + + + console.log("after changing in buildHyperparamsDict: ",paramDict); + return paramDict; + + } + + getIntOrStringValue(inputValue) { + //BUG: value 12.5 coverted to 12 + + console.log('Before changing in getIntOrStringValue: ',inputValue) + var value = parseInt(inputValue) + if(isNaN(value)) { + value = inputValue + } + console.log('After changing in getIntOrStringValue: ',value) + return value; + } + + handleUCNameChange = (event) => { + this.setState({ + ucName: event.target.value + },() => { + console.log("after set state, ucName: ", this.state.ucName); + }) + } + + handlePLNameChange = (event) => { + + this.setState({ + plName: event.target.value + },() => { + console.log("after set state, plName: ", this.state.plName); + this.fetchPipelineVersions(this.state.plName, true); + }) + } + + handleExpNameChange = (event) => { + + this.setState({ + expName: event.target.value + },() => { + console.log("after set state, expName: ", this.state.expName); + }) + } + + handleFeatureNamesChange = (event) => { + console.log('handleFeatureNamesChange', event.target.value) + this.setState({ + featureNames: event.target.value + },() => { + console.log("after set state, featureNames: ", this.state.featureNames); + }) + } + + handleFeatFiltersChange = (event) => { + this.setState({ + featureFilters: event.target.value + },() => { + console.log("after set state, featureFilters: ", this.state.featureFilters); + }) + } + + handleHyparamsChange = (event) => { + this.setState({ + hyparams: event.target.value + },() => { + console.log("after set state, hyparams: ", this.state.hyparams); + }) + } + + handleVersioningChange = (event) => { + this.setState({ + versioning: event.target.checked + },() => { + console.log("after set state, versioning: ", this.state.versioning); + }) + } + + handleTargetChange = (event) => { + this.setState({ + targetName: event.target.value + },() => { + console.log("after set state, targetName: ", this.state.targetName); + }) + } + + handleDatalakeSourceChange = (event) => { + this.setState({ + datalakeSourceName: event.target.value + },() => { + console.log("after set state, datalakeSourceName: ", this.state.datalakeSourceName); + }) + } + + handleUCDescriptionChange = (event) => { + this.setState({ + ucDescription: event.target.value + },() => { + console.log("after set state, ucDescription: ", this.state.ucDescription); + }) + } + + handlePipelineVersionChange = (event) => { + this.setState({ + plVerName: event.target.value + },() => { + console.log("after set state, plVerName: ", this.state.plVerName); + }) + } + + + + + + + + handle_measurementChange = (event) => { + this.setState({ + _measurement: event.target.value + },()=>{ + console.log("after set state, _measurement: ", this.state._measurement); + }); + } + + handleBucketChange = (event) => { + this.setState({ + bucket : event.target.value + },()=>{ + console.log("after set state, bucket: ", this.state.bucket); + }); + } + + + resetFrom = ()=> { + + this.setState({ + ucName: '', + plName: '', + expName: '', + featureNames: '', + featureFilters: '', + hyparams: '', + versioning: false, + ucDescription: '', + targetName: '', + plVerName: '', + plVerList: [], + plVerDescription: '', + datalakeSourceName: '', + superModel: '', + superModelVersion: '', + superModelVersionsList: [], + _measurement: '', + bucket: '' + }) + } + + + + render() { + + + return ( + <> + +
+ + + + Training Job Name* + { + this.props.isCreateTrainingJobForm + ? + ( + + ) + : + ( + + ) + } + + + + Pipeline Name* + + + + { + this.state.plList.map(data => ) + } + + + + { + this.state.plName !== '' + && +
+ + Pipeline Version Name* + + + + { + this.state.plVerList.map(data => { + if(data === this.state.plName){ + return + } + else{ + return + } + }) + } + + + {/* + Pipeline Version Description + + */} +
+ + } + + + Experiment Name* + + + + { + this.state.expList.map(data => ) + } + + + + + Datalake Source* + + + + + { + this.state.datalakeSourceList.map(data => ) + } + + + + + { + this.state.datalakeSourceName === "Influx DB" && +
+ + _measurement* + + + + bucket* + + +
+ + } + + + Feature Name* + + + + + Feature Filter + + + + + Hyper Parameters + + + + {/* currently don't know difference between id and controlId in Form.group*/} + + + + + + + + Description + + + + +
+ + ); + } +} + +export default CreateTrainingJob; diff --git a/src/components/home/navbar/NavbarComponent.css b/src/components/home/navbar/NavbarComponent.css new file mode 100644 index 0000000..6a42de1 --- /dev/null +++ b/src/components/home/navbar/NavbarComponent.css @@ -0,0 +1,28 @@ + /* ================================================================================== + + Copyright (c) 2022 Samsung Electronics Co., Ltd. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + ================================================================================== */ +.nav-bar{ + margin-bottom: 5px; +} + +.nav-drop-down{ + font-size: large; +} + +.logo{ + width : 130px; +} diff --git a/src/components/home/navbar/NavbarComponent.js b/src/components/home/navbar/NavbarComponent.js new file mode 100644 index 0000000..9c957bb --- /dev/null +++ b/src/components/home/navbar/NavbarComponent.js @@ -0,0 +1,43 @@ +// ================================================================================== + +// Copyright (c) 2022 Samsung Electronics Co., Ltd. All Rights Reserved. + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// ================================================================================== + +import React from 'react'; +import { Container, Nav, Navbar, NavDropdown } from 'react-bootstrap'; +import { Link } from 'react-router-dom' +import './NavbarComponent.css'; +function NavbarComponent() { + + + return ( + + + AI/ML Management Dashboard + + + + ); +} + +export default NavbarComponent; +