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>
no issue
- fixed eslint config so tests are correctly linted
- removed `.only` on stats tests preventing other tests from running
- removed unneccessary `return` from async setup functions
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
ref https://linear.app/tryghost/issue/MOM-117
- `url` was missing in the results objects that we generate from the underlying search results
- updated service integration test with check for url presence
- updated service integration test to also run against the beta search
- added missing page factory to mirage setup
- updated mirage post serializer to include a uniquely identifiable URL for unpublished posts
closes https://linear.app/tryghost/issue/MOM-80
- bumps @tryghost/koenig-lexical to add support for search result metadata in internal links as well as some improvements to the internal linking UI/UX
- updates search service to fetch and expose additional `visibility` and `published_at` fields for post/page resources
- updates `searchLinks` method passed to editor to decorate the search results with appropriate meta text and icon based on publish date, post visibility and member settings
closes https://linear.app/tryghost/issue/MOM-97
The 30s search content expiry didn't really make sense and caused unnecessary delays and server load now that search will be more widely used within the editor.
- replaced concept of time-based expiry with explicit expiry
- content still fetched on query if not already loaded or marked as stale
- added `.expireContent()` method on search service to allow explicit expiry
- updated editor to pre-fetch search content when not already loaded or marked as stale
- removes delay when first using internal linking search inside the editor
- updated post model to expire search content on save
- expires on published post save or delete
- expires on publish and unpublish
- updated tag model to expire content on create/save/delete
- only expires when name or url is changed
- updated user model to expire on save/delete
- only expires when name or url is changed
- does not handle creation because that's done server-side via invites
Ref TRI-27
- Published posts now show the published date in post list, instead of
updated date.
- The `gh-format-post-time` helper now has a `relative` and `absolute`
and option instead of formatting being tied to `draft` and `published`
state. This allows for more flexibility in how dates are displayed.
- Draft, scheduled and published posts now follow the same time
formatting pattern: today, yesterday, or explicit dates if further in
the past.
- Hover states for dates in the post list have been removed.
- Title attributes are added indicating whether timestamp refers to updated_at or published_at
- The scheduling logic on the publish page still uses relative
formatting.
refs https://github.com/TryGhost/Product/issues/4055
---
<!-- Leave the line below if you'd like GitHub Copilot to generate a
summary from your commit -->
<!--
copilot:summary
-->
### <samp>🤖 Generated by Copilot at 3b24693</samp>
Removed unused components related to announcement settings, custom theme
settings, and file upload. These components were part of a deprecated
feature or a legacy UI.
no issue
- removed labs flag
- removed main editor component and all associated components
- switched usage of `<KoenigBasicHtmlInput>` and `<KoenigBasicHtmlTextarea>` over to use plain `textarea`, the only uses were in settings modals that have been replaced in AdminX
- cleaned up unused editor CSS
refs TryGhost/Product#3510
- Added `TryGhost/Source` as a submodule in `ghost/core/content/themes` so `Source` will ship with Ghost (along with Casper)
- With this change, new installs will use `Source` as the default theme. Existing sites will have `Source` installed, but not activated, as this is a large change and we don't want to drastically change existing sites without warning. Users can upgrade to use `Source` simply by clicking 'Activate' in design settings.
- Updated protections to prevent users from uploading their own conflicting version of `Source`
no issue
- added modal-post-history component and wired it up to the
lexical-editor
### <samp>🤖 Generated by Copilot at b726dd5</samp>
> _`Post history` is the key to the past_
> _Unveil the changes in a modal so vast_
> _But beware of the doom that lurks in the edits_
> _The lexical-editor is a portal to the abyss_
refs https://github.com/TryGhost/Ghost/issues/14101
- migrated component to Glimmer
- swapped usage of `ValidationState` mixin for `{{validation-status}}` modifier
- updated modifier to accept custom error/success classes
- removed unnecessary/unused code in the `gh-benefit-item.js` backing class
no issue
- moved logic from `<GhValidationStatusContainer>` to a new `validation-status` modifier
- removes a usage of the `ValidationState` mixin
- migrated uses of the component to a mixin
- paves the way for full removal of the `ValidationState` mixin in later refactors (mixins are deprecated)
- migrated `<GhFormGroup>` to a glimmer component
- swapped the extend of `GhValidationStatusContainer` to usage of the `validation-status` modifier with a template-only component
- updated all `<GhFormGroup>` to use the standard `class=""` instead of `@classNames=""` and `@class=""`
- allows `data-test-*` attributes to be added to uses of `<FormGroup>` to help when complex components are grouped as a form input
refs: https://github.com/TryGhost/Team/issues/1121
- We've decided on one preferred message for unexpected errors
- We want to use this everywhere where we don't know what to display
- We now have a GENERIC_ERROR_MESSAGE constant that we should use
refs: https://github.com/TryGhost/Team/issues/1121
- This makes several key changes to the way errors are handled in the member importer, to ensure that we only show error messages to users that we wrote.
- Fundamentally, we no longer trust all API errors, and instead only trust a set of very specific API errors. Anything outside of that is replaced with a generic error message.
- Also switches the server-side error generated for email verification (which can throw during member import) to be a HostLimitError, as that is a more appropriate class.
- Note: there are many other parts of Ghost admin that need a similar overhaul, and a similar change we need to introduce server side to fully resolve the underlying issue of bubbling up code errors to the UI.
fixes https://github.com/TryGhost/Team/issues/2193
- When pasting a title with a newline, we now trim the string and clear newslines before pasting.
- When sending the slug to the backend to generate a unique slug, we now sluggify it in the frontend before adding it to the URL to prevent issues with unsupported characters (causing possible routing problems in Pro).
refs https://github.com/TryGhost/Team/issues/2110
- dynamically defined properties on the config service did not have
autotracking set up properly if they were accessed in any way before the
property was defined, this caused problems in a number of areas because
we have both "unauthed" and "authed" sets of config and when not logged
in we had parts of the app checking for authed config properties that
don't exist until after sign-in and subsequent config re-fetch
- renamed `config` service to `configManager` and updated to only
contain methods for fetching config data
- added a `config` instance initializer that sets up a `TrackedObject`
instance with some custom properties/methods and registers it on
`config:main`
- uses application instance initializer rather than a standard
initializer because standard initializers are only called once when
setting up the test suite so we'd end up with config leaking across
tests
- added an `@inject` decorator that when used takes the property name
and injects whatever is registered at `${propertyName}:main`, this
allows us to use dependency injection for any object rather than just
services or controllers
- using `application.inject()` in the initializer was initially used but
that only works for objects that extend from `EmberObject`, the
injections weren't available in native-class glimmer components so this
decorator keeps the injection syntax consistent
- swapped all `@service config` uses to `@inject config`
closes https://github.com/TryGhost/Team/issues/2110
- added failing test showing feature service `@feature` properties
weren't autotracking correctly if accessed before
authentication+settings fetch occurs
- shows labs and feature properties on the feature service are not
reacting to changes in the settings service
- removing the `@computed` on the `feature.labs` getter stops it being
cached but it then fails on the `feature.testFlag` computed property
- updated `settings` service to behave as expected with our current
version of Ember
- inspected the store schema for `Setting` to define the "proxied"
properties up-front rather than only after fetching
- updated the property definition to use `computed` so we're opting in
to the old style reactivity (required adding the `@classic` decorator to
pass linting)
no issue
The `config` service has been a source of confusion when writing with modern Ember patterns because it's use of the deprecated `ProxyMixin` forced all property access/setting to go via `.get()` and `.set()` whereas the rest of the system has mostly (there are a few other uses of ProxyObjects remaining) eliminated the use of the non-native get/set methods.
- removed use of `ProxyMixin` in the `config` service by grabbing the API response after fetching and using `Object.defineProperty()` to add native getters/setters that pass through to a tracked object holding the API response data. Ember's autotracking automatically works across the native getters/setters so we can then use the service as if it was any other native object
- updated all code to use `config.{attrName}` directly for getting/setting instead of `.get()` and `.set()`
- removed unnecessary async around `config.availableTimezones` which wasn't making any async calls
no issue
The `settings` service has been a source of confusion when writing with modern Ember patterns because it's use of the deprecated `ProxyMixin` forced all property access/setting to go via `.get()` and `.set()` whereas the rest of the system has mostly (there are a few other uses of ProxyObjects remaining) eliminated the use of the non-native get/set methods.
- removed use of `ProxyMixin` in the `settings` service by grabbing the attributes off the setting model after fetching and using `Object.defineProperty()` to add native getters/setters that pass through to the model's getters/setters. Ember's autotracking automatically works across the native getters/setters so we can then use the service as if it was any other native object
- updated all code to use `settings.{attrName}` directly for getting/setting instead of `.get()` and `.set()`
- removed use of observer in the `customViews` service because it was being set up before the native properties had been added on the settings service meaning autotracking wasn't able to set up properly
fixes https://github.com/TryGhost/Team/issues/1946
Problem:
- When running the admin tests in a timezone that is later than UTC, the tests failed.
Causes:
- Some tests needed some adjustements
- The DateTimePicker did not always use the correct timezone.
- Test models createdAt times sometimes depended on the timezone of the test runner
Solution:
- All the input DateTimePicker gets should be processed in the blog's timezone.
- Make sure that all communication (properties, setters, minDate...) with `PowerDatepicker` happens in the local timezone. When setting, convert that date to the blog timezone and use that as the real value.
refs 85cce39af7
- removed out of date transfer owner modal integration test
- fixed missing `?` in optional chaining in `<GhImageUploader>` error handling
no issue
Since `ember-moment@10.0` it's not been necessary to use the `ember-cli-moment-shim` package, with `moment` instead being usable directly via `ember-auto-import`. Getting rid of the shim package is necessary for compatibility with `embroider`, Ember's new build tooling.
- dropped `ember-cli-moment-shim` dependency
- added `moment-timezone` dependency and updated all imports to reflect the different package
- worked around `ember-power-calendar` having `ember-cli-moment-shim` as a sub-dependency
- added empty in-repo-addon `ember-power-calendar-moment` to avoid `ember-power-calendar` complaining about a missing package
- added `ember-power-calendar-utils` in-repo-addon that is a copy of `ember-power-calendar-moment` but without the build-time renaming of the tree for better compatibility with embroider
refs https://github.com/TryGhost/Team/issues/1025
- added `{{humanize-recipient-filter}}` helper that converts an NQL recipient filter into a more readable format
- updated posts list to use the new helper in the sends column tooltip shown when hovering with the mouse
no issue
- relocated screen-specific components into a separate `tags/` directory as part of the move to keep the top-level `components/` directory for re-usable components
No ref
- Updated modal default state to make it look more clickable
- Updated the Casper upload error state design
- Changed the 'try again' button to directly open the finder rather than only resetting the modal
refs e021843e3f
- fixed closing of alerts due to missing `.args` after migrating to glimmer syntax
- updated related tests for glimmer component syntax
refs: https://github.com/TryGhost/Toolbox/issues/327
requires: TryGhost/Ghost#14791
- lang / locale has had a lot of churn, but we decided this setting should always be locale
- Removed test relating to unused editor_is_launch_complete setting
Co-authored-by: Rishabh <zrishabhgarg@gmail.com>
refs 8e120a74d6
- we use `data-test-state` inside of some modals which also use `<GhTaskButton>` which caused unrelated tests to start failing due to a change in matching element counts
refs 502fcaba3c
- the conditional for `isFailure` was wrong meaning we were showing the idle state unintentionally
- fixed the conditional so it checks for the return value rather than a `null` error
- updated the template with test selectors so it's easier to determine state where class names are not sufficient to differentiate