Skip to content

[pull] main from TryGhost:main - #1429

Merged
pull[bot] merged 11 commits into
code:mainfrom
TryGhost:main
Aug 19, 2026
Merged

pull[bot] merged 11 commits into
code:mainfrom
TryGhost:main

Conversation

@pull

@pull pull Bot commented Aug 19, 2026 •

Copy link
Copy Markdown

See Commits and Changes for more details.


Created by pull[bot] (v2.0.0-alpha.4)

Can you help keep this open source service alive? 💖 Please sponsor : )

kevinansfield and others added 11 commits August 19, 2026 16:58
no issue

The custom fields import dialog should ask before closing when the mapping
has been changed. It could miss that check if Escape was pressed immediately
after an edit, and close without showing "Leave without importing?".

`hasEdits` was React state read from the `handleOpenChange` render closure.
Radix keeps `onOpenChange` in a callback ref that it updates in a passive
effect, while its Escape listener runs on `document` outside React event
dispatch. If Escape arrived before React committed and flushed the edit,
Radix could call the old closure and see `hasEdits` as false.

Nothing renders from this flag, so it uses a ref now. The edit updates the
ref immediately, and `handleOpenChange` reads the current value.
no refs

## History and intent

Portal introduced `contrast-color.js` in July 2020 to calculate
complementary text and icon colours for accent-coloured controls:

fb6a2c9

Portal deliberately removed that automatic colour inversion in October
2020:

b037d98

The second commit provides direct evidence that making this utility
unreachable was intentional rather than accidental: its message is
`Removed auto-invert color from primary buttons`, and its atomic diff
removes every import of the utility while replacing each computed
foreground colour with `#fff` across trigger icons, trigger text, and
primary action buttons.

The historical record does **not** explain the deeper UX rationale for
preferring white. The commit body contains only `no refs`, GitHub has no
associated pull request or commit discussion, and adjacent styling work
provides no written rationale. Therefore, the supported conclusion is
limited to this: automatic inversion was intentionally retired in favour
of a fixed-white treatment. Design consistency is suggested by the diff,
but is an inference rather than documented intent.

## Why deletion is safe

The utility remained in the tree after its final consumers were
deliberately removed and has been unreachable for nearly six years. A
repository-wide usage search finds no remaining consumer, and Knip
independently reports the file as unused. Portal has a single
`src/index.jsx` build entry, and the published package includes only
built UMD output rather than internal source paths, so the utility
cannot be reached through a secondary entry point or public export.

Deleting the orphan preserves the intentional fixed-white behavior
established by the October 2020 change.

## Validation

- `pnpm --dir apps/portal lint`
- `pnpm --dir apps/portal test` (592 passed, 1 skipped)
- `pnpm --dir apps/portal build`
- `pnpm check` (lint and all other project tests passed; the aggregate
run reported `ghost:test` as flaky)
- `pnpm nx test ghost --skip-nx-cache` (604 files and 7,852 tests passed
on retry; Nx classified the prior failure as flaky)
- Cache the extracted `.ttf` files with `actions/cache` (key
`msttcorefonts-ttf-v1`; the fonts never change).
- Cache hit → copy the fonts into place, no apt, no network.
- Cache miss → install from apt with the existing bounded retry/timeout,
then stash the `.ttf`s for the cache to save.
- `fc-cache` after placing the fonts; then install the firefox media
codecs the video-card tests need.

Only a cache miss (first run, or after ~7-day cache eviction) touches
SourceForge, and that path still fails fast instead of hanging. Ghost's
CI runs frequently enough to keep the cache warm.
…30129)

no ref

#28368 added icons and visibility controls to navigation behind the
`navigationIcons` lab flag, but one part of it shipped ungated: the
built-in navigation partial started wrapping every label in `<span
class="nav-label">`.

That affects every theme that uses `{{navigation}}` without shipping its
own `partials/navigation.hbs`, whether or not the flag is on. CSS and JS
that target the anchor's text directly — `.nav a` flex/gap layouts,
`::before` tricks, truncation on the anchor, `a.textContent` reads — see
different markup than before.

The helper now passes the flag to the template as `@navigationIcons`,
and the template renders the icon plus the label wrapper only when it is
set. With the flag off, output is byte-identical to the pre-#28368
markup.

The flag-off tests now assert the bare label, plus a new test that
asserts the full rendered string matches the old markup exactly.
fixes #30100

The 6.58 rename of `email_batches.provider_id` asked for `ALGORITHM=INSTANT`,
which MySQL only accepts for RENAME COLUMN from 8.0.28 onwards. Anyone on an
older 8.0 server — still supported per our docs — hit
ER_ALTER_OPERATION_NOT_SUPPORTED and could not upgrade past 6.58.

That migration now asks for `auto`, which is what every other algorithm-bearing
migration uses and costs nothing here: a plain RENAME COLUMN is metadata-only on
INPLACE too, and 8.0.28+ servers still pick INSTANT themselves. Editing a shipped
migration is safe because knex-migrator tracks migrations by name with no
checksum, so sites that already ran it skip it and stuck sites run the fixed
version.

To stop this recurring, the schema commands now retry an ALTER without the
algorithm clause when the server rejects it. INSTANT support is per-operation
(ADD COLUMN 8.0.12, RENAME COLUMN 8.0.28, DROP COLUMN 8.0.29), so a version
matrix in the migration utils would be a maintenance trap; reacting to the
server's own error is version- and vendor-agnostic and costs nothing on the
happy path. Verified against real MySQL 8.0.21 and 8.4 containers.
closes https://linear.app/ghost/issue/NY-1526

Added Last entry, Total entries, and In progress columns using stats
from the automation browse API. Kept the mobile list focused on name and
status, and gated the new stats behind automationRunAnalytics while run
analytics remains experimental.

<img width="1560" height="1043" alt="image"
src="https://github.com/user-attachments/assets/c60cfc64-480e-4e6f-a0c9-490391d1099e"
/>
no ref

Follow-up to #30129.

The navigation settings validator accepts an item with an icon and no
label regardless of the `navigationIcons` flag. So enabling the flag,
adding an icon-only item, then disabling the flag leaves the front end
rendering `<li class="nav-"><a href="/foo"></a></li>` — an empty,
unlabelled link, since the icon is dropped when the flag is off.

Before #28368 that data threw an `IncorrectUsageError`, which is the
worse option: it 500s the whole front end for data Admin allowed to be
saved. So items with nothing to render are now dropped instead, and a
nav where every item drops out renders nothing, matching the existing
empty-nav behaviour.

Note this also drops an item with a null label and no icon, which
previously rendered the same empty link. That shape is only reachable by
writing to the database directly — Admin has always required a label
(now label-or-icon).

Tests: an icon-only item is dropped while a sibling label item still
renders, and an all-icon-only nav renders an empty string. Flag-on
icon-only rendering is unchanged and still covered.
@pull pull Bot locked and limited conversation to collaborators Aug 19, 2026
@pull pull Bot added the ⤵️ pull label Aug 19, 2026
@pull
pull Bot merged commit 3580c2d into code:main Aug 19, 2026
3 checks passed
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants