refs https://github.com/TryGhost/Team/issues/1130
- copied theme upload modal to new modals system and refactored for Octane syntax
- updated to use `themeManagement` service rather than passed in actions so the modal-based process can be opened from any screen
- added default `beforeClose()` for the modal to the modals service so it won't close if an upload is in-progress (defaults were moved directly into the class so it had access to services)
- added `themeManagement.upload` action for triggering the upload modal and providing a central place for limit checks
- added upload-triggering buttons to change-theme and advanced design screens
refs https://github.com/TryGhost/Team/issues/1130
- added link to design sidebar
- dropped change-theme modal and associated route behaviour
- copied basic themes marketplace list into the change-theme controller/template
refs https://github.com/TryGhost/Team/issues/1130
- added `ui.contextualNavMenu` property that when set will switch the main nav menu between components, if it's not set then it will show the default "main" menu component
- added `design` menu sub-component of `gh-nav-menu` ready for use via `contextualNavMenu`
- moved sidebar contents from the design modal into this component
- updated design route to set/reset `ui.contextualNavMenu` to `design` on entering/leaving the route
- all other design routes are sub-routes so this works across all other design screens
- moved base design modal preview into the `settings/design/index` controller/template
- using index means that it's the default screen for `/settings/design` but will be automatically replaced by any other `design.x` routes
- moved `design/advanced` modal content into the `settings.design.advanced` controller/template and removed the modal handling from the route
refs https://github.com/TryGhost/Team/issues/1084
- updates shareable offer link UI to to open directly instead of route
- calculates offer url from code and updates in link modal
- wires copy button on link modal
- removes route based link code for modal
no issue
- pattern of downloading a file by creating an iframe and setting the `src` attribute was repeated throughout the codebase and was using a mix of native and jQuery patterns
- added a `utils` service for housing one-off utility methods like this to avoid repetition and mixed patterns becoming more widespread (we want to get rid of jQuery usage)
refs https://github.com/TryGhost/Team/issues/1111
refs https://github.com/TryGhost/Team/issues/1103
- moved customize modal from a link on the design screen to the main design screen
- changed modal design to be a full-screen overlay with side bar that emulates standard Admin design
- added toggled groups of settings in sidebar
- added `{{set-has}}` helper for use in conditionals matching when a Set contains an object
- added grouping of theme settings
- dropped unfinished advanced/change theme modals
no-issue
This adds the ability to apply complex filters to members, as well as to
perform bulk actions on the filtered set, including unsubscribing,
adding & removing labels.
closes https://github.com/TryGhost/Team/issues/1100
- fixes unsaved changes popup which was triggered due to incorrect price comparison on membership screen
- issue only happened if the stripe price entered translated to a decimal value as the price change check was parsing it as integer
refs https://github.com/TryGhost/Team/issues/1070
- split select form component into it's own component so it's cleaner when we get to additional setting types
- added change handler that updates the setting record's value when a new option is selected
- added `.isDirty` to the custom-theme-settings service so we can warn of unsaved changes and revert any changed values when needed
- added save of custom theme settings to the customize design modal's save routine
- added missing `notifications` service import to customize design controller
refs https://github.com/TryGhost/Team/issues/1045
- added tabs to the the customise design modal's sidebar for general settings and theme settings
- copied settings from the existing branding modal plus site description from general settings screen into the general settings tab
- theme settings tab left blank ready for static design
- `saveTask` put on the controller so that we can access it from the route, allowing us to pause modal closing when navigating away (implementation left for later)
refs https://github.com/TryGhost/Team/issues/1045
- added blank `/settings/design` route and associated screen
- redirects to settings index if associated labs flag is not enabled
- when custom theme settings labs flag is enabled, replaced Branding and Theme links with single Design link
refs https://github.com/TryGhost/Team/issues/559
- moved the modal component class, template, and sub-components into a `components/modals/` directory to keep the top-level dir cleaner
- migrated component class to full glimmer syntax
refs https://github.com/TryGhost/Team/issues/559
- moved the modal component class and template into a `components/modals/` directory to keep the top-level dir cleaner
- migrated component class to glimmer syntax
- moved route transition behaviour directly into the class to avoid weird route-action indirection
refs https://github.com/TryGhost/Team/issues/559
We want to get rid of our existing modals implementation because it doesn't play well with Glimmer compoments and the animation library it uses is now unmaintained and blocking our Ember.js upgrades.
- installed addon using customised fork
- fork allows passthrough of `allowOutsideClick` to `focus-trap` so we can allow clicks on dropdowns and other wormholed content inside of a modal
- extended the `modals` service locally so we can customise click-outside-to-close behaviour and tie in with our `dropdowns` service
- set up styles in `modals-new.css`, mostly copied from `modals.css` with a few specific overrides
- once all modals are converted we can drop the old `modals.css` and rename `modals-new.css`
no refs
- resets filter columns on list when query params are removed from the url via sidebar click transition
- reloads the updated list on new bulk actions on the filtered list
closes https://github.com/TryGhost/Team/issues/977
A new label input dropdown was added behind filtering labs flag along with new filtering UI on members list screen, which includes member editing directly via the dropdown. This adds the same editing function to the members detail screen too behind the flag
closes https://github.com/TryGhost/Team/issues/1028
Bulk operations - add/remove label, unsubscribe - were added to filtered members list behind filtering labs flag as part of introducing filtering on members list. This handles the success/error response on bulk operations and shows them in the popup similar to delete bulk operation.
refs https://github.com/TryGhost/Team/issues/963
- updates the list when either the relation or value changes for a filter row.
- only filter rows with value are used
- consistent behavior for "apply all" and "reset all"
- `Enter` and `onFocusOut` behavior for rows with text values
refs https://github.com/TryGhost/Team/issues/954
- When an email-only post with a "sent" status was edited, it's status changed to "draft", which is an incorrect behavior. This change is causing the "sent" status to persist and removes the transition error.
no issues
refs https://github.com/emberjs/ember.js/issues/5566#issuecomment-429389165
Member deletion UI gets stuck in UI when deleted via these steps: View member list, filtered by label. Click on a member, delete them. Admin transitions back to previous screen before action is completed — deletion completes successfully but deletion UI hangs.
This happens due to a niche ember bug which causes transitions to abort when transitioning to a route with query params having `refreshModel:true`. The fix is simple one liner with return being separated from the route transition statement.
refs https://github.com/TryGhost/Team/issues/981
- saving a new or existing tier needed a hit on top right save on settings as well or it wasn't showing on the front-end. This change refreshes portal preview once a tier is saved from its modal window so that frontend can correctly reflect the right data immediately.
refs https://github.com/TryGhost/Team/issues/973
- added `@showCreate` option to `<GhInputWithSelect>` that enables the create option without having to pass a function in `@showCreateWhen`
- fixed autofocus not focusing input element in `<GhInputWithSelect>` when `autofocus="true"` isn't enough by itself
- updated `selectOrCreate` in `<GhInputWithSelect>` to trigger `onChange` if it's passed in rather than `onInput`
- swapped input in labs snippet input to `<GhInputWithSelect>`
- added actions for updating a snippet when an existing snippet is selected
- added action to editor control for saving an updated snippet
refs https://github.com/TryGhost/Team/issues/994
Non-owner admin users have visibility of the "Connect with Stripe" UI in Admin, but lack permissions to setup the Stripe session in order to actually connect Stripe. This leads to a dead-end with a raw JSON api response, which should never be the case. This change patches the UI by removing Stripe Connect paths for non-owner admins.
closes https://github.com/TryGhost/Team/issues/969
Wires the bulk action operation UI to Ghost API to perform operations on filtered member list - unsubscribe filtered members, add label to filtered members or remove label from filtered members
refs https://github.com/TryGhost/Team/issues/954
- The transition values wever missing for new "sent" email status and caused a 500 error to be displayed even though it had nothing to do with server errors
- There will be more tweaks to this in future iterations, this is a stop gap solution to have a working UI
closes https://github.com/TryGhost/Team/issues/965
If there's only one filter row in the members filter builder modal, then clicking on "X" in that row resets the fields instead of removing the complete row and showing empty filter builder
refs https://github.com/TryGhost/Team/issues/969
A lot of power of filtering members comes from ability to perform actions on the filtered member list. This change adds bulk operation actions on the the UI to apply on filtered members, but has not wired them up to the API yet.
- adds unsubscribe bulk operation UI
- adds label addition bulk operation UI
- adds label removal bulk operation UI
- adds new single label selection UI for add/remove label to members UI
refs https://github.com/TryGhost/Team/issues/943
- adds new columns to member list table based on selected filters in UI
- handles dynamic columns in members list with formatted output like for labels
- works behind the filtering feature flag
no issue
- added free members to dashboard controller's count stats data
- moved email open rate chart into it's own dashboard box
- added free members count chart under paid members chart (where email open rate used to be)
refs e25e36352d
Since the concat method does not change the existing array but instead returns a new array, the extra filters on the API query object were not being applied. The extra filter included filtering on `created_at` date for members which was not applied as the filter was not stored in the array correctly.
no issue
- added `dashboardTwo` feature flag and labs screen toggle
- added `dashboard-labs` route with duplicated dashboard controller/template
- added redirect to `dashboard` route so it transitions to `dashboard-labs` when the feature is enabled
refs https://github.com/TryGhost/Team/issues/927
- we'll soon need access to adjusted accent colours outside of the application controller so they're now available on the `ui` service
closes https://github.com/TryGhost/Team/issues/865
Ghost now returns a forbidden error rather than an unauthorized error when saving whilst logged out so the session invalidation was not being triggered.
- added forbidden check to ajax service to trigger session invalidation
- added automatic retry of save in editor when re-authenticating
- fixed re-population of user and proxy services when re-authenticating, it's not needed at that point because nothing has been cleared
issue https://github.com/TryGhost/Team/issues/857
- The goal is to avoid testing for the owner role only is cases where we should be testing for the owner or admin role
- `isOwner` => `isOwnerOnly`
- `isAdmin` => `isAdminOnly`
- `isOwnerOrAdmin` => `isAdmin` (concerns now both Owner and Admins)
no issue
Having `session.user` return a promise made dealing with it in components difficult because you always had to remember it returned a promise rather than a model and had to handle the async behaviour. It also meant that you couldn't use any current user properties directly inside getters which made refactors to Glimmer/Octane idioms harder to reason about.
`session.user` was a cached computed property so it really made no sense for it to be a promise - it was loaded on first access and then always returned instantly but with a fulfilled promise rather than the underlying model.
Refactoring to a synchronous property that is loaded as part of the authentication flows (we load the current user to check that we're logged in - we may as well make use of that!) means one less thing to be aware of/remember and provides a nicer migration process to Glimmer components. As part of the refactor, the auth flows and pre-load of required data across other services was also simplified to make it easier to find and follow.
- refactored app setup and `session.user`
- added `session.populateUser()` that fetches a user model from the current user endpoint and sets it on `session.user`
- removed knowledge of app setup from the `cookie` authenticator and moved it into = `session.postAuthPreparation()`, this means we have the same post-authentication setup no matter which authenticator is used so we have more consistent behaviour in tests which don't use the `cookie` authenticator
- switched `session` service to native class syntax to get the expected `super()` behaviour
- updated `handleAuthentication()` so it populate's `session.user` and performs post-auth setup before transitioning (handles sign-in after app load)
- updated `application` route to remove duplicated knowledge of app preload behaviour that now lives in `session.postAuthPreparation()` (handles already-authed app load)
- removed out-of-date attempt at pre-loading data from setup controller as that's now handled automatically via `session.handleAuthentication`
- updated app code to not treat `session.user` as a promise
- predominant usage was router `beforeModel` hooks that transitioned users without valid permissions, this sets us up for an easier removal of the `current-user-settings` mixin in the future
no issue
- there can be cases where the connection fails but Ctrl/Cmd+S won't work as a direct retry (eg, publish fails so the status reverts, in that case Cmd+S would save a draft rather than re-attempt a publish)
- switched to a neutral "try again" message
refs https://github.com/TryGhost/Team/issues/803
With multiple products we'll re-enable segmentation by product for posts, which also means need to add a new option to the default post access setting in Membership settings. This change -
- adds new `A segment` option to default post access dropdown behind the alpha flag for multiple products
- shows member segment select dropdown for `A segment` option
- handles update of `defaultContentVisibility` to allow setting custom filter
closes https://github.com/TryGhost/Team/issues/837
We previously added automatic retries to the editor controller for post saves; reviewing the resulting logs in Sentry we can see this stopped the "Server unreachable" error alerts showing to users because the requests typically succeeded on the first retry that was made 5 seconds later. However the problem is not limited to post saves and we can see other requests hitting the same issue, including when working in the editor such as adding embed cards, uploading images, or fetching member counts before publishing.
All of the API network requests we make in Admin run through an `ajax` service that makes and handles the request/response. By moving the retry logic for specific errors out of the editor controller and into the ajax service we can make temporary connection handling more graceful across the app.
- move retry behaviour from the editor controller to the `ajax` service so we can retry any request rather than just post save requests
- speed up retries so we reconnect as soon as possible
- first retry at 500ms, then every 1000ms (previous was every 5s which meant overly long waits)
- reduce total retry time from >30s to 15s
- improve reporting to Sentry
- report when a retry was required
- report when a retry failed
- include the total time taken for both success and failure reports
- include the `server` header value from requests to distinguish between CDNs
- include type of error so we can distinguish "server unreachable" from "maintenance" retries
refs a6c6def7e1
- we weren't checking if an error was a validation error by examining the number of errors on the post model, this meant we weren't falling through to the generic error handling/display logic that shows an alert for validation errors when a save isn't a background/silent save
no issue
- when Ghost is in maintenance mode after an upgrade we know it will come back shortly so automatically retrying the save in the same way we do for "server unreachable" errors provides a smoother experience compared to halting and showing a red alert bar
no issue
- post status was not being reset after certain types of failure to publish/unpublish/schedule which meant that the editor could be left in an odd in-between state where the displayed status did not reflect reality
- fixed "saving/publish/schedule failed:" wording in error message when a server unreachable error was detected, the "saving/publish/schedule" did not reflect the actual status change because we were passing through only the current status rather than previous+new status'
no issue
- if a ServerUnreachable error is triggered by a non-background-save then we'd show the expected custom alert and then immediately overwrite it because `savePost`'s catch was not expecting an `undefined` error
refs https://github.com/TryGhost/Team/issues/792
- updates product benefit to use `name` instead of `label` attribute for benefit text
- updates model/serializer/validator to correctly handle benefit attributes
- added `+` button for adding new labels as the enter behavior is closing the popup(needs fix)
closes https://github.com/TryGhost/Team/issues/799
- previous logic was still using `stripe_plans` for MRR currency, which is not used anymore
- updates first product's currency as default mrr currency
refs https://github.com/TryGhost/Team/issues/788
- automatically retry any failed save attempts every 5 seconds for up to 30 seconds
- only show error bar after when we completely give up
- clear error bar if a later save is successful
- update error message to specify there's a connection problem and to retry with Cmd+S
- notify Sentry of a successful save after an initial failure including the number of attempts that were made and the total time for save to succeed in seconds