mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-27 21:03:29 +03:00
Fixed hosting management screen not loading after sign-in process (#15763)
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`
This commit is contained in:
parent
c00e098915
commit
9bdb25d184
@ -2,6 +2,7 @@ import Component from '@glimmer/component';
|
||||
import validator from 'validator';
|
||||
import {action} from '@ember/object';
|
||||
import {htmlSafe} from '@ember/template';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {inject as service} from '@ember/service';
|
||||
import {task, timeout} from 'ember-concurrency';
|
||||
import {tracked} from '@glimmer/tracking';
|
||||
@ -20,13 +21,14 @@ html {
|
||||
// TODO: remove duplication with <ModalPostEmailPreview>
|
||||
export default class ModalPostPreviewEmailComponent extends Component {
|
||||
@service ajax;
|
||||
@service config;
|
||||
@service feature;
|
||||
@service ghostPaths;
|
||||
@service session;
|
||||
@service settings;
|
||||
@service store;
|
||||
|
||||
@inject config;
|
||||
|
||||
@tracked html = '';
|
||||
@tracked subject = '';
|
||||
@tracked memberSegment = 'status:free';
|
||||
|
@ -4,13 +4,16 @@ import {
|
||||
IMAGE_MIME_TYPES
|
||||
} from 'ghost-admin/components/gh-image-uploader';
|
||||
import {action} from '@ember/object';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {inject as service} from '@ember/service';
|
||||
import {tracked} from '@glimmer/tracking';
|
||||
|
||||
export default class ModalPostPreviewSocialComponent extends Component {
|
||||
@service config;
|
||||
@service settings;
|
||||
@service ghostPaths;
|
||||
|
||||
@inject config;
|
||||
|
||||
@tracked editingFacebookTitle = false;
|
||||
@tracked editingFacebookDescription = false;
|
||||
@tracked editingTwitterTitle = false;
|
||||
|
@ -1,16 +1,18 @@
|
||||
import Component from '@ember/component';
|
||||
import classic from 'ember-classic-decorator';
|
||||
import {htmlSafe} from '@ember/template';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {inject as service} from '@ember/service';
|
||||
|
||||
@classic
|
||||
export default class GhBillingIframe extends Component {
|
||||
@service billing;
|
||||
@service config;
|
||||
@service ghostPaths;
|
||||
@service ajax;
|
||||
@service notifications;
|
||||
|
||||
@inject config;
|
||||
|
||||
isOwner = null;
|
||||
fetchingSubscription = false;
|
||||
|
||||
|
@ -1,17 +1,19 @@
|
||||
import Component from '@ember/component';
|
||||
import classic from 'ember-classic-decorator';
|
||||
import {action} from '@ember/object';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {reads} from '@ember/object/computed';
|
||||
import {inject as service} from '@ember/service';
|
||||
|
||||
@classic
|
||||
export default class GhBillingUpdateButton extends Component {
|
||||
@service router;
|
||||
@service config;
|
||||
@service ghostPaths;
|
||||
@service ajax;
|
||||
@service billing;
|
||||
|
||||
@inject config;
|
||||
|
||||
subscription = null;
|
||||
|
||||
@reads('billing.subscription.isActiveTrial')
|
||||
|
@ -1,10 +1,10 @@
|
||||
import Component from '@ember/component';
|
||||
import classic from 'ember-classic-decorator';
|
||||
import {inject as service} from '@ember/service';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {tagName} from '@ember-decorators/component';
|
||||
|
||||
@classic
|
||||
@tagName('')
|
||||
export default class GhBlogUrl extends Component {
|
||||
@service config;
|
||||
@inject config;
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import {
|
||||
} from 'ghost-admin/services/ajax';
|
||||
import {computed, get} from '@ember/object';
|
||||
import {htmlSafe} from '@ember/template';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {isArray} from '@ember/array';
|
||||
import {isBlank} from '@ember/utils';
|
||||
import {run} from '@ember/runloop';
|
||||
@ -23,7 +24,6 @@ export const ICON_PARAMS = {purpose: 'icon'};
|
||||
|
||||
export default Component.extend({
|
||||
ajax: service(),
|
||||
config: service(),
|
||||
notifications: service(),
|
||||
settings: service(),
|
||||
|
||||
@ -64,6 +64,8 @@ export default Component.extend({
|
||||
uploadSuccess: () => {},
|
||||
uploadFailed: () => {},
|
||||
|
||||
config: inject(),
|
||||
|
||||
// TODO: this wouldn't be necessary if the server could accept direct
|
||||
// file uploads
|
||||
formData: computed('file', function () {
|
||||
|
@ -7,6 +7,7 @@ import {action, computed} from '@ember/object';
|
||||
import {assign} from '@ember/polyfills';
|
||||
import {classNameBindings, classNames} from '@ember-decorators/component';
|
||||
import {htmlSafe} from '@ember/template';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {isEmpty, typeOf} from '@ember/utils';
|
||||
import {run} from '@ember/runloop';
|
||||
import {inject as service} from '@ember/service';
|
||||
@ -21,10 +22,11 @@ import {inject as service} from '@ember/service';
|
||||
'_isSplitScreen:gh-markdown-editor-side-by-side'
|
||||
)
|
||||
export default class GhMarkdownEditor extends Component.extend(ShortcutsMixin) {
|
||||
@service config;
|
||||
@service notifications;
|
||||
@service settings;
|
||||
|
||||
@inject config;
|
||||
|
||||
// Public attributes
|
||||
autofocus = false;
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
import Component from '@glimmer/component';
|
||||
import {action} from '@ember/object';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {inject as service} from '@ember/service';
|
||||
import {tracked} from '@glimmer/tracking';
|
||||
|
||||
@ -16,7 +17,8 @@ export default class extends Component {
|
||||
@service ghostPaths;
|
||||
@service ajax;
|
||||
@service store;
|
||||
@service config;
|
||||
|
||||
@inject config;
|
||||
|
||||
@tracked showTierModal = false;
|
||||
@tracked tierModel = null;
|
||||
|
@ -1,18 +1,20 @@
|
||||
import Component from '@glimmer/component';
|
||||
import {action} from '@ember/object';
|
||||
import {bind} from '@ember/runloop';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {isEmpty} from '@ember/utils';
|
||||
import {inject as service} from '@ember/service';
|
||||
import {tracked} from '@glimmer/tracking';
|
||||
|
||||
export default class DesignMenuComponent extends Component {
|
||||
@service config;
|
||||
@service customThemeSettings;
|
||||
@service router;
|
||||
@service settings;
|
||||
@service store;
|
||||
@service themeManagement;
|
||||
|
||||
@inject config;
|
||||
|
||||
@tracked openSection = null;
|
||||
|
||||
themes = this.store.peekAll('theme');
|
||||
|
@ -2,16 +2,18 @@ import Component from '@ember/component';
|
||||
import calculatePosition from 'ember-basic-dropdown/utils/calculate-position';
|
||||
import classic from 'ember-classic-decorator';
|
||||
import {and, match} from '@ember/object/computed';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {inject as service} from '@ember/service';
|
||||
|
||||
@classic
|
||||
export default class Footer extends Component {
|
||||
@service config;
|
||||
@service session;
|
||||
@service router;
|
||||
@service whatsNew;
|
||||
@service feature;
|
||||
|
||||
@inject config;
|
||||
|
||||
@and('config.clientExtensions.dropdown', 'session.user.isOwnerOnly')
|
||||
showDropdownExtension;
|
||||
|
||||
|
@ -7,6 +7,7 @@ import {action} from '@ember/object';
|
||||
import {and, equal, match, or, reads} from '@ember/object/computed';
|
||||
import {getOwner} from '@ember/application';
|
||||
import {htmlSafe} from '@ember/template';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {inject as service} from '@ember/service';
|
||||
import {tagName} from '@ember-decorators/component';
|
||||
import {task} from 'ember-concurrency';
|
||||
@ -15,7 +16,6 @@ import {task} from 'ember-concurrency';
|
||||
@tagName('')
|
||||
export default class Main extends Component.extend(ShortcutsMixin) {
|
||||
@service billing;
|
||||
@service config;
|
||||
@service customViews;
|
||||
@service feature;
|
||||
@service ghostPaths;
|
||||
@ -28,6 +28,8 @@ export default class Main extends Component.extend(ShortcutsMixin) {
|
||||
@service membersStats;
|
||||
@service settings;
|
||||
|
||||
@inject config;
|
||||
|
||||
iconStyle = '';
|
||||
iconClass = '';
|
||||
memberCountLoading = true;
|
||||
|
@ -2,6 +2,7 @@ import Component from '@ember/component';
|
||||
import classic from 'ember-classic-decorator';
|
||||
import copyTextToClipboard from 'ghost-admin/utils/copy-text-to-clipboard';
|
||||
import {action, computed} from '@ember/object';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {inject as service} from '@ember/service';
|
||||
import {tagName} from '@ember-decorators/component';
|
||||
import {task, timeout} from 'ember-concurrency';
|
||||
@ -9,10 +10,11 @@ import {task, timeout} from 'ember-concurrency';
|
||||
@classic
|
||||
@tagName('')
|
||||
export default class GhPortalLinks extends Component {
|
||||
@service config;
|
||||
@service store;
|
||||
@service settings;
|
||||
|
||||
@inject config;
|
||||
|
||||
isLink = true;
|
||||
prices = null;
|
||||
copiedPrice = null;
|
||||
@ -52,9 +54,8 @@ export default class GhPortalLinks extends Component {
|
||||
return [];
|
||||
}
|
||||
|
||||
init() {
|
||||
super.init(...arguments);
|
||||
this.siteUrl = this.config.blogUrl;
|
||||
get siteUrl() {
|
||||
return this.config.blogUrl;
|
||||
}
|
||||
|
||||
@action
|
||||
|
@ -4,6 +4,7 @@ import classic from 'ember-classic-decorator';
|
||||
import moment from 'moment-timezone';
|
||||
import {action, computed} from '@ember/object';
|
||||
import {alias, or} from '@ember/object/computed';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {inject as service} from '@ember/service';
|
||||
import {tagName} from '@ember-decorators/component';
|
||||
|
||||
@ -12,7 +13,6 @@ import {tagName} from '@ember-decorators/component';
|
||||
export default class GhPostSettingsMenu extends Component {
|
||||
@service feature;
|
||||
@service store;
|
||||
@service config;
|
||||
@service ajax;
|
||||
@service ghostPaths;
|
||||
@service notifications;
|
||||
@ -21,6 +21,8 @@ export default class GhPostSettingsMenu extends Component {
|
||||
@service settings;
|
||||
@service ui;
|
||||
|
||||
@inject config;
|
||||
|
||||
post = null;
|
||||
isViewingSubview = false;
|
||||
|
||||
|
@ -5,6 +5,7 @@ import validator from 'validator';
|
||||
import {action, computed} from '@ember/object';
|
||||
import {alias, not, oneWay, or} from '@ember/object/computed';
|
||||
import {htmlSafe} from '@ember/template';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {inject as service} from '@ember/service';
|
||||
import {task, timeout} from 'ember-concurrency';
|
||||
|
||||
@ -18,7 +19,8 @@ export default class Email extends Component {
|
||||
@service notifications;
|
||||
@service session;
|
||||
@service settings;
|
||||
@service config;
|
||||
|
||||
@inject config;
|
||||
|
||||
post = null;
|
||||
sendTestEmailError = '';
|
||||
|
@ -1,11 +1,11 @@
|
||||
import Component from '@glimmer/component';
|
||||
import {action} from '@ember/object';
|
||||
import {inject as service} from '@ember/service';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {task, timeout} from 'ember-concurrency';
|
||||
import {tracked} from '@glimmer/tracking';
|
||||
|
||||
export default class GhSiteIframeComponent extends Component {
|
||||
@service config;
|
||||
@inject config;
|
||||
|
||||
@tracked isInvisible = this.args.invisibleUntilLoaded;
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
import Component from '@glimmer/component';
|
||||
import {action} from '@ember/object';
|
||||
import {getSymbol} from 'ghost-admin/utils/currency';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {inject as service} from '@ember/service';
|
||||
import {tracked} from '@glimmer/tracking';
|
||||
|
||||
@ -9,7 +10,8 @@ export default class extends Component {
|
||||
@service ghostPaths;
|
||||
@service ajax;
|
||||
@service store;
|
||||
@service config;
|
||||
|
||||
@inject config;
|
||||
|
||||
@tracked showTierModal = false;
|
||||
|
||||
|
@ -2,7 +2,7 @@ import Component from '@ember/component';
|
||||
import classic from 'ember-classic-decorator';
|
||||
import {classNames} from '@ember-decorators/component';
|
||||
import {computed} from '@ember/object';
|
||||
import {inject as service} from '@ember/service';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
|
||||
/*
|
||||
Example usage:
|
||||
@ -11,7 +11,7 @@ Example usage:
|
||||
@classic
|
||||
@classNames('ghost-url-preview')
|
||||
export default class GhUrlPreview extends Component {
|
||||
@service config;
|
||||
@inject config;
|
||||
|
||||
prefix = null;
|
||||
slug = null;
|
||||
|
@ -3,7 +3,7 @@ import Component from '@glimmer/component';
|
||||
import React, {Suspense} from 'react';
|
||||
import ghostPaths from 'ghost-admin/utils/ghost-paths';
|
||||
import {action} from '@ember/object';
|
||||
import {inject as service} from '@ember/service';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
|
||||
class ErrorHandler extends React.Component {
|
||||
state = {
|
||||
@ -90,7 +90,7 @@ const KoenigEditor = (props) => {
|
||||
};
|
||||
|
||||
export default class KoenigLexicalEditor extends Component {
|
||||
@service config;
|
||||
@inject config;
|
||||
|
||||
@action
|
||||
onError(error) {
|
||||
|
@ -1,6 +1,7 @@
|
||||
import ModalBase from 'ghost-admin/components/modal-base';
|
||||
import classic from 'ember-classic-decorator';
|
||||
import {action} from '@ember/object';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {inject as service} from '@ember/service';
|
||||
import {task} from 'ember-concurrency';
|
||||
import {tracked} from '@glimmer/tracking';
|
||||
@ -9,13 +10,13 @@ import {tracked} from '@glimmer/tracking';
|
||||
@classic
|
||||
export default class ModalFreeMembershipSettings extends ModalBase {
|
||||
@service settings;
|
||||
@service config;
|
||||
|
||||
@inject config;
|
||||
|
||||
@tracked freeSignupRedirect;
|
||||
@tracked siteUrl;
|
||||
init() {
|
||||
super.init(...arguments);
|
||||
this.siteUrl = this.config.blogUrl;
|
||||
|
||||
get siteUrl() {
|
||||
return this.config.blogUrl;
|
||||
}
|
||||
|
||||
@action
|
||||
|
@ -1,16 +1,18 @@
|
||||
import ModalComponent from 'ghost-admin/components/modal-base';
|
||||
import copyTextToClipboard from 'ghost-admin/utils/copy-text-to-clipboard';
|
||||
import {alias} from '@ember/object/computed';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {inject as service} from '@ember/service';
|
||||
import {task, timeout} from 'ember-concurrency';
|
||||
|
||||
export default ModalComponent.extend({
|
||||
config: service(),
|
||||
store: service(),
|
||||
|
||||
classNames: 'modal-impersonate-member',
|
||||
|
||||
signinUrl: null,
|
||||
config: inject(),
|
||||
|
||||
member: alias('model'),
|
||||
|
||||
didInsertElement() {
|
||||
|
@ -10,11 +10,11 @@ import {
|
||||
} from 'ghost-admin/services/ajax';
|
||||
import {computed} from '@ember/object';
|
||||
import {htmlSafe} from '@ember/template';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {isBlank} from '@ember/utils';
|
||||
import {inject as service} from '@ember/service';
|
||||
|
||||
export default ModalComponent.extend({
|
||||
config: service(),
|
||||
ajax: service(),
|
||||
notifications: service(),
|
||||
store: service(),
|
||||
@ -34,6 +34,8 @@ export default ModalComponent.extend({
|
||||
// Allowed actions
|
||||
confirm: () => {},
|
||||
|
||||
config: inject(),
|
||||
|
||||
uploadUrl: computed(function () {
|
||||
return `${ghostPaths().apiRoot}/members/upload/`;
|
||||
}),
|
||||
|
@ -3,12 +3,12 @@ import ModalComponent from 'ghost-admin/components/modal-base';
|
||||
import copyTextToClipboard from 'ghost-admin/utils/copy-text-to-clipboard';
|
||||
import {action, computed} from '@ember/object';
|
||||
import {htmlSafe} from '@ember/template';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {inject as service} from '@ember/service';
|
||||
import {task, timeout} from 'ember-concurrency';
|
||||
const ICON_EXTENSIONS = ['gif', 'jpg', 'jpeg', 'png', 'svg'];
|
||||
|
||||
export default ModalComponent.extend({
|
||||
config: service(),
|
||||
modals: service(),
|
||||
membersUtils: service(),
|
||||
settings: service(),
|
||||
@ -31,6 +31,8 @@ export default ModalComponent.extend({
|
||||
|
||||
confirm() {},
|
||||
|
||||
config: inject(),
|
||||
|
||||
backgroundStyle: computed('settings.accentColor', function () {
|
||||
let color = this.settings.accentColor || '#ffffff';
|
||||
return htmlSafe(`background-color: ${color}`);
|
||||
|
@ -1,13 +1,13 @@
|
||||
import ModalComponent from 'ghost-admin/components/modal-base';
|
||||
import ValidationEngine from 'ghost-admin/mixins/validation-engine';
|
||||
import {htmlSafe} from '@ember/template';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {isVersionMismatchError} from 'ghost-admin/services/ajax';
|
||||
import {reads} from '@ember/object/computed';
|
||||
import {inject as service} from '@ember/service';
|
||||
import {task} from 'ember-concurrency';
|
||||
|
||||
export default ModalComponent.extend(ValidationEngine, {
|
||||
config: service(),
|
||||
notifications: service(),
|
||||
session: service(),
|
||||
|
||||
@ -15,6 +15,8 @@ export default ModalComponent.extend(ValidationEngine, {
|
||||
|
||||
authenticationError: null,
|
||||
|
||||
config: inject(),
|
||||
|
||||
identification: reads('session.user.email'),
|
||||
|
||||
actions: {
|
||||
|
@ -5,6 +5,7 @@ import {action} from '@ember/object';
|
||||
import {currencies, getCurrencyOptions, getSymbol} from 'ghost-admin/utils/currency';
|
||||
import {A as emberA} from '@ember/array';
|
||||
import {htmlSafe} from '@ember/template';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {inject as service} from '@ember/service';
|
||||
import {task} from 'ember-concurrency';
|
||||
import {tracked} from '@glimmer/tracking';
|
||||
@ -22,8 +23,10 @@ const CURRENCIES = currencies.map((currency) => {
|
||||
export default class ModalTierPrice extends ModalBase {
|
||||
@service feature;
|
||||
@service settings;
|
||||
@service config;
|
||||
@service membersUtils;
|
||||
|
||||
@inject config;
|
||||
|
||||
@tracked model;
|
||||
@tracked tier;
|
||||
@tracked periodVal;
|
||||
|
@ -1,5 +1,6 @@
|
||||
import Component from '@glimmer/component';
|
||||
import {action} from '@ember/object';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {inject as service} from '@ember/service';
|
||||
import {timeout} from 'ember-concurrency';
|
||||
import {tracked} from '@glimmer/tracking';
|
||||
@ -17,11 +18,12 @@ html {
|
||||
|
||||
export default class EmailPreviewModal extends Component {
|
||||
@service ajax;
|
||||
@service config;
|
||||
@service ghostPaths;
|
||||
@service settings;
|
||||
@service store;
|
||||
|
||||
@inject config;
|
||||
|
||||
static modalOptions = {
|
||||
className: 'fullscreen-modal-full-overlay fullscreen-modal-email-preview'
|
||||
};
|
||||
|
@ -1,11 +1,11 @@
|
||||
import Component from '@glimmer/component';
|
||||
import config from 'ghost-admin/config/environment';
|
||||
import copyTextToClipboard from 'ghost-admin/utils/copy-text-to-clipboard';
|
||||
import {inject as service} from '@ember/service';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {task, timeout} from 'ember-concurrency';
|
||||
|
||||
export default class LinkOfferModal extends Component {
|
||||
@service config;
|
||||
@inject config;
|
||||
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
|
@ -1,11 +1,13 @@
|
||||
import Component from '@glimmer/component';
|
||||
import config from 'ghost-admin/config/environment';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {inject as service} from '@ember/service';
|
||||
|
||||
export default class AboutModal extends Component {
|
||||
@service config;
|
||||
@service upgradeStatus;
|
||||
|
||||
@inject config;
|
||||
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
if (this.isTesting === undefined) {
|
||||
|
@ -3,7 +3,6 @@ import {action} from '@ember/object';
|
||||
import {inject as service} from '@ember/service';
|
||||
|
||||
export default class Analytics extends Component {
|
||||
@service config;
|
||||
@service settings;
|
||||
@service feature;
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
import Component from '@glimmer/component';
|
||||
import {action} from '@ember/object';
|
||||
import {currencies} from 'ghost-admin/utils/currency';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {inject as service} from '@ember/service';
|
||||
import {task, timeout} from 'ember-concurrency';
|
||||
import {tracked} from '@glimmer/tracking';
|
||||
@ -11,13 +12,14 @@ const RETRY_PRODUCT_SAVE_MAX_POLL = 15 * RETRY_PRODUCT_SAVE_POLL_LENGTH;
|
||||
const NO_OF_TOP_CURRENCIES = 5;
|
||||
|
||||
export default class StripeSettingsForm extends Component {
|
||||
@service config;
|
||||
@service ghostPaths;
|
||||
@service ajax;
|
||||
@service settings;
|
||||
@service membersUtils;
|
||||
@service store;
|
||||
|
||||
@inject config;
|
||||
|
||||
@tracked hasActiveStripeSubscriptions = false;
|
||||
@tracked showDisconnectStripeConnectModal = false;
|
||||
@tracked stripeConnectError = null;
|
||||
|
@ -1,5 +1,6 @@
|
||||
import Component from '@glimmer/component';
|
||||
import {action} from '@ember/object';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {inject as service} from '@ember/service';
|
||||
import {tracked} from '@glimmer/tracking';
|
||||
|
||||
@ -7,10 +8,11 @@ const US = {flag: '🇺🇸', name: 'US', baseUrl: 'https://api.mailgun.net/v3'}
|
||||
const EU = {flag: '🇪🇺', name: 'EU', baseUrl: 'https://api.eu.mailgun.net/v3'};
|
||||
|
||||
export default class Newsletters extends Component {
|
||||
@service config;
|
||||
@service settings;
|
||||
@service feature;
|
||||
|
||||
@inject config;
|
||||
|
||||
// set recipientsSelectValue as a static property because within this
|
||||
// component's lifecycle it's not always derived from the settings values.
|
||||
// e.g. can be set to "segment" when the filter is empty which is not derivable
|
||||
|
@ -2,6 +2,7 @@ import Component from '@glimmer/component';
|
||||
import Ember from 'ember';
|
||||
import {action} from '@ember/object';
|
||||
import {htmlSafe} from '@ember/template';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {run} from '@ember/runloop';
|
||||
import {inject as service} from '@ember/service';
|
||||
import {slugify} from '@tryghost/string';
|
||||
@ -12,9 +13,10 @@ const {Handlebars} = Ember;
|
||||
|
||||
export default class TagForm extends Component {
|
||||
@service feature;
|
||||
@service config;
|
||||
@service settings;
|
||||
|
||||
@inject config;
|
||||
|
||||
@tracked metadataOpen = false;
|
||||
@tracked twitterMetadataOpen = false;
|
||||
@tracked facebookMetadataOpen = false;
|
||||
|
@ -1,15 +1,17 @@
|
||||
import Controller from '@ember/controller';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {inject as service} from '@ember/service';
|
||||
|
||||
export default class ApplicationController extends Controller {
|
||||
@service billing;
|
||||
@service explore;
|
||||
@service config;
|
||||
@service router;
|
||||
@service session;
|
||||
@service settings;
|
||||
@service ui;
|
||||
|
||||
@inject config;
|
||||
|
||||
get showBilling() {
|
||||
return this.config.hostSettings?.billing?.enabled;
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ import {alias, mapBy} from '@ember/object/computed';
|
||||
import {capitalize} from '@ember/string';
|
||||
import {dropTask, enqueueTask, restartableTask, task, taskGroup, timeout} from 'ember-concurrency';
|
||||
import {htmlSafe} from '@ember/template';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {isBlank} from '@ember/utils';
|
||||
import {isArray as isEmberArray} from '@ember/array';
|
||||
import {isHostLimitError, isServerUnreachableError, isVersionMismatchError} from 'ghost-admin/services/ajax';
|
||||
@ -94,7 +95,6 @@ const messageMap = {
|
||||
export default class EditorController extends Controller {
|
||||
@controller application;
|
||||
|
||||
@service config;
|
||||
@service feature;
|
||||
@service membersCountCache;
|
||||
@service modals;
|
||||
@ -105,6 +105,8 @@ export default class EditorController extends Controller {
|
||||
@service settings;
|
||||
@service ui;
|
||||
|
||||
@inject config;
|
||||
|
||||
/* public properties -----------------------------------------------------*/
|
||||
|
||||
shouldFocusTitle = false;
|
||||
|
@ -13,6 +13,7 @@ import {alias, mapBy} from '@ember/object/computed';
|
||||
import {capitalize} from '@ember/string';
|
||||
import {dropTask, enqueueTask, restartableTask, task, taskGroup, timeout} from 'ember-concurrency';
|
||||
import {htmlSafe} from '@ember/template';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {isBlank} from '@ember/utils';
|
||||
import {isArray as isEmberArray} from '@ember/array';
|
||||
import {isHostLimitError, isServerUnreachableError, isVersionMismatchError} from 'ghost-admin/services/ajax';
|
||||
@ -94,7 +95,6 @@ const messageMap = {
|
||||
export default class LexicalEditorController extends Controller {
|
||||
@controller application;
|
||||
|
||||
@service config;
|
||||
@service feature;
|
||||
@service membersCountCache;
|
||||
@service modals;
|
||||
@ -105,6 +105,8 @@ export default class LexicalEditorController extends Controller {
|
||||
@service settings;
|
||||
@service ui;
|
||||
|
||||
@inject config;
|
||||
|
||||
/* public properties -----------------------------------------------------*/
|
||||
|
||||
shouldFocusTitle = false;
|
||||
|
@ -8,6 +8,7 @@ import moment from 'moment-timezone';
|
||||
import {A} from '@ember/array';
|
||||
import {action} from '@ember/object';
|
||||
import {ghPluralize} from 'ghost-admin/helpers/gh-pluralize';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {resetQueryParams} from 'ghost-admin/helpers/reset-query-params';
|
||||
import {inject as service} from '@ember/service';
|
||||
import {task, timeout} from 'ember-concurrency';
|
||||
@ -26,7 +27,6 @@ const PAID_PARAMS = [{
|
||||
|
||||
export default class MembersController extends Controller {
|
||||
@service ajax;
|
||||
@service config;
|
||||
@service ellaSparse;
|
||||
@service feature;
|
||||
@service ghostPaths;
|
||||
@ -37,6 +37,8 @@ export default class MembersController extends Controller {
|
||||
@service utils;
|
||||
@service settings;
|
||||
|
||||
@inject config;
|
||||
|
||||
queryParams = [
|
||||
'label',
|
||||
{paidParam: 'paid'},
|
||||
|
@ -5,6 +5,7 @@ import config from 'ghost-admin/config/environment';
|
||||
import copyTextToClipboard from 'ghost-admin/utils/copy-text-to-clipboard';
|
||||
import {action} from '@ember/object';
|
||||
import {getSymbol} from 'ghost-admin/utils/currency';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {inject as service} from '@ember/service';
|
||||
import {slugify} from '@tryghost/string';
|
||||
import {task} from 'ember-concurrency';
|
||||
@ -13,7 +14,7 @@ import {tracked} from '@glimmer/tracking';
|
||||
|
||||
export default class OffersController extends Controller {
|
||||
@controller offers;
|
||||
@service config;
|
||||
|
||||
@service settings;
|
||||
@service store;
|
||||
@service modals;
|
||||
@ -21,6 +22,8 @@ export default class OffersController extends Controller {
|
||||
@service membersUtils;
|
||||
@service notifications;
|
||||
|
||||
@inject config;
|
||||
|
||||
@tracked cadences = [];
|
||||
@tracked tiers = [];
|
||||
@tracked portalPreviewUrl = '';
|
||||
|
@ -1,11 +1,14 @@
|
||||
import Controller, {inject as controller} from '@ember/controller';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {inject as service} from '@ember/service';
|
||||
|
||||
export default class PostsLoadingController extends Controller {
|
||||
@controller('posts') postsController;
|
||||
|
||||
@service session;
|
||||
@service ui;
|
||||
@service config;
|
||||
|
||||
@inject config;
|
||||
|
||||
get availableTypes() {
|
||||
return this.postsController.availableTypes;
|
||||
|
@ -1,6 +1,7 @@
|
||||
import Controller from '@ember/controller';
|
||||
import {DEFAULT_QUERY_PARAMS} from 'ghost-admin/helpers/reset-query-params';
|
||||
import {action} from '@ember/object';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {inject as service} from '@ember/service';
|
||||
import {tracked} from '@glimmer/tracking';
|
||||
|
||||
@ -47,12 +48,13 @@ const ORDERS = [{
|
||||
}];
|
||||
|
||||
export default class PostsController extends Controller {
|
||||
@service config;
|
||||
@service feature;
|
||||
@service router;
|
||||
@service session;
|
||||
@service store;
|
||||
|
||||
@inject config;
|
||||
|
||||
// default values for these are set in constructor and defined in `helpers/reset-query-params`
|
||||
queryParams = ['type', 'visibility', 'author', 'tag', 'order'];
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
import Controller from '@ember/controller';
|
||||
import ValidationEngine from 'ghost-admin/mixins/validation-engine';
|
||||
import {action} from '@ember/object';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {inject as service} from '@ember/service';
|
||||
import {task} from 'ember-concurrency';
|
||||
import {tracked} from '@glimmer/tracking';
|
||||
@ -11,7 +12,8 @@ export default class ResetController extends Controller.extend(ValidationEngine)
|
||||
@service notifications;
|
||||
@service session;
|
||||
@service ajax;
|
||||
@service config;
|
||||
|
||||
@inject config;
|
||||
|
||||
@tracked newPassword = '';
|
||||
@tracked ne2Password = '';
|
||||
|
@ -1,16 +1,18 @@
|
||||
import Controller from '@ember/controller';
|
||||
import {action} from '@ember/object';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {inject as service} from '@ember/service';
|
||||
import {task} from 'ember-concurrency';
|
||||
import {tracked} from '@glimmer/tracking';
|
||||
|
||||
export default class SettingsDesignIndexController extends Controller {
|
||||
@service config;
|
||||
@service customThemeSettings;
|
||||
@service notifications;
|
||||
@service settings;
|
||||
@service themeManagement;
|
||||
|
||||
@inject config;
|
||||
|
||||
@tracked previewSize = 'desktop';
|
||||
|
||||
get isDesktopPreview() {
|
||||
|
@ -9,6 +9,7 @@ import {
|
||||
IMAGE_MIME_TYPES
|
||||
} from 'ghost-admin/components/gh-image-uploader';
|
||||
import {TrackedObject} from 'tracked-built-ins';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {run} from '@ember/runloop';
|
||||
import {task} from 'ember-concurrency';
|
||||
import {tracked} from '@glimmer/tracking';
|
||||
@ -22,7 +23,6 @@ function randomPassword() {
|
||||
|
||||
@classic
|
||||
export default class GeneralController extends Controller {
|
||||
@service config;
|
||||
@service ghostPaths;
|
||||
@service notifications;
|
||||
@service session;
|
||||
@ -30,12 +30,17 @@ export default class GeneralController extends Controller {
|
||||
@service frontend;
|
||||
@service ui;
|
||||
|
||||
@inject config;
|
||||
|
||||
@tracked scratchValues = new TrackedObject();
|
||||
|
||||
availableTimezones = this.config.availableTimezones;
|
||||
imageExtensions = IMAGE_EXTENSIONS;
|
||||
imageMimeTypes = IMAGE_MIME_TYPES;
|
||||
|
||||
get availableTimezones() {
|
||||
return this.config.availableTimezones;
|
||||
}
|
||||
|
||||
@computed('config.blogUrl', 'settings.publicHash')
|
||||
get privateRSSUrl() {
|
||||
let blogUrl = this.config.blogUrl;
|
||||
@ -127,7 +132,6 @@ export default class GeneralController extends Controller {
|
||||
@task
|
||||
*saveTask() {
|
||||
let notifications = this.notifications;
|
||||
let config = this.config;
|
||||
|
||||
try {
|
||||
let changedAttrs = this.settings.changedAttributes();
|
||||
@ -135,7 +139,7 @@ export default class GeneralController extends Controller {
|
||||
|
||||
this.clearScratchValues();
|
||||
|
||||
config.set('blogTitle', settings.title);
|
||||
this.config.blogTitle = settings.title;
|
||||
|
||||
if (changedAttrs.password) {
|
||||
this.frontend.loginIfNeeded();
|
||||
|
@ -9,15 +9,17 @@ import {
|
||||
} from 'ghost-admin/components/gh-image-uploader';
|
||||
import {action} from '@ember/object';
|
||||
import {htmlSafe} from '@ember/template';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {inject as service} from '@ember/service';
|
||||
import {task, timeout} from 'ember-concurrency';
|
||||
import {tracked} from '@glimmer/tracking';
|
||||
|
||||
export default class IntegrationController extends Controller {
|
||||
@service config;
|
||||
@service ghostPaths;
|
||||
@service modals;
|
||||
|
||||
@inject config;
|
||||
|
||||
imageExtensions = IMAGE_EXTENSIONS;
|
||||
imageMimeTypes = IMAGE_MIME_TYPES;
|
||||
|
||||
|
@ -1,11 +1,13 @@
|
||||
import Controller from '@ember/controller';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {inject as service} from '@ember/service';
|
||||
import {task} from 'ember-concurrency';
|
||||
|
||||
export default class IntegrationsController extends Controller {
|
||||
@service settings;
|
||||
@service store;
|
||||
@service config;
|
||||
|
||||
@inject config;
|
||||
|
||||
_allIntegrations = this.store.peekAll('integration');
|
||||
|
||||
|
@ -11,6 +11,7 @@ import {
|
||||
isUnsupportedMediaTypeError
|
||||
} from 'ghost-admin/services/ajax';
|
||||
import {action} from '@ember/object';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {isBlank} from '@ember/utils';
|
||||
import {isArray as isEmberArray} from '@ember/array';
|
||||
import {run} from '@ember/runloop';
|
||||
@ -38,7 +39,6 @@ const YAML_MIME_TYPE = [
|
||||
@classic
|
||||
export default class LabsController extends Controller {
|
||||
@service ajax;
|
||||
@service config;
|
||||
@service feature;
|
||||
@service ghostPaths;
|
||||
@service modals;
|
||||
@ -47,6 +47,8 @@ export default class LabsController extends Controller {
|
||||
@service settings;
|
||||
@service utils;
|
||||
|
||||
@inject config;
|
||||
|
||||
importErrors = null;
|
||||
importSuccessful = false;
|
||||
showEarlyAccessModal = false;
|
||||
@ -119,7 +121,7 @@ export default class LabsController extends Controller {
|
||||
// reload settings
|
||||
return this.settings.reload().then((settings) => {
|
||||
this.feature.fetch();
|
||||
this.config.set('blogTitle', settings.title);
|
||||
this.config.blogTitle = settings.title;
|
||||
});
|
||||
});
|
||||
}).catch((response) => {
|
||||
|
@ -3,6 +3,7 @@ import Controller from '@ember/controller';
|
||||
import envConfig from 'ghost-admin/config/environment';
|
||||
import {action} from '@ember/object';
|
||||
import {currencies, getCurrencyOptions, getSymbol} from 'ghost-admin/utils/currency';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {inject as service} from '@ember/service';
|
||||
import {task} from 'ember-concurrency';
|
||||
import {tracked} from '@glimmer/tracking';
|
||||
@ -16,7 +17,6 @@ const CURRENCIES = currencies.map((currency) => {
|
||||
});
|
||||
|
||||
export default class MembersAccessController extends Controller {
|
||||
@service config;
|
||||
@service feature;
|
||||
@service membersUtils;
|
||||
@service modals;
|
||||
@ -24,6 +24,8 @@ export default class MembersAccessController extends Controller {
|
||||
@service store;
|
||||
@service session;
|
||||
|
||||
@inject config;
|
||||
|
||||
@tracked showPortalSettings = false;
|
||||
@tracked showStripeConnect = false;
|
||||
@tracked showTierModal = false;
|
||||
|
@ -2,17 +2,19 @@ import Controller from '@ember/controller';
|
||||
import NavigationItem from 'ghost-admin/models/navigation-item';
|
||||
import RSVP from 'rsvp';
|
||||
import {action} from '@ember/object';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {inject as service} from '@ember/service';
|
||||
import {task} from 'ember-concurrency';
|
||||
import {tracked} from '@glimmer/tracking';
|
||||
|
||||
export default class NavigationController extends Controller {
|
||||
@service config;
|
||||
@service ghostPaths;
|
||||
@service notifications;
|
||||
@service session;
|
||||
@service settings;
|
||||
|
||||
@inject config;
|
||||
|
||||
@tracked dirtyAttributes = false;
|
||||
@tracked newNavItem = NavigationItem.create({isNew: true});
|
||||
@tracked newSecondaryNavItem = NavigationItem.create({isNew: true, isSecondary: true});
|
||||
|
@ -11,6 +11,7 @@ import isNumber from 'ghost-admin/utils/isNumber';
|
||||
import windowProxy from 'ghost-admin/utils/window-proxy';
|
||||
import {TrackedObject} from 'tracked-built-ins';
|
||||
import {action} from '@ember/object';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {run} from '@ember/runloop';
|
||||
import {inject as service} from '@ember/service';
|
||||
import {task, taskGroup, timeout} from 'ember-concurrency';
|
||||
@ -18,7 +19,6 @@ import {tracked} from '@glimmer/tracking';
|
||||
|
||||
export default class UserController extends Controller {
|
||||
@service ajax;
|
||||
@service config;
|
||||
@service ghostPaths;
|
||||
@service membersUtils;
|
||||
@service modals;
|
||||
@ -27,6 +27,8 @@ export default class UserController extends Controller {
|
||||
@service slugGenerator;
|
||||
@service utils;
|
||||
|
||||
@inject config;
|
||||
|
||||
@tracked dirtyAttributes = false;
|
||||
@tracked personalToken = null;
|
||||
@tracked personalTokenRegenerated = false;
|
||||
|
@ -1,23 +1,24 @@
|
||||
import Controller from '@ember/controller';
|
||||
import EmberObject, {action} from '@ember/object';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {inject as service} from '@ember/service';
|
||||
import {task} from 'ember-concurrency';
|
||||
import {tracked} from '@glimmer/tracking';
|
||||
|
||||
export default class TierController extends Controller {
|
||||
@service config;
|
||||
@service membersUtils;
|
||||
@service settings;
|
||||
|
||||
@inject config;
|
||||
|
||||
@tracked showLeaveSettingsModal = false;
|
||||
@tracked showPriceModal = false;
|
||||
@tracked priceModel = null;
|
||||
@tracked showUnsavedChangesModal = false;
|
||||
@tracked paidSignupRedirect;
|
||||
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
this.siteUrl = this.config.blogUrl;
|
||||
get siteUrl() {
|
||||
return this.config.blogUrl;
|
||||
}
|
||||
|
||||
get tier() {
|
||||
|
@ -1,12 +1,14 @@
|
||||
import Controller from '@ember/controller';
|
||||
import {action} from '@ember/object';
|
||||
import {htmlSafe} from '@ember/template';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {inject as service} from '@ember/service';
|
||||
import {tracked} from '@glimmer/tracking';
|
||||
|
||||
export default class TiersController extends Controller {
|
||||
@service settings;
|
||||
@service config;
|
||||
|
||||
@inject config;
|
||||
|
||||
@tracked iconStyle = '';
|
||||
@tracked showFreeMembershipModal = false;
|
||||
|
@ -5,6 +5,7 @@ import Controller, {inject as controller} from '@ember/controller';
|
||||
import ValidationEngine from 'ghost-admin/mixins/validation-engine';
|
||||
import {action} from '@ember/object';
|
||||
import {htmlSafe} from '@ember/template';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {isInvalidError} from 'ember-ajax/errors';
|
||||
import {isVersionMismatchError} from 'ghost-admin/services/ajax';
|
||||
import {task} from 'ember-concurrency';
|
||||
@ -14,12 +15,13 @@ export default class SetupController extends Controller.extend(ValidationEngine)
|
||||
@controller application;
|
||||
|
||||
@service ajax;
|
||||
@service config;
|
||||
@service ghostPaths;
|
||||
@service notifications;
|
||||
@service router;
|
||||
@service session;
|
||||
|
||||
@inject config;
|
||||
|
||||
// ValidationEngine settings
|
||||
validationType = 'setup';
|
||||
|
||||
@ -82,7 +84,6 @@ export default class SetupController extends Controller.extend(ValidationEngine)
|
||||
_passwordSetup() {
|
||||
let setupProperties = ['blogTitle', 'name', 'email', 'password'];
|
||||
let data = this.getProperties(setupProperties);
|
||||
let config = this.config;
|
||||
let method = this.blogCreated ? 'put' : 'post';
|
||||
|
||||
this.set('flowErrors', '');
|
||||
@ -102,7 +103,7 @@ export default class SetupController extends Controller.extend(ValidationEngine)
|
||||
}]
|
||||
}
|
||||
}).then((result) => {
|
||||
config.set('blogTitle', data.blogTitle);
|
||||
this.config.blogTitle = data.blogTitle;
|
||||
|
||||
// don't try to login again if we are already logged in
|
||||
if (this.get('session.isAuthenticated')) {
|
||||
|
@ -5,6 +5,7 @@ import Controller, {inject as controller} from '@ember/controller';
|
||||
import ValidationEngine from 'ghost-admin/mixins/validation-engine';
|
||||
import {action} from '@ember/object';
|
||||
import {htmlSafe} from '@ember/template';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {isArray as isEmberArray} from '@ember/array';
|
||||
import {isVersionMismatchError} from 'ghost-admin/services/ajax';
|
||||
import {inject as service} from '@ember/service';
|
||||
@ -15,12 +16,13 @@ export default class SigninController extends Controller.extend(ValidationEngine
|
||||
@controller application;
|
||||
|
||||
@service ajax;
|
||||
@service config;
|
||||
@service ghostPaths;
|
||||
@service notifications;
|
||||
@service session;
|
||||
@service settings;
|
||||
|
||||
@inject config;
|
||||
|
||||
@tracked submitting = false;
|
||||
@tracked loggingIn = false;
|
||||
@tracked flowErrors = '';
|
||||
|
@ -1,5 +1,6 @@
|
||||
import Controller from '@ember/controller';
|
||||
import {action} from '@ember/object';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {isArray as isEmberArray} from '@ember/array';
|
||||
import {isVersionMismatchError} from 'ghost-admin/services/ajax';
|
||||
import {inject as service} from '@ember/service';
|
||||
@ -8,12 +9,13 @@ import {tracked} from '@glimmer/tracking';
|
||||
|
||||
export default class SignupController extends Controller {
|
||||
@service ajax;
|
||||
@service config;
|
||||
@service ghostPaths;
|
||||
@service notifications;
|
||||
@service session;
|
||||
@service settings;
|
||||
|
||||
@inject config;
|
||||
|
||||
@tracked flowErrors = '';
|
||||
|
||||
get signupDetails() {
|
||||
|
48
ghost/admin/app/decorators/inject.js
Normal file
48
ghost/admin/app/decorators/inject.js
Normal file
@ -0,0 +1,48 @@
|
||||
import {computed, defineProperty} from '@ember/object';
|
||||
import {getOwner} from '@ember/application';
|
||||
|
||||
function isElementDescriptor(args) {
|
||||
let [maybeTarget, maybeKey, maybeDesc] = args;
|
||||
|
||||
return (
|
||||
// Ensure we have the right number of args
|
||||
args.length === 3 &&
|
||||
// Make sure the target is a class or object (prototype)
|
||||
(typeof maybeTarget === 'function' ||
|
||||
(typeof maybeTarget === 'object' && maybeTarget !== null)) &&
|
||||
// Make sure the key is a string
|
||||
typeof maybeKey === 'string' &&
|
||||
// Make sure the descriptor is the right shape
|
||||
((typeof maybeDesc === 'object' && maybeDesc !== null) || maybeDesc === undefined)
|
||||
);
|
||||
}
|
||||
|
||||
export function inject(...args) {
|
||||
let elementDescriptor;
|
||||
let name;
|
||||
|
||||
if (isElementDescriptor(args)) {
|
||||
elementDescriptor = args;
|
||||
} else if (typeof args[0] === 'string') {
|
||||
name = args[0];
|
||||
}
|
||||
|
||||
const getInjection = function (propertyName) {
|
||||
const owner = getOwner(this) || this.container;
|
||||
return owner.lookup(`${name || propertyName}:main`);
|
||||
};
|
||||
|
||||
const decorator = computed({
|
||||
get: getInjection,
|
||||
set(keyName, value) {
|
||||
defineProperty(this, keyName, null, value);
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
if (elementDescriptor) {
|
||||
return decorator(elementDescriptor[0], elementDescriptor[1], elementDescriptor[2]);
|
||||
} else {
|
||||
return decorator;
|
||||
}
|
||||
}
|
@ -1,11 +1,9 @@
|
||||
import Helper from '@ember/component/helper';
|
||||
import classic from 'ember-classic-decorator';
|
||||
import {htmlSafe} from '@ember/template';
|
||||
import {inject as service} from '@ember/service';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
|
||||
@classic
|
||||
export default class AccentColorBackgroundHelper extends Helper {
|
||||
@service config;
|
||||
@inject config;
|
||||
|
||||
compute() {
|
||||
const color = this.config.accent_color;
|
||||
|
@ -1,8 +1,8 @@
|
||||
import Helper from '@ember/component/helper';
|
||||
import {inject as service} from '@ember/service';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
|
||||
export default class EnableDeveloperExperimentsHelper extends Helper {
|
||||
@service config;
|
||||
@inject config;
|
||||
|
||||
compute() {
|
||||
return this.config.enableDeveloperExperiments;
|
||||
|
@ -1,8 +1,8 @@
|
||||
import Helper from '@ember/component/helper';
|
||||
import {inject as service} from '@ember/service';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
|
||||
export default class FullEmailAddressHelper extends Helper {
|
||||
@service config;
|
||||
@inject config;
|
||||
|
||||
compute([email = '']) {
|
||||
if (email.indexOf('@') > -1) {
|
||||
|
@ -1,15 +1,17 @@
|
||||
import PublishOptions from '../utils/publish-options';
|
||||
import {Resource} from 'ember-could-get-used-to-this';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {inject as service} from '@ember/service';
|
||||
import {tracked} from '@glimmer/tracking';
|
||||
|
||||
export default class PublishOptionsResource extends Resource {
|
||||
@service config;
|
||||
@service limit;
|
||||
@service session;
|
||||
@service settings;
|
||||
@service store;
|
||||
|
||||
@inject config;
|
||||
|
||||
@tracked publishOptions;
|
||||
|
||||
get value() {
|
||||
|
@ -1,11 +1,9 @@
|
||||
import Helper from '@ember/component/helper';
|
||||
import classic from 'ember-classic-decorator';
|
||||
import {htmlSafe} from '@ember/template';
|
||||
import {inject as service} from '@ember/service';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
|
||||
@classic
|
||||
export default class SiteIconStyleHelper extends Helper {
|
||||
@service config;
|
||||
@inject config;
|
||||
|
||||
compute() {
|
||||
const icon = this.config.icon || 'https://static.ghost.org/v4.0.0/images/ghost-orb-2.png';
|
||||
|
55
ghost/admin/app/instance-initializers/config.js
Normal file
55
ghost/admin/app/instance-initializers/config.js
Normal file
@ -0,0 +1,55 @@
|
||||
import timezoneData from '@tryghost/timezone-data';
|
||||
import {TrackedObject} from 'tracked-built-ins';
|
||||
|
||||
export function initialize(applicationInstance) {
|
||||
const config = new TrackedObject({});
|
||||
|
||||
Object.defineProperty(config, 'availableTimezones', {
|
||||
get() {
|
||||
return timezoneData;
|
||||
},
|
||||
enumerable: true
|
||||
});
|
||||
|
||||
Object.defineProperty(config, 'blogDomain', {
|
||||
get() {
|
||||
const blogDomain = this.blogUrl
|
||||
.replace(/^https?:\/\//, '')
|
||||
.replace(/\/?$/, '');
|
||||
|
||||
return blogDomain;
|
||||
},
|
||||
enumerable: true
|
||||
|
||||
});
|
||||
|
||||
Object.defineProperty(config, 'emailDomain', {
|
||||
get() {
|
||||
const blogDomain = this.blogDomain || '';
|
||||
const domainExp = blogDomain.match(new RegExp('^([^/:?#]+)(?:[/:?#]|$)', 'i'));
|
||||
const domain = (domainExp && domainExp[1]) || '';
|
||||
if (domain.startsWith('www.')) {
|
||||
return domain.replace(/^(www)\.(?=[^/]*\..{2,5})/, '');
|
||||
}
|
||||
return domain;
|
||||
},
|
||||
enumerable: true
|
||||
});
|
||||
|
||||
Object.defineProperty(config, 'getSiteUrl', {
|
||||
value: function (path) {
|
||||
const siteUrl = new URL(this.blogUrl);
|
||||
const subdir = siteUrl.pathname.endsWith('/') ? siteUrl.pathname : `${siteUrl.pathname}/`;
|
||||
const fullPath = `${subdir}${path.replace(/^\//, '')}`;
|
||||
|
||||
return `${siteUrl.origin}${fullPath}`;
|
||||
}
|
||||
});
|
||||
|
||||
applicationInstance.register('config:main', config, {instantiate: false});
|
||||
}
|
||||
|
||||
export default {
|
||||
name: 'config',
|
||||
initialize
|
||||
};
|
@ -7,6 +7,7 @@ import {BLANK_DOC as BLANK_MOBILEDOC} from 'koenig-editor/components/koenig-edit
|
||||
import {compare, isBlank} from '@ember/utils';
|
||||
import {computed, observer} from '@ember/object';
|
||||
import {equal, filterBy, reads} from '@ember/object/computed';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {on} from '@ember/object/evented';
|
||||
import {inject as service} from '@ember/service';
|
||||
|
||||
@ -67,7 +68,6 @@ function publishedAtCompare(postA, postB) {
|
||||
}
|
||||
|
||||
export default Model.extend(Comparable, ValidationEngine, {
|
||||
config: service(),
|
||||
session: service(),
|
||||
feature: service(),
|
||||
ghostPaths: service(),
|
||||
@ -75,6 +75,8 @@ export default Model.extend(Comparable, ValidationEngine, {
|
||||
settings: service(),
|
||||
membersUtils: service(),
|
||||
|
||||
config: inject(),
|
||||
|
||||
displayName: 'post',
|
||||
validationType: 'post',
|
||||
|
||||
|
@ -4,6 +4,7 @@ import ValidationEngine from 'ghost-admin/mixins/validation-engine';
|
||||
import {attr, hasMany} from '@ember-data/model';
|
||||
import {computed} from '@ember/object';
|
||||
import {equal, or} from '@ember/object/computed';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {inject as service} from '@ember/service';
|
||||
import {task} from 'ember-concurrency';
|
||||
|
||||
@ -44,7 +45,8 @@ export default BaseModel.extend(ValidationEngine, {
|
||||
ajax: service(),
|
||||
session: service(),
|
||||
notifications: service(),
|
||||
config: service(),
|
||||
|
||||
config: inject(),
|
||||
|
||||
// TODO: Once client-side permissions are in place,
|
||||
// remove the hard role check.
|
||||
|
@ -4,6 +4,7 @@ import ShortcutsRoute from 'ghost-admin/mixins/shortcuts-route';
|
||||
import ctrlOrCmd from 'ghost-admin/utils/ctrl-or-cmd';
|
||||
import windowProxy from 'ghost-admin/utils/window-proxy';
|
||||
import {InitSentryForEmber} from '@sentry/ember';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {
|
||||
isAjaxError,
|
||||
isNotFoundError,
|
||||
@ -27,7 +28,7 @@ shortcuts[`${ctrlOrCmd}+s`] = {action: 'save', scope: 'all'};
|
||||
|
||||
export default Route.extend(ShortcutsRoute, {
|
||||
ajax: service(),
|
||||
config: service(),
|
||||
configManager: service(),
|
||||
feature: service(),
|
||||
ghostPaths: service(),
|
||||
notifications: service(),
|
||||
@ -52,6 +53,8 @@ export default Route.extend(ShortcutsRoute, {
|
||||
this.ui.initBodyDragHandlers();
|
||||
},
|
||||
|
||||
config: inject(),
|
||||
|
||||
async beforeModel() {
|
||||
await this.session.setup();
|
||||
return this.prepareApp();
|
||||
@ -153,7 +156,7 @@ export default Route.extend(ShortcutsRoute, {
|
||||
},
|
||||
|
||||
async prepareApp() {
|
||||
await this.config.fetchUnauthenticated();
|
||||
await this.configManager.fetchUnauthenticated();
|
||||
|
||||
// init Sentry here rather than app.js so that we can use API-supplied
|
||||
// sentry_dsn and sentry_env rather than building it into release assets
|
||||
|
@ -1,10 +1,12 @@
|
||||
import Route from '@ember/routing/route';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {inject as service} from '@ember/service';
|
||||
|
||||
export default class DesignsandboxRoute extends Route {
|
||||
@service config;
|
||||
@service store;
|
||||
|
||||
@inject config;
|
||||
|
||||
beforeModel() {
|
||||
super.beforeModel(...arguments);
|
||||
if (!this.config.enableDeveloperExperiments) {
|
||||
|
@ -1,10 +1,13 @@
|
||||
import AuthenticatedRoute from 'ghost-admin/routes/authenticated';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {pluralize} from 'ember-inflector';
|
||||
import {inject as service} from '@ember/service';
|
||||
|
||||
export default class EditRoute extends AuthenticatedRoute {
|
||||
@service router;
|
||||
|
||||
@inject config;
|
||||
|
||||
beforeModel(transition) {
|
||||
super.beforeModel(...arguments);
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
import $ from 'jquery';
|
||||
import AuthenticatedRoute from 'ghost-admin/routes/authenticated';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {run} from '@ember/runloop';
|
||||
import {inject as service} from '@ember/service';
|
||||
|
||||
export default AuthenticatedRoute.extend({
|
||||
config: service(),
|
||||
feature: service(),
|
||||
notifications: service(),
|
||||
router: service(),
|
||||
@ -12,6 +12,8 @@ export default AuthenticatedRoute.extend({
|
||||
|
||||
classNames: ['editor'],
|
||||
|
||||
config: inject(),
|
||||
|
||||
beforeModel() {
|
||||
if (!this.config.editor?.url) {
|
||||
return this.router.transitionTo('posts');
|
||||
|
@ -1,11 +1,13 @@
|
||||
import AuthenticatedRoute from 'ghost-admin/routes/authenticated';
|
||||
import {action} from '@ember/object';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {inject as service} from '@ember/service';
|
||||
|
||||
export default class ProRoute extends AuthenticatedRoute {
|
||||
@service billing;
|
||||
@service session;
|
||||
@service config;
|
||||
|
||||
@inject config;
|
||||
|
||||
queryParams = {
|
||||
action: {refreshModel: true}
|
||||
|
@ -2,13 +2,15 @@ import AdminRoute from 'ghost-admin/routes/admin';
|
||||
import ConfirmUnsavedChangesModal from '../../components/modals/confirm-unsaved-changes';
|
||||
import RSVP from 'rsvp';
|
||||
import {action} from '@ember/object';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {inject as service} from '@ember/service';
|
||||
|
||||
export default class AnalyticsSettingsRoute extends AdminRoute {
|
||||
@service modals;
|
||||
@service config;
|
||||
@service settings;
|
||||
|
||||
@inject config;
|
||||
|
||||
model() {
|
||||
return RSVP.hash({
|
||||
settings: this.settings.reload()
|
||||
|
@ -2,13 +2,15 @@ import AdminRoute from 'ghost-admin/routes/admin';
|
||||
import ConfirmUnsavedChangesModal from '../../components/modals/confirm-unsaved-changes';
|
||||
import RSVP from 'rsvp';
|
||||
import {action} from '@ember/object';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {inject as service} from '@ember/service';
|
||||
|
||||
export default class GeneralSettingsRoute extends AdminRoute {
|
||||
@service modals;
|
||||
@service config;
|
||||
@service settings;
|
||||
|
||||
@inject config;
|
||||
|
||||
model() {
|
||||
return RSVP.hash({
|
||||
settings: this.settings.reload()
|
||||
|
@ -1,9 +1,11 @@
|
||||
import AdminRoute from 'ghost-admin/routes/admin';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {inject as service} from '@ember/service';
|
||||
|
||||
export default class ZapierRoute extends AdminRoute {
|
||||
@service router;
|
||||
@service config;
|
||||
|
||||
@inject config;
|
||||
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
|
@ -1,11 +1,13 @@
|
||||
import Route from '@ember/routing/route';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {inject as service} from '@ember/service';
|
||||
|
||||
export default class SetupRoute extends Route {
|
||||
@service ghostPaths;
|
||||
@service session;
|
||||
@service ajax;
|
||||
@service config;
|
||||
|
||||
@inject config;
|
||||
|
||||
// use the beforeModel hook to check to see whether or not setup has been
|
||||
// previously completed. If it has, stop the transition into the setup page.
|
||||
|
@ -2,6 +2,7 @@ import EmberObject from '@ember/object';
|
||||
import UnauthenticatedRoute from 'ghost-admin/routes/unauthenticated';
|
||||
import ValidationEngine from 'ghost-admin/mixins/validation-engine';
|
||||
import classic from 'ember-classic-decorator';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {inject as service} from '@ember/service';
|
||||
import {tracked} from '@glimmer/tracking';
|
||||
|
||||
@ -23,7 +24,8 @@ export default class SignupRoute extends UnauthenticatedRoute {
|
||||
@service notifications;
|
||||
@service session;
|
||||
@service ajax;
|
||||
@service config;
|
||||
|
||||
@inject config;
|
||||
|
||||
beforeModel() {
|
||||
if (this.session.isAuthenticated) {
|
||||
|
@ -1,13 +1,6 @@
|
||||
import AuthenticatedRoute from 'ghost-admin/routes/authenticated';
|
||||
import {inject as service} from '@ember/service';
|
||||
|
||||
export default class SiteRoute extends AuthenticatedRoute {
|
||||
@service config;
|
||||
@service settings;
|
||||
@service ui;
|
||||
|
||||
_hasLoggedIn = false;
|
||||
|
||||
model() {
|
||||
return (new Date()).valueOf();
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import moment from 'moment-timezone';
|
||||
import {AjaxError, isAjaxError, isForbiddenError} from 'ember-ajax/errors';
|
||||
import {captureMessage} from '@sentry/ember';
|
||||
import {get} from '@ember/object';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {isArray as isEmberArray} from '@ember/array';
|
||||
import {isNone} from '@ember/utils';
|
||||
import {inject as service} from '@ember/service';
|
||||
@ -163,9 +164,10 @@ export function isAcceptedResponse(errorOrStatus) {
|
||||
|
||||
@classic
|
||||
class ajaxService extends AjaxService {
|
||||
@service config;
|
||||
@service session;
|
||||
|
||||
@inject config;
|
||||
|
||||
// flag to tell our ESA authenticator not to try an invalidate DELETE request
|
||||
// because it's been triggered by this service's 401 handling which means the
|
||||
// DELETE would fail and get stuck in an infinite loop
|
||||
|
@ -1,14 +1,15 @@
|
||||
import Service, {inject as service} from '@ember/service';
|
||||
import classic from 'ember-classic-decorator';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
|
||||
@classic
|
||||
export default class BillingService extends Service {
|
||||
@service router;
|
||||
@service config;
|
||||
|
||||
@service ghostPaths;
|
||||
@service router;
|
||||
@service store;
|
||||
|
||||
@inject config;
|
||||
|
||||
billingRouteRoot = '#/pro';
|
||||
billingWindowOpen = false;
|
||||
subscription = null;
|
||||
|
44
ghost/admin/app/services/config-manager.js
Normal file
44
ghost/admin/app/services/config-manager.js
Normal file
@ -0,0 +1,44 @@
|
||||
import RSVP from 'rsvp';
|
||||
import Service, {inject as service} from '@ember/service';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {setProperties} from '@ember/object';
|
||||
|
||||
export default class ConfigManagerService extends Service {
|
||||
@service ajax;
|
||||
@service ghostPaths;
|
||||
@service session;
|
||||
|
||||
@inject config;
|
||||
|
||||
fetch() {
|
||||
let promises = [];
|
||||
|
||||
promises.push(this.fetchUnauthenticated());
|
||||
|
||||
if (this.session.isAuthenticated) {
|
||||
promises.push(this.fetchAuthenticated());
|
||||
}
|
||||
|
||||
return RSVP.all(promises);
|
||||
}
|
||||
|
||||
async fetchUnauthenticated() {
|
||||
const siteUrl = this.ghostPaths.url.api('site');
|
||||
const {site} = await this.ajax.request(siteUrl);
|
||||
|
||||
// normalize url to non-trailing-slash
|
||||
site.blogUrl = site.url.replace(/\/$/, '');
|
||||
site.blogTitle = site.title;
|
||||
delete site.url;
|
||||
delete site.title;
|
||||
|
||||
setProperties(this.config, site);
|
||||
}
|
||||
|
||||
async fetchAuthenticated() {
|
||||
const configUrl = this.ghostPaths.url.api('config');
|
||||
const {config} = await this.ajax.request(configUrl);
|
||||
|
||||
setProperties(this.config, config);
|
||||
}
|
||||
}
|
@ -1,90 +0,0 @@
|
||||
import RSVP from 'rsvp';
|
||||
import Service, {inject as service} from '@ember/service';
|
||||
import timezoneData from '@tryghost/timezone-data';
|
||||
import {TrackedObject} from 'tracked-built-ins';
|
||||
import {tracked} from '@glimmer/tracking';
|
||||
|
||||
export default class ConfigService extends Service {
|
||||
@service ajax;
|
||||
@service ghostPaths;
|
||||
@service session;
|
||||
|
||||
@tracked content = new TrackedObject();
|
||||
|
||||
availableTimezones = timezoneData;
|
||||
|
||||
fetch() {
|
||||
let promises = [];
|
||||
|
||||
promises.push(this.fetchUnauthenticated());
|
||||
|
||||
if (this.session.isAuthenticated) {
|
||||
promises.push(this.fetchAuthenticated());
|
||||
}
|
||||
|
||||
return RSVP.all(promises);
|
||||
}
|
||||
|
||||
async fetchUnauthenticated() {
|
||||
const siteUrl = this.ghostPaths.url.api('site');
|
||||
const {site} = await this.ajax.request(siteUrl);
|
||||
|
||||
// normalize url to non-trailing-slash
|
||||
site.blogUrl = site.url.replace(/\/$/, '');
|
||||
site.blogTitle = site.title;
|
||||
delete site.url;
|
||||
delete site.title;
|
||||
|
||||
Object.assign(this.content, site);
|
||||
this._defineProperties(site);
|
||||
}
|
||||
|
||||
async fetchAuthenticated() {
|
||||
const configUrl = this.ghostPaths.url.api('config');
|
||||
const {config} = await this.ajax.request(configUrl);
|
||||
|
||||
Object.assign(this.content, config);
|
||||
this._defineProperties(config);
|
||||
}
|
||||
|
||||
get blogDomain() {
|
||||
const blogDomain = this.blogUrl
|
||||
.replace(/^https?:\/\//, '')
|
||||
.replace(/\/?$/, '');
|
||||
|
||||
return blogDomain;
|
||||
}
|
||||
|
||||
get emailDomain() {
|
||||
const blogDomain = this.blogDomain || '';
|
||||
const domainExp = blogDomain.match(new RegExp('^([^/:?#]+)(?:[/:?#]|$)', 'i'));
|
||||
const domain = (domainExp && domainExp[1]) || '';
|
||||
if (domain.startsWith('www.')) {
|
||||
return domain.replace(/^(www)\.(?=[^/]*\..{2,5})/, '');
|
||||
}
|
||||
return domain;
|
||||
}
|
||||
|
||||
getSiteUrl(path) {
|
||||
const siteUrl = new URL(this.blogUrl);
|
||||
const subdir = siteUrl.pathname.endsWith('/') ? siteUrl.pathname : `${siteUrl.pathname}/`;
|
||||
const fullPath = `${subdir}${path.replace(/^\//, '')}`;
|
||||
|
||||
return `${siteUrl.origin}${fullPath}`;
|
||||
}
|
||||
|
||||
_defineProperties(obj) {
|
||||
for (const name of Object.keys(obj)) {
|
||||
if (!Object.prototype.hasOwnProperty.call(this, name)) {
|
||||
Object.defineProperty(this, name, {
|
||||
get() {
|
||||
return this.content[name];
|
||||
},
|
||||
set(newValue) {
|
||||
this.content[name] = newValue;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@ import EmberError from '@ember/error';
|
||||
import Service, {inject as service} from '@ember/service';
|
||||
import classic from 'ember-classic-decorator';
|
||||
import {computed, set} from '@ember/object';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
|
||||
export function feature(name, options = {}) {
|
||||
let {user, onChange} = options;
|
||||
@ -39,14 +40,13 @@ export function feature(name, options = {}) {
|
||||
|
||||
@classic
|
||||
export default class FeatureService extends Service {
|
||||
@service store;
|
||||
@service config;
|
||||
|
||||
@service lazyLoader;
|
||||
@service notifications;
|
||||
@service session;
|
||||
@service settings;
|
||||
@service store;
|
||||
|
||||
@service notifications;
|
||||
@service lazyLoader;
|
||||
@inject config;
|
||||
|
||||
// features
|
||||
@feature('emailAnalytics') emailAnalytics;
|
||||
|
@ -1,12 +1,14 @@
|
||||
import Service, {inject as service} from '@ember/service';
|
||||
import fetch from 'fetch';
|
||||
import validator from 'validator';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
|
||||
export default class FrontendService extends Service {
|
||||
@service settings;
|
||||
@service config;
|
||||
@service ajax;
|
||||
|
||||
@inject config;
|
||||
|
||||
_hasLoggedIn = false;
|
||||
_lastPassword = null;
|
||||
|
||||
|
@ -2,6 +2,7 @@ import LimitService from '@tryghost/limit-service';
|
||||
import RSVP from 'rsvp';
|
||||
import Service, {inject as service} from '@ember/service';
|
||||
import {bind} from '@ember/runloop';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
|
||||
class LimitError {
|
||||
constructor({errorType, errorDetails, message}) {
|
||||
@ -24,10 +25,11 @@ class HostLimitError extends LimitError {
|
||||
}
|
||||
|
||||
export default class LimitsService extends Service {
|
||||
@service config;
|
||||
@service store;
|
||||
@service membersStats;
|
||||
|
||||
@inject config;
|
||||
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
|
||||
@ -41,9 +43,7 @@ export default class LimitsService extends Service {
|
||||
|
||||
let helpLink;
|
||||
|
||||
if (this.config.hostSettings?.billing?.enabled === true
|
||||
&& this.config.hostSettings?.billing?.url
|
||||
) {
|
||||
if (this.config.hostSettings?.billing?.enabled === true && this.config.hostSettings?.billing?.url) {
|
||||
helpLink = this.config.hostSettings.billing?.url;
|
||||
} else {
|
||||
helpLink = 'https://ghost.org/help/';
|
||||
|
@ -1,12 +1,14 @@
|
||||
import Service, {inject as service} from '@ember/service';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
|
||||
export default class MembersUtilsService extends Service {
|
||||
@service config;
|
||||
@service settings;
|
||||
@service feature;
|
||||
@service session;
|
||||
@service store;
|
||||
|
||||
@inject config;
|
||||
|
||||
paidTiers = null;
|
||||
|
||||
get isMembersEnabled() {
|
||||
|
@ -3,6 +3,7 @@ import Service, {inject as service} from '@ember/service';
|
||||
import {TrackedArray} from 'tracked-built-ins';
|
||||
import {dasherize} from '@ember/string';
|
||||
import {htmlSafe} from '@ember/template';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {isArray} from '@ember/array';
|
||||
import {isBlank} from '@ember/utils';
|
||||
import {
|
||||
@ -38,9 +39,10 @@ const GENERIC_ERROR_NAMES = [
|
||||
export const GENERIC_ERROR_MESSAGE = 'An unexpected error occurred, please try again.';
|
||||
|
||||
export default class NotificationsService extends Service {
|
||||
@service config;
|
||||
@service upgradeStatus;
|
||||
|
||||
@inject config;
|
||||
|
||||
@tracked delayedNotifications = new TrackedArray([]);
|
||||
@tracked content = new TrackedArray([]);
|
||||
|
||||
|
@ -2,13 +2,14 @@ import ESASessionService from 'ember-simple-auth/services/session';
|
||||
import RSVP from 'rsvp';
|
||||
import {configureScope} from '@sentry/ember';
|
||||
import {getOwner} from '@ember/application';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {run} from '@ember/runloop';
|
||||
import {inject as service} from '@ember/service';
|
||||
import {task} from 'ember-concurrency';
|
||||
import {tracked} from '@glimmer/tracking';
|
||||
|
||||
export default class SessionService extends ESASessionService {
|
||||
@service config;
|
||||
@service configManager;
|
||||
@service('store') dataStore;
|
||||
@service feature;
|
||||
@service notifications;
|
||||
@ -20,6 +21,8 @@ export default class SessionService extends ESASessionService {
|
||||
@service whatsNew;
|
||||
@service membersUtils;
|
||||
|
||||
@inject config;
|
||||
|
||||
@tracked user = null;
|
||||
|
||||
skipAuthSuccessHandler = false;
|
||||
@ -36,7 +39,7 @@ export default class SessionService extends ESASessionService {
|
||||
|
||||
async postAuthPreparation() {
|
||||
await RSVP.all([
|
||||
this.config.fetchAuthenticated(),
|
||||
this.configManager.fetchAuthenticated(),
|
||||
this.feature.fetch(),
|
||||
this.settings.fetch(),
|
||||
this.membersUtils.fetch()
|
||||
@ -112,7 +115,7 @@ export default class SessionService extends ESASessionService {
|
||||
|
||||
// TODO: this feels hacky, find a better way than using .send
|
||||
triggerAuthorizationFailed() {
|
||||
getOwner(this).lookup(`route:${this.router.currentRouteName}`).send('authorizationFailed');
|
||||
getOwner(this).lookup(`route:${this.router.currentRouteName}`)?.send('authorizationFailed');
|
||||
}
|
||||
|
||||
loadServerNotifications() {
|
||||
|
@ -1,7 +1,8 @@
|
||||
import Service, {inject as service} from '@ember/service';
|
||||
import Service from '@ember/service';
|
||||
import fetch from 'fetch';
|
||||
import {TrackedArray} from 'tracked-built-ins';
|
||||
import {action} from '@ember/object';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {isEmpty} from '@ember/utils';
|
||||
import {task, taskGroup, timeout} from 'ember-concurrency';
|
||||
import {tracked} from '@glimmer/tracking';
|
||||
@ -11,7 +12,7 @@ const API_VERSION = 'v2';
|
||||
const DEBOUNCE_MS = 600;
|
||||
|
||||
export default class TenorService extends Service {
|
||||
@service config;
|
||||
@inject config;
|
||||
|
||||
@tracked columnCount = 4;
|
||||
@tracked columns = null;
|
||||
|
@ -1,6 +1,7 @@
|
||||
import Service, {inject as service} from '@ember/service';
|
||||
import config from 'ghost-admin/config/environment';
|
||||
import {action} from '@ember/object';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {isEmpty} from '@ember/utils';
|
||||
import {isThemeValidationError} from 'ghost-admin/services/ajax';
|
||||
import {task} from 'ember-concurrency';
|
||||
@ -8,7 +9,6 @@ import {tracked} from '@glimmer/tracking';
|
||||
|
||||
export default class ThemeManagementService extends Service {
|
||||
@service ajax;
|
||||
@service config;
|
||||
@service customThemeSettings;
|
||||
@service limit;
|
||||
@service modals;
|
||||
@ -16,6 +16,8 @@ export default class ThemeManagementService extends Service {
|
||||
@service store;
|
||||
@service frontend;
|
||||
|
||||
@inject config;
|
||||
|
||||
@tracked isUploading;
|
||||
@tracked previewType = 'homepage';
|
||||
@tracked previewHtml;
|
||||
|
@ -5,6 +5,7 @@ import {
|
||||
lightenToContrastThreshold
|
||||
} from '@tryghost/color-utils';
|
||||
import {action, get} from '@ember/object';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {isEmpty} from '@ember/utils';
|
||||
import {tracked} from '@glimmer/tracking';
|
||||
|
||||
@ -39,13 +40,14 @@ function updateBodyClasses(transition) {
|
||||
}
|
||||
|
||||
export default class UiService extends Service {
|
||||
@service config;
|
||||
@service dropdown;
|
||||
@service feature;
|
||||
@service mediaQueries;
|
||||
@service router;
|
||||
@service settings;
|
||||
|
||||
@inject config;
|
||||
|
||||
@tracked contextualNavMenu = null;
|
||||
@tracked isFullScreen = false;
|
||||
@tracked mainClass = '';
|
||||
|
@ -11,7 +11,6 @@ const API_VERSION = 'v1';
|
||||
const DEBOUNCE_MS = 600;
|
||||
|
||||
export default Service.extend({
|
||||
config: service(),
|
||||
settings: service(),
|
||||
|
||||
columnCount: 3,
|
||||
|
@ -1,10 +1,11 @@
|
||||
import Route from '@ember/routing/route';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {inject as service} from '@ember/service';
|
||||
|
||||
Route.reopen({
|
||||
config: service(),
|
||||
billing: service(),
|
||||
router: service(),
|
||||
config: inject(),
|
||||
|
||||
actions: {
|
||||
willTransition(transition) {
|
||||
|
@ -1,5 +1,6 @@
|
||||
import Component from '@glimmer/component';
|
||||
import {action} from '@ember/object';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {isBlank} from '@ember/utils';
|
||||
import {run} from '@ember/runloop';
|
||||
import {inject as service} from '@ember/service';
|
||||
@ -8,12 +9,13 @@ import {task} from 'ember-concurrency';
|
||||
import {tracked} from '@glimmer/tracking';
|
||||
|
||||
export default class KoenigCardButtonComponent extends Component {
|
||||
@service config;
|
||||
@service feature;
|
||||
@service store;
|
||||
@service membersUtils;
|
||||
@service ui;
|
||||
|
||||
@inject config;
|
||||
|
||||
@tracked buttonFocused = false;
|
||||
@tracked contentFocused = false;
|
||||
@tracked offers = null;
|
||||
|
@ -3,6 +3,7 @@ import Browser from 'mobiledoc-kit/utils/browser';
|
||||
import Component from '@glimmer/component';
|
||||
import {EmojiButton} from '@joeattardi/emoji-button';
|
||||
import {action} from '@ember/object';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {isBlank} from '@ember/utils';
|
||||
import {run} from '@ember/runloop';
|
||||
import {inject as service} from '@ember/service';
|
||||
@ -12,12 +13,13 @@ import {tracked} from '@glimmer/tracking';
|
||||
const storageKey = 'gh-kg-callout-emoji';
|
||||
|
||||
export default class KoenigCardCalloutComponent extends Component {
|
||||
@service config;
|
||||
@service feature;
|
||||
@service store;
|
||||
@service membersUtils;
|
||||
@service ui;
|
||||
|
||||
@inject config;
|
||||
|
||||
get isEmpty() {
|
||||
return isBlank(this.args.payload.calloutText) && isBlank(this.args.payload.calloutEmoji);
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ import Component from '@glimmer/component';
|
||||
import {action} from '@ember/object';
|
||||
import {formatTextReplacementHtml} from './koenig-text-replacement-html-input';
|
||||
import {guidFor} from '@ember/object/internals';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {isBlank} from '@ember/utils';
|
||||
import {run} from '@ember/runloop';
|
||||
import {schedule} from '@ember/runloop';
|
||||
@ -12,12 +13,13 @@ import {task} from 'ember-concurrency';
|
||||
import {tracked} from '@glimmer/tracking';
|
||||
|
||||
export default class KoenigCardEmailCtaComponent extends Component {
|
||||
@service config;
|
||||
@service feature;
|
||||
@service store;
|
||||
@service membersUtils;
|
||||
@service ui;
|
||||
|
||||
@inject config;
|
||||
|
||||
@tracked buttonFocused = false;
|
||||
@tracked contentFocused = false;
|
||||
@tracked offers = null;
|
||||
|
@ -2,18 +2,20 @@ import Browser from 'mobiledoc-kit/utils/browser';
|
||||
import Component from '@glimmer/component';
|
||||
import {IMAGE_EXTENSIONS, IMAGE_MIME_TYPES} from 'ghost-admin/components/gh-image-uploader';
|
||||
import {action} from '@ember/object';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {isBlank} from '@ember/utils';
|
||||
import {run} from '@ember/runloop';
|
||||
import {inject as service} from '@ember/service';
|
||||
import {set} from '@ember/object';
|
||||
|
||||
export default class KoenigCardHeaderComponent extends Component {
|
||||
@service config;
|
||||
@service feature;
|
||||
@service store;
|
||||
@service membersUtils;
|
||||
@service ui;
|
||||
|
||||
@inject config;
|
||||
|
||||
imageExtensions = IMAGE_EXTENSIONS;
|
||||
imageMimeTypes = IMAGE_MIME_TYPES;
|
||||
|
||||
|
@ -5,6 +5,7 @@ import {
|
||||
IMAGE_MIME_TYPES
|
||||
} from 'ghost-admin/components/gh-image-uploader';
|
||||
import {action} from '@ember/object';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {isBlank} from '@ember/utils';
|
||||
import {run} from '@ember/runloop';
|
||||
import {inject as service} from '@ember/service';
|
||||
@ -12,12 +13,13 @@ import {set} from '@ember/object';
|
||||
import {tracked} from '@glimmer/tracking';
|
||||
|
||||
export default class KoenigCardProductComponent extends Component {
|
||||
@service config;
|
||||
@service feature;
|
||||
@service store;
|
||||
@service membersUtils;
|
||||
@service ui;
|
||||
|
||||
@inject config;
|
||||
|
||||
@tracked files = null;
|
||||
imageExtensions = IMAGE_EXTENSIONS;
|
||||
imageMimeTypes = IMAGE_MIME_TYPES;
|
||||
|
@ -2,18 +2,20 @@ import Browser from 'mobiledoc-kit/utils/browser';
|
||||
import Component from '@glimmer/component';
|
||||
import {action} from '@ember/object';
|
||||
import {formatTextReplacementHtml} from './koenig-text-replacement-html-input';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {isBlank} from '@ember/utils';
|
||||
import {run} from '@ember/runloop';
|
||||
import {inject as service} from '@ember/service';
|
||||
import {set} from '@ember/object';
|
||||
|
||||
export default class KoenigCardToggleComponent extends Component {
|
||||
@service config;
|
||||
@service feature;
|
||||
@service store;
|
||||
@service membersUtils;
|
||||
@service ui;
|
||||
|
||||
@inject config;
|
||||
|
||||
get formattedHeading() {
|
||||
return formatTextReplacementHtml(this.args.payload.heading);
|
||||
}
|
||||
|
@ -7,8 +7,8 @@ import {action, computed} from '@ember/object';
|
||||
import {attributeBindings, classNames} from '@ember-decorators/component';
|
||||
import {getLinkMarkupFromRange} from '../utils/markup-utils';
|
||||
import {htmlSafe} from '@ember/template';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {run} from '@ember/runloop';
|
||||
import {inject as service} from '@ember/service';
|
||||
|
||||
// pixels that should be added to the `left` property of the tick adjustment styles
|
||||
// TODO: handle via CSS?
|
||||
@ -18,7 +18,7 @@ const TICK_ADJUSTMENT = 8;
|
||||
@attributeBindings('style')
|
||||
@classNames('kg-input-bar', 'absolute', 'z-999')
|
||||
export default class KoenigLinkInput extends Component {
|
||||
@service config;
|
||||
@inject config;
|
||||
|
||||
// public attrs
|
||||
editor = null;
|
||||
|
@ -5,8 +5,8 @@ import {action, computed} from '@ember/object';
|
||||
import {attributeBindings, classNames} from '@ember-decorators/component';
|
||||
import {getEventTargetMatchingTag} from 'mobiledoc-kit/utils/element-utils';
|
||||
import {htmlSafe} from '@ember/template';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {run} from '@ember/runloop';
|
||||
import {inject as service} from '@ember/service';
|
||||
|
||||
// gap between link and toolbar bottom
|
||||
const TOOLBAR_MARGIN = 8;
|
||||
@ -22,7 +22,7 @@ const DELAY = 120;
|
||||
@attributeBindings('style')
|
||||
@classNames('absolute', 'z-999')
|
||||
export default class KoenigLinkToolbar extends Component {
|
||||
@service config;
|
||||
@inject config;
|
||||
|
||||
// public attrs
|
||||
container = null;
|
||||
|
@ -1,13 +1,15 @@
|
||||
import Helper from '@ember/component/helper';
|
||||
import {get} from '@ember/object';
|
||||
import {inject} from 'ghost-admin/decorators/inject';
|
||||
import {isArray} from '@ember/array';
|
||||
import {inject as service} from '@ember/service';
|
||||
|
||||
export default class CardIsAvailableHelper extends Helper {
|
||||
@service config;
|
||||
@service feature;
|
||||
@service settings;
|
||||
|
||||
@inject config;
|
||||
|
||||
compute([card], {postType} = {}) {
|
||||
let cardIsAvailable = true;
|
||||
|
||||
|
@ -1,4 +1,3 @@
|
||||
import Service from '@ember/service';
|
||||
import hbs from 'htmlbars-inline-precompile';
|
||||
import {describe, it} from 'mocha';
|
||||
import {expect} from 'chai';
|
||||
@ -9,10 +8,10 @@ describe('Unit: Component: gh-url-preview', function () {
|
||||
setupRenderingTest();
|
||||
|
||||
beforeEach(function () {
|
||||
let configStub = Service.extend({
|
||||
let configStub = {
|
||||
blogUrl: 'http://my-ghost-blog.com'
|
||||
});
|
||||
this.owner.register('service:config', configStub);
|
||||
};
|
||||
this.owner.register('config:main', configStub, {instantiate: false});
|
||||
});
|
||||
|
||||
it('generates the correct preview URL with a prefix', async function () {
|
||||
|
@ -5,7 +5,7 @@ import {expect} from 'chai';
|
||||
import {settled} from '@ember/test-helpers';
|
||||
import {setupTest} from 'ember-mocha';
|
||||
|
||||
describe('Integration: Service: config', function () {
|
||||
describe('Integration: Service: config-manager', function () {
|
||||
setupTest();
|
||||
|
||||
let server;
|
||||
@ -19,8 +19,8 @@ describe('Integration: Service: config', function () {
|
||||
});
|
||||
|
||||
it('returns a list of timezones in the expected format', function () {
|
||||
const service = this.owner.lookup('service:config');
|
||||
const timezones = service.availableTimezones;
|
||||
const injection = this.owner.lookup('config:main');
|
||||
const timezones = injection.availableTimezones;
|
||||
|
||||
expect(timezones.length).to.equal(66);
|
||||
expect(timezones[0].name).to.equal('Pacific/Pago_Pago');
|
||||
@ -51,13 +51,14 @@ describe('Integration: Service: config', function () {
|
||||
];
|
||||
});
|
||||
};
|
||||
let service = this.owner.lookup('service:config');
|
||||
const service = this.owner.lookup('service:config-manager');
|
||||
const injection = this.owner.lookup('config:main');
|
||||
|
||||
stubBlogUrl('http://localhost:2368/');
|
||||
|
||||
service.fetch().then(() => {
|
||||
expect(
|
||||
service.get('blogUrl'), 'trailing-slash'
|
||||
injection.blogUrl, 'trailing-slash'
|
||||
).to.equal('http://localhost:2368');
|
||||
});
|
||||
|
||||
@ -66,7 +67,7 @@ describe('Integration: Service: config', function () {
|
||||
|
||||
service.fetch().then(() => {
|
||||
expect(
|
||||
service.get('blogUrl'), 'non-trailing-slash'
|
||||
injection.blogUrl, 'non-trailing-slash'
|
||||
).to.equal('http://localhost:2368');
|
||||
|
||||
done();
|
||||
|
@ -117,7 +117,7 @@ describe('Integration: Service: feature', function () {
|
||||
await session.populateUser();
|
||||
|
||||
let service = this.owner.lookup('service:feature');
|
||||
service.get('config').set('testFlag', false);
|
||||
service.config.testFlag = false;
|
||||
|
||||
return service.fetch().then(() => {
|
||||
expect(service.get('labs.testFlag')).to.be.false;
|
||||
@ -135,7 +135,7 @@ describe('Integration: Service: feature', function () {
|
||||
await session.populateUser();
|
||||
|
||||
let service = this.owner.lookup('service:feature');
|
||||
service.get('config').set('testFlag', true);
|
||||
service.config.testFlag = true;
|
||||
|
||||
return service.fetch().then(() => {
|
||||
expect(service.get('labs.testFlag')).to.be.false;
|
||||
@ -153,7 +153,7 @@ describe('Integration: Service: feature', function () {
|
||||
await session.populateUser();
|
||||
|
||||
let service = this.owner.lookup('service:feature');
|
||||
service.get('config').set('testFlag', false);
|
||||
service.config.testFlag = false;
|
||||
|
||||
return service.fetch().then(() => {
|
||||
expect(service.get('labs.testFlag')).to.be.true;
|
||||
@ -171,7 +171,7 @@ describe('Integration: Service: feature', function () {
|
||||
await session.populateUser();
|
||||
|
||||
let service = this.owner.lookup('service:feature');
|
||||
service.get('config').set('testFlag', true);
|
||||
service.config.testFlag = true;
|
||||
|
||||
return service.fetch().then(() => {
|
||||
expect(service.get('labs.testFlag')).to.be.true;
|
||||
@ -223,7 +223,7 @@ describe('Integration: Service: feature', function () {
|
||||
await session.populateUser();
|
||||
|
||||
let service = this.owner.lookup('service:feature');
|
||||
service.get('config').set('testFlag', false);
|
||||
service.config.testFlag = false;
|
||||
|
||||
return service.fetch().then(() => {
|
||||
expect(service.get('testFlag')).to.be.false;
|
||||
@ -274,7 +274,7 @@ describe('Integration: Service: feature', function () {
|
||||
await session.populateUser();
|
||||
|
||||
let service = this.owner.lookup('service:feature');
|
||||
service.get('config').set('testFlag', false);
|
||||
service.config.testFlag = false;
|
||||
|
||||
return service.fetch().then(() => {
|
||||
expect(service.get('testFlag')).to.be.false;
|
||||
@ -339,25 +339,25 @@ describe('Integration: Service: feature', function () {
|
||||
|
||||
addTestFlag();
|
||||
|
||||
let session = this.owner.lookup('service:session');
|
||||
await session.populateUser();
|
||||
let sessionService = this.owner.lookup('service:session');
|
||||
await sessionService.populateUser();
|
||||
|
||||
let service = this.owner.lookup('service:feature');
|
||||
service.get('config').set('testFlag', false);
|
||||
let featureService = this.owner.lookup('service:feature');
|
||||
featureService.config.testFlag = false;
|
||||
|
||||
return service.fetch().then(() => {
|
||||
expect(service.get('testFlag'), 'testFlag before set').to.be.false;
|
||||
return featureService.fetch().then(() => {
|
||||
expect(featureService.get('testFlag'), 'testFlag before set').to.be.false;
|
||||
|
||||
run(() => {
|
||||
expect(() => {
|
||||
service.set('testFlag', true);
|
||||
featureService.set('testFlag', true);
|
||||
}, EmberError, 'threw validation error');
|
||||
});
|
||||
|
||||
return settled().then(() => {
|
||||
// ensure validation is happening before the API is hit
|
||||
expect(server.handlers[2].numberOfCalls).to.equal(0);
|
||||
expect(service.get('testFlag')).to.be.false;
|
||||
expect(featureService.get('testFlag')).to.be.false;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user