Skip to content

Conversation

@madewithlove-machine-user

Syncing fork to upstream release v6.9.3.

ibalosh and others added 30 commits November 24, 2025 15:14
…5514)

no_ref

* Removed hard-coded waits in favor of semantic element waits  
* Improved Labs section locator specificity
* Improved settings search tests
ref
TryGhost@fcd4034
- Introduced cumulative event counts to track overall metrics across
batches.
- Added unique emailIds and memberIds tracking to prevent
re-aggregation.
- Implemented delta calculations for batch processing to improve final
reporting accuracy.
- Updated final aggregation to ensure all unique emailIds and memberIds
are included in the results.
…Ghost#25520)

no ref

The email analytics job would not set the latest event timestamp when
doing back-to-back processing of batches (ie during high volume events).
If a site got rebooted during this period, it would necessitate
processing all of those events *again*, unnecessarily.
ref
https://linear.app/ghost/issue/NY-761/static-settings-ui-for-editing-saving-welcome-emails
ref
https://linear.app/ghost/issue/NY-760/static-settings-ui-for-activating-welcome-emails

- As the first step towards automations UI, this PR adds a static
version of settings for welcome emails, for both activating and editing
email contents.

---------

Co-authored-by: Chris Raible <[email protected]>
ref https://linear.app/ghost/issue/NY-722/migrate-ghost-codebase-to-kebab-case-file-naming-convention

* Renamed all files to match to kebab-case format
* Added ESLint kebab-case,
* Updated to match our working agreement on filenames in Ghost rep
ref https://linear.app/ghost/issue/NY-754/add-a-welcome-email-e2e-test

- Updated email client interface with missing option
- Cleaned up existing test and added new one to support welcome email check
- Added configuration settings for member welcome email (enable, and inbox)
ref GVA-600

Only enable the domain warming feature if the fallbackDomain &
fallbackAddress config values are set. If we don't have those config
values, then there isn't a way to do domain warming.
ref
https://linear.app/ghost/issue/BER-3067/slice-1-improve-the-search-modal-ux
ref
https://linear.app/ghost/issue/BER-3065/slice-1-update-search-field-placeholder

- Updated search input placeholder to reflect name and URL search in
addition to handle search
- Fixed modal size to remain consistent regardless of search results
- Moved loading indicator to search input to prevent result section from
flashing
- Kept last search result visible while loading to avoid content flash
- Made search results scrollable to handle increased result count from
expanded search types
ref
https://linear.app/ghost/issue/BER-3061/auto-submit-when-2fa-email-code-is-pasted

- When a user pastes a 6‑digit 2FA login code sent via email into the
code field, the form didn't automatically submit so users needed to tap
the button.
no ref
- Where possible, moved all varieties of filters into a central filter
pipe (session_data). This could get renamed to be more descriptive, but
I struggled to find a good name, and it would introduce more changes to
review.
- Updated tests; minimally, because we want to preserve behavior here.
This effort was largely removing the tests that depended on the removed
deprecated pipes/endpoints.
- Added readme describing structure and purpose.

When reviewing the Tinybird endpoints and filter logic, it became clear
there was a number of discrepancies that ultimately led to confusion and
inconsistency. This PR is an attempt to alleviate that. Let's do some
plumbing...

**Overview**
We have several kinds of filters in Tinybird. Let's call them:

