diff --git a/SAS/TMSS/frontend/tmss_webapp/src/layout/_overrides.scss b/SAS/TMSS/frontend/tmss_webapp/src/layout/_overrides.scss index 9a50e3042bb982cadbe652218a436c9221b7f080..22509069162d3725ddfe978e8ae73b77814034e4 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/layout/_overrides.scss +++ b/SAS/TMSS/frontend/tmss_webapp/src/layout/_overrides.scss @@ -554,3 +554,12 @@ h3 + div + p { .act-btn-disable { cursor: default; } + +.addIngest .pi-search { + margin-right: 1em; +} + +.addIngestDialog { + max-height: none; + height: 30vw; +} \ No newline at end of file diff --git a/SAS/TMSS/frontend/tmss_webapp/src/layout/components/CustomDialog.js b/SAS/TMSS/frontend/tmss_webapp/src/layout/components/CustomDialog.js index 618cde5ba4cf2bc1c6119b0ca22b8a1516aba85b..ca439cd563d04b14d16b25875bd9c2c65ef62404 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/layout/components/CustomDialog.js +++ b/SAS/TMSS/frontend/tmss_webapp/src/layout/components/CustomDialog.js @@ -26,7 +26,8 @@ export class CustomDialog extends Component { return ( <div className={`custom-dlg p-grid`} data-testid="confirm_dialog" style={{opacity: (this.props.opacity===undefined || this.props.opacity===null)?1:this.props.opacity}}> - <Dialog header={this.props.header} visible={this.props.visible} style={{width: this.props.width?this.props.width:'25vw'}} + <Dialog header={this.props.header} visible={this.props.visible} style={{width: this.props.width?this.props.width:'25vw'}} + className={this.props.className} inputId="confirm_dialog" modal={true} onHide={this.props.onClose} footer={<div> 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 58752b66bcf57b66b8935bb388ab75a95ae5767e..aaf0c43edd8629a60fdd5477f39407a7ba8868e0 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/ViewSchedulingUnit.js +++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/ViewSchedulingUnit.js @@ -38,6 +38,7 @@ import { InputTextarea } from 'primereact/inputtextarea'; import { Dropdown } from 'primereact/dropdown'; import ProjectService from '../../services/project.service'; import IngestProgress from './ingest.progress'; +import AddIngestTask from './add.ingest.task'; class ViewSchedulingUnit extends Component { lsKeySortColumn = 'SortDataViewSchedulingUnit'; @@ -236,7 +237,8 @@ class ViewSchedulingUnit extends Component { dataformat: ['MeasurementSet'], taskStatus: [], permissionById: {}, - userPermission: {permissions: AuthStore.getState().userRolePermission} + userPermission: {permissions: AuthStore.getState().userRolePermission}, + showAddIngestDialog : false } this.taskFilters = []; // To get Short_Description details this.taskTemplates = []; // All task templates to be filtered based on tasks in selected strategy template @@ -287,6 +289,10 @@ class ViewSchedulingUnit extends Component { this.getStatusContent = this.getStatusContent.bind(this); this.getStatusForCopiedShedulingUnit = this.getStatusForCopiedShedulingUnit.bind(this); this.createSUCleanupTask = this.createSUCleanupTask.bind(this); + this.addNewIngestTask = this.addNewIngestTask.bind(this); + this.prepareIngestTask = this.prepareIngestTask.bind(this); + this.confirmAddIngestTask = this.confirmAddIngestTask.bind(this); + this.closeIngestDialog = this.closeIngestDialog.bind(this); this.getCleanUpDialogContent = this.getCleanUpDialogContent.bind(this); this.cleanUpSUTask = this.cleanUpSUTask.bind(this); this.confirmAutoDeletion = this.confirmAutoDeletion.bind(this); @@ -641,6 +647,12 @@ class ViewSchedulingUnit extends Component { disabled: disableUpdateAction === undefined?!this.state.permissionById.delete || !canDelete:disableUpdateAction, type: 'button', actOn: 'click', props: { callback: this.showDeleteSUConfirmation } }); + this.actions.push({ + icon: 'fa fa-plus-square', + style: this.iconStyle, + title:'Add injest task', + type: 'button', actOn: 'click', props: { callback: this.confirmAddIngestTask } + }); if(isIngestPresent) { this.actions.push({ @@ -1950,6 +1962,23 @@ class ViewSchedulingUnit extends Component { this.setState({dialog: dialog, dialogVisible: true}); } + /** + * Function to show confirmation before add Inguest Task + */ + async confirmAddIngestTask() { + let dialog = this.state.dialog; + dialog.type = "confirmation"; + dialog.header= "Confirm to Add Injest Task"; + dialog.detail = "Do you want to add Injest task for this Scheduling Unit Blueprint?"; + dialog.content = this.getCleanUpDialogContent; + dialog.actions = [{id: 'yes', title: 'Yes', callback: this.addNewIngestTask}, + {id: 'no', title: 'Cancel', className:'act-btn-cancel', callback: this.closeDialog}]; + dialog.onSubmit = this.addNewIngestTask; + dialog.width = '55vw'; + dialog.showIcon = false; + this.setState({dialog: dialog, dialogVisible: true}); + } + /** * Prepare dialog content before create clean-up task * @returns : return dialog content @@ -1993,6 +2022,71 @@ class ViewSchedulingUnit extends Component { this.setState({dialog: dialog, dialogVisible: true}); } + /** + * Prepare new Ingest Task details for current Scheduling Unit + * @param {*} existingIngestTasks + */ + prepareIngestTask(existingIngestTasks) { + let newIngestTask = { + "produced_by": [], + "consumed_by": [], + "output_pinned": false, + "tags": [], + "task_blueprints": [], + "first_scheduling_relation": [], + "second_scheduling_relation": [], + "short_description": "", + "scheduling_unit_draft" :this.state.scheduleunit.url + }; + /*if (existingIngestTasks && existingIngestTasks.length>0) { + const latestTask = existingIngestTasks[existingIngestTasks.length-1]; + newIngestTask['description'] = latestTask.description; + newIngestTask['specifications_doc'] = latestTask.specifications_doc; + newIngestTask['specifications_template'] = latestTask.specifications_template; + } else {*/ + const ingestTaskTemplate = _.find(this.taskTemplates, {'name': 'ingest'}); + newIngestTask['description'] = ingestTaskTemplate.description; + newIngestTask['specifications_doc'] = { + "$schema": ingestTaskTemplate.ref_resolved_schema['$id'] + }; + newIngestTask['specifications_template'] = ingestTaskTemplate.url; + // } + newIngestTask['name'] = `Ingest ${existingIngestTasks.length>0?existingIngestTasks.length:''}`; + return newIngestTask; + } + + /** + * Add new Ingest task + * @returns + */ + async addNewIngestTask() { + let response = null; + let ingestTasks = _.filter(this.state.scheduleunit.task_drafts, {task_type : 'ingest'}); + ingestTasks = _.orderBy(ingestTasks, "id"); + let newIngestTask = this.prepareIngestTask(ingestTasks); + try{ + response = await TaskService.createTask(newIngestTask); + if (response.statusText === 'Created' ) { + appGrowl.show({ severity: 'info', summary: 'Add Ingest Task - Status', detail: 'Added new Ingest Task Successfully' }); + this.setState({showAddIngestDialog : true, ingestTasks: ingestTasks, newIngestTask: response.data}); + } else { + appGrowl.show({ severity: 'info', summary: 'Add Ingest Task - Status', detail: 'Add to new Ingest Task is Failed' }); + } + } catch(error) { + this.statusUpdate = "Failed"; + console.log('Error While add Ingest Task', error); + } + await this.componentDidMount(); + } + + /** + * Close the Add Ingect Task Dialog + */ + closeIngestDialog() { + this.setState({showAddIngestDialog : false}); + this.componentDidMount(); + } + /** * Preparedialog content for after create Clean-up task * @returns : dialog content for clean-up task status @@ -2663,7 +2757,9 @@ class ViewSchedulingUnit extends Component { </Dialog> } {/* Dialog component to show messages and get confirmation */} - + {this.state.showAddIngestDialog && + <AddIngestTask newIngestTask={this.state.newIngestTask} existingIngestTasks = {this.state.ingestTasks} onCancel={this.closeIngestDialog} /> + } <CustomDialog type="confirmation" visible={this.state.dialogVisible} header={this.state.dialog.header} message={this.state.dialog.detail} actions={this.state.dialog.actions} content={this.state.dialog.content} width={this.state.dialog.width} showIcon={this.state.dialog.showIcon} diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/add.ingest.task.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/add.ingest.task.js new file mode 100644 index 0000000000000000000000000000000000000000..e6014b8296c4f39e2a2c707be2b1a6bf353a7825 --- /dev/null +++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/add.ingest.task.js @@ -0,0 +1,48 @@ +import React, {Component} from "react"; +import { CustomDialog } from '../../layout/components/CustomDialog'; +import { ListBox } from 'primereact/listbox'; + +export default class AddIngestTask extends Component { + constructor(props) { + super(props); + this.state = { + selectedTask: {}, + }; + this.actions = [ {id:"yes", title: 'Update', callback: this.updateTask}, + {id:"no", title: 'Close', className:'act-btn-cancel', callback: this.props.onCancel} ]; + + this.updateTask = this.updateTask.bind(this); + } + + updateTask() { + //Update Ingest Task based on input task selection + } + + render() { + return ( + <> + <CustomDialog type="success" visible={true} width="40vw" className="addIngestDialog" + header={'Edit Input Connection For Ingest Task'} + message= { + <React.Fragment> + <div className="p-fluid"> + <div className="p-field p-grid" style={{marginLeft: '4em'}}> + <label className="col-lg-4 col-md-4 col-sm-12" style={{fontSize: '20px'}}>New Ingest Task</label> + <label className="col-lg-8 col-md-8 col-sm-12" style={{fontSize: '20px'}}>Existing Input Ingest Task</label> + <label className="col-lg-4 col-md-4 col-sm-12" style={{marginTop: '5em', color: 'black', fontSize : '15px'}}>{this.props.newIngestTask.name}</label> + <ListBox value={this.state.selectedTask} options={this.props.existingIngestTasks} className="addIngest" + onChange={(e) => this.setState({ selectedTask: e.value })} filter optionLabel="name" + style={{ width: '15rem' }} listStyle={{ maxHeight: '250px' }} /> + </div> + </div> + </React.Fragment>} + content={''} onClose={this.props.onCancel} onCancel={this.props.onCancel} onSubmit={this.updateTask} showAction={true} + actions={this.actions} + showIcon={false}> + </CustomDialog> + + </> + + ); + } +} \ No newline at end of file diff --git a/SAS/TMSS/frontend/tmss_webapp/src/services/task.service.js b/SAS/TMSS/frontend/tmss_webapp/src/services/task.service.js index 13accf1b3e3f9ea65b9d126c9ec58e4622637d19..a9fc8382095c651181d47e5f50aa644a16365576 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/services/task.service.js +++ b/SAS/TMSS/frontend/tmss_webapp/src/services/task.service.js @@ -446,7 +446,22 @@ const TaskService = { console.error('[task.services.getSubtaskProgress]',"Error", error); return null } - } + }, + /** + * Cancel task + * @param {*} type + * @param {*} id + */ + createTask: async function(task) { + try { + const url = `/api/task_draft`; + const response = await axios.post(url, task); + return response; + } catch(error) { + console.error(error); + return false; + } + } } export default TaskService;