diff --git a/ghost/admin/app/components/modal-delete-webhook.hbs b/ghost/admin/app/components/modal-delete-webhook.hbs
deleted file mode 100644
index 3e91094906..0000000000
--- a/ghost/admin/app/components/modal-delete-webhook.hbs
+++ /dev/null
@@ -1,15 +0,0 @@
-
-{{svg-jar "close"}}Close
-
-
-
- Deleting this webhook may prevent the integration from functioning.
-
-
-
-
\ No newline at end of file
diff --git a/ghost/admin/app/components/modal-delete-webhook.js b/ghost/admin/app/components/modal-delete-webhook.js
deleted file mode 100644
index b39eeb90e3..0000000000
--- a/ghost/admin/app/components/modal-delete-webhook.js
+++ /dev/null
@@ -1,26 +0,0 @@
-import ModalComponent from 'ghost-admin/components/modal-base';
-import {alias} from '@ember/object/computed';
-import {inject as service} from '@ember/service';
-import {task} from 'ember-concurrency';
-
-export default ModalComponent.extend({
- notifications: service(),
-
- webhook: alias('model'),
-
- actions: {
- confirm() {
- this.deleteWebhook.perform();
- }
- },
-
- deleteWebhook: task(function* () {
- try {
- yield this.confirm();
- } catch (error) {
- this.notifications.showAPIError(error, {key: 'webhook.delete.failed'});
- } finally {
- this.send('closeModal');
- }
- }).drop()
-});
diff --git a/ghost/admin/app/components/modal-webhook-form.hbs b/ghost/admin/app/components/modal-webhook-form.hbs
deleted file mode 100644
index a4dcf2f95d..0000000000
--- a/ghost/admin/app/components/modal-webhook-form.hbs
+++ /dev/null
@@ -1,103 +0,0 @@
-
-
-
-
-
- {{#if (enable-developer-experiments)}}
-
- {{/if}}
- {{#if this.error}}
-
{{this.error}}
- {{/if}}
-
-
-
diff --git a/ghost/admin/app/components/modal-webhook-form.js b/ghost/admin/app/components/modal-webhook-form.js
deleted file mode 100644
index 51f183ee32..0000000000
--- a/ghost/admin/app/components/modal-webhook-form.js
+++ /dev/null
@@ -1,80 +0,0 @@
-import ModalComponent from 'ghost-admin/components/modal-base';
-import Webhook from 'ghost-admin/models/webhook';
-import {AVAILABLE_EVENTS} from 'ghost-admin/helpers/event-name';
-import {alias} from '@ember/object/computed';
-import {camelize} from '@ember/string';
-import {inject as service} from '@ember/service';
-import {task} from 'ember-concurrency';
-
-export default ModalComponent.extend({
- router: service(),
- feature: service(),
-
- availableEvents: null,
- error: null,
- buttonText: 'Save',
- successText: 'Saved',
-
- confirm() {},
-
- webhook: alias('model'),
-
- init() {
- this._super(...arguments);
- this.availableEvents = AVAILABLE_EVENTS;
- },
-
- didReceiveAttrs() {
- this._super(...arguments);
- if (this.webhook.isNew) {
- this.set('buttonText', 'Create');
- this.set('successText', 'Created');
- }
- },
-
- actions: {
- selectEvent(value) {
- this.webhook.set('event', value);
- this.webhook.validate({property: 'event'});
- },
-
- confirm() {
- this.saveWebhook.perform();
- }
- },
-
- saveWebhook: task(function* () {
- this.set('error', null);
-
- try {
- let webhook = yield this.confirm();
- let integration = yield webhook.get('integration');
- this.router.transitionTo('settings.integration', integration);
- } catch (e) {
- // TODO: server-side validation errors should be serialized
- // properly so that errors are added to model.errors automatically
- if (e && e.payload && e.payload.errors) {
- let attrs = Array.from(Webhook.attributes.keys());
-
- e.payload.errors.forEach((error) => {
- let {message, property = ''} = error;
- property = camelize(property);
-
- if (property && attrs.includes(property)) {
- this.webhook.errors.add(property, message);
- this.webhook.hasValidated.pushObject(property);
- } else {
- this.set('error', `Error: ${message}`);
- }
- });
-
- return;
- }
-
- // bubble up to the global error handler
- if (e) {
- throw e;
- }
- }
- })
-});
diff --git a/ghost/admin/app/components/settings/integrations/delete-webhook-modal.hbs b/ghost/admin/app/components/settings/integrations/delete-webhook-modal.hbs
new file mode 100644
index 0000000000..7f1b797923
--- /dev/null
+++ b/ghost/admin/app/components/settings/integrations/delete-webhook-modal.hbs
@@ -0,0 +1,17 @@
+
+
+
{{svg-jar "close"}}Close
+
+
+
+ Deleting this webhook may prevent the integration from functioning.
+
+
+
+
+
\ No newline at end of file
diff --git a/ghost/admin/app/components/settings/integrations/delete-webhook-modal.js b/ghost/admin/app/components/settings/integrations/delete-webhook-modal.js
new file mode 100644
index 0000000000..5c0563ccd6
--- /dev/null
+++ b/ghost/admin/app/components/settings/integrations/delete-webhook-modal.js
@@ -0,0 +1,28 @@
+import Component from '@glimmer/component';
+import {inject as service} from '@ember/service';
+import {task} from 'ember-concurrency';
+
+export default class DeleteWebhookModal extends Component {
+ @service notifications;
+ @service router;
+
+ @task({drop: true})
+ *deleteWebhookTask() {
+ try {
+ const {webhook} = this.args.data;
+
+ if (webhook.isDeleted) {
+ return true;
+ }
+
+ yield webhook.destroyRecord();
+
+ this.notifications.closeAlerts('webhook.delete');
+ return true;
+ } catch (error) {
+ this.notifications.showAPIError(error, {key: 'webhook.delete.failed'});
+ } finally {
+ this.args.close();
+ }
+ }
+}
diff --git a/ghost/admin/app/components/settings/integrations/webhook-form-modal.hbs b/ghost/admin/app/components/settings/integrations/webhook-form-modal.hbs
new file mode 100644
index 0000000000..4d1861ed4e
--- /dev/null
+++ b/ghost/admin/app/components/settings/integrations/webhook-form-modal.hbs
@@ -0,0 +1,110 @@
+
+
+ {{!-- template-lint-disable no-down-event-binding --}}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ghost/admin/app/components/settings/integrations/webhook-form-modal.js b/ghost/admin/app/components/settings/integrations/webhook-form-modal.js
new file mode 100644
index 0000000000..de556bed0f
--- /dev/null
+++ b/ghost/admin/app/components/settings/integrations/webhook-form-modal.js
@@ -0,0 +1,81 @@
+import Component from '@glimmer/component';
+import Webhook from 'ghost-admin/models/webhook';
+import {AVAILABLE_EVENTS} from 'ghost-admin/helpers/event-name';
+import {action} from '@ember/object';
+import {camelize} from '@ember/string';
+import {inject as service} from '@ember/service';
+import {task} from 'ember-concurrency';
+import {tracked} from '@glimmer/tracking';
+
+export default class WebhookFormModal extends Component {
+ @service notifications;
+ @service router;
+
+ availableEvents = AVAILABLE_EVENTS;
+ buttonText = this.args.data.webhook.isNew ? 'Create' : 'Save';
+ successText = this.args.data.webhook.isNew ? 'Created' : 'Saved';
+
+ @tracked error = null;
+
+ get webhook() {
+ return this.args.data.webhook;
+ }
+
+ @action
+ setProperty(property, event) {
+ this.webhook[property] = event.target.value;
+ }
+
+ @action
+ selectEvent(value) {
+ this.webhook.event = value;
+ this.webhook.validate({property: 'event'});
+ }
+
+ @action
+ validate(property) {
+ return this.webhook.validate({property});
+ }
+
+ @action
+ noop(event) {
+ event.preventDefault();
+ }
+
+ @task({drop: true})
+ *saveWebhookTask() {
+ this.error = null;
+
+ try {
+ const webhook = yield this.webhook.save();
+ const integration = yield webhook.integration;
+ this.router.transitionTo('settings.integration', integration);
+ return true;
+ } catch (e) {
+ // TODO: server-side validation errors should be serialized
+ // properly so that errors are added to model.errors automatically
+ if (e && e.payload && e.payload.errors) {
+ const attrs = Array.from(Webhook.attributes.keys());
+
+ e.payload.errors.forEach((error) => {
+ let {message, property = ''} = error;
+ property = camelize(property);
+
+ if (property && attrs.includes(property)) {
+ this.webhook.errors.add(property, message);
+ this.webhook.hasValidated.pushObject(property);
+ } else {
+ this.error = `Error: ${message}`;
+ }
+ });
+
+ return;
+ }
+
+ // bubble up to the global error handler
+ if (e) {
+ throw e;
+ }
+ }
+ }
+}
diff --git a/ghost/admin/app/controllers/settings/integration.js b/ghost/admin/app/controllers/settings/integration.js
index 0fbd69085d..a25e029d61 100644
--- a/ghost/admin/app/controllers/settings/integration.js
+++ b/ghost/admin/app/controllers/settings/integration.js
@@ -1,5 +1,6 @@
import Controller from '@ember/controller';
import DeleteIntegrationModal from '../../components/settings/integrations/delete-integration-modal';
+import DeleteWebhookModal from '../../components/settings/integrations/delete-webhook-modal';
import config from 'ghost-admin/config/environment';
import copyTextToClipboard from 'ghost-admin/utils/copy-text-to-clipboard';
import {
@@ -24,7 +25,6 @@ export default class IntegrationController extends Controller {
@tracked showUnsavedChangesModal = false;
@tracked selectedApiKey = null;
@tracked isApiKeyRegenerated = false;
- @tracked webhookToDelete;
constructor() {
super(...arguments);
@@ -180,13 +180,7 @@ export default class IntegrationController extends Controller {
@action
confirmWebhookDeletion(webhook, event) {
event?.preventDefault();
- this.webhookToDelete = webhook;
- }
-
- @action
- cancelWebhookDeletion(event) {
- event?.preventDefault();
- this.webhookToDelete = null;
+ return this.modals.open(DeleteWebhookModal, {webhook});
}
@action
diff --git a/ghost/admin/app/controllers/settings/integration/webhooks/edit.js b/ghost/admin/app/controllers/settings/integration/webhooks/edit.js
index 6e33dcf3c4..a1c986ec4f 100644
--- a/ghost/admin/app/controllers/settings/integration/webhooks/edit.js
+++ b/ghost/admin/app/controllers/settings/integration/webhooks/edit.js
@@ -1,28 +1,4 @@
import Controller from '@ember/controller';
-import classic from 'ember-classic-decorator';
-import {action} from '@ember/object';
-import {alias} from '@ember/object/computed';
-@classic
export default class EditController extends Controller {
- @alias('model')
- webhook;
-
- @action
- save() {
- return this.webhook.save();
- }
-
- @action
- cancel() {
- // 'new' route's dectivate hook takes care of rollback
- return this.webhook.get('integration').then((integration) => {
- this.transitionToRoute('settings.integration', integration);
- });
- }
-
- reset() {
- this.webhook.rollbackAttributes();
- this.webhook.errors.clear();
- }
}
diff --git a/ghost/admin/app/controllers/settings/integration/webhooks/new.js b/ghost/admin/app/controllers/settings/integration/webhooks/new.js
index 2032e2f2d0..2c1d6ff758 100644
--- a/ghost/admin/app/controllers/settings/integration/webhooks/new.js
+++ b/ghost/admin/app/controllers/settings/integration/webhooks/new.js
@@ -1,23 +1,4 @@
import Controller from '@ember/controller';
-import classic from 'ember-classic-decorator';
-import {action} from '@ember/object';
-import {alias} from '@ember/object/computed';
-@classic
-export default class NewController extends Controller {
- @alias('model')
- webhook;
-
- @action
- save() {
- return this.webhook.save();
- }
-
- @action
- cancel() {
- // 'new' route's dectivate hook takes care of rollback
- return this.webhook.get('integration').then((integration) => {
- this.transitionToRoute('settings.integration', integration);
- });
- }
+export default class NewWebhookController extends Controller {
}
diff --git a/ghost/admin/app/routes/settings/integration/webhooks/edit.js b/ghost/admin/app/routes/settings/integration/webhooks/edit.js
index b20ee342b7..4d6e9cd48b 100644
--- a/ghost/admin/app/routes/settings/integration/webhooks/edit.js
+++ b/ghost/admin/app/routes/settings/integration/webhooks/edit.js
@@ -1,14 +1,49 @@
import AdminRoute from 'ghost-admin/routes/admin';
+import WebhookFormModal from '../../../../components/settings/integrations/webhook-form-modal';
+import {action} from '@ember/object';
+import {inject as service} from '@ember/service';
+
+export default class EditWebhookRoute extends AdminRoute {
+ @service modals;
+ @service router;
+
+ webhook = null;
+ modal = null;
+
+ get integration() {
+ return this.modelFor('settings.integration');
+ }
-export default class EditRoute extends AdminRoute {
model(params) {
- let integration = this.modelFor('settings.integration');
- let webhook = integration.webhooks.findBy('id', params.webhook_id);
- return webhook;
+ return this.integration.webhooks.findBy('id', params.webhook_id);
+ }
+
+ setupController(controller, model) {
+ this.webhook = model;
+
+ this.modal = this.modals.open(WebhookFormModal, {
+ webhook: this.webhook
+ }, {
+ beforeClose: this.beforeModalClose
+ });
}
deactivate() {
- super.deactivate(...arguments);
- this.controller.reset();
+ this.webhook?.errors.clear();
+ this.webhook?.rollbackAttributes();
+
+ // ensure we don't try to redirect on modal close if we're already transitioning away
+ this.isLeaving = true;
+ this.modal?.close();
+
+ this.modal = null;
+ this.isLeaving = false;
+ }
+
+ @action
+ beforeModalClose() {
+ if (this.modal && !this.isLeaving) {
+ this.router.transitionTo('settings.integration', this.integration);
+ }
}
}
diff --git a/ghost/admin/app/routes/settings/integration/webhooks/new.js b/ghost/admin/app/routes/settings/integration/webhooks/new.js
index ce881bf0a0..f972b4f1d4 100644
--- a/ghost/admin/app/routes/settings/integration/webhooks/new.js
+++ b/ghost/admin/app/routes/settings/integration/webhooks/new.js
@@ -1,13 +1,45 @@
import AdminRoute from 'ghost-admin/routes/admin';
+import WebhookFormModal from '../../../../components/settings/integrations/webhook-form-modal';
+import {action} from '@ember/object';
+import {inject as service} from '@ember/service';
+
+export default class NewWebhookRoute extends AdminRoute {
+ @service modals;
+ @service router;
+
+ webhook = null;
+ modal = null;
+
+ get integration() {
+ return this.modelFor('settings.integration');
+ }
-export default class NewRoute extends AdminRoute {
model() {
- let integration = this.modelFor('settings.integration');
- return this.store.createRecord('webhook', {integration});
+ this.webhook = this.store.createRecord('webhook', {integration: this.integration});
+
+ this.modal = this.modals.open(WebhookFormModal, {
+ webhook: this.webhook
+ }, {
+ beforeClose: this.beforeModalClose
+ });
}
deactivate() {
- super.deactivate(...arguments);
- this.controller.webhook.rollbackAttributes();
+ this.webhook?.errors.clear();
+ this.webhook?.rollbackAttributes();
+
+ // ensure we don't try to redirect on modal close if we're already transitioning away
+ this.isLeaving = true;
+ this.modal?.close();
+
+ this.modal = null;
+ this.isLeaving = false;
+ }
+
+ @action
+ beforeModalClose() {
+ if (this.modal && !this.isLeaving) {
+ this.router.transitionTo('settings.integration', this.integration);
+ }
}
}
diff --git a/ghost/admin/app/templates/settings/integration.hbs b/ghost/admin/app/templates/settings/integration.hbs
index aa2692f199..2034404499 100644
--- a/ghost/admin/app/templates/settings/integration.hbs
+++ b/ghost/admin/app/templates/settings/integration.hbs
@@ -290,11 +290,4 @@
@modifier="action wide" />
{{/if}}
-{{#if this.webhookToDelete}}
-