diff --git a/backend/migrations/core/086_migrate_non_grid_standard_to_banner.js b/backend/migrations/core/086_migrate_non_grid_standard_to_banner.js index dcc9f29f..2d3340b6 100644 --- a/backend/migrations/core/086_migrate_non_grid_standard_to_banner.js +++ b/backend/migrations/core/086_migrate_non_grid_standard_to_banner.js @@ -8,8 +8,17 @@ * a new 'banner' option has been added that adds the colored banner above * the standard header. * + * In the same release, GalleryView.tsx stopped deriving controlsStyle from + * the layout — non-grid events used to default to the sidebar drawer via + * `theme.galleryLayout !== 'grid' || isHeroHeader`, and now require an + * explicit `theme.controlsStyle === 'sidebar'`. To keep affected events + * pixel-identical post-upgrade, this migration also sets controlsStyle to + * 'sidebar' when it was previously unset on every event we flip to banner. + * * To keep current galleries looking the same, every event whose effective - * config was non-grid + standard gets migrated to non-grid + banner. + * config was non-grid + standard gets migrated to non-grid + banner, and + * its controlsStyle is pinned to whatever the runtime would have used + * before the decoupling. */ const NON_GRID_LAYOUTS = ['masonry', 'carousel', 'timeline', 'mosaic']; @@ -22,6 +31,7 @@ exports.up = async function(knex) { .select('id', 'color_theme'); let migratedCount = 0; + let controlsPinnedCount = 0; for (const event of events) { try { @@ -37,6 +47,15 @@ exports.up = async function(knex) { const updatedTheme = { ...theme, headerStyle: 'banner' }; + // Preserve previous filter placement: before this release, non-grid + // layouts implicitly rendered the sidebar drawer when controlsStyle + // was unset. Pin it to 'sidebar' so the visual stays identical. Don't + // overwrite explicit values the user may have set deliberately. + if (!theme.controlsStyle) { + updatedTheme.controlsStyle = 'sidebar'; + controlsPinnedCount++; + } + await knex('events') .where('id', event.id) .update({ @@ -51,6 +70,7 @@ exports.up = async function(knex) { } console.log(`[Migration 086] Migrated ${migratedCount} events from standard to banner`); + console.log(`[Migration 086] Pinned controlsStyle='sidebar' on ${controlsPinnedCount} events`); }; exports.down = async function(knex) { @@ -79,6 +99,15 @@ exports.down = async function(knex) { const revertedTheme = { ...theme, headerStyle: 'standard' }; + // Symmetric with up: if controlsStyle is currently 'sidebar', drop it + // so the runtime falls back to whatever the older code would compute. + // Cannot perfectly distinguish "we set this" from "user agreed", but + // the scope is narrow (non-grid + banner) and rolling back is + // intentionally restoring pre-migration state. + if (revertedTheme.controlsStyle === 'sidebar') { + delete revertedTheme.controlsStyle; + } + await knex('events') .where('id', event.id) .update({