Skip to content

Commit

Permalink
feat(exception based scheduling): initial work
Browse files Browse the repository at this point in the history
  • Loading branch information
philip-cline committed Nov 8, 2023
1 parent 7682f9e commit a36bea3
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 27 deletions.
2 changes: 2 additions & 0 deletions lib/editor/actions/editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -513,6 +513,8 @@ export function fetchBaseGtfs ({
# Fetch dates to ensure we can do validation in the UI
# (avoid duplicate dates).
dates
# Fetch exemplar for display of exception based service in calendar select
exemplar
}
stops (limit: -1) {
id
Expand Down
2 changes: 2 additions & 0 deletions lib/editor/components/ScheduleExceptionForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ export default class ScheduleExceptionForm extends Component<Props> {
return 'Swap, add, or remove'
case EXCEPTION_EXEMPLARS.NO_SERVICE:
return toSentenceCase(exemplar.replace('_', ' '))
case EXCEPTION_EXEMPLARS.EXCEPTION_SERVICE:
return 'Exception Based Service'
default:
return toSentenceCase(exemplar)
}
Expand Down
60 changes: 40 additions & 20 deletions lib/editor/components/timetable/CalendarSelect.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ import Select from 'react-select'

import * as activeActions from '../../actions/active'
import {entityIsNew} from '../../util/objects'

import type {Pattern, GtfsRoute, Feed, ServiceCalendar, Trip, TripCounts} from '../../../types'
import type {Pattern, GtfsRoute, Feed, ServiceCalendar, ScheduleException, Trip, TripCounts} from '../../../types'

type CalendarOption = {
calendar: ServiceCalendar,
Expand All @@ -24,6 +23,7 @@ type Props = {
activeCalendar: ?ServiceCalendar,
activePattern: Pattern,
calendars: Array<ServiceCalendar>,
exceptionBasedCalendars: Array<ScheduleException>,
feedSource: Feed,
route: GtfsRoute,
setActiveEntity: typeof activeActions.setActiveEntity,
Expand All @@ -49,28 +49,36 @@ export default class CalendarSelect extends Component<Props> {
<span title={title}>
<Icon type='calendar-o' /> {label}
{' '}
<BsLabel
bsStyle={patternTrips ? 'success' : 'default'}
title={`Calendar has ${patternTrips} trips for pattern`}>
<Icon type='bars' /> {patternTrips}
</BsLabel>
{/** {' '}
<BsLabel
title={`Calendar has trips for ${routeCount} routes`}>
<Icon type='bus' /> {routeCount}
</BsLabel> **/}
{' '}
<BsLabel
title={`Calendar has ${totalTrips} trips for feed`}>
<Icon type='building-o' /> {totalTrips}
</BsLabel>
{/* $FlowFixMe: need to add two types of options */}
{option.type !== 'exception-based'
? <>
<BsLabel
bsStyle={patternTrips ? 'success' : 'default'}
title={`Calendar has ${patternTrips} trips for pattern`}>
<Icon type='bars' /> {patternTrips}
</BsLabel>
{/** {' '}
<BsLabel
title={`Calendar has trips for ${routeCount} routes`}>
<Icon type='bus' /> {routeCount}
</BsLabel> **/}
{' '}
<BsLabel
title={`Calendar has ${totalTrips} trips for feed`}>
<Icon type='building-o' /> {totalTrips}
</BsLabel>
</>
: <>
<Icon type='warning' />(Exception based calendar)
</>
}
</span>
)
}

_onChange = (value: CalendarOption) => {
const {activePattern, feedSource, route, setActiveEntity} = this.props
const calendar = value && value.calendar
const calendar = value && (value.calendar || value)
setActiveEntity(
feedSource.id,
'route',
Expand All @@ -94,9 +102,9 @@ export default class CalendarSelect extends Component<Props> {
}

_getOptions = (): Array<CalendarOption> => {
const {activePattern, calendars, tripCounts, trips} = this.props
const {activePattern, calendars, exceptionBasedCalendars, tripCounts, trips} = this.props
const patternId = activePattern && activePattern.patternId
const calendarOptions: Array<CalendarOption> = calendars && activePattern
let calendarOptions: Array<CalendarOption> = calendars && activePattern
? calendars
.map(calendar => ({
label: calendar.description || calendar.service_id,
Expand All @@ -111,6 +119,18 @@ export default class CalendarSelect extends Component<Props> {
}))
: []

// Add exception based calendars to the list
// TODO: trip counts (total v pattern)
const exceptionBasedCalendarOptions = exceptionBasedCalendars && exceptionBasedCalendars.map(exception => ({
label: exception.name || exception.id,
value: exception.name,
type: 'exception-based',
service_id: exception.name
}))

// $FlowFixMe: we need two types of options
calendarOptions = calendarOptions.concat(exceptionBasedCalendarOptions)

return calendarOptions
.sort((a, b) => {
return b.patternTrips - a.patternTrips
Expand Down
23 changes: 17 additions & 6 deletions lib/editor/components/timetable/TimetableHeader.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@ import OptionButton from '../../../common/components/OptionButton'
import HourMinuteInput from '../HourMinuteInput'
import {getTableById} from '../../util/gtfs'
import { getComponentMessages } from '../../../common/util/config'
import { EXCEPTION_EXEMPLARS } from '../../util'
import type {TripValidationIssues} from '../../selectors/timetable'
import type {Feed, GtfsRoute, Pattern, ServiceCalendar, TripCounts} from '../../../types'
import type {Feed, GtfsRoute, Pattern, ServiceCalendar, ScheduleException, TripCounts} from '../../../types'
import type {EditorTables, TimetableState} from '../../../types/reducers'

import PatternSelect from './PatternSelect'
Expand Down Expand Up @@ -117,7 +118,15 @@ export default class TimetableHeader extends Component<Props> {
} = this.props
const {edited, hideDepartureTimes, selected, trips, useSecondsInOffset} = timetable
const calendars: Array<ServiceCalendar> = getTableById(tableData, 'calendar')
const activeCalendar = calendars.find(c => c.service_id === activeScheduleId)
const scheduleExceptions: Array<ScheduleException> = getTableById(tableData, 'scheduleexception')
const exceptionBasedCalendars = scheduleExceptions && scheduleExceptions.reduce((calendars, exception) => {
if (exception.exemplar === EXCEPTION_EXEMPLARS.EXCEPTION_SERVICE) {
calendars.push({...exception, service_id: exception.name})
}
return calendars
}, [])

const activeCalendar = calendars.find(c => c.service_id === activeScheduleId) || exceptionBasedCalendars.find(c => c.name === activeScheduleId)
const headerStyle = {
backgroundColor: 'white'
}
Expand Down Expand Up @@ -370,14 +379,16 @@ export default class TimetableHeader extends Component<Props> {
</Col>
<Col xs={12} sm={3} data-test-id='calendar-select-container'>
<CalendarSelect
activePattern={activePattern}
route={route}
feedSource={feedSource}
activeCalendar={activeCalendar}
activePattern={activePattern}
calendars={calendars}
exceptionBasedCalendars={exceptionBasedCalendars}
feedSource={feedSource}
route={route}
setActiveEntity={setActiveEntity}
trips={trips}
tripCounts={tripCounts}
trips={trips} />
/>
</Col>
<Col sm={3}>
{/* Edit timetable buttons */}
Expand Down
3 changes: 2 additions & 1 deletion lib/editor/util/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ export const EXCEPTION_EXEMPLARS = {
SUNDAY: 6,
NO_SERVICE: 7,
CUSTOM: 8,
SWAP: 9
SWAP: 9,
EXCEPTION_SERVICE: 10
}

export const ROUTE_STATUS_CODES = {
Expand Down
1 change: 1 addition & 0 deletions lib/types/reducers.js
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ export type EditorTables = {
tripPatterns?: Array<Pattern>
}>,
schedule_exceptions: Array<{
exemplar: number,
id: number,
name: string
}>,
Expand Down

0 comments on commit a36bea3

Please sign in to comment.