Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
47e6572
fix(FeedVersionNavigator): reverse version sort; add retrieval method…
landonreed Mar 16, 2020
a279b5e
refactor(VersionRetrievalBadge): account for missing retrieval method
landonreed Mar 16, 2020
bc3a601
Merge branch 'dev' into mtc-20200310
landonreed Mar 16, 2020
4c4be61
refactor: fix lint
landonreed Mar 18, 2020
e8ec5f5
refactor: address PR comments
landonreed Mar 20, 2020
f1797a7
refactor: fix flow
landonreed Mar 26, 2020
5fb9ec9
feat(GtfsPlusVersionSummary): Add GTFS+ validation issue details.
binh-dam-ibigroup Apr 10, 2020
f2ddd81
improvement(GtfsPlusVersionSummary): Remove top boder in issues cell.…
binh-dam-ibigroup Apr 10, 2020
ade917a
fix(GtfsPlusVersionSummary): Tame down changes
binh-dam-ibigroup Apr 10, 2020
4c3f49f
style(GtfsPlusVersionSummary): Revert some code layout.
binh-dam-ibigroup Apr 10, 2020
bd14749
fix(GtfsPlusVersionSummary): Address PR comments
binh-dam-ibigroup Apr 10, 2020
1820fc5
fix(getGtfsPlusSpec): Move sorting from GtfsPlusVersionSummary to get…
binh-dam-ibigroup Apr 13, 2020
5c65a19
style(GtfsPlusVersionSummary): Adjust code layout.
binh-dam-ibigroup Apr 13, 2020
e9a558c
Merge pull request #553 from ibi-group/mtc-gtfsplus
landonreed Apr 13, 2020
734517d
fix(gtfs+): change rider_category_id from Adult -> Regular
landonreed Mar 20, 2020
82e1adb
Merge branch 'dev' into mtc-20200310
landonreed May 22, 2020
388647c
feat(gtfs-transform): add feed transformation settings
landonreed May 27, 2020
17179a5
refactor(FeedVersionNavigator): remove unnecessary bad props checks
landonreed May 27, 2020
9572a69
Merge branch 'dev' into gtfs-transform
landonreed May 27, 2020
dc179b3
refactor: fix lint/flow
landonreed Jun 12, 2020
700ab3c
refactor(gtfs-transform): address MTC comments
landonreed Jun 16, 2020
62c70db
refactor: fix flow typing
landonreed Jul 6, 2020
bccc6eb
refactor: fix flow def
landonreed Jul 6, 2020
3dd7760
refactor(gtfs-transform): move code into smaller files
landonreed Jul 6, 2020
b5dff34
refactor: update jsdoc
landonreed Jul 7, 2020
ee5e99d
refactor(gtfs-transform): add transformations indicator badge
landonreed Jul 7, 2020
d80572b
test(jest): update snapshots
landonreed Jul 7, 2020
5c5226b
refactor: address PR comments, add transform name tests
landonreed Jul 13, 2020
f6d8ab8
chore: fix lint
landonreed Jul 13, 2020
3d2c3c0
Merge pull request #579 from ibi-group/gtfs-transform
landonreed Jul 14, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions __tests__/test-utils/mock-data/manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ export const mockFeedWithVersion = {
retrievalMethod: 'MANUALLY_UPLOADED',
s3Url: null,
snapshotVersion: null,
transformRules: [],
url: 'http://mdtrip.org/googletransit/AnnapolisTransit/google_transit.zip',
user: null
}
Expand All @@ -160,6 +161,7 @@ export const mockFeedWithoutVersion = {
retrievalMethod: 'FETCHED_AUTOMATICALLY',
s3Url: null,
snapshotVersion: null,
transformRules: [],
url: null,
user: null
}
Expand Down
1 change: 1 addition & 0 deletions gtfs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -776,6 +776,7 @@

