[pull] main from TryGhost:main - #1425
Merged
Merged
Conversation
Add a guide for testing Ghost on physical devices and with non-default development URLs: HTTPS, subdirectory installs, and a separate Admin hostname.
…0024) ref https://linear.app/ghost/issue/MIG-1437/ - adds a testid attribute to the existing file upload dropbox description - adds test to ensure existing behaviour is not changed when the `csvContentImporter` flag is enabled - adds tests for when the `csvContentImporter` is enabled - adds a conditional for the file drop placeholder text
Ghost Admin composes a filter from its own field catalogue and sends NQL, and nothing on either side can tell whether the server honours what was written: admin cannot see the SQL, and the query layer cannot see what admin meant. The only place the two are observable together is the browse endpoint, so these run the NQL admin emits against a real database and assert exactly which members come back. Derived fields are the reason this matters more than it looks. A column filter is its own evidence, but `subscribed` is rewritten to a newsletter relation before it reaches the model, `email_disabled` combines with it to mean something neither column says alone, and a label is a join. Those shapes are agreed between two codebases and pinned nowhere. This lands ahead of the filter engine refactor so the safety net exists before anything moves.
…reen (#29962) closes https://linear.app/ghost/issue/NY-1520 Automation workflows could be panned completely out of view, while graph or zoom changes could leave the viewport outside its updated bounds. Centralized viewport measurement, zoom configuration and constraint handling so workflows remain recoverable across canvas, graph and zoom changes. Updated the controls to match the supported 50–100% zoom range and disable actions at their limits.
…30061) closes #30040 The file upload allowlist introduced with the file type validation was derived from observed usage and did not include Linux package formats, so sites distributing software could no longer attach `.rpm` or `.deb` files while sibling archive formats like `.tar.gz` continued to work.
no ref - `free`: kostenlos → kostenloses - `complimentary`: kostenlos → kostenloses (kept identical to `free`, mirroring `de` which uses one word for both) - `Subscription details`: Abo Details → Abo-Details (German orthography requires hyphenated compounds) - `This email address will not be used.`: E-Mail Adresse → E-Mail-Adresse (same hyphenation rule)
no ref The code injection, webhook, labs YAML editor, feature-toggle confirmation and universal import dialogs were the last `NiceModal.create` dialogs under `settings/advanced`. They now take an `onClose` prop and are rendered by the component that opens them, using `SettingsModal`'s controlled `onClose` path that the routed settings dialogs already use. This removes five of the remaining NiceModal call sites in settings so the provider and dependency can be torn down once the theme and membership dialogs follow.
no ref The invalid-theme, theme-installed, theme-editor confirm and theme-editor input dialogs were the remaining `NiceModal.create` dialogs in the theme settings area. They now render in-tree from the component that opens them: the two `ConfirmationModalContent` dialogs take an `onClose` prop, and the two promise-style editor dialogs take an `onResolve` prop, with the code editor keeping its await-based `requestConfirmation`/`requestInput` helpers via a small pending-request state instead of `NiceModal.show`. The theme code editor's dialogs are rendered as fragment siblings of its dark, backdrop-blurred root so they keep the same theme and stacking they had when NiceModal rendered them at the provider.
ref https://linear.app/ghost/issue/HKG-1914 Ghost's background jobs are moving onto a class-based interface whose transport is swappable, and this package defines the seam every backend implements. A backend extends JobsBackendBase - a frozen start/enqueue/scheduleRecurring/ shutdown contract - and only ever sees the serialised {type, payload} envelope and a single delivery-processor callback, never a live job instance. Keeping the backend blind to job instances is what makes jobs serialisable end to end and lets a durable backend drop in for the in-memory one without touching a call site. The package also exports a backend-agnostic contract test suite, so the in-memory reference backend and any future durable backend are held to the same acceptance, delivery, drain and bounded-shutdown behaviour. It is a private workspace package, matching the other adapter-base-* packages.
ref https://linear.app/ghost/issue/HKG-1914 This is the first working layer on top of the backend contract, and the point at which jobs can be registered and dispatched at all. The class-based jobs service owns everything the transport does not: the handler registry, the JSON envelope boundary, rehydration, cron validation and error reporting. InMemoryJobsBackend is the reference implementation - delivery runs through a bounded fastq queue whose concurrency comes from adapter config, shutdown drains in-flight work within a bounded time, and a recurring schedule is first-write-wins so a re-registration never disturbs one that is already running. A handler failure is reported and rethrown so the backend sees a rejected delivery as a failed one; the in-memory backend defensively logs and drops it, matching the legacy in-process queue with no redelivery yet. Because the backend is selected through adapter config, a durable backend is a drop-in replacement. Boot constructs the service, runs an initially-empty central registration step so there is a single place to wire handlers, then starts delivery.
To quote [ESLint's docs][0]: > If a variable is never reassigned, using the `const` declaration is better. This enables the `prefer-const` ESLint rule and fixes all violations. [0]: https://eslint.org/docs/latest/rules/prefer-const
no ref We had a bunch of code like this in a test: ```js assertExists(result); assert.equal(result, 123); ``` That `assertExists` can be removed. (This also fixes the fact that `assertExists` was imported strangely.)
closes https://linear.app/ghost/issue/NY-1529 ref ce08414 This adds `stats.last_run_created_at` to each automation, which we'll display in the UI soon. This was built by Claude Opus 5 with the following prompt: > Commit `ce0841435c44a24bd444277cc587e3a18adc052d` adds a "last run created at" stat to the automation browse endpoint. > > I want a new key, `total_run_count`, which is a count of all the runs for that automation. > > * Update `AutomationBrowseResult`. > * Update `AutomationBrowseRow`. > * Update `loadAutomations`. > * Update `buildAutomationBrowseResult`. > * Update `ghost/core/test/e2e-api/admin/automations.test.js`. > * Update `ghost/core/test/unit/server/services/automations/automations-repository.test.ts`. > * Re-generate the snapshots with `UPDATE_SNAPSHOTS=1` and running the necessary tests. > > Use red/green TDD. > > This should be a fairly straightforward change. In addition to unit and E2E tests, I also verified that the data appeared by checking the Network tab of the Firefox devtools:  Co-authored-by: Claude <noreply@anthropic.com>
ref #23361 This PR completes the Serbian (`sr`) locale. I'm a native Serbian speaker, and I've filled in all the previously-empty strings across `comments.json`, `ghost.json`, and `portal.json` — including the Serbian plural forms (`{count} month_*` / `{count} year_*`, which need the `_few` paucal form).
no ref This change should have no user impact. [`@ts-ignore` should never be used.][0] This removes all usages. Most of the time, we could simply delete it. Sometimes, we needed to replace it with something. All of the functionality changes were (1) only in tests (2) minor. [0]: https://evanhahn.com/ts-ignore-is-almost-always-the-worst-option/
no ref [`@ts-ignore` should never be used.][0] ESLint now errors if you do. `@ts-nocheck` is also forbidden. `@ts-expect-error` is allowed with a description. No "real" code changes were necessary after this. [0]: https://evanhahn.com/ts-ignore-is-almost-always-the-worst-option/
towards https://linear.app/ghost/issue/PLA-137 This installs Oxfmt in the Ghost repo. It doesn't add any scripts or enforcement, but it enables a workflow where we can run `pnpm exec oxfmt my-file.ts`, which will ease the future transition. --------- Co-authored-by: Steve Larson <9larsons@gmail.com>
ref https://linear.app/ghost/issue/BER-3876/refine-the-field-picker-in-the-members-import-mapping The trigger named the kind of every field it showed, putting "Membership field" under nearly every row to answer a question almost none of them raise. The kind is named now only where a custom field's name is one a native field already has, and with the second line gone the icon leaves its tile, so the control stands at the height every other one does. Building that turned up a bug. The list identified its items by their label, so a custom field named "Name" and the native "Name" were one item to cmdk: both drew as selected, and since the active item is resolved by querying the first match in the DOM, Enter took the native one whichever had been arrowed to. Identity moves to the targets, already namespaced apart as `name` and `custom_fields.name`, and the label moves to keywords — which needs a filter of its own, since cmdk scores an item's value and its keywords as one joined string and a match is otherwise free to run from one into the other. A composite's parts differ only in their last few words, so truncating the label as one string took away the only thing telling those rows apart. The name gives way first now and the part stays whole.
no ref Uses the settings `DialogPortal` from #30014. The custom field, welcome email and welcome email customize dialogs were the last `NiceModal.create` dialogs in the membership and email settings areas. They now take an `onClose` prop and are rendered by the component that opens them: the two `SettingsModal` dialogs through the settings dialog portal so they paint above the settings chrome, and the customize dialog directly, since its `EmailDesignModal` is already a portalled Shade `Dialog`. With these converted (plus #30014 and #30015), no settings dialog is created or shown through NiceModal any more, which clears the way to remove the provider, the dependency and the compatibility bridges.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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 : )