Skip to content

Make automated topLevelNavItems use built-in pages & nav improvements#1002

Open
rchlfryn wants to merge 21 commits intomainfrom
nav-updates
Open

Make automated topLevelNavItems use built-in pages & nav improvements#1002
rchlfryn wants to merge 21 commits intomainfrom
nav-updates

Conversation

@rchlfryn
Copy link
Collaborator

@rchlfryn rchlfryn commented Mar 23, 2026

Description

Improves the Navigation admin UI with contextual banners for automated fields, and seeds built-in page references for the forecasts, observations, blog, and events top-level nav tabs so their links appear as proper CMS relationships rather than being hardcoded.

Related Issues

Fixes #988
Fixes #825

Key Changes

  • Add one time script to add and assign built-in pages for current tenants in prod

  • BannerDescription component — new reusable Payload admin component that wraps @payloadcms/ui's Banner with an icon, used as contextual info banners on nav tabs

  • topLevelNavTab — adds hasReadOnlyLink and hasReadOnlyNavItems options; renders description as a ui field (banner) instead of plain tab description text; virtual logic updated to account for new options

  • itemsField — adds hasSubNavItems option to suppress the sub-item accordion UI for readonly tabs where sub-items aren't applicable

  • Seed — fetches active forecast zones per tenant from NAC API; creates zone-specific built-in pages; populates forecasts, observations, blog, and events navigation entries with proper builtInPage references

To navigation tabs:

  • Forecasts tab — now shows a readonly link and readonly items populated from NAC API zone data; single-zone centers (e.g. SAC) show a single "Avalanche Forecast" link, multi-zone centers (e.g. NWAC) show "All Forecasts" + per-zone items sorted by rank
  • Observations, blog, events tabs — now show readonly built-in page links seeded at seed time
  • Donate tab — switch enable UI to match others & banner description moved to render inline with the link field

How to test

  • Run pnpm seed
  • In admin, open Navigation:
    • Forecasts tab
      • single-zone center (SAC): Forecasts tab shows a single readonly link ("Avalanche Forecast"), no items
      • multi-zone center (NWAC): Forecasts tab shows "All Forecasts" readonly link + readonly items for each zone
    • Observations tab: shows "Recent Observations" and "Submit Observations" as readonly items
    • Blog and Events tabs: show their landing page as a readonly link
    • Donate tab: enable is similar to others & shows a "This nav item is styled as a button." banner above the link field

Screenshots / Demo video

https://www.loom.com/share/896c5419b9fb4909805422889d7a064a

Important

I updated the permission after the video to give superAdmin users edit access to read only nav items just in case we run into issues and need to edit. I also think this is okay to leave?

Migration Explanation

Adds link columns for blog, events, and forecasts to the navigations table. The forecasts tab previously had no link field; blog and events links were stored as plain URLs and are now proper relationships. All existing data should be re-seeded.

Migration script testing

Tested the one-time migration script (src/scripts/migrate-nav-builtin-pages.ts) against a copy of the production database following the Run one-time script in Notion.

Important

I ran the script on the preview environment so the admin panel will look like it will post script run

Deployment note: There is a brief window between deploying the code and running the migration script where forecasts will render as a single "Forecasts" link pointing to /forecasts/avalanche instead of the full zone dropdown. This is the default fallback at utils.ts:265-267. Once the migration script is run and the navigation cache is revalidated (Admin → Diagnostics → Revalidate Cache or republish each nav), the full dropdown appears.

Zone type Before migration script After migration script
Single-zone (SAC) Before migration SAC After migration SAC
Multi-zone (NWAC) Before migration NWAC <After migration NWAC

There are similar fallbacks for other refrences we are adding

  • Forecasts (utils.ts:265-267) — defaults to { label: 'Forecasts', url: '/forecasts/avalanche' }
  • Observations (utils.ts:296-300) — falls back to hardcoded "Recent Observations" and "Submit Observation" dropdown items
  • Blog (utils.ts:355) — falls back to { label: 'Blog', url: '/blog' }
  • Events (utils.ts:359) — falls back to { label: 'Events', url: '/events' }

Future enhancements / Questions

  • The provisioning script for new tenants should be updated to check NAC API zone count (single vs. multi-zone) and set the appropriate forecast built-in page URL(s) accordingly, rather than defaulting to the multi-zone "All Forecasts" pattern. Auto-detect single vs multi-zone center from AFP during provisioning #999
  • Do we want the ability to change the label for any of the read-only navigation items?

@rchlfryn rchlfryn changed the title Make automated topLevelNavItems use built-in pages Make automated topLevelNavItems use built-in pages & nav improvements Mar 23, 2026
@github-actions
Copy link
Contributor

github-actions bot commented Mar 23, 2026

Migration Safety Check

Found 29 potential issues:

20260325_142016_convert_auto_nav_items.ts

Warning (line 13): DELETE keyword detected - review for data loss

