Skip to content
This repository has been archived by the owner on Nov 28, 2022. It is now read-only.

Added edit webhook modal #1056

Merged
merged 7 commits into from Oct 19, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
26 changes: 26 additions & 0 deletions app/components/modal-delete-webhook.js
@@ -0,0 +1,26 @@
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()
});
12 changes: 7 additions & 5 deletions app/components/modal-webhook-form.js
@@ -1,5 +1,6 @@
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 {isInvalidError} from 'ember-ajax/errors';
Expand All @@ -10,6 +11,7 @@ export default ModalComponent.extend({
router: service(),

availableEvents: null,
error: null,
buttonText: 'Save',
successText: 'Saved',

Expand All @@ -19,11 +21,7 @@ export default ModalComponent.extend({

init() {
this._super(...arguments);
this.availableEvents = [
{event: 'site.changed', name: 'Site Changed (rebuild)'},
{event: 'subscriber.added', name: 'Subscriber Added'},
{event: 'subscriber.deleted', name: 'Subscriber Deleted'}
];
this.availableEvents = AVAILABLE_EVENTS;
},

didReceiveAttrs() {
Expand All @@ -45,6 +43,8 @@ export default ModalComponent.extend({
},

saveWebhook: task(function* () {
this.set('error', null);

try {
let webhook = yield this.confirm();
let integration = yield webhook.get('integration');
Expand All @@ -62,6 +62,8 @@ export default ModalComponent.extend({
if (property && attrs.includes(property)) {
this.webhook.errors.add(property, message);
this.webhook.hasValidated.pushObject(property);
} else {
this.set('error', message);
}
});

Expand Down
32 changes: 23 additions & 9 deletions app/controllers/settings/integration.js
@@ -1,7 +1,7 @@
import Controller from '@ember/controller';
import {alias} from '@ember/object/computed';
import {computed} from '@ember/object';
import {task} from 'ember-concurrency';
import {task, timeout} from 'ember-concurrency';

export default Controller.extend({
integration: alias('model'),
Expand All @@ -25,14 +25,6 @@ export default Controller.extend({
return this.save.perform();
},

copyContentKey() {
this._copyInputTextToClipboard('input#content_key');
},

copyAdminKey() {
this._copyInputTextToClipboard('input#admin_key');
},

toggleUnsavedChangesModal(transition) {
let leaveTransition = this.leaveScreenTransition;

Expand Down Expand Up @@ -69,13 +61,35 @@ export default Controller.extend({
this.integration.rollbackAttributes();

return transition.retry();
},

confirmWebhookDeletion(webhook) {
this.set('webhookToDelete', webhook);
},

cancelWebhookDeletion() {
this.set('webhookToDelete', null);
},

deleteWebhook() {
return this.webhookToDelete.destroyRecord();
}
},

save: task(function* () {
return yield this.integration.save();
}),

copyContentKey: task(function* () {
this._copyInputTextToClipboard('input#content_key');
yield timeout(3000);
}),

copyAdminKey: task(function* () {
this._copyInputTextToClipboard('input#admin_key');
yield timeout(3000);
}),

_copyInputTextToClipboard(selector) {
let input = document.querySelector(selector);
input.disabled = false;
Expand Down
19 changes: 19 additions & 0 deletions app/controllers/settings/integration/webhooks/edit.js
@@ -0,0 +1,19 @@
import Controller from '@ember/controller';
import {alias} from '@ember/object/computed';

export default Controller.extend({
webhook: alias('model'),

actions: {
save() {
return this.webhook.save();
},

cancel() {
// 'new' route's dectivate hook takes care of rollback
return this.webhook.get('integration').then((integration) => {
this.transitionToRoute('settings.integration', integration);
});
}
}
});
15 changes: 15 additions & 0 deletions app/helpers/event-name.js
@@ -0,0 +1,15 @@
import {helper} from '@ember/component/helper';

export const AVAILABLE_EVENTS = [
{event: 'site.changed', name: 'Site Changed (rebuild)'},
{event: 'subscriber.added', name: 'Subscriber Added'},
{event: 'subscriber.deleted', name: 'Subscriber Deleted'}
];

export function eventName([event]/*, hash*/) {
let match = AVAILABLE_EVENTS.findBy('event', event);

return match ? match.name : event;
}

export default helper(eventName);
1 change: 1 addition & 0 deletions app/router.js
Expand Up @@ -57,6 +57,7 @@ Router.map(function () {
});
this.route('settings.integration', {path: '/settings/integrations/:integration_id'}, function () {
this.route('webhooks.new', {path: 'webhooks/new'});
this.route('webhooks.edit', {path: 'webhooks/:webhook_id'});
});
this.route('settings.integrations.slack', {path: '/settings/integrations/slack'});
this.route('settings.integrations.amp', {path: '/settings/integrations/amp'});
Expand Down
14 changes: 14 additions & 0 deletions app/routes/settings/integration/webhooks/edit.js
@@ -0,0 +1,14 @@
import Route from '@ember/routing/route';

export default Route.extend({
model(params) {
let integration = this.modelFor('settings.integration');
let webhook = integration.webhooks.findBy('id', params.webhook_id);
return webhook;
},

deactivate() {
this._super(...arguments);
this.controller.webhook.rollbackAttributes();
}
});
15 changes: 15 additions & 0 deletions app/templates/components/modal-delete-webhook.hbs
@@ -0,0 +1,15 @@
<header class="modal-header">
<h1>Are you sure?</h1>
</header>
<a class="close" href="" title="Close" {{action "closeModal"}}>{{svg-jar "close"}}<span class="hidden">Close</span></a>

<div class="modal-body">
<p>
Deleting this webhook may prevent the integration from functioning.
</p>
</div>

<div class="modal-footer">
<button {{action "closeModal"}} class="gh-btn"><span>Cancel</span></button>
{{gh-task-button "Delete Webhook" successText="Deleted" task=deleteWebhook class="gh-btn gh-btn-red gh-btn-icon"}}
</div>
3 changes: 3 additions & 0 deletions app/templates/components/modal-webhook-form.hbs
Expand Up @@ -78,6 +78,9 @@
{{gh-error-message errors=webhook.errors property="secret" data-test-error="new-webhook-secret"}}
{{/gh-form-group}}
</fieldset>
{{#if error}}
<p class="red">{{error}}</p>
{{/if}}
</div>

<div class="modal-footer">
Expand Down
78 changes: 54 additions & 24 deletions app/templates/settings/integration.hbs
Expand Up @@ -63,45 +63,57 @@
<div class="flex flex-row">
{{#with integration.contentKey as |contentKey|}}
{{#gh-validation-status-container class="flex flex-column w-100 mr3"}}
<label for="content_key">Content API Key</label>
<div class="relative"
onmouseenter={{action (mut showContentKeyActions) true}}
onmouseleave={{action (mut showContentKeyActions) false}}
>
<div class="flex">
<label for="content_key" class="flex-grow-1">
Content API Key
</label>
<span class="db">
{{#if copyContentKey.isRunning}}
Copied to clipboard
{{else}}
{{contentKey.lastSeenAtUTC}}
{{/if}}
</span>
</div>
<div class="relative hide-child">
<input id="content_key"
class="gh-input"
type="text"
value={{contentKey.secret}}
disabled="true"
data-test-input="content_key">

{{#if showContentKeyActions}}
<div class="absolute top-2 right-2">
<button type="button" {{action "copyContentKey"}}>Copy</button>
</div>
{{/if}}
<div class="absolute top-1 right-1 pt1 pr2 pb1 pl2 bg-white child">
<button type="button" {{action (perform copyContentKey)}}>Copy</button>
</div>
</div>
{{/gh-validation-status-container}}
{{/with}}
{{#with integration.adminKey as |adminKey|}}
{{#gh-validation-status-container class="flex flex-column w-100 ml3"}}
<label for="admin_key">Admin API Key</label>
<div class="relative"
onmouseenter={{action (mut showAdminKeyActions) true}}
onmouseleave={{action (mut showAdminKeyActions) false}}
>
<div class="flex">
<label for="admin_key" class="flex-grow-1">
Admin API Key
</label>
<span class="db">
{{#if copyAdminKey.isRunning}}
Copied to clipboard
{{else}}
{{adminKey.lastSeenAtUTC}}
{{/if}}
</span>
</div>
<div class="relative hide-child">
<input id="admin_key"
class="gh-input"
type="text"
value={{adminKey.secret}}
disabled="true"
data-test-input="admin_key">

{{#if showAdminKeyActions}}
<div class="absolute top-2 right-2">
<button type="button" {{action "copyAdminKey"}}>Copy</button>
</div>
{{/if}}
<div class="absolute top-1 right-1 pt1 pr2 pb1 pl2 bg-white child">
<button type="button" {{action (perform copyAdminKey)}}>Copy</button>
</div>
</div>
{{/gh-validation-status-container}}
{{/with}}
Expand All @@ -115,16 +127,27 @@
<th class="pa3 br3 br--bottom br--right bg-lightgrey-l1">Name</th>
<th class="pa3 bg-lightgrey-l1">Event</th>
<th class="pa3 bg-lightgrey-l1">URL</th>
<th class="pa3 br3 br--top br--left bg-lightgrey-l1">Last triggered</th>
<th class="pa3 bg-lightgrey-l1">Last triggered</th>
<th class="pa3 br3 br--top br--left bg-lightgrey-l1"></th>
</tr>
</thead>
<tbody>
{{#each filteredWebhooks as |webhook|}}
<tr>
<tr class="hide-child">
<td class="pa3">{{webhook.name}}</td>
<td class="pa3">{{webhook.event}}</td>
<td class="pa3">{{event-name webhook.event}}</td>
<td class="pa3">{{webhook.targetUrl}}</td>
<td class="pa3">{{webhook.lastTriggeredAtUTC}}</td>
<td class="pa3">{{or webhook.lastTriggeredAtUTC "Not triggered"}}</td>
<td class="w1 pa3 nowrap">
<div class="child">
{{#link-to "settings.integration.webhooks.edit" integration webhook}}
{{svg-jar "koenig/kg-thin-edit" class="w4 fill-black-80"}}
{{/link-to}}
<button {{action "confirmWebhookDeletion" webhook}}>
{{svg-jar "trash" class="w4 fill-red"}}
</button>
</div>
</td>
</tr>
{{else}}
<tr>
Expand Down Expand Up @@ -152,4 +175,11 @@
modifier="action wide"}}
{{/if}}

{{#if webhookToDelete}}
{{gh-fullscreen-modal "delete-webhook"
confirm=(action "deleteWebhook")
close=(action "cancelWebhookDeletion")
modifier="action wide"}}
{{/if}}

{{outlet}}
5 changes: 5 additions & 0 deletions app/templates/settings/integration/webhooks/edit.hbs
@@ -0,0 +1,5 @@
{{gh-fullscreen-modal "webhook-form"
model=webhook
confirm=(action "save")
close=(action "cancel")
modifier="action wide"}}