From 37864368e26a123680d5cad41a7b6b93f90baaa2 Mon Sep 17 00:00:00 2001 From: Hannah Purcell <69368883+hannahpurcell@users.noreply.github.com> Date: Fri, 11 Oct 2024 10:44:04 -0400 Subject: [PATCH 01/10] fix: Detour modal header should be blank on new creation workflow (#2851) --- assets/src/components/detours/diversionPage.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/assets/src/components/detours/diversionPage.tsx b/assets/src/components/detours/diversionPage.tsx index b3933def7..aad251dd9 100644 --- a/assets/src/components/detours/diversionPage.tsx +++ b/assets/src/components/detours/diversionPage.tsx @@ -427,9 +427,9 @@ export const DiversionPage = ({ {useDetourProps.author} - ) : ( + ) : isMobile(displayType) ? (
Detours
- )} + ) : null} From 1665070272930d7c98e97068932df52d521512f3 Mon Sep 17 00:00:00 2001 From: Kayla Firestack Date: Fri, 11 Oct 2024 15:04:06 -0400 Subject: [PATCH 02/10] refactor: Explicitly export `vehicleLabel` (#2850) * fix(ts/helpers/vehicleLabel): explicitly export `vehicleLabel` * refactor: use `vehicleLabel` in `mapMarkers` * refactor: remove default export `vehicleLabel` Part of: - https://github.com/mbta/skate/pull/2603 --- assets/src/components/incomingBox.tsx | 2 +- assets/src/components/ladder.tsx | 2 +- assets/src/components/mapMarkers.tsx | 4 ++-- assets/src/components/propertiesPanel/header.tsx | 2 +- assets/src/components/vehicleRouteSummary.tsx | 2 +- assets/src/helpers/vehicleLabel.ts | 4 +--- assets/tests/helpers/vehicleLabel.test.ts | 3 ++- 7 files changed, 9 insertions(+), 10 deletions(-) diff --git a/assets/src/components/incomingBox.tsx b/assets/src/components/incomingBox.tsx index 82cf07ebc..0b946d70a 100644 --- a/assets/src/components/incomingBox.tsx +++ b/assets/src/components/incomingBox.tsx @@ -1,6 +1,6 @@ import React, { useContext } from "react" import { StateDispatchContext } from "../contexts/stateDispatchContext" -import vehicleLabel from "../helpers/vehicleLabel" +import { vehicleLabel } from "../helpers/vehicleLabel" import { blockWaiverAlertStyle } from "../models/blockWaiver" import { crowdingLabel, OccupancyStatus } from "../models/crowding" import { diff --git a/assets/src/components/ladder.tsx b/assets/src/components/ladder.tsx index f9d36e70f..01355a036 100644 --- a/assets/src/components/ladder.tsx +++ b/assets/src/components/ladder.tsx @@ -5,7 +5,7 @@ import "tippy.js/dist/tippy.css" import { StateDispatchContext } from "../contexts/stateDispatchContext" import { flatten, partition } from "../helpers/array" import { joinClasses } from "../helpers/dom" -import vehicleLabel from "../helpers/vehicleLabel" +import { vehicleLabel } from "../helpers/vehicleLabel" import { blockWaiverAlertStyle } from "../models/blockWaiver" import { crowdingLabel, OccupancyStatus } from "../models/crowding" import { diff --git a/assets/src/components/mapMarkers.tsx b/assets/src/components/mapMarkers.tsx index e08dd899c..21f5431e5 100644 --- a/assets/src/components/mapMarkers.tsx +++ b/assets/src/components/mapMarkers.tsx @@ -12,7 +12,7 @@ import { Marker, Polyline, Popup, Tooltip } from "react-leaflet" import { StateDispatchContext } from "../contexts/stateDispatchContext" import { joinClasses } from "../helpers/dom" -import vehicleLabelString from "../helpers/vehicleLabel" +import { vehicleLabel } from "../helpers/vehicleLabel" import { drawnStatus, statusClasses } from "../models/vehicleStatus" import { TrainVehicle, Vehicle } from "../realtime" import { Shape, Stop } from "../schedule" @@ -77,7 +77,7 @@ const makeLabelIcon = ( settings: UserSettings, isSelected: boolean ): Leaflet.DivIcon => { - const labelString = vehicleLabelString(vehicle, settings) + const labelString = vehicleLabel(vehicle, settings) const labelBackgroundHeight = isPrimary ? 16 : 12 const labelBackgroundWidth = labelString.length <= 4 ? (isPrimary ? 40 : 30) : isPrimary ? 62 : 40 diff --git a/assets/src/components/propertiesPanel/header.tsx b/assets/src/components/propertiesPanel/header.tsx index 01c5bcace..ee6083818 100644 --- a/assets/src/components/propertiesPanel/header.tsx +++ b/assets/src/components/propertiesPanel/header.tsx @@ -2,7 +2,7 @@ import React, { useContext } from "react" import { useRoute } from "../../contexts/routesContext" import { StateDispatchContext } from "../../contexts/stateDispatchContext" import { joinClasses } from "../../helpers/dom" -import vehicleLabel from "../../helpers/vehicleLabel" +import { vehicleLabel } from "../../helpers/vehicleLabel" import { secondsAgoLabel, secondsToMinutes } from "../../util/dateTime" import { useCurrentTimeSeconds } from "../../hooks/useCurrentTime" import { emptyLadderDirectionsByRouteId } from "../../models/ladderDirection" diff --git a/assets/src/components/vehicleRouteSummary.tsx b/assets/src/components/vehicleRouteSummary.tsx index 18f0ddc96..87a5e5da3 100644 --- a/assets/src/components/vehicleRouteSummary.tsx +++ b/assets/src/components/vehicleRouteSummary.tsx @@ -6,7 +6,7 @@ import React, { import { useRoute } from "../contexts/routesContext" import { StateDispatchContext } from "../contexts/stateDispatchContext" import { joinClasses } from "../helpers/dom" -import vehicleLabel from "../helpers/vehicleLabel" +import { vehicleLabel } from "../helpers/vehicleLabel" import { emptyLadderDirectionsByRouteId } from "../models/ladderDirection" import { currentRouteTab } from "../models/routeTab" import { diff --git a/assets/src/helpers/vehicleLabel.ts b/assets/src/helpers/vehicleLabel.ts index 6dc8ed5c6..840b63cb5 100644 --- a/assets/src/helpers/vehicleLabel.ts +++ b/assets/src/helpers/vehicleLabel.ts @@ -18,7 +18,7 @@ export const runOrBusNumberLabel = ( } } -const vehicleLabel = ( +export const vehicleLabel = ( vehicleOrGhost: Vehicle | Ghost, settings: UserSettings ): string => { @@ -58,5 +58,3 @@ export const runIdToLabel = (runId: RunId | null): string => { const stripLeadingZero = (num: string): string => num.startsWith("0") ? num.slice(1) : num - -export default vehicleLabel diff --git a/assets/tests/helpers/vehicleLabel.test.ts b/assets/tests/helpers/vehicleLabel.test.ts index f00550cf1..c30b74cd3 100644 --- a/assets/tests/helpers/vehicleLabel.test.ts +++ b/assets/tests/helpers/vehicleLabel.test.ts @@ -1,5 +1,6 @@ import { describe, test, expect } from "@jest/globals" -import vehicleLabel, { +import { + vehicleLabel, runOrBusNumberLabel, runIdToLabel, } from "../../src/helpers/vehicleLabel" From 7cd7729051a267516573744149e8cc137d90a087 Mon Sep 17 00:00:00 2001 From: Kayla Firestack Date: Fri, 11 Oct 2024 15:24:48 -0400 Subject: [PATCH 03/10] feat(ts/components/vehicleMarker): use `ReactMarker` for `VehicleMarker` Icon and Label (#2847) --- .../components/map/utilities/reactMarker.tsx | 50 ++- assets/src/components/mapMarkers.tsx | 155 ++++----- .../__snapshots__/mapPage.test.tsx.snap | 164 +++++---- .../shuttleMapPage.test.tsx.snap | 328 +++++++++--------- 4 files changed, 330 insertions(+), 367 deletions(-) diff --git a/assets/src/components/map/utilities/reactMarker.tsx b/assets/src/components/map/utilities/reactMarker.tsx index 1a000d94a..960089c35 100644 --- a/assets/src/components/map/utilities/reactMarker.tsx +++ b/assets/src/components/map/utilities/reactMarker.tsx @@ -1,9 +1,10 @@ -import React, { ReactNode } from "react" +import React, { forwardRef, ReactNode } from "react" import { createPortal } from "react-dom" import { Marker, MarkerProps } from "react-leaflet" import { DivIconOptions, useReactDivIcon } from "./reactDivIcon" +import { Marker as LeafletMarker } from "leaflet" /** * Component Props for {@link ReactMarker} @@ -31,30 +32,27 @@ export interface ReactMarkerProps extends Omit { * * @param {ReactMarkerProps} props Component Props with {@link DivIconOptions `divIconSettings`} */ -export const ReactMarker = ({ - icon, - divIconSettings, - children, - ...markerProps -}: ReactMarkerProps) => { - const { divIcon, iconContainer } = useReactDivIcon(divIconSettings) +export const ReactMarker = forwardRef, ReactMarkerProps>( + ({ icon, divIconSettings, children, ...markerProps }, ref) => { + const { divIcon, iconContainer } = useReactDivIcon(divIconSettings) - return ( - - <> - { - /* - React Events bubble up the React Virtual DOM, - so any Events to `icon` should bubble up to `Marker` first - */ - createPortal(icon, iconContainer) - } + return ( + + <> + { + /* + React Events bubble up the React Virtual DOM, + so any Events to `icon` should bubble up to `Marker` first + */ + createPortal(icon, iconContainer) + } - { - /* Provide children after portal so react has a stable virtual DOM reference */ - children - } - - - ) -} + { + /* Provide children after portal so react has a stable virtual DOM reference */ + children + } + + + ) + } +) diff --git a/assets/src/components/mapMarkers.tsx b/assets/src/components/mapMarkers.tsx index 21f5431e5..ac720d3e4 100644 --- a/assets/src/components/mapMarkers.tsx +++ b/assets/src/components/mapMarkers.tsx @@ -16,7 +16,6 @@ import { vehicleLabel } from "../helpers/vehicleLabel" import { drawnStatus, statusClasses } from "../models/vehicleStatus" import { TrainVehicle, Vehicle } from "../realtime" import { Shape, Stop } from "../schedule" -import { UserSettings } from "../userSettings" import garages, { Garage as GarageData } from "../data/garages" import useDeviceSupportsHover from "../hooks/useDeviceSupportsHover" @@ -37,71 +36,6 @@ import { fullStoryEvent } from "../helpers/fullStory" /* eslint-enable @typescript-eslint/ban-ts-comment */ -const makeVehicleIcon = ( - vehicle: Vehicle, - isPrimary: boolean, - userSettings: UserSettings, - isSelected: boolean -): Leaflet.DivIcon => { - const centerX = 12 - const centerY = 12 - return Leaflet.divIcon({ - html: ` - - `, - iconAnchor: [0, 0], - className: "c-vehicle-map__icon", - }) -} - -const makeLabelIcon = ( - vehicle: Vehicle, - isPrimary: boolean, - settings: UserSettings, - isSelected: boolean -): Leaflet.DivIcon => { - const labelString = vehicleLabel(vehicle, settings) - const labelBackgroundHeight = isPrimary ? 16 : 12 - const labelBackgroundWidth = - labelString.length <= 4 ? (isPrimary ? 40 : 30) : isPrimary ? 62 : 40 - const selectedClass = isSelected ? "selected" : null - return Leaflet.divIcon({ - className: joinClasses([ - "c-vehicle-map__label", - isPrimary ? "primary" : "secondary", - selectedClass, - ]), - html: ` - - - ${labelString} - - `, - iconAnchor: [labelBackgroundWidth / 2, isPrimary ? -16 : -10], - }) -} - interface VehicleMarkerProps extends PropsWithChildren { vehicle: Vehicle isPrimary: boolean @@ -152,18 +86,15 @@ export const VehicleMarker = ({ }, } const position: LatLngExpression = [vehicle.latitude, vehicle.longitude] - const vehicleIcon: Leaflet.DivIcon = makeVehicleIcon( - vehicle, - isPrimary, - userSettings, - isSelected - ) - const labelIcon: Leaflet.DivIcon = makeLabelIcon( - vehicle, - isPrimary, - userSettings, - isSelected - ) + const labelBackgroundHeight = isPrimary ? 16 : 12 + const labelBackgroundWidth = + vehicleLabel(vehicle, userSettings).length <= 4 + ? isPrimary + ? 40 + : 30 + : isPrimary + ? 62 + : 40 // https://leafletjs.com/reference.html#marker-zindexoffset // > By default, marker images zIndex is set automatically based on its latitude @@ -173,19 +104,77 @@ export const VehicleMarker = ({ return ( <> - + + + } > {children} - + - + + + {vehicleLabel(vehicle, userSettings)} + + + } eventHandlers={eventHandlers} zIndexOffset={zIndexOffset} /> diff --git a/assets/tests/components/__snapshots__/mapPage.test.tsx.snap b/assets/tests/components/__snapshots__/mapPage.test.tsx.snap index a981858dd..7824800e9 100644 --- a/assets/tests/components/__snapshots__/mapPage.test.tsx.snap +++ b/assets/tests/components/__snapshots__/mapPage.test.tsx.snap @@ -1780,22 +1780,22 @@ exports[` Snapshot renders vehicle data 1`] = ` style="margin-left: 0px; margin-top: 0px; width: 12px; height: 12px; left: 223px; top: 27px; z-index: 1027;" tabindex="0" > - - - - - - - + + + +
Snapshot renders vehicle data 1`] = ` style="margin-left: -20px; margin-top: 16px; width: 12px; height: 12px; left: 223px; top: 27px; z-index: 1027;" tabindex="0" > - - - - - - - - - 1 - - - - - + + + 1 + + +
Snapshot renders vehicle data 1`] = ` style="margin-left: 0px; margin-top: 0px; width: 12px; height: 12px; left: 223px; top: 27px; z-index: 27; z-index: 27;" tabindex="0" > - - - - - - - + + + +
Snapshot renders vehicle data 1`] = ` style="margin-left: -15px; margin-top: 10px; width: 12px; height: 12px; left: 223px; top: 27px; z-index: 27; z-index: 27;" tabindex="0" > - - - - - - - - - 2 - - - - - + + + 2 + + +
- - - - - - - + + + +
- - - - - - - - - 1818 - - - - - + + + 1818 + + +
- - - - - - - + + + +
- - - - - - - - - 1818 - - - - - + + + 1818 + + +
- - - - - - - + + + +
- - - - - - - - - 1818 - - - - - + + + 1818 + + +
- - - - - - - + + + +
- - - - - - - - - 1818 - - - - - + + + 1818 + + +
Date: Fri, 11 Oct 2024 15:41:31 -0400 Subject: [PATCH 04/10] feat(ts/components/reactDivIcon): create custom `DivIcon` for React portals [optional] (#2848) * feat(ts/components/reactDivIcon): create custom `DivIcon` for React portals * chore(ts/components/reactDivIcon): update snapshots --- .../components/map/utilities/reactDivIcon.tsx | 65 +- .../__snapshots__/mapPage.test.tsx.snap | 338 +++--- .../shuttleMapPage.test.tsx.snap | 1080 +++++++---------- .../detoursListPage.openDetour.test.tsx.snap | 308 +++-- .../map/utilities/reactMarker.test.tsx | 4 +- 5 files changed, 793 insertions(+), 1002 deletions(-) diff --git a/assets/src/components/map/utilities/reactDivIcon.tsx b/assets/src/components/map/utilities/reactDivIcon.tsx index f99a662fd..a2b3c6abf 100644 --- a/assets/src/components/map/utilities/reactDivIcon.tsx +++ b/assets/src/components/map/utilities/reactDivIcon.tsx @@ -1,6 +1,6 @@ import { useMemo } from "react" -import L, { DivIconOptions as LeafletDivIconOptions } from "leaflet" +import { DivIcon, DivIconOptions as LeafletDivIconOptions } from "leaflet" // Prevent user from setting parameters we intend to provide export type DivIconOptions = Omit @@ -8,6 +8,61 @@ export type DivIconOptions = Omit // Prevent useEffect from triggering by providing stable default reference const defaultOptions = {} +// DefinitelyTyped definitions _seem_ to allow us to use a "real" class instead of `.extend`? +// https://github.com/DefinitelyTyped/DefinitelyTyped/issues/3923 +// https://leafletjs.com/examples/extending/extending-1-classes.html +/** + * A Leaflet {@linkcode DivIcon} which uses a provided {@linkcode HTMLElement} + * as the marker element returned to leaflet when the associated Marker is added + * to the map. + * + * The provided {@linkcode HTMLElement} is a stable element that is created + * before the {@linkcode DivIcon} is added to a Map via a Marker. This is + * required so that the {@linkcode HTMLElement} reference can be created before + * the Marker and Icon are added to the `Map` + */ +class DivIconReactPortal extends DivIcon { + /** + * Stable element reference for React Portals. + */ + element: HTMLElement + + constructor(element: HTMLElement, options?: DivIconOptions) { + super(options) + this.element = element + } + + /** + * Overridden function which returns our stable {@linkcode HTMLElement} + * reference and configures the {@linkcode DivIconReactPortal.element} + * attributes according to Leaflet. + * + * --- + * + * {@linkcode _oldIcon} is the {@linkcode HTMLElement} reference that a + * Leaflet Marker stores between `onAdd` and `onRemove` calls. + * Because we _always_ want Leaflet to use our stable element reference, + * {@linkcode DivIconReactPortal.element} is always returned. + */ + createIcon(_oldIcon?: HTMLElement): HTMLElement { + this.setElementIconStyles() + return this.element + } + + // The whole reason we have to recreate the `DivIcon` entirely is because we + // need to call `_setIconStyles` on the element, when the `DivIcon` `options` + // change. Pulling this out into it's own known function may allow us to + // avoid recreating the DivIcon entirely in the future, and instead update it + // when the `options` change. + setElementIconStyles() { + // We KNOW that this function exists, but the `DefinitelyTyped` definitions + // do not include it. + if ("_setIconStyles" in this && typeof this._setIconStyles === "function") { + this._setIconStyles(this.element, "icon") + } + } +} + /** * Hook to create a `divIcon` compatible with {@link ReactDOM.createPortal}, by * creating a stable {@link HTMLDivElement container} for React to use for @@ -28,7 +83,7 @@ export function useReactDivIcon(options?: DivIconOptions) { // To ensure that the `divIcon` updates when `opts` change // regenerate the `divIcon` with the portal element and provided `opts` const divIcon = useMemo( - () => L.divIcon({ ...opts, html: iconContainer }), + () => new DivIconReactPortal(iconContainer, opts), [iconContainer, opts] ) @@ -40,8 +95,4 @@ export function useReactDivIcon(options?: DivIconOptions) { // Extend this function or add more parameters to `useReactDivIcon` to override // portal element creation -const createPortalElement = () => { - const element = document.createElement("div") - element.classList.add("w-100", "h-100") - return element -} +const createPortalElement = () => document.createElement("div") diff --git a/assets/tests/components/__snapshots__/mapPage.test.tsx.snap b/assets/tests/components/__snapshots__/mapPage.test.tsx.snap index 7824800e9..aec1bb37f 100644 --- a/assets/tests/components/__snapshots__/mapPage.test.tsx.snap +++ b/assets/tests/components/__snapshots__/mapPage.test.tsx.snap @@ -1517,21 +1517,17 @@ exports[` Snapshot renders vehicle data 1`] = ` style="margin-left: 14px; margin-top: -25px; width: 12px; height: 12px; left: -57px; top: 1295px; z-index: 1295;" tabindex="0" > -
- - - Albany - - -
+ Albany + +
Snapshot renders vehicle data 1`] = ` style="margin-left: 14px; margin-top: -25px; width: 12px; height: 12px; left: -2115px; top: 3617px; z-index: 3617;" tabindex="0" > -
- - - Arborway - - -
+ Arborway + +
Snapshot renders vehicle data 1`] = ` style="margin-left: 14px; margin-top: -25px; width: 12px; height: 12px; left: 273px; top: 1319px; z-index: 1319;" tabindex="0" > -
- - - Cabot - - -
+ Cabot + +
Snapshot renders vehicle data 1`] = ` style="margin-left: 14px; margin-top: -25px; width: 12px; height: 12px; left: -456px; top: -1720px; z-index: -1720;" tabindex="0" > -
- - - Charlestown and Somerville - - -
+ Charlestown and Somerville + +
Snapshot renders vehicle data 1`] = ` style="margin-left: 14px; margin-top: -25px; width: 12px; height: 12px; left: -1173px; top: -3823px; z-index: -3823;" tabindex="0" > -
- - - Fellsway - - -
+ Fellsway + +
Snapshot renders vehicle data 1`] = ` style="margin-left: 14px; margin-top: -25px; width: 12px; height: 12px; left: 4158px; top: -5947px; z-index: -5947;" tabindex="0" > -
- - - Lynn - - -
+ Lynn + +
Snapshot renders vehicle data 1`] = ` style="margin-left: 14px; margin-top: -25px; width: 12px; height: 12px; left: -3032px; top: -2266px; z-index: -2266;" tabindex="0" > -
- - - North Cambridge - - -
+ North Cambridge + +
Snapshot renders vehicle data 1`] = ` style="margin-left: 14px; margin-top: -25px; width: 12px; height: 12px; left: 2539px; top: 6390px; z-index: 6390;" tabindex="0" > -
- - - Quincy - - -
+ Quincy + +
Snapshot renders vehicle data 1`] = ` style="margin-left: 14px; margin-top: -25px; width: 12px; height: 12px; left: -65px; top: 1854px; z-index: 1854;" tabindex="0" > -
- - - Southampton - - -
+ Southampton + +
Snapshot renders vehicle data 1`] = ` style="margin-left: 0px; margin-top: 0px; width: 12px; height: 12px; left: 223px; top: 27px; z-index: 1027;" tabindex="0" > -
- - - -
+ +
Snapshot renders vehicle data 1`] = ` style="margin-left: -20px; margin-top: 16px; width: 12px; height: 12px; left: 223px; top: 27px; z-index: 1027;" tabindex="0" > -
- + - - - 1 - - -
+ 1 + +
Snapshot renders vehicle data 1`] = ` style="margin-left: 0px; margin-top: 0px; width: 12px; height: 12px; left: 223px; top: 27px; z-index: 27; z-index: 27;" tabindex="0" > -
- - - -
+ +
Snapshot renders vehicle data 1`] = ` style="margin-left: -15px; margin-top: 10px; width: 12px; height: 12px; left: 223px; top: 27px; z-index: 27; z-index: 27;" tabindex="0" > -
- + - - - 2 - - -
+ 2 + +
-
- - - -
+ +
-
- + + - - - 1818 - - -
+ 1818 + +
-
- - - Albany - - -
+ Albany + +
-
- - - Arborway - - -
+ Arborway + +
-
- - - Cabot - - -
+ Cabot + +
-
- - - Charlestown and Somerville - - -
+ Charlestown and Somerville + +
-
- - - Fellsway - - -
+ Fellsway + +
-
- - - Lynn - - -
+ Lynn + +
-
- - - North Cambridge - - -
+ North Cambridge + +
-
- - - Quincy - - -
+ Quincy + +
-
- - - Southampton - - -
+ Southampton + +
@@ -964,22 +920,18 @@ exports[`Shuttle Map Page renders selected shuttle routes 1`] = ` style="margin-left: 0px; margin-top: 0px; width: 12px; height: 12px; left: 0px; top: 0px; z-index: 0;" tabindex="0" > -
- - - -
+ +
-
- + + - - - 1818 - - -
+ 1818 + +
-
- - - Albany - - -
+ Albany + +
-
- - - Arborway - - -
+ Arborway + +
-
- - - Cabot - - -
+ Cabot + +
-
- - - Charlestown and Somerville - - -
+ Charlestown and Somerville + +
-
- - - Fellsway - - -
+ Fellsway + +
-
- - - Lynn - - -
+ Lynn + +
-
- - - North Cambridge - - -
+ North Cambridge + +
-
- - - Quincy - - -
+ Quincy + +
-
- - - Southampton - - -
+ Southampton + +
@@ -1715,22 +1627,18 @@ exports[`Shuttle Map Page renders with all shuttles selected 1`] = ` style="margin-left: 0px; margin-top: 0px; width: 12px; height: 12px; left: 0px; top: 0px; z-index: 0;" tabindex="0" > -
- - - -
+ +
-
- + + - - - 1818 - - -
+ 1818 + +
-
- - - Albany - - -
+ Albany + +
-
- - - Arborway - - -
+ Arborway + +
-
- - - Cabot - - -
+ Cabot + +
-
- - - Charlestown and Somerville - - -
+ Charlestown and Somerville + +
-
- - - Fellsway - - -
+ Fellsway + +
-
- - - Lynn - - -
+ Lynn + +
-
- - - North Cambridge - - -
+ North Cambridge + +
-
- - - Quincy - - -
+ Quincy + +
-
- - - Southampton - - -
+ Southampton + +
@@ -2775,22 +2643,18 @@ exports[`Shuttle Map Page renders with train vehicles 1`] = ` style="margin-left: 0px; margin-top: 0px; width: 12px; height: 12px; left: 0px; top: 0px; z-index: 0;" tabindex="0" > -
- - - -
+ +
-
- + + - - - 1818 - - -
+ 1818 + +
-
- - - Albany - - -
+ Albany + +
-
- - - Arborway - - -
+ Arborway + +
-
- - - Cabot - - -
+ Cabot + +
-
- - - Charlestown and Somerville - - -
+ Charlestown and Somerville + +
-
- - - Fellsway - - -
+ Fellsway + +
-
- - - Lynn - - -
+ Lynn + +
-
- - - North Cambridge - - -
+ North Cambridge + +
-
- - - Quincy - - -
+ Quincy + +
-
- - - Southampton - - -
+ Southampton + +
diff --git a/assets/tests/components/detours/__snapshots__/detoursListPage.openDetour.test.tsx.snap b/assets/tests/components/detours/__snapshots__/detoursListPage.openDetour.test.tsx.snap index 63bcb2e6d..4dbe2b0ef 100644 --- a/assets/tests/components/detours/__snapshots__/detoursListPage.openDetour.test.tsx.snap +++ b/assets/tests/components/detours/__snapshots__/detoursListPage.openDetour.test.tsx.snap @@ -573,30 +573,26 @@ exports[`Detours Page: Open a Detour renders detour details in an open drawer on tabindex="0" title="Detour Start" > -
- - - - -
+ + +
-
- - - -
+ +
-
- - - - -
+ + +
-
- - - - + + -
+
-
- - - - -
+ + +
-
- - - -
+ +
-
- - - - -
+ + +
-
- - - - + + -
+
{ expect(icon).toBeEmptyDOMElement() - expect(icon.parentElement?.parentElement).toHaveStyle({ + expect(icon.parentElement).toHaveStyle({ width: `${initialSizeX}px`, height: `${initialSizeY}px`, }) @@ -91,7 +91,7 @@ describe("ReactMarker", () => { /> ) - expect(icon.parentElement?.parentElement).toHaveStyle({ + expect(icon.parentElement).toHaveStyle({ width: `${newSizeX}px`, height: `${newSizeY}px`, }) From 52b5eee7d01fb4a69171c49da5902aafe5f6444b Mon Sep 17 00:00:00 2001 From: Kayla Firestack Date: Tue, 15 Oct 2024 10:36:17 -0400 Subject: [PATCH 05/10] fix: disable distributed elixir connections in production (#2854) --- config/runtime.exs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/config/runtime.exs b/config/runtime.exs index d41f217f6..cfd6e3e63 100644 --- a/config/runtime.exs +++ b/config/runtime.exs @@ -105,5 +105,7 @@ if config_env() == :prod do config :skate, Skate.Detours.TripModificationPublisher, start: true end - config :skate, DNSCluster, query: System.get_env("DNS_CLUSTER_QUERY") || :ignore + # There are currently issues with Distributed Elixir and our Data Pipelines. + # So we need to disable clustering in prod until we figure this out + # config :skate, DNSCluster, query: System.get_env("DNS_CLUSTER_QUERY") || :ignore end From 08dc1eb885c1f0a3573610450c63e982829ad378 Mon Sep 17 00:00:00 2001 From: Hannah Purcell <69368883+hannahpurcell@users.noreply.github.com> Date: Tue, 15 Oct 2024 12:04:29 -0400 Subject: [PATCH 06/10] tweak: Detour notifications behind test group (#2855) Co-authored-by: Kayla Firestack --- assets/src/components/notificationBellIcon.tsx | 7 +++++-- assets/src/components/notificationCard.tsx | 5 ++++- assets/src/userInTestGroup.ts | 1 + assets/tests/components/notificationBellIcon.test.tsx | 7 ++++++- .../tests/components/notificationCard.openDetour.test.tsx | 6 +++++- assets/tests/components/notificationCard.test.tsx | 4 +++- 6 files changed, 24 insertions(+), 6 deletions(-) diff --git a/assets/src/components/notificationBellIcon.tsx b/assets/src/components/notificationBellIcon.tsx index 4dc2a1dc2..eb83cd228 100644 --- a/assets/src/components/notificationBellIcon.tsx +++ b/assets/src/components/notificationBellIcon.tsx @@ -17,12 +17,15 @@ const NotificationBellIcon = ({ } = usePanelStateFromStateDispatchContext() const { notifications } = useContext(NotificationsContext) - const inDetoursList = inTestGroup(TestGroups.DetoursList) + const inDetoursNotificationGroup = + inTestGroup(TestGroups.DetoursList) && + inTestGroup(TestGroups.DetoursNotifications) const unreadNotifications = (notifications || []).filter( (notification) => notification.state === "unread" && !( - notification.content.$type === NotificationType.Detour && !inDetoursList + notification.content.$type === NotificationType.Detour && + !inDetoursNotificationGroup ) ) const unreadBadge: boolean = unreadNotifications.length > 0 diff --git a/assets/src/components/notificationCard.tsx b/assets/src/components/notificationCard.tsx index 3bd961496..aef5de1ea 100644 --- a/assets/src/components/notificationCard.tsx +++ b/assets/src/components/notificationCard.tsx @@ -53,7 +53,10 @@ export const NotificationCard = ({ if ( notification.content.$type === NotificationType.Detour && - !inTestGroup(TestGroups.DetoursList) + !( + inTestGroup(TestGroups.DetoursList) && + inTestGroup(TestGroups.DetoursNotifications) + ) ) { return null } diff --git a/assets/src/userInTestGroup.ts b/assets/src/userInTestGroup.ts index eeab87498..2228c89ff 100644 --- a/assets/src/userInTestGroup.ts +++ b/assets/src/userInTestGroup.ts @@ -4,6 +4,7 @@ export enum TestGroups { BackwardsDetourPrevention = "backwards-detour-prevention", DemoMode = "demo-mode", DetoursList = "detours-list", + DetoursNotifications = "detours-notifications", DetoursPilot = "detours-pilot", MinimalLadderPage = "minimal-ladder-page", LateView = "late-view", diff --git a/assets/tests/components/notificationBellIcon.test.tsx b/assets/tests/components/notificationBellIcon.test.tsx index 58aae50c0..3032ce815 100644 --- a/assets/tests/components/notificationBellIcon.test.tsx +++ b/assets/tests/components/notificationBellIcon.test.tsx @@ -160,7 +160,12 @@ describe("NotificationBellIcon", () => { }, ])("$type detour notification", () => { test("renders when there are new detour notifications and user is part of DetoursList group", () => { - jest.mocked(getTestGroups).mockReturnValue([TestGroups.DetoursList]) + jest + .mocked(getTestGroups) + .mockReturnValue([ + TestGroups.DetoursList, + TestGroups.DetoursNotifications, + ]) const { baseElement } = render( { test("renders detour details modal to match mocked fetchDetour", async () => { jest .mocked(getTestGroups) - .mockReturnValue([TestGroups.DetoursPilot, TestGroups.DetoursList]) + .mockReturnValue([ + TestGroups.DetoursPilot, + TestGroups.DetoursList, + TestGroups.DetoursNotifications, + ]) jest.mocked(fetchDetours).mockResolvedValue(Ok(detourListFactory.build())) jest diff --git a/assets/tests/components/notificationCard.test.tsx b/assets/tests/components/notificationCard.test.tsx index c4b42dd9b..175f4040d 100644 --- a/assets/tests/components/notificationCard.test.tsx +++ b/assets/tests/components/notificationCard.test.tsx @@ -32,7 +32,9 @@ jest.mock("../../src/helpers/fullStory") jest.mock("../../src/userTestGroups") beforeEach(() => { - jest.mocked(getTestGroups).mockReturnValue([TestGroups.DetoursList]) + jest + .mocked(getTestGroups) + .mockReturnValue([TestGroups.DetoursList, TestGroups.DetoursNotifications]) jest.mocked(fetchDetours).mockResolvedValue(Ok(detourListFactory.build())) jest .mocked(fetchDetour) From 945a2e9ac6dae6b30c107192ddcf9d4039d649ca Mon Sep 17 00:00:00 2001 From: Kayla Firestack Date: Tue, 15 Oct 2024 15:25:47 -0400 Subject: [PATCH 07/10] fix(ex/Realtime.Server): use `broadcast_local` instead of `broadcast` (#2856) * fix(ex/Realtime.Server): use `broadcast_local` instead of `broadcast` * fix: re-enable `DNSCluster` Reverts: https://github.com/mbta/skate/pull/2854 --- config/runtime.exs | 4 +--- lib/realtime/server.ex | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/config/runtime.exs b/config/runtime.exs index cfd6e3e63..d41f217f6 100644 --- a/config/runtime.exs +++ b/config/runtime.exs @@ -105,7 +105,5 @@ if config_env() == :prod do config :skate, Skate.Detours.TripModificationPublisher, start: true end - # There are currently issues with Distributed Elixir and our Data Pipelines. - # So we need to disable clustering in prod until we figure this out - # config :skate, DNSCluster, query: System.get_env("DNS_CLUSTER_QUERY") || :ignore + config :skate, DNSCluster, query: System.get_env("DNS_CLUSTER_QUERY") || :ignore end diff --git a/lib/realtime/server.ex b/lib/realtime/server.ex index 91cc60add..3cde364c8 100644 --- a/lib/realtime/server.ex +++ b/lib/realtime/server.ex @@ -510,7 +510,7 @@ defmodule Realtime.Server do :alerts -> "realtime_alerts" end - Phoenix.PubSub.broadcast(pubsub_name(), topic, {:new_realtime_data, state.ets}) + Phoenix.PubSub.local_broadcast(pubsub_name(), topic, {:new_realtime_data, state.ets}) end @spec block_is_active?(VehicleOrGhost.t()) :: boolean From ba6bd8e14df9db18a9bea9bfa193330aa55545e7 Mon Sep 17 00:00:00 2001 From: Hannah Purcell <69368883+hannahpurcell@users.noreply.github.com> Date: Wed, 16 Oct 2024 14:45:57 -0400 Subject: [PATCH 08/10] tweak: Make the missed stops count badge round (#2857) Co-authored-by: Kayla Firestack --- assets/src/components/detours/detourPanelComponents.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/assets/src/components/detours/detourPanelComponents.tsx b/assets/src/components/detours/detourPanelComponents.tsx index accd3ff45..384f96138 100644 --- a/assets/src/components/detours/detourPanelComponents.tsx +++ b/assets/src/components/detours/detourPanelComponents.tsx @@ -13,7 +13,10 @@ export const MissedStops = ({ missedStops }: MissedStopsProps) => ( {missedStops && (

- Missed Stops {missedStops.length} + Missed Stops + + {missedStops.length} +

{uniqBy(missedStops, (stop) => stop.id).map((missedStop) => ( From 829201a94a61a62feb3c428789d051e3d13d170a Mon Sep 17 00:00:00 2001 From: Hannah Purcell <69368883+hannahpurcell@users.noreply.github.com> Date: Wed, 16 Oct 2024 14:47:43 -0400 Subject: [PATCH 09/10] tweak: Update detour panel titles / buttons to match hi-fi language (#2853) --- .../detourPanels/detourFinishedPanel.tsx | 4 +- .../detours/detourPanels/drawDetourPanel.tsx | 2 +- .../detoursListPage.openDetour.test.tsx.snap | 8 +-- .../detoursListPage.openDetour.test.tsx | 5 +- .../detours/diversionPage.activate.test.tsx | 13 ++-- .../components/detours/diversionPage.test.tsx | 63 +++++++------------ assets/tests/components/mapPage.test.tsx | 3 +- .../notificationCard.openDetour.test.tsx | 5 +- .../components/detours/diversionPage.tsx | 6 ++ 9 files changed, 46 insertions(+), 63 deletions(-) diff --git a/assets/src/components/detours/detourPanels/detourFinishedPanel.tsx b/assets/src/components/detours/detourPanels/detourFinishedPanel.tsx index 112399934..a9d2115ed 100644 --- a/assets/src/components/detours/detourPanels/detourFinishedPanel.tsx +++ b/assets/src/components/detours/detourPanels/detourFinishedPanel.tsx @@ -19,7 +19,7 @@ export const DetourFinishedPanel = ({ }: DetourFinishedPanelProps) => ( -

Share Detour Details

+

View Draft Detour

@@ -30,7 +30,7 @@ export const DetourFinishedPanel = ({ variant="outline-primary" onClick={onNavigateBack} > - Edit Detour + Edit ( -

Create Detour

+

Draw Detour

diff --git a/assets/tests/components/detours/__snapshots__/detoursListPage.openDetour.test.tsx.snap b/assets/tests/components/detours/__snapshots__/detoursListPage.openDetour.test.tsx.snap index 4dbe2b0ef..3ebde0096 100644 --- a/assets/tests/components/detours/__snapshots__/detoursListPage.openDetour.test.tsx.snap +++ b/assets/tests/components/detours/__snapshots__/detoursListPage.openDetour.test.tsx.snap @@ -405,7 +405,7 @@ exports[`Detours Page: Open a Detour renders detour details in an open drawer on

- Share Detour Details + View Draft Detour

- Edit Detour + Edit