FOREIGN KEY (\`_parent_id\`) REFERENCES \`navigations\`(\`id\`) ON UPDATE no action ON DELETE cascade

Warning (line 30): DELETE keyword detected - review for data loss

FOREIGN KEY (\`_parent_id\`) REFERENCES \`navigations\`(\`id\`) ON UPDATE no action ON DELETE cascade

Warning (line 48): DELETE keyword detected - review for data loss

FOREIGN KEY (\`_parent_id\`) REFERENCES \`_navigations_v\`(\`id\`) ON UPDATE no action ON DELETE cascade

Warning (line 66): DELETE keyword detected - review for data loss

FOREIGN KEY (\`_parent_id\`) REFERENCES \`_navigations_v\`(\`id\`) ON UPDATE no action ON DELETE cascade

Warning (line 75): ALTER keyword detected - review for data loss

await db.run(sql`ALTER TABLE \`built_in_pages\` ADD \`is_in_nav\` integer DEFAULT false;`)

Warning (line 77): ALTER keyword detected - review for data loss

sql`ALTER TABLE \`navigations\` ADD \`forecasts_link_type\` text DEFAULT 'internal';`,

Warning (line 79): ALTER keyword detected - review for data loss

await db.run(sql`ALTER TABLE \`navigations\` ADD \`forecasts_link_url\` text;`)

Warning (line 80): ALTER keyword detected - review for data loss

await db.run(sql`ALTER TABLE \`navigations\` ADD \`forecasts_link_label\` text;`)

Warning (line 82): ALTER keyword detected - review for data loss

sql`ALTER TABLE \`navigations\` ADD \`forecasts_link_new_tab\` integer DEFAULT true;`,

Warning (line 84): ALTER keyword detected - review for data loss

await db.run(sql`ALTER TABLE \`navigations\` ADD \`blog_link_type\` text DEFAULT 'internal';`)

Warning (line 85): ALTER keyword detected - review for data loss

await db.run(sql`ALTER TABLE \`navigations\` ADD \`blog_link_url\` text;`)

Warning (line 86): ALTER keyword detected - review for data loss

await db.run(sql`ALTER TABLE \`navigations\` ADD \`blog_link_label\` text;`)

Warning (line 87): ALTER keyword detected - review for data loss

await db.run(sql`ALTER TABLE \`navigations\` ADD \`blog_link_new_tab\` integer DEFAULT true;`)

Warning (line 88): ALTER keyword detected - review for data loss

await db.run(sql`ALTER TABLE \`navigations\` ADD \`events_link_type\` text DEFAULT 'internal';`)

Warning (line 89): ALTER keyword detected - review for data loss

await db.run(sql`ALTER TABLE \`navigations\` ADD \`events_link_url\` text;`)

Warning (line 90): ALTER keyword detected - review for data loss

await db.run(sql`ALTER TABLE \`navigations\` ADD \`events_link_label\` text;`)

Warning (line 91): ALTER keyword detected - review for data loss

await db.run(sql`ALTER TABLE \`navigations\` ADD \`events_link_new_tab\` integer DEFAULT true;`)

Warning (line 93): ALTER keyword detected - review for data loss

sql`ALTER TABLE \`_navigations_v\` ADD \`version_forecasts_link_type\` text DEFAULT 'internal';`,

Warning (line 95): ALTER keyword detected - review for data loss

await db.run(sql`ALTER TABLE \`_navigations_v\` ADD \`version_forecasts_link_url\` text;`)

Warning (line 96): ALTER keyword detected - review for data loss

await db.run(sql`ALTER TABLE \`_navigations_v\` ADD \`version_forecasts_link_label\` text;`)

Warning (line 98): ALTER keyword detected - review for data loss

sql`ALTER TABLE \`_navigations_v\` ADD \`version_forecasts_link_new_tab\` integer DEFAULT true;`,

Warning (line 101): ALTER keyword detected - review for data loss

sql`ALTER TABLE \`_navigations_v\` ADD \`version_blog_link_type\` text DEFAULT 'internal';`,

Warning (line 103): ALTER keyword detected - review for data loss

await db.run(sql`ALTER TABLE \`_navigations_v\` ADD \`version_blog_link_url\` text;`)

Warning (line 104): ALTER keyword detected - review for data loss

await db.run(sql`ALTER TABLE \`_navigations_v\` ADD \`version_blog_link_label\` text;`)

Warning (line 106): ALTER keyword detected - review for data loss

sql`ALTER TABLE \`_navigations_v\` ADD \`version_blog_link_new_tab\` integer DEFAULT true;`,

Warning (line 109): ALTER keyword detected - review for data loss

sql`ALTER TABLE \`_navigations_v\` ADD \`version_events_link_type\` text DEFAULT 'internal';`,

Warning (line 111): ALTER keyword detected - review for data loss

await db.run(sql`ALTER TABLE \`_navigations_v\` ADD \`version_events_link_url\` text;`)

Warning (line 112): ALTER keyword detected - review for data loss

await db.run(sql`ALTER TABLE \`_navigations_v\` ADD \`version_events_link_label\` text;`)

Warning (line 114): ALTER keyword detected - review for data loss

sql`ALTER TABLE \`_navigations_v\` ADD \`version_events_link_new_tab\` integer DEFAULT true;`,

Review these patterns and add backup/restore logic if needed. See docs/migration-safety.md for guidance.

@github-actions
Copy link
Contributor

Preview deployment: https://nav-updates.preview.avy-fx.org

@rchlfryn rchlfryn marked this pull request as ready for review March 25, 2026 15:59
@rchlfryn rchlfryn requested a review from busbyk March 25, 2026 15:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Use built-in page references for automated top level nav items Navigation improvements - donate tab & sort link refs

1 participant