mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-25 20:03:12 +03:00
Added initial "publishOptions" setup
refs https://github.com/TryGhost/Team/issues/1542 - adds a `PublishOptions` class - an instance of this class provides everything the UI needs to display and set the publish options relevant to the current post object and overall system state - the `publish-flow` modal is passed a `PublishOptions` instance when it opens - as part of the constructor it triggers a background load of any additional data it requires to control available options such as member counts, email limits, and newsletters - adds a `{{publish-options}}` resource - sets up and returns `PublishOptions` instance - passes through service dependencies which are not available directly in the `PublishOptions` class as it's a custom native class outside of Ember's DI management - used to ensure we can get a clean `PublishOptions` instance any time the passed in `post` object is replaced meaning we don't have to rely on observers and manual teardown/setup - updated `<PublishManagement>` component - sets up `publishOptions` property using `@use` and the `{{publish-options}}` resource so reactivity for changing post objects is handled automatically - uses the `publishOptions.isLoading` property to disable the publish flow trigger button until all of the data required to manage the flow is available - updated `publish-flow` modal to use some of the initially available `publishOptions` data
This commit is contained in:
parent
bfb02d4458
commit
2be1673106
@ -3,6 +3,7 @@
|
||||
class="gh-btn gh-btn-editor darkgrey gh-publishmenu-trigger"
|
||||
{{on "click" this.openPublishFlow}}
|
||||
{{on-key "cmd+shift+p"}}
|
||||
disabled={{this.publishOptions.isLoading}}
|
||||
data-test-button="publish-flow"
|
||||
>
|
||||
<span>Publish</span>
|
||||
|
@ -1,11 +1,137 @@
|
||||
import Component from '@glimmer/component';
|
||||
import PublishFlowModal from '../modals/editor-labs/publish-flow';
|
||||
import {action} from '@ember/object';
|
||||
import PublishOptionsResource from 'ghost-admin/helpers/publish-options';
|
||||
import {action, get} from '@ember/object';
|
||||
import {inject as service} from '@ember/service';
|
||||
import {task} from 'ember-concurrency';
|
||||
import {tracked} from '@glimmer/tracking';
|
||||
import {use} from 'ember-could-get-used-to-this';
|
||||
|
||||
export default class PublishFlow extends Component {
|
||||
export class PublishOptions {
|
||||
// passed in services
|
||||
config = null;
|
||||
settings = null;
|
||||
store = null;
|
||||
|
||||
// passed in objects
|
||||
post = null;
|
||||
user = null;
|
||||
|
||||
get isLoading() {
|
||||
return this.setupTask.isRunning;
|
||||
}
|
||||
|
||||
// publish type ------------------------------------------------------------
|
||||
|
||||
@tracked publishType = 'publish+send';
|
||||
|
||||
get publishTypeOptions() {
|
||||
return [{
|
||||
value: 'publish+send',
|
||||
display: 'published and sent',
|
||||
disabled: this.emailDisabled
|
||||
}, {
|
||||
value: 'publish',
|
||||
display: 'published'
|
||||
}, {
|
||||
value: 'send',
|
||||
display: 'sent',
|
||||
disabled: this.emailDisabled
|
||||
}];
|
||||
}
|
||||
|
||||
get selectedPublishTypeOption() {
|
||||
return this.publishTypeOptions.find(pto => pto.value === this.publishType);
|
||||
}
|
||||
|
||||
// publish type dropdown is not shown at all
|
||||
get emailUnavailable() {
|
||||
const emailDisabled = get(this.settings, 'editorDefaultEmailRecipients') === 'disabled'
|
||||
|| get(this.settings, 'membersSignupAccess') === 'none';
|
||||
|
||||
return this.post.isPage || this.post.email || !this.user.canEmail || emailDisabled;
|
||||
}
|
||||
|
||||
// publish type dropdown is shown but email options are disabled
|
||||
get emailDisabled() {
|
||||
const mailgunConfigured = get(this.settings, 'mailgunIsConfigured')
|
||||
|| get(this.config, 'mailgunIsConfigured');
|
||||
|
||||
// TODO: check members count
|
||||
// TODO: check email limit
|
||||
|
||||
return !mailgunConfigured;
|
||||
}
|
||||
|
||||
// publish date ------------------------------------------------------------
|
||||
|
||||
@tracked publishDate = 'now';
|
||||
|
||||
// newsletter --------------------------------------------------------------
|
||||
|
||||
newsletters = []; // set in constructor
|
||||
|
||||
get defaultNewsletter() {
|
||||
return this.newsletters.sort(({sortOrder: a}, {sortOrder: b}) => b - a)[0];
|
||||
}
|
||||
|
||||
get onlyDefaultNewsletter() {
|
||||
return this.newsletters.length === 1;
|
||||
}
|
||||
|
||||
// recipients --------------------------------------------------------------
|
||||
|
||||
// setup -------------------------------------------------------------------
|
||||
|
||||
constructor({config, post, settings, store, user} = {}) {
|
||||
this.config = config;
|
||||
this.post = post;
|
||||
this.settings = settings;
|
||||
this.store = store;
|
||||
this.user = user;
|
||||
|
||||
// these need to be set here rather than class-level properties because
|
||||
// unlike Ember-based classes the services are not injected so can't be
|
||||
// used until after they are assigned above
|
||||
this.newsletters = this.store.peekAll('newsletter').filter(n => n.status === 'active');
|
||||
|
||||
this.setupTask.perform();
|
||||
}
|
||||
|
||||
@task
|
||||
*setupTask() {
|
||||
yield this.fetchRequiredDataTask.perform();
|
||||
|
||||
// TODO: set up initial state / defaults
|
||||
|
||||
if (this.emailUnavailable) {
|
||||
this.publishType = 'publish';
|
||||
}
|
||||
}
|
||||
|
||||
@task
|
||||
*fetchRequiredDataTask() {
|
||||
// total # of members - used to enable/disable email
|
||||
const countTotalMembers = this.store.query('member', {limit: 1}).then(res => res.meta.pagination.total);
|
||||
|
||||
// email limits
|
||||
// TODO: query limit service
|
||||
|
||||
// newsletters
|
||||
const fetchNewsletters = this.store.findAll('newsletter', {reload: true});
|
||||
|
||||
yield Promise.all([countTotalMembers, fetchNewsletters]);
|
||||
}
|
||||
}
|
||||
|
||||
// This component exists for the duration of the editor screen being open.
|
||||
// It's used to store the selected publish options and control the publishing flow.
|
||||
export default class PublishManagement extends Component {
|
||||
@service modals;
|
||||
|
||||
// ensure we get a new PublishOptions instance when @post is replaced
|
||||
@use publishOptions = new PublishOptionsResource(() => [this.args.post]);
|
||||
|
||||
publishFlowModal = null;
|
||||
|
||||
willDestroy() {
|
||||
@ -14,7 +140,13 @@ export default class PublishFlow extends Component {
|
||||
}
|
||||
|
||||
@action
|
||||
openPublishFlow() {
|
||||
this.publishFlowModal = this.modals.open(PublishFlowModal);
|
||||
openPublishFlow(event) {
|
||||
event?.preventDefault();
|
||||
|
||||
if (!this.publishFlowModal || this.publishFlowModal.isClosing) {
|
||||
this.publishFlowModal = this.modals.open(PublishFlowModal, {
|
||||
publishOptions: this.publishOptions
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,12 +9,31 @@
|
||||
<div class="gh-publish-title">Ready?</div>
|
||||
<div class="gh-publish-settings">
|
||||
<span class="gh-publish-setting">Right now</span>
|
||||
, this post will be
|
||||
<span class="gh-publish-setting">published and sent</span>
|
||||
to
|
||||
<span class="gh-publish-setting">all subscribers</span>
|
||||
of
|
||||
<span class="gh-publish-setting">The Weekly Roundup</span>.
|
||||
|
||||
, this {{@data.publishOptions.post.displayName}} will be
|
||||
|
||||
{{#if @data.publishOptions.emailUnavailable}}
|
||||
published
|
||||
{{else}}
|
||||
<span class="gh-publish-setting">{{@data.publishOptions.selectedPublishTypeOption.display}}</span>
|
||||
{{/if}}
|
||||
|
||||
{{#if (eq @data.publishOptions.publishType "publish")}}
|
||||
on your site.
|
||||
{{else}}
|
||||
to
|
||||
<span class="gh-publish-setting">all subscribers</span>
|
||||
|
||||
of
|
||||
|
||||
{{#if @data.publishOptions.onlyDefaultNewsletter}}
|
||||
your site.
|
||||
{{else}}
|
||||
<span class="gh-publish-setting">The Weekly Roundup</span>.
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<div class="gh-publish-cta">
|
||||
|
45
ghost/admin/app/helpers/publish-options.js
Normal file
45
ghost/admin/app/helpers/publish-options.js
Normal file
@ -0,0 +1,45 @@
|
||||
import {PublishOptions} from '../components/editor-labs/publish-management';
|
||||
import {Resource} from 'ember-could-get-used-to-this';
|
||||
import {inject as service} from '@ember/service';
|
||||
import {tracked} from '@glimmer/tracking';
|
||||
|
||||
export default class PublishOptionsResource extends Resource {
|
||||
@service config;
|
||||
@service session;
|
||||
@service settings;
|
||||
@service store;
|
||||
|
||||
@tracked publishOptions;
|
||||
|
||||
get value() {
|
||||
return this.publishOptions;
|
||||
}
|
||||
|
||||
setup() {
|
||||
const post = this.args.positional[0];
|
||||
this._post = post;
|
||||
|
||||
this.publishOptions = this._createPublishOptions(post);
|
||||
}
|
||||
|
||||
update() {
|
||||
// required due to a weird invalidation issue when using Ember Data with ember-could-get-used-to-this
|
||||
// TODO: re-test after upgrading to ember-resources
|
||||
const post = this.args.positional[0];
|
||||
if (post !== this._post) {
|
||||
this.publishOptions = this._createPublishOptions(post);
|
||||
}
|
||||
}
|
||||
|
||||
_createPublishOptions(post) {
|
||||
const {config, settings, store} = this;
|
||||
|
||||
return new PublishOptions({
|
||||
config,
|
||||
post,
|
||||
settings,
|
||||
store,
|
||||
user: this.session.user
|
||||
});
|
||||
}
|
||||
}
|
@ -54,6 +54,8 @@ export default BaseModel.extend(ValidationEngine, {
|
||||
isAdmin: or('isOwnerOnly', 'isAdminOnly'),
|
||||
isAuthorOrContributor: or('isAuthor', 'isContributor'),
|
||||
|
||||
canEmail: or('isAdmin', 'isEditor'),
|
||||
|
||||
isLoggedIn: computed('id', 'session.user.id', function () {
|
||||
return this.id === this.get('session.user.id');
|
||||
}),
|
||||
|
Loading…
Reference in New Issue
Block a user