diff --git a/src/Umbraco.Core/Constants-Icons.cs b/src/Umbraco.Core/Constants-Icons.cs index 5aaeb2ba61af..a18ff387e7bf 100644 --- a/src/Umbraco.Core/Constants-Icons.cs +++ b/src/Umbraco.Core/Constants-Icons.cs @@ -5,7 +5,7 @@ public static partial class Constants public static class Icons { /// - /// System default icon + /// System default icon. /// public const string DefaultIcon = Content; @@ -15,37 +15,37 @@ public static class Icons public const string Blueprint = "icon-blueprint"; /// - /// System content icon + /// System content icon. /// public const string Content = "icon-document"; /// - /// System content type icon + /// System content type icon. /// public const string ContentType = "icon-item-arrangement"; /// - /// System data type icon + /// System data type icon. /// public const string DataType = "icon-autofill"; /// - /// System dictionary icon + /// System dictionary icon. /// public const string Dictionary = "icon-book-alt"; /// - /// System generic folder icon + /// System generic folder icon. /// public const string Folder = "icon-folder"; /// - /// System language icon + /// System language icon. /// public const string Language = "icon-globe"; /// - /// System logviewer icon + /// System logviewer icon. /// public const string LogViewer = "icon-box-alt"; @@ -55,12 +55,12 @@ public static class Icons public const string ListView = "icon-thumbnail-list"; /// - /// System macro icon + /// System macro icon. /// public const string Macro = "icon-settings-alt"; /// - /// System media file icon + /// System media file icon. /// public const string MediaFile = "icon-document"; @@ -70,7 +70,7 @@ public static class Icons public const string MediaVideo = "icon-video"; /// - /// System media audio icon + /// System media audio icon. /// public const string MediaAudio = "icon-sound-waves"; @@ -80,12 +80,12 @@ public static class Icons public const string MediaArticle = "icon-article"; /// - /// System media vector icon + /// System media vector icon. /// public const string MediaVectorGraphics = "icon-picture"; /// - /// System media folder icon + /// System media folder icon. /// public const string MediaFolder = "icon-folder"; @@ -95,17 +95,17 @@ public static class Icons public const string MediaImage = "icon-picture"; /// - /// System media type icon + /// System media type icon. /// public const string MediaType = "icon-thumbnails"; /// - /// System member icon + /// System member icon. /// public const string Member = "icon-user"; /// - /// System member group icon + /// System member group icon. /// public const string MemberGroup = "icon-users-alt"; @@ -115,8 +115,14 @@ public static class Icons public const string MemberType = "icon-users"; /// - /// System packages icon + /// System package icon. /// + public const string Package = "icon-box"; + + /// + /// System packages icon. + /// + [Obsolete("Use Package icon instead.")] public const string Packages = "icon-box"; /// @@ -125,43 +131,43 @@ public static class Icons public const string PartialView = "icon-article"; /// - /// System property editor icon + /// System property editor icon. /// public const string PropertyEditor = "icon-autofill"; /// - /// Relation type icon + /// Relation type icon. /// public const string RelationType = "icon-trafic"; /// - /// Script type icon + /// Script type icon. /// public const string Script = "icon-script"; /// - /// Stylesheet type icon + /// Stylesheet type icon. /// public const string Stylesheet = "icon-brackets"; /// - /// System member icon + /// System member icon. /// public const string Template = "icon-layout"; /// - /// System user icon + /// System user icon. /// public const string User = "icon-user"; /// - /// System user group icon + /// System user group icon. /// public const string UserGroup = "icon-users"; /// - /// Webhooks icon + /// Webhook icon. /// - public const string Webhooks = "icon-directions-alt"; + public const string Webhook = "icon-webhook"; } } diff --git a/src/Umbraco.Core/EmbeddedResources/Lang/da.xml b/src/Umbraco.Core/EmbeddedResources/Lang/da.xml index 73087fff306e..bc5ef17f953c 100644 --- a/src/Umbraco.Core/EmbeddedResources/Lang/da.xml +++ b/src/Umbraco.Core/EmbeddedResources/Lang/da.xml @@ -1813,6 +1813,7 @@ Mange hilsner fra Umbraco robotten Indstillinger Design og layout Tredjepart + Webhooks Ny opdatering er klar diff --git a/src/Umbraco.Core/EmbeddedResources/Lang/en.xml b/src/Umbraco.Core/EmbeddedResources/Lang/en.xml index 8c355540438e..40be1cfd22e8 100644 --- a/src/Umbraco.Core/EmbeddedResources/Lang/en.xml +++ b/src/Umbraco.Core/EmbeddedResources/Lang/en.xml @@ -2033,6 +2033,7 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Settings Templating Third Party + Webhooks New update ready diff --git a/src/Umbraco.Web.BackOffice/Trees/PackagesTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/PackagesTreeController.cs index 88f04ba82398..2fec0ae07548 100644 --- a/src/Umbraco.Web.BackOffice/Trees/PackagesTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/PackagesTreeController.cs @@ -45,7 +45,7 @@ public PackagesTreeController( { // This will load in a custom UI instead of the dashboard for the root node root.RoutePath = $"{Constants.Applications.Packages}/{Constants.Trees.Packages}/repo"; - root.Icon = Constants.Icons.Packages; + root.Icon = Constants.Icons.Package; root.HasChildren = false; } diff --git a/src/Umbraco.Web.BackOffice/Trees/WebhooksTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/WebhooksTreeController.cs index 5f315f3cbb60..c8a7f7707c76 100644 --- a/src/Umbraco.Web.BackOffice/Trees/WebhooksTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/WebhooksTreeController.cs @@ -1,4 +1,4 @@ -using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Umbraco.Cms.Core; @@ -52,7 +52,7 @@ protected override ActionResult GetMenuForNode(string id, Fo { // This will load in a custom UI instead of the dashboard for the root node root.RoutePath = $"{Constants.Applications.Settings}/{Constants.Trees.Webhooks}/overview"; - root.Icon = Constants.Icons.Webhooks; + root.Icon = Constants.Icons.Webhook; root.HasChildren = false; root.MenuUrl = null; } diff --git a/src/Umbraco.Web.UI.Client/src/assets/icons/icon-webhook.svg b/src/Umbraco.Web.UI.Client/src/assets/icons/icon-webhook.svg new file mode 100644 index 000000000000..a7c4a876805c --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/assets/icons/icon-webhook.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/views/webhooks/logs.controller.js b/src/Umbraco.Web.UI.Client/src/views/webhooks/logs.controller.js index 11f5debee9da..b278638e34bb 100644 --- a/src/Umbraco.Web.UI.Client/src/views/webhooks/logs.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/webhooks/logs.controller.js @@ -1,20 +1,34 @@ -(function () { +(function () { "use strict"; - function WebhookLogController($q,$scope, webhooksResource, notificationsService, overlayService) { - var vm = this; + function WebhookLogController($q, webhooksResource, overlayService) { + + const vm = this; + vm.logs = []; vm.openLogOverlay = openLogOverlay; vm.isChecked = isChecked; - function loadLogs (){ + function init() { + vm.loading = true; + + let promises = []; + + promises.push(loadLogs()); + + $q.all(promises).then(function () { + vm.loading = false; + }); + } + + function loadLogs() { return webhooksResource.getLogs() - .then((data) => { + .then(data => { vm.logs = data.items; }); } - function openLogOverlay (log) { + function openLogOverlay(log) { overlayService.open({ view: "views/webhooks/overlays/details.html", title: 'Details', @@ -27,11 +41,11 @@ }); } - function isChecked (log) { + function isChecked(log) { return log.statusCode === "OK"; } - loadLogs(); + init(); } angular.module("umbraco").controller("Umbraco.Editors.Webhooks.WebhookLogController", WebhookLogController); diff --git a/src/Umbraco.Web.UI.Client/src/views/webhooks/logs.html b/src/Umbraco.Web.UI.Client/src/views/webhooks/logs.html index 10603d0ac149..6c13daf764a1 100644 --- a/src/Umbraco.Web.UI.Client/src/views/webhooks/logs.html +++ b/src/Umbraco.Web.UI.Client/src/views/webhooks/logs.html @@ -1,47 +1,30 @@ -
+
- - - - - - - - + + + + + + + + - - - - - - - - - + + + + + + + +
Webhook keyDateUrlEventRetryCount
Webhook keyDateUrlEventRetry count
- - - - - {{ log.webhookKey}} - - {{ log.date}} - - {{ log.url }} - - {{ log.eventName }} - - {{ log.retryCount}} - - - -
+ + + {{ log.webhookKey }}{{ log.date }}{{ log.url }}{{ log.eventName }}{{ log.retryCount }}
diff --git a/src/Umbraco.Web.UI.Client/src/views/webhooks/overlays/details.html b/src/Umbraco.Web.UI.Client/src/views/webhooks/overlays/details.html index 9c0856cb676a..3878c1ae877f 100644 --- a/src/Umbraco.Web.UI.Client/src/views/webhooks/overlays/details.html +++ b/src/Umbraco.Web.UI.Client/src/views/webhooks/overlays/details.html @@ -1,9 +1,9 @@ -
+
- +
{{model.webhookLogEntry.response.statusDescription}} ({{model.webhookLogEntry.response.statusCode}})
@@ -17,7 +17,7 @@
{{model.log.url}}
- Status Code + Status code
{{model.log.statusCode}}
diff --git a/src/Umbraco.Web.UI.Client/src/views/webhooks/overlays/edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/webhooks/overlays/edit.controller.js index c25ccaa6ba67..9df465f73815 100644 --- a/src/Umbraco.Web.UI.Client/src/views/webhooks/overlays/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/webhooks/overlays/edit.controller.js @@ -1,8 +1,10 @@ -(function () { +(function () { "use strict"; function EditController($scope, editorService, contentTypeResource, mediaTypeResource) { - var vm = this; + + const vm = this; + vm.clearContentType = clearContentType; vm.clearEvent = clearEvent; vm.removeHeader = removeHeader; @@ -12,9 +14,7 @@ vm.close = close; vm.submit = submit; - - function openEventPicker() - { + function openEventPicker() { editorService.eventPicker({ title: "Select event", selectedEvents: $scope.model.webhook.events, @@ -28,23 +28,39 @@ }); } - function openContentTypePicker() - { + function openContentTypePicker() { const isContent = $scope.model.webhook ? $scope.model.webhook.events[0].toLowerCase().includes("content") : null; - editorService.treePicker({ - section: 'settings', - treeAlias: isContent ? 'documentTypes' : 'mediaTypes', - entityType: isContent ? 'DocumentType' : 'MediaType', + + const editor = { multiPicker: true, + filterCssClass: "not-allowed not-published", + filter: function (item) { + // filter out folders (containers), element types (for content) and already selected items + return item.nodeType === "container"; // || item.metaData.isElement || !!_.findWhere(vm.itemTypes, { udi: item.udi }); + }, submit(model) { getEntities(model.selection, isContent); - $scope.model.webhook.contentTypeKeys = model.selection.map((item) => item.key); + $scope.model.webhook.contentTypeKeys = model.selection.map(item => item.key); editorService.close(); }, close() { editorService.close(); } - }); + }; + + const itemType = isContent ? "content" : "media"; + + switch (itemType) { + case "content": + editorService.contentTypePicker(editor); + break; + case "media": + editorService.mediaTypePicker(editor); + break; + case "member": + editorService.memberTypePicker(editor); + break; + } } function openCreateHeader() { @@ -70,29 +86,29 @@ const resource = isContent ? contentTypeResource : mediaTypeResource; $scope.model.contentTypes = []; - selection.forEach((entity) => { + selection.forEach(entity => { resource.getById(entity.key) - .then((data) => { + .then(data => { $scope.model.contentTypes.push(data); }); }); } function clearContentType(contentTypeKey) { - if (Array.isArray($scope.model.webhook.contentTypeKeys)) { + if (Utilities.isArray($scope.model.webhook.contentTypeKeys)) { $scope.model.webhook.contentTypeKeys = $scope.model.webhook.contentTypeKeys.filter(x => x !== contentTypeKey); } - if (Array.isArray($scope.model.contentTypes)) { + if (Utilities.isArray($scope.model.contentTypes)) { $scope.model.contentTypes = $scope.model.contentTypes.filter(x => x.key !== contentTypeKey); } } function clearEvent(event) { - if (Array.isArray($scope.model.webhook.events)) { + if (Utilities.isArray($scope.model.webhook.events)) { $scope.model.webhook.events = $scope.model.webhook.events.filter(x => x !== event); } - if (Array.isArray($scope.model.contentTypes)) { + if (Utilities.isArray($scope.model.contentTypes)) { $scope.model.events = $scope.model.events.filter(x => x.key !== event); } } @@ -101,16 +117,13 @@ delete $scope.model.webhook.headers[key]; } - - function close() - { + function close() { if ($scope.model.close) { $scope.model.close(); } } - function submit() - { + function submit() { if ($scope.model.submit) { $scope.model.submit($scope.model); } diff --git a/src/Umbraco.Web.UI.Client/src/views/webhooks/overlays/edit.html b/src/Umbraco.Web.UI.Client/src/views/webhooks/overlays/edit.html index 40e216c79a44..cf55320f2f5f 100644 --- a/src/Umbraco.Web.UI.Client/src/views/webhooks/overlays/edit.html +++ b/src/Umbraco.Web.UI.Client/src/views/webhooks/overlays/edit.html @@ -1,4 +1,4 @@ -
+
- + + + + - + + - + ng-click="vm.openEventPicker()"> Add - + + - + + - - Add - - Please select an event first. + ng-disabled="!model.webhook.events || model.webhook.events.length === 0" + ng-click="vm.openContentTypePicker()"> + + Add + + + Please select an event first. + + + @@ -78,8 +95,11 @@ on-click="model.webhook.enabled = !model.webhook.enabled"> - + + @@ -89,12 +109,8 @@ - - + +
- {{ key }} - - {{ value }} - {{key}}{{value}}
- + +
diff --git a/src/Umbraco.Web.UI.Client/src/views/webhooks/overlays/header.controller.js b/src/Umbraco.Web.UI.Client/src/views/webhooks/overlays/header.controller.js index a77a4f5c0065..298cb95bd8fc 100644 --- a/src/Umbraco.Web.UI.Client/src/views/webhooks/overlays/header.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/webhooks/overlays/header.controller.js @@ -1,11 +1,15 @@ -(function () { +(function () { "use strict"; function HeaderController($scope) { - var vm = this; - $scope.headerModel = { key: "", value: "" }; + const vm = this; + vm.submit = submit; vm.close = close; + vm.headers = ["Accept", "Content-Type", "User-Agent", "Content-Length"]; + + $scope.headerModel = { key: "", value: "" }; + function submit () { if ($scope.headerModel.key && $scope.headerModel.value) { $scope.model.submit($scope.headerModel); diff --git a/src/Umbraco.Web.UI.Client/src/views/webhooks/overlays/header.html b/src/Umbraco.Web.UI.Client/src/views/webhooks/overlays/header.html index b9adcb2bf6fe..114eab70c956 100644 --- a/src/Umbraco.Web.UI.Client/src/views/webhooks/overlays/header.html +++ b/src/Umbraco.Web.UI.Client/src/views/webhooks/overlays/header.html @@ -1,8 +1,8 @@ -
+
- + + required /> + + + - + { vm.page.labels.webhooks = data[0]; vm.page.labels.logs = data[1]; vm.page.navigation = [ { "name": vm.page.labels.webhooks, - "icon": "icon-directions-alt", + "icon": "icon-webhook", "view": "views/webhooks/webhooks.html", "active": webhookUri === 'overview', "alias": "umbWebhooks", @@ -53,7 +55,7 @@ } function setPageName() { - localizationService.localize("treeHeaders_webhooks").then(function (data) { + localizationService.localize("treeHeaders_webhooks").then(data => { vm.page.name = data; }) } diff --git a/src/Umbraco.Web.UI.Client/src/views/webhooks/overview.html b/src/Umbraco.Web.UI.Client/src/views/webhooks/overview.html index 2576fa1e8b34..981cf09f4486 100644 --- a/src/Umbraco.Web.UI.Client/src/views/webhooks/overview.html +++ b/src/Umbraco.Web.UI.Client/src/views/webhooks/overview.html @@ -1,13 +1,14 @@ -
+
- + diff --git a/src/Umbraco.Web.UI.Client/src/views/webhooks/webhooks.controller.js b/src/Umbraco.Web.UI.Client/src/views/webhooks/webhooks.controller.js index 5814d6f6dc27..94b1c2174246 100644 --- a/src/Umbraco.Web.UI.Client/src/views/webhooks/webhooks.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/webhooks/webhooks.controller.js @@ -1,8 +1,9 @@ -(function () { +(function () { "use strict"; - function WebhookController($q,$scope, webhooksResource, notificationsService, editorService, overlayService, contentTypeResource, mediaTypeResource) { - var vm = this; + function WebhookController($q, $timeout, $routeParams, webhooksResource, navigationService, notificationsService, editorService, overlayService, contentTypeResource, mediaTypeResource) { + + const vm = this; vm.openWebhookOverlay = openWebhookOverlay; vm.deleteWebhook = deleteWebhook; @@ -16,15 +17,33 @@ vm.webHooksContentTypes = {}; vm.webhookEvents = {}; - function loadEvents (){ + function init() { + vm.loading = true; + + let promises = []; + + promises.push(loadEvents()); + promises.push(loadWebhooks()); + + $q.all(promises).then(function () { + vm.loading = false; + }); + + // Activate tree node + $timeout(function () { + navigationService.syncTree({ tree: $routeParams.tree, path: [-1], activate: true }); + }); + } + + function loadEvents() { return webhooksResource.getAllEvents() - .then((data) => { + .then(data => { vm.events = data.map(item => item.eventName); }); } function resolveEventNames(webhook) { - webhook.events.forEach((event) => { + webhook.events.forEach(event => { if (!vm.webhookEvents[webhook.key]) { vm.webhookEvents[webhook.key] = event; } else { @@ -38,9 +57,9 @@ const resource = isContent ? contentTypeResource : mediaTypeResource; let entities = []; - webhook.contentTypeKeys.forEach((key) => { + webhook.contentTypeKeys.forEach(key => { resource.getById(key) - .then((data) => { + .then(data => { entities.push(data); }); }); @@ -56,9 +75,9 @@ delete vm.webHooksContentTypes[webhook.key]; } - webhook.contentTypeKeys.forEach((key) => { + webhook.contentTypeKeys.forEach(key => { resource.getById(key) - .then((data) => { + .then(data => { if (!vm.webHooksContentTypes[webhook.key]) { vm.webHooksContentTypes[webhook.key] = data.name; } else { @@ -97,7 +116,8 @@ handleSubmissionError(model, 'Please provide the event for which the webhook should trigger'); return; } - if(isCreating){ + + if (isCreating) { webhooksResource.create(model.webhook) .then(() => { loadWebhooks() @@ -111,7 +131,7 @@ handleSubmissionError(model, `Error saving webhook. ${errorMessage ?? ''}`); }); } - else{ + else { webhooksResource.update(model.webhook) .then(() => { loadWebhooks() @@ -136,19 +156,19 @@ function loadWebhooks(){ webhooksResource .getAll() - .then((result) => { + .then(result => { vm.webhooks = result; vm.webhookEvents = {}; vm.webHooksContentTypes = {}; - vm.webhooks.forEach((webhook) => { + vm.webhooks.forEach(webhook => { resolveTypeNames(webhook); resolveEventNames(webhook); }) }); } - function deleteWebhook (webhook) { + function deleteWebhook (webhook, event) { overlayService.open({ title: 'Confirm delete webhook', content: 'Are you sure you want to delete the webhook?', @@ -171,10 +191,12 @@ overlayService.close(); } }); + + event.preventDefault(); + event.stopPropagation(); } - loadWebhooks() - loadEvents() + init(); } angular.module("umbraco").controller("Umbraco.Editors.Webhooks.WebhookController", WebhookController); diff --git a/src/Umbraco.Web.UI.Client/src/views/webhooks/webhooks.html b/src/Umbraco.Web.UI.Client/src/views/webhooks/webhooks.html index 241a4a2015a3..e6f4e8f53d46 100644 --- a/src/Umbraco.Web.UI.Client/src/views/webhooks/webhooks.html +++ b/src/Umbraco.Web.UI.Client/src/views/webhooks/webhooks.html @@ -1,4 +1,4 @@ -
+
@@ -17,7 +17,6 @@ - @@ -27,27 +26,24 @@ - - + +
Enabled Events Url
- + - {{ vm.webhookEvents[webhook.key] }} - {{ webhook.url }} - - {{ vm.webHooksContentTypes[webhook.key] }} - {{ webhook.url }}{{ vm.webHooksContentTypes[webhook.key] }} - +