Skip to content

[pull] main from TryGhost:main#1206

Merged
pull[bot] merged 8 commits into
code:mainfrom
TryGhost:main
Jun 3, 2026
Merged

[pull] main from TryGhost:main#1206
pull[bot] merged 8 commits into
code:mainfrom
TryGhost:main

Conversation

@pull
Copy link
Copy Markdown

@pull pull Bot commented Jun 3, 2026

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 : )

ErisDS and others added 8 commits June 3, 2026 07:43
These relations were only used by the lazy router.
This is a short-term change to reduce the amount of work needed to
generate llms files and verify whether it improves latency in the wild.

The llms entry fetches only use the post/page fields needed to build the
index, full text output, and markdown URLs. Loading tags and authors here
adds extra relation work without changing the generated llms output, so
this removes those relations from both `/llms.txt` and `/llms-full.txt`.

If this proves to improve latency in the wild, then further refactors will be 
needed for this to work with LazyRouter.
ref
https://linear.app/ghost/issue/DES-1401/add-context-menu-component-to-shade

Adds a reusable Shade `ContextMenu` component backed by
`@radix-ui/react-context-menu`, matching the compound component shape of
the existing Shade dropdown menu.

## Details

- Added `ContextMenu` primitives for trigger, content, items,
checkbox/radio items, labels, separators, shortcuts, groups, portals,
and submenus.
- Added a Storybook story covering grouped actions, submenu behavior,
checked states, disabled state, shortcuts, icons, and destructive item
styling.
- Exported the component from `@tryghost/shade/components`.
- Added the Radix context menu dependency through the workspace catalog
and lockfile.
- Added Shade's direct `@typescript-eslint/eslint-plugin` dev dependency
so the lint hook resolves the same ESLint 8-compatible TypeScript ESLint
package as the parser.

## Validation

- `pnpm --filter @tryghost/shade test:types`
- `pnpm --filter @tryghost/shade build`
- `pnpm install --lockfile-only --ignore-scripts`
- Pre-commit lint-staged hook for the changed Shade TS/TSX files

ref https://linear.app/ghost/issue/DES-1401/add-context-menu-comp-shade
ref https://linear.app/ghost/issue/SC-45/
ref https://linear.app/ghost/issue/SC-35/

no issue

- Added DOMPurify sanitization for `dangerouslySetInnerHTML` usages
- The content is already sanitised on the server side. However, as best
practice, we avoid trusting any server-provided content and sanitise it
again on the frontend before rendering
ref https://linear.app/ghost/issue/BER-3588/add-archived-tiers-to-tiers-filter

Members can keep archived paid tiers, so the filter needs to preserve those options while separating them from active tiers.
towards https://linear.app/ghost/issue/NY-1286
ref #28120

