Skip to content
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
- Switched CircleCI ImageMagick download to use http
- Modified CI config to take advantage of partial dependency caching and exploit parallelism when resolving/updating dependencies
- Migrate graph-related components (FocusBar, FocusTab, GraphDropdown, GraphFallback, Infobox, and Sidebar) from classes to functions
- Refactor GraphDropdown component from being a child of Graph to being a child of NavBar
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please do another merge from master, as I've made a new release; after doing this merge, this entry should be moved into the "unreleased" section.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like you may have missed this comment

- Added `lint-staged` development dependency and fixed eslint issues
- Updated CircleCI ImageMagick setup to avoid using AppImage executable and to cache download

Expand Down
38 changes: 36 additions & 2 deletions js/components/common/NavBar.js.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,32 @@ import React from "react"
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
import { faDownload } from "@fortawesome/free-solid-svg-icons"
import { Tooltip } from "react-tooltip"
import GraphDropdown from "../graph/GraphDropdown"

/**
* NavBar component.
*/
export function NavBar({ selected_page, open_modal }) {
export function NavBar({ selected_page, open_modal, graphs = [], updateGraph }) {
const isActive = page => (page === selected_page ? "selected-page" : undefined)
const [showGraphDropdown, setShowGraphDropdown] = React.useState(false)
const [dropdownTimeouts, setDropdownTimeouts] = React.useState([])

const clearDropdownTimeouts = () => {
dropdownTimeouts.forEach(timeout => clearTimeout(timeout))
setDropdownTimeouts([])
}

const handleShowGraphDropdown = () => {
clearDropdownTimeouts()
setShowGraphDropdown(true)
}

const handleHideGraphDropdown = () => {
const timeout = setTimeout(() => {
setShowGraphDropdown(false)
}, 500)
setDropdownTimeouts(dropdownTimeouts.concat(timeout))
}

return (
<nav className="row header">
Expand All @@ -26,8 +46,22 @@ export function NavBar({ selected_page, open_modal }) {
{/* Navigation links */}
<div className="nav-middle">
<ul id="nav-links">
<li id="nav-graph" className={isActive("graph")}>
<li
id="nav-graph"
className={`${isActive("graph")} ${graphs.length > 0 ? "show-dropdown-arrow" : ""}`}
onMouseEnter={handleShowGraphDropdown}
onMouseLeave={handleHideGraphDropdown}
>
<a href="/graph">Graph</a>
{selected_page === "graph" && (
<GraphDropdown
showGraphDropdown={showGraphDropdown}
onMouseMove={handleShowGraphDropdown}
onMouseLeave={handleHideGraphDropdown}
graphs={graphs}
updateGraph={updateGraph}
/>
)}
</li>
<li id="nav-grid" className={isActive("grid")}>
<a href="/grid">Grid</a>
Expand Down
2 changes: 1 addition & 1 deletion js/components/graph/Container.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ export default class Container extends React.Component {
render() {
return (
<div>
<NavBar selected_page="graph" open_modal={this.openExportModal}></NavBar>
<NavBar selected_page="graph" open_modal={this.openExportModal} graphs={this.state.graphs} updateGraph={this.updateGraph}></NavBar>
<ExportModal
page="graph"
open={this.state.modalOpen}
Expand Down
14 changes: 10 additions & 4 deletions js/components/graph/FocusTab.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,16 @@ export default function FocusTab({ focusName, highlightFocus, selected, pId }) {
* Change whether the modal popup describing this focus is shown
* @param {bool} value
*/
const toggleFocusModal = value => {
const toggleFocusModal = (value => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Revert all of the changes in this file (these are all unrelated to the PR)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like you missed this comment.

setShowFocusModal(value)
}
})

return (
<div className={selected ? "focus active-focus" : "focus"}>
<button id={pId} onClick={() => highlightFocus(pId)}>
<button
id={pId}
onClick={() => highlightFocus(pId)}
>
{focusName}
</button>
<div className="focus-info">
Expand All @@ -28,7 +31,10 @@ export default function FocusTab({ focusName, highlightFocus, selected, pId }) {
onClose={() => toggleFocusModal(false)}
/>
{selected && (
<button onClick={() => toggleFocusModal(true)} aria-label="Focus Description">
<button
onClick={() => toggleFocusModal(true)}
aria-label="Focus Description"
>
i
</button>
)}
Expand Down
62 changes: 1 addition & 61 deletions js/components/graph/Graph.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import Edge from "./Edge"
import Node from "./Node"
import Button from "./Button"
import InfoBox from "./InfoBox"
import GraphDropdown from "./GraphDropdown"
import Sidebar from "./Sidebar"
import { parseAnd } from "../../util/util.js"
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
Expand All @@ -24,8 +23,7 @@ const ZOOM_ENUM = {
ZOOM_IN: 1,
}
const TIMEOUT_NAMES_ENUM = {
INFOBOX: 0,
DROPDOWN: 1,
INFOBOX: 0
}

export class Graph extends React.Component {
Expand All @@ -44,7 +42,6 @@ export class Graph extends React.Component {
highlightedNodesFocus: [],
highlightedNodesDeps: [],
infoboxTimeouts: [],
dropdownTimeouts: [],
width: window.innerWidth,
height: window.innerHeight,
zoomFactor: 1,
Expand All @@ -68,7 +65,6 @@ export class Graph extends React.Component {
panStartX: 0,
panStartY: 0,
showCourseModal: false,
showGraphDropdown: false,
selectedNodes: new Set(),
}
this.exportModal = React.createRef()
Expand All @@ -83,15 +79,6 @@ export class Graph extends React.Component {
// can't detect keydown event when adding event listener to react-graph
document.body.addEventListener("keydown", this.onKeyDown)

if (document.querySelector("#nav-graph > a")) {
document
.querySelector("#nav-graph > a")
.addEventListener("mouseenter", this.setShowGraphDropdown)
document
.querySelector("#nav-graph > a")
.addEventListener("mouseleave", this.hideGraphDropdown)
}

if (document.querySelector(".sidebar")) {
document
.querySelector(".sidebar")
Expand All @@ -107,23 +94,13 @@ export class Graph extends React.Component {

componentWillUnmount() {
this.state.infoboxTimeouts.forEach(timeout => clearTimeout(timeout))
this.state.dropdownTimeouts.forEach(timeout => clearTimeout(timeout))
document.body.removeEventListener("keydown", this.onKeyDown)

if (document.getElementById("nav-export")) {
document
.getElementById("nav-export")
.removeEventListener("click", this.exportModal.current.openModal)
}

if (document.querySelector("#nav-graph > a")) {
document
.querySelector("#nav-graph > a")
.removeEventListener("mouseenter", this.setShowGraphDropdown)
document
.querySelector("#nav-graph > a")
.removeEventListener("mouseleave", this.hideGraphDropdown)
}
}

getGraph = () => {
Expand Down Expand Up @@ -361,19 +338,6 @@ export class Graph extends React.Component {
}
}

clearAllTimeouts = timeoutName => {
switch (timeoutName) {
case TIMEOUT_NAMES_ENUM.INFOBOX:
this.state.infoboxTimeouts.forEach(timeout => clearTimeout(timeout))
this.setState({ infoboxTimeouts: [] })
break
case TIMEOUT_NAMES_ENUM.DROPDOWN:
this.state.dropdownTimeouts.forEach(timeout => clearTimeout(timeout))
this.setState({ dropdownTimeouts: [] })
break
}
}

/**
* Update the status of the Edge, based on the status of the Node/Bool it points from/to.
*/
Expand Down Expand Up @@ -489,8 +453,6 @@ export class Graph extends React.Component {
const currentNode = this.state.nodesJSON[courseId]
this.focusPrereqs(courseId)

this.clearAllTimeouts(TIMEOUT_NAMES_ENUM.INFOBOX)

let xPos = currentNode.pos[0]
let yPos = currentNode.pos[1]
const rightSide = xPos > 222
Expand Down Expand Up @@ -679,7 +641,6 @@ export class Graph extends React.Component {
}

infoBoxMouseEnter = () => {
this.clearAllTimeouts(TIMEOUT_NAMES_ENUM.INFOBOX)
this.setState({ showInfoBox: true, isMouseOnInfoBox: true })
}

Expand All @@ -702,20 +663,6 @@ export class Graph extends React.Component {
})
}

setShowGraphDropdown = () => {
this.clearAllTimeouts(TIMEOUT_NAMES_ENUM.DROPDOWN)
this.setState({ showGraphDropdown: true })
}

hideGraphDropdown = () => {
const timeout = setTimeout(() => {
this.setState({ showGraphDropdown: false })
}, 500)
this.setState({
dropdownTimeouts: this.state.dropdownTimeouts.concat(timeout),
})
}

onClose = () => {
this.setState({ showCourseModal: false })
}
Expand Down Expand Up @@ -1654,13 +1601,6 @@ export class Graph extends React.Component {
onClose={this.onClose}
/>
<ExportModal context="graph" session="" ref={this.exportModal} />
<GraphDropdown
showGraphDropdown={this.state.showGraphDropdown}
onMouseMove={this.setShowGraphDropdown}
onMouseLeave={this.hideGraphDropdown}
graphs={this.props.graphs}
updateGraph={this.props.updateGraph}
/>
{Object.keys(this.state.nodesJSON).length > 1 && (
<div className="graph-button-group">
<div className="button-group">
Expand Down
35 changes: 8 additions & 27 deletions js/components/graph/GraphDropdown.js
Original file line number Diff line number Diff line change
@@ -1,36 +1,17 @@
import React from "react"
import PropTypes from "prop-types"

export default function GraphDropdown({
showGraphDropdown,
onMouseMove,
onMouseLeave,
graphs = [],
updateGraph,
}) {
let className = "hidden"
let graphTabLeft = 0
if (graphs.length !== 0 && document.querySelector("#nav-graph")) {
const navGraph = document.querySelector("#nav-graph")
if (graphs.length === 0) {
navGraph.classList.remove("show-dropdown-arrow")
} else {
if (!navGraph.classList.contains("show-dropdown-arrow")) {
navGraph.classList.add("show-dropdown-arrow")
}
if (showGraphDropdown) {
graphTabLeft = navGraph.getBoundingClientRect().left
className = "graph-dropdown-display"
}
}
}
export default function GraphDropdown({showGraphDropdown, onMouseEnter, onMouseLeave, graphs = [], updateGraph }) {
const className = showGraphDropdown && graphs.length > 0
? "graph-dropdown-display"
: "hidden"

return (
<ul
className={className}
onMouseMove={onMouseMove}
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
data-testid={"test-graph-dropdown"}
style={{ left: graphTabLeft }}
data-testid="test-graph-dropdown"
>
{graphs.map((graph, i) => {
return (
Expand All @@ -54,7 +35,7 @@ GraphDropdown.defaultProps = {

GraphDropdown.propTypes = {
showGraphDropdown: PropTypes.bool,
onMouseMove: PropTypes.func,
onMouseEnter: PropTypes.func,
onMouseLeave: PropTypes.func,
graphs: PropTypes.array,
updateGraph: PropTypes.func,
Expand Down
Loading