From 7d9e55680c11b906a796441a0f1447cebf6f01ed Mon Sep 17 00:00:00 2001 From: Josh Willis <168561922+josh-willis-arcadis@users.noreply.github.com> Date: Tue, 28 Jan 2025 10:18:24 -0600 Subject: [PATCH 01/32] feat(gtfs): add initial CRUD for fare_products --- gtfs.yml | 20 ++++++++++++++++++++ lib/editor/actions/editor.js | 6 +++++- lib/editor/util/gtfs.js | 7 +++++-- lib/editor/util/ui.js | 8 ++++++++ lib/gtfs/util/index.js | 10 ++++++++++ lib/types/reducers.js | 3 ++- 6 files changed, 50 insertions(+), 4 deletions(-) diff --git a/gtfs.yml b/gtfs.yml index 746df907d..7de639e3e 100644 --- a/gtfs.yml +++ b/gtfs.yml @@ -1017,3 +1017,23 @@ required: false - name: added_service required: false + +- id: fare_products + name: fare_products.txt + helpContent: Used to describe the range of fares available for purchase by riders or taken into account when computing the total fare for journeys with multiple legs, such as transfer costs. + fields: + - name: fare_product_id + required: true + inputType: GTFS_ID + - name: fare_product_name + required: false + inputType: TEXT + - name: fare_product_id + required: false + inputType: TEXT # FARE-TODO: Needs to reference an actual fare media id. need custom type + - name: amount + inputType: NUMBER + required: true + - name: currency + required: true + inputType: TEXT # FARE-TODO: Dropdownx \ No newline at end of file diff --git a/lib/editor/actions/editor.js b/lib/editor/actions/editor.js index b83e5ad06..eb2dbaf26 100644 --- a/lib/editor/actions/editor.js +++ b/lib/editor/actions/editor.js @@ -498,9 +498,13 @@ export function fetchBaseGtfs ({ id fare_id } + fare_product (limit: -1) { + id + fare_product_id + } routes (limit: -1) { id - route_id + route_id route_short_name route_long_name # Ensure that we know route type when setting active entity (for edit diff --git a/lib/editor/util/gtfs.js b/lib/editor/util/gtfs.js index c1c136394..730724854 100644 --- a/lib/editor/util/gtfs.js +++ b/lib/editor/util/gtfs.js @@ -31,7 +31,8 @@ export const COMPONENT_LIST = [ // FIXME: table name for calendar, fare, and schedule exception { id: 'calendar', tableName: 'calendar' }, { id: 'scheduleexception', tableName: 'schedule_exceptions' }, - { id: 'agency', tableName: 'agency' } + { id: 'agency', tableName: 'agency' }, + { id: 'fare_product', tableName: 'fare_products' } ] export function getTableById (tableData: any, id?: string, emptyArrayOnNull: boolean = true): any { @@ -240,7 +241,9 @@ export function getEntityName (entity: any): string { nameKey = 'description' } else if (typeof entity.fare_id !== 'undefined') { nameKey = 'fare_id' - } else if (typeof entity.exemplar !== 'undefined') { + } else if (typeof entity.fare_product_id !== 'undefined') { + nameKey = 'fare_product_id' + } if (typeof entity.exemplar !== 'undefined') { nameKey = 'name' } diff --git a/lib/editor/util/ui.js b/lib/editor/util/ui.js index 55615ff95..28242758e 100644 --- a/lib/editor/util/ui.js +++ b/lib/editor/util/ui.js @@ -73,6 +73,14 @@ export const GTFS_ICONS = [ addable: true, title: messages('fare.title'), label: messages('fare.label') + }, + { + id: 'fare_product', + tableName: 'fare_products', + icon: 'ticket', + addable: true, + title: 'FARE PRODUCTS TEST TITLE', + label: 'FARE PRODUCTS TEST LABEL' } ] diff --git a/lib/gtfs/util/index.js b/lib/gtfs/util/index.js index 77bd5192a..39dbf3b5a 100644 --- a/lib/gtfs/util/index.js +++ b/lib/gtfs/util/index.js @@ -15,6 +15,8 @@ export function getEntityIdField (type: string): string { return 'agency_id' case 'fare': return 'fare_id' + case 'fare_product': + return 'fare_product_id' case 'calendar': return 'service_id' case 'stop': @@ -103,6 +105,10 @@ export function getGraphQLFieldsForEntity (type: string, editor: boolean = false contains_id } ` + case 'fare_product': + return ` + ${fields} + ` case 'pattern': return ` shape_id @@ -142,6 +148,8 @@ export function getEntityGraphQLRoot (type: string): string { return 'calendar' case 'fare': return 'fares' + case 'fare_product': + return 'fare_products' case 'feedinfo': return 'feed_info' case 'stop': @@ -175,6 +183,8 @@ export function getEntityTableString (type: string): string { return 'calendar' case 'fare': return 'fare_attributes' + case 'fare_product': + return 'fare_products' case 'fare_rules': return 'fare_rules' case 'feedinfo': diff --git a/lib/types/reducers.js b/lib/types/reducers.js index 17a74223e..b1c7ceb4e 100644 --- a/lib/types/reducers.js +++ b/lib/types/reducers.js @@ -121,10 +121,11 @@ export type EditorTables = { id: number, service_id: string }>, + fare_products: Array<{}>, fares: Array<{ fare_id: string, id: number, - }>, + }>, // TODO: Do this feed_info: Array<{ default_route_color: ?any, default_route_type: ?any, From e5e43a53bd4a97b96c091b04cc3d2e788560d659 Mon Sep 17 00:00:00 2001 From: Josh Willis <168561922+josh-willis-arcadis@users.noreply.github.com> Date: Wed, 29 Jan 2025 16:29:18 -0600 Subject: [PATCH 02/32] feat: add crud for rest of fares v2 tables --- lib/editor/actions/editor.js | 134 +++++++++++++++++++++++++++++++++++ lib/types/reducers.js | 8 ++- 2 files changed, 141 insertions(+), 1 deletion(-) diff --git a/lib/editor/actions/editor.js b/lib/editor/actions/editor.js index eb2dbaf26..3c9fb1fed 100644 --- a/lib/editor/actions/editor.js +++ b/lib/editor/actions/editor.js @@ -501,6 +501,140 @@ export function fetchBaseGtfs ({ fare_product (limit: -1) { id fare_product_id + fare_product_name + fare_media_id + amount + currency + fare_media { + fare_media_id + fare_media_name + fare_media_type + id + } + } + fare_media { + fare_media_id + fare_media_name + fare_media_type + id + } + fare_leg_rule (limit: -1) { + id + leg_group_id + network_id + from_area_id + to_area_id + from_timeframe_group_id + to_timeframe_group_id + fare_product_id + rule_priority + routes { + route_id + route_long_name + } + networks { + network_id + network_name + } + fare_products { + fare_product_id + fare_product_name + fare_media_id + amount + currency + } + from_time_frame { + timeframe_group_id + start_time + end_time + service_id + } + to_time_frame { + timeframe_group_id + start_time + end_time + service_id + } + to_area { + area_id + area_name + } + from_area { + area_id + area_name + } + } + area (limit: -1) { + id + area_id + area_name + } + fare_transfer_rule (limit: -1) { + from_leg_group_id + to_leg_group_id + transfer_count + duration_limit + duration_limit_type + fare_product_id + fare_products { + fare_product_id + fare_product_name + fare_media_id + amount + currency + fare_media { + fare_media_id + fare_media_name + fare_media_type + id + } + } + from_fare_leg_rule { + leg_group_id + network_id + from_area_id + to_area_id + from_timeframe_group_id + to_timeframe_group_id + fare_product_id + rule_priority + id + } + to_fare_leg_rule { + leg_group_id + network_id + from_area_id + to_area_id + from_timeframe_group_id + to_timeframe_group_id + fare_product_id + rule_priority + id + } + } + network { + network_id + network_name + } + route_network { + network_id + route_id + } + stop_area { + area_id + stop_id + id + stops { + stop_id + stop_name + } + } + time_frame { + timeframe_group_id + start_time + end_time + service_id + id } routes (limit: -1) { id diff --git a/lib/types/reducers.js b/lib/types/reducers.js index b1c7ceb4e..002fbc7d5 100644 --- a/lib/types/reducers.js +++ b/lib/types/reducers.js @@ -121,7 +121,13 @@ export type EditorTables = { id: number, service_id: string }>, - fare_products: Array<{}>, + fare_products: Array<{ + amount: number, + currency: string, + fare_media_id?: number, + fare_product_name?: string, + id: number + }>, fares: Array<{ fare_id: string, id: number, From 5d38fbbd66a4982f512460fe6a15df28eca7cc4f Mon Sep 17 00:00:00 2001 From: Josh Willis <168561922+josh-willis-arcadis@users.noreply.github.com> Date: Thu, 30 Jan 2025 12:07:34 -0600 Subject: [PATCH 03/32] Revert "feat: add crud for rest of fares v2 tables" This reverts commit e5e43a53bd4a97b96c091b04cc3d2e788560d659. --- lib/editor/actions/editor.js | 134 ----------------------------------- lib/types/reducers.js | 8 +-- 2 files changed, 1 insertion(+), 141 deletions(-) diff --git a/lib/editor/actions/editor.js b/lib/editor/actions/editor.js index 3c9fb1fed..eb2dbaf26 100644 --- a/lib/editor/actions/editor.js +++ b/lib/editor/actions/editor.js @@ -501,140 +501,6 @@ export function fetchBaseGtfs ({ fare_product (limit: -1) { id fare_product_id - fare_product_name - fare_media_id - amount - currency - fare_media { - fare_media_id - fare_media_name - fare_media_type - id - } - } - fare_media { - fare_media_id - fare_media_name - fare_media_type - id - } - fare_leg_rule (limit: -1) { - id - leg_group_id - network_id - from_area_id - to_area_id - from_timeframe_group_id - to_timeframe_group_id - fare_product_id - rule_priority - routes { - route_id - route_long_name - } - networks { - network_id - network_name - } - fare_products { - fare_product_id - fare_product_name - fare_media_id - amount - currency - } - from_time_frame { - timeframe_group_id - start_time - end_time - service_id - } - to_time_frame { - timeframe_group_id - start_time - end_time - service_id - } - to_area { - area_id - area_name - } - from_area { - area_id - area_name - } - } - area (limit: -1) { - id - area_id - area_name - } - fare_transfer_rule (limit: -1) { - from_leg_group_id - to_leg_group_id - transfer_count - duration_limit - duration_limit_type - fare_product_id - fare_products { - fare_product_id - fare_product_name - fare_media_id - amount - currency - fare_media { - fare_media_id - fare_media_name - fare_media_type - id - } - } - from_fare_leg_rule { - leg_group_id - network_id - from_area_id - to_area_id - from_timeframe_group_id - to_timeframe_group_id - fare_product_id - rule_priority - id - } - to_fare_leg_rule { - leg_group_id - network_id - from_area_id - to_area_id - from_timeframe_group_id - to_timeframe_group_id - fare_product_id - rule_priority - id - } - } - network { - network_id - network_name - } - route_network { - network_id - route_id - } - stop_area { - area_id - stop_id - id - stops { - stop_id - stop_name - } - } - time_frame { - timeframe_group_id - start_time - end_time - service_id - id } routes (limit: -1) { id diff --git a/lib/types/reducers.js b/lib/types/reducers.js index 002fbc7d5..b1c7ceb4e 100644 --- a/lib/types/reducers.js +++ b/lib/types/reducers.js @@ -121,13 +121,7 @@ export type EditorTables = { id: number, service_id: string }>, - fare_products: Array<{ - amount: number, - currency: string, - fare_media_id?: number, - fare_product_name?: string, - id: number - }>, + fare_products: Array<{}>, fares: Array<{ fare_id: string, id: number, From a9bedf710f6642b33a7b258bb2c39bd7c5abaf18 Mon Sep 17 00:00:00 2001 From: Josh Willis <168561922+josh-willis-arcadis@users.noreply.github.com> Date: Thu, 30 Jan 2025 13:22:42 -0600 Subject: [PATCH 04/32] add fare_media, fare_products fare_transfer_rule to sidebar to view data --- gtfs.yml | 59 ++++++++++++++++++++++++++++++++++-- lib/editor/actions/editor.js | 12 ++++++++ lib/editor/util/gtfs.js | 12 ++++++-- lib/editor/util/ui.js | 24 ++++++++++++--- lib/gtfs/util/index.js | 25 +++++++++++++-- lib/types/reducers.js | 6 ++-- 6 files changed, 124 insertions(+), 14 deletions(-) diff --git a/gtfs.yml b/gtfs.yml index 7de639e3e..9d13aac6c 100644 --- a/gtfs.yml +++ b/gtfs.yml @@ -1018,7 +1018,9 @@ - name: added_service required: false -- id: fare_products +# Fares v2 + +- id: fare_product name: fare_products.txt helpContent: Used to describe the range of fares available for purchase by riders or taken into account when computing the total fare for journeys with multiple legs, such as transfer costs. fields: @@ -1028,7 +1030,7 @@ - name: fare_product_name required: false inputType: TEXT - - name: fare_product_id + - name: fare_media_id required: false inputType: TEXT # FARE-TODO: Needs to reference an actual fare media id. need custom type - name: amount @@ -1036,4 +1038,55 @@ required: true - name: currency required: true - inputType: TEXT # FARE-TODO: Dropdownx \ No newline at end of file + inputType: TEXT # FARE-TODO: Dropdownx +- id: fare_media + name: fare_media.txt + helpContent: To describe the different fare media that can be employed to use fare products. Fare media are physical or virtual holders used for the representation and/or validation of a fare product. + fields: + - name: fare_media_id + required: true + inputType: GTFS_ID + - name: fare_media_name + inputType: TEXT + - name: fare_media_type + required: true + inputType: DROPDOWN + # FARE-TODO: Some help content? + options: + - value: '0' + - value: '1' + - value: '2' + - value: '3' + - value: '4' +- id: fare_transfer_rule + name: fare_transfer_rules.txt + helpContent: Fare rules for transfers between legs of travel defined in fare_leg_rules.txt. + fields: + - name: from_leg_group_id + required: false + inputType: TEXT # FARE-TODO: Needs to reference fare_leg_rules + - name: to_leg_group_id + required: false + inputType: TEXT # FARE-TODO: Needs to reference fare_leg_rules + - name: transfer_count + inputType: NUMBER # FARE-TODO: NON-ZERO INT + - name: duration_limit + inputType: POSITIVE_INT + - name: duration_limit_type + inputType: DROPDOWN + # FARE-TODO: Some help content? + options: + - value: '0' + - value: '1' + - value: '2' + - value: '3' + - name: fare_transfer_type + inputType: DROPDOWN + # FARE-TODO: Some help content? + options: + - value: '0' + - value: '1' + - value: '2' + - name: fare_product_id + required: false + inputType: TEXT # FARE-TODO: Needs to reference fare_products \ No newline at end of file diff --git a/lib/editor/actions/editor.js b/lib/editor/actions/editor.js index eb2dbaf26..5de1ab833 100644 --- a/lib/editor/actions/editor.js +++ b/lib/editor/actions/editor.js @@ -501,6 +501,18 @@ export function fetchBaseGtfs ({ fare_product (limit: -1) { id fare_product_id + fare_media_id + } + fare_media (limit: -1) { + id + fare_media_id + } + fare_transfer_rule (limit: -1) { + from_leg_group_id + to_leg_group_id + fare_product_id + transfer_count + duration_limit } routes (limit: -1) { id diff --git a/lib/editor/util/gtfs.js b/lib/editor/util/gtfs.js index 730724854..882710c31 100644 --- a/lib/editor/util/gtfs.js +++ b/lib/editor/util/gtfs.js @@ -32,7 +32,9 @@ export const COMPONENT_LIST = [ { id: 'calendar', tableName: 'calendar' }, { id: 'scheduleexception', tableName: 'schedule_exceptions' }, { id: 'agency', tableName: 'agency' }, - { id: 'fare_product', tableName: 'fare_products' } + { id: 'fare_product', tableName: 'fare_product' }, + { id: 'fare_media', tableName: 'fare_media' }, + { id: 'fare_transfer_rule', tableName: 'fare_transfer_rule' } ] export function getTableById (tableData: any, id?: string, emptyArrayOnNull: boolean = true): any { @@ -242,8 +244,12 @@ export function getEntityName (entity: any): string { } else if (typeof entity.fare_id !== 'undefined') { nameKey = 'fare_id' } else if (typeof entity.fare_product_id !== 'undefined') { - nameKey = 'fare_product_id' - } if (typeof entity.exemplar !== 'undefined') { + nameKey = 'fare_product_id' // FARE-TODO: fare_product_name? + } else if (typeof entity.fare_media_id !== 'undefined') { + nameKey = 'fare_media_id' // FARE-TODO: fare_media_name? Some combo? + } + // FARE-TODO: what to do with fare_transfer_rules.txt? + if (typeof entity.exemplar !== 'undefined') { nameKey = 'name' } diff --git a/lib/editor/util/ui.js b/lib/editor/util/ui.js index 28242758e..a311c874d 100644 --- a/lib/editor/util/ui.js +++ b/lib/editor/util/ui.js @@ -76,11 +76,27 @@ export const GTFS_ICONS = [ }, { id: 'fare_product', - tableName: 'fare_products', - icon: 'ticket', + tableName: 'fare_product', + icon: 'shopping-cart', + addable: true, + title: 'FARE PRODUCT TEST TITLE', + label: 'FARE PRODUCT TEST LABEL' + }, + { + id: 'fare_media', + tableName: 'fare_media', + icon: 'id-card', + addable: true, + title: 'FARE MEDIA TEST TITLE', + label: 'FARE MEDIA TEST LABEL' + }, + { + id: 'fare_transfer_rule', + tableName: 'fare_transfer_rule', + icon: 'link', addable: true, - title: 'FARE PRODUCTS TEST TITLE', - label: 'FARE PRODUCTS TEST LABEL' + title: 'FARE TRANSFER RULE TEST TITLE', + label: 'FARE TRANSFER RULE TEST LABEL' } ] diff --git a/lib/gtfs/util/index.js b/lib/gtfs/util/index.js index 39dbf3b5a..893edee14 100644 --- a/lib/gtfs/util/index.js +++ b/lib/gtfs/util/index.js @@ -17,6 +17,11 @@ export function getEntityIdField (type: string): string { return 'fare_id' case 'fare_product': return 'fare_product_id' + case 'fare_media': + return 'fare_media_id' + case 'fare_transfer_rule': + return 'id' + // FARE-TODO: what to do with fare_transfer_rules.txt case 'calendar': return 'service_id' case 'stop': @@ -109,6 +114,14 @@ export function getGraphQLFieldsForEntity (type: string, editor: boolean = false return ` ${fields} ` + case 'fare_media': + return ` + ${fields} + ` + case 'fare_transfer_rule': + return ` + ${fields} + ` case 'pattern': return ` shape_id @@ -149,7 +162,11 @@ export function getEntityGraphQLRoot (type: string): string { case 'fare': return 'fares' case 'fare_product': - return 'fare_products' + return 'fare_product' + case 'fare_media': + return 'fare_media' + case 'fare_transer_rule': + return 'fare_transfer_rule' case 'feedinfo': return 'feed_info' case 'stop': @@ -184,9 +201,13 @@ export function getEntityTableString (type: string): string { case 'fare': return 'fare_attributes' case 'fare_product': - return 'fare_products' + return 'fare_product' + case 'fare_media': + return 'fare_media' case 'fare_rules': return 'fare_rules' + case 'fare_transfer_rule': + return 'fare_transfer_rules' case 'feedinfo': return 'feedinfo' case 'stop': diff --git a/lib/types/reducers.js b/lib/types/reducers.js index b1c7ceb4e..e31e7a2e0 100644 --- a/lib/types/reducers.js +++ b/lib/types/reducers.js @@ -121,11 +121,13 @@ export type EditorTables = { id: number, service_id: string }>, - fare_products: Array<{}>, + fare_media: Array<{}>, // FARE-TODO: Do this + fare_product: Array<{}>, // FARE-TODO: Do this + fare_transfer_rule: Array<{}>, // FARE-TODO: Do this fares: Array<{ fare_id: string, id: number, - }>, // TODO: Do this + }>, feed_info: Array<{ default_route_color: ?any, default_route_type: ?any, From 6c8863959b466113e50e8cb0c90dd740be004398 Mon Sep 17 00:00:00 2001 From: Josh Willis <168561922+josh-willis-arcadis@users.noreply.github.com> Date: Tue, 4 Feb 2025 18:33:15 -0600 Subject: [PATCH 05/32] feat(fare_leg_rule): add table to editor --- gtfs.yml | 30 +++++++++++++++++++++++++++++- lib/editor/actions/editor.js | 11 +++++++++++ lib/editor/util/gtfs.js | 4 +++- lib/editor/util/ui.js | 8 ++++++++ lib/gtfs/util/index.js | 11 +++++++++++ lib/types/reducers.js | 1 + 6 files changed, 63 insertions(+), 2 deletions(-) diff --git a/gtfs.yml b/gtfs.yml index 9d13aac6c..5a8af4b7f 100644 --- a/gtfs.yml +++ b/gtfs.yml @@ -1089,4 +1089,32 @@ - value: '2' - name: fare_product_id required: false - inputType: TEXT # FARE-TODO: Needs to reference fare_products \ No newline at end of file + inputType: TEXT # FARE-TODO: Needs to reference fare_products +- id: fare_leg_rule + name: fare_leg_rules.txt + # FARE-TODO: Some help content? + fields: + - name: leg_group_id + required: false + inputType: GTFS_ID # FARE-TODO: should this be text or id? + - name: network_id + required: false + inputType: TEXT # FARE-TODO: Needs to reference networks.network_id or routes.network_id + - name: from_area_id + required: false + inputType: TEXT # FARE-TODO: Needs to reference areas.area_id + - name: to_area_id + required: false + inputType: TEXT # FARE-TODO: Needs to reference areas.area_id + - name: from_timeframe_group_id + required: false + inputType: TEXT # FARE-TODO: Needs to reference timeframes.timeframe_group_id + - name: to_timeframe_group_id + required: false + inputType: TEXT # FARE-TODO: Needs to reference timeframes.timeframe_group_id + - name: fare_product_id + required: true + inputType: TEXT # FARE-TODO: Needs to reference fare_products.fare_product_id + - name: rule_priority + required: false + inputType: POSITIVE_INT \ No newline at end of file diff --git a/lib/editor/actions/editor.js b/lib/editor/actions/editor.js index 5de1ab833..0d3fd300f 100644 --- a/lib/editor/actions/editor.js +++ b/lib/editor/actions/editor.js @@ -514,6 +514,17 @@ export function fetchBaseGtfs ({ transfer_count duration_limit } + fare_leg_rule { + leg_group_id + network_id + from_area_id + to_area_id + from_timeframe_group_id + to_timeframe_group_id + fare_product_id + rule_priority + id + } routes (limit: -1) { id route_id diff --git a/lib/editor/util/gtfs.js b/lib/editor/util/gtfs.js index 882710c31..1dd9abfb3 100644 --- a/lib/editor/util/gtfs.js +++ b/lib/editor/util/gtfs.js @@ -34,7 +34,8 @@ export const COMPONENT_LIST = [ { id: 'agency', tableName: 'agency' }, { id: 'fare_product', tableName: 'fare_product' }, { id: 'fare_media', tableName: 'fare_media' }, - { id: 'fare_transfer_rule', tableName: 'fare_transfer_rule' } + { id: 'fare_transfer_rule', tableName: 'fare_transfer_rule' }, + { id: 'fare_leg_rule', tableName: 'fare_leg_rule' } ] export function getTableById (tableData: any, id?: string, emptyArrayOnNull: boolean = true): any { @@ -249,6 +250,7 @@ export function getEntityName (entity: any): string { nameKey = 'fare_media_id' // FARE-TODO: fare_media_name? Some combo? } // FARE-TODO: what to do with fare_transfer_rules.txt? + // FARE-TODO: what to do with fare_leg_rules.txt? if (typeof entity.exemplar !== 'undefined') { nameKey = 'name' } diff --git a/lib/editor/util/ui.js b/lib/editor/util/ui.js index a311c874d..32b61e609 100644 --- a/lib/editor/util/ui.js +++ b/lib/editor/util/ui.js @@ -97,6 +97,14 @@ export const GTFS_ICONS = [ addable: true, title: 'FARE TRANSFER RULE TEST TITLE', label: 'FARE TRANSFER RULE TEST LABEL' + }, + { + id: 'fare_leg_rule', + tableName: 'fare_leg_rule', + icon: 'link', + addable: true, + title: 'FARE LEG RULE TEST TITLE', + label: 'FARE LEG RULE TEST LABEL' } ] diff --git a/lib/gtfs/util/index.js b/lib/gtfs/util/index.js index 893edee14..990c3b375 100644 --- a/lib/gtfs/util/index.js +++ b/lib/gtfs/util/index.js @@ -22,6 +22,9 @@ export function getEntityIdField (type: string): string { case 'fare_transfer_rule': return 'id' // FARE-TODO: what to do with fare_transfer_rules.txt + case 'fare_leg_rule': + return 'id' + // FARE-TODO: what to do with fare_leg_rules.txt case 'calendar': return 'service_id' case 'stop': @@ -122,6 +125,10 @@ export function getGraphQLFieldsForEntity (type: string, editor: boolean = false return ` ${fields} ` + case 'fare_leg_rule': + return ` + ${fields} + ` case 'pattern': return ` shape_id @@ -167,6 +174,8 @@ export function getEntityGraphQLRoot (type: string): string { return 'fare_media' case 'fare_transer_rule': return 'fare_transfer_rule' + case 'fare_leg_rule': + return 'fare_leg_rule' case 'feedinfo': return 'feed_info' case 'stop': @@ -208,6 +217,8 @@ export function getEntityTableString (type: string): string { return 'fare_rules' case 'fare_transfer_rule': return 'fare_transfer_rules' + case 'fare_leg_rule': + return 'fare_leg_rules' case 'feedinfo': return 'feedinfo' case 'stop': diff --git a/lib/types/reducers.js b/lib/types/reducers.js index e31e7a2e0..9332514af 100644 --- a/lib/types/reducers.js +++ b/lib/types/reducers.js @@ -121,6 +121,7 @@ export type EditorTables = { id: number, service_id: string }>, + fare_leg_rule: Array<{}>, // FARE-TODO: Do this fare_media: Array<{}>, // FARE-TODO: Do this fare_product: Array<{}>, // FARE-TODO: Do this fare_transfer_rule: Array<{}>, // FARE-TODO: Do this From 30cf528a96ab5a036bf03230c90c1003b1841696 Mon Sep 17 00:00:00 2001 From: Josh Willis <168561922+josh-willis-arcadis@users.noreply.github.com> Date: Wed, 5 Feb 2025 14:32:24 -0600 Subject: [PATCH 06/32] feat(fare_leg_rules): add fare_leg_rules.txt data to editor --- gtfs.yml | 2 +- lib/editor/actions/editor.js | 13 ++----------- lib/editor/util/ui.js | 2 +- lib/gtfs/util/index.js | 18 +++++++++--------- 4 files changed, 13 insertions(+), 22 deletions(-) diff --git a/gtfs.yml b/gtfs.yml index 5a8af4b7f..26422eebc 100644 --- a/gtfs.yml +++ b/gtfs.yml @@ -1096,7 +1096,7 @@ fields: - name: leg_group_id required: false - inputType: GTFS_ID # FARE-TODO: should this be text or id? + inputType: TEXT # FARE-TODO: should this be text or id? - name: network_id required: false inputType: TEXT # FARE-TODO: Needs to reference networks.network_id or routes.network_id diff --git a/lib/editor/actions/editor.js b/lib/editor/actions/editor.js index 0d3fd300f..62cb5443f 100644 --- a/lib/editor/actions/editor.js +++ b/lib/editor/actions/editor.js @@ -508,21 +508,12 @@ export function fetchBaseGtfs ({ fare_media_id } fare_transfer_rule (limit: -1) { + id from_leg_group_id to_leg_group_id - fare_product_id - transfer_count - duration_limit } - fare_leg_rule { - leg_group_id - network_id - from_area_id - to_area_id - from_timeframe_group_id - to_timeframe_group_id + fare_leg_rule (limit: -1) { fare_product_id - rule_priority id } routes (limit: -1) { diff --git a/lib/editor/util/ui.js b/lib/editor/util/ui.js index 32b61e609..7ceb42065 100644 --- a/lib/editor/util/ui.js +++ b/lib/editor/util/ui.js @@ -101,7 +101,7 @@ export const GTFS_ICONS = [ { id: 'fare_leg_rule', tableName: 'fare_leg_rule', - icon: 'link', + icon: 'book', addable: true, title: 'FARE LEG RULE TEST TITLE', label: 'FARE LEG RULE TEST LABEL' diff --git a/lib/gtfs/util/index.js b/lib/gtfs/util/index.js index 990c3b375..6db033376 100644 --- a/lib/gtfs/util/index.js +++ b/lib/gtfs/util/index.js @@ -21,10 +21,8 @@ export function getEntityIdField (type: string): string { return 'fare_media_id' case 'fare_transfer_rule': return 'id' - // FARE-TODO: what to do with fare_transfer_rules.txt case 'fare_leg_rule': return 'id' - // FARE-TODO: what to do with fare_leg_rules.txt case 'calendar': return 'service_id' case 'stop': @@ -123,10 +121,12 @@ export function getGraphQLFieldsForEntity (type: string, editor: boolean = false ` case 'fare_transfer_rule': return ` + id ${fields} ` case 'fare_leg_rule': return ` + id ${fields} ` case 'pattern': @@ -172,7 +172,7 @@ export function getEntityGraphQLRoot (type: string): string { return 'fare_product' case 'fare_media': return 'fare_media' - case 'fare_transer_rule': + case 'fare_transfer_rule': return 'fare_transfer_rule' case 'fare_leg_rule': return 'fare_leg_rule' @@ -207,18 +207,18 @@ export function getEntityTableString (type: string): string { return 'agency' case 'calendar': return 'calendar' - case 'fare': - return 'fare_attributes' + case 'fare': // Fares v1 + return 'fare_attributes' // Fares v1 case 'fare_product': return 'fare_product' case 'fare_media': return 'fare_media' - case 'fare_rules': - return 'fare_rules' + case 'fare_rules': // Fares v1 + return 'fare_rules' // Fares v1 case 'fare_transfer_rule': - return 'fare_transfer_rules' + return 'fare_transfer_rule' case 'fare_leg_rule': - return 'fare_leg_rules' + return 'fare_leg_rule' case 'feedinfo': return 'feedinfo' case 'stop': From d6f55385527c917eb682ae108ff26f7c9b6e0ba7 Mon Sep 17 00:00:00 2001 From: miles-grant-ibigroup Date: Thu, 6 Feb 2025 12:37:11 -0500 Subject: [PATCH 07/32] fix put/post --- gtfs.yml | 8 ++++---- lib/editor/util/gtfs.js | 12 ++++-------- lib/editor/util/ui.js | 16 ++++++++-------- lib/gtfs/util/index.js | 40 ++++++++++++++++++++-------------------- 4 files changed, 36 insertions(+), 40 deletions(-) diff --git a/gtfs.yml b/gtfs.yml index 26422eebc..597a56930 100644 --- a/gtfs.yml +++ b/gtfs.yml @@ -1020,7 +1020,7 @@ # Fares v2 -- id: fare_product +- id: fareproduct name: fare_products.txt helpContent: Used to describe the range of fares available for purchase by riders or taken into account when computing the total fare for journeys with multiple legs, such as transfer costs. fields: @@ -1039,7 +1039,7 @@ - name: currency required: true inputType: TEXT # FARE-TODO: Dropdownx -- id: fare_media +- id: faremedia name: fare_media.txt helpContent: To describe the different fare media that can be employed to use fare products. Fare media are physical or virtual holders used for the representation and/or validation of a fare product. fields: @@ -1058,7 +1058,7 @@ - value: '2' - value: '3' - value: '4' -- id: fare_transfer_rule +- id: faretransferrule name: fare_transfer_rules.txt helpContent: Fare rules for transfers between legs of travel defined in fare_leg_rules.txt. fields: @@ -1090,7 +1090,7 @@ - name: fare_product_id required: false inputType: TEXT # FARE-TODO: Needs to reference fare_products -- id: fare_leg_rule +- id: farelegrule name: fare_leg_rules.txt # FARE-TODO: Some help content? fields: diff --git a/lib/editor/util/gtfs.js b/lib/editor/util/gtfs.js index 1dd9abfb3..938ca2c06 100644 --- a/lib/editor/util/gtfs.js +++ b/lib/editor/util/gtfs.js @@ -32,10 +32,10 @@ export const COMPONENT_LIST = [ { id: 'calendar', tableName: 'calendar' }, { id: 'scheduleexception', tableName: 'schedule_exceptions' }, { id: 'agency', tableName: 'agency' }, - { id: 'fare_product', tableName: 'fare_product' }, - { id: 'fare_media', tableName: 'fare_media' }, - { id: 'fare_transfer_rule', tableName: 'fare_transfer_rule' }, - { id: 'fare_leg_rule', tableName: 'fare_leg_rule' } + { id: 'fareproduct', tableName: 'fare_product' }, + { id: 'faremedia', tableName: 'fare_media' }, + { id: 'faretransferrule', tableName: 'fare_transfer_rule' }, + { id: 'farelegrule', tableName: 'fare_leg_rule' } ] export function getTableById (tableData: any, id?: string, emptyArrayOnNull: boolean = true): any { @@ -244,10 +244,6 @@ export function getEntityName (entity: any): string { nameKey = 'description' } else if (typeof entity.fare_id !== 'undefined') { nameKey = 'fare_id' - } else if (typeof entity.fare_product_id !== 'undefined') { - nameKey = 'fare_product_id' // FARE-TODO: fare_product_name? - } else if (typeof entity.fare_media_id !== 'undefined') { - nameKey = 'fare_media_id' // FARE-TODO: fare_media_name? Some combo? } // FARE-TODO: what to do with fare_transfer_rules.txt? // FARE-TODO: what to do with fare_leg_rules.txt? diff --git a/lib/editor/util/ui.js b/lib/editor/util/ui.js index 7ceb42065..0e4675187 100644 --- a/lib/editor/util/ui.js +++ b/lib/editor/util/ui.js @@ -75,32 +75,32 @@ export const GTFS_ICONS = [ label: messages('fare.label') }, { - id: 'fare_product', - tableName: 'fare_product', + id: 'fareproduct', + tableName: 'fareproduct', icon: 'shopping-cart', addable: true, title: 'FARE PRODUCT TEST TITLE', label: 'FARE PRODUCT TEST LABEL' }, { - id: 'fare_media', - tableName: 'fare_media', + id: 'faremedia', + tableName: 'faremedia', icon: 'id-card', addable: true, title: 'FARE MEDIA TEST TITLE', label: 'FARE MEDIA TEST LABEL' }, { - id: 'fare_transfer_rule', - tableName: 'fare_transfer_rule', + id: 'faretransferrule', + tableName: 'faretransferrule', icon: 'link', addable: true, title: 'FARE TRANSFER RULE TEST TITLE', label: 'FARE TRANSFER RULE TEST LABEL' }, { - id: 'fare_leg_rule', - tableName: 'fare_leg_rule', + id: 'farelegrule', + tableName: 'farelegrule', icon: 'book', addable: true, title: 'FARE LEG RULE TEST TITLE', diff --git a/lib/gtfs/util/index.js b/lib/gtfs/util/index.js index 6db033376..929f01ff9 100644 --- a/lib/gtfs/util/index.js +++ b/lib/gtfs/util/index.js @@ -15,13 +15,13 @@ export function getEntityIdField (type: string): string { return 'agency_id' case 'fare': return 'fare_id' - case 'fare_product': + case 'fareproduct': return 'fare_product_id' - case 'fare_media': + case 'faremedia': return 'fare_media_id' - case 'fare_transfer_rule': + case 'faretransferrule': return 'id' - case 'fare_leg_rule': + case 'farelegrule': return 'id' case 'calendar': return 'service_id' @@ -111,20 +111,20 @@ export function getGraphQLFieldsForEntity (type: string, editor: boolean = false contains_id } ` - case 'fare_product': + case 'fareproduct': return ` ${fields} ` - case 'fare_media': + case 'faremedia': return ` ${fields} ` - case 'fare_transfer_rule': + case 'faretransferrule': return ` id ${fields} ` - case 'fare_leg_rule': + case 'farelegrule': return ` id ${fields} @@ -168,13 +168,13 @@ export function getEntityGraphQLRoot (type: string): string { return 'calendar' case 'fare': return 'fares' - case 'fare_product': + case 'fareproduct': return 'fare_product' - case 'fare_media': + case 'faremedia': return 'fare_media' - case 'fare_transfer_rule': + case 'faretransferrule': return 'fare_transfer_rule' - case 'fare_leg_rule': + case 'farelegrule': return 'fare_leg_rule' case 'feedinfo': return 'feed_info' @@ -209,16 +209,16 @@ export function getEntityTableString (type: string): string { return 'calendar' case 'fare': // Fares v1 return 'fare_attributes' // Fares v1 - case 'fare_product': - return 'fare_product' - case 'fare_media': - return 'fare_media' + case 'fareproduct': + return 'fareproduct' + case 'faremedia': + return 'faremedia' case 'fare_rules': // Fares v1 return 'fare_rules' // Fares v1 - case 'fare_transfer_rule': - return 'fare_transfer_rule' - case 'fare_leg_rule': - return 'fare_leg_rule' + case 'faretransferrule': + return 'faretransferrule' + case 'farelegrule': + return 'farelegrule' case 'feedinfo': return 'feedinfo' case 'stop': From 20754747bd8c7f2b1110ca2821d863107936a02c Mon Sep 17 00:00:00 2001 From: miles-grant-ibigroup Date: Thu, 6 Feb 2025 12:47:41 -0500 Subject: [PATCH 08/32] clean up labels --- lib/editor/actions/editor.js | 2 ++ lib/editor/util/gtfs.js | 18 ++++++++++++++++++ lib/editor/util/objects.js | 9 ++++++++- lib/editor/util/ui.js | 8 ++++---- 4 files changed, 32 insertions(+), 5 deletions(-) diff --git a/lib/editor/actions/editor.js b/lib/editor/actions/editor.js index 62cb5443f..553009528 100644 --- a/lib/editor/actions/editor.js +++ b/lib/editor/actions/editor.js @@ -511,9 +511,11 @@ export function fetchBaseGtfs ({ id from_leg_group_id to_leg_group_id + fare_product_id } fare_leg_rule (limit: -1) { fare_product_id + leg_group_id id } routes (limit: -1) { diff --git a/lib/editor/util/gtfs.js b/lib/editor/util/gtfs.js index 938ca2c06..bc809e759 100644 --- a/lib/editor/util/gtfs.js +++ b/lib/editor/util/gtfs.js @@ -244,7 +244,16 @@ export function getEntityName (entity: any): string { nameKey = 'description' } else if (typeof entity.fare_id !== 'undefined') { nameKey = 'fare_id' + } else if (typeof entity.fare_product_id !== 'undefined' && typeof entity.fare_media_id !== 'undefined') { + nameKey = 'fare_product_id' + } else if (typeof entity.fare_media_id !== 'undefined') { + nameKey = 'fare_media_id' + } else if (typeof entity.from_leg_group_id !== 'undefined' && typeof entity.to_leg_group_id !== 'undefined' && entity.fare_product_id !== 'undefined') { + nameKey = 'fare_transfer_rule_id' // FARE-TODO: fare_media_name? Some combo? + } else if (typeof entity.fare_product_id !== 'undefined' && typeof entity.leg_group_id !== 'undefined') { + nameKey = 'fare_leg_rule_id' // FARE-TODO: fare_media_name? Some combo? } + // FARE-TODO: what to do with fare_transfer_rules.txt? // FARE-TODO: what to do with fare_leg_rules.txt? if (typeof entity.exemplar !== 'undefined') { @@ -281,6 +290,15 @@ export function getEntityName (entity: any): string { return `${serviceCalendar.service_id} ${serviceCalendar.description ? `(${serviceCalendar.description})` : ''}` + case 'fare_product_id': + // FARE-TODO: type! + return `${entity.fare_product_id} (${entity.fare_media_id})` + case 'fare_transfer_rule_id': + // FARE-TODO: type! + return `${entity.from_leg_group_id} ➡️ ${entity.to_leg_group_id} (${entity.fare_product_id})` + case 'fare_leg_rule_id': + // FARE-TODO: type! + return `${entity.fare_product_id} (${entity.leg_group_id})` default: const otherEntityType: any = entity return otherEntityType[nameKey] || NO_NAME diff --git a/lib/editor/util/objects.js b/lib/editor/util/objects.js index 43b3744f9..75d120a05 100644 --- a/lib/editor/util/objects.js +++ b/lib/editor/util/objects.js @@ -1,13 +1,20 @@ // @flow import {ENTITY} from '../constants' import {camelCaseKeys, snakeCaseKeys} from '../../common/util/map-keys' - import type {Entity} from '../../types' export function componentToText (component: string): string { switch (component) { case 'scheduleexception': return 'exception' + case 'fareproduct': + return 'product' + case 'faremedia': + return 'media' + case 'faretransferrule': + return 'transfer rule' + case 'farelegrule': + return 'leg rule' default: return component } diff --git a/lib/editor/util/ui.js b/lib/editor/util/ui.js index 0e4675187..d78492b11 100644 --- a/lib/editor/util/ui.js +++ b/lib/editor/util/ui.js @@ -80,7 +80,7 @@ export const GTFS_ICONS = [ icon: 'shopping-cart', addable: true, title: 'FARE PRODUCT TEST TITLE', - label: 'FARE PRODUCT TEST LABEL' + label: 'V2: Products' }, { id: 'faremedia', @@ -88,7 +88,7 @@ export const GTFS_ICONS = [ icon: 'id-card', addable: true, title: 'FARE MEDIA TEST TITLE', - label: 'FARE MEDIA TEST LABEL' + label: 'V2: Media' }, { id: 'faretransferrule', @@ -96,7 +96,7 @@ export const GTFS_ICONS = [ icon: 'link', addable: true, title: 'FARE TRANSFER RULE TEST TITLE', - label: 'FARE TRANSFER RULE TEST LABEL' + label: 'V2: Transfer Rules' }, { id: 'farelegrule', @@ -104,7 +104,7 @@ export const GTFS_ICONS = [ icon: 'book', addable: true, title: 'FARE LEG RULE TEST TITLE', - label: 'FARE LEG RULE TEST LABEL' + label: 'V2: Leg Rules' } ] From ba3e4a61f0d2565467420751a06f269dd4908d89 Mon Sep 17 00:00:00 2001 From: Josh Willis <168561922+josh-willis-arcadis@users.noreply.github.com> Date: Mon, 10 Feb 2025 14:00:00 -0600 Subject: [PATCH 09/32] add text to faremedia dropdown --- gtfs.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/gtfs.yml b/gtfs.yml index 597a56930..11b68b32c 100644 --- a/gtfs.yml +++ b/gtfs.yml @@ -1051,13 +1051,17 @@ - name: fare_media_type required: true inputType: DROPDOWN - # FARE-TODO: Some help content? options: - value: '0' + - text: None (0) - value: '1' + - text: Physical paper ticket (1) - value: '2' + - text: Physical transit card (2) - value: '3' + - text: cEMV (3) - value: '4' + - text: Mobile app (4) - id: faretransferrule name: fare_transfer_rules.txt helpContent: Fare rules for transfers between legs of travel defined in fare_leg_rules.txt. From c35bb8667fe678cfacc0d1ad1295a25cd83f343e Mon Sep 17 00:00:00 2001 From: Josh Willis <168561922+josh-willis-arcadis@users.noreply.github.com> Date: Mon, 10 Feb 2025 14:05:15 -0600 Subject: [PATCH 10/32] remove extra whitespace --- lib/editor/actions/editor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/editor/actions/editor.js b/lib/editor/actions/editor.js index 553009528..e5f758b0a 100644 --- a/lib/editor/actions/editor.js +++ b/lib/editor/actions/editor.js @@ -520,7 +520,7 @@ export function fetchBaseGtfs ({ } routes (limit: -1) { id - route_id + route_id route_short_name route_long_name # Ensure that we know route type when setting active entity (for edit From 17d7f9486f257455ae304c6113c9d10af40b19b7 Mon Sep 17 00:00:00 2001 From: Josh Willis <168561922+josh-willis-arcadis@users.noreply.github.com> Date: Mon, 10 Feb 2025 14:43:45 -0600 Subject: [PATCH 11/32] add GTFS_FARE_MEDIA type --- gtfs.yml | 4 ++-- lib/editor/components/EditorInput.js | 3 ++- lib/editor/util/validation.js | 1 + lib/types/index.js | 3 ++- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/gtfs.yml b/gtfs.yml index 11b68b32c..464bdfea2 100644 --- a/gtfs.yml +++ b/gtfs.yml @@ -1032,7 +1032,7 @@ inputType: TEXT - name: fare_media_id required: false - inputType: TEXT # FARE-TODO: Needs to reference an actual fare media id. need custom type + inputType: GTFS_FARE_MEDIA # FARE-TODO: Needs to reference an actual fare media id. need custom type - name: amount inputType: NUMBER required: true @@ -1045,7 +1045,7 @@ fields: - name: fare_media_id required: true - inputType: GTFS_ID + inputType: GTFS_FARE_MEDIA - name: fare_media_name inputType: TEXT - name: fare_media_type diff --git a/lib/editor/components/EditorInput.js b/lib/editor/components/EditorInput.js index b72248c54..ac94a2a27 100644 --- a/lib/editor/components/EditorInput.js +++ b/lib/editor/components/EditorInput.js @@ -164,7 +164,8 @@ export default class EditorInput extends React.Component { case 'POSITIVE_NUM': case 'GTFS_BLOCK': case 'GTFS_FARE': - case 'GTFS_SERVICE': { + case 'GTFS_SERVICE': + case 'GTFS_FARE_MEDIA': { // Ensure that an empty string is passed to value prop, so that on 'undo' // the input value will revert back to a blank field. const stringValue = typeof fieldProps.value === 'undefined' diff --git a/lib/editor/util/validation.js b/lib/editor/util/validation.js index a94e23b6a..9dd1d94ec 100644 --- a/lib/editor/util/validation.js +++ b/lib/editor/util/validation.js @@ -204,6 +204,7 @@ export function validate ( case 'GTFS_BLOCK': case 'GTFS_FARE': case 'GTFS_SERVICE': + case 'GTFS_FARE_MEDIA': if (isRequiredButEmpty) { return emptyFieldValidationIssue() } else { diff --git a/lib/types/index.js b/lib/types/index.js index 1c176ef4e..4550e2d7a 100644 --- a/lib/types/index.js +++ b/lib/types/index.js @@ -41,7 +41,8 @@ type InputType = 'DAY_OF_WEEK_BOOLEAN' | 'NUMBER' | 'GTFS_FARE' | - 'EXCEPTION_DATE' + 'EXCEPTION_DATE' | + 'GTFS_FARE_MEDIA' export type RtdEntity = { AgencyId: string, From 7aa1ce3f93e06cf1c99cbc5d6d9258054a081e13 Mon Sep 17 00:00:00 2001 From: Josh Willis <168561922+josh-willis-arcadis@users.noreply.github.com> Date: Mon, 10 Feb 2025 14:46:48 -0600 Subject: [PATCH 12/32] use correct text/value for fare_media type --- gtfs.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/gtfs.yml b/gtfs.yml index 464bdfea2..76cd2661b 100644 --- a/gtfs.yml +++ b/gtfs.yml @@ -1053,15 +1053,15 @@ inputType: DROPDOWN options: - value: '0' - - text: None (0) + text: None (0) - value: '1' - - text: Physical paper ticket (1) + text: Physical paper ticket (1) - value: '2' - - text: Physical transit card (2) + text: Physical transit card (2) - value: '3' - - text: cEMV (3) + text: cEMV (3) - value: '4' - - text: Mobile app (4) + text: Mobile app (4) - id: faretransferrule name: fare_transfer_rules.txt helpContent: Fare rules for transfers between legs of travel defined in fare_leg_rules.txt. From 5de97f530f683eef9a1fdf3bb1a8e3de3f8aec7f Mon Sep 17 00:00:00 2001 From: Josh Willis <168561922+josh-willis-arcadis@users.noreply.github.com> Date: Mon, 10 Feb 2025 15:00:21 -0600 Subject: [PATCH 13/32] add currency dropdown to fare_product --- gtfs.yml | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/gtfs.yml b/gtfs.yml index 76cd2661b..f3c49ab2b 100644 --- a/gtfs.yml +++ b/gtfs.yml @@ -1038,7 +1038,31 @@ required: true - name: currency required: true - inputType: TEXT # FARE-TODO: Dropdownx + inputType: DROPDOWN + bulkEditEnabled: true + options: + - value: USD + text: US dollar (USD) + - value: AUD + text: Australian dollar (AUD) + - value: CAD + text: Canadian dollar (CAD) + - value: CHF + text: Swiss franc (CHF) + - value: CNH + text: Chinese renminbi (CNH) + - value: EUR + text: Euro (EUR) + - value: GBP + text: Pound sterling (GBP) + - value: JPY + text: Japanese yen (JPY) + - value: MXN + text: Mexican peso (MXN) + - value: NZD + text: New Zealand dollar (NZD) + - value: SEK + text: Swedish krona (SEK) - id: faremedia name: fare_media.txt helpContent: To describe the different fare media that can be employed to use fare products. Fare media are physical or virtual holders used for the representation and/or validation of a fare product. From 404900e19ecf707eacacbb1c3a1e084ca6648c13 Mon Sep 17 00:00:00 2001 From: Josh Willis <168561922+josh-willis-arcadis@users.noreply.github.com> Date: Thu, 13 Feb 2025 15:33:17 -0600 Subject: [PATCH 14/32] Revert "add GTFS_FARE_MEDIA type" This reverts commit 17d7f9486f257455ae304c6113c9d10af40b19b7. --- gtfs.yml | 4 ++-- lib/editor/components/EditorInput.js | 3 +-- lib/editor/util/validation.js | 1 - lib/types/index.js | 3 +-- 4 files changed, 4 insertions(+), 7 deletions(-) diff --git a/gtfs.yml b/gtfs.yml index f3c49ab2b..56af12723 100644 --- a/gtfs.yml +++ b/gtfs.yml @@ -1032,7 +1032,7 @@ inputType: TEXT - name: fare_media_id required: false - inputType: GTFS_FARE_MEDIA # FARE-TODO: Needs to reference an actual fare media id. need custom type + inputType: TEXT # FARE-TODO: Needs to reference an actual fare media id. need custom type - name: amount inputType: NUMBER required: true @@ -1069,7 +1069,7 @@ fields: - name: fare_media_id required: true - inputType: GTFS_FARE_MEDIA + inputType: GTFS_ID - name: fare_media_name inputType: TEXT - name: fare_media_type diff --git a/lib/editor/components/EditorInput.js b/lib/editor/components/EditorInput.js index ac94a2a27..b72248c54 100644 --- a/lib/editor/components/EditorInput.js +++ b/lib/editor/components/EditorInput.js @@ -164,8 +164,7 @@ export default class EditorInput extends React.Component { case 'POSITIVE_NUM': case 'GTFS_BLOCK': case 'GTFS_FARE': - case 'GTFS_SERVICE': - case 'GTFS_FARE_MEDIA': { + case 'GTFS_SERVICE': { // Ensure that an empty string is passed to value prop, so that on 'undo' // the input value will revert back to a blank field. const stringValue = typeof fieldProps.value === 'undefined' diff --git a/lib/editor/util/validation.js b/lib/editor/util/validation.js index 9dd1d94ec..a94e23b6a 100644 --- a/lib/editor/util/validation.js +++ b/lib/editor/util/validation.js @@ -204,7 +204,6 @@ export function validate ( case 'GTFS_BLOCK': case 'GTFS_FARE': case 'GTFS_SERVICE': - case 'GTFS_FARE_MEDIA': if (isRequiredButEmpty) { return emptyFieldValidationIssue() } else { diff --git a/lib/types/index.js b/lib/types/index.js index 4550e2d7a..1c176ef4e 100644 --- a/lib/types/index.js +++ b/lib/types/index.js @@ -41,8 +41,7 @@ type InputType = 'DAY_OF_WEEK_BOOLEAN' | 'NUMBER' | 'GTFS_FARE' | - 'EXCEPTION_DATE' | - 'GTFS_FARE_MEDIA' + 'EXCEPTION_DATE' export type RtdEntity = { AgencyId: string, From 95c4dc6b294769ab7b8ebcc9d45b33929fbea493 Mon Sep 17 00:00:00 2001 From: Josh Willis <168561922+josh-willis-arcadis@users.noreply.github.com> Date: Mon, 14 Apr 2025 12:02:28 -0500 Subject: [PATCH 15/32] add fare product input type --- gtfs.yml | 2 +- lib/editor/components/EditorInput.js | 14 ++++++ lib/editor/components/FareProductSelect.js | 53 ++++++++++++++++++++++ lib/types/index.js | 3 +- 4 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 lib/editor/components/FareProductSelect.js diff --git a/gtfs.yml b/gtfs.yml index 56af12723..0cc7e8776 100644 --- a/gtfs.yml +++ b/gtfs.yml @@ -1117,7 +1117,7 @@ - value: '2' - name: fare_product_id required: false - inputType: TEXT # FARE-TODO: Needs to reference fare_products + inputType: GTFS_FARE_PRODUCT # FARE-TODO: Needs to reference fare_products - id: farelegrule name: fare_leg_rules.txt # FARE-TODO: Some help content? diff --git a/lib/editor/components/EditorInput.js b/lib/editor/components/EditorInput.js index b72248c54..1aa4d72c3 100644 --- a/lib/editor/components/EditorInput.js +++ b/lib/editor/components/EditorInput.js @@ -20,6 +20,7 @@ import type {Entity, Feed, GtfsSpecField, GtfsAgency, GtfsStop} from '../../type import type {EditorTables} from '../../types/reducers' import ColorField from './ColorField' +import FareProductSelect from './FareProductSelect' import RouteTypeSelect from './RouteTypeSelect' import VirtualizedEntitySelect from './VirtualizedEntitySelect' import ZoneSelect from './ZoneSelect' @@ -386,6 +387,19 @@ export default class EditorInput extends React.Component { ) } + // FARE-TODO NEW TYPE DRPDOWN HERE + case 'GTFS_FARE_PRODUCT': + const fareProducts = getTableById(tableData, 'fareproduct') + return ( + + {basicLabel} + + + ) default: return null } diff --git a/lib/editor/components/FareProductSelect.js b/lib/editor/components/FareProductSelect.js new file mode 100644 index 000000000..25e7316a3 --- /dev/null +++ b/lib/editor/components/FareProductSelect.js @@ -0,0 +1,53 @@ +// @flow + +import React, {Component} from 'react' +import Select from 'react-select' + +import type {ZoneOption} from '../../types' + +type Props = { + addCreateOption?: boolean, + onChange: ?ZoneOption => void, + options: Array, + placeholder: string, + value: ?ZoneOption +} + +type State = { + value: any +} + +export default class FareProductSelect extends Component { + static defaultProps = { + placeholder: 'Select fare product ID...' + } + + state = { + value: null + } + + _onChange = (option: ZoneOption) => { + const value = option ? option.value : null + this.setState({value}) + } + + render () { + const {addCreateOption, onChange, placeholder, value, options} = this.props + const filterOptions = addCreateOption ? this._filterZoneOptions : undefined + if (value && typeof value === 'string' && !options.find(option => option.value === value)) { + console.warn(`${value} not found in zone options. Adding to options.`) + options.push({label: value, value}) + } + return ( + + + ) default: return null } diff --git a/lib/editor/components/FareProductSelect.js b/lib/editor/components/FareProductSelect.js index 9da0bcf70..19ed63604 100644 --- a/lib/editor/components/FareProductSelect.js +++ b/lib/editor/components/FareProductSelect.js @@ -32,8 +32,7 @@ export default class FareProductSelect extends Component { } render () { - const {addCreateOption, onChange, placeholder, value, options} = this.props - const filterOptions = addCreateOption ? this._filterZoneOptions : undefined + const {onChange, placeholder, value, options} = this.props if (value && typeof value === 'string' && !options.find(option => option.value === value)) { console.warn(`${value} not found in fare product options. Adding to options.`) options.push({label: value, value}) @@ -42,7 +41,6 @@ export default class FareProductSelect extends Component { + + ) default: return null } diff --git a/lib/types/index.js b/lib/types/index.js index 9397106d7..5ada0ef18 100644 --- a/lib/types/index.js +++ b/lib/types/index.js @@ -43,7 +43,8 @@ type InputType = 'GTFS_FARE' | 'EXCEPTION_DATE' | // FARE-TODO NEW TYPES!!!!! 'GTFS_FARE_PRODUCT' | - 'GTFS_FARE_MEDIA' + 'GTFS_FARE_MEDIA' | + 'GTFS_STOP_AREA' export type RtdEntity = { AgencyId: string, From 0042661673007ded60090eaf6e641c0d73c325fa Mon Sep 17 00:00:00 2001 From: Josh Willis <168561922+josh-willis-arcadis@users.noreply.github.com> Date: Mon, 28 Jul 2025 16:46:50 -0500 Subject: [PATCH 24/32] start table select component --- gtfs.yml | 12 +- .../components/EntityListSecondaryActions.js | 33 ++++- .../components/VirtualizedTableSelect.js | 124 ++++++++++++++++++ lib/editor/util/ui.js | 19 ++- 4 files changed, 177 insertions(+), 11 deletions(-) create mode 100644 lib/editor/components/VirtualizedTableSelect.js diff --git a/gtfs.yml b/gtfs.yml index ae883262c..f4d45784a 100644 --- a/gtfs.yml +++ b/gtfs.yml @@ -233,12 +233,12 @@ text: Not possible (2) columnWidth: 12 helpContent: "The wheelchair_boarding field identifies whether wheelchair boardings are possible from the specified stop or station. The field can have the following values:" - - name: "stop_area_id" - required: false - inputType: GTFS_STOP_AREA - bulkEditEnabled: true - columnWidth: 12 - helpContent: "The area_id field defines the area that this stop belongs to. This is used to group stops together in a logical way, such as all stops in a particular neighborhood or district. If this stop is not part of an area, leave this field blank." + # - name: "stop_area_id" + # required: false + # inputType: GTFS_STOP_AREA + # bulkEditEnabled: true + # columnWidth: 12 + # helpContent: "The area_id field defines the area that this stop belongs to. This is used to group stops together in a logical way, such as all stops in a particular neighborhood or district. If this stop is not part of an area, leave this field blank." - id: route name: routes.txt diff --git a/lib/editor/components/EntityListSecondaryActions.js b/lib/editor/components/EntityListSecondaryActions.js index 76886831e..deec687a8 100644 --- a/lib/editor/components/EntityListSecondaryActions.js +++ b/lib/editor/components/EntityListSecondaryActions.js @@ -4,10 +4,11 @@ import React, {Component} from 'react' import { Nav, NavItem } from 'react-bootstrap' import * as activeActions from '../actions/active' -import VirtualizedEntitySelect from './VirtualizedEntitySelect' - import type {Entity, Feed} from '../../types' +import VirtualizedEntitySelect from './VirtualizedEntitySelect' +import VirtualizedTableSelect from './VirtualizedTableSelect' + type Props = { activeComponent: string, activeEntity: Entity, @@ -97,6 +98,13 @@ export default class EntityListSecondaryActions extends Component { } } + _onTableSelect = (option: any) => { + console.log('onTableSelect::::::', option) + if (this.props.activeComponent !== option.value) { + this.props.setActiveEntity(this.props.feedSource.id, option.value) + } + } + render () { const { activeComponent, @@ -135,6 +143,27 @@ export default class EntityListSecondaryActions extends Component { entities={entities} onChange={this._onChangeEntity} /> ) + case 'fareproduct': + case 'faremedia': + case 'faretransferrule': + case 'farelegrule': + case 'area': + console.log('entities::::::', entities) + const faresv2Tables = [ + 'faremedia', + 'fareproduct', + 'faretransferrule', + 'farelegrule', + 'area' + ] + return ( + + ) default: return null } diff --git a/lib/editor/components/VirtualizedTableSelect.js b/lib/editor/components/VirtualizedTableSelect.js new file mode 100644 index 000000000..85d0b3d74 --- /dev/null +++ b/lib/editor/components/VirtualizedTableSelect.js @@ -0,0 +1,124 @@ +// @flow + +import React, {Component} from 'react' +import VirtualizedSelect from 'react-virtualized-select' + +// FARE-TODO: clean up this file!!!! +// import {getEntityName} from '../util/gtfs' + +import type {Entity, Style} from '../../types' + +export type EntityOption = { + entity: Entity, + label: string, + value: string +} + +type Props = { + clearable?: boolean, + component: string, + entities: Array, + // entityKey: string, + onChange: any => void, + optionRenderer?: Function, + style?: Style, + value?: any +} + +type State = { + options: Array, + value: any +} + +export default class VirtualizedEntitySelect extends Component { + static defaultProps = { + clearable: true + // entityKey: 'id' + } + + componentWillMount () { + this.setState({ + value: this.props.value, + options: [] + }) + } + + /** + * This component can hold a large number of options, so its + * shouldComponentUpdate method checks only for changes in state (i.e., the + * selected value) and a change in length of its entities. + */ + // shouldComponentUpdate (nextProps, nextState) { + // if (nextState.value !== this.state.value || this.state.options.length !== nextState.options.length) { + // return true + // } + // const nextEntities = nextProps.entities || [] + // const currentEntities = this.props.entities || [] + // if (nextEntities.length !== currentEntities.length) { + // console.log('entities length changed', nextEntities, currentEntities) + // return true + // } + // return false + // } + + componentWillReceiveProps (nextProps: Props) { + if (this.state.value !== nextProps.value && typeof this.props.value !== 'undefined') { + this.setState({value: nextProps.value}) + } + } + + _onChange = (value: any) => { + const {onChange} = this.props + this.setState({value}) + onChange && onChange(value) + } + + _entityToOption = (entity: any) => { + // const {entityKey} = this.props + return { + value: entity, + label: entity, + entity + } + } + + render () { + const { + clearable, + component, + entities, + optionRenderer, + style + } = this.props + const {value} = this.state + let disabled = false + let placeholder = `Select ${component}...` + let options = [] + if (entities.length > 30000) { + console.warn(`Entity list too large (count=${entities.length}). Disabling entity selector.`) + disabled = true + placeholder = 'Selector disabled. List is too large.' + } else { + options = entities + .filter(e => { + if (e.id < 0) { + console.warn(`Entity has a negative id, which indicates an unsaved entity that should not be selectable. Filtering out of selector.`, e) + return false + } else return e + }) + .map(this._entityToOption) + } + return ( + + ) + } +} diff --git a/lib/editor/util/ui.js b/lib/editor/util/ui.js index 5c83e5867..77bef57c5 100644 --- a/lib/editor/util/ui.js +++ b/lib/editor/util/ui.js @@ -77,16 +77,17 @@ export const GTFS_ICONS = [ { id: 'fareproduct', tableName: 'fareproduct', - icon: 'shopping-cart', + icon: 'money', addable: true, - title: 'FARE PRODUCT TEST TITLE', - label: 'V2: Products' + title: 'Fares (v2)', + label: 'Fares (v2)' }, { id: 'faremedia', tableName: 'faremedia', icon: 'id-card', addable: true, + hideSidebar: true, title: 'FARE MEDIA TEST TITLE', label: 'V2: Media' }, @@ -95,6 +96,7 @@ export const GTFS_ICONS = [ tableName: 'faretransferrule', icon: 'link', addable: true, + hideSidebar: true, title: 'FARE TRANSFER RULE TEST TITLE', label: 'V2: Transfer Rules' }, @@ -103,6 +105,7 @@ export const GTFS_ICONS = [ tableName: 'farelegrule', icon: 'book', addable: true, + hideSidebar: true, title: 'FARE LEG RULE TEST TITLE', label: 'V2: Leg Rules' }, @@ -111,8 +114,18 @@ export const GTFS_ICONS = [ tableName: 'area', icon: 'map', addable: true, + hideSidebar: true, title: 'AREAS TEST TITLE', label: 'V2: Areas' + }, + { + id: 'stoparea', + tableName: 'stoparea', + icon: 'map-marker', + addable: true, + hideSidebar: true, + title: 'STOP AREAS TEST TITLE', + label: 'V2: Stop Areas' } ] From 1eefea557ee06ad80a72d6f5b2414ab106e0a0fd Mon Sep 17 00:00:00 2001 From: Josh Willis <168561922+josh-willis-arcadis@users.noreply.github.com> Date: Thu, 7 Aug 2025 17:10:55 -0500 Subject: [PATCH 25/32] initial support for stop_area_ids on stop entities --- gtfs.yml | 25 ++----- lib/editor/actions/editor.js | 5 -- lib/editor/components/EditorInput.js | 15 ++-- lib/editor/components/StopAreasSelector.js | 86 ++++++++++++++++++++++ lib/editor/reducers/data.js | 1 - lib/editor/util/gtfs.js | 7 +- lib/editor/util/ui.js | 4 +- lib/types/reducers.js | 1 - 8 files changed, 107 insertions(+), 37 deletions(-) create mode 100644 lib/editor/components/StopAreasSelector.js diff --git a/gtfs.yml b/gtfs.yml index f4d45784a..3a06f1c4f 100644 --- a/gtfs.yml +++ b/gtfs.yml @@ -233,12 +233,12 @@ text: Not possible (2) columnWidth: 12 helpContent: "The wheelchair_boarding field identifies whether wheelchair boardings are possible from the specified stop or station. The field can have the following values:" - # - name: "stop_area_id" - # required: false - # inputType: GTFS_STOP_AREA - # bulkEditEnabled: true - # columnWidth: 12 - # helpContent: "The area_id field defines the area that this stop belongs to. This is used to group stops together in a logical way, such as all stops in a particular neighborhood or district. If this stop is not part of an area, leave this field blank." + - name: "stop_area_ids" + required: false + inputType: GTFS_STOP_AREA + bulkEditEnabled: true + columnWidth: 12 + helpContent: "The area_id field defines the area that this stop belongs to. This is used to group stops together in a logical way, such as all stops in a particular neighborhood or district. If this stop is not part of an area, leave this field blank." - id: route name: routes.txt @@ -1159,19 +1159,6 @@ - name: area_id required: true inputType: GTFS_ID - - name: area_name - required: false - inputType: TEXT -- id: stoparea - name: stop_areas.txt - helpContent: Areas that can be used to define fare zones for stops. - fields: - - name: area_id - required: true - inputType: GTFS_AREA - - name: stop_id - required: true - inputType: GTFS_STOP - name: area_name required: false inputType: TEXT \ No newline at end of file diff --git a/lib/editor/actions/editor.js b/lib/editor/actions/editor.js index 5a7f647f9..7bb68891a 100644 --- a/lib/editor/actions/editor.js +++ b/lib/editor/actions/editor.js @@ -552,11 +552,6 @@ export function fetchBaseGtfs ({ stop_lon zone_id # needed for fares } - stop_area (limit: -1) { - id - stop_id - area_id - } } } ` diff --git a/lib/editor/components/EditorInput.js b/lib/editor/components/EditorInput.js index 0c596281d..12364cb05 100644 --- a/lib/editor/components/EditorInput.js +++ b/lib/editor/components/EditorInput.js @@ -21,6 +21,7 @@ import type {EditorTables} from '../../types/reducers' import ColorField from './ColorField' import FareProductSelect from './FareProductSelect' +import StopAreasSelector from './StopAreasSelector' import RouteTypeSelect from './RouteTypeSelect' import VirtualizedEntitySelect from './VirtualizedEntitySelect' import ZoneSelect from './ZoneSelect' @@ -420,18 +421,18 @@ export default class EditorInput extends React.Component { ) case 'GTFS_STOP_AREA': - const stopAreas = getTableById(tableData, 'area').map(stopArea => ({ - value: stopArea.area_id, - label: stopArea.area_name || stopArea.area_id - })) + const areas = getTableById(tableData, 'area') + const stops = getTableById(tableData, 'stop') return ( {basicLabel} -