**I recommend [reviewing this with whitespace changes
disabled](https://github.com/TryGhost/Ghost/pull/28263/changes?w=1).**

When a member signs up, we should trigger an automation run and possibly
insert a new row.

Nothing happens yet when these rows are inserted. That will be done in a
future change.

This is development-only; triggering is a no-op in production.

I tested this by:

- Adding automated tests.

- Verified that the old member welcome email is still sent on member
signup.

- Creating this temporary endpoint and verifying that the results looked
expected after member signup:

  ```js
  router.get('/automations/database-dump', (_req, res) => {
      const db = getTemporaryFakeAutomationsDatabase();
      res.json({
automation_runs: db.prepare('SELECT * FROM automation_runs').all(),
automation_run_steps: db.prepare('SELECT * FROM
automation_run_steps').all()
      });
  });
  ```
ref https://linear.app/ghost/issue/NY-1318/small-automation-ui-delights

This PR collects a set of small UX improvements for the Automations
editor canvas and step settings experience. The changes are
intentionally scoped to the React automation editor UI in `apps/posts`
and focus on making canvas navigation, step insertion, node actions, and
email-step editing feel more direct and polished.

## What changed

### Canvas zoom controls

- Added compact custom zoom controls to the bottom-left of the React
Flow canvas.
- The controls are horizontal: zoom out, current zoom percentage, zoom
in.
- Clicking the zoom percentage opens a centered drop-up menu with preset
zoom levels and `Fit to view`.
- Zoom actions use React Flow viewport helpers with animation for
smoother transitions.
- Disabled the default React Flow double-click zoom because it conflicts
with node interactions.

### Add-step connectors and picker behavior

- Restyled the in-between-node add-step affordance so it matches the
larger tail add button more closely.
- Kept connector lines visible and stable on hover, while showing the
`+` button only when the pointer is over the connector hit area.
- Adjusted connector color and hidden handle sizing to remove visual
gaps between nodes and connector lines.
- Changed the in-between-node step picker to open above the `+` button,
with wider menu sizing and stronger shadow.
- Tweaked picker menu hover styling to a lighter gray.

### New-step feedback

- Added a more visible pop/fade animation when a new automation step is
created.
- Newly inserted steps are automatically selected so their settings
sidebar opens immediately after insertion.

### Wait-step settings control

- Replaced the wait-days input/select pair with a Shade `InputGroup`.
- The input group now shows the number and fixed `days` label on the
left, with compact `-` and `+` steppers on the right.
- Stepper buttons clamp values between `1` and `30` days and respect
invalid manual input.
- Kept manual input validation intact.

### Node context menus

- Added right-click context menus to automation nodes using the new
Shade `ContextMenu` components from `main`.
- The trigger node has `Edit settings` only.
- Action nodes have `Edit settings` and `Delete`.
- Email action nodes additionally have `Edit email body` and `Preview`,
separated from `Delete` with a menu separator.
- `Edit settings` opens the existing right settings sidebar.
- `Delete` uses the existing action deletion path, preserving chain
reconnection behavior.
- `Edit email body` opens the email editor modal directly without
opening or flashing the sidebar.
- `Preview` opens the same email editor modal with the Preview tab
active by default.

### Email node shortcuts

- Double-clicking a send-email node now opens the email editor modal
directly.
- Double-clicking trigger, wait, or tail nodes does nothing special.
- Canvas double-click zoom is disabled so this interaction is no longer
hijacked by React Flow.

### Sidebar typography

- Changed the automation settings sidebar heading from semibold to
medium weight to better match the surrounding hierarchy.

## Implementation notes for reviewers

- Most changes are contained in
`apps/posts/src/views/Automations/components/automation-canvas.tsx`.
- Connector/add-step styling lives in `add-step-edge.tsx` and
`step-picker.tsx`.
- The email modal now accepts `initialMode?: 'edit' | 'preview'` so
callers can open directly into Preview without duplicating modal
behavior.
- Context menu entries are built from a local menu-entry model so future
node types can add node-specific actions without changing the node shell
rendering.
- Menu click/pointer events are stopped at the context-menu content to
avoid React Flow treating menu-item clicks as node clicks.
- Right-click opening and email-menu actions avoid selecting the node,
which prevents the sidebar from flashing open behind the modal.

## Files touched

- `apps/posts/src/views/Automations/components/automation-canvas.tsx`
- `apps/posts/src/views/Automations/components/add-step-edge.tsx`
- `apps/posts/src/views/Automations/components/step-picker.tsx`
-
`apps/posts/src/views/Automations/components/email-modal/email-content-modal.tsx`
- `apps/posts/test/unit/views/automations/automation-editor.test.tsx`

## Validation

- `pnpm --filter @tryghost/posts test:unit --
test/unit/views/automations/automation-editor.test.tsx`
- `pnpm --filter @tryghost/posts lint`
- Passes with the existing unrelated warning in
`apps/posts/src/hooks/use-post-success-modal.ts` about `site?.icon` in a
`useMemo` dependency array.

## Out of scope

- No API, model, database, or migration changes.
- No automation schema changes.
- No changes to public apps.
- No new shared Shade components beyond consuming the new `ContextMenu`
component that was merged into `main`.

---------

Co-authored-by: Troy Ciesco <tmciesco@gmail.com>
no ref

Before this change, an argument to `linkSubscription` was `any`. Now
it's a "proper" type.
@pull pull Bot locked and limited conversation to collaborators Jun 3, 2026
@pull pull Bot added the ⤵️ pull label Jun 3, 2026
@pull pull Bot merged commit 2cdffab into code:main Jun 3, 2026
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.

5 participants