diff --git a/CHANGELOG.md b/CHANGELOG.md index 75448ca0a..894b74332 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ - Set `NODE_ENV=production` for webpack `build` command - Fixed dynamic graph centering bug by updating `parseTransform` in `app/Svg/Parser.hs` to parse multiple transform functions and removing `getShapesMinXY` in `js/components/graph/Graph.js` - Switched CI provider from CircleCI to GitHub Actions +- Cleared up documentation for various graph-related front-end functions ## [0.8.1] - 2026-08-10 diff --git a/js/components/common/react_modal.js.jsx b/js/components/common/react_modal.js.jsx index b88cf771a..a06231d66 100644 --- a/js/components/common/react_modal.js.jsx +++ b/js/components/common/react_modal.js.jsx @@ -134,7 +134,11 @@ class CourseModal extends React.Component { } } - /** Helper function to format the time of a Time JSON object for display */ + /** + * Helper function to format a Time data object for display in the course modal. + * @param {object} time A Time data object. + * @returns {string} The time formatted as a string (e.g. "Tuesday 11 - 13"). + * */ formatTime(time) { return DAY_TO_INT[time.weekDay] + " " + time.startHour + " - " + time.endHour } @@ -142,45 +146,48 @@ class CourseModal extends React.Component { /** * Generate the data needed for the course modal table based on the meeting times corresponding * to a course in a given session. - * @param allMeetingTimes An array of MeetTime' objects corresponding to a particular course. - * @param session The session (F, S, Y) to query. - * @returns A map containing the table data that will appear in the course modal. + * @param {object[]} allMeetTimes An array of MeetTime' objects corresponding to a particular course. + * @param {string} session The session (F, S, Y) to query. + * @returns {object[]} An array of row data objects that will appear in the course modal table. */ - getTable(allMeetingTimes, session) { - const sessions = allMeetingTimes.filter(lec => lec.meetData.session === session) - const sortedSessions = sessions.sort((firstLec, secondLec) => - firstLec.meetData.section > secondLec.meetData.section ? 1 : -1 + getTable(allMeetTimes, session) { + // Filter and sort the lecture sections in the specified session by their section code + const filteredMeetTimes = allMeetTimes.filter(meetTime => meetTime.meetData.session === session) + const sortedMeetTimes = filteredMeetTimes.sort((firstMeetTime, secondMeetTime) => + firstMeetTime.meetData.section > secondMeetTime.meetData.section ? 1 : -1 ) - return sortedSessions.map(lecture => { + return sortedMeetTimes.map(meetTime => { + // Sort each section's meeting time blocks and corresponding locations and store them in arrays. + // times2, locations2 are used for the extra columns that appear in the table when viewing a Y course. const occurrences = { times1: [], locations1: [], times2: [], locations2: [] } - const sortedTimeData = lecture.timeData.sort((occ1, occ2) => - occ1.weekDay > occ2.weekDay ? 1 : -1 + const sortedTimeData = meetTime.timeData.sort((time1, time2) => + time1.weekDay > time2.weekDay ? 1 : -1 ) - sortedTimeData.map(occurrence => { + sortedTimeData.map(time => { let location = " " - if (occurrence.timeLocation !== null && occurrence.timeLocation !== undefined) { - location = occurrence.timeLocation.buildingCode + if (time.timeLocation !== null && time.timeLocation !== undefined) { + location = time.timeLocation.buildingCode } - if (session === "Y" && occurrence.timeSession.endsWith("1")) { + if (session === "Y" && time.timeSession.endsWith("1")) { occurrences.locations2.push(location) - occurrences.times2.push(this.formatTime(occurrence)) + occurrences.times2.push(this.formatTime(time)) } else { occurrences.locations1.push(location) - occurrences.times1.push(this.formatTime(occurrence)) + occurrences.times1.push(this.formatTime(time)) } }) const rowData = { - activity: lecture.meetData.section, - instructor: lecture.meetData.instructor, + activity: meetTime.meetData.section, + instructor: meetTime.meetData.instructor, availability: - lecture.meetData.cap - - lecture.meetData.enrol + + meetTime.meetData.cap - + meetTime.meetData.enrol + " of " + - lecture.meetData.cap + + meetTime.meetData.cap + " available", - waitList: lecture.meetData.wait + " students", + waitList: meetTime.meetData.wait + " students", time1: occurrences.times1, location1: occurrences.locations1, time2: occurrences.times2, diff --git a/js/components/graph/Graph.js b/js/components/graph/Graph.js index 33558c575..fc09c193a 100644 --- a/js/components/graph/Graph.js +++ b/js/components/graph/Graph.js @@ -1218,6 +1218,11 @@ export class Graph extends React.Component { }) } + /** + * Checks if a node or bool node is currently selected or active. + * @param {string} nodeId + * @returns {boolean} + */ isSelected = nodeId => { if (this.state.nodesStatus[nodeId]) { return this.isSelectedNode(nodeId) @@ -1248,7 +1253,8 @@ export class Graph extends React.Component { /** * Check if the prerequisite courses have been satisfied based on bool type. - * @returns {boolean} Whether any of the prereqs are satisfied. + * @param {string} boolId the ID of the bool node. + * @returns {boolean} Whether the bool is satisfied based on its prerequisite nodes. */ arePrereqsSatisfiedBool = boolId => { const isAllTrue = element => { @@ -1265,8 +1271,9 @@ export class Graph extends React.Component { } /** - * Checks whether all prerequisite/preceding nodes for the current one are satisfied - * @return {boolean} + * Recursively checks whether all prerequisite/preceding nodes for a node are satisfied. + * @param {string} nodeId the ID of the node. + * @return {boolean} whether all of the node's prerequisite nodes are satisfied by the selected courses. */ arePrereqsSatisfiedNode = nodeId => { const parents = this.state.connections.parents[nodeId] @@ -1291,8 +1298,9 @@ export class Graph extends React.Component { } /** - * Checks whether a hybrid node's prereq string is satisfied - * @return {boolean} + * Checks whether a hybrid node's prereq string is satisfied. + * @param {string} nodeId the ID of the hybrid node. + * @return {boolean} whether the node's text prerequisite string is satisfied by the selected courses. */ arePrereqsSatisfiedHybrid = nodeId => { // Concatenate prereq string @@ -1744,14 +1752,15 @@ export class Graph extends React.Component { export { ZOOM_INCREMENT, KEYBOARD_PANNING_INCREMENT } -/** Helper function that adds parents of hybridNode to the parents object, and adds hybrid nodes as children of the Nodes they represent - * +/** + * Helper function to populate the parents object and children object with the connections of a hybrid node. + * A parent-child connection is added for each course that appears in the hybrid node's prereq string. * @param {Node} hybridNode * @param {Array} nodesJSON - * @param {Object} parents + * @param {Object} parentsObj * @param {Object} childrenObj */ -export function populateHybridRelatives(hybridNode, nodesJSON, parents, childrenObj) { +export function populateHybridRelatives(hybridNode, nodesJSON, parentsObj, childrenObj) { // parse prereqs based on text let hybridText = hybridNode.text.map(textTag => textTag.text).join("") const nodeParents = [] @@ -1780,12 +1789,12 @@ export function populateHybridRelatives(hybridNode, nodesJSON, parents, children console.error("Could not find prereq for ", hybridText) } } - parents[hybridNode.id_] = nodeParents + parentsObj[hybridNode.id_] = nodeParents } /** * Helper for hybrid computation. Finds the node with the same course label as the hybrid. - * @param {string} course + * @param {string} course * @param {Array} nodesJSON * @return {Node} */ diff --git a/js/util/util.js b/js/util/util.js index 4d3d01fc3..b6b6c0a9f 100644 --- a/js/util/util.js +++ b/js/util/util.js @@ -1,7 +1,8 @@ /** * Parse a logical prerequisite string as a conjunction of disjunctions. * @param {string} s the prerequisite string - * @returns a nested list of courses as an AND of ORs, or the course itself if no splitting is made + * @returns {string|Array} a nested list of courses as an AND of ORs, or the course itself if no + * splitting is made */ export function parseAnd(s) { // Base case: return the course if no splitting is to be made. @@ -25,7 +26,8 @@ export function parseAnd(s) { /** * Parse a logical prerequisite string as a disjunction of conjunctions. * @param {string} s the prerequisite string - * @returns a nested list of courses as an OR of ANDs, or the course itself if no splitting is made + * @returns {string|Array} a nested list of courses as an OR of ANDs, or the course itself if no + * splitting is made */ export function parseOr(s) { // Base case: return the course if no splitting is to be made. @@ -51,7 +53,7 @@ export function parseOr(s) { * strip the result of top-level outer parentheses and spaces. * @param {string} s the prerequisite string * @param {string} separator the separator to split by (',' for and, '/' for or) - * @returns the resulting list of conjunctives/disjunctives + * @returns {string[]} the resulting list of conjunctives/disjunctives */ export function splitPrereqString(s, separator) { let splitList = [] @@ -84,7 +86,7 @@ export function splitPrereqString(s, separator) { /** * Helper function to strip a string entirely contained within a pair of parentheses. * @param {string} s the prerequisite string to strip parentheses from - * @returns the same string with all fully-enclosing pairs of parentheses removed + * @returns {string} the same string with all fully-enclosing pairs of parentheses removed */ export function removeOuterParens(s) { if (s.length < 2 || s.charAt(0) !== "(" || s.charAt(s.length - 1) !== ")") {