Skip to content

Commit

Permalink
fix(editor): misc. editor fixes for SQL editor
Browse files Browse the repository at this point in the history
  • Loading branch information
landonreed committed Feb 1, 2018
1 parent b570069 commit 1a2ffd0
Show file tree
Hide file tree
Showing 30 changed files with 421 additions and 202 deletions.
14 changes: 7 additions & 7 deletions gtfs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -223,24 +223,24 @@
required: true
inputType: DROPDOWN
options:
- value: 'IN_PROGRESS'
- value: 0
text: 'In Progress'
- value: 'PENDING_APPROVAL'
- value: 1
text: 'Pending Approval'
- value: 'APPROVED'
- value: 2
text: 'Approved'
columnWidth: 6
adminOnly: true
# helpContent: The route_id field contains an ID that uniquely identifies a route. The route_id is dataset unique.
- name: publiclyVisible
- name: publicly_visible
datatools: true
displayName: Public?
required: true
inputType: DROPDOWN
options:
- value: false
- value: 0
text: 'No'
- value: true
- value: 1
text: 'Yes'
columnWidth: 6
adminOnly: true
Expand Down Expand Up @@ -359,7 +359,7 @@
required: false
inputType: TEXT
columnWidth: 6
helpContent: "The trip_headsign field contains the text that appears on a sign that identifies the trip's destination to passengers. Use this field to distinguish between different patterns of service in the same route. If the headsign changes during a trip, you can override the trip_headsign by specifying values for the thestop_headsign field in stop_times.txt."
helpContent: "The trip_headsign field contains the text that appears on a sign that identifies the trip's destination to passengers. Use this field to distinguish between different patterns of service in the same route. If the headsign changes during a trip, you can override the trip_headsign by specifying values for the the stop_headsign field in stop_times.txt."
- name: "trip_short_name"
required: false
inputType: TEXT
Expand Down
4 changes: 4 additions & 0 deletions lib/common/util/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ export function getConfigProperty (propertyString: string): ?any {
return objectPath.get(window.DT_CONFIG, propertyString)
}

export function getGtfsSpec (): Array<any> {
return window.DT_CONFIG.modules.editor.spec
}

