Skip to content
Snippets Groups Projects
Commit 14475882 authored by Muthukrishnan's avatar Muthukrishnan
Browse files

TMSS-407 - Reservation table implemented

Reservation table implemented
parent 8ced4808
Branches
Tags
1 merge request!336Resolve TMSS-543
......@@ -13,6 +13,9 @@ import {TriStateCheckbox} from 'primereact/tristatecheckbox';
import { Slider } from 'primereact/slider';
import { Button } from "react-bootstrap";
import { InputNumber } from "primereact/inputnumber";
import {MultiSelect} from 'primereact/multiselect';
import { RadioButton } from 'primereact/radiobutton';
import {Dropdown} from 'primereact/dropdown';
let tbldata =[], filteredData = [] ;
let selectedRows = [];
......@@ -24,7 +27,8 @@ let allowColumnSelection = true;
let allowRowSelection = false;
let columnclassname =[];
let parentCallbackFunction, parentCBonSelection;
let cyclelist =[];
let cycle= [];
// Define a default UI for filtering
function GlobalFilter({
preGlobalFilteredRows,
......@@ -114,6 +118,69 @@ function SelectColumnFilter({
)
}
// This is a custom filter UI for selecting
// a unique option from a list
function MultiSelectColumnFilter({
column: { filterValue, setFilter, preFilteredRows, id },
}) {
const [value, setValue] = useState('');
//const [filtertype, setFiltertype] = useState('');
React.useEffect(() => {
if (!filterValue && value) {
setValue('');
}
}, [filterValue, value]);
const options = React.useMemo(() => {
let options = new Set();
preFilteredRows.forEach(row => {
row.values[id].split(',').forEach( value => {
if ( value !== '') {
let hasValue = false;
options.forEach( option => {
if(option.name === value){
hasValue = true;
}
});
if(!hasValue) {
let option = { 'name': value, 'value':value};
options.add(option);
}
}
});
});
return [...options.values()]
}, [id, preFilteredRows])
// Render a multi-select box
return (
<div onClick={e => { e.stopPropagation() }} >
{/*} <div className="p-field-radiobutton">
<RadioButton inputId="filtertype1" name="filtertype" value="Any Of" onChange={(e) => this.setState({filtertype: e.value})} checked={this.state.filtertype === 'Any Of'} />
<label htmlFor="filtertype1">Any Of</label>
</div>
<div className="p-field-radiobutton">
<RadioButton inputId="filtertype2" name="filtertype" value="All" onChange={(e) => this.setState({filtertype: e.value})} checked={this.state.filtertype === 'All'} />
<label htmlFor="filtertype2">All</label>
</div> */}
<MultiSelect data-testid="stations" id="stations" optionLabel="value" optionValue="value" filter={true}
value={value}
options={options}
onChange={e => { setValue(e.target.value);
setFilter(e.target.value|| undefined)
}}
style={{
height: '24.2014px',
width: '60px',
border:'1px solid lightgrey',
}}
/>
</div>
)
}
// This is a custom filter UI that uses a
// slider to set the filter value between a column's
// min and max values
......@@ -185,6 +252,115 @@ function CalendarColumnFilter({
)
}
// This is a custom filter UI that uses a
// calendar to set the value
function DateTimeColumnFilter({
column: { setFilter, filterValue},
}) {
// Calculate the min and max
// using the preFilteredRows
const [value, setValue] = useState('');
React.useEffect(() => {
if (!filterValue && value) {
setValue(null);
}
}, [filterValue, value]);
return (
<div className="table-filter" onClick={e => { e.stopPropagation() }}>
<Calendar value={value} appendTo={document.body} onChange={(e) => {
const value = moment(e.value, moment.ISO_8601).format("YYYY-MMM-DD HH:mm:SS")
setValue(value); setFilter(value);
}} showIcon
// showTime= {true}
//showSeconds= {true}
// hourFormat= "24"
></Calendar>
{value && <i onClick={() => {setFilter(undefined); setValue('') }} className="tb-cal-reset fa fa-times" />}
</div>
)
}
/**
* Custom function to filter data from date field.
* @param {Array} rows
* @param {String} id
* @param {String} filterValue
*/
function fromDatetimeFilterFn(rows, id, filterValue) {
const filteredRows = _.filter(rows, function(row) {
// If cell value is null or empty
if (!row.values[id]) {
return false;
}
//Remove microsecond if value passed is UTC string in format "YYYY-MM-DDTHH:mm:ss.sssss"
let rowValue = moment.utc(row.values[id].split('.')[0]);
if (!rowValue.isValid()) {
// For cell data in format 'YYYY-MMM-DD'
rowValue = moment.utc(moment(row.values[id], 'YYYY-MMM-DDTHH:mm:SS').format("YYYY-MM-DDTHH:mm:SS"));
}
const start = moment.utc(moment(filterValue, 'YYYY-MMM-DDTHH:mm:SS').format("YYYY-MM-DDTHH:mm:SS"));
return (start.isSameOrBefore(rowValue));
} );
return filteredRows;
}
/**
* Custom function to filter data from date field.
* @param {Array} rows
* @param {String} id
* @param {String} filterValue
*/
function multiSelectFilterFn(rows, id, filterValue) {
const filteredRows = _.filter(rows, function(row) {
alert('tbldata',tbldata.length)
if ( filterValue.length === 0){
return true;
}
// If cell value is null or empty
if (!row.values[id]) {
return false;
}
let rowValue = row.values[id];
let hasData = false;
filterValue.forEach(filter => {
if( rowValue.includes( filter )) {
hasData = true;
}
});
return hasData;
} );
return filteredRows;
}
/**
* Custom function to filter data from date field.
* @param {Array} rows
* @param {String} id
* @param {String} filterValue
*/
function toDatetimeFilterFn(rows, id, filterValue) {
const filteredRows = _.filter(rows, function(row) {
// If cell value is null or empty
if (!row.values[id]) {
return false;
}
//Remove microsecond if value passed is UTC string in format "YYYY-MM-DDTHH:mm:ss.sssss"
let rowValue = moment.utc(row.values[id].split('.')[0]);
if (!rowValue.isValid()) {
// For cell data in format 'YYYY-MMM-DD'
rowValue = moment.utc(moment(row.values[id], 'YYYY-MMM-DDTHH:mm:SS').format("YYYY-MM-DDTHH:mm:SS"));
}
const end = moment.utc(moment(filterValue, 'YYYY-MMM-DDTHH:mm:SS').format("YYYY-MM-DDTHH:mm:SS"));
return (end.isSameOrAfter(rowValue));
} );
return filteredRows;
}
/**
* Custom function to filter data from date field.
* @param {Array} rows
......@@ -328,6 +504,10 @@ const filterTypes = {
'select': {
fn: SelectColumnFilter,
},
'multiselect': {
fn: MultiSelectColumnFilter,
type: multiSelectFilterFn
},
'switch': {
fn: BooleanColumnFilter
},
......@@ -338,6 +518,14 @@ const filterTypes = {
fn: CalendarColumnFilter,
type: dateFilterFn
},
'fromdatetime': {
fn: DateTimeColumnFilter,
type: fromDatetimeFilterFn
},
'todatetime': {
fn: DateTimeColumnFilter,
type: toDatetimeFilterFn
},
'range': {
fn: RangeColumnFilter,
type: 'between'
......@@ -540,6 +728,15 @@ const defaultColumn = React.useMemo(
</div>
{ showTopTotal && filteredData.length === data.length &&
<div className="total_records_top_label"> <label >Total records ({data.length})</label></div>
}
{ cyclelist && cyclelist.length>0 &&
<div className="total_records_top_label">
<label >Cycles </label>
<MultiSelect data-testid="cycle" id="cycle" optionLabel="name" optionValue="url" filter={true}
value={cycle}
options={cyclelist}
/>
</div>
}
{ showTopTotal && filteredData.length < data.length &&
<div className="total_records_top_label" ><label >Filtered {filteredData.length} from {data.length}</label></div>}
......@@ -629,6 +826,8 @@ function ViewTable(props) {
const history = useHistory();
// Data to show in table
tbldata = props.data;
cyclelist= props.cycleList;
parentCallbackFunction = props.filterCallback;
parentCBonSelection = props.onRowSelection;
isunittest = props.unittest;
......
.p-multiselect{
height: 10px;
}
\ No newline at end of file
import {TimelineView} from './view';
import {WeekTimelineView} from './week.view';
import { ReservationList} from './list';
export {TimelineView, WeekTimelineView} ;
export {TimelineView, WeekTimelineView, ReservationList} ;
import React, {Component} from 'react';
import ReservationService from './../../services/reservation.service';
import AppLoader from "./../../layout/components/AppLoader";
import ViewTable from './../../components/ViewTable';
import PageHeader from '../../layout/components/PageHeader';
import CycleService from '../../services/cycle.service';
import _ from 'lodash';
import moment from 'moment';
export class ReservationList extends Component{
constructor(props){
super(props);
this.state = {
reservationsList: [],
defaultcolumns: [{
name:"System Id",
description:"Description",
start_time: {
name: "Start Time",
filter: "fromdatetime"
},
end_time: {
name: "End Time",
filter: "todatetime"
},
duration:"Duration (HH:mm:ss)",
type: "Reservation type",
subject: "Subject",
planned:"Planned",
stations:{
name:"Stations",
filter:"multiselect"
},
/* cycles:{
name:"Cycle Id",
filter:"select"
},*/
manual: "Manual",
dynamic: "Dynamic",
project_id: "Project",
expert: "Expert",
hba_rfi: "HBA-RFI",
lba_rfi: "LBA-RFI"
}],
optionalcolumns: [{
actionpath:"actionpath"
}],
columnclassname: [{
"Duration (HH:mm:ss)":"filter-input-75",
"Reservation type":"filter-input-100",
"Subject":"filter-input-50",
"Planned":"filter-input-50",
"Stations":"filter-input-150",
"Manual":"filter-input-50",
"Dynamic":"filter-input-50",
"Expert":"filter-input-50",
"HBA-RFI":"filter-input-50",
"LBA-RFI":"filter-input-50",
}],
defaultSortColumn: [{id: "System Id", desc: false}],
isLoading: true,
cycleList: [],
}
this.reservations= [];
this.cycleList= [];
this.sortListCycle= [];
}
async componentDidMount() {
const promises = [ ReservationService.getAllReservation(),
CycleService.getAllCycles(),
];
this.reservations = [];
await Promise.all(promises).then(responses => {
let reservation = {};
const cycleList = responses[1];
for( const response of responses[0]){
reservation = response;
reservation = this.mergeResourceWithReservation( reservation, response.specifications_doc.activity) ;
reservation = this.mergeResourceWithReservation( reservation, response.specifications_doc.effects );
reservation = this.mergeResourceWithReservation( reservation, response.specifications_doc.schedulability );
if (response.specifications_doc.resources.stations ) {
reservation['stations'] = response.specifications_doc.resources.stations.join();
} else {
reservation['stations'] = '';
}
//Get associated cycle list
reservation['cycles'] = this.getCycleByProject(reservation.project_id, cycleList).join();
if(reservation.duration === null || reservation.duration === ''){
reservation.duration = 'Unknown';
reservation['end_time']= 'Unknown';
} else {
reservation.duration = moment.utc((reservation.duration || 0)*1000).format('HH:mm:ss');
let endDate = moment(reservation.start_time);
endDate.add(Number(reservation.duration), 'seconds');
reservation['end_time']= moment(endDate).format('YYYY-MM-DD HH:mm:ss');
}
reservation['start_time']= moment(reservation.start_time).format('YYYY-MM-DD HH:mm:ss');
this.reservations.push(reservation);
};
//specifications_doc.resources
this.setState({
isLoading: false,
reservationsList: this.reservations,
cycleList: this.sortListCycle,
});
});
}
getCycleByProject (name, cycleList) {
let cycleName= [];
cycleList.map(cycle => {
if (_.includes( cycle.projects_ids, name)) {
cycleName.push(cycle.name);
const tmpCycleList = _.filter(this.sortListCycle, function(o) { return o.name === cycle.name });
if (tmpCycleList.length === 0) {
this.sortListCycle.push(cycle);
}
}
});
return cycleName;
}
mergeResourceWithReservation ( reservation, params) {
if( params ){
Object.keys(params).map((key, i) => (
reservation[key]= params[key]
));
}
return reservation;
}
render() {
return (
<React.Fragment>
<PageHeader location={this.props.location} title={'Reservation - List'}
actions={[]}
/>
{this.state.isLoading? <AppLoader /> : (this.state.reservationsList && this.state.reservationsList.length>0) ?
<ViewTable
data={this.state.reservationsList}
defaultcolumns={this.state.defaultcolumns}
optionalcolumns={this.state.optionalcolumns}
columnclassname={this.state.columnclassname}
defaultSortColumn={this.state.defaultSortColumn}
showaction="true"
paths={this.state.paths}
keyaccessor="name"
unittest={this.state.unittest}
tablename="reservation_list"
cycleList={this.state.cycleList}
/>
: <div>No Reservation found </div>
}
</React.Fragment>
);
}
}
......@@ -326,7 +326,9 @@ export class TimelineView extends Component {
return (
<React.Fragment>
<PageHeader location={this.props.location} title={'Scheduling Units - Timeline View'}
actions={[{icon: 'fa-calendar-alt',title:'Week View', props : { pathname: `/su/timelineview/week`}}]}/>
actions={[
{icon: 'fa-plus-square',title:'Reservation List', props : { pathname: `/su/timelineview/reservation/list`}},
{icon: 'fa-calendar-alt',title:'Week View', props : { pathname: `/su/timelineview/week`}}]}/>
{ this.state.isLoading ? <AppLoader /> :
<div className="p-grid">
{/* SU List Panel */}
......
......@@ -14,7 +14,7 @@ import ViewSchedulingUnit from './Scheduling/ViewSchedulingUnit'
import SchedulingUnitCreate from './Scheduling/create';
import EditSchedulingUnit from './Scheduling/edit';
import { CycleList, CycleCreate, CycleView, CycleEdit } from './Cycle';
import {TimelineView, WeekTimelineView} from './Timeline';
import {ReservationList, TimelineView, WeekTimelineView} from './Timeline';
import SchedulingSetCreate from './Scheduling/create.scheduleset';
import Workflow from './Workflow';
......@@ -159,7 +159,12 @@ export const routes = [
name: 'Workflow',
title: 'QA Reporting (TO)'
},
{
path: "/su/timelineview/reservation/list",
component: ReservationList,
name: 'Reservation List',
title:'Reservation List'
},
];
export const RoutedContent = () => {
......
const axios = require('axios');
axios.defaults.headers.common['Authorization'] = 'Basic dGVzdDp0ZXN0';
const ReservationService = {
getReservation: async function () {
try {
const url = `/api/reservation_template`;
const response = await axios.get(url);
return response.data.results;
} catch (error) {
console.error(error);
}
},
saveReservation: async function (reservation) {
try {
const response = await axios.post(('/api/reservation/'), reservation);
return response.data;
} catch (error) {
console.error(error);
return null;
}
},
getAllReservation: async function () {
try {
const url = `/api/reservation`;
const response = await axios.get(url);
return response.data.results;
} catch (error) {
console.error(error);
}
},
}
export default ReservationService;
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment