mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-25 11:55:03 +03:00
🎨 Added confirmation dialog any time a post/page will be published
refs https://github.com/TryGhost/Team/issues/1169 Previously we were only showing a confirmation dialog if a publish action would trigger an email which was inconsistent and did not instil confidence when publishing. - replaced old `modal-confirm-email-send` modal with the newer-style `modals/editor/confirm-publish` component - updated to handle standard publish in addition to email publish - updated copy - added "error" state when attempting to send email-only post to no members - updated publish menu `save` task to open the confirm modal when going from `draft` to `published` or `scheduled` - underlying save with email polling moved to `_saveTask` so it can be re-used across `save` task (when not publishing) and when confirming from the modal
This commit is contained in:
parent
fc00dc1abc
commit
98b5506d64
@ -66,21 +66,6 @@
|
||||
</GhBasicDropdown>
|
||||
{{/if}}
|
||||
|
||||
{{#if this.showEmailConfirmationModal}}
|
||||
<GhFullscreenModal
|
||||
@modal="confirm-email-send"
|
||||
@model={{hash
|
||||
sendEmailWhenPublished=this.sendEmailWhenPublished
|
||||
isScheduled=(eq this.saveType "schedule")
|
||||
emailOnly=this.emailOnly
|
||||
retryEmailSend=this.retryEmailSend
|
||||
}}
|
||||
@confirm={{this.confirmEmailSend}}
|
||||
@close={{this.closeEmailConfirmationModal}}
|
||||
@modifier="action wide"
|
||||
/>
|
||||
{{/if}}
|
||||
|
||||
{{!--
|
||||
Workaround to have an always-shown element to attach key handlers to.
|
||||
TODO: Move onto main element once converted to a glimmer component
|
||||
|
@ -1,6 +1,6 @@
|
||||
import Component from '@ember/component';
|
||||
import EmailFailedError from 'ghost-admin/errors/email-failed-error';
|
||||
import {action} from '@ember/object';
|
||||
import {bind} from '@ember/runloop';
|
||||
import {computed} from '@ember/object';
|
||||
import {or, reads} from '@ember/object/computed';
|
||||
import {schedule} from '@ember/runloop';
|
||||
@ -12,12 +12,13 @@ const CONFIRM_EMAIL_MAX_POLL_LENGTH = 15 * 1000;
|
||||
|
||||
export default Component.extend({
|
||||
clock: service(),
|
||||
feature: service(),
|
||||
settings: service(),
|
||||
config: service(),
|
||||
session: service(),
|
||||
store: service(),
|
||||
feature: service(),
|
||||
limit: service(),
|
||||
modals: service(),
|
||||
session: service(),
|
||||
settings: service(),
|
||||
store: service(),
|
||||
|
||||
classNames: 'gh-publishmenu',
|
||||
displayState: 'draft',
|
||||
@ -297,7 +298,7 @@ export default Component.extend({
|
||||
|
||||
// wait for actions to be triggered by the focusout/blur before saving
|
||||
schedule('actions', this, function () {
|
||||
this.send('setSaveType', 'published');
|
||||
this.send('setSaveType', 'publish');
|
||||
this.save.perform();
|
||||
});
|
||||
}
|
||||
@ -336,98 +337,15 @@ export default Component.extend({
|
||||
}
|
||||
}),
|
||||
|
||||
// action is required because <GhFullscreenModal> only uses actions
|
||||
confirmEmailSend: action(function () {
|
||||
return this._confirmEmailSend.perform();
|
||||
}),
|
||||
|
||||
_confirmEmailSend: task(function* () {
|
||||
this.sendEmailConfirmed = true;
|
||||
let post = yield this.save.perform();
|
||||
|
||||
// simulate a validation error if saving failed so that the confirm
|
||||
// modal can react accordingly
|
||||
if (!post || post.errors.length) {
|
||||
throw null;
|
||||
}
|
||||
|
||||
let pollTimeout = 0;
|
||||
if (post.email && post.email.status !== 'submitted') {
|
||||
while (pollTimeout < CONFIRM_EMAIL_MAX_POLL_LENGTH) {
|
||||
yield timeout(CONFIRM_EMAIL_POLL_LENGTH);
|
||||
post = yield post.reload();
|
||||
|
||||
if (post.email.status === 'submitted') {
|
||||
break;
|
||||
}
|
||||
if (post.email.status === 'failed') {
|
||||
throw new EmailFailedError(post.email.error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return post;
|
||||
}),
|
||||
|
||||
retryEmailSend: action(function () {
|
||||
return this._retryEmailSend.perform();
|
||||
}),
|
||||
|
||||
_retryEmailSend: task(function* () {
|
||||
if (!this.post.email) {
|
||||
return;
|
||||
}
|
||||
|
||||
let email = yield this.post.email.retry();
|
||||
|
||||
let pollTimeout = 0;
|
||||
if (email && email.status !== 'submitted') {
|
||||
while (pollTimeout < CONFIRM_EMAIL_POLL_LENGTH) {
|
||||
yield timeout(CONFIRM_EMAIL_POLL_LENGTH);
|
||||
email = yield email.reload();
|
||||
|
||||
if (email.status === 'submitted') {
|
||||
break;
|
||||
}
|
||||
if (email.status === 'failed') {
|
||||
throw new EmailFailedError(email.error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return email;
|
||||
}),
|
||||
|
||||
openEmailConfirmationModal: action(function (dropdown) {
|
||||
if (dropdown) {
|
||||
this._skipDropdownCloseCleanup = true;
|
||||
dropdown.actions.close();
|
||||
}
|
||||
this.set('showEmailConfirmationModal', true);
|
||||
}),
|
||||
|
||||
closeEmailConfirmationModal: action(function () {
|
||||
this.set('showEmailConfirmationModal', false);
|
||||
this._cleanup();
|
||||
}),
|
||||
|
||||
reloadSettingsTask: task(function* () {
|
||||
yield this.settings.reload();
|
||||
}),
|
||||
|
||||
save: task(function* ({dropdown} = {}) {
|
||||
let {
|
||||
post,
|
||||
emailOnly,
|
||||
sendEmailWhenPublished,
|
||||
sendEmailConfirmed,
|
||||
saveType,
|
||||
typedDateError,
|
||||
distributionAction
|
||||
} = this;
|
||||
save: task(function* (options = {}) {
|
||||
const {post, saveType} = this;
|
||||
|
||||
// don't allow save if an invalid schedule date is present
|
||||
if (typedDateError) {
|
||||
if (this.typedDateError) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -443,18 +361,66 @@ export default Component.extend({
|
||||
return false;
|
||||
}
|
||||
|
||||
if (
|
||||
post.status === 'draft' &&
|
||||
!post.email && // email sent previously
|
||||
sendEmailWhenPublished && sendEmailWhenPublished !== 'none' &&
|
||||
distributionAction !== 'publish' &&
|
||||
!sendEmailConfirmed // set once confirmed so normal save happens
|
||||
) {
|
||||
this.openEmailConfirmationModal(dropdown);
|
||||
// always opens publish confirmation if post will be published/scheduled
|
||||
if (post.status === 'draft' && (saveType === 'publish' || saveType === 'schedule')) {
|
||||
if (options.dropdown) {
|
||||
this._skipDropdownCloseCleanup = true;
|
||||
options.dropdown.actions.close();
|
||||
}
|
||||
|
||||
return yield this.modals.open('modals/editor/confirm-publish', {
|
||||
post: this.post,
|
||||
emailOnly: this.emailOnly,
|
||||
sendEmailWhenPublished: this.sendEmailWhenPublished,
|
||||
isScheduled: saveType === 'schedule',
|
||||
confirm: this.saveWithConfirmedPublish.perform,
|
||||
retryEmailSend: this.retryEmailSendTask.perform
|
||||
}, {
|
||||
beforeClose: bind(this, this._cleanup)
|
||||
});
|
||||
}
|
||||
|
||||
return yield this._saveTask.perform(options);
|
||||
}),
|
||||
|
||||
saveWithConfirmedPublish: task(function* () {
|
||||
return yield this._saveTask.perform();
|
||||
}),
|
||||
|
||||
retryEmailSendTask: task(function* () {
|
||||
if (!this.post.email) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.sendEmailConfirmed = false;
|
||||
let email = yield this.post.email.retry();
|
||||
|
||||
let pollTimeout = 0;
|
||||
if (email && email.status !== 'submitted') {
|
||||
while (pollTimeout < CONFIRM_EMAIL_MAX_POLL_LENGTH) {
|
||||
yield timeout(CONFIRM_EMAIL_POLL_LENGTH);
|
||||
pollTimeout += CONFIRM_EMAIL_POLL_LENGTH;
|
||||
|
||||
email = yield email.reload();
|
||||
|
||||
if (email.status === 'submitted') {
|
||||
break;
|
||||
}
|
||||
if (email.status === 'failed') {
|
||||
throw new EmailFailedError(email.error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return email;
|
||||
}),
|
||||
|
||||
_saveTask: task(function* () {
|
||||
let {
|
||||
post,
|
||||
emailOnly,
|
||||
sendEmailWhenPublished,
|
||||
saveType
|
||||
} = this;
|
||||
|
||||
// runningText needs to be declared before the other states change during the
|
||||
// save action.
|
||||
@ -467,6 +433,28 @@ export default Component.extend({
|
||||
post = yield this.saveTask.perform({sendEmailWhenPublished, emailOnly});
|
||||
|
||||
this._cachePublishedAtBlogTZ();
|
||||
|
||||
if (sendEmailWhenPublished && sendEmailWhenPublished !== 'none') {
|
||||
let pollTimeout = 0;
|
||||
if (post.email && post.email.status !== 'submitted') {
|
||||
while (pollTimeout < CONFIRM_EMAIL_MAX_POLL_LENGTH) {
|
||||
yield timeout(CONFIRM_EMAIL_POLL_LENGTH);
|
||||
pollTimeout += CONFIRM_EMAIL_POLL_LENGTH;
|
||||
|
||||
post = yield post.reload();
|
||||
|
||||
if (post.email.status === 'submitted') {
|
||||
break;
|
||||
}
|
||||
if (post.email.status === 'failed') {
|
||||
throw new EmailFailedError(post.email.error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this._cleanup();
|
||||
|
||||
return post;
|
||||
} catch (error) {
|
||||
// re-throw if we don't have a validation error
|
||||
@ -482,7 +470,6 @@ export default Component.extend({
|
||||
|
||||
_cleanup() {
|
||||
this.set('distributionAction', 'publish_send');
|
||||
this.set('showConfirmEmailModal', false);
|
||||
|
||||
// when closing the menu we reset the publishedAtBlogTZ date so that the
|
||||
// unsaved changes made to the scheduled date aren't reflected in the PSM
|
||||
|
@ -1,90 +0,0 @@
|
||||
{{#unless this.errorMessage}}
|
||||
<header class="modal-header" data-test-modal="delete-user">
|
||||
<h1>Ready to go? Here’s what happens next</h1>
|
||||
</header>
|
||||
<button class="close" title="Close" {{on "click" this.closeModal}}>{{svg-jar "close"}}<span class="hidden">Close</span></button>
|
||||
|
||||
<div class="modal-body" {{did-insert this.countRecipients}}>
|
||||
{{#if this.countRecipientsTask.isRunning}}
|
||||
<div class="flex flex-column items-center">
|
||||
<div class="gh-loading-spinner"></div>
|
||||
</div>
|
||||
{{else}}
|
||||
<p>
|
||||
Your post will be delivered to
|
||||
<strong>{{this.memberCount}}</strong>
|
||||
{{#if this.model.emailOnly}}
|
||||
but it will <strong>not</strong>
|
||||
{{else}}
|
||||
and will
|
||||
{{/if}}
|
||||
be published on your site{{#if this.model.isScheduled}} at the scheduled time{{/if}}. Sound good?
|
||||
</p>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button {{on "click" this.closeModal}} class="gh-btn" data-test-button="cancel-publish-and-email">
|
||||
<span>Cancel</span>
|
||||
</button>
|
||||
{{#if this.model.isScheduled}}
|
||||
<GhTaskButton
|
||||
@disabled={{this.countRecipientsTask.isRunning}}
|
||||
@buttonText="Schedule"
|
||||
@runningText="Scheduling..."
|
||||
@task={{this.confirmAndCheckErrorTask}}
|
||||
@class="gh-btn gh-btn-black gh-btn-icon"
|
||||
data-test-button="confirm-publish-and-email"
|
||||
/>
|
||||
{{else}}
|
||||
<GhTaskButton
|
||||
@disabled={{this.countRecipientsTask.isRunning}}
|
||||
@buttonText={{if this.model.emailOnly "Send" "Publish and send"}}
|
||||
@runningText={{if this.model.emailOnly "Sending..." "Publishing..."}}
|
||||
@task={{this.confirmAndCheckErrorTask}}
|
||||
@class="gh-btn gh-btn-black gh-btn-icon"
|
||||
data-test-button="confirm-publish-and-email"
|
||||
/>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
{{else}}
|
||||
<header class="modal-header" data-test-modal="delete-user">
|
||||
<h1>Failed to send email</h1>
|
||||
</header>
|
||||
<button class="close" title="Close" {{on "click" this.closeModal}}>{{svg-jar "close"}}<span class="hidden">Close</span></button>
|
||||
|
||||
<div class="modal-body">
|
||||
<p>Your post has been published but the email failed to send. Please verify your email settings if the error persists.</p>
|
||||
<p class="mb0">
|
||||
<button type="button" class="gh-btn gh-btn-text regular" {{action (toggle "errorDetailsOpen" this)}} data-test-toggle-error>
|
||||
{{#if this.errorDetailsOpen}}
|
||||
{{svg-jar "arrow-down" class="nudge-top--2 w2 h2 fill-darkgrey mr1"}}
|
||||
{{else}}
|
||||
{{svg-jar "arrow-right" class="nudge-top--1 w2 h2 fill-darkgrey mr1"}}
|
||||
{{/if}}
|
||||
<span>Error details</span>
|
||||
</button>
|
||||
</p>
|
||||
|
||||
{{#liquid-if this.errorDetailsOpen}}
|
||||
<p class="error gh-box gh-box-error mt3 mb3">
|
||||
{{svg-jar "warning"}}
|
||||
{{this.errorMessage}}
|
||||
</p>
|
||||
{{/liquid-if}}
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button {{on "click" this.closeModal}} class="gh-btn" data-test-button="cancel-publish-and-email">
|
||||
<span>Close</span>
|
||||
</button>
|
||||
<GhTaskButton
|
||||
@buttonText="Retry email"
|
||||
@runningText="Sending..."
|
||||
@task={{this.retryEmailTask}}
|
||||
@class="gh-btn gh-btn-red gh-btn-icon"
|
||||
data-test-button="retry-email"
|
||||
/>
|
||||
</div>
|
||||
{{/unless}}
|
@ -1,80 +0,0 @@
|
||||
import ModalComponent from 'ghost-admin/components/modal-base';
|
||||
import {action} from '@ember/object';
|
||||
import {inject as service} from '@ember/service';
|
||||
import {task} from 'ember-concurrency';
|
||||
|
||||
export default ModalComponent.extend({
|
||||
membersCountCache: service(),
|
||||
session: service(),
|
||||
store: service(),
|
||||
|
||||
errorMessage: null,
|
||||
memberCount: null,
|
||||
|
||||
// Allowed actions
|
||||
confirm: () => {},
|
||||
|
||||
actions: {
|
||||
confirm() {
|
||||
if (this.errorMessage) {
|
||||
return this.retryEmailTask.perform();
|
||||
} else {
|
||||
if (!this.countRecipientsTask.isRunning) {
|
||||
return this.confirmAndCheckErrorTask.perform();
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
countRecipients: action(function () {
|
||||
this.countRecipientsTask.perform();
|
||||
}),
|
||||
|
||||
countRecipientsTask: task(function* () {
|
||||
const {sendEmailWhenPublished} = this.model;
|
||||
const filter = `subscribed:true+(${sendEmailWhenPublished})`;
|
||||
const result = sendEmailWhenPublished ? yield this.membersCountCache.countString(filter) : 'no members';
|
||||
this.set('memberCount', result);
|
||||
}),
|
||||
|
||||
confirmAndCheckErrorTask: task(function* () {
|
||||
try {
|
||||
yield this.confirm();
|
||||
this.closeModal();
|
||||
return true;
|
||||
} catch (e) {
|
||||
// switch to "failed" state if email fails
|
||||
if (e && e.name === 'EmailFailedError') {
|
||||
this.set('errorMessage', e.message);
|
||||
return;
|
||||
}
|
||||
|
||||
// close modal and continue with normal error handling if it was
|
||||
// a non-email-related error
|
||||
this.closeModal();
|
||||
if (e) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}),
|
||||
|
||||
retryEmailTask: task(function* () {
|
||||
try {
|
||||
yield this.model.retryEmailSend();
|
||||
this.closeModal();
|
||||
return true;
|
||||
} catch (e) {
|
||||
// update "failed" state if email fails again
|
||||
if (e && e.name === 'EmailFailedError') {
|
||||
this.set('errorMessage', e.message);
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: test a non-email failure - maybe this needs to go through
|
||||
// the notifications service
|
||||
if (e) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
116
ghost/admin/app/components/modals/editor/confirm-publish.hbs
Normal file
116
ghost/admin/app/components/modals/editor/confirm-publish.hbs
Normal file
@ -0,0 +1,116 @@
|
||||
<div class="modal-content" data-test-modal="editor/confirm-publish">
|
||||
{{#unless this.errorMessage}}
|
||||
<header class="modal-header" data-test-state="confirm-publish">
|
||||
<h1>Ready to go? Here’s what happens next</h1>
|
||||
</header>
|
||||
<button class="close" title="Close" {{on "click" @close}}>{{svg-jar "close"}}<span class="hidden">Close</span></button>
|
||||
|
||||
<div class="modal-body" {{did-insert this.countRecipientsTask.perform}}>
|
||||
{{#if (eq @data.post.displayName 'page')}}
|
||||
<p>
|
||||
Your page will be published {{if @data.isScheduled "at the scheduled time" "immediately"}}. Sound good?
|
||||
</p>
|
||||
{{else if this.isPublishOnly}}
|
||||
<p>
|
||||
Your post will be published {{if @data.isScheduled "at the scheduled time" "immediately"}}
|
||||
and won't be sent as an email. Sound good?
|
||||
</p>
|
||||
{{else}}
|
||||
{{#if this.countRecipientsTask.isRunning}}
|
||||
<div class="flex flex-column items-center">
|
||||
<div class="gh-loading-spinner"></div>
|
||||
</div>
|
||||
{{else}}
|
||||
{{#if this.isEmailOnlyWithNoMembers}}
|
||||
<p>
|
||||
You're trying to {{if @data.isScheduled "schedule" "send"}} a post
|
||||
as an email newsletter with <strong>0 members</strong> selected.
|
||||
Choose a segment of your audience and try again!
|
||||
</p>
|
||||
{{else}}
|
||||
<p>
|
||||
Your post will be delivered to <strong>{{this.memberCountString}}</strong>
|
||||
{{#if @data.emailOnly}}
|
||||
but it will <strong>not</strong>
|
||||
{{else}}
|
||||
and will
|
||||
{{/if}}
|
||||
be published on your site{{#if @data.isScheduled}} at the scheduled time{{/if}}. Sound good?
|
||||
</p>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
{{#if this.isEmailOnlyWithNoMembers}}
|
||||
<button type="button" class="gh-btn" {{on "click" @close}} data-test-button="cancel-email-with-no-members">
|
||||
<span>Close</span>
|
||||
</button>
|
||||
{{else}}
|
||||
<button {{on "click" @close}} class="gh-btn" data-test-button="cancel-publish-and-email">
|
||||
<span>Cancel</span>
|
||||
</button>
|
||||
{{#if @data.isScheduled}}
|
||||
<GhTaskButton
|
||||
@disabled={{this.countRecipientsTask.isRunning}}
|
||||
@buttonText="Schedule"
|
||||
@runningText="Scheduling..."
|
||||
@task={{this.confirmAndCheckErrorTask}}
|
||||
@class="gh-btn gh-btn-black gh-btn-icon"
|
||||
data-test-button="confirm-schedule"
|
||||
/>
|
||||
{{else}}
|
||||
<GhTaskButton
|
||||
@disabled={{this.countRecipientsTask.isRunning}}
|
||||
@buttonText={{this.publishAndSendButtonText}}
|
||||
@runningText={{if @data.emailOnly "Sending..." "Publishing..."}}
|
||||
@task={{this.confirmAndCheckErrorTask}}
|
||||
@class="gh-btn gh-btn-black gh-btn-icon"
|
||||
data-test-button="confirm-publish"
|
||||
/>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
{{else}}
|
||||
<header class="modal-header" data-test-state="failed-send">
|
||||
<h1>Failed to send email</h1>
|
||||
</header>
|
||||
<button class="close" title="Close" {{on "click" @close}}>{{svg-jar "close"}}<span class="hidden">Close</span></button>
|
||||
|
||||
<div class="modal-body">
|
||||
<p>Your post has been published but the email failed to send. Please verify your email settings if the error persists.</p>
|
||||
<p class="mb0">
|
||||
<button type="button" class="gh-btn gh-btn-text regular" {{on "click" this.toggleErrorDetails}} data-test-toggle-error>
|
||||
{{#if this.errorDetailsOpen}}
|
||||
{{svg-jar "arrow-down" class="nudge-top--2 w2 h2 fill-darkgrey mr1"}}
|
||||
{{else}}
|
||||
{{svg-jar "arrow-right" class="nudge-top--1 w2 h2 fill-darkgrey mr1"}}
|
||||
{{/if}}
|
||||
<span>Error details</span>
|
||||
</button>
|
||||
</p>
|
||||
|
||||
{{#liquid-if this.errorDetailsOpen}}
|
||||
<p class="error gh-box gh-box-error mt3 mb3">
|
||||
{{svg-jar "warning"}}
|
||||
{{this.errorMessage}}
|
||||
</p>
|
||||
{{/liquid-if}}
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button {{on "click" @close}} class="gh-btn" data-test-button="cancel-publish-and-email">
|
||||
<span>Close</span>
|
||||
</button>
|
||||
<GhTaskButton
|
||||
@buttonText="Retry email"
|
||||
@runningText="Sending..."
|
||||
@task={{this.retryEmailTask}}
|
||||
@class="gh-btn gh-btn-red gh-btn-icon"
|
||||
data-test-button="retry-email"
|
||||
/>
|
||||
</div>
|
||||
{{/unless}}
|
||||
</div>
|
117
ghost/admin/app/components/modals/editor/confirm-publish.js
Normal file
117
ghost/admin/app/components/modals/editor/confirm-publish.js
Normal file
@ -0,0 +1,117 @@
|
||||
import Component from '@glimmer/component';
|
||||
import {action} from '@ember/object';
|
||||
import {inject as service} from '@ember/service';
|
||||
import {task} from 'ember-concurrency-decorators';
|
||||
import {tracked} from '@glimmer/tracking';
|
||||
|
||||
export default class ModalsEditorConfirmPublishComponent extends Component {
|
||||
@service membersCountCache;
|
||||
@service session;
|
||||
@service store;
|
||||
|
||||
@tracked errorMessage = null;
|
||||
@tracked errorDetailsOpen = false;
|
||||
@tracked memberCount = null;
|
||||
@tracked memberCountString = null;
|
||||
|
||||
get isPublishOnly() {
|
||||
return this.args.data.sendEmailWhenPublished === 'none'
|
||||
|| this.args.data.post.displayName === 'page'
|
||||
|| this.args.data.post.email;
|
||||
}
|
||||
|
||||
get isEmailOnly() {
|
||||
return this.args.data.emailOnly;
|
||||
}
|
||||
|
||||
get isEmailOnlyWithNoMembers() {
|
||||
return this.isEmailOnly && this.memberCount === 0;
|
||||
}
|
||||
|
||||
get publishAndSendButtonText() {
|
||||
if (this.isEmailOnly) {
|
||||
return 'Send';
|
||||
}
|
||||
|
||||
if (this.isPublishOnly || this.memberCount === 0) {
|
||||
return 'Publish';
|
||||
}
|
||||
|
||||
return 'Publish and Send';
|
||||
}
|
||||
|
||||
@action
|
||||
confirm() {
|
||||
if (this.errorMessage) {
|
||||
return this.retryEmailTask.perform();
|
||||
} else {
|
||||
if (!this.countRecipientsTask.isRunning) {
|
||||
return this.confirmAndCheckErrorTask.perform();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
toggleErrorDetails() {
|
||||
this.errorDetailsOpen = !this.errorDetailsOpen;
|
||||
}
|
||||
|
||||
@task
|
||||
*countRecipientsTask() {
|
||||
const {sendEmailWhenPublished} = this.args.data;
|
||||
|
||||
if (sendEmailWhenPublished === 'none') {
|
||||
this.memberCount = 0;
|
||||
this.memberCountString = 'no members';
|
||||
}
|
||||
|
||||
const filter = `subscribed:true+(${sendEmailWhenPublished})`;
|
||||
|
||||
this.memberCount = sendEmailWhenPublished ? yield this.membersCountCache.count(filter) : 0;
|
||||
this.memberCountString = sendEmailWhenPublished ? yield this.membersCountCache.countString(filter) : 'no members';
|
||||
}
|
||||
|
||||
@task
|
||||
*confirmAndCheckErrorTask() {
|
||||
try {
|
||||
yield this.args.data.confirm();
|
||||
this.args.close();
|
||||
return true;
|
||||
} catch (e) {
|
||||
// switch to "failed" state if email fails
|
||||
if (e && e.name === 'EmailFailedError') {
|
||||
this.errorMessage = e.message;
|
||||
return false;
|
||||
}
|
||||
|
||||
// close modal and continue with normal error handling if it was
|
||||
// a non-email-related error
|
||||
this.args.close();
|
||||
|
||||
if (e) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@task
|
||||
*retryEmailTask() {
|
||||
try {
|
||||
yield this.args.data.retryEmailSend();
|
||||
this.args.close();
|
||||
return true;
|
||||
} catch (e) {
|
||||
// update "failed" state if email fails again
|
||||
if (e && e.name === 'EmailFailedError') {
|
||||
this.errorMessage = e.message;
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: test a non-email failure - maybe this needs to go through
|
||||
// the notifications service
|
||||
if (e) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -208,8 +208,10 @@ describe('Acceptance: Editor', function () {
|
||||
'draft post publish button text'
|
||||
).to.equal('Publish');
|
||||
|
||||
// Publish the post
|
||||
// Publish the post and re-open publish menu
|
||||
await click('[data-test-publishmenu-save]');
|
||||
await click('[data-test-button="confirm-publish"]');
|
||||
await click('[data-test-publishmenu-trigger]');
|
||||
|
||||
expect(
|
||||
find('[data-test-publishmenu-save]').textContent.trim(),
|
||||
@ -341,6 +343,8 @@ describe('Acceptance: Editor', function () {
|
||||
|
||||
await datepickerSelect('[data-test-publishmenu-draft] [data-test-date-time-picker-datepicker]', new Date(newFutureTime.format().replace(/\+.*$/, '')));
|
||||
await click('[data-test-publishmenu-save]');
|
||||
await click('[data-test-button="confirm-schedule"]');
|
||||
await click('[data-test-publishmenu-trigger]');
|
||||
|
||||
expect(
|
||||
find('[data-test-publishmenu-save]').textContent.trim(),
|
||||
@ -451,6 +455,7 @@ describe('Acceptance: Editor', function () {
|
||||
await blur('[data-test-publishmenu-draft] [data-test-date-time-picker-time-input]');
|
||||
|
||||
await click('[data-test-publishmenu-save]');
|
||||
await click('[data-test-button="confirm-schedule"]');
|
||||
|
||||
expect(
|
||||
findAll('.gh-alert').length,
|
||||
@ -475,6 +480,7 @@ describe('Acceptance: Editor', function () {
|
||||
await fillIn('[data-test-editor-title-input]', Array(260).join('a'));
|
||||
await click('[data-test-publishmenu-trigger]');
|
||||
await click('[data-test-publishmenu-save]');
|
||||
await click('[data-test-button="confirm-publish"]');
|
||||
|
||||
expect(
|
||||
findAll('.gh-alert').length,
|
||||
|
@ -38,7 +38,8 @@ describe('Acceptance: Error Handling', function () {
|
||||
await visit('/posts');
|
||||
await click('.posts-list li:nth-of-type(2) a'); // select second post
|
||||
await click('[data-test-publishmenu-trigger]');
|
||||
await click('[data-test-publishmenu-save]'); // "Save post"
|
||||
await click('[data-test-publishmenu-save]');
|
||||
await click('[data-test-button="confirm-publish"]'); // "Save post"
|
||||
|
||||
// has the refresh to update alert
|
||||
expect(findAll('.gh-alert').length).to.equal(1);
|
||||
@ -100,6 +101,7 @@ describe('Acceptance: Error Handling', function () {
|
||||
await visit('/editor/post/1');
|
||||
await click('[data-test-publishmenu-trigger]');
|
||||
await click('[data-test-publishmenu-save]');
|
||||
await click('[data-test-button="confirm-publish"]');
|
||||
|
||||
expect(findAll('.gh-alert').length).to.equal(1);
|
||||
expect(find('.gh-alert').textContent).to.not.match(/html>/);
|
||||
|
Loading…
Reference in New Issue
Block a user