mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-02-17 23:44:39 -05:00
Added newsletter dropdown to publish menu
closes https://github.com/TryGhost/Team/issues/1479 - updated post adapter to append `?newsletter_id=xyz` when passed a `newsletterId` adapterOption - updated editor save task to pass `options.newsletterId` through as `adapterOptions.newsletterId` - set up `post.newsletter` relationship ready for handling embedded newsletter association from the API - explicitly deleted when serializing back to the API as it doesn't yet ignore the attribute - updated `<GhPublishmenu>` for newsletter support - fetches newsletters on first render so they are available in the dropdown - sets "default" (first in the ordered list) newsletter as the initially selected newsletter - adds newsletter dropdown to draft publish menu - passes `newsletterId` option to editor save task when it's set This is a minimal implementation for testing. Not included: - correct free/paid member counts based on selected newsletter - correct member count in confirmation modal - indication of selected newsletter for scheduled post
This commit is contained in:
parent
114b359ab7
commit
e5c26aac89
9 changed files with 79 additions and 13 deletions
|
@ -1,14 +1,12 @@
|
|||
import ApplicationAdapter from 'ghost-admin/adapters/application';
|
||||
import classic from 'ember-classic-decorator';
|
||||
|
||||
@classic
|
||||
export default class Post extends ApplicationAdapter {
|
||||
// posts and pages now include everything by default
|
||||
buildIncludeURL(store, modelName, id, snapshot, requestType, query) {
|
||||
let url = this.buildURL(modelName, id, snapshot, requestType, query);
|
||||
let parsedUrl = new URL(url);
|
||||
const url = this.buildURL(modelName, id, snapshot, requestType, query);
|
||||
const parsedUrl = new URL(url);
|
||||
|
||||
if (snapshot && snapshot.adapterOptions && snapshot.adapterOptions.sendEmailWhenPublished) {
|
||||
if (snapshot?.adapterOptions?.sendEmailWhenPublished) {
|
||||
let emailRecipientFilter = snapshot.adapterOptions.sendEmailWhenPublished;
|
||||
|
||||
if (emailRecipientFilter === 'status:free,status:-free') {
|
||||
|
@ -18,6 +16,11 @@ export default class Post extends ApplicationAdapter {
|
|||
parsedUrl.searchParams.append('email_recipient_filter', emailRecipientFilter);
|
||||
}
|
||||
|
||||
if (snapshot?.adapterOptions?.newsletterId) {
|
||||
const newsletterId = snapshot.adapterOptions.newsletterId;
|
||||
parsedUrl.searchParams.append('newsletter_id', newsletterId);
|
||||
}
|
||||
|
||||
return parsedUrl.toString();
|
||||
}
|
||||
|
||||
|
|
|
@ -61,6 +61,22 @@
|
|||
</p>
|
||||
{{else}}
|
||||
<div class="form-group">
|
||||
{{#if (and (feature "multipleNewsletters") (gt @availableNewsletters.length 1))}}
|
||||
<div class="mb3">
|
||||
<p>Newsletter</p>
|
||||
<PowerSelect
|
||||
@selected={{@selectedNewsletter}}
|
||||
@options={{@availableNewsletters}}
|
||||
@onChange={{@selectNewsletter}}
|
||||
@triggerComponent="gh-power-select/trigger"
|
||||
@renderInPlace={{true}}
|
||||
as |newsletter|
|
||||
>
|
||||
{{newsletter.name}}
|
||||
</PowerSelect>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
<GhMembersRecipientSelect
|
||||
@filter={{@recipientsFilter}}
|
||||
@onChange={{@setSendEmailWhenPublished}}
|
||||
|
|
|
@ -42,6 +42,9 @@
|
|||
@sendingEmailLimitError={{this.sendingEmailLimitError}}
|
||||
@distributionAction={{this.distributionAction}}
|
||||
@setDistributionAction={{action "setDistributionAction"}}
|
||||
@availableNewsletters={{this.availableNewsletters}}
|
||||
@selectedNewsletter={{this.selectedNewsletter}}
|
||||
@selectNewsletter={{this.selectNewsletter}}
|
||||
data-test-publishmenu-draft="true" />
|
||||
{{/if}}
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import Component from '@ember/component';
|
||||
import ConfirmPublishModal from './modals/editor/confirm-publish';
|
||||
import EmailFailedError from 'ghost-admin/errors/email-failed-error';
|
||||
import {action, computed} from '@ember/object';
|
||||
import {bind, schedule} from '@ember/runloop';
|
||||
import {computed} from '@ember/object';
|
||||
import {or, reads} from '@ember/object/computed';
|
||||
import {inject as service} from '@ember/service';
|
||||
import {task, timeout} from 'ember-concurrency';
|
||||
|
@ -32,6 +32,7 @@ export default Component.extend({
|
|||
typedDateError: null,
|
||||
isSendingEmailLimited: false,
|
||||
sendingEmailLimitError: '',
|
||||
selectedNewsletter: null,
|
||||
|
||||
_publishedAtBlogTZ: null,
|
||||
_previousStatus: null,
|
||||
|
@ -226,6 +227,11 @@ export default Component.extend({
|
|||
}
|
||||
},
|
||||
|
||||
didInsertElement() {
|
||||
this._super(...arguments);
|
||||
this.fetchNewslettersTask.perform();
|
||||
},
|
||||
|
||||
actions: {
|
||||
setSaveType(saveType) {
|
||||
let post = this.post;
|
||||
|
@ -313,6 +319,10 @@ export default Component.extend({
|
|||
}
|
||||
},
|
||||
|
||||
get availableNewsletters() {
|
||||
return this.store.peekAll('newsletter').filter(n => n.status === 'active');
|
||||
},
|
||||
|
||||
updateSaveTypeForPostStatus(status) {
|
||||
if (status === 'draft' || status === 'published') {
|
||||
this.set('saveType', 'publish');
|
||||
|
@ -395,6 +405,7 @@ export default Component.extend({
|
|||
post: this.post,
|
||||
emailOnly: this.emailOnly,
|
||||
sendEmailWhenPublished: this.sendEmailWhenPublished,
|
||||
newsletterId: this.newsletterId,
|
||||
isScheduled: saveType === 'schedule',
|
||||
confirm: this.saveWithConfirmedPublish.perform,
|
||||
retryEmailSend: this.retryEmailSendTask.perform
|
||||
|
@ -437,6 +448,24 @@ export default Component.extend({
|
|||
return email;
|
||||
}),
|
||||
|
||||
selectNewsletter: action(function (newsletter) {
|
||||
this.set('selectedNewsletter', newsletter);
|
||||
}),
|
||||
|
||||
fetchNewslettersTask: task(function* () {
|
||||
if (this.feature.multipleNewsletters) {
|
||||
const newsletters = yield this.store.query('newsletter', {
|
||||
filter: 'status:active',
|
||||
order: 'sort_order ASC'
|
||||
});
|
||||
|
||||
const defaultNewsletter = newsletters.toArray()[0];
|
||||
|
||||
this.defaultNewsletter = defaultNewsletter;
|
||||
this.set('selectedNewsletter', defaultNewsletter);
|
||||
}
|
||||
}),
|
||||
|
||||
_saveTask: task(function* () {
|
||||
let {
|
||||
post,
|
||||
|
@ -453,7 +482,7 @@ export default Component.extend({
|
|||
|
||||
try {
|
||||
// will show alert for non-date related failed validations
|
||||
post = yield this.saveTask.perform({sendEmailWhenPublished, emailOnly});
|
||||
post = yield this.saveTask.perform({sendEmailWhenPublished, newsletterId: this.selectedNewsletter?.id, emailOnly});
|
||||
|
||||
this._cachePublishedAtBlogTZ();
|
||||
|
||||
|
@ -492,6 +521,8 @@ export default Component.extend({
|
|||
},
|
||||
|
||||
_cleanup() {
|
||||
this.set('selectedNewsletter', this.defaultNewsletter);
|
||||
|
||||
if (this.post.isScheduled && this.post.emailOnly) {
|
||||
this.set('distributionAction', 'send');
|
||||
} else if (this.post.isPage || !this.defaultEmailRecipients) {
|
||||
|
|
|
@ -490,7 +490,10 @@ export default class EditorController extends Controller {
|
|||
let isPublishing = status === 'published' && !this.post.isPublished;
|
||||
let isScheduling = status === 'scheduled' && !this.post.isScheduled;
|
||||
if (options.sendEmailWhenPublished && (isPublishing || isScheduling)) {
|
||||
options.adapterOptions = Object.assign({}, options.adapterOptions, {sendEmailWhenPublished: options.sendEmailWhenPublished});
|
||||
options.adapterOptions = Object.assign({}, options.adapterOptions, {
|
||||
sendEmailWhenPublished: options.sendEmailWhenPublished,
|
||||
newsletterId: options.newsletterId
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -114,6 +114,7 @@ export default Model.extend(Comparable, ValidationEngine, {
|
|||
authors: hasMany('user', {embedded: 'always', async: false}),
|
||||
createdBy: belongsTo('user', {async: true}),
|
||||
email: belongsTo('email', {async: false}),
|
||||
newsletter: belongsTo('newsletter', {embedded: 'always', async: false}),
|
||||
publishedBy: belongsTo('user', {async: true}),
|
||||
tags: hasMany('tag', {embedded: 'always', async: false}),
|
||||
|
||||
|
|
|
@ -10,7 +10,8 @@ export default class PostSerializer extends ApplicationSerializer.extend(Embedde
|
|||
publishedAtUTC: {key: 'published_at'},
|
||||
createdAtUTC: {key: 'created_at'},
|
||||
updatedAtUTC: {key: 'updated_at'},
|
||||
email: {embedded: 'always'}
|
||||
email: {embedded: 'always'},
|
||||
newsletter: {embedded: 'always'}
|
||||
};
|
||||
|
||||
serialize(/*snapshot, options*/) {
|
||||
|
@ -23,6 +24,7 @@ export default class PostSerializer extends ApplicationSerializer.extend(Embedde
|
|||
delete json.url;
|
||||
delete json.send_email_when_published;
|
||||
delete json.email_recipient_filter;
|
||||
delete json.newsletter;
|
||||
// Deprecated property (replaced with data.authors)
|
||||
delete json.author;
|
||||
|
||||
|
|
|
@ -71,15 +71,21 @@ export default function mockPosts(server) {
|
|||
});
|
||||
});
|
||||
|
||||
server.put('/posts/:id/', function ({posts, users, tags}, {params}) {
|
||||
let attrs = this.normalizedRequestAttrs();
|
||||
let post = posts.find(params.id);
|
||||
server.put('/posts/:id/', function ({newsletters, posts, users, tags}, {params}) {
|
||||
const attrs = this.normalizedRequestAttrs();
|
||||
const post = posts.find(params.id);
|
||||
|
||||
attrs.authors = extractAuthors(attrs, users);
|
||||
attrs.tags = extractTags(attrs, tags);
|
||||
|
||||
attrs.updatedAt = moment.utc().toDate();
|
||||
|
||||
if (params.newsletter_id) {
|
||||
const newsletter = newsletters.find(params.newsletter_id);
|
||||
post.newsletter = newsletter;
|
||||
post.save();
|
||||
}
|
||||
|
||||
return post.update(attrs);
|
||||
});
|
||||
|
||||
|
|
|
@ -3,5 +3,6 @@ import {Model, belongsTo, hasMany} from 'miragejs';
|
|||
export default Model.extend({
|
||||
tags: hasMany(),
|
||||
authors: hasMany('user'),
|
||||
email: belongsTo()
|
||||
email: belongsTo(),
|
||||
newsletter: belongsTo()
|
||||
});
|
||||
|
|
Loading…
Add table
Reference in a new issue