closes https://github.com/TryGhost/Team/issues/2285
- added passthrough of `cursorDidExitAtTop` action so the editor can trigger title input focus on key commands that trigger the cursor to leave the top of document
refs https://github.com/TryGhost/Team/issues/2327
As part of improving visibility for email failures, this change adds a new debug screen that allows visualising the email failures for a post. The screen is hidden on the UI for now and only accessible via URL directly.
Co-authored-by: Djordje Vlaisavljevic <dzvlais@gmail.com>
closes https://github.com/TryGhost/Team/issues/2286
- use the `registerAPI` prop to get access to a basic API for focusing and inserting paragraphs
- replaced commented mobiledoc based title key handling with lexical handling
closesTryGhost/Team#2313
- Added Sent event to Post analytics and Members feed. Now post can be
Sent or Received or Bounced.
- Excluded Delivered event from Sent filter on backend.
closes Sentry ADMIN-CC8
closes Sentry ADMIN-DDM
closes Sentry ADMIN-C9F
- there are situations where the editor range when key commands are triggered does not have a head section which then throws errors due to the commands assuming there will always be a section present
- added a guard to key commands that use the head section to abort early and fall back to default Mobiledoc behaviour when the section is missing
closes sentry ADMIN-C7S
- we can't guarantee that the iframe being swapped to has rendered yet at the time we swap iframes so we need a guard around the `contentDocument.body` property existing before setting it's `scrollTop` value
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
- showAPIError is a method intended for formatting errors from the Ghost API
- Ghost API Errors do not have a detail field, therefore this code was redundant
- there are also no related tests
- removing now because I'm trying to cleanup and streamline all our error handling code
refs: https://github.com/TryGhost/Team/issues/1121
- In certain cases our API sends the same data for message and context.
- We will also fix this server-side, but we should also be smart in the UI and not show duplicate info
no issue
- "unhandled" `TransitionAborted` errors almost always occur as part of expected application behaviour and were causing a lot of noise in Sentry making it harder to track down real errors
- when a `TransitionAborted` error occurs outside of expected behaviour it will usually be accompanied by other errors that do get logged
- there's a long-standing Ember issue about how aborted transition errors should be handled at https://github.com/emberjs/ember.js/issues/12505
closes https://github.com/TryGhost/Team/issues/2295
Problem:
- `<GhUploader>` is not yet converted to an Octane component so it's arguments are not read-only
- when a file is selected it sets it's `files` property which in turn updates the tracked `files` property that was passed in, and then again updates it to an empty file list when the input field is cleared
- that tracked property was never cleared once the product image was uploaded resulting in a "re-upload" attempt with an empty file list every time the product card was put back into edit mode
Fix:
- added a guard in `<GhUploader>` so it doesn't try to upload an empty file list if one is passed in as an attribute
- added a reset of the tracked `files` property in the product card once the image upload is complete
closes https://github.com/TryGhost/Team/issues/2126
- Cleaned up the following GA flags: `newsletterPaywall`, `freeTrial`, `compExpiring`, `searchHelper`, `emailAlerts`, `fixNewsletterLinks`.
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.
no refs.
- Navigating to `/settings/labs/import` opened the modal but also transitioned to a blank page in the background. Restructured content import modal so it's opening on top of the Labs page.
fixes https://github.com/TryGhost/Team/issues/2085
Don't load relations we don't need anymore for the posts table. And
reload the individual post when we open the analytics page with more
relations that we actually need.
- There was some formatting problems on the Dashboard with certain events
- There was inconsitencies with how we formatted some events over others
- Removed 'on' and just using '-' for all
refs https://github.com/TryGhost/Team/issues/2243
no issue
- `when` makes the modifier a little easier to read for it's typical use-case, eg:
- `{{scroll-to when=(eq entry.slug this.entry)}}`
- `{{scroll-to when=(eq this.focusArea "analytics")}}`
no issue
- changes were made to the default editor to adjust the header nav options when accessed from an analytics page but they weren't copied over to the duplicate editor route/controller we use for the in-development lexical editor
refs https://github.com/TryGhost/Team/issues/2233
**Problem**
When a user clicks an offer link that has an archived tier, the site
blocks and you are no longer able to scroll. This is because the product
for that offer can't be found. This has been fixed by updating the
`isActiveOffer` helper to also check for the existence of the
corresponding tier.
**Solution**
- You no longer are able to create new offers if there are no active
tiers
- A custom message is shown that instructs the user to create a new tier
if there are not active tiers on the offers page
- Improved detection of changes in tiers by correctly reloading the
members utils service after tier changes
- Portal redirects to the homepage for offers with an archived tier
(same behaviour as invalid offers)
- Offers of an archived tier are no longer visible in the dashboard
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).
fixes https://github.com/TryGhost/Team/issues/2134
fixes https://github.com/TryGhost/Team/issues/2133
- Moved all filters to separate files to make the filter component a lot more readable and easier to maintain.
- Removed long switch style code from hbs for filter column values
- Filters for features that are disabled (such as open tracking, click tracking or member attribution) are now hidden when they are disabled
- The open rate column in the members table is now only visible if open tracking is enabled
refs https://github.com/TryGhost/Team/issues/2213
When an email contains multiple links to the same destination, that link
is only shown once on the analytics page. The total displayed count is
not summed correctly.
- Made the majority of the row go to the editor instead
- Removed illegal nested hyperlinks and cleaned up other markup
- Removed some feature flag code around this page and fixed styles for them
- Improved some dark mode styling
- Lots of refactoring with code and styles
refs https://github.com/TryGhost/Team/issues/2223
closesTryGhost/Team#2143
- All logic for feedback pie chart was spread through multiple files. It
would be difficult to scale it. Now it is encapsulated in one file.
no issue
refs dac5cca899
- added cleanup of the `message` event handler added to `window` when the component is destroyed
- added a guard to the event handler method to abort early if a message is received whilst the component is being destroyed
- updated Billing Service and `<GHBillingIframe>` to not use `@classic` decorator
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`
no issue
- added cleanup of the `message` event handler added to `window` when the component is destroyed
- added a guard to the event handler method to abort early if a message is received whilst the component is being destroyed
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)
refs https://github.com/TryGhost/Ghost/issues/14101
- migrated to native class syntax and glimmer component patterns
- removed use of jQuery, the workaround to trigger change events no longer appears necessary
closes https://github.com/TryGhost/Team/issues/2190
- added a guard around the tier fetches in `membersUtils` service so the fetch doesn't occur unless we have a logged in user and they aren't a contributor
- extracted the `withPermissionsCheck` mirage util function and added role checks around the mocked tiers endpoints
- added an acceptance test that loads the content screen and creates a draft post as a contributor to help catch regressions
closes https://github.com/TryGhost/Team/issues/1076
refs f068e40723
refs 7fe9e06c4d
- The Members CSV importer was not auto-detecting and mapping the `complimentary_plan` column when it was present in CSV. This was to improve user-experience and NOT start the import as a "background job" by default.
- With resent (see refs) changes having "complimentary_plan" column in the imported file does not send the import into the background. We can now safely include it as auto-detected field, without compromising user experience.
closes: https://github.com/TryGhost/Ghost/issues/15505
When starting Ghost with a missing active theme, the design settings screen and change theme screen both end up in a broken state with the user unable to select a new theme as the active one.
The design screen has no default (or blank) slate, and so shows a preview of an empty theme.
- First added a new default screen to serve as a placeholder for when the state contains no active theme.
- Added a check for when there was no active theme, then redirects the user to the default screen .
The change theme screen wants to set an active property on the theme that should be active in the theme list.
- Added a check to see whether there is an active theme set.
- If there isn't one, don't bother trying to add the active property.
refs b027ed6378
- analytics page was split between old and new behind the audience feedback flag
- the new page had missing method as we switched the page to new one once the flag was switched on
fixes https://github.com/TryGhost/Team/issues/2175
- New event type `aggregated_click_event` that is disabled by default in all the existing activity feeds
- This returns click events, but only the first click events for each member/post combination.
- It includes the total count of unique link clicks for that member on that post combination
- Had to resort to some custom knex queries to make this work easily
- Requires `@tryghost/bookshelf-pagination@0.1.31`, included in `@tryghost/bookshelf-plugins@0.6.1` (this fixes an issue with custom selects breaking the total count query of pages)
- Went a bit overboard with the pagination tests to cover as much unknown edge cases as possible
refs https://github.com/TryGhost/Team/issues/2168
- wires new source tracking setting for members to UI
- splits the new analytics page settings to its own component, cleaned up the files and wired up the settings upstream
fixes https://github.com/TryGhost/Team/issues/2129
- This changes how the activity feed API parses the filter.
- We now parse the filter early to a MongoDB filter, and split it in two. One of the filters is applied to the pageActions, and the other one is used individually for every event type. We now allow to use grouping and OR's inside the filters because of this change. As long as we don't combine filters on 'type' with other filters inside grouped filters or OR, then it is allowed.
- We make use of mongoTransformer to manually inject a mongo filter without needing to parse it from a string value again (that would make it a lot harder because we would have to convert the splitted filter back to a string and we currently don't have methods for that).
- Added sorting by id for events with the same timestamp (required for reliable pagination)
- Added id to each event (required for pagination)
- Added more tests for filters
- Added test for pagination
- Removed unsued getSubscriptions and getVolume methods
Used new mongo utility methods introduced here: https://github.com/TryGhost/NQL/pull/49
closesTryGhost/Team#2159
- Added column to email table
- Hide the feedback tab on frontend depending on the column value
Co-authored-by: Daniel Lockyer <daniellockyer@fastmail.com>
- Changed the tab design to now include icons all across
- Better way of showing positive sentiment
- Much better responsiveness for the whole page
refs https://github.com/TryGhost/Team/issues/2172
no issue
When reloading the posts page, the labs settings wouldn't work. The 'feature' service labs property would try to JSON.parse an undefined labs setting (settings.labs === undefined) because settings wasn't loaded yet. After loading the settings, it wouldn't update because Ember's 'computed' decorator isn't able to watch this.
This was all caused by trying to access the emailAnalytics feature in the controller's constructor (this feature doesn't exist any longer). Removing this fixed the issue.
We probably need some protection for this in the future.
- Made a new function that checks if stubs are needed per tab
- Renamed the check for pagination to be a little more clear
- Made sure the pagination block is always to the right
- Made sure the pagination buttons don't show when there is no pagination
refs https://github.com/TryGhost/Team/issues/2149
- Removed the dummy rows as they looked like loading states
- Improved the spacing of the pie chart
- Showing total number when pagination isn't required
- Tweaks across the page to look more consistent
refs https://github.com/TryGhost/Team/issues/2149
fixes https://github.com/TryGhost/Team/issues/2137
For the analytics page, we need the sent events to show up immediately
after sending an email. Otherwise we need to wait for emails to be
marked as received (which takes too long) before being able to show them
on the analytics page.
This adds the email_sent_event, which is hidden by default everywhere
and used on the analytics page.
fixes: https://github.com/TryGhost/Ghost/issues/15291
- An attempt to improve re-authenticate modal toggle - show re-authenticate modal every time user save (ctrl/cmd + s)
- An attempt to fix redirection when user re-login on different tab. Prevent redirection to sign-in page since the user already logged in on another tab.
- Re-enable `editor` test on `authentication-test.js`
fixes https://github.com/TryGhost/Team/issues/2112
- Removed a bit of duplicate code across templates and components that was used to handle filters
- Updated filter objects to contain information about the filter
- Added resource filters that are able to select a single resource, which can be used in columns
- Filters can now define columns by themselves. Not all columns already make use of this functionality, but we can move those over later (cleanup: https://github.com/TryGhost/Team/issues/2133)
- The filter definitions became quite long. We should move them to separate files in the future: https://github.com/TryGhost/Team/issues/2134
- Filters can now have custom NQL parsing
- Improved support for parsing recursive or grouped NQL queries
- Added support for filtering members by feedback
refs https://github.com/TryGhost/Team/issues/2116
- allows site owners to edit a link in a post that has already been sent out, fixing any typos or other mistakes
- resets click counter for the edited link back to 0 so site owners can see the clicks on new link, doesn't change the overall click count
- Careful of flags, having different paginations depending on those
- Little stylistic adjustment to how pagination is shown on engagement bar
- Quite a few feature flag checks to make sure the right style is showing
refs https://github.com/TryGhost/Team/issues/2136
no issue
Improve the route communication between Ghost Admin and Ghost Explore to
reflect route changes in the URL and correctly navigate to Explore sub
routes
refs https://github.com/TryGhost/Team/issues/2116
- editing a link caused it to jump in the list as its count is reset to 0
- this forces the order of links same after edit, the new order is only visible on refresh or navigating away and coming back
refs https://github.com/TryGhost/Team/issues/2116
- wires link update API on post analytics UI page to save edited links for a newsletter
- all links matching the edited link are updated by the API in the backend
- Newsletter clicks module has new header and box
- Source attribution module has new header and box
- Resources have new headers inside the box
- New split layout if there are two modules side-by-side
refs https://github.com/TryGhost/Team/issues/2119
- fixes an edge case where if a site has no unavailable sources in a particular period, it broke the table view as the `Others` data doesn't get fetched
fixes https://github.com/TryGhost/Team/issues/2090
- This changes how sentiment is exposed in the API. Now it is exposed as a `sentiment` relation, directly on the model (no longer in counts). Internally we still use `count.sentiment`.
- Content API users (and themes) can include the 'sentiment' relation and order by sentiment.
- Updated Admin to use sentiment instead of count.sentiment
refs https://github.com/TryGhost/Team/issues/2116
- wires handling of success and error messages on editing a newsletter link
- has the update api commented out temporarily to mock the changes
no issue
- the `memberRecord` getter on the members activity controller was
returning the direct result of `store.findRecord()` which in reality is
a `PromiseObject` that is a type of proxy. Although templates handle
this OK, any JS code using the object needs to know that it's not a
typical type of object and has to use `.get()` for all property access
to avoid errors
- switched `memberRecord` from a getter to a resource so we have more
control over the returned object and loading lifecycle
- added a `MemberFetcher` resource class that awaits the result of the
store find and only then sets the value meaning we always have a fully
resolved model object
- being a resource the fetch will only occur when the `member` id
property changes, unlike the getter which performed the fetch every time
it was accessed
fixes https://github.com/TryGhost/Team/issues/2084
- When audience feedback is enabled, we use a single 'conversions' count instead of having separate ones for signups and paid conversions.
- The analytics component is separated so we can change it without breaking the existing page.
closes: https://github.com/TryGhost/Ghost/issues/15470
- When multiple browser tabs are open, each manipulate a different copy of ember data model, changes to the model in one tab are not reflected in the model of the other tab.
- When updating some settings, all current settings were sent to the API.
- As a result, when updating two different categories of settings (navigation/code inspection) in different tabs, the second update was overriding the first one.
- From a user perspective, this is not a natural behaviour. Only settings visible on-screen when clicking save should be modified.
Co-authored-by: Kevin Ansfield <kevin@lookingsideways.co.uk>
fixes https://github.com/TryGhost/Team/issues/2054
This change adds the sentiment and positive_feedback counts to the posts models. This change isn't really ideal because there are some problems here:
- sentiment isn't really a count
- we don't need to include the sentiment and positive_feedback as a default for posts (but the same is true for attribution)
It would make sense to move this to separate endpoints that only fetch the analytics for a given post when the analytics page is opened. But for our initial skateboard version of audience feedback this should be a good start to already see the data.
closes: https://github.com/TryGhost/Ghost/issues/15450
- the object property "note" was updated only on focus out, which is wrong
- the property should be updated on input
-this problem occurred only for TextArea component
no issue
- if a plain native class instance with tracked properties is validated against the `ValidationEngine` and it's associated validators would cause errors by assuming that the instance has a `.get()` method
- updated all model access in `ValidationEngine` and the validators to use direct property access which works for both native class and `EmberObject` instances
refs https://github.com/TryGhost/Ghost/issues/14101
- migrated to full native class syntax
- swapped use of `<GhTextInput>` in favor of native `<input>` and removed use of `{{action}}` in associated template
refs https://github.com/TryGhost/Ghost/issues/14101
- migrated to full native class syntax
- removed loading of snippets as they are not needed on post lists (they are needed on the editor screen which does it's own loading)
- removed `access` query param definition leftover from earlier development
- removed use of `{{action}}` in associated templates
no issue
- moved screen-specific components out of the top-level components directory
- top-level directory should eventually only contain generally re-usable/application-wide components
no issue
- moved screen-specific components out of the top-level components directory
- top-level directory should eventually only contain generally re-usable/application-wide components
no issue
- the `ella-sparse-array` dependency used for the sparsely populated list on the members screen creates ProxyObjects that wrap the underlying member model instances meaning the forced use of `.get()` and `.set()` required by ProxyObject was leaking through to other areas of the app causing a mismatch in code patterns
- moved the loading state for each member into a separate component and put the loading conditional directly inside the `{{#each members}}` block so that we can pass the real model instance through to components via `{{member.content}}` rather than passing the ProxyObject wrapper, avoiding unexpected errors when not using `.get()` and `.set()` on member arguments
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
no issue
- Added Ghost Explore screen behind alpha flag
- Moved existing /explore route to /explore/connect which we'll redirect to for outside requests
- Added iframe communication with Ghost Explore App
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.