diff --git a/.gitignore b/.gitignore index 29395df49..854dc14bc 100644 --- a/.gitignore +++ b/.gitignore @@ -37,7 +37,6 @@ npm-debug.log /priv/local.json /priv/local_pending.json /priv/signs_ui_config.json -/priv/triptych_player_to_screen_id.json # local environment variables /priv/local.env diff --git a/README.md b/README.md index 494c3b741..619808a92 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,6 @@ Some examples of the various client apps, as of January 2023: | [Multimodal LCD][solari sample] | used at high-traffic transfer stations served by many routes/modes | | [Pre-fare duo LCD][pre_fare sample] | posted outside of fare gates at rapid transit stations; content is split across two portrait-oriented 1080p physical displays | | ["Digital Urban Panel" LCD][dup sample] | content appears in rotation with ads on screens posted outside rapid transit station entrances | -| Triptych trio LCD | (:construction: WIP!) posted across the tracks from platforms at major stations; content is split across three portrait-oriented 1080p physical displays and appears in rotation with ads | and more to come! @@ -28,11 +27,11 @@ On almost all of our screen types, we use a common "framework" to fet Check out [ARCHITECTURE.md](/ARCHITECTURE.md) for an overview of the application architecture, as well as links to further more detailed documentation. -## Packaging the DUP and Triptych apps +## Packaging the DUP app -The DUP and Triptych screens require the client app to be packaged into a single HTML file rather than dynamically served from our Phoenix server. +The DUP screens require the client app to be packaged into a single HTML file rather than dynamically served from our Phoenix server. -You can find instructions on the DUP packaging process [here](assets/src/components/v2/dup/README.md), the triptych packaging process [here](assets/src/components/v2/triptych/README.md). +You can find instructions on the DUP packaging process [here](assets/src/components/v2/dup/README.md). ## Version upgrade guide diff --git a/assets/css/triptych_v2.scss b/assets/css/triptych_v2.scss deleted file mode 100644 index e427bdf21..000000000 --- a/assets/css/triptych_v2.scss +++ /dev/null @@ -1,69 +0,0 @@ -@import "colors"; -@import "fonts/inter_font_face"; -@import "fonts/helvetica_font_face"; -@import "v2/common/widget"; - -@mixin font--heading-3 { - font-size: 158px; - font-weight: 700; - line-height: 158px; -} - -@mixin font--subtitle { - font-size: 144px; - font-weight: 700; - line-height: 144px; -} - -@mixin font--body-1 { - font-size: 96px; - font-weight: 600; - line-height: 118px; -} - -@mixin font--body-2 { - font-size: 96px; - font-weight: 400; - line-height: 118px; -} - -@mixin font--caption-2 { - font-size: 32px; - font-weight: 600; - line-height: 40px; -} - -@mixin font--caption-3 { - font-size: 32px; - font-weight: 700; - line-height: 40px; -} - -// Top level stuff -@import "v2/triptych/screen_container"; -@import "v2/triptych/viewport"; - -// Layout/slot elements -@import "v2/triptych/screen/full_screen"; - -// No-data states -@import "v2/lcd_common/page_load_no_data"; -@import "v2/lcd_common/no_data"; -@import "v2/triptych/no_data"; - -// Widgets -@import "v2/train_crowding"; -@import "v2/placeholder"; - -// Debug overlay for test packages -@import "v2/outfront_common/debug"; -@import "v2/triptych/debug"; - -@import "v2/triptych/evergreen"; -@import "v2/simulation_common"; -@import "v2/triptych/simulation"; - -body { - margin: 0; - font-family: Inter, sans-serif; -} diff --git a/assets/css/v2/train_crowding.scss b/assets/css/v2/train_crowding.scss deleted file mode 100644 index 2aed9fac4..000000000 --- a/assets/css/v2/train_crowding.scss +++ /dev/null @@ -1,160 +0,0 @@ -.crowding-widget { - &__header { - box-sizing: border-box; - display: flex; - flex-direction: column; - height: 578px; - padding: 72px; - color: #e5e4e1; - background-color: #171f26; - } - - &__body { - position: relative; - display: flex; - flex-direction: column; - height: 920px; - background-color: #d9d6d0; - box-shadow: 0 8px 12px 0 rgb(0 0 0 / 32%); - } - - &__footer { - display: flex; - height: 422px; - background-color: #cccbc8; - } -} - -.crowding-widget__header__top-row { - display: flex; - - .t-logo { - padding: 4px; - } - - .normal-header-time { - @include font--body-2; - - margin-left: auto; - } -} - -.crowding-widget__header__destination-sentence { - @include font--heading-3; - - margin-top: auto; - color: #fff; - - .destination { - padding-left: 109px; - } -} - -.crowding-widget__footer__segment { - @include font--body-1; - - position: relative; - display: flex; - flex: 1 1; - flex-direction: column; - justify-content: space-between; - padding: 71px 72px; -} - -.crowding-widget__footer__key-row { - @include font--body-2; - - display: inline-flex; - align-items: center; - - .key-icon { - padding-right: 72px; - } -} - -.crowding-widget__footer__identifiers { - @include font--caption-2; - - position: absolute; - right: 24px; - bottom: 18px; -} - -.crowding-widget__train-row { - display: flex; - justify-content: space-between; - padding: 161px 52px 58px; -} - -@keyframes up-arrow { - 0% { - transform: translateY(0); - } - - 50% { - transform: translateY(-20px); - } - - 100% { - transform: translateY(0); - } -} - -@keyframes up-left-arrow { - 0% { - transform: translateY(0); - } - - 50% { - transform: translateY(-12px) translateX(-12px); - } - - 100% { - transform: translateY(0); - } -} - -@keyframes up-right-arrow { - 0% { - transform: translateY(0) rotate(90deg); - } - - 50% { - transform: translateY(-12px) translateX(12px) rotate(90deg); - } - - 100% { - transform: translateY(0) rotate(90deg); - } -} - -.crowding-widget__you-are-here-arrow { - width: 180px; - height: 180px; - - &--up { - animation: up-arrow 1.2s infinite ease-in-out; - } - - &--up-left { - animation: up-left-arrow 1.2s infinite ease-in-out; - } - - &--up-right { - animation: up-right-arrow 1.2s infinite ease-in-out; - } -} - -.crowding-widget__you-are-here-text { - @include font--subtitle; - - box-sizing: border-box; - width: 1080px; - padding: 0 72px 108px; - margin-top: auto; - text-align: left; - - &--right-align { - text-align: right; - } -} diff --git a/assets/css/v2/triptych/debug.scss b/assets/css/v2/triptych/debug.scss deleted file mode 100644 index ea8b78ea8..000000000 --- a/assets/css/v2/triptych/debug.scss +++ /dev/null @@ -1,8 +0,0 @@ -#debug.triptych { - width: 1080px; - height: 1920px; -} - -#debug .line { - width: 540px; -} diff --git a/assets/css/v2/triptych/evergreen.scss b/assets/css/v2/triptych/evergreen.scss deleted file mode 100644 index 20cd4b63b..000000000 --- a/assets/css/v2/triptych/evergreen.scss +++ /dev/null @@ -1,22 +0,0 @@ -.left-pane, -.middle-pane, -.right-pane { - .evergreen-content__identifiers { - position: absolute; - right: 0; - bottom: 0; - padding: 12px 24px 18px; - color: white; - text-align: right; - background-color: rgb(23 31 38 / 70%); - - @include font--caption-3; - } -} - -.evergreen-content-image__image, -.evergreen-content-video, -.evergreen-content-video .looping-video { - width: 1080px; - height: 1920px; -} diff --git a/assets/css/v2/triptych/no_data.scss b/assets/css/v2/triptych/no_data.scss deleted file mode 100644 index 9086a8a56..000000000 --- a/assets/css/v2/triptych/no_data.scss +++ /dev/null @@ -1,11 +0,0 @@ -.no-data-middle { - position: absolute; - top: 0; - left: 1080px; -} - -.no-data-right { - position: absolute; - top: 0; - left: 2160px; -} diff --git a/assets/css/v2/triptych/screen/full_screen.scss b/assets/css/v2/triptych/screen/full_screen.scss deleted file mode 100644 index 3a89d7239..000000000 --- a/assets/css/v2/triptych/screen/full_screen.scss +++ /dev/null @@ -1,7 +0,0 @@ -.full-screen { - position: relative; - width: 3240px; - height: 1920px; - margin-right: auto; - margin-left: auto; -} diff --git a/assets/css/v2/triptych/screen_container.scss b/assets/css/v2/triptych/screen_container.scss deleted file mode 100644 index 623ca9d9f..000000000 --- a/assets/css/v2/triptych/screen_container.scss +++ /dev/null @@ -1,25 +0,0 @@ -.screen-container { - position: relative; - width: 3240px; - height: 1920px; - margin: 0 auto; - overflow: hidden; -} - -.left-pane, -.middle-pane, -.right-pane { - position: absolute; - top: 0; - width: 1080px; - height: 1920px; - overflow: hidden; -} - -.middle-pane { - left: 1080px; -} - -.right-pane { - left: 2160px; -} diff --git a/assets/css/v2/triptych/simulation.scss b/assets/css/v2/triptych/simulation.scss deleted file mode 100644 index 6a2a0c747..000000000 --- a/assets/css/v2/triptych/simulation.scss +++ /dev/null @@ -1,72 +0,0 @@ -.simulation-screen-scrolling-container { - display: flex; - padding-bottom: 20px; - overflow: auto hidden; - scrollbar-color: #607180 #2e3f4d; - - &::-webkit-scrollbar { - width: 12px; - } - - &::-webkit-scrollbar-thumb { - background-color: #607180; - border: 2px solid #2e3f4d; - border-radius: 12px; - } - - &::-webkit-scrollbar-track { - background-color: #2e3f4d; - border-radius: 12px; - box-shadow: inset 0 0 6px rgb(0 0 0 / 30%); - } - - .simulation__full-page { - position: relative; - z-index: 999; - display: flex; - width: 580.5px; - height: 344px; - overflow: hidden; - - .left-pane, - .middle-pane, - .right-pane { - position: relative; - left: unset; - width: 33.33%; - height: 100%; - overflow: hidden; - - .evergreen-content-image__container, - .evergreen-content-image__image { - width: 1080px; - height: 1920px; - } - - & > * { - transform: scale(17.92%); - transform-origin: top left; - } - - .evergreen-content__identifiers { - transform-origin: bottom right; - } - } - } - - .full-screen { - z-index: 999; - width: 580.5px; - height: 344px; - - .crowding-widget { - width: 3240px; - height: 1920px; - } - - & > * { - transform: scale(17.92%); - transform-origin: top left; - } - } -} diff --git a/assets/css/v2/triptych/viewport.scss b/assets/css/v2/triptych/viewport.scss deleted file mode 100644 index 1a7042a30..000000000 --- a/assets/css/v2/triptych/viewport.scss +++ /dev/null @@ -1,31 +0,0 @@ -.triptych-screen-viewport { - position: relative; - width: 1080px; - height: 1920px; - margin-right: auto; - margin-left: auto; - overflow: hidden; - - .triptych-shifter { - position: absolute; - width: 3240px; - height: 1920px; - overflow: hidden; - } - - .triptych-shifter--left { - left: 0; - } - - .triptych-shifter--middle { - left: -1080px; - } - - .triptych-shifter--right { - right: 0; - } -} - -.triptych-screen-viewport--all { - width: 3240px; -} diff --git a/assets/src/apps/admin.tsx b/assets/src/apps/admin.tsx index 6ff08b071..fcfbb3f23 100644 --- a/assets/src/apps/admin.tsx +++ b/assets/src/apps/admin.tsx @@ -19,10 +19,8 @@ import { BusShelterV2ScreensTable, PreFareV2ScreensTable, DupV2ScreensTable, - TriptychV2ScreensTable, } from "Components/admin/admin_tables"; import AdminScreenConfigForm from "Components/admin/admin_screen_config_form"; -import AdminTriptychPlayerForm from "Components/admin/admin_triptych_player_form"; import ImageManager from "Components/admin/admin_image_manager"; import Devops from "Components/admin/devops"; import Inspector from "Components/admin/inspector"; @@ -37,13 +35,9 @@ const routes: [string, string, ComponentType][][] = [ ["gl-eink-v2-screens", "GL E-ink", GLEinkV2ScreensTable], ["pre-fare-v2-screens", "Pre-Fare", PreFareV2ScreensTable], ["busway-v2-screens", "Sectional", BuswayV2ScreensTable], - ["triptych-v2-screens", "Triptych", TriptychV2ScreensTable], ], [["solari-screens", "Solari (v1)", SolariScreensTable]], - [ - ["screens-json-editor", "Config Editor", AdminScreenConfigForm], - ["triptych-player-json-editor", "Triptych Editor", AdminTriptychPlayerForm], - ], + [["screens-json-editor", "Config Editor", AdminScreenConfigForm]], [["image-manager", "Image Manager", ImageManager]], [["devops", "Devops", Devops]], ]; diff --git a/assets/src/apps/v2/triptych.tsx b/assets/src/apps/v2/triptych.tsx deleted file mode 100644 index 17436bc2e..000000000 --- a/assets/src/apps/v2/triptych.tsx +++ /dev/null @@ -1,124 +0,0 @@ -require("../../../css/triptych_v2.scss"); - -import React from "react"; -import ReactDOM from "react-dom"; -import { BrowserRouter as Router, Route, Switch } from "react-router-dom"; - -import { usePlayerName } from "Hooks/outfront"; -import { isTriptych } from "Util/outfront"; - -import { MappingContext } from "Components/v2/widget"; -import { - ResponseMapper, - ResponseMapperContext, -} from "Components/v2/screen_container"; - -import ScreenPage from "Components/v2/screen_page"; -import MultiScreenPage from "Components/v2/multi_screen_page"; -import SimulationScreenPage from "Components/v2/simulation_screen_page"; -import Viewport from "Components/v2/triptych/viewport"; - -import FullScreen from "Components/v2/basic_layouts/full_screen"; -import TriptychThreePane from "Components/v2/triptych/triptych_three_pane"; - -import PageLoadNoData from "Components/v2/triptych/page_load_no_data"; -import NoData from "Components/v2/triptych/no_data"; - -import Placeholder from "Components/v2/placeholder"; -import TrainCrowding from "Components/v2/train_crowding"; -import OutfrontEvergreenContent from "Components/v2/outfront_evergreen_content"; - -const TYPE_TO_COMPONENT = { - // Layouts - screen_normal: FullScreen, - screen_split: TriptychThreePane, - // Components - page_load_no_data: PageLoadNoData, - no_data: NoData, - train_crowding: TrainCrowding, - evergreen_content: OutfrontEvergreenContent, - placeholder: Placeholder, -}; - -const LOADING_LAYOUT = { - full_screen: { - type: "page_load_no_data", - }, - type: "screen_normal", -}; - -const DISABLED_LAYOUT = { - full_screen: { - type: "no_data", - }, - type: "screen_normal", -}; - -const FAILURE_LAYOUT = DISABLED_LAYOUT; - -const responseMapper: ResponseMapper = (apiResponse) => { - switch (apiResponse.state) { - case "success": - case "simulation_success": - return apiResponse.data; - case "disabled": - return DISABLED_LAYOUT; - case "failure": - return FAILURE_LAYOUT; - case "loading": - return LOADING_LAYOUT; - } -}; - -const App = (): JSX.Element => { - if (isTriptych()) { - const playerName = usePlayerName()!; - - return ( - - - - - - - - ); - } - - return ( - - - - - - - - - - - - - - - - - - - - - - - - ); -}; - -ReactDOM.render(, document.getElementById("app")); diff --git a/assets/src/components/admin/admin_add_modal.tsx b/assets/src/components/admin/admin_add_modal.tsx index 9117c292e..4fa63bb6a 100644 --- a/assets/src/components/admin/admin_add_modal.tsx +++ b/assets/src/components/admin/admin_add_modal.tsx @@ -25,7 +25,6 @@ const fields = [ "solari", "solari_large", "solari_large_v2", - "triptych_v2", ]), }, { @@ -90,11 +89,6 @@ const defaultAppParamsByAppId = { stop_name: "", }, }, - triptych_v2: { - header: { - stop_name: "", - }, - }, }; const initialFormValues = _.fromPairs( diff --git a/assets/src/components/admin/admin_tables.tsx b/assets/src/components/admin/admin_tables.tsx index 5a964229b..00269afff 100644 --- a/assets/src/components/admin/admin_tables.tsx +++ b/assets/src/components/admin/admin_tables.tsx @@ -292,31 +292,6 @@ const v2Columns = [ }, ]; -const screenIDColumn = { - Header: "Screen ID", - accessor: "id", - Cell: InspectorLink, - Filter: DefaultColumnFilter, - FormCell: FormStaticCell, -}; - -const screenNameColumn = { - Header: "Name", - accessor: "name", - Cell: EditableCell, - Filter: DefaultColumnFilter, - FormCell: FormTextCell, -}; - -const evergreenContentColumn = { - Header: "Evergreen Content", - accessor: buildAppParamAccessor("evergreen_content"), - mutator: buildAppParamMutator("evergreen_content"), - Cell: EditableTextarea, - disableFilters: true, - FormCell: FormTextarea, -}; - const alertsColumn = { Header: "Alerts", accessor: buildAppParamAccessor("alerts"), @@ -470,33 +445,6 @@ const shuttleBusInfoColumn = { FormCell: FormTextarea, }; -const trainCrowdingColumn = { - Header: "Train Crowding", - accessor: buildAppParamAccessor("train_crowding"), - mutator: buildAppParamMutator("train_crowding"), - Cell: EditableTextarea, - disableFilters: true, - FormCell: FormTextarea, -}; - -const localEvergreenSetsColumn = { - Header: "Local Evergreen Content Sets", - accessor: buildAppParamAccessor("local_evergreen_sets"), - mutator: buildAppParamMutator("local_evergreen_sets"), - Cell: EditableTextarea, - disableFilters: true, - FormCell: FormTextarea, -}; - -const showIdentifiersColumn = { - Header: "Show Version & Player Name?", - accessor: buildAppParamAccessor("show_identifiers"), - mutator: buildAppParamMutator("show_identifiers"), - Cell: EditableCheckbox, - Filter: DefaultColumnFilter, - FormCell: FormBoolean, -}; - const PreFareV2ScreensTable = (): JSX.Element => { const dataFilter = ({ app_id }) => { return app_id === "pre_fare_v2"; @@ -561,26 +509,6 @@ const BuswayV2ScreensTable = (): JSX.Element => { return ; }; -const TriptychV2ScreensTable = (): JSX.Element => { - const dataFilter = ({ app_id }) => { - return app_id === "triptych_v2"; - }; - - return ( - - ); -}; - export { AllScreensTable, BusEinkV2ScreensTable, @@ -590,5 +518,4 @@ export { GLEinkV2ScreensTable, PreFareV2ScreensTable, SolariScreensTable, - TriptychV2ScreensTable, }; diff --git a/assets/src/components/admin/admin_triptych_player_form.tsx b/assets/src/components/admin/admin_triptych_player_form.tsx deleted file mode 100644 index a6b562ac7..000000000 --- a/assets/src/components/admin/admin_triptych_player_form.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import React from "react"; -import _ from "lodash"; - -import AdminForm from "Components/admin/admin_form"; - -const fetchConfig = async () => { - const result = await fetch("/api/admin/triptych_players"); - const resultJson = await result.json(); - - // Sort the entries alphanumerically by player name. - return _.chain(JSON.parse(resultJson.config)) - .toPairs() - .sortBy(([playerName, _screenId]) => playerName) - .fromPairs() - .value(); -}; - -const AdminTriptychPlayerForm = (): JSX.Element => ( - -); - -export default AdminTriptychPlayerForm; diff --git a/assets/src/components/dup/README.md b/assets/src/components/dup/README.md index d93c219b8..f0dc996e9 100644 --- a/assets/src/components/dup/README.md +++ b/assets/src/components/dup/README.md @@ -1,7 +1,7 @@ # DUP app packaging - Ensure [Corsica](https://hexdocs.pm/corsica/Corsica.html) is used on the server to allow CORS requests (ideally limited to just the DUP-relevant routes). It should already be configured at [this line](/lib/screens_web/controllers/screen_api_controller.ex#L7) in the API controller--if it is, you don't need to do anything for this step. -- Double check that any behavior specific to the DUP screen environment happens inside of an `isOFM()` check. This includes: +- Double check that any behavior specific to the DUP screen environment happens inside of an `isDup()` check. This includes: - `buildApiPath` in use_api_response.tsx should return a full URL for the API path: prefix `apiPath` string with "https://screens.mbta.com". - `App` component in dup.tsx should just return ``. - `imagePath` in util.tsx should return relative paths (no leading `/`). diff --git a/assets/src/components/v2/dup/README.md b/assets/src/components/v2/dup/README.md index 61a4f9639..765f1a09c 100644 --- a/assets/src/components/v2/dup/README.md +++ b/assets/src/components/v2/dup/README.md @@ -1,7 +1,7 @@ # DUP app packaging v2 - Ensure [Corsica](https://hexdocs.pm/corsica/Corsica.html) is used on the server to allow CORS requests (ideally limited to just the DUP-relevant routes). It should already be configured at [this line](/lib/screens_web/controllers/v2/screen_api_controller.ex#L9) in the API controller--if it is, you don't need to do anything for this step. -- Double check that any behavior specific to the DUP screen environment happens inside of an `isDup()` or `isOFM()` check. This includes: +- Double check that any behavior specific to the DUP screen environment happens inside of an `isDup()` check. This includes: - `buildApiPath` in use_api_response.tsx should return a full URL for the API path: prefix `apiPath` string with "https://screens.mbta.com". - `imagePath` in util.tsx should return relative paths (no leading `/`). - Create priv/static/dup-app.html if it doesnโ€™t already exist. Copy paste the following contents in: diff --git a/assets/src/components/v2/outfront_evergreen_content.tsx b/assets/src/components/v2/outfront_evergreen_content.tsx deleted file mode 100644 index aaa8ea835..000000000 --- a/assets/src/components/v2/outfront_evergreen_content.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import React, { ComponentType } from "react"; - -import EvergreenContent from "./evergreen_content"; -import useIsOnScreen from "Hooks/v2/use_is_on_screen"; -import { imagePath } from "Util/util"; -import { TRIPTYCH_VERSION } from "./triptych/version"; -import { usePlayerName } from "Hooks/outfront"; -import { isOFM } from "Util/outfront"; - -if (isOFM()) { - require.context("Images/triptych_psas", true, /\.webp$/); -} - -const OutfrontEvergreenContent: ComponentType<{ - asset_url: string; - show_identifiers: boolean; -}> = ({ asset_url: assetUrl, show_identifiers: showIdentifiers }) => { - const dupReadyUrl = imagePath(assetUrl); - const isPlaying = useIsOnScreen(); - const playerName = usePlayerName(); - const identifiers = `${TRIPTYCH_VERSION} ${playerName ? playerName : ""}`; - return ( - <> - - {showIdentifiers && ( -
{identifiers}
- )} - - ); -}; - -export default OutfrontEvergreenContent; diff --git a/assets/src/components/v2/screen_container.tsx b/assets/src/components/v2/screen_container.tsx index 736968833..9c084bf15 100644 --- a/assets/src/components/v2/screen_container.tsx +++ b/assets/src/components/v2/screen_container.tsx @@ -10,12 +10,11 @@ import useApiResponse, { ApiResponse, SimulationData, useDUPApiResponse, - useTriptychApiResponse, } from "Hooks/v2/use_api_response"; import WidgetTreeErrorBoundary from "Components/v2/widget_tree_error_boundary"; import Widget, { WidgetData } from "Components/v2/widget"; import useAudioReadout from "Hooks/v2/use_audio_readout"; -import { isDup, isOFM, isTriptych } from "Util/outfront"; +import { isDup } from "Util/outfront"; type ResponseMapper = (apiResponse: ApiResponse) => WidgetData | SimulationData; @@ -92,7 +91,7 @@ const ScreenLayout: ComponentType = ({ showBlink, }) => { const responseMapper = useContext(ResponseMapperContext); - const ErrorBoundaryOrFragment = isOFM() ? Fragment : WidgetTreeErrorBoundary; + const ErrorBoundaryOrFragment = isDup() ? Fragment : WidgetTreeErrorBoundary; // We know this can only be `WidgetData` and not `SimulationData` here because // `ScreenPage` is only used in contexts where a "non-simulation" API response @@ -114,8 +113,6 @@ const ScreenLayout: ComponentType = ({ const getApiResponseHook = () => { if (isDup()) { return useDUPApiResponse; - } else if (isTriptych()) { - return useTriptychApiResponse; } else { return useApiResponse; } diff --git a/assets/src/components/v2/train_crowding.tsx b/assets/src/components/v2/train_crowding.tsx deleted file mode 100644 index a9ea694e2..000000000 --- a/assets/src/components/v2/train_crowding.tsx +++ /dev/null @@ -1,261 +0,0 @@ -import React from "react"; - -import { classWithModifier } from "Util/util"; -import { NormalHeaderTime } from "./normal_header"; -import { usePlayerName } from "Hooks/outfront"; -import { TRIPTYCH_VERSION } from "./triptych/version"; - -import Logo from "Images/svgr_bundled/logo.svg"; -import ArrowUp from "Images/svgr_bundled/Arrow-90.svg"; -import ArrowUpLeft from "Images/svgr_bundled/Arrow-45.svg"; - -import KeyNotCrowded from "Images/svgr_bundled/train_crowding/Car-NotCrowded-Key.svg"; -import KeySomeCrowding from "Images/svgr_bundled/train_crowding/Car-SomeCrowding-Key.svg"; -import KeyCrowded from "Images/svgr_bundled/train_crowding/Car-Crowded-Key.svg"; -import KeyNoData from "Images/svgr_bundled/train_crowding/Car-NoData-Key.svg"; -import KeyClosed from "Images/svgr_bundled/train_crowding/Car-Closed-Key.svg"; - -import CarNotCrowdedLeft from "Images/svgr_bundled/train_crowding/Car-NotCrowded-Left.svg"; -import CarSomeCrowdingLeft from "Images/svgr_bundled/train_crowding/Car-SomeCrowding-Left.svg"; -import CarCrowdedLeft from "Images/svgr_bundled/train_crowding/Car-Crowded-Left.svg"; -import CarNoDataLeft from "Images/svgr_bundled/train_crowding/Car-NoData-Left.svg"; -import CarClosedLeft from "Images/svgr_bundled/train_crowding/Car-Closed-Left.svg"; - -import CarNotCrowdedMiddle from "Images/svgr_bundled/train_crowding/Car-NotCrowded-Middle.svg"; -import CarSomeCrowdingMiddle from "Images/svgr_bundled/train_crowding/Car-SomeCrowding-Middle.svg"; -import CarCrowdedMiddle from "Images/svgr_bundled/train_crowding/Car-Crowded-Middle.svg"; -import CarNoDataMiddle from "Images/svgr_bundled/train_crowding/Car-NoData-Middle.svg"; -import CarClosedMiddle from "Images/svgr_bundled/train_crowding/Car-Closed-Middle.svg"; - -import CarNotCrowdedRight from "Images/svgr_bundled/train_crowding/Car-NotCrowded-Right.svg"; -import CarSomeCrowdingRight from "Images/svgr_bundled/train_crowding/Car-SomeCrowding-Right.svg"; -import CarCrowdedRight from "Images/svgr_bundled/train_crowding/Car-Crowded-Right.svg"; -import CarNoDataRight from "Images/svgr_bundled/train_crowding/Car-NoData-Right.svg"; -import CarClosedRight from "Images/svgr_bundled/train_crowding/Car-Closed-Right.svg"; - -type FrontCarDirection = "left" | "right"; -type OccupancyStatus = - | "no_data" - | "not_crowded" - | "some_crowding" - | "crowded" - | "closed"; - -type CarOrientation = FrontCarDirection | "middle"; -const lookupCarComponent = ( - occupancyStatus: OccupancyStatus, - carOrientation: CarOrientation, -) => { - const lookupKey: `${CarOrientation}/${OccupancyStatus}` = `${carOrientation}/${occupancyStatus}`; - - switch (lookupKey) { - case "left/not_crowded": - return CarNotCrowdedLeft; - case "left/some_crowding": - return CarSomeCrowdingLeft; - case "left/crowded": - return CarCrowdedLeft; - case "left/no_data": - return CarNoDataLeft; - case "left/closed": - return CarClosedLeft; - - case "right/not_crowded": - return CarNotCrowdedRight; - case "right/some_crowding": - return CarSomeCrowdingRight; - case "right/crowded": - return CarCrowdedRight; - case "right/no_data": - return CarNoDataRight; - case "right/closed": - return CarClosedRight; - - case "middle/not_crowded": - return CarNotCrowdedMiddle; - case "middle/some_crowding": - return CarSomeCrowdingMiddle; - case "middle/crowded": - return CarCrowdedMiddle; - case "middle/no_data": - return CarNoDataMiddle; - case "middle/closed": - return CarClosedMiddle; - } -}; - -interface FooterSegmentProps { - children: React.ReactNode; - identifiers: string; - showIdentifiers: boolean; -} - -// Wrapper for footer segments so there is less code duplication when adding identifiers -const FooterSegment: React.ComponentType = ({ - children, - identifiers, - showIdentifiers, -}) => { - return ( -
- {children} - {showIdentifiers && ( -
- {identifiers} -
- )} -
- ); -}; - -interface Props { - arrivalTime: string; - crowding: OccupancyStatus[]; - destination: string; - front_car_direction: FrontCarDirection; - now: string; - platform_position: number; - show_identifiers: boolean; -} - -const TrainCrowding: React.ComponentType = ({ - crowding, - destination, - platform_position: platformPosition, - front_car_direction: frontCarDirection, - now, - show_identifiers: showIdentifiers, -}) => { - // If the front car direction is right, the crowding array needs to be reversed - // so the last car is rendered on the left. - const trains = crowding.map((occupancyStatus, i) => { - const CarComponent = lookupCarComponent( - occupancyStatus, - i == 0 ? frontCarDirection : "middle", - ); - return ; - }); - - const trainSequence = - frontCarDirection == "left" ? trains : [...trains].reverse(); - - // If arrow is between screens, scoot the arrow to the next slot on the right - // If arrow is beyond the end of the train (slot 25), scoot arrow left - let arrowSlot; - if ([1, 9, 17].includes(platformPosition)) { - arrowSlot = platformPosition + 1; - } else { - if (platformPosition == 25) { - arrowSlot = platformPosition - 1; - } else arrowSlot = platformPosition; - } - - // The slot arrangement exceeds the edges of the screen, so to properly set the slot positions - // we need to make a few adjustments. - const screenWidth = 3240; - const slotOverhang = 35; - const slotsWidth = screenWidth + slotOverhang * 2; - const extraArrowPadding = 24; - const arrowLeftPadding = - (arrowSlot - 1) * (slotsWidth / 25) - slotOverhang - extraArrowPadding; - const arrowDirection = [1, 9, 17].includes(platformPosition) - ? "up-left" - : platformPosition == 25 - ? "up-right" - : "up"; - - const textPane = Math.floor((arrowSlot / 25) * 3); - const textPadding = (textPane * 3240) / 3; - - const playerName = usePlayerName(); - const identifiers = `${TRIPTYCH_VERSION} ${playerName ? playerName : ""}`; - - return ( -
-
-
- - {now && } -
-
- Next train to{destination} -
-
-
-
{trainSequence}
-
- {arrowDirection == "up" ? ( - - ) : ( - - )} -
-
- You are here -
-
-
- - Current crowding on board - - -
- {" "} - Seats available -
-
- {" "} - Some crowding -
-
- -
- Crowded -
-
- {crowding.includes("closed") ? ( - <> - Car - closed - - ) : ( - crowding.includes("no_data") && ( - <> - No - data - - ) - )} -
-
-
-
- ); -}; - -export default TrainCrowding; diff --git a/assets/src/components/v2/triptych/README.md b/assets/src/components/v2/triptych/README.md deleted file mode 100644 index 64e678b63..000000000 --- a/assets/src/components/v2/triptych/README.md +++ /dev/null @@ -1,128 +0,0 @@ -# Triptych app packaging - -## Resizing the PSAs - -Outfront recommends these asset sizes: - -- Images: The boards can take webp, which saves 35% or possibly more. OFM - recommends using `sharp`, but you can also use - [webp](https://formulae.brew.sh/formula/webp). `cwebp -resize 1080 0 left.png -o left.webp` will resize left.png to the triptych screen size and convert to - webp. -- Videos: Use handbrake video transcoder to reduce size to below 10MB, at least. - (Perhaps much smaller.) To do so, get [HandBrake](https://handbrake.fr/), load - the source file, and simply hit "Start". It compresses the file. Check the - output to make sure it still looks good. - -## Prepping the package - -- Ensure [Corsica](https://hexdocs.pm/corsica/Corsica.html) is used on the - server to allow CORS requests (ideally limited to just the triptych-relevant - routes). It should already be configured at [this - line](/lib/screens_web/controllers/v2/screen_api_controller.ex#L9) in the API - controller--if it is, you don't need to do anything for this step. -- Double check that any behavior specific to the triptych screen environment - happens inside of an `isTriptych()` or `isOFM()` check. This includes: - - - `buildApiPath` in use_api_response.tsx should return a full URL for the API - path: prefix `apiPath` string with "https://screens.mbta.com". - - `imagePath` in util.tsx should return relative paths (no leading `/`). - -- Set the version string in assets/src/components/v2/triptych/version.tsx to - `current_year.current_month.current_day.1`. -- If you've renamed / removed image assets, you might want to delete the - corresponding folder in `/priv/static`. The folder accumulates assets without - clearing old ones out, and these will be included in the built bundle! -- **Only if you are packaging for local testing** - - add the following to the top of assets/src/apps/v2/triptych.tsx, filling in - the string values: - ```ts - import { __TEST_setFakeMRAID__ } from "Util/outfront"; - __TEST_setFakeMRAID__({ - playerName: "", - station: "", - triptychPane: "", - }); - ``` - This sets up a fake MRAID object that emulates the real one available to the - client when running on Outfront screens. The MRAID object gives our client - info about which screen it's running on. - - replace the definition of `OUTFRONT_BASE_URI` in - `assets/src/hooks/v2/use_api_response.tsx` with `"http://localhost:4000"`. - - make sure priv/triptych_player_to_screen_id.json mirrors - mbta-ctd-config/screens/triptych_player_to_screen_id-prod.json, or at least - contains a mapping for the `playerName` that you hardcoded two steps ago. -- `cd` to priv/static and run the following: - ```sh - npm --prefix ../../assets run deploy && \ - cp -r css/packaged_triptych_v2.css js/packaged_triptych_polyfills.js js/packaged_triptych_v2.js js/packaged_triptych_v2.js.map ../triptych_preview.png ../triptych-app.html . && \ - cp -r js/triptych_images . && \ - cp ../triptych_template.json ./template.json && \ - zip -r triptych-app.zip packaged_triptych_v2.css packaged_triptych_polyfills.js packaged_triptych_v2.js packaged_triptych_v2.js.map fonts triptych_images triptych-app.html template.json triptych_preview.png - ``` -- On completion, the packaged client app will be saved at - `priv/static/triptych-app.zip`. -- Commit the version bump on a branch, push it, and create a PR to mark the - deploy. - -## Working with Outfront - -Once you've created the client app package, you'll need to send it to Outfront -for them to test and deploy it. - -Ask a Screens team member for the email of our contact at Outfront. In your -message, be sure to specify: - -- a player name (or "Liveboard name"), and -- a triptych pane (or `Array_configuration`--value should be of the form - "Triple\_(Left|Middle|Right)") - -## Debugging - -To assist with debugging on the triptych screens, you can paste this at the -module scope in triptych.tsx to have console logs show up on the screen: - -```js -const Counter = (() => { - let n = 0; - - return { - next() { - let cur = n; - n = (n + 1) % 100; - return `${cur.toString().padStart(2, "0")}`; - }, - }; -})(); - -const dEl = document.createElement("div"); -dEl.id = "debug"; -dEl.className = "triptych"; -document.body.appendChild(dEl); -// save the original console.log function -const old_logger = console.log; -// grab html element for adding console.log output -const html_logger = document.getElementById("debug"); -// replace console.log function with our own function -console.log = function (...msgs) { - // first call old logger for console output - old_logger.call(this, arguments); - - // convert object args to strings and join them together - const text = msgs - .map((msg) => { - if (typeof msg == "object") { - return JSON && JSON.stringify ? JSON.stringify(msg) : msg; - } else { - return msg; - } - }) - .join(" "); - - // add the log to the html element. - html_logger.innerHTML = `
${Counter.next()} ${text}
${ - html_logger.innerHTML - }`; -}; - -console.log("On-screen logger initialized"); -``` diff --git a/assets/src/components/v2/triptych/no_data.tsx b/assets/src/components/v2/triptych/no_data.tsx deleted file mode 100644 index 63705602a..000000000 --- a/assets/src/components/v2/triptych/no_data.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import React, { ComponentType } from "react"; -import noDataPNG from "Images/no-data-triptych.png"; - -interface Props { - show_alternatives: boolean; -} - -const NoData: ComponentType = () => { - return ( - <> -
- -
-
- -
-
- -
- - ); -}; - -export default NoData; diff --git a/assets/src/components/v2/triptych/page_load_no_data.tsx b/assets/src/components/v2/triptych/page_load_no_data.tsx deleted file mode 100644 index bda2264bd..000000000 --- a/assets/src/components/v2/triptych/page_load_no_data.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import React, { ComponentType } from "react"; -import loadingPNG from "Images/loading-triptych.png"; - -const PageLoadNoData: ComponentType = () => { - return ( - <> -
- -
-
- -
-
- -
- - ); -}; - -export default PageLoadNoData; diff --git a/assets/src/components/v2/triptych/triptych_three_pane.tsx b/assets/src/components/v2/triptych/triptych_three_pane.tsx deleted file mode 100644 index 3c15d9cf9..000000000 --- a/assets/src/components/v2/triptych/triptych_three_pane.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import React from "react"; - -import Widget, { WidgetData } from "Components/v2/widget"; -import { TriptychPane, getTriptychPane } from "Util/outfront"; - -interface Props { - left_pane: WidgetData; - middle_pane: WidgetData; - right_pane: WidgetData; -} - -const isInViewport = (pane: TriptychPane | null, slotPosition: TriptychPane) => - pane == null || pane == slotPosition; - -const TriptychThreePane: React.ComponentType = ({ - left_pane: leftPane, - middle_pane: middlePane, - right_pane: rightPane, -}) => { - const pane = getTriptychPane(); - - return ( - <> -
- {isInViewport(pane, "left") && } -
-
- {isInViewport(pane, "middle") && } -
-
- {isInViewport(pane, "right") && } -
- - ); -}; - -export default TriptychThreePane; diff --git a/assets/src/components/v2/triptych/version.tsx b/assets/src/components/v2/triptych/version.tsx deleted file mode 100644 index bef9d8f69..000000000 --- a/assets/src/components/v2/triptych/version.tsx +++ /dev/null @@ -1 +0,0 @@ -export const TRIPTYCH_VERSION = "24.5.8.1"; diff --git a/assets/src/components/v2/triptych/viewport.tsx b/assets/src/components/v2/triptych/viewport.tsx deleted file mode 100644 index 7ee1c26c1..000000000 --- a/assets/src/components/v2/triptych/viewport.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import React from "react"; - -import { getTriptychPane } from "Util/outfront"; - -/** - * Shifts one of the three triptych panes into view - * based on a `data-triptych-pane` data attribute on the #app div. - * If the param is missing, this will show the full - * screen content (3240px x 1920px). - */ -const Viewport: React.ComponentType = ({ children }) => { - let viewportClassName = "triptych-screen-viewport"; - let shifterClassName = "triptych-shifter"; - - const pane = getTriptychPane(); - if (pane != null) { - shifterClassName += ` triptych-shifter--${pane}`; - } else { - viewportClassName += " triptych-screen-viewport--all"; - } - - return ( -
-
{children}
-
- ); -}; - -export default Viewport; diff --git a/assets/src/hooks/outfront.tsx b/assets/src/hooks/outfront.tsx index 710de4255..864f72cff 100644 --- a/assets/src/hooks/outfront.tsx +++ b/assets/src/hooks/outfront.tsx @@ -1,11 +1,5 @@ import { useMemo } from "react"; -import { - getMRAID, - getPlayerName, - getStationName, - getTriptychPane, -} from "Util/outfront"; -import type { TriptychPane } from "Util/outfront"; +import { getMRAID, getPlayerName, getStationName } from "Util/outfront"; /** * Returns the player name, or null if we fail to determine it for any reason. @@ -13,12 +7,6 @@ import type { TriptychPane } from "Util/outfront"; export const usePlayerName = (): string | null => useMemo(getPlayerName, [getMRAID()]); -/** - * Returns the triptych pane, or null if we fail to determine it for any reason. - */ -export const useTriptychPane = (): TriptychPane | null => - useMemo(getTriptychPane, [getMRAID()]); - /** * Returns the station name, or null if we fail to determine it for any reason. */ diff --git a/assets/src/hooks/use_api_response.tsx b/assets/src/hooks/use_api_response.tsx index 12bfafbfc..9836a2245 100644 --- a/assets/src/hooks/use_api_response.tsx +++ b/assets/src/hooks/use_api_response.tsx @@ -1,9 +1,9 @@ import { useEffect, useState } from "react"; -import { isOFM } from "Util/outfront"; import { isRealScreen } from "Util/util"; import useInterval from "Hooks/use_interval"; import { getDatasetValue } from "Util/dataset"; import * as SentryLogger from "Util/sentry"; +import { isDup } from "Util/outfront"; const MINUTE_IN_MS = 60_000; @@ -43,7 +43,7 @@ const useIsRealScreenParam = () => { }; const useRequestorParam = () => { - if (isOFM()) return `&requestor=real_screen`; + if (isDup()) return `&requestor=real_screen`; let requestor = getDatasetValue("requestor"); if (!requestor && isRealScreen()) { @@ -164,7 +164,7 @@ const buildApiPath = ({ apiPath += `&datetime=${datetime}`; } - if (isOFM()) { + if (isDup()) { apiPath = "https://screens.mbta.com" + apiPath; } diff --git a/assets/src/hooks/v2/use_api_response.tsx b/assets/src/hooks/v2/use_api_response.tsx index 21e15dc5d..c3df7a13d 100644 --- a/assets/src/hooks/v2/use_api_response.tsx +++ b/assets/src/hooks/v2/use_api_response.tsx @@ -3,12 +3,11 @@ import useDriftlessInterval from "Hooks/use_driftless_interval"; import React, { useEffect, useMemo, useState } from "react"; import { getDatasetValue } from "Util/dataset"; import { sendToInspector, useReceiveFromInspector } from "Util/inspector"; -import { isDup, isOFM, isTriptych, getTriptychPane } from "Util/outfront"; +import { isDup } from "Util/outfront"; import { getScreenSide, isRealScreen } from "Util/util"; import * as SentryLogger from "Util/sentry"; import { ROTATION_INDEX } from "Components/v2/dup/rotation_index"; import { DUP_VERSION } from "Components/v2/dup/version"; -import { TRIPTYCH_VERSION } from "Components/v2/triptych/version"; import useRefreshRate from "./use_refresh_rate"; const BASE_PATH = "/v2/api/screen"; @@ -119,11 +118,6 @@ const loggingParams = () => { rotation_index: ROTATION_INDEX.toString(), version: DUP_VERSION, }; - } else if (isTriptych()) { - return { - pane: getTriptychPane() ?? "UNKNOWN", - version: TRIPTYCH_VERSION, - }; } else { return {}; } @@ -131,7 +125,7 @@ const loggingParams = () => { const useApiPath = (screenId: string, appendPath?: string): string => { return useMemo(() => { - const base = isOFM() ? OUTFRONT_BASE_URI : document.baseURI; + const base = isDup() ? OUTFRONT_BASE_URI : document.baseURI; const path = [ BASE_PATH, getDatasetValue("isPending") === "true" ? "pending" : null, @@ -281,18 +275,14 @@ const useApiResponse = ({ id }) => useBaseApiResponse(id); const useSimulationApiResponse = ({ id }) => useBaseApiResponse(id, "simulation"); -// For OFM apps--DUP, triptych--we need to request a different +// For OFM apps--DUPs--we need to request a different // route that's more permissive of CORS, since these clients are loaded from a local html file // (and thus their data requests to our server are cross-origin). // // The /dup endpoint only has the CORS stuff, and otherwise runs exactly the same backend logic as // the normal one used by `useApiResponse`. -// -// The /triptych endpoint has the CORS stuff, plus an additional step that maps the player name of -// the individual triptych pane to a screen ID representing the collective trio. const useDUPApiResponse = ({ id }) => useBaseApiResponse(id, "dup"); -const useTriptychApiResponse = ({ id }) => useBaseApiResponse(id, "triptych"); export default useApiResponse; export type { ApiResponse, SimulationData }; -export { useSimulationApiResponse, useDUPApiResponse, useTriptychApiResponse }; +export { useSimulationApiResponse, useDUPApiResponse }; diff --git a/assets/src/hooks/v2/use_refresh_rate.ts b/assets/src/hooks/v2/use_refresh_rate.ts index 7ed368cb4..b8ade5c00 100644 --- a/assets/src/hooks/v2/use_refresh_rate.ts +++ b/assets/src/hooks/v2/use_refresh_rate.ts @@ -2,7 +2,7 @@ import _ from "lodash"; import { useMemo, useState } from "react"; import { fetchDatasetValue, getDatasetValue } from "Util/dataset"; import { useReceiveFromInspector } from "Util/inspector"; -import { isOFM } from "Util/outfront"; +import { isDup } from "Util/outfront"; import { useScreenID } from "./use_screen_id"; interface RefreshRateConfig { @@ -17,7 +17,7 @@ const useRefreshRate = (): RefreshRateConfig => { return useMemo(() => { // Live OFM screens ignore any configured refreshRate. // Hardcoding to 0 prevents an interval from being started unnecessarily. - const refreshRate = isOFM() ? "0" : fetchDatasetValue("refreshRate"); + const refreshRate = isDup() ? "0" : fetchDatasetValue("refreshRate"); const refreshRateOffset = getDatasetValue("refreshRateOffset") || "0"; const screenIdsWithOffsetMap = getDatasetValue("screenIdsWithOffsetMap"); diff --git a/assets/src/util/outfront.tsx b/assets/src/util/outfront.tsx index 08cb21a98..260c0bc81 100644 --- a/assets/src/util/outfront.tsx +++ b/assets/src/util/outfront.tsx @@ -1,14 +1,6 @@ import { ROTATION_INDEX } from "Components/v2/dup/rotation_index"; import { getDatasetValue } from "Util/dataset"; -/** - * Returns true if this client is running on an Outfront Media screen. - * (A DUP or a triptych.) - * - * Use this for OFM-specific logic that is common to both the DUP and triptych apps. - */ -export const isOFM = () => location.href.startsWith("file:"); - /** * Returns true if this client is running on a DUP screen. * @@ -16,25 +8,13 @@ export const isOFM = () => location.href.startsWith("file:"); */ export const isDup = () => /^file:.*dup-app.*/.test(location.href); -/** - * Returns true if this client is running on a triptych screen. - * - * Use this for triptych-specific logic. - */ -export const isTriptych = () => /^file:.*triptych-app.*/.test(location.href); - type RotationIndex = "0" | "1" | "2"; const isRotationIndex = (value: any): value is RotationIndex => { return value === "0" || value === "1" || value === "2"; }; -export type TriptychPane = "left" | "middle" | "right"; -const isTriptychPane = (value: any): value is TriptychPane => { - return value === "left" || value === "middle" || value === "right"; -}; - export const getRotationIndex = (): RotationIndex | null => { - const rotationIndex = isOFM() + const rotationIndex = isDup() ? ROTATION_INDEX.toString() : getDatasetValue("rotationIndex"); @@ -44,8 +24,6 @@ export const getRotationIndex = (): RotationIndex | null => { /** * Gets Outfront's unique name/ID for the media player we're running on. * - * For DUPs, this is just a single ID. For triptychs, each of the 3 panes has its own player name. - * * Returns null if we fail to determine the player name for any reason. */ export const getPlayerName = (): string | null => { @@ -63,36 +41,6 @@ export const getPlayerName = (): string | null => { return playerName; }; -/** - * Determines which of the 3 panes of a triptych we're running on (left, middle, or right). - * - * If we're running on a real triptych screen, we determine the pane from the `Array_configuration` tag. - * If we're running in a browser, we determine the pane from the `data-triptych-pane` attribute on the #app div. - * - * Returns null if we fail to determine the pane for any reason. - */ -export const getTriptychPane = (): TriptychPane | null => { - const pane = isTriptych() - ? getTriptychPaneFromTags() - : getDatasetValue("triptychPane"); - - return isTriptychPane(pane) ? pane : null; -}; - -const getTriptychPaneFromTags = () => { - let pane: TriptychPane | null = null; - - const tags = getTags(); - if (tags !== null) { - const arrayConfiguration = - tags.find(({ name }) => name === "Array_configuration")?.value?.[0] ?? - null; - pane = arrayConfigurationToTriptychPane(arrayConfiguration); - } - - return pane; -}; - /** * Gets name of the station (e.g. "Back Bay") from the `Station` tag. * @@ -121,25 +69,6 @@ const getTags = (): OFMTag[] | null => { return tags; }; -const arrayConfigurationToTriptychPane = ( - arrayConfiguration: string | null, -): TriptychPane | null => { - switch (arrayConfiguration) { - case "Triple_Left": - return "left"; - case "Triple_Middle": - return "middle"; - case "Triple_Right": - return "right"; - default: - return null; - } -}; - -const triptychPaneToArrayConfiguration = (pane: TriptychPane): string => { - return `Triple_${pane[0].toUpperCase().concat(pane.slice(1))}`; -}; - interface OFMWindow extends Window { mraid?: MRAID; } @@ -167,29 +96,23 @@ interface OFMTag { } export const getMRAID = (): MRAID | false => { - if (!isOFM()) return false; + if (!isDup()) return false; return (parent?.parent as OFMWindow)?.mraid ?? false; }; /** - * For use in test DUP/triptych packages only! Sets a fake MRAID object on `window` so that we can test OFM client packages + * For use in test DUP packages only! Sets a fake MRAID object on `window` so that we can test OFM client packages * as if they are running on real OFM screens. */ export const __TEST_setFakeMRAID__ = (options: { playerName: string; station: string; - triptychPane?: TriptychPane; }) => { - const { playerName, station, triptychPane } = options; - - const tags: OFMTag[] = [{ name: "Station", value: [station] }]; - if (triptychPane) { - tags.push({ - name: "Array_configuration", - value: [triptychPaneToArrayConfiguration(triptychPane)], - }); - } - const tagsJSON = JSON.stringify({ tags }); + const { playerName, station } = options; + + const tagsJSON = JSON.stringify({ + tags: [{ name: "Station", value: [station] }], + }); const deviceInfoJSON = JSON.stringify({ deviceName: playerName }); diff --git a/assets/src/util/sentry.tsx b/assets/src/util/sentry.tsx index 47b9fed0d..e4264ca00 100644 --- a/assets/src/util/sentry.tsx +++ b/assets/src/util/sentry.tsx @@ -1,4 +1,4 @@ -import { isOFM } from "Util/outfront"; +import { isDup } from "Util/outfront"; import { isRealScreen } from "Util/util"; import { getDataset } from "Util/dataset"; // Previously tried @sentry/react and @sentry/browser as the SDK, but the QtWeb browser on e-inks could not @@ -29,7 +29,7 @@ const initSentry = (appString: string) => { if (sentryDsn && isRealScreen()) { Raven.config(sentryDsn, { environment: env }).install(); - if (isOFM()) { + if (isDup()) { const today = new Date(); const hour = today.getHours(); const min = today.getMinutes(); diff --git a/assets/src/util/util.tsx b/assets/src/util/util.tsx index 8c064a936..41d41811f 100644 --- a/assets/src/util/util.tsx +++ b/assets/src/util/util.tsx @@ -3,7 +3,7 @@ import "moment-timezone"; import { RefObject } from "react"; import { getDatasetValue } from "Util/dataset"; -import { isOFM, isTriptych } from "Util/outfront"; +import { isDup } from "Util/outfront"; export const classWithModifier = (baseClass, modifier) => { if (!modifier) { @@ -33,16 +33,13 @@ export const hasOverflowX = (ref: RefObject): boolean => !!ref.current && ref.current.scrollWidth > ref.current.clientWidth; export const imagePath = (fileName: string): string => - isOFM() ? outfrontImagePath(fileName) : `/images/${fileName}`; - -export const outfrontImagePath = (fileName: string): string => - isTriptych() ? `triptych_images/${fileName}` : `images/${fileName}`; + isDup() ? `images/${fileName}` : `/images/${fileName}`; export const pillPath = (fileName: string): string => - isOFM() ? `images/pills/${fileName}` : `/images/pills/${fileName}`; + isDup() ? `images/pills/${fileName}` : `/images/pills/${fileName}`; export const isRealScreen = () => - isOFM() || getDatasetValue("isRealScreen") === "true"; + isDup() || getDatasetValue("isRealScreen") === "true"; type ScreenSide = "left" | "right"; const isScreenSide = (value: any): value is ScreenSide => { diff --git a/assets/static/images/loading-triptych.png b/assets/static/images/loading-triptych.png deleted file mode 100644 index 35ea5ce01..000000000 Binary files a/assets/static/images/loading-triptych.png and /dev/null differ diff --git a/assets/static/images/no-data-triptych.png b/assets/static/images/no-data-triptych.png deleted file mode 100644 index 3630154e5..000000000 Binary files a/assets/static/images/no-data-triptych.png and /dev/null differ diff --git a/assets/static/images/svgr_bundled/train_crowding/Car-Closed-Key.svg b/assets/static/images/svgr_bundled/train_crowding/Car-Closed-Key.svg deleted file mode 100644 index ca67fc29f..000000000 --- a/assets/static/images/svgr_bundled/train_crowding/Car-Closed-Key.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/assets/static/images/svgr_bundled/train_crowding/Car-Closed-Left.svg b/assets/static/images/svgr_bundled/train_crowding/Car-Closed-Left.svg deleted file mode 100644 index 0f46f2340..000000000 --- a/assets/static/images/svgr_bundled/train_crowding/Car-Closed-Left.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/assets/static/images/svgr_bundled/train_crowding/Car-Closed-Middle.svg b/assets/static/images/svgr_bundled/train_crowding/Car-Closed-Middle.svg deleted file mode 100644 index 2a135cec4..000000000 --- a/assets/static/images/svgr_bundled/train_crowding/Car-Closed-Middle.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/assets/static/images/svgr_bundled/train_crowding/Car-Closed-Right.svg b/assets/static/images/svgr_bundled/train_crowding/Car-Closed-Right.svg deleted file mode 100644 index 243b1bf3d..000000000 --- a/assets/static/images/svgr_bundled/train_crowding/Car-Closed-Right.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/assets/static/images/svgr_bundled/train_crowding/Car-Crowded-Key.svg b/assets/static/images/svgr_bundled/train_crowding/Car-Crowded-Key.svg deleted file mode 100644 index aabd005aa..000000000 --- a/assets/static/images/svgr_bundled/train_crowding/Car-Crowded-Key.svg +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/assets/static/images/svgr_bundled/train_crowding/Car-Crowded-Left.svg b/assets/static/images/svgr_bundled/train_crowding/Car-Crowded-Left.svg deleted file mode 100644 index ed8c827e9..000000000 --- a/assets/static/images/svgr_bundled/train_crowding/Car-Crowded-Left.svg +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/assets/static/images/svgr_bundled/train_crowding/Car-Crowded-Middle.svg b/assets/static/images/svgr_bundled/train_crowding/Car-Crowded-Middle.svg deleted file mode 100644 index 866ee9ab8..000000000 --- a/assets/static/images/svgr_bundled/train_crowding/Car-Crowded-Middle.svg +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/assets/static/images/svgr_bundled/train_crowding/Car-Crowded-Right.svg b/assets/static/images/svgr_bundled/train_crowding/Car-Crowded-Right.svg deleted file mode 100644 index e2c18da07..000000000 --- a/assets/static/images/svgr_bundled/train_crowding/Car-Crowded-Right.svg +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/assets/static/images/svgr_bundled/train_crowding/Car-NoData-Key.svg b/assets/static/images/svgr_bundled/train_crowding/Car-NoData-Key.svg deleted file mode 100644 index b5186e768..000000000 --- a/assets/static/images/svgr_bundled/train_crowding/Car-NoData-Key.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/assets/static/images/svgr_bundled/train_crowding/Car-NoData-Left.svg b/assets/static/images/svgr_bundled/train_crowding/Car-NoData-Left.svg deleted file mode 100644 index b69a0e3a0..000000000 --- a/assets/static/images/svgr_bundled/train_crowding/Car-NoData-Left.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/assets/static/images/svgr_bundled/train_crowding/Car-NoData-Middle.svg b/assets/static/images/svgr_bundled/train_crowding/Car-NoData-Middle.svg deleted file mode 100644 index 9b54906d0..000000000 --- a/assets/static/images/svgr_bundled/train_crowding/Car-NoData-Middle.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/assets/static/images/svgr_bundled/train_crowding/Car-NoData-Right.svg b/assets/static/images/svgr_bundled/train_crowding/Car-NoData-Right.svg deleted file mode 100644 index e3e25b4aa..000000000 --- a/assets/static/images/svgr_bundled/train_crowding/Car-NoData-Right.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/assets/static/images/svgr_bundled/train_crowding/Car-NotCrowded-Key.svg b/assets/static/images/svgr_bundled/train_crowding/Car-NotCrowded-Key.svg deleted file mode 100644 index f593c1440..000000000 --- a/assets/static/images/svgr_bundled/train_crowding/Car-NotCrowded-Key.svg +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - diff --git a/assets/static/images/svgr_bundled/train_crowding/Car-NotCrowded-Left.svg b/assets/static/images/svgr_bundled/train_crowding/Car-NotCrowded-Left.svg deleted file mode 100644 index bfc3648a5..000000000 --- a/assets/static/images/svgr_bundled/train_crowding/Car-NotCrowded-Left.svg +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - - - - - - - - - diff --git a/assets/static/images/svgr_bundled/train_crowding/Car-NotCrowded-Middle.svg b/assets/static/images/svgr_bundled/train_crowding/Car-NotCrowded-Middle.svg deleted file mode 100644 index d56b14c07..000000000 --- a/assets/static/images/svgr_bundled/train_crowding/Car-NotCrowded-Middle.svg +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - - - - - - - - - diff --git a/assets/static/images/svgr_bundled/train_crowding/Car-NotCrowded-Right.svg b/assets/static/images/svgr_bundled/train_crowding/Car-NotCrowded-Right.svg deleted file mode 100644 index b6e90c98b..000000000 --- a/assets/static/images/svgr_bundled/train_crowding/Car-NotCrowded-Right.svg +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - - - - - - - - - diff --git a/assets/static/images/svgr_bundled/train_crowding/Car-SomeCrowding-Key.svg b/assets/static/images/svgr_bundled/train_crowding/Car-SomeCrowding-Key.svg deleted file mode 100644 index 72d16189c..000000000 --- a/assets/static/images/svgr_bundled/train_crowding/Car-SomeCrowding-Key.svg +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/assets/static/images/svgr_bundled/train_crowding/Car-SomeCrowding-Left.svg b/assets/static/images/svgr_bundled/train_crowding/Car-SomeCrowding-Left.svg deleted file mode 100644 index 538ac1754..000000000 --- a/assets/static/images/svgr_bundled/train_crowding/Car-SomeCrowding-Left.svg +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - diff --git a/assets/static/images/svgr_bundled/train_crowding/Car-SomeCrowding-Middle.svg b/assets/static/images/svgr_bundled/train_crowding/Car-SomeCrowding-Middle.svg deleted file mode 100644 index 14a156861..000000000 --- a/assets/static/images/svgr_bundled/train_crowding/Car-SomeCrowding-Middle.svg +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - diff --git a/assets/static/images/svgr_bundled/train_crowding/Car-SomeCrowding-Right.svg b/assets/static/images/svgr_bundled/train_crowding/Car-SomeCrowding-Right.svg deleted file mode 100644 index 2974d3db2..000000000 --- a/assets/static/images/svgr_bundled/train_crowding/Car-SomeCrowding-Right.svg +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - diff --git a/assets/static/images/triptych_psas/See-Say/left.webp b/assets/static/images/triptych_psas/See-Say/left.webp deleted file mode 100644 index 808993e68..000000000 Binary files a/assets/static/images/triptych_psas/See-Say/left.webp and /dev/null differ diff --git a/assets/static/images/triptych_psas/See-Say/middle.webp b/assets/static/images/triptych_psas/See-Say/middle.webp deleted file mode 100644 index fa85a530a..000000000 Binary files a/assets/static/images/triptych_psas/See-Say/middle.webp and /dev/null differ diff --git a/assets/static/images/triptych_psas/See-Say/right.webp b/assets/static/images/triptych_psas/See-Say/right.webp deleted file mode 100644 index 0ffdbcc73..000000000 Binary files a/assets/static/images/triptych_psas/See-Say/right.webp and /dev/null differ diff --git a/assets/static/images/triptych_psas/Stroll-n-Scroll/left.webp b/assets/static/images/triptych_psas/Stroll-n-Scroll/left.webp deleted file mode 100644 index c4a27f5e8..000000000 Binary files a/assets/static/images/triptych_psas/Stroll-n-Scroll/left.webp and /dev/null differ diff --git a/assets/static/images/triptych_psas/Stroll-n-Scroll/middle.webp b/assets/static/images/triptych_psas/Stroll-n-Scroll/middle.webp deleted file mode 100644 index cc713445f..000000000 Binary files a/assets/static/images/triptych_psas/Stroll-n-Scroll/middle.webp and /dev/null differ diff --git a/assets/static/images/triptych_psas/Stroll-n-Scroll/right.webp b/assets/static/images/triptych_psas/Stroll-n-Scroll/right.webp deleted file mode 100644 index 5bd8014be..000000000 Binary files a/assets/static/images/triptych_psas/Stroll-n-Scroll/right.webp and /dev/null differ diff --git a/assets/webpack.config.js b/assets/webpack.config.js index ae62fe9b0..80179a8ee 100644 --- a/assets/webpack.config.js +++ b/assets/webpack.config.js @@ -8,62 +8,6 @@ const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin"); const CopyWebpackPlugin = require("copy-webpack-plugin"); const { sentryWebpackPlugin } = require("@sentry/webpack-plugin"); -const common_export_body = { - resolve: { - extensions: [".ts", ".tsx", ".js", ".jsx"], - alias: { - // Please also update the "paths" list in tsconfig.json when you add aliases here! - Components: path.resolve(__dirname, "src/components"), - Hooks: path.resolve(__dirname, "src/hooks"), - Util: path.resolve(__dirname, "src/util"), - Constants: path.resolve(__dirname, "src/constants"), - Images: path.resolve(__dirname, "static/images"), - }, - }, - output: { - filename: "[name].js", - path: path.resolve(__dirname, "../priv/static/js"), - }, - devtool: "source-map", - optimization: { - minimizer: [new TerserPlugin(), new OptimizeCSSAssetsPlugin()], - }, -}; - -const common_rules = [ - { - enforce: "pre", - test: /\.js$/, - loader: "source-map-loader", - }, - { - test: /\.s?css$/, - use: [ - MiniCssExtractPlugin.loader, - { - loader: "css-loader", - }, - { - loader: "sass-loader", - }, - ], - }, - { - test: /\.svg$/i, - issuer: /\.[jt]sx?$/, - use: ["@svgr/webpack"], - }, -]; - -const common_babel_loader_plugins = [ - "@babel/plugin-proposal-export-default-from", - "@babel/plugin-proposal-logical-assignment-operators", - ["@babel/plugin-proposal-optional-chaining", { loose: false }], - ["@babel/plugin-proposal-pipeline-operator", { proposal: "minimal" }], - ["@babel/plugin-proposal-nullish-coalescing-operator", { loose: false }], - "@babel/plugin-proposal-do-expressions", -]; - module.exports = (env, argv) => { // Upload source maps to Sentry for prod builds. Must be the last plugin. const appendPlugins = @@ -79,7 +23,25 @@ module.exports = (env, argv) => { return [ { - ...common_export_body, + resolve: { + extensions: [".ts", ".tsx", ".js", ".jsx"], + alias: { + // Please also update the "paths" list in tsconfig.json when you add aliases here! + Components: path.resolve(__dirname, "src/components"), + Hooks: path.resolve(__dirname, "src/hooks"), + Util: path.resolve(__dirname, "src/util"), + Constants: path.resolve(__dirname, "src/constants"), + Images: path.resolve(__dirname, "static/images"), + }, + }, + output: { + filename: "[name].js", + path: path.resolve(__dirname, "../priv/static/js"), + }, + devtool: "source-map", + optimization: { + minimizer: [new TerserPlugin(), new OptimizeCSSAssetsPlugin()], + }, entry: { polyfills: "./src/polyfills.js", bus_eink: "./src/apps/bus_eink.tsx", @@ -95,7 +57,6 @@ module.exports = (env, argv) => { dup_v2: "./src/apps/v2/dup.tsx", bus_shelter_v2: "./src/apps/v2/bus_shelter.tsx", pre_fare_v2: "./src/apps/v2/pre_fare.tsx", - triptych_v2: "./src/apps/v2/triptych.tsx", }, module: { rules: [ @@ -110,76 +71,48 @@ module.exports = (env, argv) => { "@babel/preset-react", "@babel/preset-typescript", ], - plugins: common_babel_loader_plugins, + plugins: [ + "@babel/plugin-proposal-export-default-from", + "@babel/plugin-proposal-logical-assignment-operators", + [ + "@babel/plugin-proposal-optional-chaining", + { loose: false }, + ], + [ + "@babel/plugin-proposal-pipeline-operator", + { proposal: "minimal" }, + ], + [ + "@babel/plugin-proposal-nullish-coalescing-operator", + { loose: false }, + ], + "@babel/plugin-proposal-do-expressions", + ], }, }, }, - ...common_rules, { - test: /\.(woff(2)?|ttf|eot)(\?v=\d+\.\d+\.\d+)?$/, - use: [ - { - loader: "file-loader", - options: { - name: "[name].[ext]", - outputPath: "fonts/", - publicPath: "../fonts/", - useRelativePaths: true, - }, - }, - ], + enforce: "pre", + test: /\.js$/, + loader: "source-map-loader", }, { - test: /\.(png|jpe?g|gif|webp)$/i, + test: /\.s?css$/, use: [ + MiniCssExtractPlugin.loader, { - loader: "file-loader", - options: { - name: "/[folder]/[name].[ext]", - useRelativePaths: true, - }, + loader: "css-loader", + }, + { + loader: "sass-loader", }, ], }, - ], - }, - plugins: [ - new MiniCssExtractPlugin({ filename: "../css/[name].css" }), - new CopyWebpackPlugin({ patterns: [{ from: "static/", to: "../" }] }), - ...appendPlugins, - ], - }, - { - ...common_export_body, - entry: { - packaged_triptych_polyfills: "./src/polyfills.js", - packaged_triptych_v2: "./src/apps/v2/triptych.tsx", - }, - module: { - rules: [ { - test: /\.ts(x?)$/, - exclude: /node_modules/, - use: { - loader: "babel-loader", - options: { - presets: [ - // When no targets are specified: Babel will assume you are targeting the oldest browsers possible. - [ - "@babel/preset-env", - { - corejs: { version: 3, proposals: true }, - useBuiltIns: "usage", - }, - ], - "@babel/preset-react", - "@babel/preset-typescript", - ], - plugins: common_babel_loader_plugins, - }, - }, + test: /\.svg$/i, + issuer: /\.[jt]sx?$/, + use: ["@svgr/webpack"], }, - ...common_rules, { test: /\.(woff(2)?|ttf|eot)(\?v=\d+\.\d+\.\d+)?$/, use: [ @@ -188,36 +121,19 @@ module.exports = (env, argv) => { options: { name: "[name].[ext]", outputPath: "fonts/", - publicPath: "fonts/", - useRelativePaths: true, - }, - }, - ], - }, - { - test: /\.(png|jpe?g|gif)$/i, - use: [ - { - loader: "file-loader", - - options: { - name: "[name].[ext]", - outputPath: "triptych_images/", - publicPath: "triptych_images/", + publicPath: "../fonts/", useRelativePaths: true, }, }, ], }, { - test: /\.(webp)$/i, + test: /\.(png|jpe?g|gif|webp)$/i, use: [ { loader: "file-loader", options: { name: "/[folder]/[name].[ext]", - outputPath: "triptych_images/triptych_psas/", - publicPath: "triptych_images/triptych_psas/", useRelativePaths: true, }, }, @@ -227,9 +143,7 @@ module.exports = (env, argv) => { }, plugins: [ new MiniCssExtractPlugin({ filename: "../css/[name].css" }), - new CopyWebpackPlugin({ - patterns: [{ from: "static/fonts", to: "../fonts" }], - }), + new CopyWebpackPlugin({ patterns: [{ from: "static/", to: "../" }] }), ...appendPlugins, ], }, diff --git a/config/config.exs b/config/config.exs index b0bfaa12b..2a45747ea 100644 --- a/config/config.exs +++ b/config/config.exs @@ -70,8 +70,6 @@ config :screens, audio_psa_s3_directory: "/screens/audio_assets/psa/", signs_ui_s3_path: "config.json", signs_ui_config_fetcher: Screens.SignsUiConfig.Fetch.S3, - triptych_player_s3_bucket: "mbta-ctd-config", - triptych_player_fetcher: Screens.TriptychPlayer.Fetch.S3, last_deploy_fetcher: Screens.Util.LastDeploy.S3Fetch, blue_bikes_api_client: Screens.BlueBikes.Client, blue_bikes_station_information_url: diff --git a/config/dev.exs b/config/dev.exs index 69b2c71bd..3f174537c 100644 --- a/config/dev.exs +++ b/config/dev.exs @@ -16,13 +16,11 @@ config :screens, ScreensWeb.Endpoint, config :screens, config_fetcher: Screens.Config.Fetch.Local, pending_config_fetcher: Screens.PendingConfig.Fetch.Local, - triptych_player_fetcher: Screens.TriptychPlayer.Fetch.Local, last_deploy_fetcher: Screens.Util.LastDeploy.LocalFetch, local_config_file_spec: {:priv, "local.json"}, local_pending_config_file_spec: {:priv, "local_pending.json"}, local_signs_ui_config_file_spec: {:priv, "signs_ui_config.json"}, - signs_ui_config_fetcher: Screens.SignsUiConfig.Fetch.Local, - local_triptych_player_file_spec: {:priv, "triptych_player_to_screen_id.json"} + signs_ui_config_fetcher: Screens.SignsUiConfig.Fetch.Local config :screens, ScreensWeb.AuthManager, secret_key: "secret key" diff --git a/config/test.exs b/config/test.exs index d6a7662fe..0232e9d1d 100644 --- a/config/test.exs +++ b/config/test.exs @@ -13,9 +13,7 @@ config :screens, local_config_file_spec: {:test, "config.json"}, local_pending_config_file_spec: {:test, "pending_config.json"}, local_signs_ui_config_file_spec: {:test, "signs_ui_config.json"}, - local_triptych_player_file_spec: {:test, "triptych_player_to_screen_id.json"}, signs_ui_config_fetcher: Screens.SignsUiConfig.Fetch.Local, - triptych_player_fetcher: Screens.TriptychPlayer.Fetch.Local, # This will help us write testable functions. # Functions that request external data cause flaky tests, so to stop us from writing tests that execute API requests, # we pass a non-string as the default URL (causing tests to break.) diff --git a/lib/screens/application.ex b/lib/screens/application.ex index 131d9a94c..1aba7fb38 100644 --- a/lib/screens/application.ex +++ b/lib/screens/application.ex @@ -13,7 +13,6 @@ defmodule Screens.Application do Screens.Telemetry, {Screens.Cache.Owner, engine_module: Screens.Config.Cache.Engine}, {Screens.Cache.Owner, engine_module: Screens.SignsUiConfig.Cache.Engine}, - {Screens.Cache.Owner, engine_module: Screens.TriptychPlayer.Cache.Engine}, :hackney_pool.child_spec(:ex_aws_pool, []), :hackney_pool.child_spec(:blue_bikes_pool, []), :hackney_pool.child_spec(:api_v3_pool, max_connections: 100), @@ -27,8 +26,6 @@ defmodule Screens.Application do {Task.Supervisor, name: Screens.ScreensByAlert.SelfRefreshRunner.TaskSupervisor}, # ScreensByAlert self-refresh job runner {Screens.ScreensByAlert.SelfRefreshRunner, name: Screens.ScreensByAlert.SelfRefreshRunner}, - Screens.OlCrowding.DynamicSupervisor, - {Screens.OlCrowding.Agent, %{}}, # Task supervisor for parallel running of candidate generator variants {Task.Supervisor, name: Screens.V2.ScreenData.ParallelRunSupervisor}, {Screens.ScreenApiResponseCache, []}, diff --git a/lib/screens/log_screen_data.ex b/lib/screens/log_screen_data.ex index af791a762..b32418b7c 100644 --- a/lib/screens/log_screen_data.ex +++ b/lib/screens/log_screen_data.ex @@ -25,8 +25,6 @@ defmodule Screens.LogScreenData do if is_screen or not is_nil(requestor) do screen_side = params["screen_side"] rotation_index = params["rotation_index"] - triptych_pane = params["pane"] - triptych_player_name = params["player_name"] ofm_app_package_version = params["version"] data = @@ -38,8 +36,6 @@ defmodule Screens.LogScreenData do |> insert_screen_side(screen_side) |> insert_requestor(requestor) |> insert_dup_rotation_index(rotation_index) - |> insert_triptych_pane(triptych_pane) - |> insert_triptych_player_name(triptych_player_name) |> insert_version(ofm_app_package_version) log_message("[screen data request]", data) @@ -67,10 +63,6 @@ defmodule Screens.LogScreenData do log_message("[screen frontend error]", data) end - def log_unrecognized_triptych_player(player_name) do - log_message("[unrecognized triptych player name]", %{player_name: player_name}) - end - def log_api_response(response, screen_id, last_refresh, is_screen, screen_side \\ nil) def log_api_response( @@ -157,16 +149,6 @@ defmodule Screens.LogScreenData do defp insert_dup_rotation_index(data, rotation_index), do: Map.put(data, :page_number, rotation_index) - defp insert_triptych_pane(data, nil), do: data - - defp insert_triptych_pane(data, triptych_pane), - do: Map.put(data, :triptych_pane, triptych_pane) - - defp insert_triptych_player_name(data, nil), do: data - - defp insert_triptych_player_name(data, triptych_player_name), - do: Map.put(data, :triptych_player_name, triptych_player_name) - defp insert_version(data, nil), do: data defp insert_version(data, version), do: Map.put(data, :ofm_app_package_version, version) end diff --git a/lib/screens/ol_crowding/agent.ex b/lib/screens/ol_crowding/agent.ex deleted file mode 100644 index 89f49a00f..000000000 --- a/lib/screens/ol_crowding/agent.ex +++ /dev/null @@ -1,23 +0,0 @@ -defmodule Screens.OlCrowding.Agent do - @moduledoc false - use Agent - - def start_link(initial_value) do - Agent.start_link(fn -> initial_value end, name: __MODULE__) - end - - def get(station_id, direction_id) do - Agent.get(__MODULE__, &Map.get(&1, "#{station_id}.#{direction_id}")) - end - - def delete(station_id, direction_id) do - Agent.update(__MODULE__, &Map.delete(&1, "#{station_id}.#{direction_id}")) - end - - def put(station_id, direction_id, previous_station_stopped_prediction) do - Agent.update( - __MODULE__, - &Map.put(&1, "#{station_id}.#{direction_id}", previous_station_stopped_prediction) - ) - end -end diff --git a/lib/screens/ol_crowding/dynamic_supervisor.ex b/lib/screens/ol_crowding/dynamic_supervisor.ex deleted file mode 100644 index dbd64fb3a..000000000 --- a/lib/screens/ol_crowding/dynamic_supervisor.ex +++ /dev/null @@ -1,49 +0,0 @@ -defmodule Screens.OlCrowding.DynamicSupervisor do - @moduledoc false - - require Logger - - use DynamicSupervisor - alias Screens.OlCrowding.LogCrowdingInfo - - def start_link(init_arg) do - DynamicSupervisor.start_link(__MODULE__, init_arg, name: __MODULE__) - end - - @impl true - def init(_init_arg) do - DynamicSupervisor.init(strategy: :one_for_one) - end - - def start_logger( - original_crowding_levels, - %{ - next_train_prediction: prediction, - logging_options: logging_options, - train_crowding_config: train_crowding_config, - fetch_predictions_fn: fetch_predictions_fn, - fetch_parent_stop_id_fn: fetch_parent_stop_id_fn, - fetch_params: fetch_params - } - ) do - spec = %{ - id: LogCrowdingInfo, - start: - {LogCrowdingInfo, :start_link, - [ - %{ - original_crowding_levels: original_crowding_levels, - prediction: prediction, - logging_options: logging_options, - train_crowding_config: train_crowding_config, - fetch_predictions_fn: fetch_predictions_fn, - fetch_parent_stop_id_fn: fetch_parent_stop_id_fn, - fetch_params: fetch_params - } - ]}, - restart: :transient - } - - DynamicSupervisor.start_child(__MODULE__, spec) - end -end diff --git a/lib/screens/ol_crowding/logger.ex b/lib/screens/ol_crowding/logger.ex deleted file mode 100644 index f883702df..000000000 --- a/lib/screens/ol_crowding/logger.ex +++ /dev/null @@ -1,81 +0,0 @@ -defmodule Screens.OlCrowding.LogCrowdingInfo do - @moduledoc false - - require Logger - use GenServer - - alias Screens.Predictions.Prediction - alias Screens.Util - - def start_link(opts) do - GenServer.start_link(__MODULE__, opts) - end - - @impl true - def init(state) do - # Widget only shows for a maximum of 15 seconds. Go ahead and schedule the exit. - Process.send_after(self(), :shutdown, 15_000) - - schedule_run() - - {:ok, state} - end - - @impl true - def handle_info( - :run, - %{ - original_crowding_levels: original_crowding_levels, - prediction: prediction, - logging_options: %{ - is_real_screen: true, - screen_id: screen_id, - triptych_pane: triptych_pane - }, - train_crowding_config: train_crowding_config, - fetch_predictions_fn: fetch_predictions_fn, - fetch_parent_stop_id_fn: fetch_parent_stop_id_fn, - fetch_params: fetch_params - } = state - ) do - schedule_run() - - {:ok, predictions} = fetch_predictions_fn.(fetch_params) - next_train_prediction = List.first(predictions) - - crowding_levels = - Enum.map_join( - prediction.vehicle.carriages, - ",", - &Util.translate_carriage_occupancy_status/1 - ) - - cond do - # A car's crowding level changed. Log it and shutdown the process. - original_crowding_levels != crowding_levels -> - Logger.info( - "[train_crowding car_crowding_class_change] screen_id=#{screen_id} triptych_pane=#{triptych_pane} trip_id=#{prediction.trip.id} original_crowding_levels=#{original_crowding_levels} car_crowding_levels=#{crowding_levels}" - ) - - {:stop, :shutdown, state} - - # The train is now stopped at the current station and no crowding level changed. Shut down the process without logging. - Prediction.vehicle_status(next_train_prediction) == :stopped_at and - next_train_prediction |> Prediction.stop_for_vehicle() |> fetch_parent_stop_id_fn.() == - train_crowding_config.station_id -> - {:stop, :shutdown, state} - - # Still more work to do. - true -> - {:noreply, state} - end - end - - def handle_info(:shutdown, state) do - {:stop, :shutdown, state} - end - - defp schedule_run do - Process.send_after(self(), :run, 2000) - end -end diff --git a/lib/screens/screens_by_alert/self_refresh_runner.ex b/lib/screens/screens_by_alert/self_refresh_runner.ex index 9b8031d8f..63db62fd8 100644 --- a/lib/screens/screens_by_alert/self_refresh_runner.ex +++ b/lib/screens/screens_by_alert/self_refresh_runner.ex @@ -91,13 +91,11 @@ defmodule Screens.ScreensByAlert.SelfRefreshRunner do # A screen is valid for self-refresh if all of these are true: # - It's a v2 screen (i.e., it shows widgets) # - It's not hidden from Screenplay - # - It's a screen type that can show alerts in some capacity defp valid_for_self_refresh?(screen_config) do is_v2 = Screen.v2_screen?(screen_config) is_visible_to_screenplay = not screen_config.hidden_from_screenplay - shows_alerts = Screen.shows_alerts?(screen_config) - is_v2 and is_visible_to_screenplay and shows_alerts + is_v2 and is_visible_to_screenplay end defp schedule_run do diff --git a/lib/screens/stops/stop.ex b/lib/screens/stops/stop.ex index e8d258d43..55cd9e7bf 100644 --- a/lib/screens/stops/stop.ex +++ b/lib/screens/stops/stop.ex @@ -17,7 +17,7 @@ defmodule Screens.Stops.Stop do alias Screens.Stops alias Screens.Util alias Screens.V3Api - alias ScreensConfig.V2.{BusEink, BusShelter, Dup, GlEink, PreFare, Triptych} + alias ScreensConfig.V2.{BusEink, BusShelter, Dup, GlEink, PreFare} defstruct id: nil, name: nil, @@ -33,7 +33,7 @@ defmodule Screens.Stops.Stop do platform_name: String.t() | nil } - @type screen_type :: BusEink | BusShelter | GlEink | PreFare | Dup | Triptych + @type screen_type :: BusEink | BusShelter | GlEink | PreFare | Dup @blue_line_stops [ {"place-wondl", {"Wonderland", "Wonderland"}}, @@ -447,7 +447,6 @@ defmodule Screens.Stops.Stop do # Ashmont should not show Mattapan alerts for PreFare or Dup def get_route_type_filter(app, "place-asmnl") when app in [PreFare, Dup], do: [:subway] def get_route_type_filter(PreFare, _), do: [:light_rail, :subway] - def get_route_type_filter(Triptych, _), do: [:light_rail, :subway] # WTC is a special bus-only case def get_route_type_filter(Dup, "place-wtcst"), do: [:bus] def get_route_type_filter(Dup, _), do: [:light_rail, :subway] @@ -483,14 +482,12 @@ defmodule Screens.Stops.Stop do RoutePattern.fetch_tagged_stop_sequences_through_stop(stop_id) end - defp fetch_tagged_stop_sequences_by_app(app, stop_id, routes_at_stop) - when app in [Dup, Triptych] do + defp fetch_tagged_stop_sequences_by_app(Dup, stop_id, routes_at_stop) do route_ids = Route.route_ids(routes_at_stop) RoutePattern.fetch_tagged_parent_station_sequences_through_stop(stop_id, route_ids) end - defp fetch_tagged_stop_sequences_by_app(app, stop_id, routes_at_stop) - when app == PreFare do + defp fetch_tagged_stop_sequences_by_app(PreFare, stop_id, routes_at_stop) do route_ids = Route.route_ids(routes_at_stop) # We limit results to canonical route patterns only--no stop sequences for nonstandard patterns. diff --git a/lib/screens/triptych_player.ex b/lib/screens/triptych_player.ex deleted file mode 100644 index e859888cc..000000000 --- a/lib/screens/triptych_player.ex +++ /dev/null @@ -1,20 +0,0 @@ -defmodule Screens.TriptychPlayer do - @moduledoc """ - Provides access to a mapping from triptych player name - (a unique ID for an individual pane of a triptych trio, provided by OFM) - to screen ID - (our ID for the collective triptych screen comprising 3 panes). - - The mapping is cached in an ETS table controlled by a GenServer - which checks for updates to the source JSON file every 15 seconds. - """ - - alias Screens.TriptychPlayer.Cache - alias Screens.TriptychPlayer.Validator - - defdelegate fetch_screen_id_for_player(player_name), to: Cache - - defdelegate fetch_player_names_for_screen_id(player_name), to: Cache - - defdelegate validate(mapping), to: Validator -end diff --git a/lib/screens/triptych_player/cache.ex b/lib/screens/triptych_player/cache.ex deleted file mode 100644 index e86c41495..000000000 --- a/lib/screens/triptych_player/cache.ex +++ /dev/null @@ -1,38 +0,0 @@ -defmodule Screens.TriptychPlayer.Cache do - @moduledoc """ - Functions to read data from a cached copy of the triptych player config. - """ - - use Screens.Cache.Client, table: :triptych_player - - @type table_contents :: list(table_entry) - - @type table_entry :: {player_name :: String.t(), screen_id :: String.t()} - - def fetch_screen_id_for_player(player_name) do - with_table default: :error do - case :ets.match(@table, {player_name, :"$1"}) do - [[screen_id]] -> {:ok, screen_id} - [] -> :error - end - end - end - - def fetch_player_names_for_screen_id(screen_id) do - with_table default: :error do - player_names = - @table - # [[name1], [name2], [name3]] - |> :ets.match({:"$1", screen_id}) - # [name1, name2, name3] - |> List.flatten() - # (Just in case) - |> Enum.uniq() - - case player_names do - [] -> :error - l -> {:ok, l} - end - end - end -end diff --git a/lib/screens/triptych_player/cache/engine.ex b/lib/screens/triptych_player/cache/engine.ex deleted file mode 100644 index 1f8725039..000000000 --- a/lib/screens/triptych_player/cache/engine.ex +++ /dev/null @@ -1,31 +0,0 @@ -defmodule Screens.TriptychPlayer.Cache.Engine do - @moduledoc """ - Engine for the triptych player config cache. - """ - - alias Screens.TriptychPlayer.Fetch - - @behaviour Screens.Cache.Engine - - @impl true - def name, do: Screens.TriptychPlayer.Cache.table() - - @impl true - def update_table(current_version) do - with {:ok, body, new_version} <- Fetch.fetch_config(current_version), - {:ok, deserialized} <- Jason.decode(body) do - table_entries = Map.to_list(deserialized) - - {:replace, table_entries, new_version} - else - :unchanged -> :unchanged - _ -> :error - end - end - - @impl true - def update_interval_ms, do: 15_000 - - @impl true - def update_failure_error_log_threshold_minutes, do: 0 -end diff --git a/lib/screens/triptych_player/fetch.ex b/lib/screens/triptych_player/fetch.ex deleted file mode 100644 index 409d603ee..000000000 --- a/lib/screens/triptych_player/fetch.ex +++ /dev/null @@ -1,21 +0,0 @@ -defmodule Screens.TriptychPlayer.Fetch do - @moduledoc """ - Defines a behaviour for, and delegates to, a module that provides access to - the triptych player config file. - """ - - alias Screens.Cache.Engine - - @callback fetch_config(Engine.table_version()) :: - {:ok, String.t(), Engine.table_version()} | :unchanged | :error - - @callback put_config(String.t()) :: :ok | :error - - alias Screens.Cache.Engine - - @config_fetcher Application.compile_env(:screens, :triptych_player_fetcher) - - defdelegate fetch_config(config_version), to: @config_fetcher - defdelegate fetch_config(), to: @config_fetcher - defdelegate put_config(file_contents), to: @config_fetcher -end diff --git a/lib/screens/triptych_player/fetch/local.ex b/lib/screens/triptych_player/fetch/local.ex deleted file mode 100644 index 1684c9601..000000000 --- a/lib/screens/triptych_player/fetch/local.ex +++ /dev/null @@ -1,49 +0,0 @@ -defmodule Screens.TriptychPlayer.Fetch.Local do - @moduledoc """ - Functions to work with a local copy of the triptych player config. - """ - - @behaviour Screens.TriptychPlayer.Fetch - - @impl true - def fetch_config(current_version \\ nil) do - path = local_config_path() - - with {:ok, last_modified} <- get_last_modified(path) do - if last_modified == current_version do - :unchanged - else - do_fetch(path, last_modified) - end - end - end - - @impl true - def put_config(file_contents) do - case File.write(local_config_path(), file_contents) do - :ok -> :ok - {:error, _} -> :error - end - end - - defp local_config_path do - case Application.get_env(:screens, :local_triptych_player_file_spec) do - {:priv, file_name} -> Path.join(:code.priv_dir(:screens), file_name) - {:test, file_name} -> Path.join(~w[#{File.cwd!()} test fixtures #{file_name}]) - end - end - - defp do_fetch(path, last_modified) do - case File.read(path) do - {:ok, contents} -> {:ok, contents, last_modified} - _ -> :error - end - end - - defp get_last_modified(path) do - case File.stat(path) do - {:ok, %File.Stat{mtime: mtime}} -> {:ok, mtime} - {:error, _} -> :error - end - end -end diff --git a/lib/screens/triptych_player/fetch/s3.ex b/lib/screens/triptych_player/fetch/s3.ex deleted file mode 100644 index 5849b2db0..000000000 --- a/lib/screens/triptych_player/fetch/s3.ex +++ /dev/null @@ -1,57 +0,0 @@ -defmodule Screens.TriptychPlayer.Fetch.S3 do - @moduledoc """ - Functions to work with an S3-hosted copy of the triptych player config. - """ - - require Logger - - @behaviour Screens.TriptychPlayer.Fetch - - @impl true - def fetch_config(current_version \\ nil) do - bucket = Application.get_env(:screens, :triptych_player_s3_bucket) - path = config_path_for_environment() - - opts = - case current_version do - nil -> [] - _ -> [if_none_match: current_version] - end - - get_operation = ExAws.S3.get_object(bucket, path, opts) - - case ExAws.request(get_operation) do - {:ok, %{status_code: 304}} -> - :unchanged - - {:ok, %{body: body, headers: headers, status_code: 200}} -> - etag = - headers - |> Enum.into(%{}) - |> Map.get("ETag") - - {:ok, body, etag} - - {:error, err} -> - _ = Logger.info("s3_triptych_player_config_fetch_error #{inspect(err)}") - :error - end - end - - @impl true - def put_config(file_contents) do - bucket = Application.get_env(:screens, :triptych_player_s3_bucket) - path = config_path_for_environment() - put_operation = ExAws.S3.put_object(bucket, path, file_contents) - - case ExAws.request(put_operation) do - {:ok, %{status_code: 200}} -> :ok - _ -> :error - end - end - - defp config_path_for_environment do - "screens-" <> env = Application.get_env(:screens, :environment_name, "screens-prod") - "screens/triptych-player-#{env}.json" - end -end diff --git a/lib/screens/triptych_player/validator.ex b/lib/screens/triptych_player/validator.ex deleted file mode 100644 index 82b148b30..000000000 --- a/lib/screens/triptych_player/validator.ex +++ /dev/null @@ -1,54 +0,0 @@ -defmodule Screens.TriptychPlayer.Validator do - @moduledoc false - - @doc """ - Determines whether a term is a valid player name -> screen ID mapping. - """ - @spec validate(term()) :: :ok | {:error, reason :: String.t()} - def validate(mapping) do - with :ok <- validate_map(mapping), - :ok <- validate_string_keys(mapping) do - validate_screen_id_values(mapping) - end - end - - defp validate_map(mapping) when is_map(mapping), do: :ok - defp validate_map(_), do: {:error, "Not a map"} - - defp validate_string_keys(mapping) do - invalid_keys = - mapping - |> Map.keys() - |> Enum.reject(&is_binary/1) - - case invalid_keys do - [] -> :ok - keys -> {:error, "Mapping contains non-string keys: #{inspect(keys)}"} - end - end - - defp validate_screen_id_values(mapping) do - mapped_screen_ids = - mapping - |> Map.values() - |> MapSet.new() - - all_triptych_screen_ids = - MapSet.new( - Screens.Config.Cache.screen_ids(&match?({_screen_id, %{app_id: :triptych_v2}}, &1)) - ) - - if MapSet.subset?(mapped_screen_ids, all_triptych_screen_ids) do - :ok - else - unrecognized_ids = - mapped_screen_ids - |> MapSet.difference(all_triptych_screen_ids) - |> Enum.sort() - - {:error, - "Mapping contains unrecognized triptych screen IDs: #{inspect(unrecognized_ids)}.\n\n" <> - "Make sure all relevant screens have been configured as triptychs before linking them to triptych player names."} - end - end -end diff --git a/lib/screens/v2/candidate_generator.ex b/lib/screens/v2/candidate_generator.ex index fe5bb0eb5..e4128ec20 100644 --- a/lib/screens/v2/candidate_generator.ex +++ b/lib/screens/v2/candidate_generator.ex @@ -13,7 +13,7 @@ defmodule Screens.V2.CandidateGenerator do Fetches data and returns a list of candidate widget instances to be considered for placement on the template. """ - @callback candidate_instances(Screen.t(), keyword()) :: [WidgetInstance.t()] + @callback candidate_instances(Screen.t()) :: [WidgetInstance.t()] @doc """ Receives the finalized list of widget instances that were placed on diff --git a/lib/screens/v2/candidate_generator/bus_eink.ex b/lib/screens/v2/candidate_generator/bus_eink.ex index 9a5c1fef9..09a718510 100644 --- a/lib/screens/v2/candidate_generator/bus_eink.ex +++ b/lib/screens/v2/candidate_generator/bus_eink.ex @@ -49,7 +49,6 @@ defmodule Screens.V2.CandidateGenerator.BusEink do # credo:disable-for-next-line Credo.Check.Design.DuplicatedCode def candidate_instances( config, - _opts, now \\ DateTime.utc_now(), fetch_stop_name_fn \\ &Stop.fetch_stop_name/1, departures_instances_fn \\ &Widgets.Departures.departures_instances/2, diff --git a/lib/screens/v2/candidate_generator/bus_shelter.ex b/lib/screens/v2/candidate_generator/bus_shelter.ex index 55ae61802..4fdbcd28d 100644 --- a/lib/screens/v2/candidate_generator/bus_shelter.ex +++ b/lib/screens/v2/candidate_generator/bus_shelter.ex @@ -47,7 +47,6 @@ defmodule Screens.V2.CandidateGenerator.BusShelter do # credo:disable-for-next-line Credo.Check.Design.DuplicatedCode def candidate_instances( config, - _opts, now \\ DateTime.utc_now(), fetch_stop_name_fn \\ &Stop.fetch_stop_name/1, departures_instances_fn \\ &Widgets.Departures.departures_instances/2, diff --git a/lib/screens/v2/candidate_generator/busway.ex b/lib/screens/v2/candidate_generator/busway.ex index ffc48f399..9231d2f06 100644 --- a/lib/screens/v2/candidate_generator/busway.ex +++ b/lib/screens/v2/candidate_generator/busway.ex @@ -30,7 +30,7 @@ defmodule Screens.V2.CandidateGenerator.Busway do end @impl CandidateGenerator - def candidate_instances(config, _opts, deps \\ %Deps{}) do + def candidate_instances(config, deps \\ %Deps{}) do now = deps.now.() [ diff --git a/lib/screens/v2/candidate_generator/dup.ex b/lib/screens/v2/candidate_generator/dup.ex index 9bba80765..2e3d8bb7b 100644 --- a/lib/screens/v2/candidate_generator/dup.ex +++ b/lib/screens/v2/candidate_generator/dup.ex @@ -76,7 +76,6 @@ defmodule Screens.V2.CandidateGenerator.Dup do @impl CandidateGenerator def candidate_instances( config, - _opts, now \\ DateTime.utc_now(), fetch_stop_name_fn \\ &Stop.fetch_stop_name/1, evergreen_content_instances_fn \\ &Widgets.Evergreen.evergreen_content_instances/1, diff --git a/lib/screens/v2/candidate_generator/dup_new.ex b/lib/screens/v2/candidate_generator/dup_new.ex index b603e7857..a2cc9d898 100644 --- a/lib/screens/v2/candidate_generator/dup_new.ex +++ b/lib/screens/v2/candidate_generator/dup_new.ex @@ -11,7 +11,7 @@ defmodule Screens.V2.CandidateGenerator.DupNew do defdelegate screen_template(), to: DupBase @impl CandidateGenerator - def candidate_instances(_config, _opts) do + def candidate_instances(_config) do List.duplicate( %Placeholder{ color: :gray, diff --git a/lib/screens/v2/candidate_generator/gl_eink.ex b/lib/screens/v2/candidate_generator/gl_eink.ex index b81beead3..4bdeffc0f 100644 --- a/lib/screens/v2/candidate_generator/gl_eink.ex +++ b/lib/screens/v2/candidate_generator/gl_eink.ex @@ -78,7 +78,6 @@ defmodule Screens.V2.CandidateGenerator.GlEink do @impl CandidateGenerator def candidate_instances( config, - _opts, now \\ DateTime.utc_now(), fetch_destination_fn \\ &fetch_destination/2, departures_instances_fn \\ &Widgets.Departures.departures_instances/3, diff --git a/lib/screens/v2/candidate_generator/pre_fare.ex b/lib/screens/v2/candidate_generator/pre_fare.ex index 0e89b9eea..f3a715f19 100644 --- a/lib/screens/v2/candidate_generator/pre_fare.ex +++ b/lib/screens/v2/candidate_generator/pre_fare.ex @@ -64,7 +64,6 @@ defmodule Screens.V2.CandidateGenerator.PreFare do # credo:disable-for-next-line def candidate_instances( config, - _opts, now \\ DateTime.utc_now(), subway_status_instance_fn \\ &Widgets.SubwayStatus.subway_status_instances/2, reconstructed_alert_instances_fn \\ &Widgets.ReconstructedAlert.reconstructed_alert_instances/1, diff --git a/lib/screens/v2/candidate_generator/solari_large.ex b/lib/screens/v2/candidate_generator/solari_large.ex index 8b68d6907..37593bbf7 100644 --- a/lib/screens/v2/candidate_generator/solari_large.ex +++ b/lib/screens/v2/candidate_generator/solari_large.ex @@ -25,7 +25,6 @@ defmodule Screens.V2.CandidateGenerator.SolariLarge do # credo:disable-for-next-line Credo.Check.Design.DuplicatedCode def candidate_instances( config, - _opts, now \\ DateTime.utc_now(), departures_instances_fn \\ &Widgets.Departures.departures_instances/2 ) do diff --git a/lib/screens/v2/candidate_generator/triptych.ex b/lib/screens/v2/candidate_generator/triptych.ex deleted file mode 100644 index f27a9dda2..000000000 --- a/lib/screens/v2/candidate_generator/triptych.ex +++ /dev/null @@ -1,39 +0,0 @@ -defmodule Screens.V2.CandidateGenerator.Triptych do - @moduledoc false - - alias Screens.V2.CandidateGenerator - alias Screens.V2.CandidateGenerator.Widgets - alias Screens.V2.Template.Builder - - @behaviour CandidateGenerator - - @impl CandidateGenerator - def screen_template do - {:screen, - %{ - screen_normal: [:full_screen], - screen_split: [:left_pane, :middle_pane, :right_pane] - }} - |> Builder.build_template() - end - - @impl CandidateGenerator - def candidate_instances( - config, - opts, - crowding_widget_instances_fn \\ &Widgets.TrainCrowding.crowding_widget_instances/2, - evergreen_content_instances_fn \\ &Widgets.Evergreen.evergreen_content_instances/1, - local_evergreen_set_instances_fn \\ &Widgets.LocalEvergreenSet.local_evergreen_set_instances/1 - ) do - [ - fn -> crowding_widget_instances_fn.(config, opts[:logging_options]) end, - fn -> evergreen_content_instances_fn.(config) end, - fn -> local_evergreen_set_instances_fn.(config) end - ] - |> Task.async_stream(& &1.(), timeout: 20_000) - |> Enum.flat_map(fn {:ok, instances} -> instances end) - end - - @impl CandidateGenerator - def audio_only_instances(_widgets, _config), do: [] -end diff --git a/lib/screens/v2/candidate_generator/widgets/evergreen.ex b/lib/screens/v2/candidate_generator/widgets/evergreen.ex index 7c0e1c13e..bb1078ec3 100644 --- a/lib/screens/v2/candidate_generator/widgets/evergreen.ex +++ b/lib/screens/v2/candidate_generator/widgets/evergreen.ex @@ -5,13 +5,13 @@ defmodule Screens.V2.CandidateGenerator.Widgets.Evergreen do alias Screens.V2.WidgetInstance.EvergreenContent alias ScreensConfig.Screen alias ScreensConfig.V2.EvergreenContentItem - alias ScreensConfig.V2.{BusEink, BusShelter, Dup, GlEink, PreFare, Triptych} + alias ScreensConfig.V2.{BusEink, BusShelter, Dup, GlEink, PreFare} def evergreen_content_instances( %Screen{app_params: %app{evergreen_content: evergreen_content}} = config, now \\ DateTime.utc_now() ) - when app in [BusEink, BusShelter, Dup, GlEink, PreFare, Triptych] do + when app in [BusEink, BusShelter, Dup, GlEink, PreFare] do Enum.map(evergreen_content, &evergreen_content_instance(&1, config, now)) end diff --git a/lib/screens/v2/candidate_generator/widgets/local_evergreen_set.ex b/lib/screens/v2/candidate_generator/widgets/local_evergreen_set.ex deleted file mode 100644 index cc7e213ed..000000000 --- a/lib/screens/v2/candidate_generator/widgets/local_evergreen_set.ex +++ /dev/null @@ -1,104 +0,0 @@ -defmodule Screens.V2.CandidateGenerator.Widgets.LocalEvergreenSet do - @moduledoc """ - Widget for displaying evergreen content that is stored internally. - Additionally, allows us to set a group of PSAs that appear in conjunction. - Currently used only by Triptychs, which randomizes which PSA set appears. - """ - - require Logger - - alias Screens.V2.WidgetInstance.EvergreenContent - alias ScreensConfig.Screen - alias ScreensConfig.V2.{LocalEvergreenSet, Triptych} - - def local_evergreen_set_instances( - %Screen{app_params: %app{local_evergreen_sets: local_evergreen_sets}} = config, - now \\ DateTime.utc_now() - ) - when app in [Triptych] do - # Use the current time to help seed the random number generator so that all 3 screens - # should be in sync. So we'll seed with current time rounded down to the nearest multiple of 15 seconds. - # (Known risk: it's remotely possible that the screens are panels are out-of-sync on either side of a 15-second boundary) - seed_number = - now - |> DateTime.truncate(:second) - |> DateTime.to_unix() - |> div(15) - - _ = :rand.seed(:exsss, {seed_number, seed_number, seed_number}) - - local_evergreen_sets - |> Enum.random() - |> get_set_instances(config, now) - end - - def string_to_slot_name(string) do - cond do - String.contains?(string, "left") -> :left_pane - String.contains?(string, "middle") -> :middle_pane - String.contains?(string, "right") -> :right_pane - end - end - - defp get_set_instances( - %LocalEvergreenSet{ - folder_name: folder_name, - schedule: schedule - }, - config, - now - ) do - relative_path = Path.join("triptych_psas/", folder_name) - path = Path.join("assets/static/images/", relative_path) - - case File.ls(path) do - {:ok, files} -> - build_widget_instances(files, config, relative_path, schedule, now) - - {:error, _} -> - relative_path = "triptych_psas/" - path = Path.join("assets/static/images/", relative_path) - - case File.ls(path) do - {:ok, triptych_psa_contents} -> - default_psa_folder = hd(triptych_psa_contents) - default_psa_path = Path.join(path, default_psa_folder) - - Logger.warning( - "[Triptych PSA filepath not found, using default] configured_folder_name=#{folder_name} default_folder_name=#{default_psa_folder}" - ) - - files = File.ls!(default_psa_path) - - build_widget_instances( - files, - config, - Path.join(relative_path, default_psa_folder), - schedule, - now - ) - - {:error, _} -> - Logger.warning("[Empty triptych PSA folder]") - [] - end - end - end - - defp build_widget_instances(files, config, partial_path, schedule, now) do - Enum.map(files, fn file -> - slot_name = string_to_slot_name(file) - - %EvergreenContent{ - screen: config, - slot_names: [slot_name], - asset_url: Path.join([partial_path, "/", file]), - priority: [2], - schedule: schedule, - now: now, - text_for_audio: "", - audio_priority: [0] - } - end) - end -end diff --git a/lib/screens/v2/candidate_generator/widgets/train_crowding.ex b/lib/screens/v2/candidate_generator/widgets/train_crowding.ex deleted file mode 100644 index 7223607da..000000000 --- a/lib/screens/v2/candidate_generator/widgets/train_crowding.ex +++ /dev/null @@ -1,349 +0,0 @@ -defmodule Screens.V2.CandidateGenerator.Widgets.TrainCrowding do - @moduledoc false - - require Logger - - alias Screens.Alerts.Alert - alias Screens.OlCrowding.Agent - alias Screens.Predictions.Prediction - alias Screens.Stops.Stop - alias Screens.Util - alias Screens.V2.LocalizedAlert - alias Screens.V2.WidgetInstance.TrainCrowding, as: CrowdingWidget - alias ScreensConfig.Screen - alias ScreensConfig.V2.{TrainCrowding, Triptych} - - # {parent_station_id, {sb_platform_id, nb_platform_id}} - @ol_station_to_platform_map [ - {"place-ogmnl", {"70036", "70036"}}, - {"place-mlmnl", {"70034", "70035"}}, - {"place-welln", {"70032", "70033"}}, - {"place-astao", {"70278", "70279"}}, - {"place-sull", {"70030", "70031"}}, - {"place-ccmnl", {"70028", "70029"}}, - {"place-north", {"70026", "70027"}}, - {"place-haecl", {"70024", "70025"}}, - {"place-state", {"70022", "70023"}}, - {"place-dwnxg", {"70020", "70021"}}, - {"place-chncl", {"70018", "70019"}}, - {"place-tumnl", {"70016", "70017"}}, - {"place-bbsta", {"70014", "70015"}}, - {"place-masta", {"70012", "70013"}}, - {"place-rugg", {"70010", "70011"}}, - {"place-rcmnl", {"70008", "70009"}}, - {"place-jaksn", {"70006", "70007"}}, - {"place-sbmnl", {"70004", "70005"}}, - {"place-grnst", {"70002", "70003"}}, - {"place-forhl", {"70001", "70001"}} - ] - - @spec crowding_widget_instances(Screen.t(), map()) :: list(CrowdingWidget.t()) - def crowding_widget_instances( - config, - logging_options, - now \\ DateTime.utc_now(), - fetch_predictions_fn \\ &Prediction.fetch/1, - fetch_location_context_fn \\ &Stop.fetch_location_context/3, - fetch_parent_stop_id_fn \\ &Stop.fetch_parent_stop_id/1, - fetch_alerts_fn \\ &Alert.fetch/1 - ) - - def crowding_widget_instances( - %Screen{app_params: %Triptych{train_crowding: %TrainCrowding{enabled: false}}}, - _, - _, - _, - _, - _, - _ - ) do - [] - end - - def crowding_widget_instances( - %Screen{app_params: %Triptych{train_crowding: train_crowding}} = config, - logging_options, - now, - fetch_predictions_fn, - fetch_location_context_fn, - fetch_parent_stop_id_fn, - fetch_alerts_fn - ) do - params = %{ - direction_id: train_crowding.direction_id, - route_ids: [train_crowding.route_id], - stop_ids: [train_crowding.station_id] - } - - with {:ok, predictions} <- fetch_predictions_fn.(params), - {:ok, location_context} <- - fetch_location_context_fn.(Triptych, train_crowding.station_id, now), - {:ok, alerts} <- - params |> Map.to_list() |> fetch_alerts_fn.() do - next_train_prediction = List.first(predictions) - - if next_train_prediction && logging_options && logging_options.is_real_screen do - Logger.info( - "[train_crowding next_prediction] screen_id=#{logging_options.screen_id} triptych_pane=#{logging_options.triptych_pane} next_trip_id=#{next_train_prediction.trip.id}" - ) - end - - common_params = %{ - screen_config: config, - next_train_prediction: next_train_prediction, - train_crowding_config: train_crowding, - logging_options: logging_options, - fetch_parent_stop_id_fn: fetch_parent_stop_id_fn, - fetch_predictions_fn: fetch_predictions_fn, - fetch_params: params, - now: now - } - - get_instance( - any_alert_makes_this_a_terminal?(alerts, location_context, now), - common_params - ) - else - :error -> [] - end - end - - defp get_instance( - alert_makes_this_a_terminal, - common_params - ) - when alert_makes_this_a_terminal or is_nil(common_params.next_train_prediction) or - common_params.next_train_prediction == [], - do: [] - - defp get_instance( - _alert_makes_this_a_terminal, - common_params - ) do - next_train_prediction = common_params.next_train_prediction - - # If there is an upcoming train, it's headed to this station, - # and we're not at a temporary terminal, log the widget. - if Prediction.vehicle_status(next_train_prediction) in [:in_transit_to, :incoming_at] and - next_train_prediction - |> Prediction.stop_for_vehicle() - |> common_params.fetch_parent_stop_id_fn.() == - common_params.train_crowding_config.station_id do - _ = log_crowding_info(:in_transit, common_params) - - Agent.delete( - common_params.train_crowding_config.station_id, - common_params.train_crowding_config.direction_id - ) - - [ - %CrowdingWidget{ - screen: common_params[:screen_config], - prediction: next_train_prediction, - now: common_params[:now] - } - ] - - # Test other heuristics - else - log_heuristics(common_params) - end - end - - defp log_heuristics(common_params) do - train_crowding_config = common_params.train_crowding_config - next_train_prediction = common_params.next_train_prediction - - ol_stop_sequence = - if train_crowding_config.direction_id == 0 do - @ol_station_to_platform_map - else - Enum.reverse(@ol_station_to_platform_map) - end - - previous_stop_index = - Enum.find_index( - ol_stop_sequence, - &(elem(&1, 0) == train_crowding_config.station_id) - ) - 1 - - {_, platform_id_tuple} = Enum.at(ol_stop_sequence, previous_stop_index) - - previous_platform_id = elem(platform_id_tuple, train_crowding_config.direction_id) - - cached_prediction = - Agent.get(train_crowding_config.station_id, train_crowding_config.direction_id) - - cond do - cached_prediction != nil -> - # Time-based heuristic - # We think the train is about to leave the previous station. Log the heuristic. - _ = check_time_based_heuristic(cached_prediction, common_params, -10) - - # Consecutive crowding class heuristic. - # Crowding class this fetch is the same as last. Log the heuristic. - _ = - check_consecutive_crowding_heuristic( - next_train_prediction, - previous_platform_id, - cached_prediction, - common_params - ) - - [] - - # Cache previous prediction but don't log the widget - Prediction.vehicle_status(next_train_prediction) == :stopped_at and - Prediction.stop_for_vehicle(next_train_prediction) == previous_platform_id -> - previous_station_prediction_current_trip = - fetch_previous_station_prediction( - train_crowding_config, - previous_platform_id, - next_train_prediction.trip.id, - common_params.fetch_predictions_fn - ) - - if is_nil(previous_station_prediction_current_trip) do - Logger.warning( - "[log_heuristics] Failed to fetch previous station's prediction: current_platform_id: #{train_crowding_config.station_id} previous_platform_id: #{previous_platform_id} trip_id: #{next_train_prediction.trip.id}" - ) - - [] - else - # Cache the prediction for the current trip at the previous station. - Agent.put( - train_crowding_config.station_id, - train_crowding_config.direction_id, - previous_station_prediction_current_trip - ) - - [] - end - - true -> - [] - end - end - - defp fetch_previous_station_prediction( - train_crowding_config, - relevant_platform_id, - trip_id, - fetch_predictions_fn - ) do - params = %{ - direction_id: train_crowding_config.direction_id, - route_ids: [train_crowding_config.route_id], - stop_ids: [relevant_platform_id], - trip_id: trip_id - } - - {:ok, predictions} = fetch_predictions_fn.(params) - List.first(predictions) - end - - defp check_time_based_heuristic( - cached_prediction, - common_params, - previous_departure_time_cushion - ) do - # cached_prediction.departure_time minus previous_departure_time_cushion is when we expect crowding to be reliable. - # When now >= this time, log the widget. - log_widget_after_time = - DateTime.add(cached_prediction.departure_time, previous_departure_time_cushion) - - if DateTime.compare( - common_params.now, - log_widget_after_time - ) in [ - :eq, - :gt - ] do - log_crowding_info( - :time_based, - common_params - ) - end - end - - defp check_consecutive_crowding_heuristic( - next_train_prediction, - relevant_platform_id, - cached_prediction, - common_params - ) do - if next_train_prediction.vehicle.carriages == - cached_prediction.vehicle.carriages do - log_crowding_info( - :consecutive_crowding, - common_params - ) - else - # Update the cached prediction so we can check the new crowding classes next fetch. - # The departure time we use in the other heuristic should not change, and if it does it is changing to a more accurate time. - # If the prediction is nil, leave the existing one alone just in case the time heuristic can log next refresh. - previous_station_prediction_current_trip = - fetch_previous_station_prediction( - common_params.train_crowding_config, - relevant_platform_id, - next_train_prediction.trip.id, - common_params.fetch_predictions_fn - ) - - if previous_station_prediction_current_trip != nil do - Agent.put( - common_params.train_crowding_config.station_id, - common_params.train_crowding_config.direction_id, - previous_station_prediction_current_trip - ) - end - end - end - - # Given alerts at this station, check to see if any alert make this a temporary terminal - defp any_alert_makes_this_a_terminal?(alerts, location_context, now) do - Enum.any?(alerts, fn alert -> - if Alert.happening_now?(alert, now) do - temporary_terminal?(%{alert: alert, location_context: location_context}) - end - end) - end - - # credo:disable-for-next-line - # TODO: This isn't the first time we've written a temporary_terminal function, but this one - # is a little more reusable? Consider using this func in other places - defp temporary_terminal?(localized_alert) do - localized_alert.alert.effect in [:suspension, :shuttle] and - LocalizedAlert.location(localized_alert) in [:boundary_downstream, :boundary_upstream] - end - - defp log_crowding_info( - scenario, - %{ - next_train_prediction: prediction, - train_crowding_config: train_crowding_config, - logging_options: %{ - is_real_screen: true, - screen_id: screen_id, - triptych_pane: triptych_pane - } - } = common_params - ) do - Agent.delete(train_crowding_config.station_id, train_crowding_config.direction_id) - - crowding_levels = - Enum.map_join( - prediction.vehicle.carriages, - ",", - &Util.translate_carriage_occupancy_status/1 - ) - - Logger.info( - "[train_crowding car_crowding_info] screen_id=#{screen_id} triptych_pane=#{triptych_pane} trip_id=#{prediction.trip.id} car_crowding_levels=#{crowding_levels} scenario=#{scenario}" - ) - - Screens.OlCrowding.DynamicSupervisor.start_logger(crowding_levels, common_params) - end - - defp log_crowding_info(_, _), do: :ok -end diff --git a/lib/screens/v2/screen_data.ex b/lib/screens/v2/screen_data.ex index 5f754a95d..68263b8c1 100644 --- a/lib/screens/v2/screen_data.ex +++ b/lib/screens/v2/screen_data.ex @@ -26,7 +26,6 @@ defmodule Screens.V2.ScreenData do @type variants(data) :: {data, %{String.t() => data}} @type screen_id :: String.t() @type options :: [ - logging_options: %{atom() => term()}, generator_variant: String.t(), pending_config: Screen.t(), run_all_variants?: boolean(), @@ -69,13 +68,13 @@ defmodule Screens.V2.ScreenData do Enum.each(other_variants, fn variant -> {:ok, _pid} = Task.Supervisor.start_child(ParallelRunSupervisor, fn -> - config |> Layout.generate(variant, opts) |> then_fn.(config) + config |> Layout.generate(variant) |> then_fn.(config) end) end) end config - |> Layout.generate(selected_variant, opts) + |> Layout.generate(selected_variant) |> tap(&update_visible_alerts(&1, screen_id, config, opts)) |> then_fn.(config) end @@ -90,7 +89,7 @@ defmodule Screens.V2.ScreenData do |> Task.Supervisor.async_stream( [nil | @parameters.get_variants(config)], fn variant -> - {variant, config |> Layout.generate(variant, opts) |> then_fn.(config)} + {variant, config |> Layout.generate(variant) |> then_fn.(config)} end ) |> Enum.map(fn {:ok, result} -> result end) diff --git a/lib/screens/v2/screen_data/layout.ex b/lib/screens/v2/screen_data/layout.ex index e5697b630..c09b0cc5e 100644 --- a/lib/screens/v2/screen_data/layout.ex +++ b/lib/screens/v2/screen_data/layout.ex @@ -32,13 +32,12 @@ defmodule Screens.V2.ScreenData.Layout do @spec generate(Screen.t()) :: t() @spec generate(Screen.t(), String.t() | nil) :: t() - @spec generate(Screen.t(), String.t() | nil, keyword()) :: t() - def generate(config, variant \\ nil, candidate_generator_opts \\ []) do + def generate(config, variant \\ nil) do candidate_generator = @parameters.get_candidate_generator(config, variant) screen_template = candidate_generator.screen_template() config - |> candidate_generator.candidate_instances(candidate_generator_opts) + |> candidate_generator.candidate_instances() |> Enum.filter(&WidgetInstance.valid_candidate?/1) |> pick_instances(screen_template) end diff --git a/lib/screens/v2/screen_data/parameters.ex b/lib/screens/v2/screen_data/parameters.ex index 1cbc2f55c..4f28705a0 100644 --- a/lib/screens/v2/screen_data/parameters.ex +++ b/lib/screens/v2/screen_data/parameters.ex @@ -13,8 +13,7 @@ defmodule Screens.V2.ScreenData.Parameters do dup_v2: { CandidateGenerator.Dup, %{"new_departures" => CandidateGenerator.DupNew} - }, - triptych_v2: CandidateGenerator.Triptych + } } @app_id_to_refresh_rate %{ @@ -24,8 +23,7 @@ defmodule Screens.V2.ScreenData.Parameters do busway_v2: 15, solari_large_v2: 15, pre_fare_v2: 20, - dup_v2: 30, - triptych_v2: 30 + dup_v2: 30 } @app_id_to_audio_readout_interval %{ @@ -35,8 +33,7 @@ defmodule Screens.V2.ScreenData.Parameters do busway_v2: 0, solari_large_v2: 0, pre_fare_v2: 0, - dup_v2: 0, - triptych_v2: 0 + dup_v2: 0 } @callback get_candidate_generator(ScreensConfig.Screen.t()) :: module() diff --git a/lib/screens/v2/widget_instance/evergreen_content.ex b/lib/screens/v2/widget_instance/evergreen_content.ex index 788510fc5..c4e84e186 100644 --- a/lib/screens/v2/widget_instance/evergreen_content.ex +++ b/lib/screens/v2/widget_instance/evergreen_content.ex @@ -4,7 +4,7 @@ defmodule Screens.V2.WidgetInstance.EvergreenContent do alias Screens.Util alias Screens.V2.WidgetInstance alias ScreensConfig.Screen - alias ScreensConfig.V2.{RecurrentSchedule, Schedule, Triptych} + alias ScreensConfig.V2.{RecurrentSchedule, Schedule} @enforce_keys ~w[screen slot_names asset_url priority now]a defstruct screen: nil, @@ -14,8 +14,7 @@ defmodule Screens.V2.WidgetInstance.EvergreenContent do schedule: [%Schedule{}], now: nil, text_for_audio: nil, - audio_priority: nil, - show_identifiers: false + audio_priority: nil @type t :: %__MODULE__{ screen: Screen.t(), @@ -25,18 +24,11 @@ defmodule Screens.V2.WidgetInstance.EvergreenContent do schedule: list(Schedule.t()) | RecurrentSchedule.t(), now: DateTime.t(), text_for_audio: String.t(), - audio_priority: WidgetInstance.priority(), - show_identifiers: boolean() + audio_priority: WidgetInstance.priority() } def priority(%__MODULE__{} = instance), do: instance.priority - def serialize(%__MODULE__{ - screen: %Screen{app_params: %Triptych{show_identifiers: show_identifiers}}, - asset_url: asset_url - }), - do: %{asset_url: asset_url, show_identifiers: show_identifiers} - def serialize(%__MODULE__{asset_url: asset_url}), do: %{asset_url: asset_url} def slot_names(%__MODULE__{slot_names: slot_names}), do: slot_names diff --git a/lib/screens/v2/widget_instance/train_crowding.ex b/lib/screens/v2/widget_instance/train_crowding.ex deleted file mode 100644 index 7cb74e766..000000000 --- a/lib/screens/v2/widget_instance/train_crowding.ex +++ /dev/null @@ -1,96 +0,0 @@ -defmodule Screens.V2.WidgetInstance.TrainCrowding do - @moduledoc """ - A widget that displays the crowding on a train that is en route to the current station. - """ - - alias Screens.Predictions.Prediction - alias Screens.Util - alias ScreensConfig.Screen - alias ScreensConfig.V2.Triptych - - defstruct screen: nil, - prediction: nil, - now: nil - - @type t :: %__MODULE__{ - screen: Screen.t(), - prediction: Prediction.t(), - now: DateTime.t() - } - - @type widget_data :: %{ - destination: String.t(), - crowding: list(crowding_level), - # Describes where the "you are here" arrow should be positioned. - # 1: leftmost, 25: rightmost - platform_position: 1..25, - front_car_direction: :left | :right, - now: String.t(), - show_identifiers: boolean() - } - - @type crowding_level :: :no_data | :not_crowded | :some_crowding | :crowded | :closed - - @spec serialize(t()) :: widget_data() - def serialize(%__MODULE__{ - screen: %Screen{ - app_params: %Triptych{ - train_crowding: train_crowding, - show_identifiers: show_identifiers - } - }, - prediction: prediction, - now: now - }) do - %{ - destination: prediction.trip.headsign, - crowding: serialize_carriages(prediction.vehicle.carriages), - platform_position: train_crowding.platform_position, - front_car_direction: train_crowding.front_car_direction, - now: serialize_time(now), - show_identifiers: show_identifiers - } - end - - defp serialize_time(%DateTime{} = time) do - DateTime.to_iso8601(time) - end - - defp serialize_carriages(nil), do: nil - - defp serialize_carriages(carriages), - do: - Enum.map( - carriages, - &Util.translate_carriage_occupancy_status/1 - ) - - def priority(_instance), do: [1] - - def slot_names(_instance), do: [:full_screen] - - def widget_type(_instance), do: :train_crowding - - def valid_candidate?(_instance), do: true - - ### Required audio callbacks. The widget does not have audio equivalence, so these are "stubbed". - def audio_serialize(_t), do: %{} - def audio_sort_key(_t), do: [0] - def audio_valid_candidate?(_t), do: false - def audio_view(_t), do: nil - - defimpl Screens.V2.WidgetInstance do - alias Screens.V2.WidgetInstance.TrainCrowding - - def priority(instance), do: TrainCrowding.priority(instance) - def serialize(instance), do: TrainCrowding.serialize(instance) - def slot_names(instance), do: TrainCrowding.slot_names(instance) - def widget_type(instance), do: TrainCrowding.widget_type(instance) - def valid_candidate?(instance), do: TrainCrowding.valid_candidate?(instance) - - def audio_serialize(instance), do: TrainCrowding.audio_serialize(instance) - def audio_sort_key(instance), do: TrainCrowding.audio_sort_key(instance) - def audio_valid_candidate?(instance), do: TrainCrowding.audio_valid_candidate?(instance) - def audio_view(instance), do: TrainCrowding.audio_view(instance) - end -end diff --git a/lib/screens_web/controllers/admin_api_controller.ex b/lib/screens_web/controllers/admin_api_controller.ex index 235313092..2daf3e74c 100644 --- a/lib/screens_web/controllers/admin_api_controller.ex +++ b/lib/screens_web/controllers/admin_api_controller.ex @@ -4,8 +4,6 @@ defmodule ScreensWeb.AdminApiController do alias Screens.Config.Cache, as: ConfigCache alias Screens.Config.Fetch, as: ConfigFetch alias Screens.Image - alias Screens.TriptychPlayer - alias Screens.TriptychPlayer.Fetch, as: TriptychPlayerFetch alias ScreensConfig.{Config, Devops, Screen} plug :accepts, ["multipart/form-data"] when action == :upload_image @@ -61,36 +59,6 @@ defmodule ScreensWeb.AdminApiController do json(conn, %{success: success}) end - def index_triptych_players(conn, _params) do - {:ok, mapping, _version} = TriptychPlayerFetch.fetch_config() - json(conn, %{config: mapping}) - end - - def validate_triptych_players(conn, %{"config" => config}) do - with {:ok, mapping} <- Jason.decode(config), - :ok <- TriptychPlayer.validate(mapping) do - json(conn, %{success: true, config: mapping}) - else - {:error, message} when is_binary(message) -> - json(conn, %{success: false, message: message}) - - {:error, jason_exception} when is_exception(jason_exception) -> - json(conn, %{success: false, message: Exception.message(jason_exception)}) - end - end - - def confirm_triptych_players(conn, %{"config" => config}) do - pretty_json = config |> Jason.decode!() |> Jason.encode!(pretty: true) - - success = - case TriptychPlayerFetch.put_config(pretty_json) do - :ok -> true - :error -> false - end - - json(conn, %{success: success}) - end - def devops(conn, %{"disabled_modes" => _disabled_modes} = json) do current_screens_config = ConfigCache.screens() new_devops_config = Devops.from_json(json) diff --git a/lib/screens_web/controllers/v2/screen_api_controller.ex b/lib/screens_web/controllers/v2/screen_api_controller.ex index b720a63cd..b63b523c8 100644 --- a/lib/screens_web/controllers/v2/screen_api_controller.ex +++ b/lib/screens_web/controllers/v2/screen_api_controller.ex @@ -14,7 +14,7 @@ defmodule ScreensWeb.V2.ScreenApiController do plug(:check_config) - plug Corsica, [origins: "*"] when action in [:show_dup, :show_triptych, :log_frontend_error] + plug Corsica, [origins: "*"] when action in [:show_dup, :log_frontend_error] defp check_config(conn, _) do if Cache.ok?() do @@ -29,7 +29,6 @@ defmodule ScreensWeb.V2.ScreenApiController do def show(conn, %{"id" => screen_id, "last_refresh" => last_refresh} = params) do is_screen = ScreensWeb.UserAgent.screen_conn?(conn, screen_id) screen_side = params["screen_side"] - triptych_pane = params["pane"] variant = params["variant"] screen = Cache.screen(screen_id) @@ -85,15 +84,7 @@ defmodule ScreensWeb.V2.ScreenApiController do response = screen_id - |> screen_response(variant, - run_all_variants?: true, - update_visible_alerts?: true, - logging_options: %{ - is_real_screen: is_screen, - screen_id: screen_id, - triptych_pane: triptych_pane - } - ) + |> screen_response(variant, run_all_variants?: true, update_visible_alerts?: true) |> put_extra_fields(screen_id, screen) json(conn, response) @@ -135,21 +126,6 @@ defmodule ScreensWeb.V2.ScreenApiController do def show_dup(conn, params), do: show(conn, params) - def show_triptych(conn, %{"player_name" => player_name} = params) do - case Screens.TriptychPlayer.fetch_screen_id_for_player(player_name) do - {:ok, screen_id} -> - show(conn, Map.put(params, "id", screen_id)) - - :error -> - LogScreenData.log_unrecognized_triptych_player(player_name) - - # Reuse the logic + logging in show/2 for nonexistent IDs. - # This will log a data request for the nonexistent player name and - # return a 404 response. - show(conn, Map.put(params, "id", "triptych_player_name--#{player_name}")) - end - end - def simulation(conn, %{"id" => screen_id, "last_refresh" => last_refresh} = params) do variant = params["variant"] @@ -197,16 +173,7 @@ defmodule ScreensWeb.V2.ScreenApiController do not_found_response(conn) config -> - screen_data = - ScreenData.get( - screen_id, - pending_config: config, - logging_options: %{ - is_real_screen: false, - screen_id: screen_id, - triptych_pane: "UNKNOWN" - } - ) + screen_data = ScreenData.get(screen_id, pending_config: config) json(conn, %{@base_response | data: screen_data}) end diff --git a/lib/screens_web/controllers/v2/screen_controller.ex b/lib/screens_web/controllers/v2/screen_controller.ex index 57f467adf..a89390659 100644 --- a/lib/screens_web/controllers/v2/screen_controller.ex +++ b/lib/screens_web/controllers/v2/screen_controller.ex @@ -6,7 +6,7 @@ defmodule ScreensWeb.V2.ScreenController do alias ScreensConfig.Screen @default_app_id :bus_eink - @recognized_app_ids ~w[bus_eink_v2 bus_shelter_v2 busway_v2 dup_v2 gl_eink_v2 solari_large_v2 pre_fare_v2 triptych_v2]a + @recognized_app_ids ~w[bus_eink_v2 bus_shelter_v2 busway_v2 dup_v2 gl_eink_v2 solari_large_v2 pre_fare_v2]a @app_id_strings Enum.map(@recognized_app_ids, &Atom.to_string/1) plug(:check_config) @@ -55,15 +55,6 @@ defmodule ScreensWeb.V2.ScreenController do end end - defp triptych_pane(params) do - case params["pane"] do - "left" -> "left" - "middle" -> "middle" - "right" -> "right" - _ -> nil - end - end - def index(conn, %{"id" => app_id}) when app_id in @app_id_strings do app_id = String.to_existing_atom(app_id) @@ -145,7 +136,6 @@ defmodule ScreensWeb.V2.ScreenController do screen_side: screen_side(params), requestor: params["requestor"], rotation_index: rotation_index(params), - triptych_pane: triptych_pane(params), variant: params["variant"], is_pending: false ] diff --git a/lib/screens_web/router.ex b/lib/screens_web/router.ex index 7710c9c7e..f5eff2aed 100644 --- a/lib/screens_web/router.ex +++ b/lib/screens_web/router.ex @@ -72,9 +72,6 @@ defmodule ScreensWeb.Router do get "/image_filenames", AdminApiController, :image_filenames post "/image", AdminApiController, :upload_image delete "/image/:filename", AdminApiController, :delete_image - get "/triptych_players", AdminApiController, :index_triptych_players - post "/triptych_players/validate", AdminApiController, :validate_triptych_players - post "/triptych_players/confirm", AdminApiController, :confirm_triptych_players end scope "/screen", ScreensWeb do @@ -108,7 +105,6 @@ defmodule ScreensWeb.Router do get "/:id/simulation", ScreenApiController, :simulation get "/:id/dup", ScreenApiController, :show_dup - get "/:player_name/triptych", ScreenApiController, :show_triptych get "/pending/:id", ScreenApiController, :show_pending get "/pending/:id/simulation", ScreenApiController, :simulation_pending diff --git a/lib/screens_web/templates/v2/screen/index.html.eex b/lib/screens_web/templates/v2/screen/index.html.eex index a5eb0dbc4..9618a7f6b 100644 --- a/lib/screens_web/templates/v2/screen/index.html.eex +++ b/lib/screens_web/templates/v2/screen/index.html.eex @@ -16,9 +16,6 @@ <%= if not is_nil(@rotation_index) do %> data-rotation-index="<%= @rotation_index %>" <% end %> - <%= if not is_nil(@triptych_pane) do %> - data-triptych-pane="<%= @triptych_pane %>" - <% end %> <%= if assigns[:screenplay_fullstory_org_id] do %> data-screenplay-fullstory-org-id="<%= assigns[:screenplay_fullstory_org_id] %>" <% end %> diff --git a/mix.exs b/mix.exs index 6251959e9..dc1335c2d 100644 --- a/mix.exs +++ b/mix.exs @@ -87,7 +87,7 @@ defmodule Screens.MixProject do {:telemetry_metrics, "~> 0.4"}, {:screens_config, git: "https://github.com/mbta/screens-config-lib.git", - ref: "2c67758bca5ec61d08e4194aa19bf289cb4ec6ef"}, + ref: "594c88ae0a4e9deb43697ab5e0567f1c97f19671"}, {:nebulex, "~> 2.6"}, {:remote_ip, "~> 1.2"}, {:hackney_telemetry, "~> 0.2.0"}, diff --git a/mix.lock b/mix.lock index d714d14ba..d87cb94db 100644 --- a/mix.lock +++ b/mix.lock @@ -61,7 +61,7 @@ "ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"}, "remote_ip": {:hex, :remote_ip, "1.2.0", "fb078e12a44414f4cef5a75963c33008fe169b806572ccd17257c208a7bc760f", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "2ff91de19c48149ce19ed230a81d377186e4412552a597d6a5137373e5877cb7"}, "retry": {:hex, :retry, "0.18.0", "dc58ebe22c95aa00bc2459f9e0c5400e6005541cf8539925af0aa027dc860543", [:mix], [], "hexpm", "9483959cc7bf69c9e576d9dfb2b678b71c045d3e6f39ab7c9aa1489df4492d73"}, - "screens_config": {:git, "https://github.com/mbta/screens-config-lib.git", "2c67758bca5ec61d08e4194aa19bf289cb4ec6ef", [ref: "2c67758bca5ec61d08e4194aa19bf289cb4ec6ef"]}, + "screens_config": {:git, "https://github.com/mbta/screens-config-lib.git", "594c88ae0a4e9deb43697ab5e0567f1c97f19671", [ref: "594c88ae0a4e9deb43697ab5e0567f1c97f19671"]}, "sentry": {:hex, :sentry, "10.7.1", "33392222d80ccff99c503f972998d2858b4c1e5aca2219a34269b68dacba8e7d", [:mix], [{:hackney, "~> 1.8", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: true]}, {:nimble_options, "~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_ownership, "~> 0.3.0 or ~> 1.0", [hex: :nimble_ownership, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.6", [hex: :phoenix, repo: "hexpm", optional: true]}, {:phoenix_live_view, "~> 0.20", [hex: :phoenix_live_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.6", [hex: :plug, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "56291312397bf2b6afab6cf4f7aa1f27413b0eb2ceeb63b8aab2d7658aaea882"}, "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.7", "354c321cf377240c7b8716899e182ce4890c5938111a1296add3ec74cf1715df", [:make, :mix, :rebar3], [], "hexpm", "fe4c190e8f37401d30167c8c405eda19469f34577987c76dde613e838bbc67f8"}, "stream_data": {:hex, :stream_data, "1.1.1", "fd515ca95619cca83ba08b20f5e814aaf1e5ebff114659dc9731f966c9226246", [:mix], [], "hexpm", "45d0cd46bd06738463fd53f22b70042dbb58c384bb99ef4e7576e7bb7d3b8c8c"}, diff --git a/priv/triptych-app.html b/priv/triptych-app.html deleted file mode 100644 index bc03999bd..000000000 --- a/priv/triptych-app.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - Screens - - - - -
- - - - \ No newline at end of file diff --git a/priv/triptych_preview.png b/priv/triptych_preview.png deleted file mode 100644 index 3630154e5..000000000 Binary files a/priv/triptych_preview.png and /dev/null differ diff --git a/priv/triptych_template.json b/priv/triptych_template.json deleted file mode 100644 index fe6c0a1b3..000000000 --- a/priv/triptych_template.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "templates": [ - { - "displayName": "MBTA - TRIPTYCH APP", - "preview": "triptych_preview.png", - "indexTemplate": "triptych-app.html", - "previewOrientation": "portrait" - } - ] -} diff --git a/scripts/build_triptych_config.ts b/scripts/build_triptych_config.ts deleted file mode 100644 index c1cde44bf..000000000 --- a/scripts/build_triptych_config.ts +++ /dev/null @@ -1,292 +0,0 @@ -/** - * This script provides some type checking and "spell-checking" on triptych config entries, and lets you skip duplicating all of the common bits of JSON. - * To use, go to https://www.typescriptlang.org/play and paste this whole thing in, then hit "Run". - * You may first need to click "TS Config" and set Target to ES2019 or later. - * - * The resulting JSON will be printed to the console. It will be an object with two top-level fields: - * - `screenConfig`: the main configuration for all of the triptychs, to be merged into the contents of screens-(dev|dev-green|prod).json - * - `playerNameMapping`: the mapping from player name to screen ID. This should be dropped into triptych-player-(dev|dev-green|prod).json - * - * To change the common parts of the config objects, e.g. to make train crowding widget enabled by default or add a new PSA set, edit the body of `makeScreenConfig`. - */ - -/** - * ๐Ÿ‘‰ IMPORTANT NOTES - * ------------------ - * - Screen IDs are of the form `TRI-${StationName}-${routeID}-${directionID}-${index}` - * - The last part, the `index`, starts at 1 for the triptych *nearest the front of the train*, and increments from there. - * So, if the train travels right relative to this platform, the rightmost triptych along that platform has index 1. - * If the train travels left, the leftmost triptych has index 1. - * - Try to order the lists of 3 player names associated with each screen ID by left-middle-right. - */ - -type ConfigItemParams = [TriptychScreenID, DirID, CarDir, PlatformPosition, StationID, [string, string, string], string]; - -// vvv Add items to this array vvv - -const getDraftConfigs = (): ConfigItemParams[] => [ - // MALDEN CENTER - ["TRI-MaldenCenter-Orange-0-1", DirID.SB, CarDir.L, 6, "place-mlmnl", ["MAN-DS-001", "MAN-DS-002", "MAN-DS-003"], "Malden Center - OL Inbound 1"], - ["TRI-MaldenCenter-Orange-0-2", DirID.SB, CarDir.L, 11, "place-mlmnl", ["MAN-DS-004", "MAN-DS-005", "MAN-DS-006"], "Malden Center - OL Inbound 2"], - ["TRI-MaldenCenter-Orange-0-3", DirID.SB, CarDir.L, 16, "place-mlmnl", ["MAN-DS-007", "MAN-DS-008", "MAN-DS-009"], "Malden Center - OL Inbound 3"], - - // WELLINGTON - ["TRI-Wellington-Orange-0-1", DirID.SB, CarDir.L, 22, "place-welln", ["WEL-DS-001", "WEL-DS-002", "WEL-DS-003"], "Wellington - OL Inbound 1"], - ["TRI-Wellington-Orange-0-2", DirID.SB, CarDir.L, 23, "place-welln", ["WEL-DS-004", "WEL-DS-005", "WEL-DS-006"], "Wellington - OL Inbound 2"], - ["TRI-Wellington-Orange-0-3", DirID.SB, CarDir.L, 25, "place-welln", ["WEL-DS-007", "WEL-DS-008", "WEL-DS-009"], "Wellington - OL Inbound 3"], - - // SULLIVAN SQUARE - // ๐Ÿ’ฅ The station map doesn't seem to agree with the spreadsheet for Sullivan. - // Station map has 01-02-03::left-middle-right, spreadsheet has 01-02-03::right-middle-left - // We should check to confirm that the player name groupings are reflected accurately, and the panes (`Array_configuration`) are tagged correctly as left/middle/right. - // If groupings are wrong, we could end up showing the "You are here" arrow in the wrong place, or not at all. - // If pane tags are wrong, we could end up showing left pane content on the right and vice versa. - ["TRI-SullivanSquare-Orange-0-1", DirID.SB, CarDir.L, 9, "place-sull", ["SSQ-DS-004", "SSQ-DS-005", "SSQ-DS-006"], "Sullivan Square - OL Inbound 1"], - ["TRI-SullivanSquare-Orange-0-2", DirID.SB, CarDir.L, 20, "place-sull", ["SSQ-DS-001", "SSQ-DS-002", "SSQ-DS-003"], "Sullivan Square - OL Inbound 2"], - - // NORTH STATION - ["TRI-NorthStation-Orange-0-1", DirID.SB, CarDir.R, 22, "place-north", ["NST-DS-029", "NST-DS-028", "NST-DS-027"], "North Station - OL Inbound 1"], - ["TRI-NorthStation-Orange-0-2", DirID.SB, CarDir.R, 16, "place-north", ["NST-DS-035", "NST-DS-034", "NST-DS-033"], "North Station - OL Inbound 2"], - ["TRI-NorthStation-Orange-1-1", DirID.NB, CarDir.R, 10, "place-north", ["NST-DS-036", "NST-DS-037", "NST-DS-038"], "North Station - OL Outbound 1"], - ["TRI-NorthStation-Orange-1-2", DirID.NB, CarDir.R, 4, "place-north", ["NST-DS-030", "NST-DS-031", "NST-DS-032"], "North Station - OL Outbound 2"], - - // HAYMARKET - ["TRI-Haymarket-Orange-0-1", DirID.SB, CarDir.R, 16, "place-haecl", ["HAT-DS-003", "HAT-DS-002", "HAT-DS-001"], "Haymarket - OL Inbound 1"], - ["TRI-Haymarket-Orange-0-2", DirID.SB, CarDir.R, 14, "place-haecl", ["HAT-DS-006", "HAT-DS-005", "HAT-DS-004"], "Haymarket - OL Inbound 2"], - ["TRI-Haymarket-Orange-0-3", DirID.SB, CarDir.R, 12, "place-haecl", ["HAT-DS-009", "HAT-DS-008", "HAT-DS-007"], "Haymarket - OL Inbound 3"], - ["TRI-Haymarket-Orange-1-1", DirID.NB, CarDir.R, 16, "place-haecl", ["HAT-DS-016", "HAT-DS-017", "HAT-DS-018"], "Haymarket - OL Outbound 1"], - ["TRI-Haymarket-Orange-1-2", DirID.NB, CarDir.R, 14, "place-haecl", ["HAT-DS-013", "HAT-DS-014", "HAT-DS-015"], "Haymarket - OL Outbound 2"], - ["TRI-Haymarket-Orange-1-3", DirID.NB, CarDir.R, 12, "place-haecl", ["HAT-DS-010", "HAT-DS-011", "HAT-DS-012"], "Haymarket - OL Outbound 3"], - - // STATE - ["TRI-State-Orange-0-1", DirID.SB, CarDir.L, 10, "place-state", ["STS-DS-010", "STS-DS-011", "STS-DS-012"], "State - OL Inbound/Southbound 1"], - ["TRI-State-Orange-0-2", DirID.SB, CarDir.L, 14, "place-state", ["STS-DS-013", "STS-DS-014", "STS-DS-015"], "State - OL Inbound/Southbound 2"], - ["TRI-State-Orange-0-3", DirID.SB, CarDir.L, 22, "place-state", ["STS-DS-016", "STS-DS-017", "STS-DS-018"], "State - OL Inbound/Southbound 3"], - ["TRI-State-Orange-1-1", DirID.NB, CarDir.R, 17, "place-state", ["STS-DS-007", "STS-DS-008", "STS-DS-009"], "State - OL Outbound/Northbound 1"], - ["TRI-State-Orange-1-2", DirID.NB, CarDir.R, 10, "place-state", ["STS-DS-004", "STS-DS-005", "STS-DS-006"], "State - OL Outbound/Northbound 2"], - ["TRI-State-Orange-1-3", DirID.NB, CarDir.R, 6, "place-state", ["STS-DS-001", "STS-DS-002", "STS-DS-003"], "State - OL Outbound/Northbound 3"], - - // DOWNTOWN CROSSING - // NAME CHANGE: DTX / DTX - // ๐Ÿ’ฅ Travel directions seem mislabeled on the station map for this one. - // The tracks are also not labeled with their destinations. - // We should double-check the triptychs at DTX to make sure they're properly configured. - ["TRI-DTX-Orange-0-1", DirID.SB, CarDir.R, 20, "place-dwnxg", ["DOW-DS-009", "DOW-DS-008", "DOW-DS-007"], "DTX - OL Outbound/Southbound 1"], - ["TRI-DTX-Orange-0-2", DirID.SB, CarDir.R, 12, "place-dwnxg", ["DOW-DS-030", "DOW-DS-029", "DOW-DS-028"], "DTX - OL Outbound/Southbound 2"], - ["TRI-DTX-Orange-0-3", DirID.SB, CarDir.R, 3, "place-dwnxg", ["DOW-DS-012", "DOW-DS-011", "DOW-DS-010"], "DTX - OL Outbound/Southbound 3"], - ["TRI-DTX-Orange-1-1", DirID.NB, CarDir.R, 18, "place-dwnxg", ["DOW-DS-025", "DOW-DS-026", "DOW-DS-027"], "DTX - OL Inbound/Northbound 1"], - ["TRI-DTX-Orange-1-2", DirID.NB, CarDir.R, 9, "place-dwnxg", ["DOW-DS-004", "DOW-DS-005", "DOW-DS-006"], "DTX - OL Inbound/Northbound 2"], - ["TRI-DTX-Orange-1-3", DirID.NB, CarDir.R, 3, "place-dwnxg", ["DOW-DS-001", "DOW-DS-002", "DOW-DS-003"], "DTX - OL Inbound/Northbound 3"], - - // TUFTS MEDICAL CENTER - // NAME CHANGE: TuftsMed / Tufts Med - ["TRI-TuftsMed-Orange-0-1", DirID.SB, CarDir.R, 21, "place-tumnl", ["NMC-DS-015", "NMC-DS-014", "NMC-DS-013"], "Tufts Med - OL Outbound 1"], - ["TRI-TuftsMed-Orange-0-2", DirID.SB, CarDir.R, 10, "place-tumnl", ["NMC-DS-009", "NMC-DS-008", "NMC-DS-007"], "Tufts Med - OL Outbound 2"], - ["TRI-TuftsMed-Orange-0-3", DirID.SB, CarDir.R, 5, "place-tumnl", ["NMC-DS-003", "NMC-DS-002", "NMC-DS-001"], "Tufts Med - OL Outbound 3"], - ["TRI-TuftsMed-Orange-1-1", DirID.NB, CarDir.R, 21, "place-tumnl", ["NMC-DS-004", "NMC-DS-005", "NMC-DS-006"], "Tufts Med - OL Inbound 1"], - ["TRI-TuftsMed-Orange-1-2", DirID.NB, CarDir.R, 16, "place-tumnl", ["NMC-DS-010", "NMC-DS-011", "NMC-DS-012"], "Tufts Med - OL Inbound 2"], - ["TRI-TuftsMed-Orange-1-3", DirID.NB, CarDir.R, 5, "place-tumnl", ["NMC-DS-016", "NMC-DS-017", "NMC-DS-018"], "Tufts Med - OL Inbound 3"], - - // BACK BAY - ["TRI-BackBay-Orange-0-1", DirID.SB, CarDir.L, 6, "place-bbsta", ["BKB-DS-001", "BKB-DS-002", "BKB-DS-003"], "Back Bay - OL Outbound 1"], - ["TRI-BackBay-Orange-0-2", DirID.SB, CarDir.L, 12, "place-bbsta", ["BKB-DS-004", "BKB-DS-005", "BKB-DS-006"], "Back Bay - OL Outbound 2"], - ["TRI-BackBay-Orange-0-3", DirID.SB, CarDir.L, 18, "place-bbsta", ["BKB-DS-007", "BKB-DS-008", "BKB-DS-009"], "Back Bay - OL Outbound 3"], - ["TRI-BackBay-Orange-1-1", DirID.NB, CarDir.L, 4, "place-bbsta", ["BKB-DS-018", "BKB-DS-017", "BKB-DS-016"], "Back Bay - OL Inbound 1"], - ["TRI-BackBay-Orange-1-2", DirID.NB, CarDir.L, 16, "place-bbsta", ["BKB-DS-015", "BKB-DS-014", "BKB-DS-013"], "Back Bay - OL Inbound 2"], - ["TRI-BackBay-Orange-1-3", DirID.NB, CarDir.L, 19, "place-bbsta", ["BKB-DS-012", "BKB-DS-011", "BKB-DS-010"], "Back Bay - OL Inbound 3"], - - // MASSACHUSETTS AVENUE - // NAME CHANGE: MassAve / Mass Ave - // ๐Ÿ’ฅ One of the player names in the spreadsheet is concerning--"MAS-DS-010_failed". - // (This is the right pane of TRI-MassAve-Orange-1-2) - // I assumed that that name was temporary at time of the spreadsheet's creation, and used the - // normal naming pattern without the "_failed" suffix. - // We should check this out. - // RELATED: Should we use player IDs instead of names? Are those less likely to change? - // It should be possible to get it from the MRAID object in the same way we get the player name. - ["TRI-MassAve-Orange-0-1", DirID.SB, CarDir.L, 18, "place-masta", ["MAS-DS-007", "MAS-DS-008", "MAS-DS-009"], "Mass Ave - OL Outbound 1"], - ["TRI-MassAve-Orange-0-2", DirID.SB, CarDir.L, 22, "place-masta", ["MAS-DS-001", "MAS-DS-002", "MAS-DS-003"], "Mass Ave - OL Outbound 2"], - ["TRI-MassAve-Orange-1-1", DirID.NB, CarDir.L, 4, "place-masta", ["MAS-DS-006", "MAS-DS-005", "MAS-DS-004"], "Mass Ave - OL Inbound 1"], - ["TRI-MassAve-Orange-1-2", DirID.NB, CarDir.L, 8, "place-masta", ["MAS-DS-012", "MAS-DS-011", "MAS-DS-010"], "Mass Ave - OL Inbound 2"], - - // RUGGLES - ["TRI-Ruggles-Orange-0-1", DirID.SB, CarDir.L, 11, "place-rugg", ["RUG-DS-001", "RUG-DS-002", "RUG-DS-003"], "Ruggles - OL Outbound 1"], - ["TRI-Ruggles-Orange-0-2", DirID.SB, CarDir.L, 20, "place-rugg", ["RUG-DS-004", "RUG-DS-005", "RUG-DS-006"], "Ruggles - OL Outbound 2"], - ["TRI-Ruggles-Orange-1-1", DirID.NB, CarDir.L, 7, "place-rugg", ["RUG-DS-012", "RUG-DS-011", "RUG-DS-010"], "Ruggles - OL Inbound 1"], - ["TRI-Ruggles-Orange-1-2", DirID.NB, CarDir.L, 15, "place-rugg", ["RUG-DS-009", "RUG-DS-008", "RUG-DS-007"], "Ruggles - OL Inbound 2"] -]; - -// ^^^ Add to this ^^^ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// ----- You normally don't need to edit anything below here, unless changing default config shape or adding new subway lines ----- - -type TriptychScreenID = `TRI-${string}-Orange-${0 | 1}-${number}`; - -type StationID = - | "place-ogmnl" - | "place-mlmnl" - | "place-welln" - | "place-astao" - | "place-sull" - | "place-ccmnl" - | "place-north" - | "place-haecl" - | "place-state" - | "place-dwnxg" - | "place-chncl" - | "place-tumnl" - | "place-bbsta" - | "place-masta" - | "place-rugg" - | "place-rcmnl" - | "place-jaksn" - | "place-sbmnl" - | "place-grnst" - | "place-forhl"; - -enum DirID { - SB = 0, - NB = 1, - WB = 0, - EB = 1 -} - -enum CarDir { - L = "left", - R = "right" -} - -type PlatformPosition = number; -const isPlatformPosition = (value: number): value is PlatformPosition => { - return value >= 1 && value <= 25; -}; - -interface ConfigItem { - configEntry: [TriptychScreenID, object], - playerNameEntries: [[string, TriptychScreenID], [string, TriptychScreenID], [string, TriptychScreenID]] -} - -const getConfigs = () => JSON.stringify(validate(mergeConfigs(getDraftConfigs().map((params) => makeConfig.apply(null, params))))); - -const mergeConfigs = (configs: ConfigItem[]) => - configs.reduce(({ screenConfig, playerNameMapping }, { configEntry: [k, v], playerNameEntries }) => ({ - screenConfig: { ...screenConfig, [k]: v }, - playerNameMapping: { ...playerNameMapping, ...Object.fromEntries(playerNameEntries) } - }), { screenConfig: {}, playerNameMapping: {} }); - -const validate = (mergedConfig: { screenConfig: object, playerNameMapping: object }) => { - const { screenConfig, playerNameMapping } = mergedConfig; - - const screenCount = Object.keys(screenConfig).length; - const playerNameCount = Object.keys(playerNameMapping).length; - - if (playerNameCount > 3 * screenCount) { - throw "There are too few screen configurations compared to player names. Do you have a duplicate screen ID somewhere in the list?"; - } else if (playerNameCount < 3 * screenCount) { - throw "There are too few player names compared to screens. Do you have a duplicate player name somewhere in the list?"; - } else { - return mergedConfig; - } -}; - -const makeConfig: (...params: ConfigItemParams) => ConfigItem = (id, directionID, frontCarDirection, platformPosition, stationID, playerNames, name) => { - if (!isPlatformPosition(platformPosition)) throw "Not a platform position"; - - return { - configEntry: [id, makeScreenConfig(directionID, frontCarDirection, platformPosition, stationID, name)], - playerNameEntries: playerNames.map(name => [name, id]) as ConfigItem["playerNameEntries"] - }; -}; - -const makeScreenConfig = (directionID: DirID, frontCarDirection: CarDir, platformPosition: PlatformPosition, stationID: StationID, name: string) => ({ - "app_id": "triptych_v2", - "app_params": { - "evergreen_content": [], - "local_evergreen_sets": [ - { - "folder_name": "See-Say", - "schedule": [ - { - "end_dt": null, - "start_dt": null - } - ] - }, - { - "folder_name": "Closing-Doors", - "schedule": [ - { - "end_dt": null, - "start_dt": null - } - ] - } - ], - "show_identifiers": false, - "train_crowding": { - "direction_id": directionID, - "enabled": true, - "front_car_direction": frontCarDirection, - "platform_position": platformPosition, - "route_id": "Orange", - "station_id": stationID - } - }, - "device_id": "N/A", - "disabled": false, - "hidden_from_screenplay": true, - "name": name, - "refresh_if_loaded_before": "2023-05-09T18:41:27.318063Z", - "tags": [], - "vendor": "outfront" -}); - -// This line actually runs the thing. -console.log(getConfigs()); diff --git a/scripts/pull_configs.sh b/scripts/pull_configs.sh index be9af8bbe..ca7e22a39 100755 --- a/scripts/pull_configs.sh +++ b/scripts/pull_configs.sh @@ -33,5 +33,4 @@ maybe_cp() { maybe_cp s3://mbta-ctd-config/screens/screens-"$1".json priv/local.json maybe_cp s3://mbta-ctd-config/screens/pending-screens-"$1".json priv/local_pending.json -maybe_cp s3://mbta-ctd-config/screens/triptych-player-"$1".json priv/triptych_player_to_screen_id.json maybe_cp s3://mbta-signs/config.json priv/signs_ui_config.json diff --git a/test/fixtures/triptych_player_to_screen_id.json b/test/fixtures/triptych_player_to_screen_id.json deleted file mode 100644 index 0967ef424..000000000 --- a/test/fixtures/triptych_player_to_screen_id.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/test/screens/v2/candidate_generator/bus_eink_test.exs b/test/screens/v2/candidate_generator/bus_eink_test.exs index ba409599a..b96ccc6bc 100644 --- a/test/screens/v2/candidate_generator/bus_eink_test.exs +++ b/test/screens/v2/candidate_generator/bus_eink_test.exs @@ -52,7 +52,7 @@ defmodule Screens.V2.CandidateGenerator.BusEinkTest do end end - describe "candidate_instances/3" do + describe "candidate_instances/7" do test "returns expected header", %{config: config} do departures_instances_fn = fn _, _ -> [] end alerts_instances_fn = fn _ -> [] end @@ -60,12 +60,10 @@ defmodule Screens.V2.CandidateGenerator.BusEinkTest do now = ~U[2020-04-06T10:00:00Z] evergreen_content_instances_fn = fn _ -> [] end subway_status_instances_fn = fn _, _ -> [] end - opts = [] actual_instances = BusEink.candidate_instances( config, - opts, now, fetch_stop_fn, departures_instances_fn, diff --git a/test/screens/v2/candidate_generator/bus_shelter_test.exs b/test/screens/v2/candidate_generator/bus_shelter_test.exs index 66c74e0c0..ac8eb53c0 100644 --- a/test/screens/v2/candidate_generator/bus_shelter_test.exs +++ b/test/screens/v2/candidate_generator/bus_shelter_test.exs @@ -72,7 +72,7 @@ defmodule Screens.V2.CandidateGenerator.BusShelterTest do end end - describe "candidate_instances/3" do + describe "candidate_instances/7" do test "returns expected header and footer", %{config: config} do departures_instances_fn = fn _, _ -> [] end alert_instances_fn = fn _ -> [] end @@ -80,7 +80,6 @@ defmodule Screens.V2.CandidateGenerator.BusShelterTest do now = ~U[2020-04-06T10:00:00Z] evergreen_content_instances_fn = fn _ -> [] end subway_status_instances_fn = fn _, _ -> [] end - opts = [] expected_header = %NormalHeader{ screen: config, @@ -94,7 +93,6 @@ defmodule Screens.V2.CandidateGenerator.BusShelterTest do actual_instances = BusShelter.candidate_instances( config, - opts, now, fetch_stop_fn, departures_instances_fn, @@ -117,7 +115,6 @@ defmodule Screens.V2.CandidateGenerator.BusShelterTest do now = ~U[2020-04-06T10:00:00Z] evergreen_content_instances_fn = fn _ -> [] end subway_status_instances_fn = fn _, _ -> [] end - opts = [] expected_header = %NormalHeader{ screen: config, @@ -129,7 +126,6 @@ defmodule Screens.V2.CandidateGenerator.BusShelterTest do actual_instances = BusShelter.candidate_instances( config, - opts, now, fetch_stop_fn, departures_instances_fn, diff --git a/test/screens/v2/candidate_generator/busway_test.exs b/test/screens/v2/candidate_generator/busway_test.exs index 09219078f..1ca4188ba 100644 --- a/test/screens/v2/candidate_generator/busway_test.exs +++ b/test/screens/v2/candidate_generator/busway_test.exs @@ -39,14 +39,14 @@ defmodule Screens.V2.CandidateGenerator.BuswayTest do deps = struct!(deps, now: fn -> now end) expected_header = %NormalHeader{screen: config, icon: :logo, text: "Ruggles", time: now} - assert expected_header in Busway.candidate_instances(config, [], deps) + assert expected_header in Busway.candidate_instances(config, deps) end test "includes departures instances", %{config: config, deps: deps} do no_data = %DeparturesNoData{screen: config, show_alternatives?: true} deps = struct!(deps, departures_instances: fn ^config, _ -> [no_data] end) - assert no_data in Busway.candidate_instances(config, [], deps) + assert no_data in Busway.candidate_instances(config, deps) end end end diff --git a/test/screens/v2/candidate_generator/dup_test.exs b/test/screens/v2/candidate_generator/dup_test.exs index 43cea3f99..1347cc002 100644 --- a/test/screens/v2/candidate_generator/dup_test.exs +++ b/test/screens/v2/candidate_generator/dup_test.exs @@ -83,14 +83,13 @@ defmodule Screens.V2.CandidateGenerator.DupTest do end end - describe "candidate_instances/4" do + describe "candidate_instances/6" do test "returns expected header", %{config: config} do now = ~U[2020-04-06T10:00:00Z] fetch_stop_fn = fn "place-gover" -> "Government Center" end departures_instances_fn = fn _, _ -> [] end evergreen_content_instances_fn = fn _ -> [] end alerts_instances_fn = fn _, _ -> [] end - opts = [] expected_headers = List.duplicate( @@ -106,7 +105,6 @@ defmodule Screens.V2.CandidateGenerator.DupTest do actual_instances = Dup.candidate_instances( config, - opts, now, fetch_stop_fn, evergreen_content_instances_fn, diff --git a/test/screens/v2/candidate_generator/solari_large_test.exs b/test/screens/v2/candidate_generator/solari_large_test.exs index e4c1c776c..cd5e839a9 100644 --- a/test/screens/v2/candidate_generator/solari_large_test.exs +++ b/test/screens/v2/candidate_generator/solari_large_test.exs @@ -30,11 +30,10 @@ defmodule Screens.V2.CandidateGenerator.SolariLargeTest do end end - describe "candidate_instances/2" do + describe "candidate_instances/3" do test "returns expected header", %{config: config} do departures_instances_fn = fn _, _ -> [] end now = ~U[2020-04-06T10:00:00Z] - opts = [] expected_header = %NormalHeader{ screen: config, @@ -44,7 +43,7 @@ defmodule Screens.V2.CandidateGenerator.SolariLargeTest do } actual_instances = - SolariLarge.candidate_instances(config, opts, now, departures_instances_fn) + SolariLarge.candidate_instances(config, now, departures_instances_fn) assert expected_header in actual_instances end diff --git a/test/screens/v2/candidate_generator/triptych_test.exs b/test/screens/v2/candidate_generator/triptych_test.exs deleted file mode 100644 index 4d5c85e18..000000000 --- a/test/screens/v2/candidate_generator/triptych_test.exs +++ /dev/null @@ -1,36 +0,0 @@ -defmodule Screens.V2.CandidateGenerator.TriptychTest do - use ExUnit.Case, async: true - - alias ScreensConfig.{Screen, V2} - alias Screens.V2.CandidateGenerator.Triptych - - setup do - config = %Screen{ - app_params: %V2.Triptych{ - local_evergreen_sets: [], - train_crowding: %V2.TrainCrowding{ - station_id: "place-dwnxg", - direction_id: 1, - platform_position: 3, - front_car_direction: "right" - } - }, - vendor: :outfront, - device_id: "TEST", - name: "TEST", - app_id: :triptych_v2 - } - - %{config: config} - end - - describe "screen_template/0" do - test "returns template" do - assert {:screen, - %{ - screen_normal: [:full_screen], - screen_split: [:left_pane, :middle_pane, :right_pane] - }} == Triptych.screen_template() - end - end -end diff --git a/test/screens/v2/candidate_generator/widgets/train_crowding_test.exs b/test/screens/v2/candidate_generator/widgets/train_crowding_test.exs deleted file mode 100644 index 0a47caae2..000000000 --- a/test/screens/v2/candidate_generator/widgets/train_crowding_test.exs +++ /dev/null @@ -1,303 +0,0 @@ -defmodule Screens.V2.CandidateGenerator.Widgets.TrainCrowdingTest do - use ExUnit.Case, async: true - - import Screens.V2.CandidateGenerator.Widgets.TrainCrowding - - alias ScreensConfig.Screen - alias ScreensConfig.V2.{TrainCrowding, Triptych} - alias Screens.Predictions.Prediction - alias Screens.Vehicles.{Carriage, Vehicle} - alias Screens.V2.WidgetInstance.TrainCrowding, as: CrowdingWidget - - setup :setup_base - - defp setup_base(_) do - config = %Screen{ - app_params: %Triptych{ - train_crowding: %TrainCrowding{ - station_id: "place-masta", - direction_id: 1, - platform_position: 3, - front_car_direction: "right", - enabled: true - }, - local_evergreen_sets: [] - }, - vendor: :outfront, - device_id: "TEST", - name: "TEST", - app_id: :triptych_v2 - } - - now = ~U[2023-08-16 21:04:00Z] - - next_train_prediction = - struct(Prediction, %{ - vehicle: - struct(Vehicle, %{ - stop_id: "10001", - current_status: :incoming_at, - carriages: [struct(Carriage)] - }) - }) - - location_context = %Screens.LocationContext{ - home_stop: "place-masta", - tagged_stop_sequences: %{ - "Orange" => [ - [ - "place-ogmnl", - "place-mlmnl", - "place-welln", - "place-astao", - "place-sull", - "place-ccmnl", - "place-north", - "place-haecl", - "place-state", - "place-dwnxg", - "place-chncl", - "place-tumnl", - "place-bbsta", - "place-masta", - "place-rugg", - "place-rcmnl", - "place-jaksn", - "place-sbmnl", - "place-grnst", - "place-forhl" - ] - ] - }, - upstream_stops: - MapSet.new([ - "place-astao", - "place-bbsta", - "place-ccmnl", - "place-chncl", - "place-dwnxg", - "place-haecl", - "place-mlmnl", - "place-north", - "place-ogmnl", - "place-state", - "place-sull", - "place-tumnl", - "place-welln" - ]), - downstream_stops: - MapSet.new([ - "place-forhl", - "place-grnst", - "place-jaksn", - "place-rcmnl", - "place-rugg", - "place-sbmnl" - ]), - routes: [ - %{ - active?: true, - direction_destinations: ["Forest Hills", "Oak Grove"], - long_name: "Orange Line", - route_id: "Orange", - short_name: "", - type: :subway - } - ], - alert_route_types: [:light_rail, :subway] - } - - alerts = [ - %Screens.Alerts.Alert{ - id: "141245", - cause: :unknown, - effect: :shuttle, - severity: 7, - header: "Shuttle buses replacing Orange Line service", - informed_entities: [ - %{direction_id: nil, route: "Orange", route_type: 1, stop: "70012"}, - %{direction_id: nil, route: "Orange", route_type: 1, stop: "70013"}, - %{direction_id: nil, route: "Orange", route_type: 1, stop: "70014"}, - %{direction_id: nil, route: "Orange", route_type: 1, stop: "70015"}, - %{direction_id: nil, route: "Orange", route_type: 1, stop: "70016"}, - %{direction_id: nil, route: "Orange", route_type: 1, stop: "70017"}, - %{direction_id: nil, route: "Orange", route_type: 1, stop: "70018"}, - %{direction_id: nil, route: "Orange", route_type: 1, stop: "70019"}, - %{direction_id: nil, route: "Orange", route_type: 1, stop: "70020"}, - %{direction_id: nil, route: "Orange", route_type: 1, stop: "70021"}, - %{direction_id: nil, route: "Orange", route_type: 1, stop: "70022"}, - %{direction_id: nil, route: "Orange", route_type: 1, stop: "70023"}, - %{direction_id: nil, route: "Orange", route_type: 1, stop: "70024"}, - %{direction_id: nil, route: "Orange", route_type: 1, stop: "70025"}, - %{direction_id: nil, route: "Orange", route_type: 1, stop: "place-bbsta"}, - %{direction_id: nil, route: "Orange", route_type: 1, stop: "place-chncl"}, - %{direction_id: nil, route: "Orange", route_type: 1, stop: "place-dwnxg"}, - %{direction_id: nil, route: "Orange", route_type: 1, stop: "place-haecl"}, - %{direction_id: nil, route: "Orange", route_type: 1, stop: "place-masta"}, - %{direction_id: nil, route: "Orange", route_type: 1, stop: "place-state"}, - %{direction_id: nil, route: "Orange", route_type: 1, stop: "place-tumnl"} - ], - active_period: [{DateTime.add(now, -1, :hour), DateTime.add(now, 2, :hour)}], - lifecycle: "NEW", - timeframe: nil, - created_at: ~U[2023-08-16 20:04:02Z], - updated_at: ~U[2023-08-16 20:04:02Z], - url: nil, - description: - "Affected stops:\r\nHaymarket\r\nState\r\nDowntown Crossing\r\nChinatown\r\nTufts Medical Center\r\nBack Bay\r\nMassachusetts Avenue" - } - ] - - %{ - config: config, - logging_options: %{is_real_screen: false, screen_id: "TEST", triptych_pane: nil}, - now: now, - next_train_prediction: next_train_prediction, - fetch_predictions_fn: fn _ -> {:ok, [next_train_prediction]} end, - fetch_location_context_fn: fn _, _, _ -> {:ok, location_context} end, - fetch_parent_stop_id_fn: fn "10001" -> "place-masta" end, - fetch_empty_alerts_fn: fn _ -> {:ok, []} end, - fetch_alerts_fn: fn _ -> {:ok, alerts} end - } - end - - defp disable_widget(config) do - %{ - config - | app_params: %{ - config.app_params - | train_crowding: %{config.app_params.train_crowding | enabled: false} - } - } - end - - describe "crowding_widget_instances/3" do - test "returns crowding widget if train is on the way to this station", context do - assert crowding_widget_instances( - context.config, - context.logging_options, - context.now, - context.fetch_predictions_fn, - context.fetch_location_context_fn, - context.fetch_parent_stop_id_fn, - context.fetch_empty_alerts_fn - ) == [ - %CrowdingWidget{ - screen: context.config, - prediction: context.next_train_prediction, - now: context.now - } - ] - end - - test "returns empty if train is not coming yet", context do - alt_prediction = - struct(Prediction, %{ - vehicle: struct(Vehicle, %{stop_id: "9999", current_status: :incoming_at}) - }) - - assert crowding_widget_instances( - context.config, - context.logging_options, - context.now, - fn _ -> {:ok, [alt_prediction]} end, - context.fetch_location_context_fn, - fn "9999" -> "place-bbsta" end, - context.fetch_empty_alerts_fn - ) == [] - end - - test "returns empty if train has already arrived at this station", context do - alt_prediction = - struct(Prediction, %{ - vehicle: struct(Vehicle, %{stop_id: "10001", current_status: :stopped_at}) - }) - - assert crowding_widget_instances( - context.config, - context.logging_options, - context.now, - fn _ -> {:ok, [alt_prediction]} end, - context.fetch_location_context_fn, - context.fetch_parent_stop_id_fn, - context.fetch_empty_alerts_fn - ) == [] - end - - test "returns empty if there is a shuttle / suspension that makes this station a temp terminal", - context do - assert crowding_widget_instances( - context.config, - context.logging_options, - context.now, - context.fetch_predictions_fn, - context.fetch_location_context_fn, - context.fetch_parent_stop_id_fn, - context.fetch_alerts_fn - ) == [] - end - - test "returns empty if there are no predictions", context do - assert crowding_widget_instances( - context.config, - context.logging_options, - context.now, - fn _ -> {:ok, []} end, - context.fetch_location_context_fn, - context.fetch_parent_stop_id_fn, - context.fetch_empty_alerts_fn - ) == [] - end - - test "returns empty if any fetches fail", context do - assert crowding_widget_instances( - context.config, - context.logging_options, - context.now, - fn _ -> :error end, - context.fetch_location_context_fn, - context.fetch_parent_stop_id_fn, - context.fetch_empty_alerts_fn - ) == [] - - assert crowding_widget_instances( - context.config, - context.logging_options, - context.now, - context.fetch_predictions_fn, - fn _, _, _ -> :error end, - context.fetch_parent_stop_id_fn, - context.fetch_empty_alerts_fn - ) == [] - - assert crowding_widget_instances( - context.config, - context.logging_options, - context.now, - context.fetch_predictions_fn, - context.fetch_location_context_fn, - fn _ -> :error end, - context.fetch_empty_alerts_fn - ) == [] - - assert crowding_widget_instances( - context.config, - context.logging_options, - context.now, - context.fetch_predictions_fn, - context.fetch_location_context_fn, - context.fetch_parent_stop_id_fn, - fn _ -> :error end - ) == [] - end - - test "returns empty if widget is disabled", %{ - config: config, - logging_options: logging_options - } do - config = disable_widget(config) - - assert crowding_widget_instances(config, logging_options) == [] - end - end -end diff --git a/test/screens/v2/screen_data_test.exs b/test/screens/v2/screen_data_test.exs index 7fe3e69b2..374d6066e 100644 --- a/test/screens/v2/screen_data_test.exs +++ b/test/screens/v2/screen_data_test.exs @@ -12,7 +12,7 @@ defmodule Screens.V2.ScreenDataTest.Stub do def screen_template(), do: Builder.build_template({:screen, %{normal: [:main]}}) @impl CandidateGenerator - def candidate_instances(config, _opts) do + def candidate_instances(config) do unquote(instances_fn).(config) end diff --git a/test/screens/v2/widget_instance/train_crowding_test.exs b/test/screens/v2/widget_instance/train_crowding_test.exs deleted file mode 100644 index db2b7ff1d..000000000 --- a/test/screens/v2/widget_instance/train_crowding_test.exs +++ /dev/null @@ -1,181 +0,0 @@ -defmodule Screens.V2.WidgetInstance.TrainCrowdingTest do - use ExUnit.Case, async: true - - alias Screens.Predictions.Prediction - alias Screens.V2.WidgetInstance.TrainCrowding, as: WidgetInstance - alias Screens.Vehicles.{Carriage, Vehicle} - - defp put_crowding_levels(widget, carriages) do - put_in(widget.prediction.vehicle.carriages, carriages) - end - - setup do - config = - struct(ScreensConfig.Screen, %{ - app_params: - struct(ScreensConfig.V2.Triptych, %{ - train_crowding: %ScreensConfig.V2.TrainCrowding{ - station_id: "place-masta", - direction_id: 1, - platform_position: 3, - front_car_direction: "right", - enabled: true - } - }) - }) - - prediction = - struct(Prediction, %{ - trip: %{ - headsign: "Oak Grove" - }, - vehicle: - struct(Vehicle, %{ - stop_id: "10001", - current_status: :incoming_at, - carriages: [ - %Carriage{ - car_number: "1", - occupancy_status: :crushed_standing_room_only, - occupancy_percentage: 45 - }, - %Carriage{ - car_number: "2", - occupancy_status: :few_seats_available, - occupancy_percentage: 5 - }, - %Carriage{ - car_number: "3", - occupancy_status: :standing_room_only, - occupancy_percentage: 20 - }, - %Carriage{ - car_number: "4", - occupancy_status: :many_seats_available, - occupancy_percentage: 5 - }, - %Carriage{car_number: "5", occupancy_status: :full, occupancy_percentage: 45}, - %Carriage{ - car_number: "6", - occupancy_status: :not_accepting_passengers, - occupancy_percentage: -1 - } - ] - }) - }) - - widget = %WidgetInstance{ - screen: config, - prediction: prediction, - now: ~U[2023-08-16 21:04:00Z] - } - - %{widget: widget} - end - - describe "serialize/1" do - test "serializes data, 6/7 possible crowding levels", %{widget: widget} do - expected = %{ - destination: "Oak Grove", - crowding: [:crowded, :not_crowded, :some_crowding, :not_crowded, :crowded, :closed], - platform_position: 3, - front_car_direction: "right", - now: "2023-08-16T21:04:00Z", - show_identifiers: false - } - - assert expected == WidgetInstance.serialize(widget) - end - - test "serializes data, last crowding level (no_data)", %{widget: widget} do - widget = - put_crowding_levels(widget, [ - %Carriage{ - car_number: "1", - occupancy_status: :no_data_available, - occupancy_percentage: -1 - }, - %Carriage{ - car_number: "2", - occupancy_status: :no_data_available, - occupancy_percentage: -1 - }, - %Carriage{ - car_number: "3", - occupancy_status: :standing_room_only, - occupancy_percentage: 25 - }, - %Carriage{ - car_number: "4", - occupancy_status: :many_seats_available, - occupancy_percentage: 5 - }, - %Carriage{car_number: "5", occupancy_status: :full, occupancy_percentage: 45}, - %Carriage{ - car_number: "6", - occupancy_status: :not_accepting_passengers, - occupancy_percentage: -1 - } - ]) - - expected = %{ - destination: "Oak Grove", - crowding: [:no_data, :no_data, :some_crowding, :not_crowded, :crowded, :closed], - platform_position: 3, - front_car_direction: "right", - now: "2023-08-16T21:04:00Z", - show_identifiers: false - } - - assert expected == WidgetInstance.serialize(widget) - end - end - - describe "priority/1" do - test "returns max priority", %{widget: widget} do - assert [1] == WidgetInstance.priority(widget) - end - end - - describe "slot_names/1" do - test "returns [:full_screen]", %{widget: widget} do - assert [:full_screen] == WidgetInstance.slot_names(widget) - end - end - - describe "widget_type/1" do - test "returns :train_crowding", %{widget: widget} do - assert :train_crowding == WidgetInstance.widget_type(widget) - end - end - - describe "valid_candidate?/1" do - test "returns true", %{widget: widget} do - assert WidgetInstance.valid_candidate?(widget) - end - end - - describe "audio_serialize/1" do - test "returns empty", %{widget: widget} do - assert %{} == WidgetInstance.audio_serialize(widget) - end - end - - describe "audio_sort_key/1" do - test "returns [0]", %{widget: widget} do - assert [0] == WidgetInstance.audio_sort_key(widget) - end - end - - describe "audio_valid_candidate?/1" do - test "returns false", %{widget: widget} do - assert not WidgetInstance.audio_valid_candidate?(widget) - end - end - - describe "audio_view/1" do - test "returns nil", %{widget: widget} do - assert nil == WidgetInstance.audio_view(widget) - end - end -end