From 4ddc2572ad7edfe78247029097b78989c57d67d9 Mon Sep 17 00:00:00 2001 From: Fanna Lautenbach <lautenbach@astron.nl> Date: Thu, 27 Jul 2023 11:27:02 +0200 Subject: [PATCH] extract timelineitempopover + tests --- .../components/TimelineItemPopover.js | 88 +++++++++++++++++ .../components/TimelineItemPopover.test.js | 94 +++++++++++++++++++ .../src/routes/Timeline/week.view.js | 81 +--------------- 3 files changed, 184 insertions(+), 79 deletions(-) create mode 100644 SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/components/TimelineItemPopover.js create mode 100644 SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/components/TimelineItemPopover.test.js diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/components/TimelineItemPopover.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/components/TimelineItemPopover.js new file mode 100644 index 00000000000..ebbd178067a --- /dev/null +++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/components/TimelineItemPopover.js @@ -0,0 +1,88 @@ +import UIConstants from "../../../utils/ui.constants"; +import React from "react"; + +export default function TimelineItemPopover(props) { + const {mouseOverItem} = props; + if (!mouseOverItem) { + return; + } + return <div className="p-overlaypanel-content"> + {mouseOverItem && mouseOverItem.type === "SCHEDULE" && + <div className={`p-grid timeline-item su-${mouseOverItem.status}`} style={{width: '350px'}}> + <h3 className={`col-12 su-${mouseOverItem.status}-icon`}> + Scheduling Unit ({mouseOverItem.suId}) 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.name}</div> + <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> + <label className={`col-5 su-${mouseOverItem.status}-icon`}>Start Time:</label> + <div + className="col-7">{mouseOverItem.suStartTime.format(UIConstants.CALENDAR_DATETIME_FORMAT)}</div> + <label className={`col-5 su-${mouseOverItem.status}-icon`}>End Time:</label> + <div + className="col-7">{mouseOverItem.suStopTime.format(UIConstants.CALENDAR_DATETIME_FORMAT)}</div> + <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> + {mouseOverItem.status === 'unschedulable' && + <> + <label className={`col-5 su-${mouseOverItem.status}-icon`}>Unschedule + Reason:</label> + <div className="col-7">{mouseOverItem.unschedulable_reason}</div> + </> + } + {mouseOverItem.type === 'SCHEDULE' && + <> + <label className={`col-5 su-${mouseOverItem.status}-icon`}>Exposure + Time:</label> + <div className="col-7">{mouseOverItem.on_sky_duration}</div> + <label className={`col-5 su-${mouseOverItem.status}-icon`}>SU 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">{mouseOverItem.stations.groups ? `${mouseOverItem.stations.groups} : ${mouseOverItem.stations.counts}` : mouseOverItem.stations}</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.displayStartTime.format(UIConstants.CALENDAR_DATETIME_FORMAT)}</div> + <label className={`col-5`} style={{color: mouseOverItem.color}}>End Time:</label> + <div + className="col-7">{mouseOverItem.displayEndTime ? mouseOverItem.displayEndTime.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> + } + </div> +} diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/components/TimelineItemPopover.test.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/components/TimelineItemPopover.test.js new file mode 100644 index 00000000000..b9eb3f13bbf --- /dev/null +++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/components/TimelineItemPopover.test.js @@ -0,0 +1,94 @@ +import {render} from "@testing-library/react"; +import TimelineItemPopover from "./TimelineItemPopover"; +import moment from "moment"; +import {removeReact18ConsoleErrors} from "../../../utils/test.helper"; + +removeReact18ConsoleErrors() + +describe("TimelineItemPopover", () => { + let mouseOverItemSchedule = { + type: "SCHEDULE", + status: "scheduled", + suId: "123", + project: "X-men", + name: "Wolverine", + scheduleMethod: "dynamic", + suStartTime: moment("2023-07-27T08:00:00Z"), + suStopTime: moment("2023-07-27T10:00:00Z"), + antennaSet: "LBA", + stations: { + groups: 2, + counts: 8, + }, + on_sky_duration: 2.5, + duration: 3.5, + }; + test("Render type SCHEDULE for a schedulable item", () => { + const content = render(<TimelineItemPopover mouseOverItem={mouseOverItemSchedule}/>); + + console.log("container") + expect(content.getByText(`Scheduling Unit (${mouseOverItemSchedule.suId}) Overview`)).toBeInTheDocument(); + expect(content.getByText(`Project: ${mouseOverItemSchedule.project}`)).toBeInTheDocument(); + expect(content.getByText(`Scheduling Unit: ${mouseOverItemSchedule.name}`)).toBeInTheDocument(); + expect(content.getByText(`Scheduler: ${mouseOverItemSchedule.scheduleMethod}`)).toBeInTheDocument(); + expect(content.getByText(`Friends: ${mouseOverItemSchedule.friends ? mouseOverItemSchedule.friends : "-"}`)).toBeInTheDocument(); + expect(content.getByText(`Start Time: ${mouseOverItemSchedule.suStartTime.toISOString()}`)).toBeInTheDocument(); + expect(content.getByText(`End Time: ${mouseOverItemSchedule.suStopTime.toISOString()}`)).toBeInTheDocument(); + expect(content.getByText(`Antenna Set: ${mouseOverItemSchedule.antennaSet}`)).toBeInTheDocument(); + expect(content.getByText(`Stations: ${mouseOverItemSchedule.stations.groups}:${mouseOverItemSchedule.stations.counts}`)).toBeInTheDocument(); + expect(content.getByText(`Status: ${mouseOverItemSchedule.status}`)).toBeInTheDocument(); + expect(content.getByText("Exposure Time:")).toBeInTheDocument(); + expect(content.getByText(mouseOverItemSchedule.on_sky_duration.toString())).toBeInTheDocument(); + expect(content.getByText("SU Duration:")).toBeInTheDocument(); + expect(content.getByText(mouseOverItemSchedule.duration.toString())).toBeInTheDocument(); + }); + + test("Render type SCHEDULE for an unschedulable item", () => { + const {getByText} = render(<TimelineItemPopover mouseOverItem={mouseOverItemSchedule}/>); + + expect(getByText(`Scheduling Unit (${mouseOverItemSchedule.suId}) Overview`)).toBeInTheDocument(); + expect(getByText(`Project: ${mouseOverItemSchedule.project}`)).toBeInTheDocument(); + expect(getByText(`Scheduling Unit: ${mouseOverItemSchedule.name}`)).toBeInTheDocument(); + expect(getByText(`Scheduler: ${mouseOverItemSchedule.scheduleMethod}`)).toBeInTheDocument(); + expect(getByText(`Friends: ${mouseOverItemSchedule.friends ? mouseOverItemSchedule.friends : "-"}`)).toBeInTheDocument(); + expect(getByText(`Start Time: ${mouseOverItemSchedule.suStartTime.toISOString()}`)).toBeInTheDocument(); + expect(getByText(`End Time: ${mouseOverItemSchedule.suStopTime.toISOString()}`)).toBeInTheDocument(); + expect(getByText(`Antenna Set: ${mouseOverItemSchedule.antennaSet}`)).toBeInTheDocument(); + expect(getByText(`Stations: ${mouseOverItemSchedule.stations.groups}:${mouseOverItemSchedule.stations.counts}`)).toBeInTheDocument(); + expect(getByText(`Status: ${mouseOverItemSchedule.status}`)).toBeInTheDocument(); + expect(getByText("Unschedule Reason:")).toBeInTheDocument(); + expect(getByText(mouseOverItemSchedule.unschedulable_reason)).toBeInTheDocument(); + + }); + + test("Render a RESERVATION", () => { + const mouseOverItem = { + type: "RESERVATION", + bgColor: "#ffffff", + color: "#000000", + name: "Reservation Name", + desc: "Reservation Description", + activity_type: "Type", + stations: "Station Name", + project: "Project Name", + displayStartTime: moment("2023-07-27T12:00:00Z"), + displayEndTime: moment("2023-07-27T14:00:00Z"), + duration: 2, + planned: true, + }; + + const {getByText} = render(<TimelineItemPopover mouseOverItem={mouseOverItem}/>); + + expect(getByText("Reservation Overview")).toBeInTheDocument(); + expect(getByText(`Name: ${mouseOverItem.name}`)).toBeInTheDocument(); + expect(getByText(`Description: ${mouseOverItem.desc}`)).toBeInTheDocument(); + + }); + + test.each([null, undefined, {}])('Render nothing on invalid input: %s', (mouseOverItem) => { + const {queryByText} = render(<TimelineItemPopover mouseOverItem={mouseOverItem}/>); + + expect(queryByText("Reservation Overview")).not.toBeInTheDocument(); + expect(queryByText("Scheduling Unit Overview")).not.toBeInTheDocument(); + }); +}); \ No newline at end of file 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 09dd8832d62..9fb42ede8f4 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 @@ -34,6 +34,7 @@ import AuthUtil from '../../utils/auth.util'; import AuthStore from '../../authenticate/auth.store'; import TopProgressBar from '../../layout/components/TopProgressBar'; import {getTimelineItem} from "./week.view.helper"; +import TimelineItemPopover from "./components/TimelineItemPopover"; // Color constant for status export const STATUS_COLORS = { @@ -1648,85 +1649,7 @@ export class WeekTimelineView extends Component { {/* SU Item Tooltip popover with SU status color */} <div className="p-overlaypanel p-component timeline-popover" style={{...this.state.popPosition, zIndex: 1324, opacity: 1.944}}> - <div className="p-overlaypanel-content"> - {mouseOverItem && mouseOverItem.type === "SCHEDULE" && - <div className={`p-grid su-${mouseOverItem.status}`} style={{width: '350px'}}> - <h3 className={`col-12 su-${mouseOverItem.status}-icon`}> - Scheduling Unit ({mouseOverItem.suId}) 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.name}</div> - <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> - <label className={`col-5 su-${mouseOverItem.status}-icon`}>Start Time:</label> - <div - className="col-7">{mouseOverItem.suStartTime.format(UIConstants.CALENDAR_DATETIME_FORMAT)}</div> - <label className={`col-5 su-${mouseOverItem.status}-icon`}>End Time:</label> - <div - className="col-7">{mouseOverItem.suStopTime.format(UIConstants.CALENDAR_DATETIME_FORMAT)}</div> - <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> - {mouseOverItem.status === 'unschedulable' && - <> - <label className={`col-5 su-${mouseOverItem.status}-icon`}>Unschedule - Reason:</label> - <div className="col-7">{mouseOverItem.unschedulable_reason}</div> - </> - } - {mouseOverItem.type === 'SCHEDULE' && - <> - <label className={`col-5 su-${mouseOverItem.status}-icon`}>Exposure - Time:</label> - <div className="col-7">{mouseOverItem.on_sky_duration}</div> - <label className={`col-5 su-${mouseOverItem.status}-icon`}>SU 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">{mouseOverItem.stations.groups ? `${mouseOverItem.stations.groups} : ${mouseOverItem.stations.counts}` : mouseOverItem.stations}</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.displayStartTime.format(UIConstants.CALENDAR_DATETIME_FORMAT)}</div> - <label className={`col-5`} style={{color: mouseOverItem.color}}>End Time:</label> - <div - className="col-7">{mouseOverItem.displayEndTime ? mouseOverItem.displayEndTime.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> - } - </div> + <TimelineItemPopover mouseOverItem={mouseOverItem}/> </div> {/* Open Websocket after loading all initial data */} {!this.state.isLoading && -- GitLab