- id: scheduleexception
name: (none)
datatools: true
helpContent: Conveyal-specific table for classifying schedule exceptions.
fields:
- name: name
Expand Down
17 changes: 17 additions & 0 deletions i18n/english.yml
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,23 @@ components:
upload: Upload
versions: Versions
viewPublic: View public page
FeedTransformationDescriptions:
general:
fileDefined: below text
filePlaceholder: '[choose file]'
tablePlaceholder: '[choose table]'
table: table
version: version
versionPlaceholder: '[choose version]'
DeleteRecordsTransformation:
label: Delete records from %tablePlaceholder%
name: Delete records transformation
ReplaceFileFromStringTransformation:
label: Replace %tablePlaceholder% from %filePlaceholder%
name: Replace file from string transformation
ReplaceFileFromVersionTransformation:
label: Replace %tablePlaceholder% from %versionPlaceholder%
name: Replace file from version transformation
FeedVersionNavigator:
confirmDelete: Are you sure you want to delete this version? This cannot be undone.
confirmLoad: 'This will override all active GTFS Editor data for this Feed Source with the data from this version. If there is unsaved work in the Editor you want to keep, you must snapshot the current Editor data first. Are you sure you want to continue?'
Expand Down
4 changes: 2 additions & 2 deletions lib/common/actions/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export function createVoidPayloadAction (type: string) {
return () => ({ type })
}

