diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/list.tabs.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/list.tabs.js index 1d6b270679205a88a36a258e980942d7e49b2fbd..d912e1ed14be8889456b2dd5fc74c7df68f68678 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/list.tabs.js +++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/list.tabs.js @@ -27,6 +27,7 @@ class TimelineListTabs extends Component { this.timelineUIAttributes = UtilService.localStore({ type: 'get', key: "TIMELINE_UI_ATTR" }) || {}; this.suListFilterCallback = this.suListFilterCallback.bind(this); this.taskListFilterCallback = this.taskListFilterCallback.bind(this); + this.reservListFilterCallback = this.reservListFilterCallback.bind(this); this.getTaskList = this.getTaskList.bind(this); this.getSUFilterOptions = this.getSUFilterOptions.bind(this); this.getTaskFilterOptions = this.getTaskFilterOptions.bind(this); @@ -70,7 +71,8 @@ class TimelineListTabs extends Component { */ suListFilterCallback(filteredData) { this.filteredSUB = filteredData; - this.props.suListFilterCallback(filteredData); + this.filteredTasks = null; + this.props.suListFilterCallback(filteredData, this.filteredTasks, this.filteredReservs); } /** @@ -79,7 +81,18 @@ class TimelineListTabs extends Component { * @param {Array} filteredData - Array of task table rows */ taskListFilterCallback(filteredData) { - this.props.suListFilterCallback(this.filteredSUB, filteredData); + this.filteredTasks = filteredData; + this.props.suListFilterCallback(this.filteredSUB, filteredData, this.filteredReservs); + } + + /** + * Callback function passed to Reservation list table which in turn call back the parenst (View or Weekview) callback function + * to show or hide the reservations shown in the timeline. + * @param {Array} filteredData - Array of reservation table rows + */ + reservListFilterCallback(filteredData) { + this.filteredReservs = filteredData; + this.props.suListFilterCallback(this.filteredSUB, this.filteredTasks, filteredData); } /** @@ -210,7 +223,7 @@ class TimelineListTabs extends Component { showColumnFilter={true} tablename={`timeline_reservation_list`} showTopTotal={false} - // filterCallback={this.taskListFilterCallback} // TODO: Implementing filter callback to timeline + filterCallback={this.reservListFilterCallback} lsKeySortColumn={"ResListSortColumn"} toggleBySorting={(sortData) => this.storeSortingColumn("ResListSortColumn", sortData)} pageUpdated={this.pageUpdated} 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 da7b6ff5f534d7a7f87df5ab5b31170c8021c47c..6e4f1d0110f17dc623abb6d60da4f0ee423f6492 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/view.js +++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/view.js @@ -146,10 +146,6 @@ export class TimelineView extends Component { ] this.setState({menuOptions: menuOptions, loader: true }); TaskService.getTaskTypes().then(results => {taskTypes = results}); - // Fetch Reservations and keep ready to use in station view - ReservationService.getReservations().then(reservations => { - this.reservations = reservations; - }); UtilService.getReservationTemplates().then(templates => { this.reservationTemplate = templates.length > 0 ? templates[0] : null; if (this.reservationTemplate) { @@ -301,6 +297,11 @@ export class TimelineView extends Component { * @returns - Object with both original SUBs from backend and formatted SUBs for table list. */ async loadSchedulingUnits(startTime, endTime) { + ReservationService.getTimelineReservations(startTime.format(UIConstants.CALENDAR_DATETIME_FORMAT), + endTime.format(UIConstants.CALENDAR_DATETIME_FORMAT)) + .then(reservations => { + this.reservations = _.uniqBy(this.reservations.concat(reservations), 'id'); + }); let suBlueprints = await ScheduleService.getExpandedSUList(startTime.format(UIConstants.CALENDAR_DATETIME_FORMAT), endTime.format(UIConstants.CALENDAR_DATETIME_FORMAT)); suBlueprints = _.filter(suBlueprints, suBlueprint => suBlueprint.status.toLowerCase !== 'obsolete'); @@ -385,7 +386,6 @@ export class TimelineView extends Component { let items = [], itemGroup = []; const subtaskTemplates = this.subtaskTemplates; for (let task of suBlueprint.tasks) { - console.log(task); if (((!this.state.stationView && this.state.selectedTaskTypes.indexOf(task.task_type)>=0) || (this.state.stationView && task.task_type === 'observation')) && ( filteredTasks.length===0 || filteredTasks.indexOf(task.id)>=0 ) @@ -682,9 +682,10 @@ export class TimelineView extends Component { * @param {moment} startTime * @param {moment} endTime */ - addStationReservations(items, startTime, endTime) { + addStationReservations(items, startTime, endTime, reservFilterData) { let reservations = this.reservations; let reservationItems = []; + let filteredReservations = reservFilterData?_.map(reservFilterData, data => {data.id = data.actionpath.split("view/")[1]; return parseInt(data.id);}):[]; for (const reservation of reservations) { const reservationStartTime = moment.utc(reservation.start_time); const reservationEndTime = reservation.duration ? reservationStartTime.clone().add(reservation.duration, 'seconds') : endTime; @@ -697,6 +698,7 @@ export class TimelineView extends Component { || reservationEndTime.isBetween(startTime, endTime) || (reservationStartTime.isSameOrBefore(startTime) && reservationEndTime.isSameOrAfter(endTime))) + && (filteredReservations.length === 0 || filteredReservations.indexOf(reservation.id)>=0) && (this.state.reservationFilter.length === 0 || // No reservation filter added this.state.reservationFilter.indexOf(reservationSpec.activity.type) >= 0 )) { // Reservation reason == Filtered reaseon if (this.state.stationView) { @@ -790,16 +792,18 @@ export class TimelineView extends Component { let reservations = this.reservations; for (const reservation of reservations) { const reservationStartTime = moment.utc(reservation.start_time); - const reservationEndTime = reservation.duration ? reservationStartTime.clone().add(reservation.duration, 'seconds') : endTime; + const reservationEndTime = reservation.duration ? reservationStartTime.clone().add(reservation.duration, 'seconds') : null; const reservationSpec = reservation.specifications_doc; - if ((reservationStartTime.isSame(startTime) - || reservationStartTime.isSame(endTime) - || reservationStartTime.isBetween(startTime, endTime) - || reservationEndTime.isSame(startTime) - || reservationEndTime.isSame(endTime) - || reservationEndTime.isBetween(startTime, endTime) - || (reservationStartTime.isSameOrBefore(startTime) - && reservationEndTime.isSameOrAfter(endTime))) + // if ((reservationStartTime.isSame(startTime) + // || reservationStartTime.isSame(endTime) + // || reservationStartTime.isBetween(startTime, endTime) + // || reservationEndTime.isSame(startTime) + // || reservationEndTime.isSame(endTime) + // || reservationEndTime.isBetween(startTime, endTime) + // || (reservationStartTime.isSameOrBefore(startTime) + // && reservationEndTime.isSameOrAfter(endTime))) + if ((reservationStartTime.isSameOrBefore(endTime) + && (reservationEndTime === null || reservationEndTime.isSameOrAfter(startTime))) && (this.state.reservationFilter.length === 0 || // No reservation filter added this.state.reservationFilter.indexOf(reservationSpec.activity.type) >= 0 )) { // Reservation reason == Filtered reaseon if (!this.state.stationView || @@ -886,12 +890,13 @@ export class TimelineView extends Component { /** * Callback function to pass to the Scheduling Unit Table component to pass back filtered data. - * The same function is called when the filter applied in the task table so that the tasks shown in the timeline - * are updated accordingly. + * The same function is called when the filter applied in the task and reservation tables so that + * the tasks and reservations shown in the timeline are updated accordingly. * @param {Array} filteredSUData - filtered data from Scheduling Unit list table * @param {Array} filteredTaskData - filtered data from Task list table. This will be null when the function is called by SU List table. + * @param {Array} filteredReservData - filtered data from Reservation list table. */ - suListFilterCallback(filteredSUData, filteredTaskData) { + suListFilterCallback(filteredSUData, filteredTaskData, filteredReservData) { let group = [], items = []; const suBlueprints = this.state.suBlueprints; for (const data of filteredSUData) { @@ -920,7 +925,7 @@ export class TimelineView extends Component { } } if (this.state.stationView || this.state.showReservation) { - items = this.addStationReservations(items, this.state.currentStartTime, this.state.currentEndTime); + items = this.addStationReservations(items, this.state.currentStartTime, this.state.currentEndTime, filteredReservData); } if (this.state.showReservation) { let reservationGroup = [{id: "RESERVATION", parent: "RESERVATION", diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/week.view.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/week.view.js index a4690fda9d0d2cf645b4dba37bddda93fe958de6..692b5258551d9bf1b043e68b4c2f5f0090b8a9d2 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/week.view.js +++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/week.view.js @@ -115,9 +115,9 @@ export class WeekTimelineView extends Component { ] this.setState({menuOptions: menuOptions, userPermission: weekviewPermission}); - ReservationService.getReservations().then(reservations => { - this.reservations = reservations; - }); + // ReservationService.getReservations().then(reservations => { + // this.reservations = reservations; + // }); UtilService.getReservationTemplates().then(templates => { this.reservationTemplate = templates.length > 0 ? templates[0] : null; if (this.reservationTemplate) { @@ -244,6 +244,11 @@ export class WeekTimelineView extends Component { */ async loadSchedulingUnits(startTime, endTime) { let suList = []; + ReservationService.getTimelineReservations(startTime.format(UIConstants.CALENDAR_DATETIME_FORMAT), + endTime.format(UIConstants.CALENDAR_DATETIME_FORMAT)) + .then(reservations => { + this.reservations = _.uniqBy(this.reservations.concat(reservations), 'id'); + }); let suBlueprints = await ScheduleService.getExpandedSUList(startTime.format(UIConstants.CALENDAR_DATETIME_FORMAT), endTime.format(UIConstants.CALENDAR_DATETIME_FORMAT)); suBlueprints = _.filter(suBlueprints, suBlueprint => suBlueprint.status.toLowerCase !== 'obsolete'); @@ -871,18 +876,12 @@ export class WeekTimelineView extends Component { let reservations = this.reservations; for (const reservation of reservations) { const reservationStartTime = moment.utc(reservation.start_time); - const reservationEndTime = reservation.duration ? reservationStartTime.clone().add(reservation.duration, 'seconds') : endTime; + const reservationEndTime = reservation.duration ? reservationStartTime.clone().add(reservation.duration, 'seconds') : null; const reservationSpec = reservation.specifications_doc; - if ((reservationStartTime.isSame(startTime) - || reservationStartTime.isSame(endTime) - || reservationStartTime.isBetween(startTime, endTime) - || reservationEndTime.isSame(startTime) - || reservationEndTime.isSame(endTime) - || reservationEndTime.isBetween(startTime, endTime) - || (reservationStartTime.isSameOrBefore(startTime) - && reservationEndTime.isSameOrAfter(endTime))) + if ((reservationStartTime.isSameOrBefore(endTime) + && (reservationEndTime === null || reservationEndTime.isSameOrAfter(startTime))) && (!this.state.reservationFilter || // No reservation filter added - reservationSpec.activity.type === this.state.reservationFilter)) { // Reservation reason == Filtered reaseon + reservationSpec.activity.type === this.state.reservationFilter)) { // Reservation reason == Filtered reaseon let item = _.cloneDeep(reservation); item.stop_time = item.stop_time || "Unknown"; item.duration = UnitConverter.getSecsToDDHHmmss(item.duration) || "Unknown"; diff --git a/SAS/TMSS/frontend/tmss_webapp/src/services/reservation.service.js b/SAS/TMSS/frontend/tmss_webapp/src/services/reservation.service.js index c0a348feefdcc9f90b0a8ab4f158b59f484c6af5..85f9183ea2db87f7df141af64503fe751c68bc0f 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/services/reservation.service.js +++ b/SAS/TMSS/frontend/tmss_webapp/src/services/reservation.service.js @@ -45,6 +45,33 @@ const ReservationService = { } return reservations; }, + /** Get the reservations that are present during the period specified by startTime and stopTime */ + getTimelineReservations: async(startTime, stopTime) => { + let reservations = []; + try { + let url = `/api/reservation/?ordering=id`; + if (stopTime) { // Gets the reservations started and stopped between the period + url = `${url}&start_time_before=${stopTime || ''}&stop_time_after=${startTime || ''}`; + } else if (startTime) { // Gets the reservations started before the startTime and still exists + url = `${url}&start_time_before=${startTime || ''}&stop_time_isnull=true`; + } + let initialResponse = await axios.get(url); + const totalCount = initialResponse.data.count; + const initialCount = initialResponse.data.results.length + reservations = reservations.concat(initialResponse.data.results); + if (totalCount > initialCount) { + let secondResponse = await axios.get(`${url}&limit=${totalCount-initialCount}&offset=${initialCount}`); + reservations = reservations.concat(secondResponse.data.results); + } + if (stopTime) { // Get the reservations started before the stopTime and exists. + let indefiniteReservations = await ReservationService.getReservations(stopTime); + reservations = reservations.concat(indefiniteReservations); + } + } catch(error) { + console.error('[schedule.services.getTimelineReservations]',error); + } + return reservations; + }, getReservation: async function (id) { try { const response = await axios.get(`/api/reservation/${id}`);