diff --git a/app/assets/javascripts/admin/addon/templates/web-hooks-show-events.hbs b/app/assets/javascripts/admin/addon/components/webhook-events.hbs similarity index 57% rename from app/assets/javascripts/admin/addon/templates/web-hooks-show-events.hbs rename to app/assets/javascripts/admin/addon/components/webhook-events.hbs index c9791f0fc4f..927a6309fc4 100644 --- a/app/assets/javascripts/admin/addon/templates/web-hooks-show-events.hbs +++ b/app/assets/javascripts/admin/addon/components/webhook-events.hbs @@ -1,16 +1,17 @@ -
- - {{d-icon "list"}} {{i18n "admin.web_hooks.events.go_list"}} - - - - {{d-icon "far-edit"}} {{i18n "admin.web_hooks.events.go_details"}} - -
+
+ -
- {{#if this.model}} - + {{#if this.events}} +
{{i18n "admin.web_hooks.events.status"}}
@@ -18,20 +19,22 @@
{{i18n "admin.web_hooks.events.timestamp"}}
{{i18n "admin.web_hooks.events.completion"}}
{{i18n "admin.web_hooks.events.actions"}}
-
+ {{#if this.hasIncoming}} {{/if}} +
    - {{#each this.model as |webHookEvent|}} + {{#each this.events as |webHookEvent|}} {{/each}}
- + +
{{else}}

{{i18n "admin.web_hooks.events.none"}}

diff --git a/app/assets/javascripts/admin/addon/components/webhook-events.js b/app/assets/javascripts/admin/addon/components/webhook-events.js new file mode 100644 index 00000000000..a3559af8cc4 --- /dev/null +++ b/app/assets/javascripts/admin/addon/components/webhook-events.js @@ -0,0 +1,89 @@ +import Component from "@glimmer/component"; +import { inject as service } from "@ember/service"; +import { tracked } from "@glimmer/tracking"; +import { action } from "@ember/object"; +import { ajax } from "discourse/lib/ajax"; +import { gt, readOnly } from "@ember/object/computed"; +import { bind } from "discourse-common/utils/decorators"; +import { popupAjaxError } from "discourse/lib/ajax-error"; + +export default class WebhookEvents extends Component { + @service messageBus; + @service store; + + @tracked pingEnabled = true; + @tracked events = []; + @tracked incomingEventIds = []; + + @readOnly("incomingEventIds.length") incomingCount; + @gt("incomingCount", 0) hasIncoming; + + constructor() { + super(...arguments); + this.loadEvents(); + } + + async loadEvents() { + this.events = await this.store.findAll( + "web-hook-event", + this.args.webhookId + ); + } + + @bind + subscribe() { + const channel = `/web_hook_events/${this.args.webhookId}`; + this.messageBus.subscribe(channel, this._addIncoming); + } + + @bind + unsubscribe() { + this.messageBus.unsubscribe("/web_hook_events/*", this._addIncoming); + } + + @bind + _addIncoming(data) { + if (data.event_type === "ping") { + this.pingEnabled = true; + } + + if (!this.incomingEventIds.includes(data.web_hook_event_id)) { + this.incomingEventIds.pushObject(data.web_hook_event_id); + } + } + + @action + async showInserted(event) { + event?.preventDefault(); + + const path = `/admin/api/web_hooks/${this.args.webhookId}/events/bulk`; + const data = await ajax(path, { + data: { ids: this.incomingEventIds }, + }); + + const objects = data.map((webHookEvent) => + this.store.createRecord("web-hook-event", webHookEvent) + ); + this.events.unshiftObjects(objects); + this.incomingEventIds = []; + } + + @action + loadMore() { + this.events.loadMore(); + } + + @action + async ping() { + this.pingEnabled = false; + + try { + await ajax(`/admin/api/web_hooks/${this.args.webhookId}/ping`, { + type: "POST", + }); + } catch (error) { + this.pingEnabled = true; + popupAjaxError(error); + } + } +} diff --git a/app/assets/javascripts/admin/addon/controllers/admin-web-hooks-edit.js b/app/assets/javascripts/admin/addon/controllers/admin-web-hooks-edit.js new file mode 100644 index 00000000000..f24dfef939e --- /dev/null +++ b/app/assets/javascripts/admin/addon/controllers/admin-web-hooks-edit.js @@ -0,0 +1,101 @@ +import Controller, { inject as controller } from "@ember/controller"; +import EmberObject, { action } from "@ember/object"; +import I18n from "I18n"; +import { alias } from "@ember/object/computed"; +import discourseComputed from "discourse-common/utils/decorators"; +import { isEmpty } from "@ember/utils"; +import { popupAjaxError } from "discourse/lib/ajax-error"; +import { inject as service } from "@ember/service"; + +export default Controller.extend({ + adminWebHooks: controller(), + dialog: service(), + eventTypes: alias("adminWebHooks.eventTypes"), + defaultEventTypes: alias("adminWebHooks.defaultEventTypes"), + contentTypes: alias("adminWebHooks.contentTypes"), + + @discourseComputed + showTagsFilter() { + return this.siteSettings.tagging_enabled; + }, + + @discourseComputed("model.isSaving", "saved", "saveButtonDisabled") + savingStatus(isSaving, saved, saveButtonDisabled) { + if (isSaving) { + return I18n.t("saving"); + } else if (!saveButtonDisabled && saved) { + return I18n.t("saved"); + } + // Use side effect of validation to clear saved text + this.set("saved", false); + return ""; + }, + + @discourseComputed("model.isNew") + saveButtonText(isNew) { + return isNew + ? I18n.t("admin.web_hooks.create") + : I18n.t("admin.web_hooks.save"); + }, + + @discourseComputed("model.secret") + secretValidation(secret) { + if (!isEmpty(secret)) { + if (secret.includes(" ")) { + return EmberObject.create({ + failed: true, + reason: I18n.t("admin.web_hooks.secret_invalid"), + }); + } + + if (secret.length < 12) { + return EmberObject.create({ + failed: true, + reason: I18n.t("admin.web_hooks.secret_too_short"), + }); + } + } + }, + + @discourseComputed("model.wildcard_web_hook", "model.web_hook_event_types.[]") + eventTypeValidation(isWildcard, eventTypes) { + if (!isWildcard && isEmpty(eventTypes)) { + return EmberObject.create({ + failed: true, + reason: I18n.t("admin.web_hooks.event_type_missing"), + }); + } + }, + + @discourseComputed( + "model.isSaving", + "secretValidation", + "eventTypeValidation", + "model.payload_url" + ) + saveButtonDisabled( + isSaving, + secretValidation, + eventTypeValidation, + payloadUrl + ) { + return isSaving + ? false + : secretValidation || eventTypeValidation || isEmpty(payloadUrl); + }, + + @action + async save() { + this.set("saved", false); + + try { + await this.model.save(); + + this.set("saved", true); + this.adminWebHooks.model.addObject(this.model); + this.transitionToRoute("adminWebHooks.show", this.model); + } catch (e) { + popupAjaxError(e); + } + }, +}); diff --git a/app/assets/javascripts/admin/addon/controllers/admin-web-hooks-index.js b/app/assets/javascripts/admin/addon/controllers/admin-web-hooks-index.js new file mode 100644 index 00000000000..a1294cf09d7 --- /dev/null +++ b/app/assets/javascripts/admin/addon/controllers/admin-web-hooks-index.js @@ -0,0 +1,36 @@ +import Controller, { inject as controller } from "@ember/controller"; +import I18n from "I18n"; +import { popupAjaxError } from "discourse/lib/ajax-error"; +import { inject as service } from "@ember/service"; +import { action } from "@ember/object"; +import { alias } from "@ember/object/computed"; + +export default Controller.extend({ + adminWebHooks: controller(), + dialog: service(), + contentTypes: alias("adminWebHooks.contentTypes"), + defaultEventTypes: alias("adminWebHooks.defaultEventTypes"), + deliveryStatuses: alias("adminWebHooks.deliveryStatuses"), + eventTypes: alias("adminWebHooks.eventTypes"), + model: alias("adminWebHooks.model"), + + @action + destroy(webhook) { + return this.dialog.deleteConfirm({ + message: I18n.t("admin.web_hooks.delete_confirm"), + didConfirm: async () => { + try { + await webhook.destroyRecord(); + this.model.removeObject(webhook); + } catch (e) { + popupAjaxError(e); + } + }, + }); + }, + + @action + loadMore() { + this.model.loadMore(); + }, +}); diff --git a/app/assets/javascripts/admin/addon/controllers/admin-web-hooks-show-events.js b/app/assets/javascripts/admin/addon/controllers/admin-web-hooks-show-events.js deleted file mode 100644 index 5e9dacb83b7..00000000000 --- a/app/assets/javascripts/admin/addon/controllers/admin-web-hooks-show-events.js +++ /dev/null @@ -1,81 +0,0 @@ -import Controller from "@ember/controller"; -import { ajax } from "discourse/lib/ajax"; -import { action } from "@ember/object"; -import { alias } from "@ember/object/computed"; -import discourseComputed, { bind } from "discourse-common/utils/decorators"; -import { popupAjaxError } from "discourse/lib/ajax-error"; - -export default Controller.extend({ - pingDisabled: false, - incomingCount: alias("incomingEventIds.length"), - - init() { - this._super(...arguments); - - this.incomingEventIds = []; - }, - - @discourseComputed("incomingCount") - hasIncoming(incomingCount) { - return incomingCount > 0; - }, - - subscribe() { - this.messageBus.subscribe( - `/web_hook_events/${this.get("model.extras.web_hook_id")}`, - this._addIncoming - ); - }, - - unsubscribe() { - this.messageBus.unsubscribe("/web_hook_events/*", this._addIncoming); - }, - - @bind - _addIncoming(data) { - if (data.event_type === "ping") { - this.set("pingDisabled", false); - } - - if (!this.incomingEventIds.includes(data.web_hook_event_id)) { - this.incomingEventIds.pushObject(data.web_hook_event_id); - } - }, - - @action - showInserted(event) { - event?.preventDefault(); - const webHookId = this.get("model.extras.web_hook_id"); - - ajax(`/admin/api/web_hooks/${webHookId}/events/bulk`, { - type: "GET", - data: { ids: this.incomingEventIds }, - }).then((data) => { - const objects = data.map((webHookEvent) => - this.store.createRecord("web-hook-event", webHookEvent) - ); - this.model.unshiftObjects(objects); - this.set("incomingEventIds", []); - }); - }, - - actions: { - loadMore() { - this.model.loadMore(); - }, - - ping() { - this.set("pingDisabled", true); - - ajax( - `/admin/api/web_hooks/${this.get("model.extras.web_hook_id")}/ping`, - { - type: "POST", - } - ).catch((error) => { - this.set("pingDisabled", false); - popupAjaxError(error); - }); - }, - }, -}); diff --git a/app/assets/javascripts/admin/addon/controllers/admin-web-hooks-show.js b/app/assets/javascripts/admin/addon/controllers/admin-web-hooks-show.js index f1e8caadcf8..38bef778fb4 100644 --- a/app/assets/javascripts/admin/addon/controllers/admin-web-hooks-show.js +++ b/app/assets/javascripts/admin/addon/controllers/admin-web-hooks-show.js @@ -1,121 +1,32 @@ import Controller, { inject as controller } from "@ember/controller"; -import EmberObject from "@ember/object"; +import { action } from "@ember/object"; import I18n from "I18n"; -import { alias } from "@ember/object/computed"; -import discourseComputed from "discourse-common/utils/decorators"; -import { isEmpty } from "@ember/utils"; import { popupAjaxError } from "discourse/lib/ajax-error"; import { inject as service } from "@ember/service"; export default Controller.extend({ adminWebHooks: controller(), dialog: service(), - eventTypes: alias("adminWebHooks.eventTypes"), - defaultEventTypes: alias("adminWebHooks.defaultEventTypes"), - contentTypes: alias("adminWebHooks.contentTypes"), + router: service(), - @discourseComputed - showTagsFilter() { - return this.siteSettings.tagging_enabled; + @action + edit() { + return this.router.transitionTo("adminWebHooks.edit", this.model); }, - @discourseComputed("model.isSaving", "saved", "saveButtonDisabled") - savingStatus(isSaving, saved, saveButtonDisabled) { - if (isSaving) { - return I18n.t("saving"); - } else if (!saveButtonDisabled && saved) { - return I18n.t("saved"); - } - // Use side effect of validation to clear saved text - this.set("saved", false); - return ""; - }, - - @discourseComputed("model.isNew") - saveButtonText(isNew) { - return isNew - ? I18n.t("admin.web_hooks.create") - : I18n.t("admin.web_hooks.save"); - }, - - @discourseComputed("model.secret") - secretValidation(secret) { - if (!isEmpty(secret)) { - if (secret.includes(" ")) { - return EmberObject.create({ - failed: true, - reason: I18n.t("admin.web_hooks.secret_invalid"), - }); - } - - if (secret.length < 12) { - return EmberObject.create({ - failed: true, - reason: I18n.t("admin.web_hooks.secret_too_short"), - }); - } - } - }, - - @discourseComputed("model.wildcard_web_hook", "model.web_hook_event_types.[]") - eventTypeValidation(isWildcard, eventTypes) { - if (!isWildcard && isEmpty(eventTypes)) { - return EmberObject.create({ - failed: true, - reason: I18n.t("admin.web_hooks.event_type_missing"), - }); - } - }, - - @discourseComputed( - "model.isSaving", - "secretValidation", - "eventTypeValidation", - "model.payload_url" - ) - saveButtonDisabled( - isSaving, - secretValidation, - eventTypeValidation, - payloadUrl - ) { - return isSaving - ? false - : secretValidation || eventTypeValidation || isEmpty(payloadUrl); - }, - - actions: { - save() { - this.set("saved", false); - const model = this.model; - const isNew = model.get("isNew"); - - return model - .save() - .then(() => { - this.set("saved", true); - this.adminWebHooks.get("model").addObject(model); - - if (isNew) { - this.transitionToRoute("adminWebHooks.show", model.get("id")); - } - }) - .catch(popupAjaxError); - }, - - destroy() { - return this.dialog.yesNoConfirm({ - message: I18n.t("admin.web_hooks.delete_confirm"), - didConfirm: () => { - this.model - .destroyRecord() - .then(() => { - this.adminWebHooks.get("model").removeObject(this.model); - this.transitionToRoute("adminWebHooks"); - }) - .catch(popupAjaxError); - }, - }); - }, + @action + destroy() { + return this.dialog.deleteConfirm({ + message: I18n.t("admin.web_hooks.delete_confirm"), + didConfirm: async () => { + try { + await this.model.destroyRecord(); + this.adminWebHooks.model.removeObject(this.model); + this.transitionToRoute("adminWebHooks"); + } catch (e) { + popupAjaxError(e); + } + }, + }); }, }); diff --git a/app/assets/javascripts/admin/addon/controllers/admin-web-hooks.js b/app/assets/javascripts/admin/addon/controllers/admin-web-hooks.js index 405f8594132..fa4ba1ee7d2 100644 --- a/app/assets/javascripts/admin/addon/controllers/admin-web-hooks.js +++ b/app/assets/javascripts/admin/addon/controllers/admin-web-hooks.js @@ -1,29 +1,3 @@ import Controller from "@ember/controller"; -import I18n from "I18n"; -import { popupAjaxError } from "discourse/lib/ajax-error"; -import { inject as service } from "@ember/service"; -import { action } from "@ember/object"; -export default Controller.extend({ - dialog: service(), - - @action - destroy(webhook) { - return this.dialog.yesNoConfirm({ - message: I18n.t("admin.web_hooks.delete_confirm"), - didConfirm: () => { - webhook - .destroyRecord() - .then(() => { - this.model.removeObject(webhook); - }) - .catch(popupAjaxError); - }, - }); - }, - - @action - loadMore() { - this.model.loadMore(); - }, -}); +export default Controller.extend({}); diff --git a/app/assets/javascripts/admin/addon/routes/admin-route-map.js b/app/assets/javascripts/admin/addon/routes/admin-route-map.js index 9b888f9ce55..37272c1c07a 100644 --- a/app/assets/javascripts/admin/addon/routes/admin-route-map.js +++ b/app/assets/javascripts/admin/addon/routes/admin-route-map.js @@ -123,7 +123,7 @@ export default function () { { path: "/web_hooks", resetNamespace: true }, function () { this.route("show", { path: "/:web_hook_id" }); - this.route("showEvents", { path: "/:web_hook_id/events" }); + this.route("edit", { path: "/:web_hook_id/edit" }); } ); }); diff --git a/app/assets/javascripts/admin/addon/routes/admin-web-hooks-edit.js b/app/assets/javascripts/admin/addon/routes/admin-web-hooks-edit.js new file mode 100644 index 00000000000..6bd96b117b3 --- /dev/null +++ b/app/assets/javascripts/admin/addon/routes/admin-web-hooks-edit.js @@ -0,0 +1,28 @@ +import DiscourseRoute from "discourse/routes/discourse"; + +export default DiscourseRoute.extend({ + serialize(model) { + return { web_hook_id: model.id || "new" }; + }, + + model(params) { + if (params.web_hook_id === "new") { + return this.store.createRecord("web-hook"); + } + + return this.store.find("web-hook", params.web_hook_id); + }, + + setupController(controller, model) { + this._super(...arguments); + + if (model.get("isNew")) { + model.set( + "web_hook_event_types", + this.controllerFor("adminWebHooks").defaultEventTypes + ); + } + + controller.set("saved", false); + }, +}); diff --git a/app/assets/javascripts/admin/addon/routes/admin-web-hooks-show-events.js b/app/assets/javascripts/admin/addon/routes/admin-web-hooks-show-events.js deleted file mode 100644 index 1b7923224bb..00000000000 --- a/app/assets/javascripts/admin/addon/routes/admin-web-hooks-show-events.js +++ /dev/null @@ -1,21 +0,0 @@ -import DiscourseRoute from "discourse/routes/discourse"; -import { get } from "@ember/object"; - -export default DiscourseRoute.extend({ - model(params) { - return this.store.findAll("web-hook-event", get(params, "web_hook_id")); - }, - - setupController(controller, model) { - controller.set("model", model); - controller.subscribe(); - }, - - deactivate() { - this.controllerFor("adminWebHooks.showEvents").unsubscribe(); - }, - - renderTemplate() { - this.render("admin/templates/web-hooks-show-events", { into: "adminApi" }); - }, -}); diff --git a/app/assets/javascripts/admin/addon/routes/admin-web-hooks-show.js b/app/assets/javascripts/admin/addon/routes/admin-web-hooks-show.js index 6d7c64f9559..369bbd00597 100644 --- a/app/assets/javascripts/admin/addon/routes/admin-web-hooks-show.js +++ b/app/assets/javascripts/admin/addon/routes/admin-web-hooks-show.js @@ -1,30 +1,7 @@ import DiscourseRoute from "discourse/routes/discourse"; -import { get } from "@ember/object"; export default DiscourseRoute.extend({ - serialize(model) { - return { web_hook_id: model.get("id") || "new" }; - }, - model(params) { - if (params.web_hook_id === "new") { - return this.store.createRecord("web-hook"); - } - return this.store.find("web-hook", get(params, "web_hook_id")); - }, - - setupController(controller, model) { - if (model.get("isNew")) { - model.set("web_hook_event_types", controller.get("defaultEventTypes")); - } - - model.set("category_ids", model.get("category_ids")); - model.set("tag_names", model.get("tag_names")); - model.set("group_ids", model.get("group_ids")); - controller.setProperties({ model, saved: false }); - }, - - renderTemplate() { - this.render("admin/templates/web-hooks-show", { into: "adminApi" }); + return this.store.find("web-hook", params.web_hook_id); }, }); diff --git a/app/assets/javascripts/admin/addon/routes/admin-web-hooks.js b/app/assets/javascripts/admin/addon/routes/admin-web-hooks.js index 4b207311360..3619142a4c2 100644 --- a/app/assets/javascripts/admin/addon/routes/admin-web-hooks.js +++ b/app/assets/javascripts/admin/addon/routes/admin-web-hooks.js @@ -1,4 +1,5 @@ import Route from "@ember/routing/route"; + export default Route.extend({ model() { return this.store.findAll("web-hook"); diff --git a/app/assets/javascripts/admin/addon/templates/components/admin-web-hook-event-chooser.hbs b/app/assets/javascripts/admin/addon/templates/components/admin-web-hook-event-chooser.hbs index 68f9a2ae9f6..b2420e4ebb9 100644 --- a/app/assets/javascripts/admin/addon/templates/components/admin-web-hook-event-chooser.hbs +++ b/app/assets/javascripts/admin/addon/templates/components/admin-web-hook-event-chooser.hbs @@ -1,3 +1,11 @@ - - -

{{this.details}}

+ diff --git a/app/assets/javascripts/admin/addon/templates/web-hooks-edit.hbs b/app/assets/javascripts/admin/addon/templates/web-hooks-edit.hbs new file mode 100644 index 00000000000..0b56fb116ff --- /dev/null +++ b/app/assets/javascripts/admin/addon/templates/web-hooks-edit.hbs @@ -0,0 +1,110 @@ + + {{d-icon "arrow-left"}} + {{i18n "admin.web_hooks.go_back"}} + + +
+

{{i18n "admin.web_hooks.detailed_instruction"}}

+ +
+
+ + + +
+ +
+ + +
+ +
+ + + +
+ +
+ + + + {{#unless this.model.wildcard_web_hook}} +
+ {{#each this.eventTypes as |type|}} + + {{/each}} +
+ {{/unless}} + + +
+ +
+
+ + +
{{i18n "admin.web_hooks.categories_filter_instructions"}}
+
+ + {{#if this.showTagsFilter}} +
+ + +
{{i18n "admin.web_hooks.tags_filter_instructions"}}
+
+ {{/if}} + +
+ + +
{{i18n "admin.web_hooks.groups_filter_instructions"}}
+
+
+ + + + + +
+ + + {{#if this.model.active}} +
{{i18n "admin.web_hooks.active_notice"}}
+ {{/if}} +
+ + +
+ + + {{#if this.model.isNew}} + + {{i18n "cancel"}} + + {{else}} + + {{i18n "cancel"}} + + {{/if}} + + {{this.savingStatus}} +
+
diff --git a/app/assets/javascripts/admin/addon/templates/web-hooks-index.hbs b/app/assets/javascripts/admin/addon/templates/web-hooks-index.hbs new file mode 100644 index 00000000000..3f4185b0fcb --- /dev/null +++ b/app/assets/javascripts/admin/addon/templates/web-hooks-index.hbs @@ -0,0 +1,68 @@ +
+

{{i18n "admin.web_hooks.instruction"}}

+ +
+ + {{d-icon "plus"}} + {{i18n "admin.web_hooks.new"}} + +
+ + {{#if this.model}} + + + + + + + + + + + + {{#each this.model as |webHook|}} + + + + + + + {{/each}} + +
{{i18n "admin.web_hooks.delivery_status.title"}}{{i18n "admin.web_hooks.payload_url"}}{{i18n "admin.web_hooks.description_label"}}{{i18n "admin.web_hooks.controls"}}
+ + + + + {{webHook.payload_url}} + {{webHook.description}} + + {{d-icon "far-edit"}} + + + +
+ +
+ {{else}} +

{{i18n "admin.web_hooks.none"}}

+ {{/if}} +
diff --git a/app/assets/javascripts/admin/addon/templates/web-hooks-show.hbs b/app/assets/javascripts/admin/addon/templates/web-hooks-show.hbs index 2ce340bc71f..91f3523d5b7 100644 --- a/app/assets/javascripts/admin/addon/templates/web-hooks-show.hbs +++ b/app/assets/javascripts/admin/addon/templates/web-hooks-show.hbs @@ -3,90 +3,32 @@ {{i18n "admin.web_hooks.go_back"}} -
-

{{i18n "admin.web_hooks.detailed_instruction"}}

-
-
- - - -
+
+

+ {{this.model.payload_url}} -
- - -
+ -
- - - -
+ +

-
- -
- - {{i18n "admin.web_hooks.individual_event"}} - -
- {{#unless this.model.wildcard_web_hook}} -
- {{#each this.eventTypes as |type|}} - - {{/each}} -
- {{/unless}} -
- - {{i18n "admin.web_hooks.wildcard_event"}} -
-
+
+ + {{i18n "admin.web_hooks.description_label"}}: + -
-
- - -
{{i18n "admin.web_hooks.categories_filter_instructions"}}
-
- {{#if this.showTagsFilter}} -
- - -
{{i18n "admin.web_hooks.tags_filter_instructions"}}
-
- {{/if}} -
- - -
{{i18n "admin.web_hooks.groups_filter_instructions"}}
-
-
- - - -
- {{i18n "admin.web_hooks.verify_certificate"}} -
-
-
- {{i18n "admin.web_hooks.active"}} -
- {{#if this.model.active}} -
{{i18n "admin.web_hooks.active_notice"}}
- {{/if}} -
- - -
- - - {{#unless this.model.isNew}} - - - {{i18n "admin.web_hooks.events.go_events"}} - - {{/unless}} - {{this.savingStatus}} + {{this.model.description}}
+ + diff --git a/app/assets/javascripts/admin/addon/templates/web-hooks.hbs b/app/assets/javascripts/admin/addon/templates/web-hooks.hbs index ecf04bb08ff..c24cd68950a 100644 --- a/app/assets/javascripts/admin/addon/templates/web-hooks.hbs +++ b/app/assets/javascripts/admin/addon/templates/web-hooks.hbs @@ -1,38 +1 @@ -
-

{{i18n "admin.web_hooks.instruction"}}

-
- - {{d-icon "plus"}} {{i18n "admin.web_hooks.new"}} - -
- {{#if this.model}} - - - - - - - - - - - - {{#each this.model as |webHook|}} - - - - - - - {{/each}} - -
{{i18n "admin.web_hooks.delivery_status.title"}}{{i18n "admin.web_hooks.payload_url"}}{{i18n "admin.web_hooks.description"}}{{i18n "admin.web_hooks.controls"}}
{{webHook.payload_url}}{{webHook.description}} - {{d-icon "far-edit"}} - -
- -
- {{else}} -

{{i18n "admin.web_hooks.none"}}

- {{/if}} -
+{{outlet}} diff --git a/app/assets/javascripts/discourse/tests/acceptance/admin-webhooks-test.js b/app/assets/javascripts/discourse/tests/acceptance/admin-webhooks-test.js new file mode 100644 index 00000000000..ce8a1057a0b --- /dev/null +++ b/app/assets/javascripts/discourse/tests/acceptance/admin-webhooks-test.js @@ -0,0 +1,72 @@ +import { acceptance } from "discourse/tests/helpers/qunit-helpers"; +import { click, currentURL, fillIn, visit } from "@ember/test-helpers"; +import { test } from "qunit"; +import pretender, { + parsePostData, + response, +} from "discourse/tests/helpers/create-pretender"; + +acceptance("Admin - Webhooks", function (needs) { + needs.user(); + + test("adding a webhook", async function (assert) { + pretender.get("/admin/api/web_hooks", () => { + return response({ + web_hooks: [], + total_rows_web_hooks: 0, + load_more_web_hooks: "/admin/api/web_hooks.json?limit=50&offset=50", + extras: { + content_types: [ + { id: 1, name: "application/json" }, + { id: 2, name: "application/x-www-form-urlencoded" }, + ], + default_event_types: [{ id: 2, name: "post" }], + delivery_statuses: [ + { id: 1, name: "inactive" }, + { id: 2, name: "failed" }, + { id: 3, name: "successful" }, + ], + event_types: [ + { id: 1, name: "topic" }, + { id: 2, name: "post" }, + { id: 3, name: "user" }, + { id: 4, name: "group" }, + ], + }, + }); + }); + + pretender.get("/admin/api/web_hook_events/1", () => { + return response({ + web_hook_events: [], + load_more_web_hook_events: + "/admin/api/web_hook_events/1.json?limit=50&offset=50", + total_rows_web_hook_events: 15, + extras: { web_hook_id: 1 }, + }); + }); + + pretender.post("/admin/api/web_hooks", (request) => { + const data = parsePostData(request.requestBody); + assert.strictEqual( + data.web_hook.payload_url, + "https://example.com/webhook" + ); + + return response({ + web_hook: { + id: 1, + // other attrs + }, + }); + }); + + await visit("/admin/api/web_hooks"); + await click(".admin-webhooks__new-button"); + + await fillIn(`[name="payload-url"`, "https://example.com/webhook"); + await click(".admin-webhooks__save-button"); + + assert.strictEqual(currentURL(), "/admin/api/web_hooks/1"); + }); +}); diff --git a/app/assets/stylesheets/common/admin/api.scss b/app/assets/stylesheets/common/admin/api.scss index 19ca2c84ecc..02a76ba0417 100644 --- a/app/assets/stylesheets/common/admin/api.scss +++ b/app/assets/stylesheets/common/admin/api.scss @@ -265,14 +265,21 @@ table.api-keys { } } -.web-hook-direction { - a, - button { - margin-right: 10px; - } +.admin-webhooks__summary { + margin-bottom: 1rem; +} + +.admin-webhooks__edit-button, +.admin-webhooks__delete-button { + font-size: var(--font-0-rem); } .web-hook-events { + .heading-container { + width: 100%; + background-color: var(--primary-low); + } + li { padding: 2px 0; } @@ -283,6 +290,13 @@ table.api-keys { overflow-y: auto; overflow-x: hidden; } + .col.heading { + font-weight: bold; + padding: 4px 0; + } + .col.heading.actions { + padding: 4px 0; + } .col.first { width: 90px; } @@ -296,18 +310,14 @@ table.api-keys { width: 250px; } .col.actions { - width: 455px; padding-top: 0; a { text-decoration: underline; } } - .col.heading.actions { - padding: 4px 0; - } .details { display: block; - margin-top: 10px; + margin-top: 1rem; } label { font-size: var(--font-0); @@ -317,10 +327,13 @@ table.api-keys { } } +.webhook-events__ping-button { + margin-bottom: 1rem; +} + .web-hook-events-listing { - margin-top: 15px; .alert { - margin: 15px 0 0 0; + margin: 0; } } diff --git a/app/assets/stylesheets/common/admin/staff_logs.scss b/app/assets/stylesheets/common/admin/staff_logs.scss index 9aa7443a2f0..a3252cc1d6d 100644 --- a/app/assets/stylesheets/common/admin/staff_logs.scss +++ b/app/assets/stylesheets/common/admin/staff_logs.scss @@ -1,28 +1,5 @@ // Styles for /admin/logs -.web-hook-events { - border-bottom: dotted 1px var(--primary-low-mid); - .heading-container { - width: 100%; - background-color: var(--primary-low); - } - .col.heading { - font-weight: bold; - padding: 4px 0; - } - .col { - display: inline-block; - padding-top: 6px; - vertical-align: top; - overflow-y: auto; - overflow-x: hidden; - } - .ember-list-item-view { - width: 100%; - border-top: solid 1px var(--primary-low); - } -} - .log-details-modal { pre { white-space: pre-wrap; diff --git a/app/controllers/admin/web_hooks_controller.rb b/app/controllers/admin/web_hooks_controller.rb index c4889a47dd0..cb747112bd4 100644 --- a/app/controllers/admin/web_hooks_controller.rb +++ b/app/controllers/admin/web_hooks_controller.rb @@ -32,6 +32,10 @@ class Admin::WebHooksController < Admin::AdminController render_serialized(@web_hook, AdminWebHookSerializer, root: 'web_hook') end + def edit + render_serialized(@web_hook, AdminWebHookSerializer, root: 'web_hook') + end + def create web_hook = WebHook.new(web_hook_params) @@ -58,9 +62,6 @@ class Admin::WebHooksController < Admin::AdminController render json: success_json end - def new - end - def list_events limit = 50 offset = params[:offset].to_i diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 7f5d2ff79e7..fa0c09f0360 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -4724,9 +4724,9 @@ en: detailed_instruction: "A POST request will be sent to provided URL when chosen event happens." new: "New Webhook" create: "Create" + edit: "Edit" save: "Save" - destroy: "Delete" - description: "Description" + description_label: "Event triggers" controls: "Controls" go_back: "Back to list" payload_url: "Payload URL" @@ -4807,9 +4807,6 @@ en: headers: "Headers" payload: "Payload" body: "Body" - go_list: "Go to list" - go_details: "Edit webhook" - go_events: "Go to events" ping: "Ping" status: "Status Code" event_id: "ID" diff --git a/config/routes.rb b/config/routes.rb index e70f12b5a9c..a60b48146be 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -300,7 +300,6 @@ Discourse::Application.routes.draw do resources :web_hooks get 'web_hook_events/:id' => 'web_hooks#list_events', as: :web_hook_events - get 'web_hooks/:id/events' => 'web_hooks#list_events' get 'web_hooks/:id/events/bulk' => 'web_hooks#bulk_events' post 'web_hooks/:web_hook_id/events/:event_id/redeliver' => 'web_hooks#redeliver_event' post 'web_hooks/:id/ping' => 'web_hooks#ping'