ref https://linear.app/tryghost/issue/ENG-1570
- for a Ghost site hosted on a subdirectory, e.g. `/blog/`, adding a
navigation link to `/blog/page/` was being re-written as `/page/` in Admin settings
- fixed the underlying `formatUrl` utility function and added unit tests
- we shouldn't try and load the Stripe CLI via the dev script because
it's done in the browser tests and involves more setup than the dev
script contains
- this cuts 2mins from the browser tests because they're no longer
waiting for the Stripe CLI to be auth'd
REF DES-770
- In certain email clients such as Protonmail, the newsletter title
line-height was inherited from the `body` rather than the parent `td`.
This commit adds line-height to the title link explicitly.
- we should be able to trust Nx enough that we can sustain the build
cache across commits, which will speed up the workflow because we
don't need to rebuild our TS projects all the time
ref https://linear.app/tryghost/issue/AP-395
This is a stopgap solution, because currently we don't have any of our own
reply data in the frontend, so this will show the new reply, but it won't be
present on page reload. Should be enough for a demo video, but I think we need
to either fetch our outbox, or make a new replies endpoint and fetch from there
ref b9d02f8051beb9120a282bcbf0f70440c2a3c39e
Because we disabled the button on blue of the textarea, it was being disabled
before the click would be handled! Using the mousedown event means that our
event gets handled before the blur.
ref https://linear.app/tryghost/issue/AP-396
We need to use a number instead of boolean here so that the state is always
refreshed, otherwise we can run into issues where we set `focused` to true but
there's no rerender because it was previously set to true, but unfocused
ref https://linear.app/tryghost/issue/AP-398
This adds an internal focus state so that we can render the reply box different
based on whether or not the textarea is focused!
ref https://linear.app/tryghost/issue/AP-396
I think it's nicer API to pass in a focused property, rather than an
element ref, but I don't have much experience here, so it might be the
wrong approach!
ref https://linear.app/tryghost/issue/AP-397
I think we're gonna want to pass this data into the component long
term, but this will do for now, I'm going to look at cleaning up these
components in my next B week
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
closes https://linear.app/tryghost/issue/ANAL-77/na-data-should-be-zero
ref https://www.tinybird.co/blog-posts/tips-9-filling-gaps-in-time-series-on-clickhouse
- Sometimes we have no matching data for a particular date/date range, which makes our charts look super janky
- Clickhouse has a feature to fill these in called WITH FILL, which makes it really easy to fix this!
- WITH FILL works except for on bounce rate. That seems to be due to the column being marked as nullable and so WITH FILL fills missing data with NULL instead of 0
- To fix that, I've updated the code that generates the bounce rate so that it doesn't generate nulls, and that seems to result in a not-nullable column, which then works with WITH FILL
- When I went off, I quickly recreated all our endpoints with some new functionality
- However, I forgot that I was manually managing tokens, this meant the UI for stats broke with a token error
- Adding the tokens to the endpoint definitions should prevent this happening again, by automating the management of the token scopes