closes https://linear.app/tryghost/issue/PLG-15
- removed `internalLinking` GA labs flag
- renamed search providers to `flex` and `basic`
- keeps old search provider around as it can handle non-English languages unlike the faster flex provider
- updated `search` service to switch from `flex` to `basic` when the site's locale is not english
- bumped Koenig packages to switch from a feature flag for toggling internal linking features to the presence of the `searchLinks` function in card config
- updated tests to correctly switch between flex and basic providers in respective suites
fixes
https://linear.app/tryghost/issue/DES-435/excerpt-in-post-settings-has-an-inconsistent-error-state
The excerpt form field seemed to not be properly handling errors.
However, it was a case of the error styling being overruled by the
regular styling, causing the red border to only show upon `:focus` when
there is an error in the excerpt.
I've rewritten the logic to be slightly less obfuscated and added some
CSS to circumvent the issue.
ref ONC-225
- Wires up the `editor_default_email_recipients` key to the settings
public / content api endpoint.
- This key is then wired up to Portal to determine whether it's hiding or
showing the Member subscribe toggle
refs https://ghost-foundation.sentry.io/issues/4907452370/
- we want to ignore these errors but the caret is stopping us from doing
so because the errors usually start with AbortError
- we can remove the caret to do so and clean up Sentry
refs ENG-661
Fixes a long-standing issue where an outdated Lexical schema in the
database triggered the unsaved changes confirmation dialog incorrectly.
Implemented a secondary hidden Lexical instance that loads the state
from the database, renders it, and uses this updated state to compare
with the live editor's scratch.
This ensures the unsaved changes prompt appears only when there are real
changes from the user.
ref
https://linear.app/tryghost/issue/ENG-1440/backfill-offer-redemption-data-with-a-migration
There was a bug that caused offer redemptions to not be recorded in the
database for some subscriptions that were created with an offer.
However, we still have the `offer_id` attached to the subscriptions, so
we are able to backfill the missing redemptions. The bug was fixed in
bf895e6e99
This commit only contains a migration, which queries for subscriptions
that have an `offer_id` but do not have any offer redemptions recorded,
and adds any missing redemptions to the `offer_redemptions` table.
ref https://linear.app/tryghost/issue/ONC-197
- YouTube has started responding to video page requests with localised content when requested from certain IPs, with that localised content not containing the required `<link rel="alternate" ...>` tag pointing to the oembed endpoint
- we were fetching video pages rather than the oembed endpoint for YouTube Live URLs because they are not recognised by the oembed extraction library we use
- by modifying the URL from a live URL to a watch URL before we perform oembed lookup/extraction we are able to bypass the (localised) page fetch and instead grab the oembed content directly
ref https://linear.app/tryghost/issue/ONC-199
The `updateSubscriptionItemPrice()` method in our Stripe library used by the importer when moving a subscription over to a Ghost product/price was setting `proration_behavior: 'always_invoice'`. This resulted in invoices being created when changing the subscription (even though no prices were changing as far as the customer is concerned) and in some cases where a customer previously had a one-off discount the customer was incorrectly charged the proration difference because the discount was no longer applied to the new invoice.
- updated `updateSubscriptionItemPrice()` to accept an `options` param allowing the `proration_behavior` property passed to the Stripe API to be overridden on a per-call basis
- updated the `forceStripeSubscriptionToProduct()` method used by the importer to pass an options object with `prorationBehavior: 'none'` when updating the subscription item price so that no invoice and no unexpected charges occur when importing
ref https://linear.app/tryghost/issue/ONC-199
The `updateSubscriptionItemPrice()` method in our Stripe library used by the importer when moving a subscription over to a Ghost product/price was setting `proration_behavior: 'always_invoice'`. This resulted in invoices being created when changing the subscription (even though no prices were changing as far as the customer is concerned) and in some cases where a customer previously had a one-off discount the customer was incorrectly charged the proration difference because the discount was no longer applied to the new invoice.
- updated `updateSubscriptionItemPrice()` to accept an `options` param allowing the `proration_behavior` property passed to the Stripe API to be overridden on a per-call basis
- updated the `forceStripeSubscriptionToProduct()` method used by the importer to pass an options object with `prorationBehavior: 'none'` when updating the subscription item price so that no invoice and no unexpected charges occur when importing
Ref https://linear.app/tryghost/issue/SLO-193/optimise-count-query-skip-distinct-from-count-query-for-members-events
The member events endpoint have many queries like:-
select count(distinct members_subscribe_events.id) as aggregate
from `members_subscribe_events`
where `members_subscribe_events`.`created_at` < '2024-07-30 11:30:39'
In these queries, distinct is not required as id is a primary key. Skipping distinct would improve the performance.
This PR will changed the query to:-
select count(*) as aggregate
from `members_subscribe_events`
where `members_subscribe_events`.`created_at` < '2024-07-30 11:30:39'
ref 8ea1dfb
ref https://linear.app/tryghost/issue/ONC-111
* undid the reversion for the performance improvements
* built upon new tests for the posts list functionality in admin,
including right click actions
* added tests for pages view in Admin
This was reverted because it broke the Pages list view in Admin, which
is a thin extension of the Posts functionality in admin (route &
controller). That has been fixed and tests added.
This was originally reverted because the changes to improve loading
response times broke right click (bulk) actions in the posts list. This
was not caught because it turned out we had near-zero test coverage of
that part of the codebase. Test coverage has been expanded for the posts
list, and while not comprehensive, is a much better place for us to be
in.
fixes https://linear.app/tryghost/issue/ONC-206
ref https://app.incident.io/ghost/incidents/90
- when multiple member filters are used in combination, NQL sometimes
hit a limitation that results in the wrong members being returned
- while we work on the NQL limitation, we are temporarily disabling bulk
member deletion when more than one member filter has been applied
no ref
- while reviewing the newsletter flows, it was apparent that we were
missing test coverage
Some of the tests in Portal are a bit redundant with tests added for
child components, but it didn't seem worth removing them after getting
them to work. There was a bug in our Portal fixture data that requires a
few changes, as well as some small adjustments for making tests easier
(testing-lib-react has `getByTestId` and simply a `querySelector` to use
alternate test attributes).
ref
https://linear.app/tryghost/issue/PA-71/remove-cache-bust-from-projs-in-admin
ref
15ed2eb245
- This cache buster was added in March to mitigate a client side error in pro.js,
to effectively force browsers to redownload the fixed version of the file.
- It's not needed anymore, as the error has been fixed for a few months
now, so we can safely remove it.
ref https://linear.app/tryghost/issue/SLO-160
- in the Members list, we were using VerticalCollection with
`@bufferSize` set to 20, which means that 20 additional items before and
after the visible items in the viewport were pre-loaded
- however, scrolling down too quickly (e.g. dragging the scrollbar thumb
to the bottom) breaks the list
- with this fix, we adjust `@estimateHeight` parameter to the correct
item size, and reduce the `@bufferSize`
REF MOM-315
- Changed to column layout
- Fixed broken currency dropdown
- Included a link to Stripe terms & conditions
- Renamed from "Tips or donations" to "Tips & donations"
Right now identity tokens can only be fetched by the Owner, which means they
implicitly have the Owner role, but we want to expand that. The first step is
adding the role to the token, and then we need to update each place which uses
the token and add an assertion that the role is correct.
- right now, it loops through all packages serially, which isn't
effectively using multi-core machines
- by using `concurrently`, we can rely on it to use all the cores it
can, so this should dramatically speed up the bundling step
ref DES-571
- padding does not work well with paragraph inside blockquote as
horizontal spacing on Outlook
- using margin instead of padding makes sure the spacing is consistent
across Outlook versions
ref DES-571
- iOS Mail app ignores spacing on the \<blockquote\> element, but will
respect spacing on the \<p\> element inside it
- for that reason, we started to enforce always rendering \<p\> inside
\<blockquote\> for emails
- these changes move the spacing related styles from blockquote to p
inside
closes https://linear.app/tryghost/issue/ENG-1432
- bumps `kg-lexical-html-render` package with required rendering change
- bumps `koenig-lexical` with TypeError fix and improved handling of failed image uploads
- bumps other packages that were missed from previous bumps, fixes split versions of underlying lexical packages
fixes https://linear.app/tryghost/issue/ONC-189
- commit 4084a3d introduced a regression that caused member subscription
details to not be rendered for active/canceled subscriptions
- with this fix, the rendering logic in Admin for member subscription
details has been fully moved to a helper and is now covered by
additional unit tests
ref https://github.com/TryGhost/Ghost/pull/20503
- undid the reversion for the performance improvements
- built upon new tests for the posts list functionality in admin,
including right click actions
This was originally reverted because the changes to improve loading
response times broke right click (bulk) actions in the posts list. This
was not caught because it turned out we had near-zero test coverage of
that part of the codebase. Test coverage has been expanded for the posts
list, and while not comprehensive, is a much better place for us to be
in.
ref e626dd9
There has been some flakiness in Github CI with the new tests for the
probe library. We'll start with extending timeouts in case CI is running
particularly slowly.
ref https://linear.app/tryghost/issue/ENG-1360
Not *all* functionality has been covered by these tests. There's a few
missing pieces from our mirage build and use that likely doesn't need
full coverage within the admin package. Regardless, this view has
dramatically more coverage at this point.
ref https://linear.app/tryghost/issue/ENG-1254
- when a subscription is canceled automatically by Stripe (e.g. due to
multiple failed payments), we now send a staff notification
- logic before: if a member cancels a sub in Portal, then send a staff
notification
- logic now: if a subscription was active, but is now set to cancel
immediately or at the end of the billing period, then send a staff
notification.
- with that logic change, we now send a cancellation staff notification
when:
1. A member cancels their sub in Portal (existing)
2. A staff member cancels a member sub in Stripe (new)
3. A staff member cancels a member sub in Admin (new)
4. A sub is canceled automatically by Stripe because of multiple failed
payments (new)
- the copy of the staff notification email has also been updated to take
into account 1) manual vs automatic cancellations, and 2) immediate vs
end of billing period cancellations
ref https://linear.app/tryghost/issue/ONC-160
- POST is incorrect as the form itself doesn't post to any path; all we
want are the authentication flows to kick off on submit
We've had reports of users experiencing a 404 error on attempting to
sign in to Ghost Admin (at /ghost/), where the login form seems to
submit a POST request to the /ghost/ path (we don't have a route for
that method, hence the 404; only GET). While I haven't been able to
reproduce the issue, there's very few places in Ghost that actually
issue a POST request.
Removing this method here has no impact to Ghost auth and may prevent
some unexpected default behavior from the browser.
ref https://linear.app/tryghost/issue/ENG-1408/
- added additional safeguards to the image size dimensions probing
For some reason that requires further investigation, the
probe-image-size package was silently failing (neither resolving nor
rejecting) for a particular URL. This was causing Ghost to hang on to
serving the request, and after a few of these came in, ultimately caused
Ghost to stop being responsive.
Rather than trying to patch a dependency, we'll wrap the call to this
package and use the same timeout we pass into the package (which is
ignored in this particular case) as an additional safeguard.
ref DES-263
- we've recently started forcing white background color to the bookmark
card by default
- the reason was making it look good regardless of the site background
color
- it caused an issue to some sites, mostly in dark mode, because the
text color was inherited from the theme
- this sets explicit color to the bookmark content which is consistent
with the nft card
refs
[ENG-1355](https://linear.app/tryghost/issue/ENG-1355/site-boot-cycling-due-to-free-tier-having-a-currency)
Fixed data importer allowing invalid free product to be imported which
could cause Ghost to not start due to the error:
`ValidationError: Free Tiers cannot have a currency`
It should not be possible to import a free product with pricing data (as
that means its not free 😄)
ref
https://linear.app/tryghost/issue/ENG-1251/support-escalation-re-offers-not-tracking
- Offer Redemptions were not being persisted in the database for
existing free members who upgrade to a paid plan with an offer, which
resulted in inaccurate offer redemption counts. This made it difficult
to assess the performance of an offer.
- Previously, Ghost recorded an offer redemption in the DB in response
to the `SubscriptionCreatedEvent`, under the assumption that the offer
details would be included in this event. This assumption was valid for
brand new members starting a subscription with an offer, but not for
existing free members upgrading to a paid plan with an offer.
- For existing free members, the subscription is first stored in Ghost
in response to the `customer.subscription.created` Stripe webhook. At
this point, the offer/discount is not attached to the subscription, so
the `SubscriptionCreatedEvent` triggers without the offer information,
and the offer redemption is not recorded. After the
`checkout.session.completed` webhook is received (which _does_ include
the offer details), the subscription is updated in Ghost, but the Offer
Redemption is not stored.
- For brand new members, the `customer.subscription.created` webhook
no-ops, because the member and Stripe Customer don't exist yet.
Therefore, the subscription is first created in Ghost in response to the
`checkout.session.completed` webhook, which _does_ include the offer
information, so the offer information is included in the
`SubscriptionCreatedEvent` and the offer redemption is recorded as
expected.
- This change adds a new `OfferRedemptionEvent`, which triggers
either: (1) when a new subscription is created with an offer (as in the
case of a brand new member), or (2) when an existing subscription is
first updated to include an offer (as in the case of an existing free
member upgrading with an offer). The Offer Redemption is then persisted
in the DB in response to the `OfferRedemptionEvent` rather than the
`SubscriptionCreatedEvent`.
ref https://linear.app/tryghost/issue/ENG-1266
- Mexico changed tz to not participate in DST
- our package was a couple years behind, so we likely have fixes for
other countries/regions, too