From e1d27362ee4ee34d370e2e87ddc439f25eadc5fa Mon Sep 17 00:00:00 2001 From: Fanna Lautenbach <lautenbach@astron.nl> Date: Thu, 3 Aug 2023 18:32:09 +0200 Subject: [PATCH] initial styling changes --- SAS/TMSS/frontend/tmss_webapp/src/App.css | 2 +- .../components/Timeline/CalendarTimeline.js | 100 ++++--- .../src/layout/sass/_timeline.scss | 246 +++++++++++------- .../Timeline/components/DateTimeNavigator.js | 105 ++++---- .../routes/Timeline/components/Legendbar.js | 62 +++-- .../src/routes/Timeline/components/Toolbar.js | 130 +++++---- .../tmss_webapp/src/routes/Timeline/view.js | 58 ++--- .../src/routes/Timeline/week.view.js | 15 +- 8 files changed, 447 insertions(+), 271 deletions(-) diff --git a/SAS/TMSS/frontend/tmss_webapp/src/App.css b/SAS/TMSS/frontend/tmss_webapp/src/App.css index 37b319b8619..60f55563b14 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/App.css +++ b/SAS/TMSS/frontend/tmss_webapp/src/App.css @@ -46,7 +46,7 @@ h3, .h3 { } h5, .h5 { - font-size: 15px !important; + font-size: 14px !important; } a{ diff --git a/SAS/TMSS/frontend/tmss_webapp/src/components/Timeline/CalendarTimeline.js b/SAS/TMSS/frontend/tmss_webapp/src/components/Timeline/CalendarTimeline.js index f183bacee90..5dc26ae7a82 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/components/Timeline/CalendarTimeline.js +++ b/SAS/TMSS/frontend/tmss_webapp/src/components/Timeline/CalendarTimeline.js @@ -28,6 +28,7 @@ import shortcutButtonsPlugin from "shortcut-buttons-flatpickr"; import UIConstants from '../../utils/ui.constants'; import DateTimeNavigator from "../../routes/Timeline/components/DateTimeNavigator"; import Legendbar from "../../routes/Timeline/components/Legendbar"; +import Toolbar from "../../routes/Timeline/components/Toolbar"; // Label formats for day headers based on the interval label width const DAY_HEADER_FORMATS = [{ name: "longer", minWidth: 300, maxWidth: 50000, format: "DD dddd, MMMM YYYY"}, @@ -123,8 +124,31 @@ export class CalendarTimeline extends Component { scrollPosition: 0, weekDay: weekDay?[weekDay.format(UTC_DATE_FORMAT)]:null, showCustomDate: false, - reset: false + reset: false, + //Toolbar properties + onSkyViewToggle: props.onSkyViewToggle, + setOnSkyViewToggle: props.setOnSkyViewToggle, + stationsViewToggle: props.stationsViewToggle, + setStationsViewToggle: props.setStationsViewToggle, + isStationTasksVisible: props.isStationTasksVisible, + changeViewBlocks: props.changeViewBlocks, + selectedStationGroup: props.selectedStationGroup, + mainStationGroupOptions: props.mainStationGroupOptions, + setSelectedStationGroup: props.setSelectedStationGroup, + showTimeLineItems: props.showTimelineItems, + showSUs: props.showSUs, + showTasks: props.showTasks, + selectedTaskTypes: props.selectedTaskTypes, + taskTypes: props.taskTypes, + setSelectedTaskTypes: props.setSelectedTaskTypes, + setGroupByProject: props.setGroupByProject, + isGroupedByProject: props.isGroupedByProject, + reservationsViewToggle: props.reservationsViewToggle, + setReservationsViewToggle: props.setReservationsViewToggle, + reservationFilter: props.reservationFilter, + setReservationFilter: props.setReservationFilter } + if (props.viewType && props.viewType===UIConstants.timeline.types.WEEKVIEW) { this.state.timelineStartDate = this.state.defaultStartTime.clone(); this.state.timelineEndDate = this.state.defaultEndTime.clone(); @@ -1375,13 +1399,13 @@ export class CalendarTimeline extends Component { let weekHeaderVisible = this.state.weekHeaderVisible; let lstDateHeaderUnit = this.state.lstDateHeaderUnit; let rangeDays = endDate.diff(startDate, 'days'); - dayHeaderVisible = rangeDays > 35?false: true; + dayHeaderVisible = rangeDays > 35?false: true; weekHeaderVisible = rangeDays > 35?true: false; lstDateHeaderUnit = rangeDays > 35?"day":"hour"; this.setState({zoomRange:value, prevZoomRange:value, defaultStartTime: startDate, defaultEndTime: endDate, zoomLevel: ZOOM_LEVELS[ZOOM_LEVELS.length-1].name, isTimelineZoom: false, - dayHeaderVisible: dayHeaderVisible, weekHeaderVisible: weekHeaderVisible, + dayHeaderVisible: dayHeaderVisible, weekHeaderVisible: weekHeaderVisible, lstDateHeaderUnit: lstDateHeaderUnit }); const result = await this.changeDateRange(startDate, endDate); @@ -1539,7 +1563,6 @@ export class CalendarTimeline extends Component { } render() { - let isWeekView = this.state.viewType === UIConstants.timeline.types.WEEKVIEW; const isRange = this.state.viewType !== UIConstants.timeline.types.WEEKVIEW; let onCloseDateFunction = isRange ? (value) => { @@ -1553,36 +1576,53 @@ export class CalendarTimeline extends Component { } return ( <React.Fragment> - <DateTimeNavigator - currentUTC={this.state.currentUTC} - allowLive={isRange} - timelineUIAttributes={this.timelineUIAttributes} - timelineCommonUtils={this.timelineCommonUtils} - isRange={isRange} - currentDateValue={isRange ? this.state.zoomRange : this.state.weekDay} - onChangeDateCallback={isRange ? (value) => this.setZoomRange(value, false) : undefined} - onCloseDateCallback={onCloseDateFunction} - onClickDateResetButtonCallback={isRange ? () => this.setZoomRange(null, true) : this.resetToCurrentTime} - onWeekChangeCallback={isRange ? undefined : this.changeWeek} - onClickTimeZoomResetButtonCallback={this.resetToCurrentTime} - moveLeftCallback={this.moveLeft} - moveRightCallback={this.moveRight} - zoomOutCallback={this.zoomIn} - zoomInCallback={this.zoomOut} - zoomLevel={this.state.zoomLevel} - allZoomLevels={this.ZOOM_LEVELS} - onChangeZoomLevelCallback={this.changeZoomLevel} - /> - {/* Toolbar for the timeline */} - <Legendbar/> + <div className="timeline-tools"> + <Toolbar onSkyViewToggle={this.state.onSkyViewToggle} + setOnSkyViewToggle={this.state.setOnSkyViewToggle} + stationsViewToggle={this.state.stationsViewToggle} + setStationsViewToggle={this.state.setStationsViewToggle} + isStationTasksVisible={this.state.isStationTasksVisible} + changeViewBlocks={this.state.changeViewBlocks} + selectedStationGroup={this.state.selectedStationGroup} + mainStationGroupOptions={this.state.mainStationGroupOptions} + setSelectedStationGroup={this.state.setSelectedStationGroup} + showTimeLineItems={this.state.showTimelineItems} + showSUs={this.state.showSUs} + showTasks={this.state.showTasks} + selectedTaskTypes={this.state.selectedTaskTypes} + taskTypes={this.state.taskTypes} + setSelectedTaskTypes={this.state.setSelectedTaskTypes} + setGroupByProject={this.state.setGroupByProject} + isGroupedByProject={this.state.isGroupedByProject} + reservationsViewToggle={this.state.reservationsViewToggle} + setReservationsViewToggle={this.state.setReservationsViewToggle} + reservationFilter={this.state.reservationFilter} + setReservationFilter={this.state.setReservationFilter}/> + <DateTimeNavigator + currentUTC={this.state.currentUTC} + allowLive={isRange} + timelineUIAttributes={this.timelineUIAttributes} + timelineCommonUtils={this.timelineCommonUtils} + isRange={isRange} + currentDateValue={isRange ? this.state.zoomRange : this.state.weekDay} + onChangeDateCallback={isRange ? (value) => this.setZoomRange(value, false) : undefined} + onCloseDateCallback={onCloseDateFunction} + onClickDateResetButtonCallback={isRange ? () => this.setZoomRange(null, true) : this.resetToCurrentTime} + onWeekChangeCallback={isRange ? undefined : this.changeWeek} + onClickTimeZoomResetButtonCallback={this.resetToCurrentTime} + moveLeftCallback={this.moveLeft} + moveRightCallback={this.moveRight} + zoomOutCallback={this.zoomIn} + zoomInCallback={this.zoomOut} + zoomLevel={this.state.zoomLevel} + allZoomLevels={this.ZOOM_LEVELS} + onChangeZoomLevelCallback={this.changeZoomLevel}/> + <Legendbar/> + </div> <div onMouseOut={e => this.cursorTime = null }> <Timeline groups={this.state.group} items={this.state.items} - // Use these below properties to stop zoom and move - // defaultTimeStart={this.props.defaultStartTime?this.props.defaultStartTime:this.state.defaultStartTime} - // defaultTimeStart={this.state.defaultStartTime} - // defaultTimeEnd={this.state.defaultEndTime} visibleTimeStart={this.state.defaultStartTime.valueOf()} visibleTimeEnd={this.state.defaultEndTime.valueOf()} resizeDetector={containerResizeDetector} diff --git a/SAS/TMSS/frontend/tmss_webapp/src/layout/sass/_timeline.scss b/SAS/TMSS/frontend/tmss_webapp/src/layout/sass/_timeline.scss index dc65dd0f130..16f3dd1e9ec 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/layout/sass/_timeline.scss +++ b/SAS/TMSS/frontend/tmss_webapp/src/layout/sass/_timeline.scss @@ -16,61 +16,187 @@ // border: none !important; } -.timeline-view-toolbar { - margin-left: 10px; -} +.timeline-tools { + //The timeline tools consists of 3 elements: + // - Toolbar (.timeline-view-toolbar), + // - DateTimeNavigator (.timeline-datetime-navigator), + // - Legendbar (.legendbar) + //adapt the width accordingly + display: flex; -.timeline-view-toolbar label { - margin-bottom: 0px; - vertical-align: top; - margin-right: 10px; + .header { + display: flex; + justify-content: center; + text-decoration: underline; + font-size: 14px; + font-weight: 600; + color: #004B93; + padding-bottom: 1rem; + } + + .group { + display: flex; + width: 100%; + + &--row { + flex-direction: row; + justify-content: space-evenly; + } + + &--disabled { + opacity: 50%; + cursor: not-allowed; + } + } } -.timeline-view-toolbar .p-radiobutton { - margin-top: -18px; - margin-right: 3px; - height: 25px; +.timeline-view-toolbar { + margin-right: 2.5rem; + flex-direction: row; + overflow: scroll; + + label { + display: inline-block; + width: 6rem; + vertical-align: top; + padding-right: 0.75rem; + } + + .p-radiobutton { + margin-top: -18px; + margin-right: 3px; + height: 25px; + } + + .toggle-container { + padding-right: 1rem; + flex: 0 0 auto; + + .disabled { + opacity: 50%; + cursor: not-allowed; + } + } + + .multiselect-container { + .disabled { + opacity: 50%; + cursor: not-allowed; + } + + .p-multiselect-label-container { + height: inherit; + } + } + + .radiobutton-container { + display: ruby; + + .button-label { + width: auto; + } + } } .timeline-toolbar-margin-top-0 { margin-top: 0px !important; } -.timeline-toolbar { - // margin-top: 25px; +.timeline-datetime-navigator { margin-bottom: 2px; font-size: 12px; -} + flex-direction: row; + flex: 0 0 auto; + + .datetime-info-container { + width: 50%; + display: inline-grid; + + .element { + display: ruby; + overflow: hidden; + text-overflow: ellipsis; + } + + label { + padding: 0 0.25rem; + } + } + + .selector-container { + width: 75%; + + label { + margin: 0.1rem; + } + + .p-button.p-button-icon-only { + line-height: 0; + padding: 0.1rem; + margin-right: 0.1rem; + } + + .week-changer { + margin-top: 0.25rem; + + label { + padding: 0 0.25rem; + } + } + } + + .zoom-selector-container { + label { + margin-right: 0.25rem; + } + + .p-dropdown { + float: none + } + } + + .move-container { + label { + margin-left: 0.5rem; + } + + .pi { + font-size: 1.5rem; + font-weight: normal; + color: var(--gray-500); + } + } -.timeline-actionbar { - padding-right: 0px; } -.timeline-actionbar button { - padding-top: 3px; - font-size: 1.0rem; - padding-left: 3px; - // float: right; +.legendbar { + flex-direction: row; + font-size: 10px !important; + + .section { + display: flex; + flex-direction: row; + line-height: 1; + + label { + font-size: 0.75rem; + text-overflow: ellipsis; + overflow: hidden; + } + } + } -.timeline-toolbar .p-dropdown { +.p-dropdown { float: right; } -.timeline-toolbar .p-dropdown, .timeline-toolbar .p-dropdown-panel { +.p-dropdown, .p-dropdown-panel { font-size: 12px !important; white-space: nowrap; } -.timeline-filters, .timeline-bottom { - padding-top: 25px; -} - -.timeline-filters button { - // width: auto !important; -} - -.timeline-filters .p-calendar .p-inputtext { +.p-inputtext { font-size: 12px; } @@ -99,18 +225,6 @@ border-bottom-left-radius: 0px !important; } -.timeline-week-span { - margin-left: 5px; - margin-right: 5px; -} - -.timeline-button { - padding-bottom: 5px; - padding-left: 0px; - padding-right: 0px; - padding-top: 25px; -} - .timeline-details-pane { font-size: 14px; flex-direction: column; @@ -132,11 +246,6 @@ } } - -#now-btn { - margin-left: 10px; -} - .sidebar-header { color: #ffffff; text-align: right; @@ -154,18 +263,6 @@ font-size: 14px; } -.legend-section { - background-color: purple; -} - -.legend-header { - font-size: 0.75rem; - font-weight: bold; - text-decoration: underline; - padding-right: 0.25rem; - justify-content: center; - display: flex; -} .suntime-header { line-height: 30px; @@ -463,24 +560,8 @@ } .su-legend { - cursor: default; - overflow: hidden; - // text-overflow: ellipsis; - // white-space: nowrap; - text-align: center; padding: 0.5rem; - margin: 0.25rem; -} - -.legendbar { - // height: 20px; - font-size: 10px !important; - position: sticky; - top: 0px; - z-index: 999; - margin-top: 5px; - // margin-left: 8px; - background-color: white; + margin-bottom: 0.5rem; } .timeline-popover { @@ -534,11 +615,6 @@ body .p-multiselect-panel .p-multiselect-header .p-multiselect-filter-container justify-content: flex-start; } -.sub-header { - display: inline-block; - padding: 10px 5px !important; -} - .sub-header-content { display: inline-block; padding: 0px !important; @@ -556,10 +632,6 @@ body .p-multiselect-panel .p-multiselect-header .p-multiselect-filter-container vertical-align: top; } -.subheader-dropdown-div { - margin-top: 8px; -} - .body .p-inputswitch { width: 3em; height: 1.75em; diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/components/DateTimeNavigator.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/components/DateTimeNavigator.js index e504dfc79bb..89ace643567 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/components/DateTimeNavigator.js +++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/components/DateTimeNavigator.js @@ -6,25 +6,21 @@ import {Dropdown} from "primereact/dropdown"; import React, {useEffect, useState} from "react"; import UtilService from "../../../services/util.service"; import moment from "moment/moment"; -import confirmDatePlugin from "flatpickr/dist/plugins/confirmDate/confirmDate"; - -const UTC_DATE_FORMAT = "YYYY-MM-DD"; -const UTC_TIME_FORMAT = "HH:mm:ss"; function getDateTimeElement(title, time, formatter) { if (!time) { return null } - return <div style={{marginTop: "0px"}}> - <label - style={{marginBottom: "0px"}}>{title}:</label><span>{time.format(formatter)}</span> + const formattedDateTime = time.format(formatter); + return <div className="element"> + <label>{title}:</label><span className="h5" title={formattedDateTime}>{formattedDateTime}</span> </div> } function getDateTimeInfo(currentUTC, currentLST) { - return <div className="p-col-2" style={{padding: '0px 0px 0px 10px'}}> - {getDateTimeElement("Date", currentUTC, UTC_DATE_FORMAT)} - {getDateTimeElement("UTC", currentUTC, UTC_TIME_FORMAT)} + return <div className="datetime-info-container"> + {getDateTimeElement("Date", currentUTC, "YYYY-MM-DD")} + {getDateTimeElement("UTC", currentUTC, "HH:mm:ss")} {getDateTimeElement("LST", currentLST, UIConstants.CALENDAR_TIME_FORMAT)} </div> } @@ -34,9 +30,9 @@ function getMoveWithTimeCheckbox(allowLive, isLive, setIsLive) { //TODO: make su return null } return <div className="p-col-1 timeline-filters" style={{paddingTop: "5px"}}> - <label style={{paddingRight: "3px", marginBottom: "0px"}}>Move with time</label> <Checkbox checked={isLive} onChange={(e) => setIsLive(e.checked)} - title="Move the timeline every 5 seconds a little to the right"/> + title="Move the timeline every 5 seconds a little to the right" style={{paddingRight: "3px"}}/> + <label style={{marginBottom: "0px"}}>Move with time</label> </div> } @@ -61,7 +57,7 @@ function getDateSelector(isRange, currentDateValue, onChangeDateCallback, onClos const resetButtonTitle = isRange ? "Reset to the default date range" : "Reset to the current week" return <div> - <span>{title}</span> + <label>{title}</label> <Flatpickr data-enable-time={isRange} data-input value={currentDateValue} @@ -86,52 +82,59 @@ function getWeekChanger(isRange, onWeekChangeCallback) { if (isRange || !onWeekChangeCallback) { return null } - return <div className="col-lg-5" style={{marginTop: "12px"}}> + return <div className="week-changer"> <Button icon="pi pi-angle-double-left" title="Previous Week" onClick={() => onWeekChangeCallback(-1)}/> - <label className="timeline-week-span">Week</label> + <label>Week</label> <Button icon="pi pi-angle-double-right" title="Next Week" onClick={() => onWeekChangeCallback(1)}/> </div> } function getResetButton(onClickTimeZoomResetButtonCallback) { - return <div className="p-col-1 timeline-button"> - <Button icon="pi pi-arrow-down" - className="p-button-rounded p-button-success" - id="now-btn" - onClick={onClickTimeZoomResetButtonCallback} - title="Reset Zoom & Move to Current Time"/> + return <div> + <label>Reset:</label> + <div> + <Button icon="pi pi-undo" + className="p-button p-button-primary" + onClick={onClickTimeZoomResetButtonCallback} + title="Reset Zoom & Move to Current Time"/> + </div> </div> } function getIconButton(title, onClickCallback, iconClassName, disabled = false) { return <button className="p-link" title={title} - onClick={() => onClickCallback()} + onClick={onClickCallback} disabled={disabled}> <i className={`pi ${iconClassName}`}/> </button> } function getZoomAndMoveActions(moveLeftCallback, moveRightCallback, zoomOutCallback, zoomInCallback, zoomLevel = "") { - return <div className="p-col-2 timeline-actionbar timeline-filters"> - {getIconButton("Move Left", moveLeftCallback, "pi-angle-left")} - {getIconButton("Zoom out", zoomOutCallback, "pi-minus-circle", zoomLevel.startsWith("Custom"))} - {getIconButton("Zoom in", zoomInCallback, "pi-plus-circle", zoomLevel.startsWith("Custom"))} - {getIconButton("Move Right", moveRightCallback, "pi-angle-right")} + return <div className="move-container"> + <label>Move:</label> + <div> + {getIconButton("Move Left", moveLeftCallback, "pi-angle-left")} + {getIconButton("Zoom out", zoomOutCallback, "pi-minus-circle", zoomLevel.startsWith("Custom"))} + {getIconButton("Zoom in", zoomInCallback, "pi-plus-circle", zoomLevel.startsWith("Custom"))} + {getIconButton("Move Right", moveRightCallback, "pi-angle-right")} + </div> </div> } function getZoomSelect(zoomLevel, allZoomLevels, onChangeZoomLevelCallback) { - return <div className="p-col-2 timeline-filters" style={{paddingRight: '0px'}}> - <Dropdown optionLabel="name" optionValue="name" - style={{fontSize: '10px'}} - value={zoomLevel} - options={allZoomLevels} - filter - showClear={false} - filterBy="name" - onChange={(e) => onChangeZoomLevelCallback(e.value, false)} - placeholder="Zoom"/> + return <div className="zoom-selector-container"> + <label>Span:</label> + <div> + <Dropdown optionLabel="name" optionValue="name" + value={zoomLevel} + options={allZoomLevels} + filter + showClear={false} + filterBy="name" + onChange={(e) => onChangeZoomLevelCallback(e.value, false)} + placeholder="Zoom"/> + </div> </div> } @@ -196,13 +199,25 @@ export default function DateTimeNavigator(props) { return null; } - return <div className="p-fluid p-grid timeline-toolbar" style={{backgroundColor: "cyan"}}> - {getDateTimeInfo(currentUTC, currentLST)} - {getMoveWithTimeCheckbox(allowLive, isLive, setIsLive)} - {getDateSelector(isRange, currentDateValue, onChangeDateCallback, onCloseDateCallback, onClickDateResetButtonCallback)} - {getWeekChanger(isRange, onWeekChangeCallback)} - {getResetButton(onClickTimeZoomResetButtonCallback)} - {getZoomSelect(zoomLevel, allZoomLevels, onChangeZoomLevelCallback)} - {getZoomAndMoveActions(moveLeftCallback, moveRightCallback, zoomOutCallback, zoomInCallback, zoomLevel)} + return <div className="p-grid timeline-datetime-navigator"> + <div> + <div className="header">Navigation</div> + <div className="group"> + {getDateTimeInfo(currentUTC, currentLST)} + <div className="selector-container"> + {getDateSelector(isRange, currentDateValue, onChangeDateCallback, onCloseDateCallback, onClickDateResetButtonCallback)} + {getMoveWithTimeCheckbox(allowLive, isLive, setIsLive)} + {getWeekChanger(isRange, onWeekChangeCallback)} + </div> + </div> + </div> + <div> + <div className="header">Zoom</div> + <div className="group group--row"> + {getZoomSelect(zoomLevel, allZoomLevels, onChangeZoomLevelCallback)} + {getZoomAndMoveActions(moveLeftCallback, moveRightCallback, zoomOutCallback, zoomInCallback, zoomLevel)} + {getResetButton(onClickTimeZoomResetButtonCallback)} + </div> + </div> </div> } \ No newline at end of file diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/components/Legendbar.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/components/Legendbar.js index 8054db5b898..80243939232 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/components/Legendbar.js +++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/components/Legendbar.js @@ -1,53 +1,71 @@ import React from "react"; -const LEGEND_SECTIONS = +const LEGEND_SECTIONS_LEFT = [ { - title: "Scheduling Unit", - elements: [{classKey: "su-started", value: "Error"}, - {classKey: "su-cancelled", value: "Cancelled"}, + title: "Status", + elements: [ {classKey: "su-defined", value: "Defined"}, {classKey: "su-schedulable", value: "Schedulable"}, {classKey: "su-scheduled", value: "Scheduled"}, - {classKey: "su-queued", value: "Queued"}, - {classKey: "su-started", value: "Started"}] + {classKey: "su-queued", value: "Queued"} + ] }, { - title: "Status", - elements: [{classKey: "su-observing", value: "Observing"}, - {classKey: "su-observed", value: "Observed"}, + title: "Active", + elements: [{classKey: "su-started", value: "Started"}, + {classKey: "su-observing", value: "Observing"}, {classKey: "su-processing", value: "Processing"}, - {classKey: "su-processed", value: "Processed"}, - {classKey: "su-ingesting", value: "Ingesting"}, + {classKey: "su-ingesting", value: "Ingesting"} + ] + }, + { + title: "Success", + elements: [{classKey: "su-processed", value: "Processed"}, + {classKey: "su-observed", value: "Observed"}, {classKey: "su-ingested", value: "Ingested"}, - {classKey: "su-finished", value: "Finished"}, - {classKey: "su-unschedulable", value: "Unschedulable"}] + {classKey: "su-finished", value: "Finished"} + ] }, + { + title: "Fail", + elements: [{classKey: "su-cancelled", value: "Cancelled"}, + {classKey: "su-error", value: "Error"}, + {classKey: "su-unschedulable", value: "Unschedulable"} + ] + } + ] + +const LEGEND_SECTIONS_RIGHT = + [ { title: "Station Reservation", elements: [{classKey: "reserve-not-available", value: "Not Available"}, {classKey: "reserve-available", value: "Available"}, {classKey: "reserve-fixed_time", value: "Fixed Time"}, - {classKey: "reserve-dynamic", value: "Dynamic"}] + {classKey: "reserve-dynamic", value: "Dynamic"} + ] }, { title: "Indicators", elements: [{classKey: "su-fixed_time", value: "Fixed Time"}, {classKey: "su-dynamic", value: "Dynamic"}, {classKey: "su-placed", value: "Placed"}, - {classKey: "su-unplaced", value: "Unplaced"}] + {classKey: "su-unplaced", value: "Unplaced"} + ] }, { title: "Sunturn", elements: [{classKey: "legend-sunrise", value: "Sunrise"}, {classKey: "legend-sunset", value: "Sunset"}, - {classKey: "legend-night", value: "Night"}] + {classKey: "legend-night", value: "Night"} + ] } ] function getLegendItem(section) { - return <div className='legend-section'> - <div className="legend-header">{section.title}</div> + return <div className="section"> + <label className="col-3" title={section.title}>{section.title}:</label> {section.elements.map(element => <div className={`su-legend ${element.classKey}`} title={element.value}> {element.value} </div>)} @@ -56,6 +74,12 @@ function getLegendItem(section) { export default function Legendbar() { return <div className="p-grid legendbar"> - {LEGEND_SECTIONS.map(section => getLegendItem(section))} + <div className="header">Legend</div> + <div> + {LEGEND_SECTIONS_LEFT.map(section => getLegendItem(section))} + </div> + <div> + {LEGEND_SECTIONS_RIGHT.map(section => getLegendItem(section))} + </div> </div> } \ No newline at end of file diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/components/Toolbar.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/components/Toolbar.js index 0adeac846fb..74ebe075b13 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/components/Toolbar.js +++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/components/Toolbar.js @@ -2,6 +2,8 @@ import {InputSwitch} from "primereact/inputswitch"; import {MultiSelect} from "primereact/multiselect"; import React, {useEffect, useState} from "react"; import UtilService from "../../../services/util.service"; +import ReactTooltip from "react-tooltip"; +import {Tooltip} from "primereact/tooltip"; function fetchReservationReasons() { let reasons = [] @@ -18,12 +20,15 @@ function fetchReservationReasons() { } function getToggle(labelName, tooltipText, checkedValue, onChangeCallback) { - if (checkedValue === undefined || onChangeCallback === undefined) { //there is no toggle definition - return null; + let isDisabled = false + if (!checkedValue || onChangeCallback === undefined) { + isDisabled = true } - return <div className="col-lg-3 sub-header"> + + return <div className={`toggle-container ${isDisabled ? "disabled" : ""}`}> <label>{labelName}</label> - <InputSwitch checked={checkedValue} + <InputSwitch disabled={isDisabled} + checked={checkedValue} tooltip={tooltipText} onChange={(e) => onChangeCallback(e.value) }/> @@ -31,17 +36,16 @@ function getToggle(labelName, tooltipText, checkedValue, onChangeCallback) { } function getMultiSelectForToggle(dependentToggle, currentValue, allOptions, onChangeCallback, tooltip, placeHolder, - title, optionLabel = "value", optionValue = "value") { + optionLabel = "value", optionValue = "value") { + let isDisabled = false if (!dependentToggle || currentValue === undefined || allOptions === undefined || onChangeCallback === undefined) { - return null; + isDisabled = true; } - return <div className="col-lg-2 subheader-dropdown-div"> - <label style={{marginLeft: '20px'}}>{title}</label> - <MultiSelect - // data-testid="reserv-reasons" id="reserv-reasons" - // disabled={dependentToggle} //TODO: do this with styling + return <div className="multiselect-container"> + {<MultiSelect + className={isDisabled ? "disabled" : ""} + disabled={isDisabled} optionLabel={optionLabel} optionValue={optionValue} - style={{top: '2px', marginLeft: '5px', minWidth: '100px'}} tooltip={tooltip} tooltipOptions={{position: 'left'}} value={currentValue} @@ -49,30 +53,29 @@ function getMultiSelectForToggle(dependentToggle, currentValue, allOptions, onCh maxSelectedLabels="1" filter filterBy={optionValue} - placeholder={placeHolder} + placeholder={dependentToggle ? placeHolder : "Not active"} onChange={(e) => onChangeCallback(e.value)} - /> - + />} </div> } -//TODO: disable on dependantToggle function getRadioButtonsForToggle(dependentToggle, onChangeCallback, entries, title = "Show:") { + let isDisabled = false + if (!dependentToggle || onChangeCallback === undefined || entries === undefined) { - return null; + isDisabled = true } - return <div className="sub-header col-lg-3"> - <div className="sub-header-content col-lg-8"> - <fieldset> - <label>{title}</label> - {entries.map(entry => <> - <input type="radio" value={entry.value} name={entry.name} className="timeline-toolbar-radio" - onClick={(e) => onChangeCallback(e.target.value)} checked={entry.checkedProperty}/> - <label htmlFor={entry.name}>{entry.title}</label> - </>)} - </fieldset> - </div> + return <div className={`radiobutton-container ${isDisabled ? "disabled" : ""}`}> + <fieldset> + <label>{title}</label> + {entries.map(entry => <> + <input disabled={isDisabled} type="radio" value={entry.value} name={entry.name} + className="timeline-toolbar-radio" + onClick={(e) => onChangeCallback(e.target.value)} checked={entry.checkedProperty}/> + <label className="button-label" htmlFor={entry.name}>{entry.title}</label> + </>)} + </fieldset> </div>; } @@ -110,30 +113,53 @@ export default function Toolbar(props) { }, [reservationsViewToggle]) //stations view and on sky view cannot be shown together - const shouldDefineOnSkyViewToggle = stationsViewToggle ? undefined : onSkyViewToggle + const shouldDefineOnSkyViewToggle = stationsViewToggle ? false : onSkyViewToggle - return <div className={`p-grid timeline-view-toolbar`} style={{backgroundColor: "salmon"}}> - {getToggle("On Sky", "Show on-sky system durations", shouldDefineOnSkyViewToggle, setOnSkyViewToggle)} - {getToggle("Reservations", "Show station reservations", reservationsViewToggle, setReservationsViewToggle)} - {getMultiSelectForToggle(reservationsViewToggle, reservationFilter, reservationReasons, setReservationFilter, - "Select Reservation Reason(s)", "Select Reason", "Reason", "name", "name")} - {getToggle("Stations", "Show overview of all stations instead of SU's", stationsViewToggle, setStationsViewToggle)} - {getRadioButtonsForToggle(stationsViewToggle, changeViewBlocks, [ - {value: "su", name: "Only SUs", title: "SUs", checkedProperty: !isStationTasksVisible}, - {value: "task", name: "Only Tasks", title: "Tasks", checkedProperty: isStationTasksVisible}, - ])} - {getMultiSelectForToggle(stationsViewToggle, selectedStationGroup, mainStationGroupOptions, setSelectedStationGroup, - "Select Stations to show in the timeline", "Select Group", "Station group")} - {getRadioButtonsForToggle(shouldDefineOnSkyViewToggle, showTimeLineItems, [ - {value: "su", name: "Only SUs", title: "SUs", checkedProperty: showSUs && !showTasks}, - {value: "task", name: "Only Tasks", title: "Tasks", checkedProperty: !showSUs && showTasks}, - {value: "both", name: "Both", title: "Both", checkedProperty: showSUs && showTasks}, - ])} - {getMultiSelectForToggle(showTasks, selectedTaskTypes, taskTypes, setSelectedTaskTypes, - "Select Task with certain types to show in the timeline", "Select Task", "Task")} - {getRadioButtonsForToggle(shouldDefineOnSkyViewToggle, setGroupByProject, [ - {value: "su", name: "SU", title: "SU", checkedProperty: !isGroupedByProject}, - {value: "project", name: "Project", title: "Project", checkedProperty: isGroupedByProject}, - ], "Group by:")} + return <div className="p-grid timeline-view-toolbar"> + <div> + <Tooltip target=".header" mouseTrack mouseTrackLeft={10}/> + <div className="header" + data-pr-tooltip="Some options might not be available for your view so are disabled">Filters + </div> + <div className="group"> + {getToggle("On Sky", "Show on-sky system durations", shouldDefineOnSkyViewToggle, setOnSkyViewToggle)} + </div> + <div className="group"> + {getToggle("Reservations", "Show station reservations", reservationsViewToggle, setReservationsViewToggle)} + {getMultiSelectForToggle(reservationsViewToggle, reservationFilter, reservationReasons, setReservationFilter, + "Select Reservation Reason(s)", "Reason", "name", "name")} + </div> + <div className="group group--disabled"> + {getToggle("Stations", "Show overview of all stations instead of SU's", stationsViewToggle, setStationsViewToggle)} + {getMultiSelectForToggle(stationsViewToggle, selectedStationGroup, mainStationGroupOptions, setSelectedStationGroup, + "Select Stations to show in the timeline", "Group")} + </div> + + <div className="group group--disabled"> + {/*something with week/timeline view stuff*/} + {getToggle("Tasks", "Show tasks", + shouldDefineOnSkyViewToggle ? !showSUs && showTasks : isStationTasksVisible, + shouldDefineOnSkyViewToggle ? showTimeLineItems : changeViewBlocks)} + {getMultiSelectForToggle(shouldDefineOnSkyViewToggle ? !showSUs && showTasks : isStationTasksVisible, + selectedTaskTypes, taskTypes, setSelectedTaskTypes, + "Select Task with certain types to show in the timeline", "Task")} + </div> + + <div className="group group--disabled"> + {/*something with week/timeline view stuff*/} + {getToggle("SUs", "Show scheduling units", + shouldDefineOnSkyViewToggle ? showSUs && !showTasks : !isStationTasksVisible, + shouldDefineOnSkyViewToggle ? showTimeLineItems : changeViewBlocks)} + </div> + </div> + <div> + <div className="header">Grouping</div> + <div className="group group--disabled"> + {getRadioButtonsForToggle(onSkyViewToggle, setGroupByProject, [ + {value: "su", name: "SU", title: "SU", checkedProperty: !isGroupedByProject}, + {value: "project", name: "Project", title: "Project", checkedProperty: isGroupedByProject}, + ], "Group by:")} + </div> + </div> </div> } \ No newline at end of file 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 9af0c667d6f..9b8878843ee 100644 --- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/view.js +++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/view.js @@ -160,6 +160,7 @@ export class TimelineView extends Component { this.showTimelineItems = this.showTimelineItems.bind(this); this.setSelectedTaskTypes = this.setSelectedTaskTypes.bind(this); this.setReservationFilter = this.setReservationFilter.bind(this); + this.setOnSkyView = this.setOnSkyView.bind(this); } /* Cancel on Scheduling Constraint Popup onEdit */ @@ -1352,12 +1353,12 @@ export class TimelineView extends Component { return stations; } - async setStationView(e) { + async setStationView(isChecked) { this.closeSummaryPanel(); let selectedGroups = this.state.selectedStationGroup; // Store selected view and station group. Remove for default values. Default is all station groups. - if (e.value) { - this.timelineUIAttributes["stationView"] = e.value; + if (isChecked) { + this.timelineUIAttributes["stationView"] = isChecked; selectedGroups = this.timelineUIAttributes.stationGroups || selectedGroups; if (selectedGroups.length === this.mainStationGroupOptions.length) { delete this.timelineUIAttributes["stationGroups"]; @@ -1368,11 +1369,12 @@ export class TimelineView extends Component { delete this.timelineUIAttributes["stationView"]; } this.timelineCommonUtils.storeUIAttributes(this.timelineUIAttributes); - await this.setState({ stationView: e.value, selectedStationGroup: selectedGroups }); + await this.setState({ stationView: isChecked, selectedStationGroup: selectedGroups }); this.updateTimeline(); } async setOnSkyView(value) { + console.log("setting it", value) await this.setState({isOnSkyView: value}); this.timelineUIAttributes['isOnSkyView'] = value; this.timelineCommonUtils.storeUIAttributes(this.timelineUIAttributes); @@ -1876,29 +1878,6 @@ export class TimelineView extends Component { </button> } </div> - <Toolbar onSkyViewToggle={this.state.isOnSkyView} - setOnSkyViewToggle={this.setOnSkyView} - stationsViewToggle={this.state.stationView} - setStationsViewToggle={this.setStationView} - isStationTasksVisible={this.state.isStationTasksVisible} - changeViewBlocks={this.changeViewBlocks} - selectedStationGroup={this.state.selectedStationGroup} - mainStationGroupOptions={this.mainStationGroupOptions} - setSelectedStationGroup={this.setSelectedStationGroup} - showTimeLineItems={this.showTimelineItems} - showSUs={this.state.showSUs} - showTasks={this.state.showTasks} - selectedTaskTypes={this.state.selectedTaskTypes} - taskTypes={this.state.taskTypes} - setSelectedTaskTypes={this.setSelectedTaskTypes} - setGroupByProject={this.setGroupByProject} - isGroupedByProject={this.state.groupByProject} - reservationsViewToggle={this.state.showReservation} - setReservationsViewToggle={this.showReservationBlocks} - reservationFilter={this.state.reservationFilter} - setReservationFilter={this.setReservationFilter} - /> - <Timeline ref={(tl) => { this.timeline = tl }} defaultStartTime={this.state.currentStartTime} defaultEndTime={this.state.currentEndTime} @@ -1914,9 +1893,30 @@ export class TimelineView extends Component { showSunTimings={!this.state.stationView} timelineCommonUtils={this.timelineCommonUtils} timelineUIAttributes={this.timelineUIAttributes} - // stackItems ={this.state.stationView} stackItems - className="timeline-toolbar-margin-top-0"></Timeline> + className="timeline-toolbar-margin-top-0" + //Toolbar properties + setOnSkyViewToggle={this.setOnSkyView} + stationsViewToggle={this.state.stationView} + setStationsViewToggle={this.setStationView} + isStationTasksVisible={this.state.isStationTasksVisible} + changeViewBlocks={this.changeViewBlocks} + selectedStationGroup={this.state.selectedStationGroup} + mainStationGroupOptions={this.mainStationGroupOptions} + setSelectedStationGroup={this.setSelectedStationGroup} + showTimeLineItems={this.showTimelineItems} + showSUs={this.state.showSUs} + showTasks={this.state.showTasks} + selectedTaskTypes={this.state.selectedTaskTypes} + taskTypes={this.state.taskTypes} + setSelectedTaskTypes={this.setSelectedTaskTypes} + setGroupByProject={this.setGroupByProject} + isGroupedByProject={this.state.groupByProject} + reservationsViewToggle={this.state.showReservation} + setReservationsViewToggle={this.showReservationBlocks} + reservationFilter={this.state.reservationFilter} + setReservationFilter={this.setReservationFilter} + ></Timeline> </div> {/* Details Panel */} {isSUDetsVisible && 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 efc24573dc8..cac0e7c9b4a 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 @@ -1531,14 +1531,6 @@ export class WeekTimelineView extends Component { </button> } </div> - <Toolbar - onSkyViewToggle={this.state.isOnSkyView} - setOnSkyViewToggle={this.setOnSkyView} - reservationsViewToggle={this.state.reservationEnabled} - setReservationsViewToggle={this.showReservations} - reservationFilter={this.state.reservationFilter} - setReservationFilter={this.setReservationFilter}/> - <Timeline ref={(tl) => { this.timeline = tl }} @@ -1559,6 +1551,13 @@ export class WeekTimelineView extends Component { showLive={false} showDateRange={false} viewType={UIConstants.timeline.types.WEEKVIEW} dateRangeCallback={this.dateRangeCallback} + //Toolbar properties + onSkyViewToggle={this.state.isOnSkyView} + setOnSkyViewToggle={this.setOnSkyView} + reservationsViewToggle={this.state.reservationEnabled} + setReservationsViewToggle={this.showReservations} + reservationFilter={this.state.reservationFilter} + setReservationFilter={this.setReservationFilter} ></Timeline> </div> {/* Details Panel */} -- GitLab