Skip to content

Commit

Permalink
Merge branch 'master' into building-block-library
Browse files Browse the repository at this point in the history
  • Loading branch information
amy-corson-ibigroup committed Oct 23, 2023
2 parents 69622a6 + 8c4ae18 commit 297cc1e
Show file tree
Hide file tree
Showing 73 changed files with 47,776 additions and 37,103 deletions.
83,800 changes: 47,039 additions & 36,761 deletions __snapshots__/storybook.test.ts.snap

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions packages/base-map/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@opentripplanner/base-map",
"version": "3.0.14",
"version": "3.0.15",
"description": "Base Map Component",
"author": "@binh-dam-ibigroup",
"homepage": "https://github.com/opentripplanner/otp-ui/#readme",
Expand All @@ -14,7 +14,7 @@
"react-map-gl": "^7.0.15"
},
"peerDependencies": {
"@opentripplanner/types": "^6.0.0",
"@opentripplanner/types": "^6.1.0",
"react": "^16.14.0",
"styled-components": "^5.3.0"
},
Expand Down
7 changes: 3 additions & 4 deletions packages/core-utils/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@opentripplanner/core-utils",
"version": "9.0.3",
"version": "11.1.2",
"description": "Core functionality that is shared among numerous UI components",
"engines": {
"node": ">=13"
Expand All @@ -14,10 +14,9 @@
"dependencies": {
"@conveyal/lonlat": "^1.4.1",
"@mapbox/polyline": "^1.1.0",
"@opentripplanner/geocoder": "^1.4.1",
"@opentripplanner/geocoder": "^1.4.2",
"@styled-icons/foundation": "^10.34.0",
"@turf/along": "^6.0.1",
"bowser": "^2.7.0",
"chroma-js": "^2.4.2",
"date-fns": "^2.28.0",
"date-fns-tz": "^1.2.2",
Expand All @@ -31,7 +30,7 @@
"tsc": "tsc"
},
"devDependencies": {
"@opentripplanner/types": "^6.0.0-alpha.9",
"@opentripplanner/types": "^7.0.0-alpha.9",
"@types/chroma-js": "^2.1.4"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import {
getDisplayedStopId,
getItineraryCost,
getLegCost,
getLegRouteLongName,
getLegRouteName,
getLegRouteShortName,
isTransit
} from "../itinerary";

Expand Down Expand Up @@ -180,4 +183,72 @@ describe("util > itinerary", () => {
});
});
});
describe("getLegRouteShortName", () => {
it("should extract a route short name from an OTP1 leg", () => {
expect(getLegRouteShortName({ route: "15" })).toBe("15");
expect(getLegRouteShortName({ route: "15", routeShortName: "31" })).toBe(
"31"
);
});

it("should extract a route short name from an OTP2 leg", () => {
expect(
getLegRouteShortName({
route: { id: "id15", shortName: "15" },
routeShortName: "31"
})
).toBe("15");
});
});
describe("getLegRouteLongName", () => {
it("should extract a route long name from an OTP1 leg", () => {
expect(getLegRouteLongName({ route: "15" })).toBeUndefined();
expect(
getLegRouteLongName({ route: "15", routeLongName: "Candler Road" })
).toBe("Candler Road");
});
it("should extract a route long name from an OTP2 leg", () => {
expect(
getLegRouteLongName({
route: { id: "id15", longName: "15" },
routeLongName: "31"
})
).toBe("15");
});
});
describe("getLegRouteName", () => {
it("should extract a route name from an OTP1 leg where a route short name is provided", () => {
expect(
getLegRouteName({
route: "15",
routeShortName: "31",
routeLongName: "Route 31"
})
).toBe("31");
});
it("should extract a route name from an OTP1 leg where a route short name is not provided", () => {
expect(
getLegRouteName({
routeLongName: "Route 31"
})
).toBe("Route 31");
});
it("should extract a route name from an OTP2 leg where a route short name is provided", () => {
expect(
getLegRouteName({
route: { id: "id15", longName: "15", shortName: "10" },
routeLongName: "31"
})
).toBe("10");
});
it("should extract a route name from an OTP2 leg where a route short name is not provided", () => {
expect(
getLegRouteName({
route: { id: "id15", longName: "15" },
routeLongName: "31",
routeShortName: "31"
})
).toBe("15");
});
});
});
39 changes: 35 additions & 4 deletions packages/core-utils/src/itinerary.ts
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@ export function legElevationAtDistance(
const elevDistanceSpan = points[i][0] - start[0];
if (distance >= traversed && distance <= traversed + elevDistanceSpan) {
// Distance falls within this point and the previous one;
// compute & return iterpolated elevation value
// compute & return interpolated elevation value
if (start[1] === null) {
console.warn(
"Elevation value does not exist for distance.",
Expand Down Expand Up @@ -369,10 +369,10 @@ export function getElevationProfile(
* @see https://stackoverflow.com/questions/118241/calculate-text-width-with-javascript/21015393#21015393
*/
export function getTextWidth(text: string, font = "22px Arial"): number {
// Create custom type for function including re-used canvas object
// Create custom type for function including reused canvas object
type GetTextWidth = typeof getTextWidth & { canvas: HTMLCanvasElement };

// re-use canvas object for better performance
// reuse canvas object for better performance
const canvas =
(getTextWidth as GetTextWidth).canvas ||
((getTextWidth as GetTextWidth).canvas = document.createElement("canvas"));
Expand Down Expand Up @@ -655,6 +655,7 @@ const pickupDropoffTypeToOtp1 = otp2Type => {
export const convertGraphQLResponseToLegacy = (leg: any): any => ({
...leg,
agencyBrandingUrl: leg.agency?.url,
agencyId: leg.agency?.id,
agencyName: leg.agency?.name,
agencyUrl: leg.agency?.url,
alightRule: pickupDropoffTypeToOtp1(leg.dropoffType),
Expand All @@ -669,7 +670,7 @@ export const convertGraphQLResponseToLegacy = (leg: any): any => ({
},
route: leg.route?.shortName,
routeColor: leg.route?.color,
routeId: leg.route?.id,
routeId: leg.route?.gtfsId,
routeLongName: leg.route?.longName,
routeShortName: leg.route?.shortName,
routeTextColor: leg.route?.textColor,
Expand All @@ -681,3 +682,33 @@ export const convertGraphQLResponseToLegacy = (leg: any): any => ({
tripHeadsign: leg.trip?.tripHeadsign,
tripId: leg.trip?.gtfsId
});

/** Extracts the route number for a leg returned from OTP1 or OTP2. */
export const getLegRouteShortName = (
leg: Pick<Leg, "route" | "routeShortName">
): string | null => {
const { route, routeShortName } = leg;
// typeof route === "object" denotes newer OTP2 responses. routeShortName and route as string is OTP1.
return typeof route === "object"
? route?.shortName
: routeShortName || (route as string);
};

/** Extract the route long name for a leg returned from OTP1 or OTP2. */
export const getLegRouteLongName = (
leg: Pick<Leg, "route" | "routeLongName">
): string | null => {
const { route, routeLongName } = leg;
// typeof route === "object" denotes newer OTP2 responses. routeLongName is OTP1.
return typeof route === "object" ? route?.longName : routeLongName;
};

/**
* Returns the route short name, or the route long name if no short name is provided.
* This is happens with Seattle area streetcars and ferries.
*/
export const getLegRouteName = (
leg: Pick<Leg, "route" | "routeLongName" | "routeShortName">
): string => {
return getLegRouteShortName(leg) || getLegRouteLongName(leg);
};
38 changes: 22 additions & 16 deletions packages/core-utils/src/otpSchema.json
Original file line number Diff line number Diff line change
Expand Up @@ -2292,7 +2292,7 @@
"fields": [
{
"name": "id",
"description": "Identifier local to the itinerary that allows to cross-reference and deduplicate\nfare products that span more than one leg.\n\nIf you want to uniquely identify the fare product itself (not its use) use the product's `id`.\n\n### Example: Day pass\n\nWhen a day pass is valid for all three legs in the itinerary it will appear\nfor each leg but with the same use-`id`.\n\n*It is the responsibility of the API consumers to display the day pass as a product for the\nentire itinerary rather than three day passes!*\n\n### Example: Several single tickets\n\nIf you have two legs and need to buy two single tickets they will appear in each leg with the\nsame `product.id` but different use-`id`.",
"description": "Represents the use of a single instance of a fare product throughout the itinerary. It can\nbe used to cross-reference and de-duplicate fare products that are applicable for more than one\nleg.\n\nIf you want to uniquely identify the fare product itself (not its use) use the product's `id`.\n\n### Example: Day pass\n\nThe day pass is valid for both legs in the itinerary. It is listed as the applicable `product` for each leg,\nand the same FareProductUse id is shown, indicating that only one pass was used/bought.\n\n**Illustration**\n```yaml\nitinerary:\n leg1:\n fareProducts:\n id: \"AAA\" // id of a FareProductUse instance\n product:\n id: \"day-pass\" // product id\n name: \"Day Pass\"\n leg2:\n fareProducts:\n id: \"AAA\" // identical to leg1. the passenger needs to buy ONE pass, not two.\n product:\n id: \"day-pass\" // product id\n name: \"Day Pass\"\n```\n\n**It is the responsibility of the API consumers to display the day pass as a product for the\nentire itinerary rather than two day passes!**\n\n### Example: Several single tickets\n\nIf you have two legs and need to buy two single tickets they will appear in each leg with the\nsame `FareProduct.id` but different `FareProductUse.id`.\n\n**Illustration**\n```yaml\nitinerary:\n leg1:\n fareProducts:\n id: \"AAA\" // id of a FareProductUse instance, not product id\n product:\n id: \"single-ticket\" // product id\n name: \"Single Ticket\"\n leg2:\n fareProducts:\n id: \"BBB\" // different to leg1. the passenger needs to buy two single tickets.\n product:\n id: \"single-ticket\" // product id\n name: \"Single Ticket\"\n```",
"args": [],
"type": {
"kind": "NON_NULL",
Expand Down Expand Up @@ -3558,7 +3558,7 @@
},
{
"name": "steps",
"description": null,
"description": "The turn-by-turn navigation instructions.",
"args": [],
"type": {
"kind": "LIST",
Expand All @@ -3572,6 +3572,18 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "headsign",
"description": "For transit legs, the headsign that the vehicle shows at the stop where the passenger boards.\nFor non-transit legs, null.",
"args": [],
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "pickupType",
"description": "This is used to indicate if boarding this leg is possible only with special arrangements.",
Expand Down Expand Up @@ -8446,49 +8458,43 @@
"enumValues": [
{
"name": "NO_TRANSIT_CONNECTION",
"description": "No transit connection was found between the origin and destination withing the operating day or the next day",
"description": "No transit connection was found between the origin and destination within the operating day or\nthe next day, not even sub-optimal ones.",
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "NO_TRANSIT_CONNECTION_IN_SEARCH_WINDOW",
"description": "Transit connection was found, but it was outside the search window, see metadata for the next search window",
"description": "A transit connection was found, but it was outside the search window. See the metadata for a token\nfor retrieving the result outside the search window.",
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "OUTSIDE_SERVICE_PERIOD",
"description": "The date specified is outside the range of data currently loaded into the system",
"description": "The date specified is outside the range of data currently loaded into the system as it is too\nfar into the future or the past.\n\nThe specific date range of the system is configurable by an administrator and also depends on\nthe input data provided.",
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "OUTSIDE_BOUNDS",
"description": "The coordinates are outside the bounds of the data currently loaded into the system",
"description": "The coordinates are outside the geographic bounds of the transit and street data currently loaded\ninto the system and therefore cannot return any results.",
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "LOCATION_NOT_FOUND",
"description": "The specified location is not close to any streets or transit stops",
"description": "The specified location is not close to any streets or transit stops currently loaded into the\nsystem, even though it is generally within its bounds.\n\nThis can happen when there is only transit but no street data coverage at the location in\nquestion.",
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "NO_STOPS_IN_RANGE",
"description": "No stops are reachable from the location specified. You can try searching using a different access or egress mode",
"description": "No stops are reachable from the start or end locations specified.\n\nYou can try searching using a different access or egress mode, for example cycling instead of walking,\nincrease the walking/cycling/driving speed or have an administrator change the system's configuration\nso that stops further away are considered.",
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "WALKING_BETTER_THAN_TRANSIT",
"description": "The origin and destination are so close to each other, that walking is always better, but no direct mode was specified for the search",
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "SYSTEM_ERROR",
"description": "An unknown error happened during the search. The details have been logged to the server logs",
"description": "Transit connections were requested and found but because it is easier to just walk all the way\nto the destination they were removed.\n\nIf you want to still show the transit results, you need to make walking less desirable by\nincreasing the walk reluctance.",
"isDeprecated": false,
"deprecationReason": null
}
Expand Down Expand Up @@ -10059,7 +10065,7 @@
"args": [
{
"name": "language",
"description": "If translated headsign is found from gtfs translation.txt and wanted language is not same as\nfeed's language then returns wanted translation. Otherwise uses name from trip_headsign.txt.",
"description": "If a translated headsign is found from GTFS translation.txt and wanted language is not same as\nfeed's language then returns wanted translation. Otherwise uses name from trip_headsign.txt.",
"type": {
"kind": "SCALAR",
"name": "String",
Expand Down
8 changes: 4 additions & 4 deletions packages/core-utils/src/planQuery.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ query Plan(
effectiveStartDate
id
}
id
gtfsId: id
name
timezone
url
Expand Down Expand Up @@ -106,6 +106,7 @@ query Plan(
}
vertexType
}
headsign
interlineWithPreviousLeg
intermediateStops {
lat
Expand Down Expand Up @@ -156,7 +157,8 @@ query Plan(
id
}
color
id
gtfsId
id: gtfsId
longName
shortName
textColor
Expand Down Expand Up @@ -222,10 +224,8 @@ query Plan(
}
stopPosition
}

gtfsId
id
tripHeadsign
}
}
startTime
Expand Down
6 changes: 6 additions & 0 deletions packages/core-utils/src/query-gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,12 @@ export function generateOtp2Query(
prev[cur.inverseKey] = cur.high - cur.value + cur.low;
}
prev[cur.key] = cur.value;

// If we assign a value on true, return the value (or null) instead of a boolean.
if (cur.type === "CHECKBOX" && cur.truthValue) {
prev[cur.key] =
cur.value === true ? cur.truthValue : cur.falseValue ?? null;
}
return prev;
}, {}) as ModeSettingValues;

Expand Down
2 changes: 1 addition & 1 deletion packages/core-utils/src/query.js
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ export function expandOtpFlexMode(mode) {
const modes = reduceOtpFlexModes(mode.split(","));
return modes
.map(m => {
// If both the expanded and shrunk modes are included, remove the exapnded one
// If both the expanded and shrunk modes are included, remove the expanded one
if (m === "FLEX_EGRESS" || m === "FLEX_ACCESS" || m === "FLEX_DIRECT") {
if (mode.includes("FLEX")) return "";
}
Expand Down
10 changes: 0 additions & 10 deletions packages/core-utils/src/ui.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,9 @@
import bowser from "bowser";

export function isMobile(): boolean {
// TODO: consider using 3rd-party library?
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
navigator.userAgent
);
}

/**
* Returns true if the user is using a [redacted] browser
*/
export function isIE(): boolean {
return bowser.parse(navigator.userAgent).browser === "Internet Explorer";
}

/**
* Enables scrolling for a specified selector, while disabling scrolling for all
* other targets. This is adapted from https://stackoverflow.com/a/41601290/915811
Expand Down
Loading

0 comments on commit 297cc1e

Please sign in to comment.