ref ONC-364
- Adds a condition to check whether the record is deleted or if deleting
is in progress before firing the `setFeatureImageCaption`.
- Adds tests. Managed to reproduce the issue using tests.
no issue
- Added Sentry logs to capture how often we are running into
`QuotaExceededErrors` when saving local revisions to localStorage, to
help in deciding if localStorage is sufficient, or if we need to expand
to e.g. IndexedDB.
- Also adds some handling to ignore errors when calling
`localStorage.setItem()` elsewhere in the admin app to avoid crashing if
localStorage isn't supported or the quota is exceeded.
ref https://app.incident.io/ghost/incidents/107
ref cc88757e2a
- added new path in admin `/restore`
- added basic ui for restoring posts from local storage
- added limits for # of revisions for posts with an `id` (5 revisions)
This commit adds a simple UI for restoring posts in case of data loss.
This is a backstop for very rare situations in which it seems Ember gets
into a conflicted state. See ref'd commit for more info. Clicking
'Restore' will create a new post with the saved off content.
ref
https://linear.app/tryghost/issue/ANAL-60/click-through-filtering-for-sources
- In our stats page we use the referrer without a protocol or www, that
is the pure domain as our source that we output
- Meanwhile all the data pipelines had the full url as the referrer
passed through
- When we come to add clickthroughs/filtering, we'll need to use this
value to filter the data. If we have a different value locally in the UI
to what is in the DB, we won't be able to make the filters match
- Also, we pay for everything we store, and this removes all the
https:// and www. data
ref
https://linear.app/tryghost/issue/ANAL-53/10-stats-page-engineering-stuff
- All of these changes are intended to improve developer experience
going forward, to make it easier to implement further changes to the
stats page.
- Moved the modal into the stats components, as it has a lot of shared
code, and it makes it easier to update them all
- Removed various comment blocks that were outdated or didn't really add
value
- Fixed all imports to use the same pattern starting `ghost-admin/`
- Ensured all the components had the correct name
- Dried up the generation of params for Tinybird charts into a utility
function as we'll need to add several more in the near future
- Tried to use a consistent pattern everywhere for the order of
operations
- Dried up the implementation of technical.js which handles the
device/browser charts
DES-774
- The buttons in the Admin got very diverse over the last couple of
years. This PR updates the styles to use outline buttons, white
background for better contrast and slightly more rounded corners.
Additionally the right click and dropdown menu typography and spacing
has also been updated.
ref https://linear.app/tryghost/issue/ONC-323
When the store gets into a bad state for new posts that causes saves to fail we can detect that by looking at the `model.isNew` property. Currently our best approach to fix this state is to restart the app.
- added a `didTransition()` hook to our `lexical-edit.new` route
- detects the bad state, logs the error, and triggers a browser refresh
- logs with a `recreatedPostIsGood` property that will let us know if we could instead just try recreating the post and avoiding a full refresh (so far we have no reproduction case so we need to learn what we can)
- added `sinon-chai` dependency for better assertions on spies/stubs
- added `sentry-testkit` dependency so we can test our Sentry integration calls
- we can't use sinon for these calls because of the way Sentry's es6 imports work
- extracted our full Sentry config object generation to a util function so it can be re-used in unit tests
- updated our integrations list to disable the default `dedupe` integration because it can cause very unexpected/difficult to debug test failures when you're asserting using `sentry-testkit`
ref https://linear.app/tryghost/issue/ONC-323
- sometimes posts can be deleted by another user or in a different tab but then edited in an old tab that had the post loaded in the editor
- in this situation we were displaying our "Editor crashed" error put in place for the rarer situation where the editor is genuinely in a bad state
- added an extra conditional for the bad state and a custom error message for the deleted post state
ref https://app.incident.io/ghost/incidents/107
- We have a rare bug that causes the initial `POST` request to create a
new post from the editor to be skipped or fail. Subsequent `PUT`
requests then fail because there is no post ID, potentially resulting in
data loss. The aim of this commit is to start saving revisions of posts
in the editor to the browser's localStorage, as a last-ditch option to
restore lost work.
- Since we don't know where the bug is yet, and to protect against
future bugs, we've deliberately avoided depending too heavily on the
`lexical-editor` controller or the ember store. We've aimed to create a
direct route to the state in the editor, by hooking into the
`updateScratch` method (effectively the `onChange` handler for the
editor).
- The `scheduleSave` function on the new `local-revisions` service is
called immediately upon any changes to the state of the lexical editor,
which is effectively every keystroke. The service has some logic and
timeouts, so it doesn't actually save a revision on every change to the
editor.
- The "schema" of the datastore is a simple key-value store, where the
key is of the format: `post-revision-${postId}-${timestamp}` if the post
has an ID, or `post-revision-draft-${timestamp}` for an unsaved draft.
There is also an array of all the revisions' keys, which allows us to
clear all the revisions without having to loop over every key in
localStorage (along with some other conveniences, like filtering).
- There is currently no UI for viewing/restoring revisions. In the event
that you need to restore a revision, you can access the service in the
browser console. You can access all the saved revisions using the
`list()` method, which logs all the revisions to the console by title &
timestamp. You can then choose a revision to restore, and call
`restore(revision_key)`, which will `POST` the revision's data to the
server to create a new post.
- Since localStorage data is limited to a 5mb quota in most browsers,
the service has a mechanism for evicting the oldest revisions once it
meets the quota. If a save fails because it would exceed the quota, the
`performSave` method will evict the oldest revision, then recursively
try to save again.
---------
Co-authored-by: Steve Larson <9larsons@gmail.com>
ref https://linear.app/tryghost/issue/ONC-323
- added debug logs to print to console each time the post state changes and include a full list of post state changes within the editor session in the error reports when we hit the 404 error caused by a bad editor state
closes https://linear.app/tryghost/issue/ENG-1533
- the code to switch to "from analytics" state for the editor was applying when clicking the create post button in the nav menu whilst on the analytics screen which was confusing because you not only lost the `< Posts` link in the editor but you couldn't see the post's saving status
ref https://linear.app/tryghost/issue/ONC-323
- the post model state appears to be in an odd situation when this issue occurs, the extra log context should help us determine if the bad state is occurring at the route level or inside the editor controller
ref https://linear.app/tryghost/issue/ENG-661
Logging the full lexical objects to Sentry for the "showing leave editor modal" event isn't very useful because they almost always truncated due to size or stripped due to potentially sensitive data which makes the reports difficult to debug and action.
- added `code` to the context for each report to make identification easier
- updated `reason` for the lexical diverged reason to better match what's happened
- stripped `lexical`, `scratch`, and `secondaryLexical` from the context that is logged to Sentry because they aren't actionable there and just add noise
- added a diff to the logged context for the lexical change reason to more easily identify the changes that triggered an unexpected modal display
- previously we didn't get full objects in Sentry so couldn't do a comparison and the local workflow was to grab the logged scratch and secondaryLexical values and run a manual diff - this should help in both cases
ref https://linear.app/tryghost/issue/ENG-1466
ref https://linear.app/tryghost/issue/ENG-1484
- Previously, filtering members with multiple "Unsubscribed from
newsletter x" led to no filtering at all, all members were returned
- This was caused by a bug in NQL, that is fixed in version 0.12.5, cf.
[commit](dd18d1d6ca)
- We're also removing the safeguard in the product around bulk deletion
when multiple newsletter filters are in use, as the root problem has
been fixed
ref https://linear.app/tryghost/issue/ONC-323
- our fallback 404 error handler assumed we always had a transition along with the error
- this wasn't a bad assumption, it should be very unlikely that we see a 404 outside of navigating to a non-existent/deleted resource
- unfortunately we weren't handling the error thrown by our error handler which meant the error was silent as far as the user was concerned
- having a silent error meant that in very rare circumstances the editor could get into a state where saving was failing but there was no indication of that
- updated the fallback 404 error handler to only do something when navigation was occurring in which case it transitions to the 404 screen, otherwise let the error continue to our generic API error handling which will stay on the current screen but show an error alert
- adjusted the editor saving to actually trigger autosave-after-change when testing (albeit with 100ms wait compared to 3s) so the tests better reflect actual behaviour
ref https://linear.app/tryghost/issue/ONC-323
- we're seeing a rare situation where the editor can get into a bad state when creating a new post that means saves silently fail
- added logging to help debug
- Added activity icon for Replies
- Updated Replies design
- Updated hard-coded Profile values to more realistic ones
- Renamed ActivityPub nav item and moved it to the top of the navbar
- Added a check for post attachments
[ANAL-79](https://linear.app/tryghost/issue/ANAL-79/stats-page-v10-design-refinements)
- typography is inconsistent in table headings
- chart section headings are not unified
- spacings are off between section and data headings
- inactive KPI tab colors are too light
- tech data numbers are not formatted
[ANAL-43](https://linear.app/tryghost/issue/ANAL-43/implement-all-possible-ui-for-10)
- The BarList component wasn't using the parameters provided in its
latest release
- Number formatting was missing on all numbers
- "See all" links were missing in Content/Sources/Locations
- Empty/default values was showing [blank]
- Flags were missing for country values
[ANAL-43](https://linear.app/tryghost/issue/ANAL-50/update-colors-of-barlist)
- Copy is too technical, doesn't follow conventions on Stats page
- Range filter dropdown has to be updated with more meaningful values
- KPI charts need a granularity dropdown to display meaninful charts
depending on the context
- Typography details should be updated
- "Posts/pages" dropdown needs to be added to Content section. This is a
Ghost specific filter that brings high value to customers
- "Campaigns" dropdown needs to be added to Sources section to support
ad tracking and filtering in the future
- BarList colors should be updated to be less purple all over the place
no issue
Give your audience a simple way to support your work with one-time payments, no membership required.
- cleaned up `tipsAndDonations` labs flag
closes https://linear.app/tryghost/issue/PLG-205
The server trims whitespace from the title when saving but our unsaved changes detection was comparing the raw title input field value meaning there would be a mismatch after publishing if the title field contained leading/trailing whitespace.
- updated title comparison to compare trimmed values
- moved and improved unsaved changes modal tests from publish-flow to unsaved-changes acceptance test file
- added util for pasting content into the editor to test for content changes
[ANAL-1](https://linear.app/tryghost/issue/ANAL-32/add-stats-kpis-charts)
The technical details section in Stats contains only the browser breakdown ATM. This PR adds the rest (devices, operating systems) and fixes a couple of minor UI details on the rest of the charts
closes https://linear.app/tryghost/issue/ANAL-23/filtering-by-logged-out-logged-in-traffic
- Updated all of our tinybird datasources and pipes to handle member status
- Added member_status as an array query param to the API endpoints
- Added a really dodgy power select multiple to the stats page to demonstrate it works (needs styling)
- Added all of the wiring so each chart updates
- This was done pretty fast, and may not be 100% right yet
ref DES-706
* After a user publishes or schedules a post, they are directed to the post list
* If a post is sent as an email, they are directed to the Analytics page
* In both cases, a confirmation modal is shown
* If a post is published, they can share it directly from the confirmation modal
* Added a "Share" button and some additional functions (view, edit, and delete post) to
published posts in post analytics
* Added a manual "Refresh" button to post analytics so that there is
no need to reload the whole app to update the data
---------
Co-authored-by: Sag <guptazy@gmail.com>
closes
https://linear.app/tryghost/issue/ANAL-10/stats-page-in-ghost-admin
- Adds all the structure, logic and permissions tests for the Stats page
to check we're loading the right thing at the right time
- Adds @tinybirdco/charts as a dependency, and has a single example of a
chart setup using the right config
ref DES-756, DES-757
- made the email property to make the refresh work properly for published-only posts
- included sentiment in the query to update the feedback percentage when refreshed
ref DES-709
- when refresh button is clicked, the numbers in the analytics will be animated if changed
- for the animation to be performant, added a new dependency "animejs"
- to minimize the flash and layout shift, the analytics data is kept as it is while loading
- once finished loading, it will be replaced with the new data
Buttons were previously part of the bookmark card, but that's no longer
the case. This makes it easier to scale between different types of
posts/emails.
ref DES-731
- improved mobile styles for the social buttons in the modal
- fixed the flow for publishing/scheduling pages
- redirect to post list only when a post doesn't involve any email
ref https://linear.app/tryghost/issue/ENG-1489/
The changes to improve posts loading in admin broke the shift selection
functionality. This restores that, as we need to be able to crawl across
the (now) three models when present.
The new modal for the updated publishing flow has an entirely new
layout, based on feedback previously received. In addition, this PR
includes a few tweaks to the underlying logic.
ref https://linear.app/tryghost/issue/ONC-263/
- labels dropdown in sign up card was not successfully fetching labels
- offers dropdown suffered the same fate
When introducing the second editor instance, it appears we ran into some
race conditions with the Ember tasks used to fetch the resources. The
init instance was beating the other to the punch, and so the state was
never successfully updated, as it is only fetched once on mounting the
card.
ref PLG-153
- Scoped one-time payments (`donation_event`) under the "payments"
category in the member activity feed filter.
- Updated `toggleEventType` logic to ensure that toggling "payments"
also toggles one-time payments when the `tipsAndDonations` feature is
enabled.
- Refactored event type handling into utility functions for easier
testing.
- Added unit tests for the new utility functions to ensure correct
behaviour.
- Added acceptance testing.
ref https://linear.app/tryghost/issue/ONC-261
- Previous method of hiding the second Lexical instance using `width:
0`, `height: 0`, and `overflow: hidden` caused CPU usage to spike,
likely due to CodeMirror continuously processing the element.
ref DES-697
- used client side navigation on the flow instead of hard refresh
- reduced layout shift on the analytics screen
- made the modal transition a bit smoother
ref https://linear.app/tryghost/issue/PLG-174
- forcing autosave on excerpt blur caused posts to revert to `draft` and save immediately even when they were published/scheduled
- updated the save-on-excerpt-blur to only autosave drafts
- added acceptance tests for title and excerpt change+blur on published posts
ref [ENG-661](https://linear.app/tryghost/issue/ENG-661/)
ref [ONC-253](https://linear.app/tryghost/issue/ONC-253/)
ref [PLG-174](https://linear.app/tryghost/issue/PLG-174/)
- restored the original but reverted fix for unsaved changes modal from https://github.com/TryGhost/Ghost/pull/20687
- updated code to remove some incorrect early-falsy-return logic in `editorController.hasDirtyAttributes` that prevented save of unsaved changes on the underlying model (e.g. excerpt)
- updated unit tests so they are testing real post model instances and therefore are testing what we expect them to test
- added acceptance tests to ensure autosave is working for title and excerpt fields
---------
Co-authored-by: Ronald Langeveld <hi@ronaldlangeveld.com>
ref https://linear.app/tryghost/issue/PLG-174
- added `blur` handler to excerpt field so it acts the same as the title field and triggers a save when it loses focus
ref [ENG-661](https://linear.app/tryghost/issue/ENG-661/) ONC-253
- Reverts the revert of
93cbb94b90
of the intial bug fix.
- Updated hasDirtyAttributes logic to ensure the dirty state changes
when typing a draft, despite not title.
- Updated tests and added tests missing from the hasDirtyAttributes
logic
REF DES-321
- Added a "Copy post link" button to the context menu to copy the post URL for published posts, and a "Copy preview link" for draft and scheduled posts.
---------
Co-authored-by: Kevin Ansfield <kevin@lookingsideways.co.uk>
ref ENG-1490
- Regression from the secondary lexical instance.
- Replaced the visibility and positioning styles with width, height, and
overflow to prevent layout space issues.
- Ensured the element takes up no space and is not visible, while
allowing proper initialisation.
fixes https://linear.app/tryghost/issue/ENG-1484
- in Ghost release
[v5.89.0](https://github.com/TryGhost/Ghost/releases/tag/v5.89.0), we
have added a safeguard around bulk member deletion, due to a limitation
in NQL for member filters (commit: 2484a77)
- with this change, we limit the safeguard to only the cases we know are
problematic, and remove it for other useful and safe queries
- more precisely, the safeguard is in place only when:
- Multiple newsletters exist, and the filter contains 2 or more
newsletter filters
- If any of the following stripe filters are used even once:
- Billing period
- Stripe subscription status
- Paid start date
- Next billing date
- Subscription started on post/page
- Offers
ref PLG-109
- Added a boolean config property `stripeEnabled` to the configuration.
- This property is now passed down to the Koenig Editor to manage
features based on Stripe connectivity.
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.
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 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
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`