always filters [date filters, site uuid, timezone]
(page) hit-level filters [pathname, post_uuid, member_status,
session filters
These need to be treated distinctly.

Always filters are so named because they are always applied - they are
our primary and secondary keys in analytics_events: ENGINE_SORTING_KEY
"site_uuid, timestamp". They optimize queries by reducing the data set.

Page hit data/filters are those that may change on any particular
page_hit. When clicking around, a user is navigating to different
pathnames which have unique poat_uuids. If they come to a site and then
log in, their member_status may change (currently).

Session data/filters are those that are wrapped up or attributed to the
session itself. For the various UTM parameters, we set those based on
the first page hit in the session within mv_session_data. Same for
source; these are commonly attribution elements.

**Architecture**
With this is mind, we have to differentiate in where and how we filter
by these various categories. We need to make sure when filtering by page
hit data, that we check every hit in a session, but when checking for
session data, that we only check the session (even if we include every
hit from that session in the end results).

This can be accomplished fairly simply: for any query, we filter by page
hit data, then session data, then take an intersection of the two. This
is what filtered_sessions.pipe does.

Endpoints themselves only need to specify the return data. And in some
cases, if the filters change the behavior, they made need to be
specified (e.g. api_top_pages needs pathname because otherwise you end
up seeing all session data for that path, which doesn't particularly
make sense in this case).

**Note that site_uuid is unique and kept around for query optimization
across the board within Clickhouse.**
closes https://linear.app/ghost/issue/BER-3048/the-ghost-loading-orb-isnt-displayed-on-startup

The React admin index.html was missing the loading indicator that exists in the
Ember admin, causing a blank page while waiting for assets to load.
refs https://linear.app/ghost/issue/BER-2989/integrate-new-admin-shell-with-yarn-dev

This adds a unified Ghost local development setup that leverages NX
for orchestration and Docker to for running the Ghost backend and it's
dependencies.
ref
https://linear.app/ghost/issue/DES-1250/toast-notification-spacing-bug-without-action-component

- Removed bottom margin from theme error banner message
- Prevents unnecessary white space below toast notifications
Closes https://linear.app/ghost/issue/BER-3010/fix-sidebar-active-state-for-submenu-items-and-add-tests

- Added getRouteUrl/isRouteActive methods to the Ember bridge that exposes the
  full route/query param state (that is automatically managed by Ember)
- Integrated bridged routing state routing via a controlled isActive state and 
  new useEmberRouting hook
- Added comprehensive unit tests

This enables the React admin shell to properly reflect Ember routing state
during the Ember-to-React migration phase, including support for "sticky"
query params/filters.
ref
https://linear.app/ghost/issue/BER-2924/clicking-unfollow-on-a-profile-flashes-and-then-says-youre-still

The unfollow API returns a `202 Accepted` status with an empty response
body, but the fetchJSON method was only handling `204 No Content`
responses. This caused the client to attempt parsing the empty response
as JSON, throwing an error and triggering the mutation error callback,
which reverted the button state back to "Following".
* Added tiny change to remove linter warning, one more to go to get them to zero
ref https://linear.app/ghost/issue/NY-722/migrate-ghost-codebase-to-kebab-case-file-naming-convention

* Renamed all files to match to kebab-case format
* Added ESLint kebab-case rule
* To match our working agreement on filenames in Ghost repo
)

no issue

If the `setInterval` pathway was hit by a state-bridge event hook then it would run indefinitely even if the hook that triggered it was unmounted. Aside from being a memory leak it also causes test flakiness because the `window` object used inside the timeout callback could have been torn down before the callback runs

- having a shared promise to avoid the possibility of multiple `setInterval` calls when multiple hooks are registered was a micro optimisation that complicates teardown significantly
- switched to each hook maintaining its own promise+setInterval with associated cleanup when unmounting
…host#25528)

closes https://linear.app/tryghost/issue/DES-1251/
closes https://linear.app/ghost/issue/ONC-1291/

- regression was introduced when we increased specificity of Ember Admin's `.hidden` class
- some wormholed/animated content gets rendered outside of the main `.gh-app` element meaning content that was hidden is now visible, resulting in text like "Photo of Staff Name" overlaying staff user images in the post history revisions list or delete icons in members filters not showing correctly
…ost#25541)

* Replaced page reload with visits to prevent that, especially after cookie clear
* Added explicit navigation before reload in newsletters test to ensure consistent page state
* Replaced cookie clearing with proper signout navigation for logout
* Used isolated browser context for 2FA tests to trigger 2fa requirement without need of cookie clearing
* This update should improve the trust in the test suite for tests like password reset, 2fa
…t#25532)

no issue

We'd like to avoid having any `postinstall` scripts as its best security practice to have npm install scripts disabled. The `esm` patch that we install with `patch-package` via `postinstall-postinstall` was only necessary for a specific range of Node versions (22.10.0-22.17.x) and is needed during the Ember Admin build that only impacts core developers who can more easily switch to a compatible Node version.

- added a node version compatibility check to `ember-cli-build.js` that is called on all Ember builds, outputting a helpful message when we detect an incompatible Node version being used before any build error can be hit
- removed the `esm` patch and associated packages
- bumped Node version to 22.18.0 in CI to support Ember Admin builds
…host#25522)

