switch all modals over to ember-concurrency and gh-task-button

This commit is contained in:
Kevin Ansfield 2017-01-19 11:40:31 +00:00
parent 0e7d455351
commit 01cc9ae9be
22 changed files with 195 additions and 164 deletions

View File

@ -1,10 +1,9 @@
import injectService from 'ember-service/inject';
import ModalComponent from 'ghost-admin/components/modals/base';
import {task} from 'ember-concurrency';
export default ModalComponent.extend({
submitting: false,
ghostPaths: injectService(),
notifications: injectService(),
store: injectService(),
@ -28,18 +27,21 @@ export default ModalComponent.extend({
this.get('notifications').showAPIError(error, {key: 'all-content.delete'});
},
deleteAll: task(function* () {
try {
yield this._deleteAll();
this._unloadData();
this._showSuccess();
} catch (error) {
this._showFailure(error);
} finally {
this.send('closeModal');
}
}).drop(),
actions: {
confirm() {
this.set('submitting', true);
this._deleteAll().then(() => {
this._unloadData();
this._showSuccess();
}).catch((error) => {
this._showFailure(error);
}).finally(() => {
this.send('closeModal');
});
this.get('deleteAll').perform();
}
}
});

View File

@ -1,11 +1,10 @@
import {alias} from 'ember-computed';
import injectService from 'ember-service/inject';
import ModalComponent from 'ghost-admin/components/modals/base';
import {task} from 'ember-concurrency';
export default ModalComponent.extend({
submitting: false,
post: alias('model'),
notifications: injectService(),
@ -33,17 +32,20 @@ export default ModalComponent.extend({
this.get('notifications').showAPIError(error, {key: 'post.delete.failed'});
},
deletePost: task(function* () {
try {
yield this._deletePost();
this._success();
} catch (e) {
this._failure(e);
} finally {
this.send('closeModal');
}
}).drop(),
actions: {
confirm() {
this.set('submitting', true);
this._deletePost().then(() => {
this._success();
}, (error) => {
this._failure(error);
}).finally(() => {
this.send('closeModal');
});
this.get('deletePost').perform();
}
}
});

View File

@ -1,20 +1,19 @@
import {alias} from 'ember-computed';
import ModalComponent from 'ghost-admin/components/modals/base';
import {invokeAction} from 'ember-invoke-action';
import {task} from 'ember-concurrency';
export default ModalComponent.extend({
submitting: false,
subscriber: alias('model'),
deleteSubscriber: task(function* () {
yield invokeAction(this, 'confirm');
}).drop(),
actions: {
confirm() {
this.set('submitting', true);
invokeAction(this, 'confirm').finally(() => {
this.set('submitting', false);
});
this.get('deleteSubscriber').perform();
}
}
});

View File

@ -1,24 +1,27 @@
import computed, {alias} from 'ember-computed';
import ModalComponent from 'ghost-admin/components/modals/base';
import {invokeAction} from 'ember-invoke-action';
import {task} from 'ember-concurrency';
export default ModalComponent.extend({
submitting: false,
tag: alias('model'),
postInflection: computed('tag.count.posts', function () {
return this.get('tag.count.posts') > 1 ? 'posts' : 'post';
}),
deleteTag: task(function* () {
try {
yield invokeAction(this, 'confirm');
} finally {
this.send('closeModal');
}
}).drop(),
actions: {
confirm() {
this.set('submitting', true);
invokeAction(this, 'confirm').finally(() => {
this.send('closeModal');
});
this.get('deleteTag').perform();
}
}
});

View File

@ -1,21 +1,24 @@
import ModalComponent from 'ghost-admin/components/modals/base';
import {alias} from 'ember-computed';
import {invokeAction} from 'ember-invoke-action';
import {task} from 'ember-concurrency';
export default ModalComponent.extend({
submitting: false,
theme: alias('model.theme'),
download: alias('model.download'),
deleteTheme: task(function* () {
try {
yield invokeAction(this, 'confirm');
} finally {
this.send('closeModal');
}
}).drop(),
actions: {
confirm() {
this.set('submitting', true);
invokeAction(this, 'confirm').finally(() => {
this.send('closeModal');
});
this.get('deleteTheme').perform();
}
}
});

View File

@ -1,20 +1,23 @@
import ModalComponent from 'ghost-admin/components/modals/base';
import {invokeAction} from 'ember-invoke-action';
import {alias} from 'ember-computed';
import {task} from 'ember-concurrency';
export default ModalComponent.extend({
submitting: false,
user: alias('model'),
deleteUser: task(function* () {
try {
yield invokeAction(this, 'confirm');
} finally {
this.send('closeModal');
}
}).drop(),
actions: {
confirm() {
this.set('submitting', true);
invokeAction(this, 'confirm').finally(() => {
this.send('closeModal');
});
this.get('deleteUser').perform();
}
}
});

View File

@ -4,6 +4,7 @@ import {A as emberA} from 'ember-array/utils';
import run from 'ember-runloop';
import ModalComponent from 'ghost-admin/components/modals/base';
import ValidationEngine from 'ghost-admin/mixins/validation-engine';
import {task} from 'ember-concurrency';
const {Promise} = RSVP;
@ -13,7 +14,6 @@ export default ModalComponent.extend(ValidationEngine, {
role: null,
roles: null,
authorRole: null,
submitting: false,
validationType: 'inviteUser',
@ -85,42 +85,49 @@ export default ModalComponent.extend(ValidationEngine, {
});
},
sendInvitation: task(function* () {
let email = this.get('email');
let role = this.get('role');
let notifications = this.get('notifications');
let notificationText = `Invitation sent! (${email})`;
let invite;
try {
yield this.validate();
invite = this.get('store').createRecord('invite', {
email,
role
});
yield invite.save();
// If sending the invitation email fails, the API will still return a status of 201
// but the invite's status in the response object will be 'invited-pending'.
if (invite.get('status') === 'pending') {
notifications.showAlert('Invitation email was not sent. Please try resending.', {type: 'error', key: 'invite.send.failed'});
} else {
notifications.showNotification(notificationText, {key: 'invite.send.success'});
}
this.send('closeModal');
} catch (error) {
// validation will reject and cause this to be called with no error
if (error) {
invite.deleteRecord();
notifications.showAPIError(error, {key: 'invite.send'});
this.send('closeModal');
}
}
}).drop(),
actions: {
setRole(role) {
this.set('role', role);
},
confirm() {
let email = this.get('email');
let role = this.get('role');
let notifications = this.get('notifications');
let invite;
this.validate().then(() => {
this.set('submitting', true);
invite = this.get('store').createRecord('invite', {
email,
role
});
invite.save().then(() => {
let notificationText = `Invitation sent! (${email})`;
// If sending the invitation email fails, the API will still return a status of 201
// but the invite's status in the response object will be 'invited-pending'.
if (invite.get('status') === 'pending') {
notifications.showAlert('Invitation email was not sent. Please try resending.', {type: 'error', key: 'invite.send.failed'});
} else {
notifications.showNotification(notificationText, {key: 'invite.send.success'});
}
}).catch((error) => {
invite.deleteRecord();
notifications.showAPIError(error, {key: 'invite.send'});
}).finally(() => {
this.send('closeModal');
});
});
this.get('sendInvitation').perform();
}
}
});

View File

@ -1,8 +1,35 @@
import {A as emberA} from 'ember-array/utils';
import ModalComponent from 'ghost-admin/components/modals/base';
import {isInvalidError} from 'ember-ajax/errors';
import {task} from 'ember-concurrency';
export default ModalComponent.extend({
addSubscriber: task(function* () {
try {
yield this.get('confirm')();
this.send('closeModal');
} catch (error) {
// TODO: server-side validation errors should be serialized
// properly so that errors are added to the model's errors
// property
if (error && isInvalidError(error)) {
let [firstError] = error.errors;
let {message} = firstError;
if (message && message.match(/email/i)) {
this.get('model.errors').add('email', message);
this.get('model.hasValidated').pushObject('email');
return;
}
}
// this is a route action so it should bubble up to the global
// error handler
throw error;
}
}).drop(),
actions: {
updateEmail(newEmail) {
this.set('model.email', newEmail);
@ -11,35 +38,7 @@ export default ModalComponent.extend({
},
confirm() {
let confirmAction = this.get('confirm');
this.set('submitting', true);
confirmAction().then(() => {
this.send('closeModal');
}).catch((error) => {
// TODO: server-side validation errors should be serialized
// properly so that errors are added to the model's errors
// property
if (error && isInvalidError(error)) {
let [firstError] = error.errors;
let {message} = firstError;
if (message && message.match(/email/i)) {
this.get('model.errors').add('email', message);
this.get('model.hasValidated').pushObject('email');
return;
}
}
// this is a route action so it should bubble up to the global
// error handler
throw error;
}).finally(() => {
if (!this.get('isDestroying') && !this.get('isDestroyed')) {
this.set('submitting', false);
}
});
this.get('addSubscriber').perform();
}
}
});

View File

@ -5,11 +5,11 @@ import {htmlSafe} from 'ember-string';
import ModalComponent from 'ghost-admin/components/modals/base';
import ValidationEngine from 'ghost-admin/mixins/validation-engine';
import {isVersionMismatchError} from 'ghost-admin/services/ajax';
import {task} from 'ember-concurrency';
export default ModalComponent.extend(ValidationEngine, {
validationType: 'signin',
submitting: false,
authenticationError: null,
config: injectService(),
@ -44,7 +44,7 @@ export default ModalComponent.extend(ValidationEngine, {
this.set('authenticationError', null);
this.validate({property: 'signin'}).then(() => {
return this.validate({property: 'signin'}).then(() => {
this._authenticate().then(() => {
this.get('notifications').closeAlerts();
this.send('closeModal');
@ -74,7 +74,7 @@ export default ModalComponent.extend(ValidationEngine, {
this.toggleProperty('submitting');
this.set('authenticationError', '');
this.get('torii')
return this.get('torii')
.open('ghost-oauth2', {type: 'signin'})
.then((authentication) => {
this.get('session').set('skipAuthSuccessHandler', true);
@ -93,13 +93,17 @@ export default ModalComponent.extend(ValidationEngine, {
});
},
reauthenticate: task(function* () {
if (this.get('config.ghostOAuth')) {
yield this._oauthConfirm();
} else {
yield this._passwordConfirm();
}
}).drop(),
actions: {
confirm() {
if (this.get('config.ghostOAuth')) {
return this._oauthConfirm();
} else {
return this._passwordConfirm();
}
this.get('reauthenticate').perform();
}
}
});

View File

@ -1,17 +1,21 @@
import ModalComponent from 'ghost-admin/components/modals/base';
import {invokeAction} from 'ember-invoke-action';
import {task} from 'ember-concurrency';
export default ModalComponent.extend({
user: null,
submitting: false,
transferOwnership: task(function* () {
try {
yield invokeAction(this, 'confirm');
} finally {
this.send('closeModal');
}
}).drop(),
actions: {
confirm() {
this.set('submitting', true);
invokeAction(this, 'confirm').finally(() => {
this.send('closeModal');
});
this.get('transferOwnership').perform();
}
}
});

View File

@ -3,10 +3,10 @@ import injectService from 'ember-service/inject';
import {isEmpty} from 'ember-utils';
import ModalComponent from 'ghost-admin/components/modals/base';
import cajaSanitizers from 'ghost-admin/utils/caja-sanitizers';
import {task} from 'ember-concurrency';
export default ModalComponent.extend({
model: null,
submitting: false,
url: '',
newUrl: '',
@ -65,6 +65,25 @@ export default ModalComponent.extend({
},
// end validation
uploadImage: task(function* () {
let model = this.get('model.model');
let newUrl = this.get('newUrl');
let result = this._validateUrl(newUrl);
let notifications = this.get('notifications');
if (result === true) {
this.set('image', newUrl);
try {
yield model.save();
} catch (e) {
notifications.showAPIError(e, {key: 'image.upload'});
} finally {
this.send('closeModal');
}
}
}).drop(),
actions: {
fileUploaded(url) {
this.set('url', url);
@ -77,21 +96,7 @@ export default ModalComponent.extend({
},
confirm() {
let model = this.get('model.model');
let newUrl = this.get('newUrl');
let result = this._validateUrl(newUrl);
let notifications = this.get('notifications');
if (result === true) {
this.set('submitting', true);
this.set('image', newUrl);
model.save().catch((err) => {
notifications.showAPIError(err, {key: 'image.upload'});
}).finally(() => {
this.send('closeModal');
});
}
this.get('uploadImage').perform();
}
}
});

View File

@ -9,5 +9,5 @@
<div class="modal-footer">
<button {{action "closeModal"}} class="btn btn-default btn-minor">Cancel</button>
{{#gh-spin-button action="confirm" class="btn btn-red" submitting=submitting}}Delete{{/gh-spin-button}}
</div>
{{#gh-task-button task=deleteAll class="btn btn-red"}}Delete{{/gh-task-button}}
</div>

View File

@ -13,5 +13,5 @@
<div class="modal-footer">
<button {{action "closeModal"}} class="btn btn-default btn-minor">Cancel</button>
{{#gh-spin-button action="confirm" class="btn btn-red" submitting=submitting}}Delete{{/gh-spin-button}}
</div>
{{#gh-task-button task=deletePost class="btn btn-red"}}Delete{{/gh-task-button}}
</div>

View File

@ -9,5 +9,5 @@
<div class="modal-footer">
<button {{action "closeModal"}} class="btn btn-default btn-minor">Cancel</button>
{{#gh-spin-button action="confirm" class="btn btn-red" submitting=submitting}}Delete{{/gh-spin-button}}
</div>
{{#gh-task-button task=deleteSubscriber class="btn btn-red"}}Delete{{/gh-task-button}}
</div>

View File

@ -13,5 +13,5 @@
<div class="modal-footer">
<button {{action "closeModal"}} class="btn btn-default btn-minor">Cancel</button>
{{#gh-spin-button action="confirm" class="btn btn-red" submitting=submitting}}Delete{{/gh-spin-button}}
</div>
{{#gh-task-button task=deleteTag class="btn btn-red"}}Delete{{/gh-task-button}}
</div>

View File

@ -16,5 +16,5 @@
<div class="modal-footer">
<button {{action "closeModal"}} class="btn btn-default btn-minor">Cancel</button>
{{#gh-spin-button action="confirm" class="btn btn-red" submitting=submitting}}Delete{{/gh-spin-button}}
</div>
{{#gh-task-button task=deleteTheme class="btn btn-red"}}Delete{{/gh-task-button}}
</div>

View File

@ -13,5 +13,5 @@
<div class="modal-footer">
<button {{action "closeModal"}} class="btn btn-default btn-minor">Cancel</button>
{{#gh-spin-button action="confirm" class="btn btn-red" submitting=submitting}}Delete{{/gh-spin-button}}
</div>
{{#gh-task-button task=deleteUser class="btn btn-red"}}Delete{{/gh-task-button}}
</div>

View File

@ -42,5 +42,5 @@
</div>
<div class="modal-footer">
{{#gh-spin-button action="confirm" class="btn btn-green" submitting=submitting}}Send invitation now{{/gh-spin-button}}
</div>
{{#gh-task-button task=sendInvitation class="btn btn-green"}}Send invitation now{{/gh-task-button}}
</div>

View File

@ -25,5 +25,5 @@
<div class="modal-footer">
<button {{action "closeModal"}} class="btn btn-default btn-minor">Cancel</button>
{{#gh-spin-button action="confirm" class="btn btn-green" submitting=submitting}}Add{{/gh-spin-button}}
</div>
{{#gh-task-button task=addSubscriber class="btn btn-green"}}Add{{/gh-task-button}}
</div>

View File

@ -6,17 +6,17 @@
<div class="modal-body {{if authenticationError 'error'}}">
{{#if config.ghostOAuth}}
{{#gh-spin-button class="login btn btn-blue btn-block" type="submit" action="confirm" tabindex="3" submitting=loggingIn autoWidth="false"}}Sign in with Ghost{{/gh-spin-button}}
{{#gh-task-button task=reauthenticate class="login btn btn-blue btn-block" tabindex="3" autoWidth="false"}}Sign in with Ghost{{/gh-task-button}}
{{else}}
<form id="login" class="login-form" method="post" novalidate="novalidate" {{action "confirm" on="submit"}}>
{{#gh-validation-status-container class="password-wrap" errors=errors property="password" hasValidated=hasValidated}}
{{gh-input password class="password" type="password" placeholder="Password" name="password" update=(action (mut password))}}
{{/gh-validation-status-container}}
{{#gh-spin-button class="btn btn-blue" type="submit" submitting=submitting}}Log in{{/gh-spin-button}}
{{#gh-task-button task=reauthenticate class="btn btn-blue" type="submit"}}Log in{{/gh-task-button}}
</form>
{{/if}}
{{#if authenticationError}}
<p class="response">{{authenticationError}}</p>
{{/if}}
</div>
</div>

View File

@ -12,5 +12,5 @@
<div class="modal-footer">
<button {{action "closeModal"}} class="btn btn-default btn-minor">Cancel</button>
{{#gh-spin-button action="confirm" class="btn btn-red" submitting=submitting}}Yep - I'm sure{{/gh-spin-button}}
</div>
{{#gh-task-button task=transferOwnership class="btn btn-red"}}Yep - I'm sure{{/gh-task-button}}
</div>

View File

@ -18,5 +18,5 @@
<div class="modal-footer">
<button {{action "closeModal"}} class="btn btn-default btn-minor">Cancel</button>
{{#gh-spin-button action="confirm" class="btn btn-blue right js-button-accept" submitting=submitting}}Save{{/gh-spin-button}}
</div>
{{#gh-task-button task=uploadImage class="btn btn-blue right js-button-accept"}}Save{{/gh-task-button}}
</div>