diff --git a/SAS/TMSS/frontend/tmss_webapp/src/App.css b/SAS/TMSS/frontend/tmss_webapp/src/App.css index ba646b1315d9b1db73071db2c7c39cc18e058550..05abe02b86af57144506bd48ad6d10bd8c5bec8a 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/App.css +++ b/SAS/TMSS/frontend/tmss_webapp/src/App.css @@ -147,9 +147,9 @@ p { margin-bottom: 1rem; } -.layout-main .fa { +.layout-main .fa,.far { color: #005b9f; - font-size: 20px; + font-size: 20px !important; } thead { diff --git a/SAS/TMSS/frontend/tmss_webapp/src/layout/components/PageHeader.js b/SAS/TMSS/frontend/tmss_webapp/src/layout/components/PageHeader.js index a10e7781758b1c70b410114790ede0cc202b0875..db24a5ade532d6b7c296520ce38a50b80b39d726 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/layout/components/PageHeader.js +++ b/SAS/TMSS/frontend/tmss_webapp/src/layout/components/PageHeader.js @@ -44,7 +44,7 @@ export default ({ title, subTitle, actions, ...props}) => { if(action.type === 'button') { return ( <button className="p-link" key={index} title={action.title || ''}> - <i className={`fa ${action.disabled?'fa-disabled':''} ${action.icon} ${action.classes}`} + <i className={`${action.iconType?action.iconType:'fa'} ${action.disabled?'fa-disabled':''} ${action.icon} ${action.classes}`} onMouseOver={(e) => action.disabled?'':onButtonMouseOver(e, action)} onClick={(e) => action.disabled?'':onButtonClick(e, action)} /> </button> @@ -62,7 +62,7 @@ export default ({ title, subTitle, actions, ...props}) => { return ( <Link key={index} className={action.classname} to={action.disabled?{}:{ ...action.props }} title={action.title || ''} onClick={() => action.disabled?'':onClickLink(action)}> - <i className={`fa ${action.disabled?'fa-disabled':''} ${action.icon}`}></i> + <i className={`${action.iconType?action.iconType:'fa'} ${action.disabled?'fa-disabled':''} ${action.icon}`}></i> </Link> ); } diff --git a/SAS/TMSS/frontend/tmss_webapp/src/layout/sass/_pageheader.scss b/SAS/TMSS/frontend/tmss_webapp/src/layout/sass/_pageheader.scss index 69e483f2e745524d094d8fdfa60c5427be4bceab..7972ed62d59edd64b77428caac7dff3ff325b025 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/layout/sass/_pageheader.scss +++ b/SAS/TMSS/frontend/tmss_webapp/src/layout/sass/_pageheader.scss @@ -19,7 +19,7 @@ margin-left: 5px; } -.page-header .fa { +.page-header .fa,.far { font-size: 25px !important; } 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 385b4f931ba93f2dd5a5e4c207023a13d89b3b3a..862068b72de643d49aa5b338e4636379462a85a4 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/ViewSchedulingUnit.js +++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/ViewSchedulingUnit.js @@ -1069,23 +1069,45 @@ class ViewSchedulingUnit extends Component { */ getTaskCancelConfirmContent() { let selectedTasks = []; + let ignoredTasks = []; for (const obj of this.selectedRows) { if (this.TASK_END_STATUSES.indexOf(obj.status) < 0) { selectedTasks.push({ id: obj.id, suId: this.state.scheduleunit.id, suName: this.state.scheduleunit.name, taskId: obj.id, controlId: obj.subTaskID, taskName: obj.name, status: obj.status }); + } else { + ignoredTasks.push({ + id: obj.id, suId: this.state.scheduleunit.id, suName: this.state.scheduleunit.name, + taskId: obj.id, controlId: obj.subTaskID, taskName: obj.name, status: obj.status + }); } } return <> - <DataTable value={selectedTasks} resizableColumns columnResizeMode="expand" className="card" style={{ paddingLeft: '0em' }}> - <Column field="suId" header="Scheduling Unit Id"></Column> - <Column field="suName" header="Scheduling Unit Name"></Column> - <Column field="taskId" header="Task Id"></Column> - <Column field="controlId" header="Control Id"></Column> - <Column field="taskName" header="Task Name"></Column> - <Column field="status" header="Status"></Column> - </DataTable> + <div style={{marginTop: '1em'}}> + <b>Task(s) that can be cancelled</b> + <DataTable value={selectedTasks} resizableColumns columnResizeMode="expand" className="card" style={{ paddingLeft: '0em' }}> + <Column field="suId" header="Scheduling Unit Id"></Column> + <Column field="suName" header="Scheduling Unit Name"></Column> + <Column field="taskId" header="Task Id"></Column> + <Column field="controlId" header="Control Id"></Column> + <Column field="taskName" header="Task Name"></Column> + <Column field="status" header="Status"></Column> + </DataTable> + </div> + {ignoredTasks.length > 0 && + <div style={{marginTop: '1em'}}> + <b>Task(s) that will be ignored</b> + <DataTable value={ignoredTasks} resizableColumns columnResizeMode="expand" className="card" style={{ paddingLeft: '0em' }}> + <Column field="suId" header="Scheduling Unit Id"></Column> + <Column field="suName" header="Scheduling Unit Name"></Column> + <Column field="taskId" header="Task Id"></Column> + <Column field="controlId" header="Control Id"></Column> + <Column field="taskName" header="Task Name"></Column> + <Column field="status" header="Status"></Column> + </DataTable> + </div> + } </> } @@ -1111,12 +1133,10 @@ class ViewSchedulingUnit extends Component { } return <> <div style={{marginTop: '1em'}}> - <b>Task(s) that can be marked as obsolete’ if task has null for obsolete_since.</b> - <p>Task(s) that are marked as obsolete will be ignored’. If you want to mark as obsolete for task(s) for which obsolete_since is null, click "Yes"</p> - {selectedTasksWithObsolete.length>0 && + {selectedTasksWithoutObsolete.length>0 && <> - <p>Selected Task (s) with Obsolete are listed below</p> - <DataTable value={selectedTasksWithObsolete} resizableColumns columnResizeMode="expand" className="card" style={{ paddingLeft: '0em' }}> + <b>Task(s) that can be marked as obsolete</b> + <DataTable value={selectedTasksWithoutObsolete} resizableColumns columnResizeMode="expand" className="card" style={{ paddingLeft: '0em' }}> <Column field="suId" header="Scheduling Unit Id"></Column> <Column field="suName" header="Scheduling Unit Name"></Column> <Column field="taskId" header="Task Id"></Column> @@ -1125,11 +1145,10 @@ class ViewSchedulingUnit extends Component { <Column field="status" header="Status"></Column> </DataTable> </>} - - {selectedTasksWithoutObsolete.length>0 && + {selectedTasksWithObsolete.length>0 && <> - <p>Selected Task (s) without Obsolete are listed below</p> - <DataTable value={selectedTasksWithoutObsolete} resizableColumns columnResizeMode="expand" className="card" style={{ paddingLeft: '0em' }}> + <b>Task(s) that are marked as obsolete will be ignored</b> + <DataTable value={selectedTasksWithObsolete} resizableColumns columnResizeMode="expand" className="card" style={{ paddingLeft: '0em' }}> <Column field="suId" header="Scheduling Unit Id"></Column> <Column field="suName" header="Scheduling Unit Name"></Column> <Column field="taskId" header="Task Id"></Column> @@ -1158,8 +1177,9 @@ class ViewSchedulingUnit extends Component { </DataTable> </> } + /** - * Content to show status of marking task as obsolete + * Content to show status after marking task as obsolete */ getObsTaskStatusContent() { let obsoleteTasks = this.state.obsoleteTasks; @@ -1175,8 +1195,9 @@ class ViewSchedulingUnit extends Component { </DataTable> </> } + /** - * To check is selected tasks are marked as obsolete or not + * To check if selected tasks are marked as obsolete or not * @param {Array} selectedBlueprints * @returns Array - List of tasks which have obsolete_since as null */ @@ -1196,80 +1217,88 @@ class ViewSchedulingUnit extends Component { let selectedBlueprints = this.selectedRows.filter(task => { return task.tasktype === 'Blueprint' && this.TASK_END_STATUSES.indexOf(task.status)<0}); - if (selectedBlueprints.length === 0) { + if (this.selectedRows.length === 0) { appGrowl.show({ severity: 'info', summary: 'Select Row', detail: 'Select atleast one cancellable Task Blueprint to cancel.' }); } else { - let dialog = this.state.dialog; - dialog.type = "confirmation"; - dialog.header = "Confirm to Cancel Task(s)"; - dialog.actions = [{ id: 'yes', title: 'Yes', callback: this.cancelTasks }, - { id: 'no', title: 'No', callback: this.closeDialog }]; - dialog.detail = "Cancelling the task means it will no longer be executed / will be aborted. This action cannot be undone. Do you want to proceed?"; - dialog.content = this.getTaskCancelConfirmContent; - dialog.submit = this.cancelTasks; - dialog.width = '55vw'; - dialog.showIcon = false; - this.setState({ dialog: dialog, dialogVisible: true }); + if(selectedBlueprints.length === 0) { + appGrowl.show({ severity: 'warn', summary: 'Already Cancelled', + detail: 'Selected task(s) are already cancelled' }); + } + else { + let dialog = this.state.dialog; + dialog.type = "confirmation"; + dialog.header = "Confirm to Cancel Task(s)"; + dialog.actions = [{ id: 'yes', title: 'Yes', callback: this.cancelTasks }, + { id: 'no', title: 'No', callback: this.closeDialog }]; + dialog.detail = "Cancelling the task means it will no longer be executed / will be aborted. This action cannot be undone. Do you want to proceed?"; + dialog.content = this.getTaskCancelConfirmContent; + dialog.submit = this.cancelTasks; + dialog.width = '55vw'; + dialog.showIcon = false; + this.setState({ dialog: dialog, dialogVisible: true, cancelledBlueprint: selectedBlueprints }); + } } } + /** * Function to get conirmation before marking task(s) as obsolete */ confirmObsoleteTasks() { this.pageUpdated = false; let selectedBlueprints = this.selectedRows.filter(task => { - return task.tasktype === 'Blueprint' - }); - const blueprintsWithObsolete = this.checkObsolete(selectedBlueprints) + return task.tasktype === 'Blueprint'; + }); + const blueprintsWithObsolete = this.checkObsolete(selectedBlueprints); const blueprintWithoutObsolete = _.difference(selectedBlueprints, blueprintsWithObsolete); if (selectedBlueprints.length === 0) { appGrowl.show({ severity: 'info', summary: 'Select Row', detail: 'Please select minimum one task to mark as obsolete' }); } else { if (blueprintWithoutObsolete.length === 0) { - appGrowl.show({ severity: 'warn', summary: 'Already marked as obsolete', - detail: 'Selected task(s) are already marked as obsolete' }); + appGrowl.show({ severity: 'warn', summary: 'Already marked as obsolete', + detail: 'Selected task(s) are already marked as obsolete' }); } else { - let dialog = this.state.dialog; - dialog.type = "confirmation"; - dialog.header = "Confirm to mark task(s) as obsolete"; - dialog.actions = [{ id: 'yes', title: 'Yes', callback: this.markObsoleteTasks }, - { id: 'no', title: 'No', callback: this.closeDialog }]; - dialog.detail = "Warning: Obsolete task(s) will not be copied and dataproducts will not be used for pipelines and ingest. Are you sure you want to make the task(s) obsolete?"; - dialog.content = this.getObsTaskConfirmDlgContent; - dialog.submit = this.markObsoleteTasks; - dialog.width = '55vw'; - dialog.showIcon = false; - this.setState({ dialog: dialog, dialogVisible: true, blueprintsWithObsolete: blueprintsWithObsolete}); + let dialog = this.state.dialog; + dialog.type = "confirmation"; + dialog.header = "Confirm to mark task(s) as obsolete"; + dialog.actions = [{ id: 'yes', title: 'Yes', callback: this.markObsoleteTasks }, + { id: 'no', title: 'No', callback: this.closeDialog }]; + dialog.detail = "Warning: Obsolete task(s) will not be copied and dataproducts will not be used for pipelines and ingest. Are you sure you want to make the task(s) obsolete?"; + dialog.content = this.getObsTaskConfirmDlgContent; + dialog.submit = this.markObsoleteTasks; + dialog.width = '55vw'; + dialog.showIcon = false; + this.setState({ dialog: dialog, dialogVisible: true, blueprintsWithObsolete: blueprintsWithObsolete}); } } - } + } + /** - * Function to mark task(s) as obsolete as show the status after completion + * Function to mark task(s) as obsolete and show the status after completion */ - async markObsoleteTasks() { + async markObsoleteTasks() { let schedulingUnitTasks = this.state.schedulingUnitTasks; const blueprintWithoutObsolete = _.difference(this.selectedRows, this.state.blueprintsWithObsolete); let obsoleteTask = [] for (const selectedTask of blueprintWithoutObsolete) { - const obsTask = await TaskService.obsoleteTask(selectedTask.id); - let task = _.find(schedulingUnitTasks, {'id': selectedTask.id, tasktype: 'Blueprint'}); - if (obsTask) { - task.status = obsTask.status; - } - obsoleteTask.push({ - id: task.id, suId: this.state.scheduleunit.id, suName: this.state.scheduleunit.name, - taskId: task.id, controlId: task.subTaskID, taskName: task.name, - status: task.status.toLowerCase()==='obsolete'?'Obsolete': task.status, - actionStatus: obsTask?'Success': 'Failed' - }); - + const obsTask = await TaskService.markTaskObsolete(selectedTask.id); + let task = _.find(schedulingUnitTasks, {'id': selectedTask.id, tasktype: 'Blueprint'}); + if (obsTask) { + task.status = obsTask.status; + task.obsolete_since = obsTask.obsolete_since; + } + obsoleteTask.push({ + id: task.id, suId: this.state.scheduleunit.id, suName: this.state.scheduleunit.name, + taskId: task.id, controlId: task.subTaskID, taskName: task.name, + status: task.status.toLowerCase()==='obsolete'?'Obsolete': task.status, + actionStatus: obsTask?'Success': 'Failed' + }); } let dialog = this.state.dialog; dialog.type = "confirmation"; - dialog.header = "Obsolete Task(s) Status"; + dialog.header = "Mark task(s) as obsolete - Status"; dialog.actions = [{ id: 'no', title: 'Ok', callback: this.closeDialog }]; dialog.detail = "" dialog.content = this.getObsTaskStatusContent; @@ -1280,7 +1309,7 @@ class ViewSchedulingUnit extends Component { this.setState({ schedulingUnitTasks: schedulingUnitTasks, obsoleteTasks: obsoleteTask, dialog: dialog, dialogVisible: true }); } - /** + /** * Function to cancel all selected task blueprints if the task status is not one of the end statuses * and update their status on successful cancellation. */ @@ -1571,11 +1600,11 @@ class ViewSchedulingUnit extends Component { <> {this.props.match.params.type === 'draft' && <> - <button className="p-link" href="#" onClick={this.confirmCancelTasks} + <button className="p-link" href="#" onClick={this.confirmCancelTasks} style={{ marginLeft: '8px'}} title={userPermissions.task_draft.canceltask?"Cancel selected Task(s)": `${this.access_denied_message} to cancel Task(s)`}> <i class={userPermissions.task_draft.canceltask?"fa fa-ban":"fa fa-ban fa-disabled"} aria-hidden="true" ></i> </button> - <button className="p-link" href="#" style={{ pointerEvents: this.props.disabled ? 'none' : 'auto' }}onClick={this.confirmDeleteTasks} + <button className="p-link" href="#" style={{ pointerEvents: this.props.disabled ? 'none' : 'auto', marginLeft: '8px' }} onClick={this.confirmDeleteTasks} title={userPermissions.task.delete?"Delete selected Task(s)": `${this.access_denied_message} to delete Task(s)`} > <i class={userPermissions.task.delete?"fa fa-trash":"fa fa-trash fa-disabled"} aria-hidden="true" ></i> </button> @@ -1588,7 +1617,7 @@ class ViewSchedulingUnit extends Component { <i class={userPermissions.task_blueprint.canceltask?"fa fa-ban":"fa fa-ban fa-disabled"} aria-hidden="true" ></i></a> <a className="p-link" style={{ marginLeft: '8px'}} href="#" onClick={this.confirmObsoleteTasks} title={userPermissions.task.edit?"Mark as Obsolete": `${this.access_denied_message}`}> - <i class={userPermissions.task.edit?"fa fa-bullseye":"fa fa-bullseye fa-disabled"} aria-hidden="true" ></i> + <i class={userPermissions.task.edit?"far fa-times-circle":"far fa-times-circle fa-disabled"} aria-hidden="true" ></i> </a> <a href="#" style={{ pointerEvents: this.props.disabled ? 'none' : 'auto', marginLeft: '8px' }} onClick={this.confirmDeleteTasks} title={userPermissions.task.delete?"Delete selected Task(s)": `${this.access_denied_message} to delete Task(s)`} > diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Task/list.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Task/list.js index f203225cd178eb8b626187bbfe3d3844b42a1802..1823dbf144ca7aa3e78ff8e42f8490c67ed4288c 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Task/list.js +++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Task/list.js @@ -235,7 +235,7 @@ export class TaskList extends Component { this.closeDialog = this.closeDialog.bind(this); this.getTaskDeleteDialogContent = this.getTaskDeleteDialogContent.bind(this); this.getTaskCancelConfirmContent = this.getTaskCancelConfirmContent.bind(this); - this.getObsTaskStatusContent = this.getObsTaskStatusContent.bind(this); + this.getCancelTaskStatusContent = this.getCancelTaskStatusContent.bind(this); this.changeTaskType = this.changeTaskType.bind(this); this.fetchTableData = this.fetchTableData.bind(this); this.getFilterOptions = this.getFilterOptions.bind(this); @@ -348,10 +348,7 @@ export class TaskList extends Component { this.subtaskTemplates = await TaskService.getSubtaskTemplates(); let actions = []; if(this.state.taskType === 'Draft'){ - actions = [{icon: 'fa fa-ban', - title: task_draft.canceltask?'Cancel Task(s)': `${this.access_denied_message} to cancel Task(s)`, - disabled: task_draft.canceltask? !task_draft.canceltask: true, - type: 'button', actOn: 'click', props: { callback: this.confirmCancelTasks }}, + actions = [ {icon: 'fa fa-trash', title: task.delete?'Delete Task(s)':`${this.access_denied_message} to delete Task(s)`, disabled: task.delete? !task.delete: true, @@ -359,7 +356,7 @@ export class TaskList extends Component { ]; } else { - actions = [ {icon: 'fa fa-bullseye', + actions = [ {icon: 'fa fa-times-circle', title: task.edit?'Mark as Obsolete': `${this.access_denied_message}`, disabled: task.edit? !task.edit: true, type: 'button', actOn: 'click', props: { callback: this.confirmObsoleteTasks }}, @@ -495,12 +492,10 @@ export class TaskList extends Component { return <> <div style={{marginTop: '1em'}}> - <b>Task(s) that can be marked as obsolete’ if task has null for obsolete_since.</b> - <p>Task(s) that are marked as obsolete will be ignored’. If you want to mark as obsolete for task(s) for which obsolete_since is null, click "Yes"</p> - {selectedTasksWithObsolete.length>0 && + {selectedTasksWithoutObsolete.length>0 && <> - <p>Selected Task (s) with Obsolete are listed below</p> - <DataTable value={selectedTasksWithObsolete} resizableColumns columnResizeMode="expand" className="card" style={{ paddingLeft: '0em' }}> + <b>Task(s) that can be marked as obsolete</b> + <DataTable value={selectedTasksWithoutObsolete} resizableColumns columnResizeMode="expand" className="card" style={{ paddingLeft: '0em' }}> <Column field="suId" header="Scheduling Unit Id"></Column> <Column field="suName" header="Scheduling Unit Name"></Column> <Column field="taskId" header="Task Id"></Column> @@ -509,11 +504,10 @@ export class TaskList extends Component { <Column field="status" header="Status"></Column> </DataTable> </>} - - {selectedTasksWithoutObsolete.length>0 && + {selectedTasksWithObsolete.length>0 && <> - <p>Selected Task (s) without Obsolete are listed below</p> - <DataTable value={selectedTasksWithoutObsolete} resizableColumns columnResizeMode="expand" className="card" style={{ paddingLeft: '0em' }}> + <b>Task(s) already marked as obsolete will be ignored</b> + <DataTable value={selectedTasksWithObsolete} resizableColumns columnResizeMode="expand" className="card" style={{ paddingLeft: '0em' }}> <Column field="suId" header="Scheduling Unit Id"></Column> <Column field="suName" header="Scheduling Unit Name"></Column> <Column field="taskId" header="Task Id"></Column> @@ -576,7 +570,7 @@ export class TaskList extends Component { /** * Prepare Task(s) details to show status of Task cancellationn */ - getObsTaskStatusContent() { + getCancelTaskStatusContent() { let cancelledTasks = this.state.cancelledTasks; return <> <DataTable value={cancelledTasks} resizableColumns columnResizeMode="expand" className="card" style={{ paddingLeft: '0em' }}> @@ -617,27 +611,35 @@ export class TaskList extends Component { let selectedBlueprints = this.selectedRows.filter(task => { return task.tasktype === 'Blueprint' && this.TASK_END_STATUSES.indexOf(task.status)<0}); - if (selectedBlueprints.length === 0) { + if (this.selectedRows.length === 0) { appGrowl.show({ severity: 'info', summary: 'Select Row', - detail: 'Select atleast one cancellable Task Blueprint to cancel.' }); + detail: 'Please select minimum one task to cancel' }); } else { - let dialog = this.state.dialog; - dialog.type = "confirmation"; - dialog.header = "Confirm to Cancel Task(s)"; - dialog.actions = [{ id: 'yes', title: 'Yes', callback: this.cancelTasks }, - { id: 'no', title: 'No', callback: this.closeDialog }]; - dialog.detail = "Cancelling the task means, it will no longer be executed / will be aborted. This action cannot be undone. Already finished/cancelled task(s) will be ignored. Do you want to proceed?"; - dialog.content = this.getTaskCancelConfirmContent; - dialog.submit = this.cancelTasks; - dialog.width = '55vw'; - dialog.showIcon = false; - this.setState({ dialog: dialog, dialogVisible: true }); + if(selectedBlueprints.length === 0) { + appGrowl.show({ severity: 'warn', summary: 'Already Cancelled', + detail: 'Selected task(s) are already cancelled' }); + } + else { + let dialog = this.state.dialog; + dialog.type = "confirmation"; + dialog.header = "Confirm to Cancel Task(s)"; + dialog.actions = [{ id: 'yes', title: 'Yes', callback: this.cancelTasks }, + { id: 'no', title: 'No', callback: this.closeDialog }]; + dialog.detail = "Warning: Cancelling the task means, it will no longer be executed / will be aborted. This action cannot be undone. Already finished/cancelled task(s) will be ignored. Do you want to proceed?"; + dialog.content = this.getTaskCancelConfirmContent; + dialog.submit = this.cancelTasks; + dialog.width = '55vw'; + dialog.showIcon = false; + this.setState({ dialog: dialog, dialogVisible: true }); + } + } } + /** * Function to show confirmation dialog before marking task as obsolete */ - confirmObsoleteTasks() { + confirmObsoleteTasks() { this.pageUpdated = false; let selectedBlueprints = this.selectedRows.filter(task => { return task.tasktype === 'Blueprint' @@ -695,7 +697,7 @@ export class TaskList extends Component { dialog.header = "Cancel Task(s) Status"; dialog.actions = [{ id: 'no', title: 'Ok', callback: this.closeDialog }]; dialog.detail = "" - dialog.content = this.getObsTaskStatusContent; + dialog.content = this.getCancelTaskStatusContent; dialog.submit = this.closeDialog; dialog.width = '55vw'; dialog.showIcon = false; @@ -710,10 +712,11 @@ export class TaskList extends Component { const blueprintWithoutObsolete = _.difference(this.selectedRows, this.state.blueprintsWithObsolete); let obsoleteTasks = [] for (const selectedTask of blueprintWithoutObsolete) { - const obsTask = await TaskService.obsoleteTask(selectedTask.id); + const obsTask = await TaskService.markTaskObsolete(selectedTask.id); let task = _.find(tasks, {'id': selectedTask.id, tasktype: 'Blueprint'}); if (obsTask) { task.status = obsTask.status; + task.obsolete_since = obsTask.obsolete_since ; } obsoleteTasks.push({ id: task.id, suId: task.schedulingUnitId, suName: task.schedulingUnitName, @@ -914,11 +917,8 @@ export class TaskList extends Component { tasks = await this.formatDataProduct(tasks); let actions = []; if(task_blueprint && task_draft){ - if(taskType === 'draft'){ - actions = [{icon: 'fa fa-ban', - title: task_draft.canceltask?'Cancel Task(s)': `${this.access_denied_message} to cancel Task(s)`, - disabled: task_draft.canceltask? !task_draft.canceltask: true, - type: 'button', actOn: 'click', props: { callback: this.confirmCancelTasks }}, + if(taskType === 'Draft'){ + actions = [ {icon: 'fa fa-trash', title: task.delete?'Delete Task(s)':`${this.access_denied_message} to delete Task(s)`, disabled: task.delete? !task.delete: true, @@ -930,7 +930,7 @@ export class TaskList extends Component { title: task_blueprint.canceltask?'Cancel Task(s)': `${this.access_denied_message} to cancel Task(s)`, disabled: task_blueprint.canceltask? !task_blueprint.canceltask: true, type: 'button', actOn: 'click', props: { callback: this.confirmCancelTasks }}, - {icon: 'fa fa-bullseye', + {icon: 'fa-times-circle', iconType:'far', title: task.edit?'Mark as Obsolete': `${this.access_denied_message}`, disabled: task.edit? !task.edit: true, type: 'button', actOn: 'click', props: { callback: this.confirmObsoleteTasks }}, 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 c8dee333f5f1ff56801a4de0ad7413c04408828f..7216149a447c906ba7ca4b5559eb03139151e723 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Task/view.js +++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Task/view.js @@ -86,7 +86,7 @@ export class TaskView extends Component { optionalcolumns: [{ }], subtasks:[], - obsoleteTasks:[],cancelledTasks:[], + obsoleteTasks:[],cancelledSubtasks:[], columnclassname: [{ "Duration (Days HH:mm:ss)":"filter-input-75", "Subtask Type":"filter-input-125", @@ -112,15 +112,16 @@ export class TaskView extends Component { this.getFilterOptions = this.getFilterOptions.bind(this); this.cancelView = this.cancelView.bind(this); this.showObsoleteConfirmation = this.showObsoleteConfirmation.bind(this); - this.obsoleteTask = this.obsoleteTask.bind(this); + this.markTaskObsolete = this.markTaskObsolete.bind(this); this.onRowSelection=this.onRowSelection.bind(this); this.showSubtaskCancelConfirmation=this.showSubtaskCancelConfirmation.bind(this); this.cancelSubtasks=this.cancelSubtasks.bind(this); this.getSubtaskCancelConfirmContent = this.getSubtaskCancelConfirmContent.bind(this); this.showSubtaskObsoleteConfirmation=this.showSubtaskObsoleteConfirmation.bind(this); - this.obsoleteSubtasks=this.obsoleteSubtasks.bind(this); - this.getSubTaskObsoleteConfirmContent = this.getSubTaskObsoleteConfirmContent.bind(this); - this.getSubtaskobsStatusContent = this.getSubtaskobsStatusContent.bind(this); + this.markSubtasksObsolete=this.markSubtasksObsolete.bind(this); + this.getSubtaskObsoleteConfirmContent = this.getSubtaskObsoleteConfirmContent.bind(this); + this.getSubtaskObsoleteStatusContent = this.getSubtaskObsoleteStatusContent.bind(this); + this.getSubtaskCancelStatusContent = this.getSubtaskCancelStatusContent.bind(this); if (this.props.match.params.id) { this.state.taskId = this.props.match.params.id; } @@ -129,19 +130,6 @@ export class TaskView extends Component { } } - // static getDerivedStateFromProps(nextProps, prevstate){ - // console.log("DERIVED STATE FROM PROPS"); - // console.log(nextProps); - // console.log(prevstate); - // if (prevstate.task && nextProps.match.params && - // (nextProps.match.params.id === prevstate.task.id || - // nextProps.match.params.type === prevstate.taskType)) { - // return {taskId: prevstate.task.id, taskType: prevstate.taskType} - // } - // console.log("RETURNS NULL"); - // return null; - // } - onRowSelection(selectedRows) { this.selectedRows = selectedRows; } @@ -304,7 +292,7 @@ export class TaskView extends Component { } closeDialog() { - this.setState({confirmDialogVisible: false,obsoleteTasks:[],cancelledTasks:[]}); + this.setState({confirmDialogVisible: false,obsoleteTasks:[],cancelledSubtasks:[]}); } cancelView(){ @@ -360,45 +348,64 @@ export class TaskView extends Component { showObsoleteConfirmation() { let dialog = this.state.dialog; dialog.type = "confirmation"; - dialog.header = "Confirm to Obsolete Task"; - dialog.actions = [{ id: 'yes', title: 'Yes', callback: this.obsoleteTask }, + dialog.header = "Confirm to mark task as obsolete"; + dialog.actions = [{ id: 'yes', title: 'Yes', callback: this.markTaskObsolete }, { id: 'no', title: 'No', callback: this.closeDialog }]; dialog.detail = "Warning: Obsolete tasks will not be copied and dataproducts will not be used for pipelines and ingest. Are you sure you want to make the task obsolete?"; dialog.content = ''; - dialog.submit = this.obsoleteTask; + dialog.submit = this.markTaskObsolete; dialog.width = '40vw'; dialog.showIcon = true; this.setState({ dialog: dialog, confirmDialogVisible: true }); } /** - * Show confirmation dialog before marking subtask as obsolete + * Show confirmation dialog content while cancelling subtask. + * @returns component */ getSubtaskCancelConfirmContent() { let selectedTasks = []; - for (const obj of this.selectedRows) { - selectedTasks.push({ + let ignoredTasks = []; + for (const obj of this.selectedRows) { + if (obj.status !== 'cancelled') { + selectedTasks.push({ id: obj.id, type: obj.type, status: obj.status - }); + }); + } else { + ignoredTasks.push({ + id: obj.id, type: obj.type, status: obj.status + }); + } } this.selectedRows = []; return <> + {selectedTasks.length > 0 && <div style={{marginTop: '1em'}}> - <b>Task(s) that can be cancelled</b> + <b>Subtask(s) that can be cancelled</b> <DataTable value={selectedTasks} resizableColumns columnResizeMode="expand" className="card" style={{ paddingLeft: '0em' }}> <Column field="id" header="Subtask Id"></Column> <Column field="type" header="Type"></Column> <Column field="status" header="Status"></Column> </DataTable> + </div>} + {ignoredTasks.length > 0 && + <div style={{marginTop: '1em'}}> + <b>Subtask(s) already cancelled will be ignored</b> + <DataTable value={ignoredTasks} resizableColumns columnResizeMode="expand" className="card" style={{ paddingLeft: '0em' }}> + <Column field="id" header="Subtask Id"></Column> + <Column field="type" header="Type"></Column> + <Column field="status" header="Status"></Column> + </DataTable> </div> + } </> } /** * Content for confirmation dialog to mark subtask as obsolete */ - getSubTaskObsoleteConfirmContent() { + getSubtaskObsoleteConfirmContent() { const subtaskWithObsolete = this.state.subtaskWithObsolete; const subtaskWithoutObsolete = _.difference(this.selectedRows, subtaskWithObsolete); let selectedSubtaskWithObsolete = []; @@ -417,29 +424,59 @@ export class TaskView extends Component { return <> <div style={{marginTop: '1em'}}> - <b>Sub Task(s) that can be marked as obsolete’ if task has null for obsolete_since.</b> - <p>Sub Task(s) that are marked as obsolete already will be ignored’ if task has value for obsolete_since.</p> - {selectedSubtaskWithObsolete.length>0 && - <DataTable value={selectedSubtaskWithObsolete} resizableColumns columnResizeMode="expand" className="card" style={{ paddingLeft: '0em' }}> - <Column field="id" header="Subtask Id"></Column> - <Column field="type" header="Type"></Column> - <Column field="status" header="Status"></Column> - </DataTable>} {selectedSubtasksWithoutObsolete.length>0 && - <DataTable value={selectedSubtasksWithoutObsolete} resizableColumns columnResizeMode="expand" className="card" style={{ paddingLeft: '0em' }}> + <> + <b>Subtask(s) that can be marked as obsolete</b> + <DataTable value={selectedSubtasksWithoutObsolete} resizableColumns columnResizeMode="expand" className="card" style={{ paddingLeft: '0em' }}> + <Column field="id" header="Subtask Id"></Column> + <Column field="type" header="Type"></Column> + <Column field="status" header="Status"></Column> + </DataTable> + </>} + {selectedSubtaskWithObsolete.length>0 && + <> + <b>Subtask(s) already marked as obsolete will be ignored</b> + <DataTable value={selectedSubtaskWithObsolete} resizableColumns columnResizeMode="expand" className="card" style={{ paddingLeft: '0em' }}> + <Column field="id" header="Subtask Id"></Column> + <Column field="type" header="Type"></Column> + <Column field="status" header="Status"></Column> + </DataTable> + </>} + + </div> + </> + } + + /** + * Content for status dialog after cancelling subtask + */ + getSubtaskCancelStatusContent () { + let selectedTasks = []; + for (const obj of this.state.cancelledSubtasks) { + selectedTasks.push({ + id: obj.id, type: obj.type, status: obj.status + }) + + } + this.selectedRows = []; + + return <> + {selectedTasks.length > 0 && + <div style={{marginTop: '1em'}}> + <DataTable value={selectedTasks} resizableColumns columnResizeMode="expand" className="card" style={{ paddingLeft: '0em' }}> <Column field="id" header="Subtask Id"></Column> <Column field="type" header="Type"></Column> <Column field="status" header="Status"></Column> - </DataTable>} - </div> + </DataTable> + </div>} </> } + /** * Content for status dialog after marking subtask as obsolete */ - getSubtaskobsStatusContent() { - this.selectedRows = []; - + getSubtaskObsoleteStatusContent() { + this.selectedRows = []; return <> <div style={{marginTop: '1em'}}> <DataTable value={this.state.obsoleteTasks} resizableColumns columnResizeMode="expand" className="card" style={{ paddingLeft: '0em' }}> @@ -451,16 +488,19 @@ export class TaskView extends Component { </> } + /** + * Function that cancels the subtask and set content to show in status dialog + */ async cancelSubtasks() { let subtasks = this.state.subtaskRowList; - let cancelledTasks = [] - for (const selectedTask of this.selectedRows) { - const cancelledTask = await TaskService.cancelsubTask(selectedTask.id); + let cancelledSubtasks = []; + for (const selectedTask of this.state.selectedSubtasks) { + const cancelledTask = await TaskService.cancelSubtask(selectedTask.id); let task = _.find(subtasks, {'id': selectedTask.id}); if (cancelledTask) { task.status = cancelledTask.state_value; } - cancelledTasks.push({ + cancelledSubtasks.push({ id: task.id, type: task.type, status: task.status.toLowerCase()==='cancelled'?'Cancelled': 'Error Occured' @@ -468,35 +508,36 @@ export class TaskView extends Component { } let dialog = this.state.dialog; dialog.type = "confirmation"; - dialog.header = "Cancel Task(s) Status"; + dialog.header = "Cancel subtask(s) - Status"; dialog.actions = [{ id: 'no', title: 'Ok', callback: this.closeDialog }]; dialog.detail = "" - dialog.content = this.getSubtaskCancelConfirmContent; + dialog.content = this.getSubtaskCancelStatusContent; dialog.submit = this.closeDialog; dialog.width = '55vw'; dialog.showIcon = false; this.selectedRows = []; - this.setState({ subtaskRowList:subtasks, cancelledTasks: cancelledTasks, dialog: dialog, confirmDialogVisible: true }); + this.setState({ subtaskRowList:subtasks, cancelledSubtasks: cancelledSubtasks, dialog: dialog, confirmDialogVisible: true }); } /** * Function to mark subtask as obsolete */ - async obsoleteSubtasks() { + async markSubtasksObsolete() { let subtasks = this.state.subtaskRowList; const subtaskWithoutObsolete = _.difference(this.selectedRows, this.state.subtaskWithObsolete); let obsoleteTasks = [] for (const selectedTask of subtaskWithoutObsolete) { - const obsoleteTask = await TaskService.obsoleteSubtask(selectedTask.id); + const obsoleteTask = await TaskService.markSubtaskObsolete(selectedTask.id); let task = _.find(subtasks, {'id': selectedTask.id}); if (obsoleteTask) { task.status = obsoleteTask.state_value; + task['obsolete'] = obsoleteTask.obsolete_since; } obsoleteTasks.push({ id: task.id, type: task.type, status: task.status.toLowerCase()==='obsolete'?'Obsolete': 'Error Occured', - actionStatus:obsoleteTask?'Success':'Failed' + actionStatus:obsoleteTask && obsoleteTask.obsolete_since?'Success':'Failed' }); } let dialog = this.state.dialog; @@ -504,7 +545,7 @@ export class TaskView extends Component { dialog.header = "Mark Subtask(s) as obsolete - Status"; dialog.actions = [{ id: 'no', title: 'Ok', callback: this.closeDialog }]; dialog.detail = "" - dialog.content = this.getSubtaskobsStatusContent; + dialog.content = this.getSubtaskObsoleteStatusContent; dialog.submit = this.closeDialog; dialog.width = '55vw'; dialog.showIcon = false; @@ -512,39 +553,49 @@ export class TaskView extends Component { this.setState({ subtaskRowList:subtasks, obsoleteTasks: obsoleteTasks, dialog: dialog, confirmDialogVisible: true }); } + /** + * Shows confirmation dialog before cancelling subtask(s) + */ showSubtaskCancelConfirmation() { this.pageUpdated = false; - let selectedBlueprints = this.selectedRows.filter(task => { + let selectedSubtasks = this.selectedRows.filter(task => { return task.status !== 'cancelled'}); - if (selectedBlueprints.length === 0) { + console.log(selectedSubtasks); + if (this.selectedRows.length === 0) { appGrowl.show({ severity: 'info', summary: 'Select Row', - detail: 'Please Select atleast one Subtask to cancel or selected task might be cancelled already.' }); + detail: 'Please Select atleast one Subtask to cancel' }); } else { - let dialog = this.state.dialog; - dialog.type = "confirmation"; - dialog.header = "Confirm to Cancel Task(s)"; - dialog.actions = [{ id: 'yes', title: 'Yes', callback: this.cancelSubtasks }, - { id: 'no', title: 'No', callback: this.closeDialog }]; - dialog.detail = "Cancelling the task means, it will no longer be executed / will be aborted. This action cannot be undone. Already finished/cancelled task(s) will be ignored. Do you want to proceed?"; - dialog.content = this.getSubtaskCancelConfirmContent; - dialog.submit = this.cancelSubtasks; - dialog.width = '55vw'; - dialog.showIcon = false; - this.setState({ dialog: dialog, confirmDialogVisible: true }); + if(selectedSubtasks.length === 0) { + appGrowl.show({ severity: 'warn', summary: 'Already Cancelled', + detail: 'Selected subtask(s) are already cancelled' }); + } else { + let dialog = this.state.dialog; + dialog.type = "confirmation"; + dialog.header = "Confirm to cancel Subtask(s)"; + dialog.actions = [{ id: 'yes', title: 'Yes', callback: this.cancelSubtasks }, + { id: 'no', title: 'No', callback: this.closeDialog }]; + dialog.detail = "Cancelling the subtask means, it will no longer be executed / will be aborted. This action cannot be undone. Already finished/cancelled subtask(s) will be ignored. Do you want to proceed?"; + dialog.content = this.getSubtaskCancelConfirmContent; + dialog.submit = this.cancelSubtasks; + dialog.width = '55vw'; + dialog.showIcon = false; + this.setState({ dialog: dialog, confirmDialogVisible: true, selectedSubtasks: selectedSubtasks }); + } } } + /** * Function to show confirmation dialog before marking subtask as obsolete */ showSubtaskObsoleteConfirmation() { this.pageUpdated = false; - let selectedBlueprints = this.selectedRows.filter(task => { + let selectedSubtasks = this.selectedRows.filter(task => { return task.status !== 'obsolete'}); - const subtaskWithObsolete = this.checkObsolete(selectedBlueprints) - const subtaskWithoutObsolete = _.difference(selectedBlueprints, subtaskWithObsolete); - if(selectedBlueprints.length === 0) { + const subtaskWithObsolete = this.checkObsolete(selectedSubtasks) + const subtaskWithoutObsolete = _.difference(selectedSubtasks, subtaskWithObsolete); + if(selectedSubtasks.length === 0) { appGrowl.show({ severity: 'info', summary: 'Select Row', - detail: 'Please select minimum one task to mark as obsolete' }); + detail: 'Please select minimum one subtask to mark as obsolete' }); } else { if (subtaskWithoutObsolete.length === 0) { appGrowl.show({ severity: 'warn', summary: 'Already marked as obsolete', @@ -553,12 +604,12 @@ export class TaskView extends Component { else { let dialog = this.state.dialog; dialog.type = "confirmation"; - dialog.header = "Confirm to mark task as obsolete"; - dialog.actions = [{ id: 'yes', title: 'Yes', callback: this.obsoleteSubtasks }, + dialog.header = "Confirm to mark Subtask(s) as obsolete"; + dialog.actions = [{ id: 'yes', title: 'Yes', callback: this.markSubtasksObsolete }, { id: 'no', title: 'No', callback: this.closeDialog }]; - dialog.detail = "Warning: Obsolete task will not be copied and dataproducts will not be used for pipelines and ingest. Are you sure you want to make the task obsolete?"; - dialog.content = this.getSubTaskObsoleteConfirmContent; - dialog.submit = this.obsoleteSubtasks; + dialog.detail = "Warning: Obsolete subtask will not be copied and dataproducts will not be used for pipelines and ingest. Are you sure you want to make the subtask obsolete?"; + dialog.content = this.getSubtaskObsoleteConfirmContent; + dialog.submit = this.markSubtasksObsolete; dialog.width = '55vw'; dialog.showIcon = false; this.setState({ dialog: dialog, confirmDialogVisible: true, subtaskWithObsolete: subtaskWithObsolete }); @@ -583,22 +634,25 @@ export class TaskView extends Component { this.setState({ confirmDialogVisible: false, task: task, actions: actions}); } } + /** * Function to mark task as obsolete */ - async obsoleteTask() { + async markTaskObsolete() { let task = this.state.task; - let obeslateTask = await TaskService.obsoleteTask(task.id); - if (!obeslateTask.status) { + let obsoleteTask = await TaskService.markTaskObsolete(task.id); + if (!obsoleteTask.status) { appGrowl.show({ severity: 'error', summary: 'error', detail: 'Error while Obsolete Task' }); this.setState({ dialogVisible: false }); } else { - task.status = obeslateTask.status; + task.status = obsoleteTask.status; + task.obsolete_since = obsoleteTask.obsolete_since; let actions = this.state.actions; - appGrowl.show({ severity: 'success', summary: 'Success', detail: 'Task is Obsolete successfully' }); + appGrowl.show({ severity: 'success', summary: 'Success', detail: 'Task is Marked as Obsolete' }); this.setState({ confirmDialogVisible: false, task: task, actions: actions}); } } + /** * Function to check if subtask is marked as obsolete */ @@ -673,7 +727,7 @@ export class TaskView extends Component { this.state.permissionById && this.state.permissionById[this.state.taskId].cancel? false: true, props: { callback: this.showCancelConfirmation } }); - actions.push({icon: 'fa fa-bullseye', + actions.push({icon: 'fa-times-circle', iconType: 'far', title: this.state.task && this.state.task.obsolete_since?'Already marked as obsolete':this.state.permissionById[this.state.taskId] && this.state.permissionById[this.state.taskId].edit?'Mark as Obsolete':`${this.access_denied_message}`, disabled: this.state.task && this.state.task.obsolete_since? true: this.state.permissionById[this.state.taskId] && this.state.permissionById[this.state.taskId].edit?false: true, type: 'button', actOn: 'click', props: { callback: this.showObsoleteConfirmation }}); @@ -701,12 +755,7 @@ export class TaskView extends Component { ); const subtaskMenu=[]; - subtaskMenu.push({icon: 'fa fa-bullseye', - title: 'Mark as Obsolete', - type: 'button', actOn: 'click', props: { callback: this.showSubtaskObsoleteConfirmation }}, - {icon: 'fa fa-ban', - title:'Cancel Sub Tasks', - type: 'button', actOn: 'click', props: { callback: this.showSubtaskCancelConfirmation }}); + subtaskMenu.push() return ( <React.Fragment> @@ -824,9 +873,26 @@ export class TaskView extends Component { } {this.state.taskType === 'blueprint' && <div style={{marginBottom: "10px"}}> - <div style={{marginTop: "10px"}}> - <PageHeader location={this.props.location} title={'Subtasks'} actions={subtaskMenu} /> + <div style={{marginTop: "10px"}}> + <h3>Subtasks</h3> + </div> + <div className="delete-option"> + <div > + <span className="p-float-label"> + <> + <button className="p-link" href="#" style={{ marginLeft: '8px'}} onClick={this.showSubtaskCancelConfirmation} + title={'Cancel Subtasks'} > + <i class={'fa fa-ban'} aria-hidden="true" ></i> + </button> + <button className="p-link" href="#" style={{ marginLeft: '8px'}} onClick={this.showSubtaskObsoleteConfirmation} + title={'Mark as Obsolete'}> + <i class={'far fa-times-circle'} aria-hidden="true" ></i> + </button> + </> + </span> </div> + </div> + <ViewTable data={this.state.subtaskRowList} defaultcolumns={this.state.defaultcolumns} 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 1f7933649b9abf57edb2d8f463004ef9c7a7e79a..d5a4bfb49cac19e379cff7d4725e98b15caf5ff2 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/services/task.service.js +++ b/SAS/TMSS/frontend/tmss_webapp/src/services/task.service.js @@ -310,36 +310,36 @@ const TaskService = { return false; } }, - cancelsubTask: async function(id) { - try { - const url = `/api/subtask/${id}/cancel/`; - const res = await axios.post(url, {}); - return res.data; - } catch(error) { - console.error(error); - return false; - } - }, -obsoleteSubtask: async function(id) { - try { - const url = `/api/subtask/${id}/mark_as_obsolete/`; - const res = await axios.post(url, {}); - return res.data; - } catch(error) { - console.error(error); - return false; - } -}, - obsoleteTask: async function(id) { - try { - const url = `/api/task_blueprint/${id}/mark_as_obsolete`; - const res = await axios.post(url, {}); - return res.data; - } catch(error) { - console.error(error); - return false; - } - }, + cancelSubtask: async function(id) { + try { + const url = `/api/subtask/${id}/cancel/`; + const res = await axios.post(url, {}); + return res.data; + } catch(error) { + console.error(error); + return null; + } + }, + markSubtaskObsolete: async function(id) { + try { + const url = `/api/subtask/${id}/mark_as_obsolete/`; + const res = await axios.post(url, {}); + return res.data; + } catch(error) { + console.error(error); + return null; + } + }, + markTaskObsolete: async function(id) { + try { + const url = `/api/task_blueprint/${id}/mark_as_obsolete/`; + const res = await axios.post(url, {}); + return res.data; + } catch(error) { + console.error(error); + return null; + } + }, getTaskFilterDefinition: async function (type){ let res = []; try {