ref
https://linear.app/ghost/issue/NY-748/create-tinybird-mv-to-speed-up-monitoring-endpoints

## Problem
The Tinybird monitoring endpoints (and raw queries used in our
monitoring dashboard) are slow enough that they frequently timeout. Part
of the problem is the date parsing of the
`payload.meta.received_timestamp` field at query time.

## Solution
This change aims to improve the performance of these endpoints by
parsing the `inserted_at` and `received_at` fields and pre-calculating
the ingestion latency in the `mv_hits` materialized view, thereby moving
the parsing & calculating to ingest time, rather than query time.
* Simplifed preview modal load, by creating published post to preview
ref https://linear.app/ghost/issue/NY-722/migrate-ghost-codebase-to-kebab-case-file-naming-convention

* Renamed all files to match to kebab-case format
* Moved tests to match folder structure in other micro-aps
* Added ESLint kebab-case rule
* Updated `README` with the package release process 
* Added to match our working agreement on filenames in Ghost repo
…ryGhost#25545)

ref https://linear.app/ghost/issue/PRO-1540/

- running scripts during yarn install has been a recent/recurring security issue with compromised npm packages, we want to remove avenues for that to occur
…tainers (TryGhost#25545)" (TryGhost#25548)

This reverts commit 8abcfb5.

- caused sqlite3 bindings errors in CI runs
ref https://linear.app/ghost/issue/BER-3038

Added E2E test for the Sidebar and Custom Views (which is related to the Sidebar). Increased accessibility in both the Ember and React apps for the Sidebar and Posts page in order to power semantic queries in the test page objects.
…ryGhost#25550)

ref https://linear.app/ghost/issue/PRO-1540/

- running scripts during yarn install has been a recent/recurring security issue with compromised npm packages, we want to remove avenues for that to occur
- adding `--ignore-scripts` to all `yarn install` commands avoids running malicious commands in compromised packages but it introduces problems with sqlite3 as it uses a postinstall script to download/build the required binaries
  - one problem with running `npm run install` in `sqlite3` manually is that we lose yarn's intelligent postinstall skip meaning we need to run our own check for binaries being present to avoid re-building on every install
  - extracted that logic to a script to avoid repeating everywhere we install dependencies within CI/Docker and replaced all `yarn install` commands with a run of our new `install-deps.sh` script
ibalosh and others added 11 commits November 27, 2025 16:39
* added direnv .envrc to ignore list, so that you can auto load with .envrc environments locally
resolves https://linear.app/ghost/issue/BER-3085/css-conflict-affecting-settings-styles-in-local-dev

The config already included settings, but since settings in turn depend on
components from the adminx-design-system, these also need to be included.
refs https://linear.app/ghost/issue/BER-3077/improve-e2e-testing-integration

This greatly improves the reliability and total run time of the E2E tests when
running them locally.
closes
[GVA-605](https://linear.app/ghost/issue/GVA-605/adjust-the-warmup-numbers-to-reflect-joeys-suggestions)

Our initial scaling factors were based on some preliminary research, and
were designed to be as simple as possible. After further discussions,
we've decided to avoid having such a fast ramp-up at the early stage,
and limit the growth at the later stages to 75k+ per send. That should
still prevent any large sites from going back into warm-up between
sends, but is more likely to avoid damaging the reputation by scaling
too aggressively.
closes https://linear.app/ghost/issue/BER-3078/

- we moved search and settings keyboard shortcuts from the Ember sidebar component to the application route so we still have working shortcuts inside React shell where we don't render the Ember sidebar at all
- this caused a slight change in behaviour because the shortcuts are now always active, even when Ember wouldn't have rendered the sidebar such as inside the editor, resulting in duplicate keyboard shortcuts / unexpected search bar opening
- added an early return to the shortcut handlers that uses `ui.isFullScreen` as a proxy for the sidebar not being shown and therefore the shortcuts not being active
no issue

- when using the `install-deps.sh` script from production Docker files we want to do `yarn install --production` but in order to do that we need to pass arguments through
ref https://linear.app/ghost/issue/BER-2993/implement-floating-user-profile-menu-for-contributors

- This change implements a floating user profile menu for contributor accounts in the new React admin, replacing the full sidebar. This aligns with the existing Ember behavior for contributors which was a missing function in the Ember to React transition.
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.