diff --git a/SAS/TMSS/frontend/tmss_webapp/package.json b/SAS/TMSS/frontend/tmss_webapp/package.json index aa36b24233af3cc9b0c57a2bafd5c32e3da553d7..cb7cdfd8d918aa5493e31b674b520928159c79f9 100644 --- a/SAS/TMSS/frontend/tmss_webapp/package.json +++ b/SAS/TMSS/frontend/tmss_webapp/package.json @@ -12,20 +12,33 @@ "bootstrap": "^4.5.0", "font-awesome": "^4.7.0", "history": "^5.0.0", + "lodash": "^4.17.19", + "match-sorter": "^4.1.0", + "moment": "^2.27.0", "node-sass": "^4.12.0", "primeflex": "^1.3.0", "primeicons": "^4.0.0", "primereact": "^4.2.2", + "prop-types": "^15.7.2", "react": "^16.13.1", "react-app-polyfill": "^1.0.6", "react-bootstrap": "^1.0.1", "react-bootstrap-datetimepicker": "0.0.22", + "react-bootstrap-table-next": "^4.0.3", + "react-bootstrap-table2-filter": "^1.3.3", + "react-bootstrap-table2-paginator": "^2.1.2", + "react-bootstrap-table2-toolkit": "^2.1.3", "react-dom": "^16.13.1", "react-frame-component": "^4.1.2", "react-json-view": "^1.19.1", + "react-lodash": "^0.1.2", "react-router-dom": "^5.2.0", "react-scripts": "3.4.1", + "react-table": "^7.2.1", "react-transition-group": "^1.2.1", + "react-widgets": "^4.5.0", + "reactstrap": "^8.5.1", + "styled-components": "^5.1.1", "typescript": "^3.9.5", "yup": "^0.29.1" }, diff --git a/SAS/TMSS/frontend/tmss_webapp/src/layout/components/ActionComponents.js b/SAS/TMSS/frontend/tmss_webapp/src/layout/components/ActionComponents.js new file mode 100644 index 0000000000000000000000000000000000000000..777784715bc34c41fd5cf29f0dfddafe3a365334 --- /dev/null +++ b/SAS/TMSS/frontend/tmss_webapp/src/layout/components/ActionComponents.js @@ -0,0 +1,73 @@ +export { + Alert, + Badge, + Breadcrumb, + BreadcrumbItem, + Button, + ButtonDropdown, + ButtonGroup, + ButtonToolbar, + CardBody, + CardColumns, + CardDeck, + CardFooter, + CardGroup, + CardImg, + CardImgOverlay, + CardLink, + CardSubtitle, + CardText, + CardTitle, + Carousel, + CarouselCaption, + CarouselControl, + CarouselIndicators, + CarouselItem, + Col, + Collapse, + Container, + Dropdown, + DropdownItem, + DropdownMenu, + DropdownToggle, + Fade, + Form, + FormFeedback, + FormGroup, + FormText, + Input, + InputGroup, + InputGroupButtonDropdown, + InputGroupText, + Jumbotron, + Label, + ListGroup, + ListGroupItem, + ListGroupItemHeading, + ListGroupItemText, + Media, + Modal, + ModalBody, + ModalFooter, + ModalHeader, + NavbarBrand, + NavbarToggler, + NavItem, + NavLink, + Pagination, + PaginationItem, + PaginationLink, + Popover, + PopoverBody, + PopoverHeader, + Row, + TabContent, + Table, + TabPane, + Tooltip, + UncontrolledAlert, + UncontrolledButtonDropdown, + UncontrolledDropdown, + UncontrolledCollapse, + UncontrolledTooltip +} from 'reactstrap'; diff --git a/SAS/TMSS/frontend/tmss_webapp/src/layout/components/AppFooter.js b/SAS/TMSS/frontend/tmss_webapp/src/layout/components/AppFooter.js index 27edea6d5758942eaf4582237ed240d18b554082..6453a2d30d49d4d43ea767294d466d195a1eaa37 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/layout/components/AppFooter.js +++ b/SAS/TMSS/frontend/tmss_webapp/src/layout/components/AppFooter.js @@ -5,7 +5,7 @@ export class AppFooter extends Component { render() { return ( <div className="layout-footer"> - <span className="footer-text" style={{'marginRight': '5px'}}><strong>TMSS</strong> by <strong>ASTRON</strong></span> + <span className="footer-text" style={{'marginRight': '5px', color:'#0066CC'}}><strong>TMSS</strong> by <strong>ASTRON</strong></span> </div> ); } diff --git a/SAS/TMSS/frontend/tmss_webapp/src/layout/components/UncontrolledModal/UncontrolledModal.js b/SAS/TMSS/frontend/tmss_webapp/src/layout/components/UncontrolledModal/UncontrolledModal.js new file mode 100644 index 0000000000000000000000000000000000000000..1b812de2765a0338083b3264f17709e21b98eeb3 --- /dev/null +++ b/SAS/TMSS/frontend/tmss_webapp/src/layout/components/UncontrolledModal/UncontrolledModal.js @@ -0,0 +1,63 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import _ from 'lodash'; +import { Modal } from 'reactstrap'; + +import { Provider } from './context'; + +class UncontrolledModal extends React.Component { + static propTypes = { + target: PropTypes.string.isRequired + } + + constructor(props) { + super(props); + + this.state = { + isOpen: false + }; + + this.boundClickEventHandler = this.clickEventHandler.bind(this); + } + + componentDidMount() { + if (typeof document !== 'undefined') { + this.triggerElement = document.querySelector(`#${this.props.target}`); + + if (!this.triggerElement) { + // eslint-disable-next-line no-console + console.error('UncontrolledModal: \'target\' element has not been found in the DOM via querySelector'); + return; + } + + this.triggerElement.addEventListener('click', this.boundClickEventHandler); + } + } + + componentWillUnmount() { + if (this.triggerElement) { + this.triggerElement.removeEventListener('click', this.boundClickEventHandler); + } + } + + clickEventHandler() { + this.setState({ isOpen: true }); + } + + render() { + const modalProps = _.omit(this.props, ['target']); + const toggleModal = () => { this.setState({ isOpen: !this.state.isOpen }) }; + + return ( + <Provider value={{ toggleModal }}> + <Modal + { ...modalProps } + isOpen={ this.state.isOpen } + toggle={ toggleModal } + /> + </Provider> + ); + } +} + +export { UncontrolledModal }; diff --git a/SAS/TMSS/frontend/tmss_webapp/src/layout/components/UncontrolledModal/UncontrolledModalClose.js b/SAS/TMSS/frontend/tmss_webapp/src/layout/components/UncontrolledModal/UncontrolledModalClose.js new file mode 100644 index 0000000000000000000000000000000000000000..5f8ad29fa4ca192549c55a7c0693d10be84e359c --- /dev/null +++ b/SAS/TMSS/frontend/tmss_webapp/src/layout/components/UncontrolledModal/UncontrolledModalClose.js @@ -0,0 +1,34 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { Button } from 'reactstrap'; + +import { Consumer } from './context'; + +const UncontrolledModalClose = (props) => { + const { tag, ...otherProps } = props; + const Tag = tag; + + return ( + <Consumer> + { + (value) => ( + <Tag + { ...otherProps } + onClick={ () => value.toggleModal() } + /> + ) + } + </Consumer> + ) +}; +UncontrolledModalClose.propTypes = { + tag: PropTypes.oneOfType([ + PropTypes.func, + PropTypes.string + ]) +}; +UncontrolledModalClose.defaultProps = { + tag: Button +}; + +export { UncontrolledModalClose }; diff --git a/SAS/TMSS/frontend/tmss_webapp/src/layout/components/UncontrolledModal/context.js b/SAS/TMSS/frontend/tmss_webapp/src/layout/components/UncontrolledModal/context.js new file mode 100644 index 0000000000000000000000000000000000000000..bf325a1a345d72ce78840f32a8ac29301530120b --- /dev/null +++ b/SAS/TMSS/frontend/tmss_webapp/src/layout/components/UncontrolledModal/context.js @@ -0,0 +1,8 @@ +import React from 'react'; + +const { Provider, Consumer } = React.createContext(); + +export { + Provider, + Consumer +} diff --git a/SAS/TMSS/frontend/tmss_webapp/src/layout/components/UncontrolledModal/index.js b/SAS/TMSS/frontend/tmss_webapp/src/layout/components/UncontrolledModal/index.js new file mode 100644 index 0000000000000000000000000000000000000000..3927d23c324d2b7d6a3538dd9edcfd41aea5f7ec --- /dev/null +++ b/SAS/TMSS/frontend/tmss_webapp/src/layout/components/UncontrolledModal/index.js @@ -0,0 +1,6 @@ +import { UncontrolledModal } from './UncontrolledModal'; +import { UncontrolledModalClose } from './UncontrolledModalClose'; + +UncontrolledModal.Close = UncontrolledModalClose; + +export default UncontrolledModal; \ No newline at end of file diff --git a/SAS/TMSS/frontend/tmss_webapp/src/layout/components/ViewTable.js b/SAS/TMSS/frontend/tmss_webapp/src/layout/components/ViewTable.js new file mode 100644 index 0000000000000000000000000000000000000000..965b6e0aeb73d4c73ac3ca6296ff6a3549e245db --- /dev/null +++ b/SAS/TMSS/frontend/tmss_webapp/src/layout/components/ViewTable.js @@ -0,0 +1,449 @@ +import React, {useState, useRef } from "react"; +import styled from 'styled-components' +import { useSortBy, useTable, useFilters, useGlobalFilter, useAsyncDebounce } from 'react-table' +import matchSorter from 'match-sorter' +import _ from 'lodash'; +import {Button, Collapse} from 'react-bootstrap' +import { UncontrolledButtonDropdown,DropdownMenu, } from './ActionComponents'; +import moment from 'moment'; +import { useHistory } from "react-router-dom"; +import {OverlayPanel} from 'primereact/overlaypanel'; + +const Styles = styled.div` + padding: 1rem; + table { + border-spacing: 0; + border: 1px solid black; + + tr { + :last-child { + td { + + border-bottom: 0; + } + } + } + + th, + td { + margin: 0; + padding: 0.5rem; + border-bottom: 1px solid black; + border-right: 1px solid black; + :last-child { + border-right: 0; + } + } + } +` +let dataheader = [] ; +let tbldata =[]; + +// Define a default UI for filtering +function GlobalFilter({ + preGlobalFilteredRows, + globalFilter, + setGlobalFilter, + }) { + const count = preGlobalFilteredRows.length + const [value, setValue] = React.useState(globalFilter) + const onChange = useAsyncDebounce(value => {setGlobalFilter(value || undefined)}, 200) + + return ( + <span> + Table Data Search:{' '} + <input + value={value || ""} + onChange={e => { + setValue(e.target.value); + onChange(e.target.value); + }} + placeholder={`${count} records...`} + style={{ + fontSize: '1.1rem', + border: '1', + }} + /> + </span> + ) +} + +// Define a default UI for filtering +function DefaultColumnFilter({ + column: { filterValue, preFilteredRows, setFilter }, +}) { + const count = preFilteredRows.length + + return ( + <input + value={filterValue || ''} + onChange={e => { + setFilter(e.target.value || undefined) // Set undefined to remove the filter entirely + }} + placeholder={`Search ${count} records...`} + /> + ) +} + +// This is a custom filter UI for selecting +// a unique option from a list +function SelectColumnFilter({ + column: { filterValue, setFilter, preFilteredRows, id }, + }) { + // Calculate the options for filtering + // using the preFilteredRows + const options = React.useMemo(() => { + const options = new Set() + preFilteredRows.forEach(row => { + options.add(row.values[id]) + }) + return [...options.values()] + }, [id, preFilteredRows]) + + // Render a multi-select box + return ( + <select + value={filterValue} + onChange={e => { + setFilter(e.target.value || undefined) + }} + > + <option value="">All</option> + {options.map((option, i) => ( + <option key={i} value={option}> + {option} + </option> + ))} + </select> + ) +} + + // This is a custom filter UI that uses a + // slider to set the filter value between a column's + // min and max values + function SliderColumnFilter({ + column: { filterValue, setFilter, preFilteredRows, id }, + }) { + // Calculate the min and max + // using the preFilteredRows + + const [min, max] = React.useMemo(() => { + let min = preFilteredRows.length ? preFilteredRows[0].values[id] : 0 + let max = preFilteredRows.length ? preFilteredRows[0].values[id] : 0 + preFilteredRows.forEach(row => { + min = Math.min(row.values[id], min) + max = Math.max(row.values[id], max) + }) + return [min, max] + }, [id, preFilteredRows]) + + return ( + <> + <input + type="range" + min={min} + max={max} + value={filterValue || min} + onChange={e => { + setFilter(parseInt(e.target.value, 10)) + }} + /> + <button onClick={() => setFilter(undefined)}>Off</button> + </> + ) +} + +// This is a custom UI for our 'between' or number range +// filter. It uses two number boxes and filters rows to +// ones that have values between the two +function NumberRangeColumnFilter({ + column: { filterValue = [], preFilteredRows, setFilter, id }, +}) { + const [min, max] = React.useMemo(() => { + let min = preFilteredRows.length ? preFilteredRows[0].values[id] : 0 + let max = preFilteredRows.length ? preFilteredRows[0].values[id] : 0 + preFilteredRows.forEach(row => { + min = Math.min(row.values[id], min) + max = Math.max(row.values[id], max) + }) + return [min, max] + }, [id, preFilteredRows]) + + return ( + <div + style={{ + display: 'flex', + }} + > + <input + value={filterValue[0] || ''} + type="number" + onChange={e => { + const val = e.target.value + setFilter((old = []) => [val ? parseInt(val, 10) : undefined, old[1]]) + }} + placeholder={`Min (${min})`} + style={{ + width: '70px', + marginRight: '0.5rem', + }} + /> + to + <input + value={filterValue[1] || ''} + type="number" + onChange={e => { + const val = e.target.value + setFilter((old = []) => [old[0], val ? parseInt(val, 10) : undefined]) + }} + placeholder={`Max (${max})`} + style={{ + width: '70px', + marginLeft: '0.5rem', + }} + /> + </div> + ) +} + +function fuzzyTextFilterFn(rows, id, filterValue) { + return matchSorter(rows, filterValue, { keys: [row => row.values[id]] }) +} + +// Let the table remove the filter if the string is empty +fuzzyTextFilterFn.autoRemove = val => !val + +const IndeterminateCheckbox = React.forwardRef( + ({ indeterminate, ...rest }, ref) => { + const defaultRef = React.useRef() + const resolvedRef = ref || defaultRef + + React.useEffect(() => { + resolvedRef.current.indeterminate = indeterminate + }, [resolvedRef, indeterminate]) + + return <input type="checkbox" ref={resolvedRef} {...rest} /> + } +) + +// Our table component +function Table({ columns, data }) { + + const filterTypes = React.useMemo( + () => ({ + // Add a new fuzzyTextFilterFn filter type. + fuzzyText: fuzzyTextFilterFn, + // Or, override the default text filter to use + // "startWith" + text: (rows, id, filterValue) => { + return rows.filter(row => { + const rowValue = row.values[id] + return rowValue !== undefined + ? String(rowValue) + .toLowerCase() + .startsWith(String(filterValue).toLowerCase()) + : true + }) + }, + }), + [] + ) + + const defaultColumn = React.useMemo( + () => ({ + // Let's set up our default Filter UI + Filter: DefaultColumnFilter, + }), + [] + ) + + const { + getTableProps, + getTableBodyProps, + headerGroups, + rows, + prepareRow, + allColumns, + getToggleHideAllColumnsProps, + state, + preGlobalFilteredRows, + setGlobalFilter, + state: { pageIndex, pageSize }, + setHiddenColumns, + } = useTable( + { + columns, + data, + defaultColumn, + filterTypes, + }, + useFilters, + useGlobalFilter, + useSortBy, + ) + + React.useEffect(() => { + setHiddenColumns( + columns.filter(column => !column.isVisible).map(column => column.accessor) + ); + }, [setHiddenColumns, columns]); + + const firstPageRows = rows.slice(0, 10) + const [dropdownOpen, setOpen] = useState(false); + let op = useRef(null); + + return ( + <> + <div> + <div style={{textAlign:'left',}}> + <Button type="button" label="Toggle Columns" onClick={(e) => op.current.toggle(e)}/> + <OverlayPanel ref={op} id="overlay_panel" showCloseIcon={true}> + <DropdownMenu > + <div style={{float: 'left', backgroundColor: '#d1cdd936', width: '250px', height: '400px', overflow: 'auto'}}> + <div id="tagleid" > + <div style={{textAlign: 'center'}}> + <h5><p>Select column(s) to view</p></h5> + </div> + <div > + <div style={{marginBottom:'5px'}}> + <IndeterminateCheckbox {...getToggleHideAllColumnsProps()} /> Select All + </div> + {allColumns.map(column => ( + <div key={column.id}> + <label style={{color:'black'}}> + <input type="checkbox" {...column.getToggleHiddenProps()} />{' '} {_.startCase(column.id)} + </label> + </div> + ))} + <br /> + </div> + </div> + </div> + </DropdownMenu> + </OverlayPanel> + </div> + <div style={{textAlign:'right'}}> + {tbldata.length>0 && + <GlobalFilter + preGlobalFilteredRows={preGlobalFilteredRows} + globalFilter={state.globalFilter} + setGlobalFilter={setGlobalFilter} + /> + } + </div> + </div> + + <table {...getTableProps()}> + <thead> + {headerGroups.map(headerGroup => ( + <tr {...headerGroup.getHeaderGroupProps()}> + {headerGroup.headers.map(column => ( + <th {...column.getHeaderProps(column.getSortByToggleProps())}> + {column.render('Header')} + <span> + {column.isSorted ? (column.isSortedDesc ? <i className="fa fa-sort-desc" aria-hidden="true"></i> : <i className="fa fa-sort-asc" aria-hidden="true"></i>) : ""} + </span> + {/* Render the columns filter UI */} + <div>{column.canFilter ? column.render('Filter') : null}</div> + </th> + ))} + </tr> + ))} + + </thead> + <tbody {...getTableBodyProps()}> + {firstPageRows.map((row, i) => { + prepareRow(row) + return ( + <tr {...row.getRowProps()}> + {row.cells.map(cell => { + return <td {...cell.getCellProps()}>{cell.render('Cell')}</td> + })} + </tr> + ) + })} + </tbody> + </table> + </> + ) +} + +// Define a custom filter filter function! +function filterGreaterThan(rows, id, filterValue) { + return rows.filter(row => { + const rowValue = row.values[id] + return rowValue >= filterValue + }) +} + +// This is an autoRemove method on the filter function that +// when given the new filter value and returns true, the filter +// will be automatically removed. Normally this is just an undefined +// check, but here, we want to remove the filter if it's not a number +filterGreaterThan.autoRemove = val => typeof val !== 'number' + +function ViewTable(props) { + const history = useHistory(); + const navigateTo = (pdata) => history.push({ + pathname: props.path, + state: { + "scheunit": props.data, + "schedule_task":props.data1, + "defaultcolumns": props.defaultcolumns, + } + }); + + tbldata = props.data; + let defaultheader = props.defaultcolumns; + dataheader = Object.keys(tbldata[0]); + let columns = []; + dataheader.forEach(header => { + var text = _.startCase(header); + columns.push({ + Header: text, + accessor: header, + filter: 'fuzzyText', + isVisible: defaultheader.includes(header), + Cell: props => <div> {dateformat(props.value)} </div>, + minWidth: 20, + }) + }); + + function dateformat(date){ + try{ + if(date && date.length==26){ + var result = moment(date).format("YYYY-MM-DD HH:mm:SS") + if(result == 'Invalid date'){ + return date; + }else{ + return result; + } + } + }catch(err){ + console.err('Error',err) + } + return date; + } + + if(columns.length>0 && props.showaction == 'true'){ + columns.push( + { + Header: 'Action', + Cell: row => <UncontrolledButtonDropdown> + <a onClick={navigateTo}> + View + </a> + </UncontrolledButtonDropdown>, + }) + } + + return ( + <div > + <Styles style={{overflow: 'auto'}}> + <Table columns={columns} data={tbldata} /> + </Styles> + </div> + ) +} + +export default ViewTable diff --git a/SAS/TMSS/frontend/tmss_webapp/src/layout/services/ScheduleService.js b/SAS/TMSS/frontend/tmss_webapp/src/layout/services/ScheduleService.js new file mode 100644 index 0000000000000000000000000000000000000000..8a50b166509a15ef0e0c31241bbfd397394e409a --- /dev/null +++ b/SAS/TMSS/frontend/tmss_webapp/src/layout/services/ScheduleService.js @@ -0,0 +1,58 @@ +import axios from 'axios' + + +export async function getScheduling_Unit_Draft(){ + let res = []; + await axios.get('/api/scheduling_unit_draft/', { + headers: { + "Content-Type": "application/json", + "Authorization": "Basic dGVzdDp0ZXN0" + } + } + ).then(function(response) { + res= response; + }).catch(function(error) { + console.log('Error on Authentication',error); + }); + return res; +} + +export async function getSchedule_Unit_Draft_By_Id(id){ + let res=[]; + await axios.get('/api/scheduling_unit_draft/'+id+'/task_draft/', { + headers: { + "Content-Type": "application/json", + "Authorization": "Basic dGVzdDp0ZXN0" + } + } + ).then(function(response) { + res= response; + }).catch(function(error) { + console.log('Error on Authentication',error); + }); + return res; +} + +let rdata = []; +export const fetchData = async (url) => { + try{ + const data = await axios.get(url).then(function(response) { + // console.log (response.data); + rdata = response.data; + }); + return rdata; + }catch (err){ + alert(err) + } +} + +export const getData = async (url) => { + try{ + await axios.get(url).then(function(response) { + rdata = response.data; + }); + return rdata; + }catch (err){ + alert(err) + } +} \ No newline at end of file diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Dashboard/index.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Dashboard/index.js index dd52fdf11774d21f1e002716cf9804f1ac581d8d..174a7a7af740a2d36a804c4a2dc6759d9a106fea 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Dashboard/index.js +++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Dashboard/index.js @@ -2,6 +2,10 @@ import React, {Component} from 'react'; export class Dashboard extends Component { + constructor(props){ + super(props) + console.log(this.props) + } render() { return ( <h1>Dashboard</h1> diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/SchedulingUnitList.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/SchedulingUnitList.js new file mode 100644 index 0000000000000000000000000000000000000000..ea289e14a61bf1451d3f5372e039374e9d878ef2 --- /dev/null +++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/SchedulingUnitList.js @@ -0,0 +1,39 @@ +import React, { Component } from 'react' +import 'primeflex/primeflex.css'; +import ViewTable from '../../layout/components/ViewTable'; +import _ from 'lodash'; + +class SchedulingUnitList extends Component{ + + constructor(props){ + super(props) + } + + render(){ + + let scheduleunit = this.props.scheunit; + {this.props.scheunit && + scheduleunit.forEach(item =>{ + delete item ['requirements_doc'] + }) + } + + let defaultcolumns = [ "name","description","created_at","updated_at","requirements_template_id","scheduling_set_id"] + return( + <> + {scheduleunit && + <ViewTable + data={scheduleunit} + data1={this.props.schedule_task} + defaultcolumns={defaultcolumns} + showaction="true" + path="/viewschedulingunit" + /> + } + </> + + ) + } +} + +export default SchedulingUnitList \ No newline at end of file diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/ViewSchedulingUnit.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/ViewSchedulingUnit.js new file mode 100644 index 0000000000000000000000000000000000000000..e8106b634d31c7871cfa5d002a035199f008f1f9 --- /dev/null +++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/ViewSchedulingUnit.js @@ -0,0 +1,75 @@ +import React, { Component } from 'react' +import {InputText, InputTextarea, Dropdown} from 'primereact/inputtext'; +import 'primeflex/primeflex.css'; +import ViewTable from '../../layout/components/ViewTable'; +import _ from 'lodash'; + +class ViewSchedulingUnit extends Component{ + constructor(props){ + super(props) + } + + render(){ + let tasks_details = this.props.location.state.schedule_task; + tasks_details.forEach(item =>{ + delete item ['specifications_doc'] + }) + let defaultcolumns = [ "id","name","description","created_at","updated_at","duration","specifications_template_id"] + return( + <> + <div > + <h1>Scheduling Units Details</h1> + </div> + + {this.props.location.state.scheunit && + <div className="p-toolbar p-component p-grid form-group" style={{ marginTop: '10px', }}> + <div className="p-col-12 p-md-1"> + <label htmlFor="input">Name:</label> + </div> + <div className="p-col-12 p-md-3"> + <label style={{fontWeight: 'bold'}} htmlFor="input">{this.props.location.state.scheunit[0].name}</label> + </div> + <div className="p-col-12 p-md-1"> + <label htmlFor="input">Description:</label> + </div> + <div className="p-col-12 p-md-3"> + <label style={{fontWeight: 'bold'}} htmlFor="input">{this.props.location.state.scheunit[0].description}</label> + </div> + <div className="p-col-12 p-md-1"> + <label htmlFor="input">Scheduling Set:</label> + </div> + <div className="p-col-12 p-md-3"> + <label style={{fontWeight: 'bold',overflowWrap:'anywhere'}} htmlFor="input">{this.props.location.state.scheunit[0].scheduling_set}</label> + </div> + <div className="p-col-12 p-md-1"> + <label htmlFor="input">Created At:</label> + </div> + <div className="p-col-12 p-md-3"> + <label style={{fontWeight: 'bold'}} htmlFor="input">{this.props.location.state.scheunit[0].created_at}</label> + </div> + <div className="p-col-12 p-md-1"> + <label htmlFor="input">Updated At:</label> + </div> + <div className="p-col-12 p-md-3"> + <label style={{fontWeight: 'bold'}} htmlFor="input">{this.props.location.state.scheunit[0].updated_at}</label> + </div> + </div> + } + <div style={{marginTop: '10px'}}> + <h1>Tasks Details</h1> + </div> + {this.props.location.state.schedule_task && + <ViewTable + data={tasks_details} + defaultcolumns={defaultcolumns} + showaction="true" + path="/viewtask" + /> + } + </> + + ) + } +} + +export default ViewSchedulingUnit \ No newline at end of file diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/index.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/index.js index 5ce2273ff25cb9371132f73e8c685415cb3ab5de..10771b820478e27f79eee453f09cb4d2e1b0c92c 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/index.js +++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/index.js @@ -1,10 +1,35 @@ import React, {Component} from 'react'; +import SchedulingUnitList from './SchedulingUnitList' +import {getScheduling_Unit_Draft, getSchedule_Unit_Draft_By_Id} from '../../layout/services/ScheduleService' export class Scheduling extends Component { + constructor(props){ + super(props) + this.state = { + scheduleunit: [], + schedule_unit_task: [] + } + } + async componentDidMount(){ + let resdata = await getScheduling_Unit_Draft(); + this.setState({ + scheduleunit : resdata.data + }); + resdata = []; + resdata = await getSchedule_Unit_Draft_By_Id(this.state.scheduleunit.results[0].id); + this.setState({ + schedule_unit_task : resdata.data + }); + } render() { return ( - <h1>Scheduling Units</h1> + <> + <h1>Scheduling Units List</h1> + {this.state.scheduleunit && + <SchedulingUnitList scheunit= {this.state.scheduleunit.results} schedule_task={this.state.schedule_unit_task.results} /> + } + </> ); } } diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/index.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/index.js index 42a57b784c881506b9d8a72c382fd12d04feddca..ee644b7e50f0d8df7e5fda6d37583a488f00d8eb 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/routes/index.js +++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/index.js @@ -8,6 +8,7 @@ import { import {Dashboard} from './Dashboard'; import {Scheduling} from './Scheduling'; import {TaskEdit, TaskView} from './Task'; +import ViewSchedulingUnit from './Scheduling/ViewSchedulingUnit' export const RoutedContent = () => { return ( @@ -18,6 +19,7 @@ export const RoutedContent = () => { <Route path="/task" exact component={TaskView} /> <Route path="/task/view" exact component={TaskView} /> <Route path="/task/edit" exact component={TaskEdit} /> + <Route path="/viewschedulingunit" exact component={ViewSchedulingUnit} /> </Switch> ); } \ No newline at end of file diff --git a/SAS/TMSS/frontend/tmss_webapp/tmss_webapp.rar b/SAS/TMSS/frontend/tmss_webapp/tmss_webapp.rar new file mode 100644 index 0000000000000000000000000000000000000000..ff27f871dca3693ca6a4043b3ed8b845d0342cad Binary files /dev/null and b/SAS/TMSS/frontend/tmss_webapp/tmss_webapp.rar differ