From 2ad735738ad53a51fe3cdd3d3c29b9fab7c8bb13 Mon Sep 17 00:00:00 2001 From: Muthukrishnanmatriot <76949556+muthukrishnanmatriot@users.noreply.github.com> Date: Thu, 26 Aug 2021 21:33:54 +0530 Subject: [PATCH] TMSS-936 & TMSS-941 - added On/Off switch and filter update --- .../authenticate/permission.stack.handler.js | 10 +- .../src/components/DynamicScheduler.js | 85 +++ .../tmss_webapp/src/routes/Timeline/view.js | 576 ++++++++++-------- .../src/routes/Workflow/workflow.list.js | 1 - .../tmss_webapp/src/services/util.service.js | 31 +- 5 files changed, 430 insertions(+), 273 deletions(-) create mode 100644 SAS/TMSS/frontend/tmss_webapp/src/components/DynamicScheduler.js diff --git a/SAS/TMSS/frontend/tmss_webapp/src/authenticate/permission.stack.handler.js b/SAS/TMSS/frontend/tmss_webapp/src/authenticate/permission.stack.handler.js index 1d1c2be92ec..709589985c0 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/authenticate/permission.stack.handler.js +++ b/SAS/TMSS/frontend/tmss_webapp/src/authenticate/permission.stack.handler.js @@ -44,7 +44,8 @@ const PermissionStackUtil = { task_blueprint: 'task_blueprint', reservation: 'reservation', task_relation_draft: 'task_relation_draft', - task_relation_blueprint: 'task_relation_blueprint' + task_relation_blueprint: 'task_relation_blueprint', + dynamicScheduler: 'setting/dynamic_scheduling_enabled' } const modules = Object.keys(module_url); for(const module of modules) { @@ -115,7 +116,12 @@ const PermissionStackUtil = { edit: allowedPermission?(_.includes(allowedPermission, 'PATCH')):false, delete: allowedPermission?(_.includes(allowedPermission, 'DELETE')):false }; - } + } + else if (module === 'dynamicScheduler') { + permissionStack[module] = { + setting: allowedPermission?(_.includes(allowedPermission, 'PATCH')):false, + }; + } } } permissionStack['workflow'] = { diff --git a/SAS/TMSS/frontend/tmss_webapp/src/components/DynamicScheduler.js b/SAS/TMSS/frontend/tmss_webapp/src/components/DynamicScheduler.js new file mode 100644 index 00000000000..29df7378f83 --- /dev/null +++ b/SAS/TMSS/frontend/tmss_webapp/src/components/DynamicScheduler.js @@ -0,0 +1,85 @@ +import React, { Component } from 'react'; +import UtilService from '../services/util.service'; +import { CustomDialog } from '../layout/components/CustomDialog'; +import { Growl } from 'primereact/components/growl/Growl'; +import { ToggleButton } from 'primereact/togglebutton'; + +export default class DynamicScheduler extends Component { + constructor(props) { + super(props); + this.dailyOptions= []; + this.state= { + dsStatus: false, // Dynamic Scheduler Status + showDialog: false, + } + this.currentStatus = null; + this.updateDSStatus = this.updateDSStatus.bind(this); + this.closeDialog = this.closeDialog.bind(this); + this.showConfirmDialog = this.showConfirmDialog.bind(this); + } + + async componentDidMount(){ + let response = await UtilService.getDynamicSchedulerStatus(); + var status = false; + if(response) { + status = response.value; + } + this.setState({dynamicScheduler: response, dsStatus: status}); + } + + /** + * Update Dynamic Scheduling + */ + async updateDSStatus() { + let dynamicScheduler = this.state.dynamicScheduler; + dynamicScheduler.value = this.currentStatus; + let response = await UtilService.updateDynamicSchedulerStatus(dynamicScheduler); + if(response) { + this.growl.show({severity: 'success', summary: 'Success', detail: 'Dynamic Scheduling Switched '+((this.currentStatus === true)?'On' : 'Off')+' successfully!'}); + } else { + this.growl.show({severity: 'error', summary: 'Error', detail: 'Dynamic Scheduling is not updated successfully.'}); + } + this.setState({dsStatus: this.currentStatus, showDialog: false}); + } + + /** + * Show confirmation dialog to enable/disable Dynamic Scheduling + * @param {*} e + */ + async showConfirmDialog(e) { + this.currentStatus = e.value; + await this.setState({showDialog: true}) + } + + /** + * Close the Confirmation dialog + */ + closeDialog() { + this.setState({showDialog: false}); + } + + render() { + return ( + <> + <Growl ref={(el) => this.growl = el} /> + <div className="p-field p-grid"> + <label htmlFor="autodeletion" style={{marginRight: '10px', marginLeft: '50px'}}>Dynamic Scheduling : </label> + <div data-testid="autodeletion" > + <ToggleButton onLabel="On" offLabel="Off" onIcon="pi pi-check" offIcon="pi pi-times" + checked={this.state.dsStatus} onChange={(e) => this.showConfirmDialog(e)} + tooltip={`Click to ${this.state.dsStatus? "'Switch Off'" : "'Switch On'"} the Dynamic Scheduling`} + tooltipOptions={this.tooltipOptions}/> + + + </div> + </div> + + <CustomDialog type="confirmation" visible={this.state.showDialog} width={'35vw'} + header={'Confirmation'} message={`Are you sure want to switch ${this.currentStatus === true ? 'On' : 'Off'} the Dynamic Scheduling?` } + content={''} showIcon={true} + onClose={this.closeDialog} onCancel={this.closeDialog} onSubmit={this.updateDSStatus} + /> + </> + ); + } +} \ No newline at end of file diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/view.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/view.js index 1faf0cf5704..2dd9e702b34 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/view.js +++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/view.js @@ -9,6 +9,7 @@ import { InputSwitch } from 'primereact/inputswitch'; import AppLoader from '../../layout/components/AppLoader'; import PageHeader from '../../layout/components/PageHeader'; +import { CustomDialog } from '../../layout/components/CustomDialog'; import Timeline from '../../components/Timeline'; import ScheduleService from '../../services/schedule.service'; @@ -30,6 +31,7 @@ import TimelineListTabs from './list.tabs'; import TimelineCommonUtils from './common.utils'; import AuthStore from '../../authenticate/auth.store'; import AuthUtil from '../../utils/auth.util'; +import DynamicScheduler from '../../components/DynamicScheduler'; //import { TRUE } from 'node-sass'; @@ -90,7 +92,8 @@ export class TimelineView extends Component { showReservation: this.timelineUIAttributes.showReservation || false, // Flag to show reservations in normal timeline view userrole: AuthStore.getState(), suStatusList: [], - taskStatusList: [] + taskStatusList: [], + showDialog: false, } this.STATUS_BEFORE_SCHEDULED = ['defining', 'defined', 'schedulable']; // Statuses before scheduled to get station_group this.allStationsGroup = []; @@ -123,6 +126,8 @@ export class TimelineView extends Component { this.setGroupByProject = this.setGroupByProject.bind(this); this.changeViewBlocks = this.changeViewBlocks.bind(this); this.showReservationBlocks = this.showReservationBlocks.bind(this); + this.showDymanicSchedulerPopup = this.showDymanicSchedulerPopup.bind(this); + this.close = this.close.bind(this); } async componentDidMount() { @@ -1099,7 +1104,22 @@ export class TimelineView extends Component { this.setState({suStatusList: suStatusList, taskStatusList: taskStatusList}); } + /** + * Show Dynamic Scheduling popup + */ + showDymanicSchedulerPopup(){ + this.setState({showDialog: true}); + } + + /** + * Close Dynamic Scheduling popup + */ + close() { + this.setState({showDialog: false}); + } + render() { + const {dynamicScheduler} = this.state.userrole.userRolePermission; if (this.state.redirect) { return <Redirect to={{ pathname: this.state.redirect }}></Redirect> } @@ -1124,290 +1144,308 @@ export class TimelineView extends Component { let mouseOverItem = this.state.mouseOverItem; return ( <React.Fragment> - <TieredMenu className="app-header-menu" model={this.state.menuOptions} popup ref={el => this.optionsMenu = el} /> - <PageHeader location={this.props.location} title={'Scheduling Units - Timeline View'} - actions={[ - { icon: 'fa-bars', title: '', - type: 'button', actOn: 'mouseOver', props: { callback: this.showOptionMenu }, }, - { icon: 'fa-calendar-alt', title: 'Week View', props: { pathname: `/su/timelineview/week` } } - ]} - /> - { this.state.isLoading ? <AppLoader /> : - <div className="p-grid"> - {/* SU List Panel */} - <div className={isSUListVisible && (isSUDetsVisible || isReservDetsVisible || isTaskDetsVisible || - (canExtendSUList && !canShrinkSUList) ? "col-lg-4 col-md-4 col-sm-12" : - ((canExtendSUList && canShrinkSUList) ? "col-lg-5 col-md-5 col-sm-12" : "col-lg-6 col-md-6 col-sm-12"))} - style={isSUListVisible ? { position: "inherit", borderRight: "3px solid #efefef", paddingTop: "10px" } : { display: 'none' }}> - <TimelineListTabs suBlueprintList={this.state.suBlueprintList} - suListFilterCallback={this.suListFilterCallback} - reservationList={this.getReservationList()} - suStatusList={this.state.suStatusList} - taskStatusList={this.state.taskStatusList} - ></TimelineListTabs> - </div> - {/* Timeline Panel */} - <div className={isSUListVisible ? ((isSUDetsVisible || isReservDetsVisible) ? "col-lg-5 col-md-5 col-sm-12" : - (!canExtendSUList && canShrinkSUList) ? "col-lg-6 col-md-6 col-sm-12" : - ((canExtendSUList && canShrinkSUList) ? "col-lg-7 col-md-7 col-sm-12" : "col-lg-8 col-md-8 col-sm-12")) : - ((isSUDetsVisible || isReservDetsVisible || isTaskDetsVisible) ? "col-lg-9 col-md-9 col-sm-12" : "col-lg-12 col-md-12 col-sm-12")} - // style={{borderLeft: "3px solid #efefef"}} - > - {/* Panel Resize buttons */} - {isSUListVisible && - <div className="resize-div"> - <button className="p-link resize-btn" disabled={!this.state.canShrinkSUList} - title="Shrink List/Expand Timeline" - onClick={(e) => { this.resizeSUList(-1) }}> - <i className="pi pi-step-backward"></i> - </button> - <button className="p-link resize-btn" disabled={!this.state.canExtendSUList} - title="Expand List/Shrink Timeline" - onClick={(e) => { this.resizeSUList(1) }}> - <i className="pi pi-step-forward"></i> - </button> + {dynamicScheduler && + <> + <TieredMenu className="app-header-menu" model={this.state.menuOptions} popup ref={el => this.optionsMenu = el} /> + <PageHeader location={this.props.location} title={'Scheduling Units - Timeline View'} + actions={[ + { icon: 'fa-cog', title: dynamicScheduler.setting? 'Switch On/Off the Dynamic Scheduling': `Don't have permission to Switch On/Off the Dynamic Scheduling`, + type: 'button', actOn: 'click', props: { callback: this.showDymanicSchedulerPopup }, + disabled: dynamicScheduler.setting?!dynamicScheduler.setting:true, }, + { icon: 'fa-bars', title: '', + type: 'button', actOn: 'mouseOver', props: { callback: this.showOptionMenu }, }, + { icon: 'fa-calendar-alt', title: 'Week View', props: { pathname: `/su/timelineview/week` } } + ]} + /> + { this.state.isLoading ? <AppLoader /> : + <div className="p-grid"> + {/* SU List Panel */} + <div className={isSUListVisible && (isSUDetsVisible || isReservDetsVisible || isTaskDetsVisible || + (canExtendSUList && !canShrinkSUList) ? "col-lg-4 col-md-4 col-sm-12" : + ((canExtendSUList && canShrinkSUList) ? "col-lg-5 col-md-5 col-sm-12" : "col-lg-6 col-md-6 col-sm-12"))} + style={isSUListVisible ? { position: "inherit", borderRight: "3px solid #efefef", paddingTop: "10px" } : { display: 'none' }}> + <TimelineListTabs suBlueprintList={this.state.suBlueprintList} + suListFilterCallback={this.suListFilterCallback} + reservationList={this.getReservationList()} + suStatusList={this.state.suStatusList} + taskStatusList={this.state.taskStatusList} + ></TimelineListTabs> </div> - } - <div className={isSUListVisible ? "resize-div su-visible" : "resize-div su-hidden"}> - {isSUListVisible && - <button className="p-link resize-btn" - title="Hide List" - onClick={(e) => { this.showListPanel(false) }}> - <i className="pi pi-eye-slash"></i> - </button> - } - {!isSUListVisible && - <button className="p-link resize-btn" - title="Show List" - onClick={(e) => { this.showListPanel(true) }}> - <i className="pi pi-eye"> Show List</i> - </button> - } - </div> - <div className={`timeline-view-toolbar p-grid ${this.state.stationView && 'alignTimeLineHeader'}`}> - <div className="sub-header col-lg-2"> - <label >Station View</label> - <InputSwitch checked={this.state.stationView} onChange={(e) => { this.setStationView(e) }} /> - </div> - {this.state.stationView && - <> - <div className="sub-header col-lg-2"> - <label>Show</label> - <Button className="p-button-rounded toggle-btn" - tooltip={this.state.isStationTasksVisible?"Show Scheduling Units":"Show Tasks"} - style={{minWidth: "50px"}} - label={this.state.isStationTasksVisible?"SUs":"Tasks"} - onClick={e => this.changeViewBlocks()} /> - </div> - <div className="sub-header col-lg-4"> - <label style={{ marginLeft: '20px' }}>Stations Group</label> - <MultiSelect data-testid="stations" id="stations" optionLabel="value" optionValue="value" - style={{ top: '2px', width: '175px' }} - tooltip="Select Stations" - value={this.state.selectedStationGroup} - options={this.mainStationGroupOptions} - placeholder="Select Group" - onChange={(e) => this.setSelectedStationGroup(e.value)} - /> - </div> - </> - } - {!this.state.stationView && - <> - <div className="sub-header col-lg-5"> - <div className={`sub-header-content ${isSUListVisible?"col-lg-12":"col-lg-8"}`} style={{padding: '0px !important'}}> - <fieldset> - <label style={{ marginLeft: '0px' }}>Show :</label> - <input type="radio" value="su" name="Only SUs" className="timeline-toolbar-radio" inputId="suOnly" onClick={(e) => this.showTimelineItems(e.target.value)} checked={this.state.showSUs && !this.state.showTasks} /> - <label htmlFor="suOnly">Only SU</label> - <input type="radio" value="task" name="Only Tasks" className="timeline-toolbar-radio" inputId="taskOnly" onChange={(e) => this.showTimelineItems(e.target.value)} checked={!this.state.showSUs && this.state.showTasks} /> - <label htmlFor="suOnly">Only Task</label> - <input type="radio" value="suTask" name="Both" className="timeline-toolbar-radio" inputId="bothSuTask" onChange={(e) => this.showTimelineItems(e.target.value)} checked={this.state.showSUs && this.state.showTasks} /> - <label htmlFor="suOnly">Both</label> - </fieldset> + {/* Timeline Panel */} + <div className={isSUListVisible ? ((isSUDetsVisible || isReservDetsVisible) ? "col-lg-5 col-md-5 col-sm-12" : + (!canExtendSUList && canShrinkSUList) ? "col-lg-6 col-md-6 col-sm-12" : + ((canExtendSUList && canShrinkSUList) ? "col-lg-7 col-md-7 col-sm-12" : "col-lg-8 col-md-8 col-sm-12")) : + ((isSUDetsVisible || isReservDetsVisible || isTaskDetsVisible) ? "col-lg-9 col-md-9 col-sm-12" : "col-lg-12 col-md-12 col-sm-12")} + // style={{borderLeft: "3px solid #efefef"}} + > + {/* Panel Resize buttons */} + {isSUListVisible && + <div className="resize-div"> + <button className="p-link resize-btn" disabled={!this.state.canShrinkSUList} + title="Shrink List/Expand Timeline" + onClick={(e) => { this.resizeSUList(-1) }}> + <i className="pi pi-step-backward"></i> + </button> + <button className="p-link resize-btn" disabled={!this.state.canExtendSUList} + title="Expand List/Shrink Timeline" + onClick={(e) => { this.resizeSUList(1) }}> + <i className="pi pi-step-forward"></i> + </button> </div> - {this.state.showTasks && - <div className={`sub-header-content ${isSUListVisible?"col-lg-12":"col-lg-3"}`} style={{padding: '0px !important', marginLeft: `${isSUListVisible?"50px":"0px"}`}}> - <MultiSelect data-testid="tasks" id="tasks" optionLabel="value" optionValue="value" - style={{ width: '120px', height: '25px', marginRight: '10px' }} - tooltip={this.state.selectedTaskTypes.length>0? - `Showing tasks of task type(s) ${this.state.selectedTaskTypes.join(', ')}`: - "Select task type(s) to show in the timeline"} - maxSelectedLabels="1" - selectedItemsLabel="{0} Task Types" - value={this.state.selectedTaskTypes} - options={this.state.taskTypes} - placeholder="Task Type" - onChange={(e) => {this.setSelectedTaskTypes(e.value)}} - /> - </div> + } + <div className={isSUListVisible ? "resize-div su-visible" : "resize-div su-hidden"}> + {isSUListVisible && + <button className="p-link resize-btn" + title="Hide List" + onClick={(e) => { this.showListPanel(false) }}> + <i className="pi pi-eye-slash"></i> + </button> + } + {!isSUListVisible && + <button className="p-link resize-btn" + title="Show List" + onClick={(e) => { this.showListPanel(true) }}> + <i className="pi pi-eye"> Show List</i> + </button> } </div> - <div className="sub-header col-lg-2" style={{paddingTop: "15px !important"}}> - {this.state.groupByProject && - <Button className="p-button-rounded toggle-btn" label="Group By SU" onClick={e => this.setGroupByProject(false)} />} - {!this.state.groupByProject && - <Button className="p-button-rounded toggle-btn" label="Group By Project" onClick={e => this.setGroupByProject(true)} />} - </div> - </> - } - <div className="sub-header col-lg-3"> - {!this.state.stationView && - <Button className="p-button-rounded toggle-btn" - tooltip={this.state.showReservation?"Hide Reservations":"Show Reservations"} - style={{minWidth: "50px"}} - label={this.state.showReservation?"Hide Reservation":"Show Reservation"} - onClick={e => this.showReservationBlocks()} /> - } - { this.state.stationView && - <label style={{ marginLeft: '20px' }}>Reservation</label> - } - { (this.state.stationView || this.state.showReservation) && + <div className={`timeline-view-toolbar p-grid ${this.state.stationView && 'alignTimeLineHeader'}`}> + <div className="sub-header col-lg-2"> + <label >Station View</label> + <InputSwitch checked={this.state.stationView} onChange={(e) => { this.setStationView(e) }} /> + </div> + {this.state.stationView && <> - <MultiSelect data-testid="reserv-reasons" id="reserv-reasons" - optionLabel="name" optionValue="name" - style={{ top: '2px', marginLeft:'5px', minWidth: '100px' }} - panelStyle={{right: '0px'}} - tooltip="Select Reservation Reason(s)" - value={this.state.reservationFilter} - options={this.reservationReasons} - maxSelectedLabels="1" - filter showClear={true} filterBy="name" - placeholder="Reason" - onChange={(e) => this.setReservationFilter(e.value)} - /> + <div className="sub-header col-lg-2"> + <label>Show</label> + <Button className="p-button-rounded toggle-btn" + tooltip={this.state.isStationTasksVisible?"Show Scheduling Units":"Show Tasks"} + style={{minWidth: "50px"}} + label={this.state.isStationTasksVisible?"SUs":"Tasks"} + onClick={e => this.changeViewBlocks()} /> + </div> + <div className="sub-header col-lg-4"> + <label style={{ marginLeft: '20px' }}>Stations Group</label> + <MultiSelect data-testid="stations" id="stations" optionLabel="value" optionValue="value" + style={{ top: '2px', width: '175px' }} + tooltip="Select Stations" + value={this.state.selectedStationGroup} + options={this.mainStationGroupOptions} + placeholder="Select Group" + onChange={(e) => this.setSelectedStationGroup(e.value)} + /> + </div> </> - } - </div> + } + {!this.state.stationView && + <> + <div className="sub-header col-lg-5"> + <div className={`sub-header-content ${isSUListVisible?"col-lg-12":"col-lg-8"}`} style={{padding: '0px !important'}}> + <fieldset> + <label style={{ marginLeft: '0px' }}>Show :</label> + <input type="radio" value="su" name="Only SUs" className="timeline-toolbar-radio" inputId="suOnly" onClick={(e) => this.showTimelineItems(e.target.value)} checked={this.state.showSUs && !this.state.showTasks} /> + <label htmlFor="suOnly">Only SU</label> + <input type="radio" value="task" name="Only Tasks" className="timeline-toolbar-radio" inputId="taskOnly" onChange={(e) => this.showTimelineItems(e.target.value)} checked={!this.state.showSUs && this.state.showTasks} /> + <label htmlFor="suOnly">Only Task</label> + <input type="radio" value="suTask" name="Both" className="timeline-toolbar-radio" inputId="bothSuTask" onChange={(e) => this.showTimelineItems(e.target.value)} checked={this.state.showSUs && this.state.showTasks} /> + <label htmlFor="suOnly">Both</label> + </fieldset> + </div> + {this.state.showTasks && + <div className={`sub-header-content ${isSUListVisible?"col-lg-12":"col-lg-3"}`} style={{padding: '0px !important', marginLeft: `${isSUListVisible?"50px":"0px"}`}}> + <MultiSelect data-testid="tasks" id="tasks" optionLabel="value" optionValue="value" + style={{ width: '120px', height: '25px', marginRight: '10px' }} + tooltip={this.state.selectedTaskTypes.length>0? + `Showing tasks of task type(s) ${this.state.selectedTaskTypes.join(', ')}`: + "Select task type(s) to show in the timeline"} + maxSelectedLabels="1" + selectedItemsLabel="{0} Task Types" + value={this.state.selectedTaskTypes} + options={this.state.taskTypes} + placeholder="Task Type" + onChange={(e) => {this.setSelectedTaskTypes(e.value)}} + /> + </div> + } + </div> + <div className="sub-header col-lg-2" style={{paddingTop: "15px !important"}}> + {this.state.groupByProject && + <Button className="p-button-rounded toggle-btn" label="Group By SU" onClick={e => this.setGroupByProject(false)} />} + {!this.state.groupByProject && + <Button className="p-button-rounded toggle-btn" label="Group By Project" onClick={e => this.setGroupByProject(true)} />} + </div> + </> + } + <div className="sub-header col-lg-3"> + {!this.state.stationView && + <Button className="p-button-rounded toggle-btn" + tooltip={this.state.showReservation?"Hide Reservations":"Show Reservations"} + style={{minWidth: "50px"}} + label={this.state.showReservation?"Hide Reservation":"Show Reservation"} + onClick={e => this.showReservationBlocks()} /> + } + { this.state.stationView && + <label style={{ marginLeft: '20px' }}>Reservation</label> + } + { (this.state.stationView || this.state.showReservation) && + <> + <MultiSelect data-testid="reserv-reasons" id="reserv-reasons" + optionLabel="name" optionValue="name" + style={{ top: '2px', marginLeft:'5px', minWidth: '100px' }} + panelStyle={{right: '0px'}} + tooltip="Select Reservation Reason(s)" + value={this.state.reservationFilter} + options={this.reservationReasons} + maxSelectedLabels="1" + filter showClear={true} filterBy="name" + placeholder="Reason" + onChange={(e) => this.setReservationFilter(e.value)} + /> + </> + } + </div> - </div> + </div> - <Timeline ref={(tl) => { this.timeline = tl }} - defaultStartTime={this.state.currentStartTime} - defaultEndTime={this.state.currentEndTime} - group={this.state.group} - items={this.state.items} - currentUTC={this.state.currentUTC} - rowHeight={this.state.stationView ? 50 : 50} - sidebarWidth={!this.state.showSUs ? 250 : 200} - itemClickCallback={this.onItemClick} - itemMouseOverCallback={this.onItemMouseOver} - itemMouseOutCallback={this.onItemMouseOut} - dateRangeCallback={this.dateRangeCallback} - showSunTimings={!this.state.stationView} - timelineCommonUtils={this.timelineCommonUtils} - timelineUIAttributes={this.timelineUIAttributes} - // stackItems ={this.state.stationView} - stackItems - className="timeline-toolbar-margin-top-0"></Timeline> - </div> - {/* Details Panel */} - {this.state.isSUDetsVisible && - <div className="col-lg-3 col-md-3 col-sm-12" - style={{ borderLeft: "1px solid #efefef", marginTop: "0px", backgroundColor: "#f2f2f2" }}> - {this.state.isSummaryLoading ? <AppLoader /> : - <SchedulingUnitSummary schedulingUnit={suBlueprint} suTaskList={this.state.suTaskList} - viewInNewWindow - constraintsTemplate={this.state.suConstraintTemplate} - stationGroup={this.state.stationGroup} - closeCallback={this.closeSUDets}></SchedulingUnitSummary> + <Timeline ref={(tl) => { this.timeline = tl }} + defaultStartTime={this.state.currentStartTime} + defaultEndTime={this.state.currentEndTime} + group={this.state.group} + items={this.state.items} + currentUTC={this.state.currentUTC} + rowHeight={this.state.stationView ? 50 : 50} + sidebarWidth={!this.state.showSUs ? 250 : 200} + itemClickCallback={this.onItemClick} + itemMouseOverCallback={this.onItemMouseOver} + itemMouseOutCallback={this.onItemMouseOut} + dateRangeCallback={this.dateRangeCallback} + showSunTimings={!this.state.stationView} + timelineCommonUtils={this.timelineCommonUtils} + timelineUIAttributes={this.timelineUIAttributes} + // stackItems ={this.state.stationView} + stackItems + className="timeline-toolbar-margin-top-0"></Timeline> + </div> + {/* Details Panel */} + {this.state.isSUDetsVisible && + <div className="col-lg-3 col-md-3 col-sm-12" + style={{ borderLeft: "1px solid #efefef", marginTop: "0px", backgroundColor: "#f2f2f2" }}> + {this.state.isSummaryLoading ? <AppLoader /> : + <SchedulingUnitSummary schedulingUnit={suBlueprint} suTaskList={this.state.suTaskList} + viewInNewWindow + constraintsTemplate={this.state.suConstraintTemplate} + stationGroup={this.state.stationGroup} + closeCallback={this.closeSUDets}></SchedulingUnitSummary> + } + </div> } - </div> - } - {this.state.isTaskDetsVisible && - <div className="col-lg-3 col-md-3 col-sm-12" - style={{ borderLeft: "1px solid #efefef", marginTop: "0px", backgroundColor: "#f2f2f2" }}> - {this.state.isSummaryLoading ? <AppLoader /> : - <div>Yet to be developed <i className="fa fa-times" onClick={this.closeSUDets}></i></div> + {this.state.isTaskDetsVisible && + <div className="col-lg-3 col-md-3 col-sm-12" + style={{ borderLeft: "1px solid #efefef", marginTop: "0px", backgroundColor: "#f2f2f2" }}> + {this.state.isSummaryLoading ? <AppLoader /> : + <div>Yet to be developed <i className="fa fa-times" onClick={this.closeSUDets}></i></div> + } + </div> } - </div> - } - {this.state.isReservDetsVisible && - <div className="col-lg-3 col-md-3 col-sm-12" - style={{ borderLeft: "1px solid #efefef", marginTop: "0px", backgroundColor: "#f2f2f2" }}> - {this.state.isSummaryLoading ? <AppLoader /> : - <ReservationSummary reservation={reservation} viewInNewWindow={true} - closeCallback={this.closeSUDets}></ReservationSummary> + {this.state.isReservDetsVisible && + <div className="col-lg-3 col-md-3 col-sm-12" + style={{ borderLeft: "1px solid #efefef", marginTop: "0px", backgroundColor: "#f2f2f2" }}> + {this.state.isSummaryLoading ? <AppLoader /> : + <ReservationSummary reservation={reservation} viewInNewWindow={true} + closeCallback={this.closeSUDets}></ReservationSummary> + } + </div> } </div> - } - </div> - } - {/* SU Item Tooltip popover with SU status color */} - <OverlayPanel className="timeline-popover" ref={(el) => this.popOver = el} dismissable> - {(mouseOverItem && (["SCHEDULE", "TASK", "STATION_TASK"].indexOf(mouseOverItem.type) >= 0)) && - <div className={`p-grid su-${mouseOverItem.status}`} style={{ width: '350px' }}> - <h3 className={`col-12 su-${mouseOverItem.status}-icon`}>{mouseOverItem.type === 'SCHEDULE' ? 'Scheduling Unit ' : 'Task '}Overview</h3> - <hr></hr> - <label className={`col-5 su-${mouseOverItem.status}-icon`}>Project:</label> - <div className="col-7">{mouseOverItem.project}</div> - <label className={`col-5 su-${mouseOverItem.status}-icon`}>Scheduling Unit:</label> - <div className="col-7">{mouseOverItem.suName}</div> - {mouseOverItem.type === 'SCHEDULE' && - <> + } + {/* SU Item Tooltip popover with SU status color */} + <OverlayPanel className="timeline-popover" ref={(el) => this.popOver = el} dismissable> + {(mouseOverItem && (["SCHEDULE", "TASK", "STATION_TASK"].indexOf(mouseOverItem.type) >= 0)) && + <div className={`p-grid su-${mouseOverItem.status}`} style={{ width: '350px' }}> + <h3 className={`col-12 su-${mouseOverItem.status}-icon`}>{mouseOverItem.type === 'SCHEDULE' ? 'Scheduling Unit ' : 'Task '}Overview</h3> + <hr></hr> + <label className={`col-5 su-${mouseOverItem.status}-icon`}>Project:</label> + <div className="col-7">{mouseOverItem.project}</div> + <label className={`col-5 su-${mouseOverItem.status}-icon`}>Scheduling Unit:</label> + <div className="col-7">{mouseOverItem.suName}</div> + {mouseOverItem.type === 'SCHEDULE' && + <> - <label className={`col-5 su-${mouseOverItem.status}-icon`}>Scheduler:</label> - <div className="col-7">{mouseOverItem.scheduleMethod}</div> - <label className={`col-5 su-${mouseOverItem.status}-icon`}>Friends:</label> - <div className="col-7">{mouseOverItem.friends ? mouseOverItem.friends : "-"}</div> - </>} - { (mouseOverItem.type === 'TASK' || mouseOverItem.type === 'STATION_TASK') && - <> - <label className={`col-5 su-${mouseOverItem.status}-icon`}>Task Name:</label> + <label className={`col-5 su-${mouseOverItem.status}-icon`}>Scheduler:</label> + <div className="col-7">{mouseOverItem.scheduleMethod}</div> + <label className={`col-5 su-${mouseOverItem.status}-icon`}>Friends:</label> + <div className="col-7">{mouseOverItem.friends ? mouseOverItem.friends : "-"}</div> + </>} + { (mouseOverItem.type === 'TASK' || mouseOverItem.type === 'STATION_TASK') && + <> + <label className={`col-5 su-${mouseOverItem.status}-icon`}>Task Name:</label> + <div className="col-7">{mouseOverItem.name}</div> + </>} + <label className={`col-5 su-${mouseOverItem.status}-icon`}>Start Time:</label> + <div className="col-7">{mouseOverItem.start_time.format(UIConstants.CALENDAR_DATETIME_FORMAT)}</div> + <label className={`col-5 su-${mouseOverItem.status}-icon`}>End Time:</label> + <div className="col-7">{mouseOverItem.end_time.format(UIConstants.CALENDAR_DATETIME_FORMAT)}</div> + {mouseOverItem.type === 'SCHEDULE' && + <> + <label className={`col-5 su-${mouseOverItem.status}-icon`}>Antenna Set:</label> + <div className="col-7">{mouseOverItem.antennaSet}</div> + </>} + <label className={`col-5 su-${mouseOverItem.status}-icon`}>Stations:</label> + <div className="col-7">{mouseOverItem.stations.groups}:{mouseOverItem.stations.counts}</div> + <label className={`col-5 su-${mouseOverItem.status}-icon`}>Status:</label> + <div className="col-7">{mouseOverItem.status}</div> + <label className={`col-5 su-${mouseOverItem.status}-icon`}>Duration:</label> + <div className="col-7">{mouseOverItem.duration}</div> + </div> + } + {(mouseOverItem && mouseOverItem.type === "RESERVATION") && + <div className={`p-grid`} style={{ width: '350px', backgroundColor: mouseOverItem.bgColor, color: mouseOverItem.color }}> + <h3 className={`col-12`}>Reservation Overview</h3> + <hr></hr> + <label className={`col-5`} style={{ color: mouseOverItem.color }}>Name:</label> <div className="col-7">{mouseOverItem.name}</div> - </>} - <label className={`col-5 su-${mouseOverItem.status}-icon`}>Start Time:</label> - <div className="col-7">{mouseOverItem.start_time.format(UIConstants.CALENDAR_DATETIME_FORMAT)}</div> - <label className={`col-5 su-${mouseOverItem.status}-icon`}>End Time:</label> - <div className="col-7">{mouseOverItem.end_time.format(UIConstants.CALENDAR_DATETIME_FORMAT)}</div> - {mouseOverItem.type === 'SCHEDULE' && - <> - <label className={`col-5 su-${mouseOverItem.status}-icon`}>Antenna Set:</label> - <div className="col-7">{mouseOverItem.antennaSet}</div> - </>} - <label className={`col-5 su-${mouseOverItem.status}-icon`}>Stations:</label> - <div className="col-7">{mouseOverItem.stations.groups}:{mouseOverItem.stations.counts}</div> - <label className={`col-5 su-${mouseOverItem.status}-icon`}>Status:</label> - <div className="col-7">{mouseOverItem.status}</div> - <label className={`col-5 su-${mouseOverItem.status}-icon`}>Duration:</label> - <div className="col-7">{mouseOverItem.duration}</div> - </div> - } - {(mouseOverItem && mouseOverItem.type === "RESERVATION") && - <div className={`p-grid`} style={{ width: '350px', backgroundColor: mouseOverItem.bgColor, color: mouseOverItem.color }}> - <h3 className={`col-12`}>Reservation Overview</h3> - <hr></hr> - <label className={`col-5`} style={{ color: mouseOverItem.color }}>Name:</label> - <div className="col-7">{mouseOverItem.name}</div> - <label className={`col-5`} style={{ color: mouseOverItem.color }}>Description:</label> - <div className="col-7">{mouseOverItem.desc}</div> - <label className={`col-5`} style={{ color: mouseOverItem.color }}>Type:</label> - <div className="col-7">{mouseOverItem.activity_type}</div> - <label className={`col-5`} style={{ color: mouseOverItem.color }}>Stations:</label> - {/* <div className="col-7"><ListBox options={mouseOverItem.stations} /></div> */} - <div className="col-7 station-list"> - {mouseOverItem.stations.map((station, index) => ( - <div key={`stn-${index}`}>{station}</div> - ))} + <label className={`col-5`} style={{ color: mouseOverItem.color }}>Description:</label> + <div className="col-7">{mouseOverItem.desc}</div> + <label className={`col-5`} style={{ color: mouseOverItem.color }}>Type:</label> + <div className="col-7">{mouseOverItem.activity_type}</div> + <label className={`col-5`} style={{ color: mouseOverItem.color }}>Stations:</label> + {/* <div className="col-7"><ListBox options={mouseOverItem.stations} /></div> */} + <div className="col-7 station-list"> + {mouseOverItem.stations.map((station, index) => ( + <div key={`stn-${index}`}>{station}</div> + ))} + </div> + <label className={`col-5`} style={{ color: mouseOverItem.color }}>Project:</label> + <div className="col-7">{mouseOverItem.project ? mouseOverItem.project : "-"}</div> + <label className={`col-5`} style={{ color: mouseOverItem.color }}>Start Time:</label> + <div className="col-7">{mouseOverItem.start_time.format(UIConstants.CALENDAR_DATETIME_FORMAT)}</div> + <label className={`col-5`} style={{ color: mouseOverItem.color }}>End Time:</label> + <div className="col-7">{mouseOverItem.duration!=="Unknown"?mouseOverItem.end_time.format(UIConstants.CALENDAR_DATETIME_FORMAT):"Unknown"}</div> + {/* <label className={`col-5`} style={{color: mouseOverItem.color}}>Stations:</label> + <div className="col-7">{mouseOverItem.stations.groups}:{mouseOverItem.stations.counts}</div> */} + <label className={`col-5`} style={{ color: mouseOverItem.color }}>Duration:</label> + <div className="col-7">{mouseOverItem.duration}</div> + <label className={`col-5`} style={{ color: mouseOverItem.color }}>Planned:</label> + <div className="col-7">{mouseOverItem.planned ? 'Yes' : 'No'}</div> + </div> + } + </OverlayPanel> + {!this.state.isLoading && + <Websocket url={process.env.REACT_APP_WEBSOCKET_URL} onOpen={this.onConnect} onMessage={this.handleData} onClose={this.onDisconnect} />} + {this.state.showDialog && + <div className="p-grid" data-testid="confirm_dialog"> + <CustomDialog type="success" visible={this.state.showDialog} width="30vw" showIcon={false} + header="Dynamic Scheduling Settings" message={<DynamicScheduler />} + content={''} + actions={ [ + {id:"no", title: 'Close', callback: this.close} ]} + onClose={this.close} + /> </div> - <label className={`col-5`} style={{ color: mouseOverItem.color }}>Project:</label> - <div className="col-7">{mouseOverItem.project ? mouseOverItem.project : "-"}</div> - <label className={`col-5`} style={{ color: mouseOverItem.color }}>Start Time:</label> - <div className="col-7">{mouseOverItem.start_time.format(UIConstants.CALENDAR_DATETIME_FORMAT)}</div> - <label className={`col-5`} style={{ color: mouseOverItem.color }}>End Time:</label> - <div className="col-7">{mouseOverItem.duration!=="Unknown"?mouseOverItem.end_time.format(UIConstants.CALENDAR_DATETIME_FORMAT):"Unknown"}</div> - {/* <label className={`col-5`} style={{color: mouseOverItem.color}}>Stations:</label> - <div className="col-7">{mouseOverItem.stations.groups}:{mouseOverItem.stations.counts}</div> */} - <label className={`col-5`} style={{ color: mouseOverItem.color }}>Duration:</label> - <div className="col-7">{mouseOverItem.duration}</div> - <label className={`col-5`} style={{ color: mouseOverItem.color }}>Planned:</label> - <div className="col-7">{mouseOverItem.planned ? 'Yes' : 'No'}</div> - </div> - } - </OverlayPanel> - {!this.state.isLoading && - <Websocket url={process.env.REACT_APP_WEBSOCKET_URL} onOpen={this.onConnect} onMessage={this.handleData} onClose={this.onDisconnect} />} + } + </> + } </React.Fragment> ); diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Workflow/workflow.list.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Workflow/workflow.list.js index 2d8c808db2d..d0167fada52 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Workflow/workflow.list.js +++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Workflow/workflow.list.js @@ -36,7 +36,6 @@ class WorkflowList extends Component{ suName:"Scheduling Unit Name", su: { name: "Scheduling Unit ID", - filter: "range", format: UIConstants.CALENDAR_TIME_FORMAT }, status: { diff --git a/SAS/TMSS/frontend/tmss_webapp/src/services/util.service.js b/SAS/TMSS/frontend/tmss_webapp/src/services/util.service.js index cdb5e1876a5..4529a11408a 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/services/util.service.js +++ b/SAS/TMSS/frontend/tmss_webapp/src/services/util.service.js @@ -229,7 +229,36 @@ const UtilService = { console.error('[UtilService.getProjectRoles]', error); return []; } - } + }, + /** + * Get Dynamic Schediling On/Off Status + * @returns JSON object + */ + getDynamicSchedulerStatus: async function() { + try { + const url = `/api/setting/dynamic_scheduling_enabled`; + const response = await axios.get(url); + return response.data; + } catch (error) { + console.error('[getDynamicSchedulerStatus]',"Mistake", error); + return null; + } + }, + /** + * Update Switch On/Off status of Dynamic Scheduling + * @param {Object} JSON object + * @returns + */ + updateDynamicSchedulerStatus: async function (response) { + try { + const url = `/api/setting/dynamic_scheduling_enabled`; + response = await axios.patch(url, response); + return response.data; + } catch (error) { + console.error('[updateDynamicSchedulerStatus]',"Mistake", error); + return null + } + }, } export default UtilService; \ No newline at end of file -- GitLab