Skip to content

Commit

Permalink
Merge pull request #227 from ibi-group/upstream-merge-2024-09-30
Browse files Browse the repository at this point in the history
Upstream merge 2024-09-30
  • Loading branch information
miles-grant-ibigroup authored Sep 30, 2024
2 parents e668156 + 00fdbff commit ccb97b4
Show file tree
Hide file tree
Showing 99 changed files with 1,451 additions and 701 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/smoke-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ jobs:
strategy:
matrix:
locations:
#- name: seattle
# sleep: 30
- name: seattle
sleep: 30
- name: atlanta
sleep: 15
- name: houston
Expand Down
2 changes: 1 addition & 1 deletion client/.env.development
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
VITE_API_URL=http://localhost:8080/otp/transmodel/v3
VITE_DEBUG_STYLE_URL=http://localhost:8080/otp/routers/default/inspector/vectortile/style.json
VITE_GRAPHIQL_URL=http://localhost:8080/graphiql?flavor=transmodel
VITE_GRAPHIQL_URL=http://localhost:8080/graphiql?flavor=transmodel
18 changes: 18 additions & 0 deletions client/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
},
"dependencies": {
"@googlemaps/polyline-codec": "1.0.28",
"@js-temporal/polyfill": "0.4.4",
"bootstrap": "5.3.3",
"graphql": "16.9.0",
"graphql-request": "7.1.0",
Expand Down
13 changes: 8 additions & 5 deletions client/src/components/ItineraryList/ItineraryHeaderContent.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { TripPattern } from '../../gql/graphql.ts';
import { TIME_BOX_WIDTH, useHeaderContentStyleCalculations } from './useHeaderContentStyleCalculations.ts';
import { ItineraryHeaderLegContent } from './ItineraryHeaderLegContent.tsx';
import { useMemo } from 'react';
import { useContext, useMemo } from 'react';
import { formatTime } from '../../util/formatTime.ts';
import { TimeZoneContext } from '../../hooks/TimeZoneContext.ts';

export function ItineraryHeaderContent({
tripPattern,
Expand All @@ -24,14 +25,16 @@ export function ItineraryHeaderContent({
latestEndTime,
);

const timeZone = useContext(TimeZoneContext);

const formattedStartTime = useMemo(
() => formatTime(tripPattern.expectedStartTime, 'short'),
[tripPattern.expectedStartTime],
() => formatTime(tripPattern.expectedStartTime, timeZone, 'short'),
[tripPattern.expectedStartTime, timeZone],
);

const formattedEndTime = useMemo(
() => formatTime(tripPattern.expectedEndTime, 'short'),
[tripPattern.expectedEndTime],
() => formatTime(tripPattern.expectedEndTime, timeZone, 'short'),
[tripPattern.expectedEndTime, timeZone],
);

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { ItineraryHeaderContent } from './ItineraryHeaderContent.tsx';
import { useEarliestAndLatestTimes } from './useEarliestAndLatestTimes.ts';
import { ItineraryDetails } from './ItineraryDetails.tsx';
import { ItineraryPaginationControl } from './ItineraryPaginationControl.tsx';
import { useContext } from 'react';
import { TimeZoneContext } from '../../hooks/TimeZoneContext.ts';

export function ItineraryListContainer({
tripQueryResult,
Expand All @@ -21,6 +23,7 @@ export function ItineraryListContainer({
}) {
const [earliestStartTime, latestEndTime] = useEarliestAndLatestTimes(tripQueryResult);
const { containerRef, containerWidth } = useContainerWidth();
const timeZone = useContext(TimeZoneContext);

return (
<section className="itinerary-list-container below-content" ref={containerRef}>
Expand Down Expand Up @@ -56,6 +59,9 @@ export function ItineraryListContainer({
</Accordion.Item>
))}
</Accordion>
<div className="time-zone-info">
All times in <code>{timeZone}</code>
</div>
</section>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ export function ItineraryPaginationControl({
return (
<div style={{ display: 'flex', justifyContent: 'space-evenly', margin: '1rem 0 ' }}>
<Button
variant="outline-primary"
size="sm"
disabled={!previousPageCursor || loading}
onClick={() => {
previousPageCursor && onPagination(previousPageCursor);
Expand All @@ -22,6 +24,8 @@ export function ItineraryPaginationControl({
Previous page
</Button>{' '}
<Button
variant="outline-primary"
size="sm"
disabled={!nextPageCursor || loading}
onClick={() => {
nextPageCursor && onPagination(nextPageCursor);
Expand Down
9 changes: 6 additions & 3 deletions client/src/components/ItineraryList/LegTime.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { formatTime } from '../../util/formatTime.ts';
import { useContext } from 'react';
import { TimeZoneContext } from '../../hooks/TimeZoneContext.ts';

export function LegTime({
aimedTime,
Expand All @@ -9,18 +11,19 @@ export function LegTime({
expectedTime: string;
hasRealtime: boolean;
}) {
const timeZone = useContext(TimeZoneContext);
return aimedTime !== expectedTime ? (
<>
<span title={expectedTime} style={{ color: 'red' }}>
{formatTime(expectedTime, 'short')}
{formatTime(expectedTime, timeZone, 'short')}
</span>
<span title={aimedTime} style={{ textDecoration: 'line-through' }}>
{formatTime(aimedTime, 'short')}
{formatTime(aimedTime, timeZone, 'short')}
</span>
</>
) : (
<span title={expectedTime}>
{formatTime(expectedTime, 'short')}
{formatTime(expectedTime, timeZone, 'short')}
{hasRealtime && <span> (on time)</span>}
</span>
);
Expand Down
40 changes: 0 additions & 40 deletions client/src/components/SearchBar/DateInputField.tsx

This file was deleted.

42 changes: 42 additions & 0 deletions client/src/components/SearchBar/DateTimeInputField.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { Form } from 'react-bootstrap';
import { TripQueryVariables } from '../../gql/graphql.ts';
import { ChangeEvent, useCallback, useContext } from 'react';
import { Temporal } from '@js-temporal/polyfill';
import { TimeZoneContext } from '../../hooks/TimeZoneContext.ts';

export function DateTimeInputField({
tripQueryVariables,
setTripQueryVariables,
}: {
tripQueryVariables: TripQueryVariables;
setTripQueryVariables: (tripQueryVariables: TripQueryVariables) => void;
}) {
const timeZone = useContext(TimeZoneContext);
const current = Temporal.Instant.from(tripQueryVariables.dateTime)
.toZonedDateTimeISO(timeZone)
.toPlainDateTime()
.toString({ smallestUnit: 'minute', calendarName: 'never' });

const onChange = useCallback(
(event: ChangeEvent<HTMLInputElement>) => {
const dateTime = Temporal.PlainDateTime.from(event.target.value)
.toZonedDateTime(timeZone)
.toString({ calendarName: 'never', timeZoneName: 'never' });

setTripQueryVariables({
...tripQueryVariables,
dateTime: dateTime,
});
},
[tripQueryVariables, setTripQueryVariables, timeZone],
);

return (
<Form.Group>
<Form.Label column="sm" htmlFor="timePicker" title={'Time zone: ' + timeZone}>
Time
</Form.Label>
<Form.Control type="datetime-local" id="timePicker" size="sm" onChange={onChange} value={current} />
</Form.Group>
);
}
17 changes: 12 additions & 5 deletions client/src/components/SearchBar/GraphiQLRouteButton.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,25 @@
import { Button } from 'react-bootstrap';
import { TripQueryVariables } from '../../gql/graphql.ts';
import { queryAsString } from '../../static/query/tripQuery.tsx';
import graphqlIcon from '../../static/img/graphql-solid.svg';

const graphiQLUrl = import.meta.env.VITE_GRAPHIQL_URL;

function GraphiQLRouteButton({ tripQueryVariables }: { tripQueryVariables: TripQueryVariables }) {
const formattedVariables = encodeURIComponent(JSON.stringify(tripQueryVariables));
const formattedQuery = encodeURIComponent(queryAsString);

const hint = 'Open in GraphiQL';

return (
<div className="search-bar-route-button-wrapper">
<Button href={graphiQLUrl + '&query=' + formattedQuery + '&variables=' + formattedVariables} target={'_blank'}>
GraphiQL
</Button>
</div>
<Button
title={hint}
href={graphiQLUrl + '&query=' + formattedQuery + '&variables=' + formattedVariables}
target={'_blank'}
>
<img alt={hint} title={hint} src={graphqlIcon} width="20" height="20" className="d-inline-block align-middle" />
</Button>
);
}

export default GraphiQLRouteButton;
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@ export function ItineraryFilterDebugSelect({
return (
<Form.Group>
<Form.Label column="sm" htmlFor="itineraryDebugFilterSelect">
Itinerary filter debug
Filter debug
</Form.Label>
<Form.Select
id="itineraryDebugFilterSelect"
size="sm"
className="input-medium"
onChange={(e) => {
setTripQueryVariables({
...tripQueryVariables,
Expand Down
1 change: 1 addition & 0 deletions client/src/components/SearchBar/LocationInputField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export function LocationInputField({ location, id, label }: { location: Location
id={id}
size="sm"
placeholder="[Click in map]"
className="input-medium"
// Intentionally empty for now, but needed because of
// https://react.dev/reference/react-dom/components/input#controlling-an-input-with-a-state-variable
onChange={() => {}}
Expand Down
3 changes: 2 additions & 1 deletion client/src/components/SearchBar/NumTripPatternsInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,15 @@ export function NumTripPatternsInput({
return (
<Form.Group>
<Form.Label column="sm" htmlFor="numTripPatternsInput">
Number of trip patterns
Num. results
</Form.Label>
<Form.Control
type="number"
id="numTripPatternsInput"
size="sm"
placeholder="12"
min={1}
className="input-small"
value={tripQueryVariables.numTripPatterns || ''}
onChange={(event) =>
setTripQueryVariables({
Expand Down
34 changes: 20 additions & 14 deletions client/src/components/SearchBar/SearchBar.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { Button, Spinner } from 'react-bootstrap';
import { Button, ButtonGroup, Spinner } from 'react-bootstrap';
import { ServerInfo, TripQueryVariables } from '../../gql/graphql.ts';
import { LocationInputField } from './LocationInputField.tsx';
import { DepartureArrivalSelect } from './DepartureArrivalSelect.tsx';
import { TimeInputField } from './TimeInputField.tsx';
import { DateInputField } from './DateInputField.tsx';
import { DateTimeInputField } from './DateTimeInputField.tsx';
import { SearchWindowInput } from './SearchWindowInput.tsx';
import { AccessSelect } from './AccessSelect.tsx';
import { EgressSelect } from './EgressSelect.tsx';
Expand All @@ -16,6 +15,7 @@ import { ServerInfoTooltip } from './ServerInfoTooltip.tsx';
import { useRef, useState } from 'react';
import logo from '../../static/img/otp-logo.svg';
import GraphiQLRouteButton from './GraphiQLRouteButton.tsx';
import WheelchairAccessibleCheckBox from './WheelchairAccessibleCheckBox.tsx';

type SearchBarProps = {
onRoute: () => void;
Expand All @@ -40,8 +40,7 @@ export function SearchBar({ onRoute, tripQueryVariables, setTripQueryVariables,
<LocationInputField location={tripQueryVariables.from} label="From" id="fromInputField" />
<LocationInputField location={tripQueryVariables.to} label="To" id="toInputField" />
<DepartureArrivalSelect tripQueryVariables={tripQueryVariables} setTripQueryVariables={setTripQueryVariables} />
<TimeInputField tripQueryVariables={tripQueryVariables} setTripQueryVariables={setTripQueryVariables} />
<DateInputField tripQueryVariables={tripQueryVariables} setTripQueryVariables={setTripQueryVariables} />
<DateTimeInputField tripQueryVariables={tripQueryVariables} setTripQueryVariables={setTripQueryVariables} />
<NumTripPatternsInput tripQueryVariables={tripQueryVariables} setTripQueryVariables={setTripQueryVariables} />
<SearchWindowInput tripQueryVariables={tripQueryVariables} setTripQueryVariables={setTripQueryVariables} />
<AccessSelect tripQueryVariables={tripQueryVariables} setTripQueryVariables={setTripQueryVariables} />
Expand All @@ -52,17 +51,24 @@ export function SearchBar({ onRoute, tripQueryVariables, setTripQueryVariables,
tripQueryVariables={tripQueryVariables}
setTripQueryVariables={setTripQueryVariables}
/>
<WheelchairAccessibleCheckBox
tripQueryVariables={tripQueryVariables}
setTripQueryVariables={setTripQueryVariables}
/>

<div className="search-bar-route-button-wrapper">
<Button variant="primary" onClick={() => onRoute()} disabled={loading}>
{loading && (
<>
<Spinner as="span" animation="border" size="sm" role="status" aria-hidden="true" />{' '}
</>
)}
Route
</Button>
<ButtonGroup>
<Button variant="primary" onClick={() => onRoute()} disabled={loading}>
{loading && (
<>
<Spinner as="span" animation="border" size="sm" role="status" aria-hidden="true" />{' '}
</>
)}
Route
</Button>
<GraphiQLRouteButton tripQueryVariables={tripQueryVariables}></GraphiQLRouteButton>
</ButtonGroup>
</div>
<GraphiQLRouteButton tripQueryVariables={tripQueryVariables}></GraphiQLRouteButton>
</div>
);
}
1 change: 1 addition & 0 deletions client/src/components/SearchBar/SearchWindowInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export function SearchWindowInput({
size="sm"
placeholder="(in minutes)"
min={1}
className="input-small"
value={tripQueryVariables.searchWindow || ''}
onChange={(event) =>
setTripQueryVariables({
Expand Down
Loading

0 comments on commit ccb97b4

Please sign in to comment.