export function secureFetch (url: string, method: string = 'get', payload: any, raw: boolean = false, isJSON: boolean = true, actionOnFail: any): any {
export function secureFetch (url: string, method: string = 'get', payload?: any, raw: boolean = false, isJSON: boolean = true, actionOnFail?: string): any {
return function (dispatch: dispatchFn, getState: getStateFn) {
function consoleError (message) {
console.error(`Error making ${method} request to ${url}: `, message)
Expand Down Expand Up @@ -95,7 +95,7 @@ export function fetchGraphQL ({
}: {
errorMessage?: string,
query: string,
variables: any
variables?: {[key: string]: string | number | Array<string>}
}): any {
return function (dispatch: dispatchFn, getState: getStateFn) {
const body = {
Expand Down
16 changes: 16 additions & 0 deletions lib/common/constants/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// @flow

const SECURE: string = 'secure/'
export const API_PREFIX: string = `/api/manager/`
export const SECURE_API_PREFIX: string = `${API_PREFIX}${SECURE}`
Expand All @@ -9,3 +10,18 @@ export const DEFAULT_DESCRIPTION = 'A command center for managing, editing, vali
export const DEFAULT_LOGO = 'https://d2tyb7byn1fef9.cloudfront.net/ibi_group_black-512x512.png'
export const DEFAULT_LOGO_SMALL = 'https://d2tyb7byn1fef9.cloudfront.net/ibi_group-128x128.png'
export const DEFAULT_TITLE = 'Data Tools'

export const RETRIEVAL_METHODS = Object.freeze({
MANUALLY_UPLOADED: 'MANUALLY_UPLOADED',
FETCHED_AUTOMATICALLY: 'FETCHED_AUTOMATICALLY',
PRODUCED_IN_HOUSE: 'PRODUCED_IN_HOUSE',
SERVICE_PERIOD_MERGE: 'SERVICE_PERIOD_MERGE',
REGIONAL_MERGE: 'REGIONAL_MERGE',
VERSION_CLONE: 'VERSION_CLONE'
})

export const FEED_TRANSFORMATION_TYPES = Object.freeze({
DELETE_RECORDS: 'DeleteRecordsTransformation',
REPLACE_FILE_FROM_VERSION: 'ReplaceFileFromVersionTransformation',
REPLACE_FILE_FROM_STRING: 'ReplaceFileFromStringTransformation'
})
4 changes: 2 additions & 2 deletions lib/common/util/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export function getGtfsPlusSpec (): Array<GtfsSpecTable> {
const CONFIG: DataToolsConfig = window.DT_CONFIG
const GTFS_PLUS_SPEC = CONFIG.specifications.gtfsplus
if (!GTFS_PLUS_SPEC) throw new Error('GTFS+ yml configuration file is not defined!')
return GTFS_PLUS_SPEC
return GTFS_PLUS_SPEC.sort((table1, table2) => table1.name.localeCompare(table2.name))
}

/**
Expand All @@ -58,7 +58,7 @@ export function getComponentMessages (
return message
} else {
if (logWarning) console.warn(`Couldn't find message entry for ${componentName}.${path}`)
return `{${path}}`
return message || `{${path}}`
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions lib/editor/actions/trip.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ export function fetchTripsForCalendar (
) {
return function (dispatch: dispatchFn, getState: getStateFn) {
const namespace = getEditorNamespace(feedId, getState())
if (!namespace) throw new Error('Editor namespace is undefined!')
// 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]) {
Expand Down Expand Up @@ -277,6 +278,7 @@ export function fetchCalendarTripCountsForPattern (
) {
return function (dispatch: dispatchFn, getState: getStateFn) {
const namespace = getEditorNamespace(feedId, getState())
if (!namespace) throw new Error('Editor namespace is undefined!')
// 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) {
Expand Down Expand Up @@ -304,6 +306,7 @@ export function fetchCalendarTripCountsForPattern (
export function fetchTripCounts (feedId: string) {
return function (dispatch: dispatchFn, getState: getStateFn) {
const namespace = getEditorNamespace(feedId, getState())
if (!namespace) throw new Error('Editor namespace is undefined!')
// 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) {
Expand Down
20 changes: 15 additions & 5 deletions lib/gtfsplus/components/GtfsPlusVersionSummary.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,24 @@
// @flow

import moment from 'moment'
import React, {Component} from 'react'
import {Panel, Row, Col, Table, Button, ButtonToolbar, Glyphicon, Alert} from 'react-bootstrap'
import {
Alert,
Button,
ButtonToolbar,
Col,
Glyphicon,
Panel,
Row,
Table
} from 'react-bootstrap'
import {browserHistory, Link} from 'react-router'
import moment from 'moment'

import {getGtfsPlusSpec} from '../../common/util/config'
import * as gtfsPlusActions from '../actions/gtfsplus'

import {getGtfsPlusSpec} from '../../common/util/config'
import type {Props as ContainerProps} from '../containers/ActiveGtfsPlusVersionSummary'
import type {GtfsPlusValidationIssue} from '../../types'
import type {GtfsPlusReducerState, ManagerUserState} from '../../types/reducers'

type Props = ContainerProps & {
Expand Down Expand Up @@ -51,7 +61,7 @@ export default class GtfsPlusVersionSummary extends Component<Props, State> {
return issuesForTable[tableId].length.toLocaleString()
}

_getTableLevelIssues = (tableId: string) => {
_getTableLevelIssues = (tableId: string): ?Array<GtfsPlusValidationIssue> => {
const {issuesForTable} = this.props
if (!issuesForTable) return null
if (!(tableId in issuesForTable)) return null
Expand Down Expand Up @@ -214,7 +224,7 @@ export default class GtfsPlusVersionSummary extends Component<Props, State> {
{tableLevelIssues.length} critical table issue(s):
<ul>
{tableLevelIssues.map((issue, i) =>
<li key={i}>{issue.description}</li>)}
<li key={i}>{issue.fieldName}: {issue.description}</li>)}
</ul>
</small>
: null
Expand Down
2 changes: 2 additions & 0 deletions lib/manager/actions/__tests__/__snapshots__/projects.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ Object {
"retrievalMethod": "MANUALLY_UPLOADED",
"s3Url": null,
"snapshotVersion": null,
"transformRules": Array [],
"url": "http://mdtrip.org/googletransit/AnnapolisTransit/google_transit.zip",
"user": null,
},
Expand Down Expand Up @@ -162,6 +163,7 @@ Object {
"retrievalMethod": "MANUALLY_UPLOADED",
"s3Url": null,
"snapshotVersion": null,
"transformRules": Array [],
"url": "http://mdtrip.org/googletransit/AnnapolisTransit/google_transit.zip",
"user": null,
},
Expand Down
111 changes: 58 additions & 53 deletions lib/manager/actions/status.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ import {API_PREFIX} from '../../common/constants'
import {isExtensionEnabled} from '../../common/util/config'
import { fetchDeployment } from './deployments'
import { fetchFeedSource } from './feeds'
import { downloadMergedFeedViaToken } from './projects'
import { fetchProjectWithFeeds } from './projects'
import { downloadSnapshotViaCredentials } from '../../editor/actions/snapshots'

import type {DataToolsConfig, ServerJob} from '../../types'
import type {DataToolsConfig, MergeFeedsResult, ServerJob} from '../../types'
import type {dispatchFn, getStateFn} from '../../types/reducers'

type ErrorMessage = {
Expand All @@ -21,6 +21,13 @@ type ErrorMessage = {
title?: string
}

type ModalContent = {
action?: any,
body: string,
detail?: any,
title: string
}

export const clearStatusModal = createVoidPayloadAction('CLEAR_STATUS_MODAL')
const handlingFinishedJob = createAction(
'HANDLING_FINISHED_JOB',
Expand Down Expand Up @@ -57,12 +64,7 @@ const setAppInfo = createAction(

const setStatusModal = createAction(
'SET_STATUS_MODAL',
(payload: {
action?: any,
body: string,
detail?: any,
title: string
}) => payload
(payload: ModalContent) => payload
)

export type StatusActions = ActionType<typeof clearStatusModal> |
Expand Down Expand Up @@ -134,6 +136,48 @@ export async function fetchAppInfo () {
}
}

function getMergeFeedModalContent (result: MergeFeedsResult): ModalContent {
const details = []
// Do nothing or show merged feed modal? Feed version is be created
details.push('Remapped ID count: ' + result.remappedReferences)
if (Object.keys(result.remappedIds).length > 0) {
const remappedIdStrings = []
for (let key in result.remappedIds) {
// Modify key to remove feed name.
const split = key.split(':')
const tableAndId = split.splice(1, 1)
remappedIdStrings.push(`${tableAndId.join(':')} -> ${result.remappedIds[key]}`)
}
details.push('Remapped IDs: ' + remappedIdStrings.join(', '))
}
if (result.skippedIds.length > 0) {
const skippedRecordsForTables = {}
result.skippedIds.forEach(id => {
const table = id.split(':')[0]
// Increment count of skipped records for each value found per table.
skippedRecordsForTables[table] = (skippedRecordsForTables[table] || 0) + 1
})
const skippedRecordsStrings = []
for (let key in skippedRecordsForTables) {
skippedRecordsStrings.push(`${key} - ${skippedRecordsForTables[key]}`)
}
details.push('Skipped records: ' + skippedRecordsStrings.join(', '))
}
if (result.idConflicts.length > 0) {
// const conflicts = result.idConflicts
details.push('ID conflicts: ' + result.idConflicts.join(', '))
}
return {
title: result.failed
? 'Warning: Errors encountered during feed merge!'
: 'Feed merge was successful!',
body: result.failed
? `Merge failed with ${result.errorCount} errors. ${result.failureReasons.join(', ')}`
: `Merge was completed successfully. A new version will be processed/validated containing the resulting feed.`,
detail: details.join('\n')
}
}

/* eslint-disable complexity */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you remove /* eslint-disable complexity */ now?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if this is needed anywhere anymore. When I remove these yarn lint runs fine. @evansiroky can you weigh in on whether these are still needed?

export function handleFinishedJob (job: ServerJob) {
return function (dispatch: dispatchFn, getState: getStateFn) {
Expand Down Expand Up @@ -203,60 +247,21 @@ export function handleFinishedJob (job: ServerJob) {
// If merging feeds for the project, end result is to download zip.
if (!job.projectId) {
// FIXME use setErrorMessage instead?
console.warn('No project found on job')
return
throw new Error('No project found on job')
}
dispatch(downloadMergedFeedViaToken(job.projectId, false))
// FIXME
dispatch(fetchProjectWithFeeds(job.projectId))
} else {
const result = job.mergeFeedsResult
const details = []
if (result) {
// Do nothing or show merged feed modal? Feed version is be created
details.push('Remapped ID count: ' + result.remappedReferences)
if (Object.keys(result.remappedIds).length > 0) {
const remappedIdStrings = []
for (let key in result.remappedIds) {
// Modify key to remove feed name.
const split = key.split(':')
const tableAndId = split.splice(1, 1)
remappedIdStrings.push(`${tableAndId.join(':')} -> ${result.remappedIds[key]}`)
}
details.push('Remapped IDs: ' + remappedIdStrings.join(', '))
}
if (result.skippedIds.length > 0) {
const skippedRecordsForTables = {}
result.skippedIds.forEach(id => {
const table = id.split(':')[0]
if (skippedRecordsForTables[table]) {
skippedRecordsForTables[table] = skippedRecordsForTables[table] + 1
} else {
skippedRecordsForTables[table] = 1
}
})
const skippedRecordsStrings = []
for (let key in skippedRecordsForTables) {
skippedRecordsStrings.push(`${key} - ${skippedRecordsForTables[key]}`)
}
details.push('Skipped records: ' + skippedRecordsStrings.join(', '))
}
if (result.idConflicts.length > 0) {
// const conflicts = result.idConflicts
details.push('ID conflicts: ' + result.idConflicts.join(', '))
}
dispatch(setStatusModal({
title: result.failed
? 'Warning: Errors encountered during feed merge!'
: 'Feed merge was successful!',
body: result.failed
? `Merge failed with ${result.errorCount} errors. ${result.failureReasons.join(', ')}`
: `Merge was completed successfully. A new version will be processed/validated containing the resulting feed.`,
detail: details.join('\n')
}))
const modalContent = getMergeFeedModalContent(result)
dispatch(setStatusModal(modalContent))
}
}
break
default:
console.warn(`No completion step defined for job type ${job.type}`)
break
}
}
}
Expand Down
12 changes: 6 additions & 6 deletions lib/manager/actions/versions.js
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ export function publishFeedVersion (feedVersion: FeedVersion) {
/**
* Merges two feed versions according to the strategy defined within the
*/
export function mergeVersions (targetVersionId: string, versionId: string, mergeType: string) {
export function mergeVersions (targetVersionId: string, versionId: string, mergeType: 'SERVICE_PERIOD' | 'REGIONAL') {
return function (dispatch: dispatchFn, getState: getStateFn) {
const url = `${SECURE_API_PREFIX}feedversion/merge?feedVersionIds=${targetVersionId},${versionId}&mergeType=${mergeType}`
return dispatch(secureFetch(url, 'put'))
Expand Down Expand Up @@ -290,11 +290,11 @@ export function fetchGTFSEntities ({
}
}
`
// If fetching for the editor, cast id to int for csv_line field
return dispatch(fetchGraphQL({
query,
variables: {namespace, [entityIdField]: editor ? +id : id}
}))
const variables = !id
? {namespace}
// If fetching a single ID for the editor, cast id to int for csv_line field
: {namespace, [entityIdField]: editor ? +id : id}
return dispatch(fetchGraphQL({query, variables}))
.then(data => {
dispatch(receiveGTFSEntities({namespace, id, component: type, data, editor, replaceNew}))
if (editor) {
Expand Down
Loading