diff --git a/SAS/TMSS/frontend/tmss_webapp/package.json b/SAS/TMSS/frontend/tmss_webapp/package.json index 36c5a54e803ee8f26341c1f4dbe90fdd65c31e3d..b2ab4d9cd7dbf242a366dea5e6ebbb6e42a5fc04 100644 --- a/SAS/TMSS/frontend/tmss_webapp/package.json +++ b/SAS/TMSS/frontend/tmss_webapp/package.json @@ -36,6 +36,7 @@ "prop-types": "^15.7.2", "react": "^16.13.1", "react-app-polyfill": "^1.0.6", + "react-beautiful-dnd": "^13.1.0", "react-beforeunload": "^2.4.0", "react-bootstrap": "^1.0.1", "react-bootstrap-datetimepicker": "0.0.22", diff --git a/SAS/TMSS/frontend/tmss_webapp/src/components/ViewTable.js b/SAS/TMSS/frontend/tmss_webapp/src/components/ViewTable.js index 011ed83d8809fdef613c9c0b28b421d56f696c72..e1b58c59c7e2cb5cc97ae33607574d19d19449bc 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/components/ViewTable.js +++ b/SAS/TMSS/frontend/tmss_webapp/src/components/ViewTable.js @@ -23,7 +23,7 @@ import "flatpickr/dist/flatpickr.css"; import Flatpickr from "react-flatpickr"; import confirmDatePlugin from "flatpickr/dist/plugins/confirmDate/confirmDate"; import shortcutButtonsPlugin from "shortcut-buttons-flatpickr"; - +import { DragDropContext, Droppable, Draggable } from "react-beautiful-dnd"; import UtilService from '../../src/services/util.service' import Papa from "papaparse"; import JsPDF from "jspdf"; @@ -56,8 +56,22 @@ let tmpTableData = null; let currentTableName = null; let storeFilter = false; let storage_array = []; +let dragged = null; +let reorder = []; //let confirmDatePlugin = new confirmDatePlugin(); // Define a default UI for filtering + +const getItemStyle = ({ isDragging, isDropAnimating }, draggableStyle) => ({ + ...draggableStyle, + // some basic styles to make the items look a bit nicer + userSelect: "none", + cursor: isDragging? 'move': 'move', + ...(!isDragging && { transform: "translate(0,0)" }), + ...(isDropAnimating && { transitionDuration: "0.001s" }) + + // styles we need to apply on draggables +}); + function GlobalFilter({ preGlobalFilteredRows, globalFilter, @@ -1838,6 +1852,7 @@ function Table(props) { useColumnOrder, useExportData ); + const currentColOrder = React.useRef(); let pageCount = doServersideFilter?controlledPageCount:data.length; tmpTableData = data; // while siwtch the task type or Su type, this will set the relavent default sort column @@ -1862,11 +1877,17 @@ function Table(props) { columns.filter(column => !column.isVisible).map(column => column.id) ); // console.log('columns List', visibleColumns.map((d) => d.id)); - if (columnOrders && columnOrders.length) { + const storedColOrder = UtilService.localStore({ type: 'get', key: tablename+'colOrder'}); + if (storedColOrder) { + setColumnOrder(storedColOrder) + } + else if (columnOrders && columnOrders.length) { if (showAction === 'true') { setColumnOrder(['Select', 'Action', ...columnOrders]); + UtilService.localStore({ type: 'set', key: tablename+'colOrder', value: ['Select', 'Action', ...columnOrders]}); } else { setColumnOrder(['Select', ...columnOrders]); + UtilService.localStore({ type: 'set', key: tablename+'colOrder', value: ['Select', ...columnOrders]}); } } setLoading(dataFetchStatus); @@ -2078,31 +2099,74 @@ function Table(props) { <table {...getTableProps()} data-testid="viewtable" className="viewtable" > <thead> {headerGroups.map(headerGroup => ( - <tr {...headerGroup.getHeaderGroupProps()}> - {headerGroup.headers.map(column => ( - <th onClick={() => { - if(!doServersideFilter) { - toggleBySorting({ 'id': column.id, desc: (column.isSortedDesc != undefined ? !column.isSortedDesc : false) }) - } + <DragDropContext + onDragStart={() => { + currentColOrder.current = allColumns.map(column => column.id); + }} + onDragUpdate={(dragUpdateObj, b) => { + const colOrder = [...currentColOrder.current]; + const sIndex = dragUpdateObj.source.index; + const dIndex = dragUpdateObj.destination && dragUpdateObj.destination.index; + if(typeof sIndex === 'number' && typeof dIndex === "number") { + colOrder.splice(sIndex, 1); + colOrder.splice(dIndex, 0, dragUpdateObj.draggableId); + setColumnOrder(colOrder); + UtilService.localStore({ type: 'set', key: tablename+'colOrder', value: colOrder}); + } + }} + > + <Droppable droppableId="droppable" direction="horizontal"> + {(droppableProvided, snapshot) => ( + <tr {...headerGroup.getHeaderGroupProps()} + ref={droppableProvided.innerRef}> + {headerGroup.headers.map((column,index) => ( + <Draggable + key={column.id} + draggableId={column.id} + index={index} + isDragDisabled={_.includes(['Select', 'Action', 'Status Logs'], column.id)? true: false}> + {(provided, snapshot) => { + return ( + <th onClick={() => { + if(!doServersideFilter) { + toggleBySorting({ 'id': column.id, desc: (column.isSortedDesc != undefined ? !column.isSortedDesc : false) }); + } }}> - <div {...column.getHeaderProps(column.getSortByToggleProps())} > - {column.Header !== 'actionpath' && column.render('Header')} - {column.Header !== 'Action' ? - column.isSorted ? (column.isSortedDesc ? <i className="pi pi-sort-down" aria-hidden="true"></i> : <i className="pi pi-sort-up" aria-hidden="true"></i>) : "" - : "" - } - </div> - - {/* Render the columns filter UI */} - {column.Header !== 'actionpath' && - <div className={columnclassname[0][column.Header]} > - {column.canFilter && column.Header !== 'Action' ? column.render('Filter') : null} - - </div> - } - </th> - ))} - </tr> + <div {...column.getHeaderProps(column.getSortByToggleProps())} > + <div + {...provided.draggableProps} + {...provided.dragHandleProps} + // {...extraProps} + ref={provided.innerRef} + style={{ + ...getItemStyle( + snapshot, + provided.draggableProps.style + ) + // ...style + }}> + {column.Header !== 'actionpath' && column.render('Header')} + {column.Header !== 'Action' ? + column.isSorted ? (column.isSortedDesc ? <i className="pi pi-sort-down" aria-hidden="true"></i> : <i className="pi pi-sort-up" aria-hidden="true"></i>) : "" + : "" + } + </div> + </div> + {/* Render the columns filter UI */} + {column.Header !== 'actionpath' && + <div className={columnclassname[0][column.Header]}> + {column.canFilter && column.Header !== 'Action' ? column.render('Filter') : null} + </div> + } + </th> + ); + }} + </Draggable> + ))} + </tr> + )} + </Droppable> + </DragDropContext> ))} {(doServersideFilter && loading) && <tr style={{height: "5px"}}><td colSpan={columns.length} style={{padding: "0px"}}> diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/SchedulingUnitList.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/SchedulingUnitList.js index e7d17780bf4303c8c6d5af722de4396450e6a6d3..804838a703147d84cd988e75e94a45efdfc53815 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/SchedulingUnitList.js +++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/SchedulingUnitList.js @@ -18,6 +18,7 @@ import UtilService from '../../services/util.service'; import { Dropdown } from 'primereact/dropdown'; import SUBCreator from './sub.create'; import AuthUtil from '../../utils/auth.util'; +import TimelineCommonUtils from '../Timeline/common.utils'; class SchedulingUnitList extends Component{ @@ -434,18 +435,15 @@ class SchedulingUnitList extends Component{ const output = []; if (isInitial) { this.mainStationGroups = null; - let workflowProcesses = null; const promises = [ ScheduleService.getMainGroupStations(), - WorkflowService.getWorkflowProcesses(), ]; await Promise.all(promises).then(async responses => { if(responses) { this.mainStationGroups = responses[0]; - workflowProcesses = responses[1]; } }); - this.setState({scheduleunitDrafts: [], workflowProcesses: workflowProcesses}); + this.setState({scheduleunitDrafts: []}); } else { let scheduleunits = []; let expand = suType.toLowerCase() === 'draft' ? this.SU_DRAFT_EXPAND: this.SU_BLUEPRINT_EXPAND; @@ -532,8 +530,7 @@ class SchedulingUnitList extends Component{ }; scheduleunit['scheduling_set'] = scheduleunit.draft.scheduling_set.name; scheduleunit['workflowStatus'] = null; - const workflowProcess = _.find(this.state.workflowProcesses, ['su', scheduleunit.id]); - scheduleunit['workflowStatus'] = workflowProcess?workflowProcess.status: null; + scheduleunit['workflowStatus'] = this.timelineCommonUtils.getWorkflowStatus(scheduleunit); scheduleunit.duration = moment.utc((scheduleunit.duration || 0)*1000).format('HH:mm:ss'); scheduleunit.type= 'Blueprint'; scheduleunit['actionpath'] ='/schedulingunit/view/blueprint/'+scheduleunit.id; @@ -618,6 +615,7 @@ class SchedulingUnitList extends Component{ this.getFilterColumns(this.state.suType.toLowerCase()); this.getSchedulingUnitList(true, this.state.suType, this.filterQry, this.orderBy, this.limit, this.offset); this.setToggleBySorting(); + this.timelineCommonUtils = new TimelineCommonUtils(); } /**