mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-11-25 09:03:12 +03:00
Fixed webhook modal title showing "New webhook" when editing a webhook
refs https://github.com/TryGhost/Ghost/issues/10137 - adjust modal title depending on `webhook.isNew` state - add acceptance tests for modal creation - add missing mirage webhook factory - mock integrations/api-keys/webhooks in test env rather than development
This commit is contained in:
parent
032fba8f7b
commit
c33edbac08
@ -1,30 +1,30 @@
|
||||
<header class="modal-header" data-test-modal="webhook-form">
|
||||
<h1>New webhook</h1>
|
||||
<h1 data-test-text="title">{{if webhook.isNew "New" "Edit"}} webhook</h1>
|
||||
</header>
|
||||
<button class="close" href="" title="Close" {{action "closeModal"}}>{{svg-jar "close"}}</button>
|
||||
|
||||
<div class="modal-body">
|
||||
<fieldset>
|
||||
{{#gh-form-group errors=webhook.errors hasValidated=webhook.hasValidated property="name"}}
|
||||
<label for="new-webhook-name" class="fw6">Name</label>
|
||||
<label for="webhook-name" class="fw6">Name</label>
|
||||
{{gh-text-input
|
||||
value=(readonly webhook.name)
|
||||
input=(action (mut webhook.name) value="target.value")
|
||||
focus-out=(action "validate" "name" target=webhook)
|
||||
id="new-webhook-name"
|
||||
id="webhook-name"
|
||||
name="name"
|
||||
class="gh-input mt1"
|
||||
placeholder="Webhook name..."
|
||||
autofocus="autofocus"
|
||||
autocapitalize="off"
|
||||
autocorrect="off"
|
||||
data-test-input="new-webhook-name"}}
|
||||
{{gh-error-message errors=webhook.errors property="name" data-test-error="new-webhook-name"}}
|
||||
data-test-input="webhook-name"}}
|
||||
{{gh-error-message errors=webhook.errors property="name" data-test-error="webhook-name"}}
|
||||
{{/gh-form-group}}
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
{{#gh-form-group errors=webhook.errors hasValidated=webhook.hasValidated property="event"}}
|
||||
<label for="new-webhook-event" class="fw6">Event</label>
|
||||
<label for="webhook-event" class="fw6">Event</label>
|
||||
<span class="gh-select">
|
||||
{{one-way-select webhook.event
|
||||
options=availableEvents
|
||||
@ -35,49 +35,49 @@
|
||||
includeBlank=true
|
||||
prompt="Select an event"
|
||||
update=(action "selectEvent")
|
||||
id="new-webhook-event"
|
||||
id="webhook-event"
|
||||
name="event"
|
||||
data-test-select="new-webhook-event"}}
|
||||
data-test-select="webhook-event"}}
|
||||
{{svg-jar "arrow-down-small"}}
|
||||
</span>
|
||||
{{gh-error-message errors=webhook.errors property="event" data-test-error="new-webhook-event"}}
|
||||
{{gh-error-message errors=webhook.errors property="event" data-test-error="webhook-event"}}
|
||||
{{/gh-form-group}}
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
{{#gh-form-group errors=webhook.errors hasValidated=webhook.hasValidated property="targetUrl"}}
|
||||
<label for="new-webhook-targetUrl" class="fw6">Target URL</label>
|
||||
<label for="webhook-targetUrl" class="fw6">Target URL</label>
|
||||
{{gh-text-input
|
||||
value=(readonly webhook.targetUrl)
|
||||
input=(action (mut webhook.targetUrl) value="target.value")
|
||||
focus-out=(action "validate" "targetUrl" target=webhook)
|
||||
id="new-webhook-targetUrl"
|
||||
id="webhook-targetUrl"
|
||||
name="targetUrl"
|
||||
class="gh-input mt1"
|
||||
placeholder="Webhook target URL..."
|
||||
autofocus="autofocus"
|
||||
autocapitalize="off"
|
||||
autocorrect="off"
|
||||
data-test-input="new-webhook-targetUrl"}}
|
||||
{{gh-error-message errors=webhook.errors property="targetUrl" data-test-error="new-webhook-targetUrl"}}
|
||||
data-test-input="webhook-targetUrl"}}
|
||||
{{gh-error-message errors=webhook.errors property="targetUrl" data-test-error="webhook-targetUrl"}}
|
||||
{{/gh-form-group}}
|
||||
</fieldset>
|
||||
{{#if config.enableDeveloperExperiments}}
|
||||
<fieldset>
|
||||
{{#gh-form-group errors=webhook.errors hasValidated=webhook.hasValidated property="secret"}}
|
||||
<label for="new-webhook-secret" class="fw6">Secret</label>
|
||||
<label for="webhook-secret" class="fw6">Secret</label>
|
||||
{{gh-text-input
|
||||
value=(readonly webhook.secret)
|
||||
oninput=(action (mut webhook.secret) value="target.value")
|
||||
focus-out=(action "validate" "secret" target=webhook)
|
||||
id="new-webhook-secret"
|
||||
id="webhook-secret"
|
||||
name="secret"
|
||||
class="gh-input mt1"
|
||||
placeholder="Webhook secret..."
|
||||
autofocus="autofocus"
|
||||
autocapitalize="off"
|
||||
autocorrect="off"
|
||||
data-test-input="new-webhook-secret"}}
|
||||
{{gh-error-message errors=webhook.errors property="secret" data-test-error="new-webhook-secret"}}
|
||||
data-test-input="webhook-secret"}}
|
||||
{{gh-error-message errors=webhook.errors property="secret" data-test-error="webhook-secret"}}
|
||||
{{/gh-form-group}}
|
||||
</fieldset>
|
||||
{{/if}}
|
||||
@ -87,7 +87,7 @@
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button {{action "closeModal"}} class="gh-btn" data-test-button="cancel-new-webhook">
|
||||
<button {{action "closeModal"}} class="gh-btn" data-test-button="cancel-webhook">
|
||||
<span>Cancel</span>
|
||||
</button>
|
||||
{{gh-task-button buttonText
|
||||
|
@ -172,28 +172,30 @@
|
||||
</thead>
|
||||
<tbody>
|
||||
{{#each filteredWebhooks as |webhook|}}
|
||||
<tr class="hide-child bt b--whitegrey f7">
|
||||
<td class="pa2 pl3">{{webhook.name}}</td>
|
||||
<td class="pa2 pl3">{{event-name webhook.event}}</td>
|
||||
<td class="pa2 pl3">{{webhook.targetUrl}}</td>
|
||||
<td class="pa2 pl3">{{or webhook.lastTriggeredAtUTC "Not triggered"}}</td>
|
||||
<tr class="hide-child bt b--whitegrey f7" data-test-webhook-row="{{webhook.id}}">
|
||||
<td class="pa2 pl3" data-test-text="name">{{webhook.name}}</td>
|
||||
<td class="pa2 pl3" data-test-text="event">{{event-name webhook.event}}</td>
|
||||
<td class="pa2 pl3" data-test-text="targetUrl">{{webhook.targetUrl}}</td>
|
||||
<td class="pa2 pl3" data-test-text="last-triggered">{{or webhook.lastTriggeredAtUTC "Not triggered"}}</td>
|
||||
<td class="w1 pa2 pl3 nowrap">
|
||||
<div class="child flex items-center">
|
||||
{{#link-to "settings.integration.webhooks.edit" integration webhook}}
|
||||
{{#link-to "settings.integration.webhooks.edit" integration webhook data-test-link="edit-webhook"}}
|
||||
{{svg-jar "pen" class="w6 h-auto fill-midgrey pa1 mr1"}}
|
||||
{{/link-to}}
|
||||
<button {{action "confirmWebhookDeletion" webhook}}>
|
||||
<button {{action "confirmWebhookDeletion" webhook}} data-test-button="delete-webhook">
|
||||
{{svg-jar "trash" class="w6 fill-red pa1"}}
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{{else}}
|
||||
<tr class="bt b--whitegrey">
|
||||
<tr class="bt b--whitegrey" data-test-webhooks-blank-slate>
|
||||
<td colspan="5" class="pa5 pt15 pb15 tc midgrey f7">
|
||||
<span class="db">No webhooks configured</span>
|
||||
<span class="dib mt1">
|
||||
{{#link-to "settings.integration.webhooks.new" integration classNames="flex items-center"}}{{svg-jar "add" class="w3 h-auto fill-blue mr1"}} Add webhook{{/link-to}}
|
||||
{{#link-to "settings.integration.webhooks.new" integration classNames="flex items-center" data-test-link="add-webhook"}}
|
||||
{{svg-jar "add" class="w3 h-auto fill-blue mr1"}} Add webhook
|
||||
{{/link-to}}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
@ -203,8 +205,9 @@
|
||||
<tfoot class="bt b--lightgrey">
|
||||
<tr>
|
||||
<td colspan="5" class="pa3 f7">
|
||||
{{#link-to "settings.integration.webhooks.new" integration classNames="flex items-center"}}{{svg-jar "add" class="w3
|
||||
h-auto fill-blue mr1"}} Add webhook{{/link-to}}
|
||||
{{#link-to "settings.integration.webhooks.new" integration classNames="flex items-center" data-test-link="add-webhook"}}
|
||||
{{svg-jar "add" class="w3h-auto fill-blue mr1"}} Add webhook
|
||||
{{/link-to}}
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
|
@ -25,9 +25,6 @@ export default function () {
|
||||
// this.put('/posts/:id/', versionMismatchResponse);
|
||||
// mockTags(this);
|
||||
// this.loadFixtures('settings');
|
||||
mockIntegrations(this);
|
||||
mockApiKeys(this);
|
||||
mockWebhooks(this);
|
||||
|
||||
// keep this line, it allows all other API requests to hit the real server
|
||||
this.passthrough();
|
||||
@ -45,8 +42,10 @@ export function testConfig() {
|
||||
// this.timing = 400; // delay for each request, automatically set to 0 during testing
|
||||
// this.logging = true;
|
||||
|
||||
mockApiKeys(this);
|
||||
mockAuthentication(this);
|
||||
mockConfiguration(this);
|
||||
mockIntegrations(this);
|
||||
mockInvites(this);
|
||||
mockPosts(this);
|
||||
mockRoles(this);
|
||||
@ -57,6 +56,7 @@ export function testConfig() {
|
||||
mockThemes(this);
|
||||
mockUploads(this);
|
||||
mockUsers(this);
|
||||
mockWebhooks(this);
|
||||
|
||||
/* Notifications -------------------------------------------------------- */
|
||||
|
||||
|
@ -7,11 +7,6 @@ export default function mockWebhooks(server) {
|
||||
|
||||
server.post('/webhooks/', function ({webhooks}) {
|
||||
let attrs = this.normalizedRequestAttrs();
|
||||
|
||||
// TODO: should mirage be handling this?
|
||||
attrs.integrationId = attrs.integration;
|
||||
delete attrs.integration;
|
||||
|
||||
let errors = [];
|
||||
|
||||
if (!attrs.name) {
|
||||
|
18
ghost/admin/mirage/factories/webhook.js
Normal file
18
ghost/admin/mirage/factories/webhook.js
Normal file
@ -0,0 +1,18 @@
|
||||
import moment from 'moment';
|
||||
import {AVAILABLE_EVENTS} from 'ghost-admin/helpers/event-name';
|
||||
import {Factory} from 'ember-cli-mirage';
|
||||
|
||||
export default Factory.extend({
|
||||
name(i) { return `Integration ${i + 1}`;},
|
||||
event(i) {
|
||||
let event = AVAILABLE_EVENTS[i % 3];
|
||||
return event.event;
|
||||
},
|
||||
target(i) { return `https://example.com/${i + 1}`; },
|
||||
lastTriggeredAt: null,
|
||||
|
||||
createdAt() { return moment.utc().format(); },
|
||||
createdBy: 1,
|
||||
updatedAt() { return moment.utc().format(); },
|
||||
updatedBy: 1
|
||||
});
|
@ -422,6 +422,52 @@ describe('Acceptance: Settings - Integrations', function () {
|
||||
).to.equal('Test Integration');
|
||||
});
|
||||
|
||||
it('can manage an integration\'s webhooks', async function () {
|
||||
server.create('integration');
|
||||
|
||||
await visit('/settings/integrations/1');
|
||||
|
||||
expect(find('[data-test-webhooks-blank-slate]').length).to.equal(1);
|
||||
|
||||
// open new webhook modal
|
||||
await click('[data-test-link="add-webhook"]');
|
||||
expect(find('[data-test-modal="webhook-form"]').length).to.equal(1);
|
||||
expect(find('[data-test-modal="webhook-form"] [data-test-text="title"]').text())
|
||||
.to.have.string('New webhook');
|
||||
|
||||
// can cancel new webhook
|
||||
await click('[data-test-button="cancel-webhook"]');
|
||||
expect(find('[data-test-modal="webhook-form"]').length).to.equal(0);
|
||||
|
||||
// create new webhook
|
||||
await click('[data-test-link="add-webhook"]');
|
||||
await fillIn('[data-test-input="webhook-name"]', 'First webhook');
|
||||
await fillIn('[data-test-select="webhook-event"]', 'site.changed');
|
||||
await fillIn('[data-test-input="webhook-targetUrl"]', 'https://example.com/first-webhook');
|
||||
await click('[data-test-button="save-webhook"]');
|
||||
|
||||
// modal closed and 1 webhook listed with correct details
|
||||
expect(find('[data-test-modal="webhook-form"]').length).to.equal(0);
|
||||
expect(find('[data-test-webhook-row]').length).to.equal(1);
|
||||
let row = find('[data-test-webhook-row="1"]');
|
||||
expect(row.find('[data-test-text="name"]').text())
|
||||
.to.have.string('First webhook');
|
||||
expect(row.find('[data-test-text="event"]').text())
|
||||
.to.have.string('Site Changed (rebuild)');
|
||||
expect(row.find('[data-test-text="targetUrl"]').text())
|
||||
.to.have.string('https://example.com/first-webhook');
|
||||
expect(row.find('[data-test-text="last-triggered"]').text())
|
||||
.to.have.string('Not triggered');
|
||||
|
||||
// click edit webhook link
|
||||
await click('[data-test-webhook-row="1"] [data-test-link="edit-webhook"]');
|
||||
|
||||
// modal appears and has correct title
|
||||
expect(find('[data-test-modal="webhook-form"]').length).to.equal(1);
|
||||
expect(find('[data-test-modal="webhook-form"] [data-test-text="title"]').text())
|
||||
.to.have.string('Edit webhook');
|
||||
});
|
||||
|
||||
// test to ensure the `value=description` passed to `gh-text-input` is `readonly`
|
||||
it('doesn\'t show unsaved changes modal after placing focus on description field', async function () {
|
||||
server.create('integration');
|
||||
|
Loading…
Reference in New Issue
Block a user