Repository navigation
feat: add feed location directory - #259
Alessandro100 wants to merge 11 commits into
Conversation
Turn the Feeds header item into a dropdown (Search, Locations), add a Locations footer link, and add the /locations directory: continent > country > subdivision > municipality with GTFS / GTFS-RT / GBFS counts, breadcrumbs, and a paginated, relevance-sorted feed list using the search page's compact view. Also move the translation hook in SearchTable's data type cell into a component, so changing the number of rows no longer breaks the hook order. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
A 400 or 404 from the location directory API was cached as a missing location for a day, so a page requested before the API route was deployed kept returning 404 after it was. Throw on a miss inside the cached functions, which unstable_cache never stores, and resolve it to null outside the cache. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Use the feed detail page's container and breadcrumb navigation, with its back button, and show GTFS / GTFS-RT / GBFS counts as chips. Child locations are now sorted by feed count, shown as shadowed cards like the advanced search results, and listed in a scrollable box with a search field that filters them by name, ignoring accents and case. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Country segments use name slugs (/locations/europe/portugal) through the API's new `country` parameter; API types regenerated. - Child cards show per-type feed counts as plain text instead of chips. - Child search field gets a white background. - No viewport prefetch on child cards and pagination links. - Directory data cache lowered from 1 day to 6 hours. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Clicking a child location shows a pending bar on its card (useLinkStatus, delayed 150ms to avoid flashing on fast navigations). - loading.tsx renders a skeleton of the location page while it streams. - Feed counts on child cards show their numbers in bold. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The feeds of a location node come from /v1/search with the node's location parameters, the directory statuses and sort=location, replacing the removed /v1/locations/directory/feeds endpoint. The root page has no location, so it lists the newest feeds first. API types regenerated and the search mock serves directory feeds for location queries. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Pages use /v1/locations (continents, countries of a continent, a location
by path, its children by parent_location_id) and /v1/search with continent
or location_id, replacing /v1/locations/directory.
- /locations/{continent}/{path...} works at any depth; segments are the API
slugs, and the breadcrumb comes from path_names and path_slugs.
- Children are fetched page by page on the server (100 per call).
- Mocks cover variable depth and suffixed slugs; level-specific wording is
now level-agnostic.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The location filters and feed counts now locate GTFS Realtime feeds through the schedule feeds they reference; only the descriptions change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
*Lighthouse ran on https://mobilitydatabase-7kyufzses-mobility-data.vercel.app/ * (Desktop)
*Lighthouse ran on https://mobilitydatabase-7kyufzses-mobility-data.vercel.app/feeds * (Desktop)
*Lighthouse ran on https://mobilitydatabase-7kyufzses-mobility-data.vercel.app/feeds/gtfs/mdb-2126 * (Desktop)
*Lighthouse ran on https://mobilitydatabase-7kyufzses-mobility-data.vercel.app/feeds/gtfs_rt/mdb-2585 * (Desktop)
*Lighthouse ran on https://mobilitydatabase-7kyufzses-mobility-data.vercel.app/feeds/gbfs/gbfs-flamingo_porirua * (Desktop)
|
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every directory page now resolves its URL with /v1/locations/lookup?path=...&include=feed_counts,children and lists its feeds with /v1/search?location_path=..., both sent at the same time, so a page waits for one round trip. Continents are ordinary locations with negative ids, and a location's path is its URL after /locations/, so the continent special cases are gone. Empty feed pages are never cached, so an unknown URL leaves nothing in the data cache. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Summary:
Adds a feed location directory at
/locations. Depends on MobilityData/mobility-feed-api#1884, which adds location lookup, children and feed counts to the locations API and location filters to/v1/search, built on the OSM geopolygon data.Header: "Feeds" is now a dropdown like "Tools", with "Search" (
/feeds) and "Locations" (/locations). Clicking "Feeds" on desktop still goes to/feeds. On mobile, the drawer shows "Feeds" as an accordion.Footer: "Locations" link next to "Feeds".
/locations/[[...location]]:/locations/{path...}at any depth, with?page=N. For example:/locations/north-america/canada/quebec./locations/is exactly the API'spath, from the continent down, so depth follows each country's geopolygon hierarchy./locations/clipperton)./feeds(SearchTable), 20 per page.Data: every page's API calls are built from the URL alone and sent at the same time, so a page waits for one round trip.
/locations: continents from/v1/locations?location_type=continent&has_feeds=true&include=feed_counts&sort=feed_count, and the newest feeds./v1/locations/lookup?path=<path>&include=feed_counts,children&has_feeds=true&sort=feed_count&limit=100returns the location and the first 100 children that have feeds./v1/search?location_path=<path>&status=active,inactive,development,future&sort=locationreturns the feeds, those with most of their stops in the place first. These statuses are the ones the counts include./v1/locations/{location_id}/children, fetched in parallel on the server.Loading states:
useLinkStatus, shown after 150ms so fast navigations don't flash).loading.tsxrenders a skeleton of the page while the next location streams in.SEO:
generateMetadata(title, description, canonical URL, OpenGraph).prefetch={false}, since a location can list hundreds of children.Caching:
location-directoryandguest-feedstags, sorevalidateAllFeeds()also clears it.i18n: new
locationsnamespace inenandfr. Headings don't name a level ("Places"), since depth varies by country.Mocks: MSW mocks for:
/v1/locations;/v1/searchwithlocation_idorlocation_path.The data is fictional:
ApiError: inservices/feeds/index.ts, it now carries the HTTP status (the message is unchanged), so the page can map 400/404 tonotFound().Fix:
getDataTypeElementinSearchTablecalleduseTranslationsonce per row. That crashed when the row count changed between renders, for example moving from a partial last page to a full one. The hook now lives in a smallDataTypeElementcomponent.CI:
cypress-io/github-actionbumped to v7 (fixes the "Socket closed" e2e failures; same change as in feat: unsubscribe page #255).Before merging:
src/app/services/feeds/types.tswas generated from the API PR's spec. After the API change is released, runyarn generate:api-typesagain, and merge this after the API PR.Known limitations:
/frpages show "North America".loading.tsxstarts streaming beforenotFound()runs (already the case before this change).https://mobilitydatabase.orgbase.Expected behavior:
/locationsshows the continents with counts./locations/north-americalists its countries that have feeds, most feeds first./locations/north-america/canada/quebec/montreal?page=2shows feeds 21 onward./locations/North-America,/locations/atlantis,/locations/europe/canadaand?page=0render the not-found page.Testing tips:
yarn start:dev:mock, then browse/locationsand/fr/locations.Against real data: the API PR is deployed to dev, so the Vercel preview of this branch shows real data. On dev, a page nobody had opened loaded in 0.56 to 0.93 s (lookup 0.21 to 0.62 s, search 0.05 to 0.45 s); cached pages load in about 0.3 s.
Checks:
yarn lint(0 errors; 3 warnings in files this PR doesn't touch),yarn test:ci(661 passed) andnpx tsc --noEmitpass.Run the unit tests with
yarn testto make sure you didn't break anythingAdd or update any needed documentation to the repo
Format the title like "feat: [new feature short description]". Title must follow the Conventional Commit Specification(https://www.conventionalcommits.org/en/v1.0.0/).
Linked all relevant issues
Include screenshot(s) showing how this pull request works and fixes the issue(s)
Generated with Claude Code