export function getGtfsPlusSpec (): Array<GtfsPlusTable> {
return window.DT_CONFIG.modules.gtfsplus.spec
}
Expand Down
2 changes: 1 addition & 1 deletion lib/editor/actions/active.js
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ export function saveEntity (feedId, entity, component) {
.then(savedEntity => {
const namespace = getEditorNamespace(feedId, getState())
// Refetch entity and replace in store
dispatch(fetchGTFSEntities({
return dispatch(fetchGTFSEntities({
namespace,
id: savedEntity.id,
type: component,
Expand Down
27 changes: 22 additions & 5 deletions lib/editor/actions/map/stopStrategies.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import along from '@turf/along'
import ll from '@conveyal/lonlat'
import clone from 'lodash.clonedeep'
import lineDistance from 'turf-line-distance'
import lineSlice from 'turf-line-slice'
import lineString from 'turf-lineString'
import point from 'turf-point'

import {updateActiveGtfsEntity, saveActiveGtfsEntity} from '../active'
import {generateUID} from '../../../common/util/util'
import {POINT_TYPE} from '../../constants'
import {newGtfsEntity} from '../editor'
import {setErrorMessage} from '../../../manager/actions/status'
import {getTableById} from '../../util/gtfs'
Expand Down Expand Up @@ -180,7 +185,7 @@ export function addStopToPattern (pattern, stop, index) {
dispatch(updateActiveGtfsEntity(pattern, 'trippattern', {patternStops}))
// saveActiveGtfsEntity('trippattern')
const {stop_lon: lng, stop_lat: lat} = stop
return dispatch(extendPatternToPoint(pattern, endPoint, {lng, lat}))
return dispatch(extendPatternToPoint(pattern, endPoint, {lng, lat}, stop))
} else {
// If shape coordinates do not exist, add pattern stop and get shape
// between stops (if multiple stops exist).
Expand Down Expand Up @@ -220,24 +225,36 @@ export function addStopToPattern (pattern, stop, index) {
* Extends shape of input pattern from specified end point to new end point,
* optionally following streets if the setting is enabled.
*/
function extendPatternToPoint (pattern, endPoint, newEndPoint) {
function extendPatternToPoint (pattern, endPoint, newEndPoint, stop = null) {
return async function (dispatch, getState) {
const {followStreets} = getState().editor.editSettings.present
const {controlPoints, patternSegments} = getControlPoints(getState())
const clonedControlPoints = clone(controlPoints)
let newShape
if (followStreets) {
newShape = await getPolyline([endPoint, newEndPoint])
}
// get single coordinate for straight line if polyline fails or if not following streets
if (!newShape) {
newShape = [ll.toCoordinates(newEndPoint)]
newShape = [ll.toCoordinates(endPoint), ll.toCoordinates(newEndPoint)]
}
// append newShape coords to existing pattern coords
const shape = {type: 'LineString', coordinates: [...pattern.shape.coordinates, ...newShape]}
// Update pattern geometry
// If extending to a stop, add control point for stop
if (stop) {
const controlPoint = {
id: generateUID(),
point: point(ll.toCoordinates(newEndPoint)),
pointType: POINT_TYPE.STOP,
distance: lineDistance(lineString(newShape), 'meters'),
stopId: stop.stop_id
}
clonedControlPoints.push(controlPoint)
}
// Update pattern geometry and control points
dispatch(updatePatternGeometry({
// FIXME Should control points be updated here?
controlPoints,
controlPoints: clonedControlPoints,
patternSegments: [...patternSegments, newShape]
}))
await dispatch(saveActiveGtfsEntity('trippattern'))
Expand Down
28 changes: 17 additions & 11 deletions lib/editor/actions/trip.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,51 +27,57 @@ export const removeTrips = createAction('REMOVE_TRIPS')
export function fetchTripsForCalendar (feedId, pattern, calendarId) {
return function (dispatch, getState) {
const namespace = getEditorNamespace(feedId, getState())
// FIXME: pattern integer id hack (shouldn't need quotes around pattern_id var)
// This fetches patterns on the pattern_id field (rather than ID) because
// pattern_id is needed to join on the nested trips table
const query = `query ($namespace: String, $pattern_id: [String], $service_id: [String]) {
feed(namespace: $namespace) {
patterns (pattern_id: $pattern_id) {
id: pattern_id
trips (service_id: $service_id) {
trips (service_id: $service_id, limit: -1) {
id
tripId: trip_id
tripHeadsign: trip_headsign
tripShortName: trip_short_name
blockId: block_id
directionId: direction_id
route_id
shape_id
wheelchair_accessible
bikes_allowed
pattern_id
service_id
stopTimes: stop_times {
stopTimes: stop_times (limit: -1) {
stopId: stop_id
stopSequence: stop_sequence
arrivalTime: arrival_time
departureTime: departure_time
stopHeadsign: stop_headsign
shape_dist_traveled: shape_dist_traveled
pickup_type
drop_off_type
timepoint
}
}
}
}
}`
dispatch(requestingTripsForCalendar({feedId, pattern, calendarId, query}))
// FIXME: string casting pattern id
return dispatch(fetchGraphQL({query, variables: {namespace, pattern_id: `${pattern.id}`, service_id: calendarId}}))
return dispatch(fetchGraphQL({query, variables: {namespace, pattern_id: pattern.patternId, service_id: calendarId}}))
.then(res => res.json())
.then(data => dispatch(receiveTripsForCalendar({trips: data.feed.patterns[0].trips, pattern})))
.catch(err => {
console.log(err)
dispatch(setErrorMessage({message: 'Could not fetch trips for pattern'}))
})
}
}

export function saveTripsForCalendar (feedId, pattern, calendarId, trips) {
return function (dispatch, getState) {
let errorCount = 0
const errorIndexes = []
// FIXME: add rest of mapping
trips = trips
.map(t => ({
serviceId: t.calendarId,
...t
}))
.map(snakeCaseKeys)
trips = trips.map(snakeCaseKeys)
dispatch(savingTrips({feedId, pattern, calendarId, trips}))
return Promise.all(trips.filter(t => t).map((trip, index) => {
const tripExists = !entityIsNew(trip) && trip.id !== null
Expand Down
31 changes: 19 additions & 12 deletions lib/editor/actions/tripPattern.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ import {createAction} from 'redux-actions'
import snakeCaseKeys from 'snakecase-keys'

import {secureFetch} from '../../common/actions'
import {setActiveGtfsEntity, updateEditSetting} from './active'
import {entityIsNew, tripPatternToGtfs} from '../util/objects'
import {fetchGTFSEntities} from '../../manager/actions/versions'
import {updateEditSetting} from './active'
import {entityIsNew} from '../util/objects'
import {getEditorNamespace} from '../util/gtfs'

// TRIP PATTERNS

Expand All @@ -13,7 +15,6 @@ export const undoActiveTripPatternEdits = createAction('UNDO_TRIP_PATTERN_EDITS'
export const setActiveStop = createAction('SET_ACTIVE_PATTERN_STOP')
export const togglingPatternEditing = createAction('TOGGLE_PATTERN_EDITING')
export const setActivePatternSegment = createAction('SET_ACTIVE_PATTERN_SEGMENT')
const savedTripPattern = createAction('SAVED_TRIP_PATTERN')
export const resnapStops = createAction('RESNAP_STOPS')

export function togglePatternEditing () {
Expand Down Expand Up @@ -44,7 +45,9 @@ export function saveTripPattern (feedId, tripPattern) {
return function (dispatch, getState) {
const patternIsNew = entityIsNew(tripPattern)
const method = patternIsNew ? 'post' : 'put'
const routeId = tripPattern.routeId
// Route ID needed for re-fetch is the ID field of the active entity (route)
// NOTE: The pattern being saved is the active **sub**-entity.
const routeId = getState().editor.data.active.entity.id
const data = snakeCaseKeys(tripPattern)
// Convert control points and pattern segments into shape points
// FIXME: ready shape_points for insertion into shapes table
Expand All @@ -56,14 +59,18 @@ export function saveTripPattern (feedId, tripPattern) {
data.id = patternIsNew ? null : tripPattern.id
return dispatch(secureFetch(url, method, data))
.then(res => res.json())
.then(tripPattern => {
dispatch(savedTripPattern({feedId, tripPattern: tripPatternToGtfs(tripPattern)}))
if (patternIsNew) {
dispatch(setActiveGtfsEntity(feedId, 'route', routeId, 'trippattern', tripPattern.id))
}
// dispatch(fetchTripPatternsForRoute(feedId, routeId))
// const tp = tripPattern
return tripPattern
.then(newTripPattern => {
const namespace = getEditorNamespace(feedId, getState())
// // Refetch entity and replace in store
console.log(`setting active pattern to ${newTripPattern.id}`)
return dispatch(fetchGTFSEntities({
namespace,
id: routeId,
type: 'route',
editor: true,
replaceNew: patternIsNew,
patternId: newTripPattern.id
}))
})
}
}
31 changes: 22 additions & 9 deletions lib/editor/components/EditorFeedSourcePanel.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import Icon from '@conveyal/woonerf/components/icon'
import React, {Component, PropTypes} from 'react'
import { Panel, Row, Col, ButtonGroup, Button, Glyphicon, ListGroup, ListGroupItem } from 'react-bootstrap'
import { LinkContainer } from 'react-router-bootstrap'
import {Panel, Row, Col, ButtonGroup, Button, Glyphicon, ListGroup, ListGroupItem} from 'react-bootstrap'
import {LinkContainer} from 'react-router-bootstrap'
import moment from 'moment'

import CreateSnapshotModal from '../../editor/components/CreateSnapshotModal'
import ConfirmModal from '../../common/components/ConfirmModal'
import { getComponentMessages, getMessage, getConfigProperty } from '../../common/util/config'
import {getComponentMessages, getMessage, getConfigProperty} from '../../common/util/config'
import {isEditingDisabled} from '../../manager/util'

export default class EditorFeedSourcePanel extends Component {
static propTypes = {
Expand Down Expand Up @@ -43,20 +44,27 @@ export default class EditorFeedSourcePanel extends Component {
})
}

isSnapshotActive = snapshot => {
return snapshot.feedLoadResult &&
snapshot.feedLoadResult.uniqueIdentifier === this.props.feedSource.editorNamespace
}

render () {
const {
feedSource,
project,
user
} = this.props
const disabled = !user.permissions.hasFeedPermission(project.organizationId, project.id, feedSource.id, 'manage-feed')
const editDisabled = !user.permissions.hasFeedPermission(project.organizationId, project.id, feedSource.id, 'edit-gtfs')
const editDisabled = isEditingDisabled(user, feedSource, project)
const hasVersions = feedSource && feedSource.feedVersions && feedSource.feedVersions.length > 0
const currentSnapshot = feedSource.editorSnapshots && feedSource.editorSnapshots.length
? feedSource.editorSnapshots.find(s => s.current)
? feedSource.editorSnapshots.find(this.isSnapshotActive)
: null
const inactiveSnapshots = feedSource.editorSnapshots
? feedSource.editorSnapshots.filter(s => !s.current).sort((a, b) => b.snapshotTime - a.snapshotTime)
? feedSource.editorSnapshots
.filter(s => !this.isSnapshotActive(s))
.sort((a, b) => b.snapshotTime - a.snapshotTime)
: []
return (
<Row>
Expand All @@ -67,11 +75,13 @@ export default class EditorFeedSourcePanel extends Component {
<Col xs={9}>
{feedSource.editorSnapshots && feedSource.editorSnapshots.length
? <div>
{/* This is the active snapshot */}
<Panel bsStyle='success' header={<h3>Active snapshot</h3>}>
{currentSnapshot
? <ListGroup fill>
<SnapshotItem
modal={this.refs.confirmModal}
isActive
disabled={disabled}
snapshot={currentSnapshot}
{...this.props} />
Expand All @@ -81,6 +91,7 @@ export default class EditorFeedSourcePanel extends Component {
</ListGroup>
}
</Panel>
{/* These are the inactive snapshots */}
<Panel bsStyle='warning' header={<h3>Inactive snapshots</h3>}>
<ListGroup fill>
{inactiveSnapshots.length === 0
Expand All @@ -90,6 +101,7 @@ export default class EditorFeedSourcePanel extends Component {
<SnapshotItem
modal={this.refs.confirmModal}
key={s.id}
isActive={false}
disabled={disabled}
snapshot={s}
{...this.props} />
Expand Down Expand Up @@ -145,6 +157,7 @@ export default class EditorFeedSourcePanel extends Component {

class SnapshotItem extends Component {
static propTypes = {
isActive: PropTypes.bool,
modal: PropTypes.object.isRequired,
snapshot: PropTypes.object.isRequired,
feedSource: PropTypes.object.isRequired
Expand Down Expand Up @@ -175,7 +188,7 @@ class SnapshotItem extends Component {
}

render () {
const {disabled, snapshot} = this.props
const {disabled, isActive, snapshot} = this.props
const dateFormat = getConfigProperty('application.date_format')
const timeFormat = 'h:MMa'
return (
Expand All @@ -190,9 +203,9 @@ class SnapshotItem extends Component {
<ButtonGroup className='pull-right' style={{marginTop: '-20px'}}>
<Button
bsSize='small'
disabled={snapshot.current || disabled}
disabled={isActive || disabled}
onClick={this._onRestoreSnapshot}>
{snapshot.current
{isActive
? <span><Icon type='check-circle' /> {getMessage(this.messages, 'active')}</span>
: <span><Glyphicon glyph='pencil' /> {getMessage(this.messages, 'restore')}</span>
}
Expand Down
8 changes: 6 additions & 2 deletions lib/editor/components/FareRulesForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import React, {Component, PropTypes} from 'react'
import { Checkbox, Button, FormGroup, Panel } from 'react-bootstrap'

import FareRuleSelections from './FareRuleSelections'
import {getTableById} from '../util/gtfs'
import {generateNullProps, getTableById} from '../util/gtfs'

const FARE_RULE_TYPES = [
{type: 'route_id', label: 'Route'},
Expand All @@ -24,7 +24,11 @@ export default class FareRulesForm extends Component {
_onClickAdd = () => {
const {activeComponent, activeEntity, updateActiveEntity} = this.props
const rules = [...activeEntity.fare_rules]
rules.unshift({fare_id: activeEntity.fare_id})
// Add new fare rule to beginning of array
rules.unshift({
...generateNullProps('fare_rules'),
fare_id: activeEntity.fare_id
})
updateActiveEntity(activeEntity, activeComponent, {fare_rules: rules})
}

Expand Down
Loading

0 comments on commit 1a2ffd0

Please sign in to comment.