From 97d20baecb07dbac6436b915333540dbc44d3995 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Wed, 20 Jan 2021 15:30:41 +0100 Subject: [PATCH 1/8] skipValidation for content save --- .../components/content/edit.controller.js | 22 ++++++++++++------- .../services/contenteditinghelper.service.js | 19 ++++++++++------ 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js index f2dc0622c7..ac470642e7 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js @@ -271,7 +271,7 @@ * @param {any} app the active content app */ function createButtons(content) { - + var isBlueprint = content.isBlueprint; if ($scope.page.isNew && $location.path().search(/contentBlueprints/i) !== -1) { @@ -456,7 +456,8 @@ create: $scope.page.isNew, action: args.action, showNotifications: args.showNotifications, - softRedirect: true + softRedirect: true, + skipValidation: args.skipValidation }).then(function (data) { //success init(); @@ -468,7 +469,9 @@ eventsService.emit("content.saved", { content: $scope.content, action: args.action }); - resetNestedFieldValiation(fieldsToRollback); + if($scope.contentForm.$invalid !== true) { + resetNestedFieldValiation(fieldsToRollback); + } ensureDirtyIsSetIfAnyVariantIsDirty(); return $q.when(data); @@ -476,7 +479,9 @@ function (err) { syncTreeNode($scope.content, $scope.content.path); - resetNestedFieldValiation(fieldsToRollback); + if($scope.contentForm.$invalid !== true) { + resetNestedFieldValiation(fieldsToRollback); + } return $q.reject(err); }); @@ -729,9 +734,9 @@ clearNotifications($scope.content); // TODO: Add "..." to save button label if there are more than one variant to publish - currently it just adds the elipses if there's more than 1 variant if (hasVariants($scope.content)) { - //before we launch the dialog we want to execute all client side validations first - if (formHelper.submitForm({ scope: $scope, action: "openSaveDialog" })) { + //before we launch the dialog we want to execute all client side validations first + if (formHelper.submitForm({ scope: $scope, action: "openSaveDialog", skipValidation:true, keepServerValidation:true })) { var dialog = { parentScope: $scope, view: "views/content/overlays/save.html", @@ -778,7 +783,8 @@ $scope.page.saveButtonState = "busy"; return performSave({ saveMethod: $scope.saveMethod(), - action: "save" + action: "save", + skipValidation: true }).then(function () { $scope.page.saveButtonState = "success"; }, function (err) { @@ -981,7 +987,7 @@ $scope.appChanged = function (activeApp) { $scope.activeApp = activeApp; - + _.forEach($scope.content.apps, function (app) { app.active = false; if (app.alias === $scope.activeApp.alias) { diff --git a/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js b/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js index 6d41ea087d..fd0bd3efd9 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js @@ -84,7 +84,7 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, editorSt //when true, the url will change but it won't actually re-route //this is merely here for compatibility, if only the content/media/members used this service we'd prob be ok but tons of editors //use this service unfortunately and probably packages too. - args.softRedirect = false; + args.softRedirect = false; } @@ -93,7 +93,12 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, editorSt //we will use the default one for content if not specified var rebindCallback = args.rebindCallback === undefined ? self.reBindChangedProperties : args.rebindCallback; - if (formHelper.submitForm({ scope: args.scope, action: args.action })) { + var formSubmitOptions = { scope: args.scope, action: args.action }; + if(args.skipValidation === true) { + formSubmitOptions.skipValidation = true; + formSubmitOptions.keepServerValidation = true; + } + if (formHelper.submitForm(formSubmitOptions)) { return args.saveMethod(args.content, args.create, fileManager.getFiles(), args.showNotifications) .then(function (data) { @@ -298,7 +303,7 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, editorSt } // if publishing is allowed also allow schedule publish - // we add this manually becuase it doesn't have a permission so it wont + // we add this manually becuase it doesn't have a permission so it wont // get picked up by the loop through permissions if (_.contains(args.content.allowedActions, "U")) { buttons.subButtons.push(createButtonDefinition("SCHEDULE")); @@ -622,7 +627,7 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, editorSt if (!args.err) { throw "args.err cannot be null"; } - + //When the status is a 400 status with a custom header: X-Status-Reason: Validation failed, we have validation errors. //Otherwise the error is probably due to invalid data (i.e. someone mucking around with the ids or something). //Or, some strange server error @@ -640,7 +645,7 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, editorSt if (!this.redirectToCreatedContent(args.err.data.id, args.softRedirect) || args.softRedirect) { // If we are not redirecting it's because this is not newly created content, else in some cases we are - // soft-redirecting which means the URL will change but the route wont (i.e. creating content). + // soft-redirecting which means the URL will change but the route wont (i.e. creating content). // In this case we need to detect what properties have changed and re-bind them with the server data. if (args.rebindCallback && angular.isFunction(args.rebindCallback)) { @@ -687,7 +692,7 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, editorSt if (!this.redirectToCreatedContent(args.redirectId ? args.redirectId : args.savedContent.id, args.softRedirect) || args.softRedirect) { // If we are not redirecting it's because this is not newly created content, else in some cases we are - // soft-redirecting which means the URL will change but the route wont (i.e. creating content). + // soft-redirecting which means the URL will change but the route wont (i.e. creating content). // In this case we need to detect what properties have changed and re-bind them with the server data. if (args.rebindCallback && angular.isFunction(args.rebindCallback)) { @@ -723,7 +728,7 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, editorSt navigationService.setSoftRedirect(); } //change to new path - $location.path("/" + $routeParams.section + "/" + $routeParams.tree + "/" + $routeParams.method + "/" + id); + $location.path("/" + $routeParams.section + "/" + $routeParams.tree + "/" + $routeParams.method + "/" + id); //don't add a browser history for this $location.replace(); return true; From 3185a285d93a2835044b0cdc7b95301dd2929fa0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Mon, 1 Feb 2021 11:56:51 +0100 Subject: [PATCH 2/8] Correcting merge --- .../common/directives/components/content/edit.controller.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js index c3e23e4cfd..fb70143fa5 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js @@ -481,13 +481,14 @@ syncTreeNode($scope.content, $scope.content.path); + if($scope.contentForm.$invalid !== true) { + resetNestedFieldValiation(fieldsToRollback); + } if (err.status === 400 && err.data) { // content was saved but is invalid. eventsService.emit("content.saved", { content: $scope.content, action: args.action, valid: false }); } - resetNestedFieldValiation(fieldsToRollback); - return $q.reject(err); }); } From 12cde0c571318847e5a23ec58093c09b22ad7af5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Tue, 20 Apr 2021 11:10:07 +0200 Subject: [PATCH 3/8] Use warning style when saving --- .../components/content/edit.controller.js | 7 ++- .../validation/valformmanager.directive.js | 57 ++++++++++++++++++- .../services/contenteditinghelper.service.js | 18 ++++-- .../src/less/alerts.less | 16 ++++++ .../umb-editor-navigation-item.less | 23 +++++--- .../less/components/umb-nested-content.less | 6 +- .../src/less/components/umb-tabs.less | 7 +++ src/Umbraco.Web.UI.Client/src/less/forms.less | 10 ++++ .../src/less/variables.less | 4 +- .../labelblock/labelblock.editor.less | 6 ++ 10 files changed, 137 insertions(+), 17 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js index da93450522..c7f56eeda6 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js @@ -788,7 +788,12 @@ }).then(function () { $scope.page.saveButtonState = "success"; }, function (err) { - $scope.page.saveButtonState = "error"; + // Because this is the "save"-action, then we actually save though there was a validation error, therefor we will show success and display the validation errors politely. + if(err && err.data && err.data.ModelState && Object.keys(err.data.ModelState).length > 0) { + $scope.page.saveButtonState = "success"; + } else { + $scope.page.saveButtonState = "error"; + } handleHttpException(err); }); } diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/validation/valformmanager.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/validation/valformmanager.directive.js index 55878db2e9..be84d45075 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/validation/valformmanager.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/validation/valformmanager.directive.js @@ -15,6 +15,7 @@ function valFormManager(serverValidationManager, $rootScope, $timeout, $location, overlayService, eventsService, $routeParams, navigationService, editorService, localizationService, angularHelper) { var SHOW_VALIDATION_CLASS_NAME = "show-validation"; + var SHOW_VALIDATION_Type_CLASS_NAME = "show-validation-type-"; var SAVING_EVENT_NAME = "formSubmitting"; var SAVED_EVENT_NAME = "formSubmitted"; @@ -25,7 +26,7 @@ function valFormManager(serverValidationManager, $rootScope, $timeout, $location function ValFormManagerController($scope) { //This exposes an API for direct use with this directive - // We need this as a way to reference this directive in the scope chain. Since this directive isn't a component and + // We need this as a way to reference this directive in the scope chain. Since this directive isn't a component and // because it's an attribute instead of an element, we can't use controllerAs or anything like that. Plus since this is // an attribute an isolated scope doesn't work so it's a bit weird. By doing this we are able to lookup the parent valFormManager // in the scope hierarchy even if the DOM hierarchy doesn't match (i.e. in infinite editing) @@ -44,6 +45,8 @@ function valFormManager(serverValidationManager, $rootScope, $timeout, $location this.isShowingValidation = () => $scope.showValidation === true; + this.getValidationMessageType = () => $scope.valMsgType; + this.notify = notify; this.isValid = function () { @@ -94,6 +97,7 @@ function valFormManager(serverValidationManager, $rootScope, $timeout, $location var parentFormMgr = scope.parentFormMgr = getAncestorValFormManager(scope, ctrls, 1); var subView = ctrls.length > 1 ? ctrls[2] : null; var labels = {}; + var valMsgType = 2;// error var labelKeys = [ "prompt_unsavedChanges", @@ -109,6 +113,46 @@ function valFormManager(serverValidationManager, $rootScope, $timeout, $location labels.stayButton = values[3]; }); + var lastValidationMessageType = null; + function setValidationMessageType(type) { + + removeValidationMessageType(); + scope.valMsgType = type; + + // overall a copy of message types from notifications.service: + var postfix = ""; + switch(type) { + case 0: + //save + break; + case 1: + //info + postfix = "info"; + break; + case 2: + //error + postfix = "error"; + break; + case 3: + //success + postfix = "success"; + break; + case 4: + //warning + postfix = "warning"; + break; + } + var cssClass = SHOW_VALIDATION_Type_CLASS_NAME+postfix; + element.addClass(cssClass); + lastValidationMessageType = cssClass; + } + function removeValidationMessageType() { + if(lastValidationMessageType) { + element.removeClass(lastValidationMessageType); + lastValidationMessageType = null; + } + } + //watch the list of validation errors to notify the application of any validation changes // TODO: Wouldn't it be easier/faster to watch formCtrl.$invalid ? scope.$watch(() => angularHelper.countAllFormErrors(formCtrl), @@ -138,6 +182,8 @@ function valFormManager(serverValidationManager, $rootScope, $timeout, $location if (serverValidationManager.items.length > 0 || (parentFormMgr && parentFormMgr.isShowingValidation())) { element.addClass(SHOW_VALIDATION_CLASS_NAME); scope.showValidation = true; + var parentValMsgType = parentFormMgr ? parentFormMgr.getValidationMessageType() : 2; + setValidationMessageType(parentValMsgType || 2); notifySubView(); } @@ -145,8 +191,16 @@ function valFormManager(serverValidationManager, $rootScope, $timeout, $location //listen for the forms saving event unsubscribe.push(scope.$on(SAVING_EVENT_NAME, function (ev, args) { + + var messageType = 2;//error + switch (args.action) { + case "save": + messageType = 4;//warning + break; + } element.addClass(SHOW_VALIDATION_CLASS_NAME); scope.showValidation = true; + setValidationMessageType(messageType); notifySubView(); //set the flag so we can check to see if we should display the error. isSavingNewItem = $routeParams.create; @@ -156,6 +210,7 @@ function valFormManager(serverValidationManager, $rootScope, $timeout, $location unsubscribe.push(scope.$on(SAVED_EVENT_NAME, function (ev, args) { //remove validation class element.removeClass(SHOW_VALIDATION_CLASS_NAME); + removeValidationMessageType(); scope.showValidation = false; notifySubView(); })); diff --git a/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js b/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js index 8524b960c6..b7f765d8e0 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js @@ -32,7 +32,8 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, editorSt return true; } - function showNotificationsForModelsState(ms) { + function showNotificationsForModelsState(ms, messageType) { + messageType = messageType || 2; for (const [key, value] of Object.entries(ms)) { var errorMsg = value[0]; @@ -42,12 +43,14 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, editorSt var idsToErrors = serverValidationManager.parseComplexEditorError(errorMsg, ""); idsToErrors.forEach(x => { if (x.modelState) { - showNotificationsForModelsState(x.modelState); + showNotificationsForModelsState(x.modelState, messageType); } }); } else if (value[0]) { - notificationsService.error("Validation", value[0]); + //notificationsService.error("Validation", value[0]); + console.log({type:messageType, header:"Validation", message:value[0]}) + notificationsService.showNotification({type:messageType, header:"Validation", message:value[0]}) } } } @@ -124,6 +127,7 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, editorSt showNotifications: args.showNotifications, softRedirect: args.softRedirect, err: err, + action: args.action, rebindCallback: function () { // if the error contains data, we want to map that back as we want to continue editing this save. Especially important when the content is new as the returned data will contain ID etc. if(err.data) { @@ -639,9 +643,15 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, editorSt //wire up the server validation errs formHelper.handleServerValidation(args.err.data.ModelState); + var messageType = 2;//error + console.log(args) + if (args.action === "save") { + messageType = 4;//warning + } + //add model state errors to notifications if (args.showNotifications) { - showNotificationsForModelsState(args.err.data.ModelState); + showNotificationsForModelsState(args.err.data.ModelState, messageType); } if (!this.redirectToCreatedContent(args.err.data.id, args.softRedirect) || args.softRedirect) { diff --git a/src/Umbraco.Web.UI.Client/src/less/alerts.less b/src/Umbraco.Web.UI.Client/src/less/alerts.less index 3539e21064..ab0ab9aa13 100644 --- a/src/Umbraco.Web.UI.Client/src/less/alerts.less +++ b/src/Umbraco.Web.UI.Client/src/less/alerts.less @@ -54,6 +54,15 @@ border-color: @errorBorder; color: @errorText; } + +.alert-warning() { + background-color: @warningBackground; + border-color: @warningBorder; + color: @warningText; +} +.alert-warning { + .alert-warning() +} .alert-danger h4, .alert-error h4 { color: @errorText; @@ -110,6 +119,13 @@ padding: 6px 16px 6px 12px; margin-bottom: 6px; + .show-validation-type-warning & { + .alert-warning(); + &.alert-error::after { + border-top-color: @warningBackground; + } + } + &::after { content:''; position: absolute; diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-editor-navigation-item.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-editor-navigation-item.less index 5e9772fb26..5fd743aaf0 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-editor-navigation-item.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-editor-navigation-item.less @@ -86,6 +86,16 @@ } } } + + .show-validation.show-validation-type-warning &.-has-error { + color: @yellow-d2; + &:hover { + color: @yellow-d2 !important; + } + &::before { + background-color: @yellow-d2; + } + } } &__action:active, @@ -122,14 +132,6 @@ line-height: 16px; display: block; - &.-type-alert { - background-color: @red; - } - - &.-type-warning { - background-color: @yellow-d2; - } - &:empty { height: 12px; min-width: 12px; @@ -137,6 +139,11 @@ &.--error-badge { display: none; font-weight: 900; + background-color: @red; + + .show-validation-type-warning & { + background-color: @yellow-d2; + } } } diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-nested-content.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-nested-content.less index bd787e2329..9dd40a4386 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-nested-content.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-nested-content.less @@ -48,6 +48,10 @@ &.--error { border-color: @formErrorBorder !important; } + + .show-validation-type-warning &.--error { + border-color: @formWarningBorder !important; + } } .umb-nested-content__item.ui-sortable-placeholder { @@ -292,4 +296,4 @@ .umb-textarea, .umb-textstring { width:100%; } -} \ No newline at end of file +} diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-tabs.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-tabs.less index 15b317aa45..1b249f1c3a 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-tabs.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-tabs.less @@ -86,6 +86,13 @@ background-color: @red !important; border-color: @errorBorder; } +.show-validation.show-validation-type-warning .umb-tab--error > .umb-tab-button, +.show-validation.show-validation-type-warning .umb-tab--error > .umb-tab-button:hover, +.show-validation.show-validation-type-warning .umb-tab--error > .umb-tab-button:focus { + color: @white !important; + background-color: @yellow-d2 !important; + border-color: @warningBorder; +} .show-validation .umb-tab--error .umb-tab-button:before { content: "\e25d"; diff --git a/src/Umbraco.Web.UI.Client/src/less/forms.less b/src/Umbraco.Web.UI.Client/src/less/forms.less index 3782fca695..60561f9acc 100644 --- a/src/Umbraco.Web.UI.Client/src/less/forms.less +++ b/src/Umbraco.Web.UI.Client/src/less/forms.less @@ -506,10 +506,20 @@ input[type="checkbox"][readonly] { .formFieldState(@formErrorText, @formErrorText, @formErrorBackground); } +// ValidationError as a warning +.show-validation.show-validation-type-warning.ng-invalid .control-group.error, +.show-validation.show-validation-type-warning.ng-invalid .umb-editor-header__name-wrapper { + .formFieldState(@formWarningText, @formWarningText, @formWarningBackground); +} + //val-highlight directive styling .highlight-error { color: @formErrorText !important; border-color: @red-l1 !important; + .show-validation-type-warning & { + color: @formWarningText !important; + border-color: @yellow-d2 !important; + } } // FORM ACTIONS diff --git a/src/Umbraco.Web.UI.Client/src/less/variables.less b/src/Umbraco.Web.UI.Client/src/less/variables.less index cab0745a42..90cf24cf2d 100644 --- a/src/Umbraco.Web.UI.Client/src/less/variables.less +++ b/src/Umbraco.Web.UI.Client/src/less/variables.less @@ -291,8 +291,8 @@ @btnSuccessBackground: @ui-btn-positive;// updated 2019 @btnSuccessBackgroundHighlight: @ui-btn-positive-hover;// updated 2019 -@btnWarningBackground: @orange; -@btnWarningBackgroundHighlight: lighten(@orange, 10%); +@btnWarningBackground: @yellow-d2; +@btnWarningBackgroundHighlight: lighten(@yellow-d2, 10%); @btnDangerBackground: @red; @btnDangerBackgroundHighlight: @red-l1; diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/blocklistentryeditors/labelblock/labelblock.editor.less b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/blocklistentryeditors/labelblock/labelblock.editor.less index 613a47b926..837fd3f564 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/blocklistentryeditors/labelblock/labelblock.editor.less +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/blocklistentryeditors/labelblock/labelblock.editor.less @@ -42,6 +42,9 @@ ng-form.ng-invalid-val-server-match-content > .umb-block-list__block > .umb-block-list__block--content > div > & { color: @formErrorText; + .show-validation-type-warning & { + color: @formWarningText; + } } ng-form.ng-invalid-val-server-match-content > .umb-block-list__block:not(.--active) > .umb-block-list__block--content > div > & { > span { @@ -61,6 +64,9 @@ padding: 2px; line-height: 10px; background-color: @formErrorText; + .show-validation-type-warning & { + background-color: @formWarningText; + } font-weight: 900; animation-duration: 1.4s; From 021c0b82c185d82194360ed36f0d91984f0dd7e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Tue, 20 Apr 2021 11:35:40 +0200 Subject: [PATCH 4/8] final corrections --- .../components/content/edit.controller.js | 8 +++++++- src/Umbraco.Web.UI.Client/src/less/alerts.less | 1 + .../src/less/components/overlays.less | 3 +++ .../src/less/components/umb-list.less | 5 ++++- src/Umbraco.Web.UI.Client/src/less/variables.less | 2 +- .../src/views/content/overlays/save.html | 4 ++-- .../blocklist/umb-block-list-property-editor.less | 15 ++++++++++----- 7 files changed, 28 insertions(+), 10 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js index 61433c2b62..196c885b4e 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js @@ -765,7 +765,13 @@ }, function (err) { clearDirtyState($scope.content.variants); - model.submitButtonState = "error"; + //model.submitButtonState = "error"; + // Because this is the "save"-action, then we actually save though there was a validation error, therefor we will show success and display the validation errors politely. + if(err && err.data && err.data.ModelState && Object.keys(err.data.ModelState).length > 0) { + model.submitButtonState = "success"; + } else { + model.submitButtonState = "error"; + } //re-map the dialog model since we've re-bound the properties dialog.variants = $scope.content.variants; handleHttpException(err); diff --git a/src/Umbraco.Web.UI.Client/src/less/alerts.less b/src/Umbraco.Web.UI.Client/src/less/alerts.less index ab0ab9aa13..94dcef6f25 100644 --- a/src/Umbraco.Web.UI.Client/src/less/alerts.less +++ b/src/Umbraco.Web.UI.Client/src/less/alerts.less @@ -121,6 +121,7 @@ .show-validation-type-warning & { .alert-warning(); + font-weight: bold; &.alert-error::after { border-top-color: @warningBackground; } diff --git a/src/Umbraco.Web.UI.Client/src/less/components/overlays.less b/src/Umbraco.Web.UI.Client/src/less/components/overlays.less index 035bf02f91..12cce286d6 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/overlays.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/overlays.less @@ -267,6 +267,9 @@ .umb-overlay .text-error { color: @formErrorText; } +.umb-overlay .text-warning { + color: @formWarningText; +} .umb-overlay .text-success { color: @formSuccessText; diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-list.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-list.less index 57ba73305a..c281f7f5ea 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-list.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-list.less @@ -26,7 +26,10 @@ a.umb-list-item:focus { } .umb-list-item--error { - color: @red; + color: @formErrorText; +} +.umb-list-item--warning { + color: @formWarningText; } .umb-list-item:hover .umb-list-checkbox, diff --git a/src/Umbraco.Web.UI.Client/src/less/variables.less b/src/Umbraco.Web.UI.Client/src/less/variables.less index 90cf24cf2d..9d114b093e 100644 --- a/src/Umbraco.Web.UI.Client/src/less/variables.less +++ b/src/Umbraco.Web.UI.Client/src/less/variables.less @@ -480,7 +480,7 @@ @formWarningBorder: darken(spin(@warningBackground, -10), 3%); @formErrorText: @errorBackground; -@formErrorBackground: lighten(@errorBackground, 55%); +@formErrorBackground: @errorBackground; @formErrorBorder: @red; @formSuccessText: @successBackground; diff --git a/src/Umbraco.Web.UI.Client/src/views/content/overlays/save.html b/src/Umbraco.Web.UI.Client/src/views/content/overlays/save.html index fa9ab8c437..d414f30dbf 100644 --- a/src/Umbraco.Web.UI.Client/src/views/content/overlays/save.html +++ b/src/Umbraco.Web.UI.Client/src/views/content/overlays/save.html @@ -16,7 +16,7 @@
-
+
- {{saveVariantSelectorForm.saveVariantSelector.errorMsg}} + {{saveVariantSelectorForm.saveVariantSelector.errorMsg}} diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/umb-block-list-property-editor.less b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/umb-block-list-property-editor.less index 019a772fdd..fbb7e1b32e 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/umb-block-list-property-editor.less +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/umb-block-list-property-editor.less @@ -23,10 +23,6 @@ > .umb-block-list__block--actions { opacity: 0; transition: opacity 120ms; - - .--error { - color: @formErrorBorder !important; - } } &:hover, @@ -100,6 +96,12 @@ ng-form.ng-invalid-val-server-match-settings > .umb-block-list__block > .umb-blo &:hover { color: @ui-action-discreet-type-hover; } + &.--error { + color: @errorBackground; + .show-validation-type-warning & { + color: @warningBackground; + } + } > .__error-badge { position: absolute; top: -2px; @@ -113,7 +115,10 @@ ng-form.ng-invalid-val-server-match-settings > .umb-block-list__block > .umb-blo font-weight: bold; padding: 2px; line-height: 8px; - background-color: @red; + background-color: @errorBackground; + .show-validation-type-warning & { + background-color: @warningBackground; + } display: none; font-weight: 900; } From 4369747c720d2b5fa7e3c8b7c3617e3ba29a4421 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 22 Apr 2021 16:55:18 +0200 Subject: [PATCH 5/8] skip client side validation --- .../components/content/edit.controller.js | 87 +++++++++---------- 1 file changed, 39 insertions(+), 48 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js index 196c885b4e..bce797d5c8 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js @@ -442,7 +442,6 @@ // This is a helper method to reduce the amount of code repitition for actions: Save, Publish, SendToPublish function performSave(args) { - //Used to check validility of nested form - coming from Content Apps mostly //Set them all to be invalid var fieldsToRollback = checkValidility(); @@ -476,8 +475,6 @@ return $q.when(data); }, function (err) { - - syncTreeNode($scope.content, $scope.content.path); if($scope.contentForm.$invalid !== true) { @@ -739,54 +736,48 @@ clearNotifications($scope.content); // TODO: Add "..." to save button label if there are more than one variant to publish - currently it just adds the elipses if there's more than 1 variant if (hasVariants($scope.content)) { - - //before we launch the dialog we want to execute all client side validations first - if (formHelper.submitForm({ scope: $scope, action: "openSaveDialog", skipValidation:true, keepServerValidation:true })) { - var dialog = { - parentScope: $scope, - view: "views/content/overlays/save.html", - variants: $scope.content.variants, //set a model property for the dialog - skipFormValidation: true, //when submitting the overlay form, skip any client side validation - submitButtonLabelKey: "buttons_save", - submit: function (model) { - model.submitButtonState = "busy"; + var dialog = { + parentScope: $scope, + view: "views/content/overlays/save.html", + variants: $scope.content.variants, //set a model property for the dialog + skipFormValidation: true, //when submitting the overlay form, skip any client side validation + submitButtonLabelKey: "buttons_save", + submit: function (model) { + model.submitButtonState = "busy"; + clearNotifications($scope.content); + //we need to return this promise so that the dialog can handle the result and wire up the validation response + return performSave({ + saveMethod: $scope.saveMethod(), + action: "save", + showNotifications: false, + skipValidation: true + }).then(function (data) { + //show all notifications manually here since we disabled showing them automatically in the save method + formHelper.showNotifications(data); clearNotifications($scope.content); - //we need to return this promise so that the dialog can handle the result and wire up the validation response - return performSave({ - saveMethod: $scope.saveMethod(), - action: "save", - showNotifications: false - }).then(function (data) { - //show all notifications manually here since we disabled showing them automatically in the save method - formHelper.showNotifications(data); - clearNotifications($scope.content); - overlayService.close(); - return $q.when(data); - }, - function (err) { - clearDirtyState($scope.content.variants); - //model.submitButtonState = "error"; - // Because this is the "save"-action, then we actually save though there was a validation error, therefor we will show success and display the validation errors politely. - if(err && err.data && err.data.ModelState && Object.keys(err.data.ModelState).length > 0) { - model.submitButtonState = "success"; - } else { - model.submitButtonState = "error"; - } - //re-map the dialog model since we've re-bound the properties - dialog.variants = $scope.content.variants; - handleHttpException(err); - }); - }, - close: function (oldModel) { overlayService.close(); - } - }; + return $q.when(data); + }, + function (err) { + clearDirtyState($scope.content.variants); + //model.submitButtonState = "error"; + // Because this is the "save"-action, then we actually save though there was a validation error, therefor we will show success and display the validation errors politely. + if(err && err.data && err.data.ModelState && Object.keys(err.data.ModelState).length > 0) { + model.submitButtonState = "success"; + } else { + model.submitButtonState = "error"; + } + //re-map the dialog model since we've re-bound the properties + dialog.variants = $scope.content.variants; + handleHttpException(err); + }); + }, + close: function (oldModel) { + overlayService.close(); + } + }; - overlayService.open(dialog); - } - else { - showValidationNotification(); - } + overlayService.open(dialog); } else { //ensure the flags are set From dcfdcb11de0a515ca224eb57e010f700455a2e5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Mon, 3 May 2021 11:29:52 +0200 Subject: [PATCH 6/8] remove log --- .../src/common/services/contenteditinghelper.service.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js b/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js index 6ae2becf41..bab665579c 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js @@ -649,7 +649,6 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, editorSt formHelper.handleServerValidation(args.err.data.ModelState); var messageType = 2;//error - console.log(args) if (args.action === "save") { messageType = 4;//warning } From c2fd28810be3a043a5fcf84abc6fa6439af25caa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Tue, 4 May 2021 10:38:26 +0200 Subject: [PATCH 7/8] show invariant property validation issues in the save dialog --- .../components/editor/umb-variant-switcher.less | 13 ++++++++++++- .../src/views/content/overlays/save.html | 10 ++++++++-- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/less/components/editor/umb-variant-switcher.less b/src/Umbraco.Web.UI.Client/src/less/components/editor/umb-variant-switcher.less index 9d2782f184..594558da51 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/editor/umb-variant-switcher.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/editor/umb-variant-switcher.less @@ -50,6 +50,10 @@ button.umb-variant-switcher__toggle { font-weight: bold; background-color: @errorBackground; color: @errorText; + .show-validation-type-warning & { + background-color: @warningBackground; + color: @warningText; + } animation-duration: 1.4s; animation-iteration-count: infinite; @@ -233,7 +237,10 @@ button.umb-variant-switcher__toggle { .umb-variant-switcher__item.--error { .umb-variant-switcher__name { - color: @red; + color: @formErrorText; + .show-validation-type-warning & { + color: @formWarningText; + } &::after { content: '!'; position: relative; @@ -250,6 +257,10 @@ button.umb-variant-switcher__toggle { font-weight: bold; background-color: @errorBackground; color: @errorText; + .show-validation-type-warning & { + background-color: @warningBackground; + color: @warningText; + } animation-duration: 1.4s; animation-iteration-count: infinite; diff --git a/src/Umbraco.Web.UI.Client/src/views/content/overlays/save.html b/src/Umbraco.Web.UI.Client/src/views/content/overlays/save.html index d414f30dbf..36e01991df 100644 --- a/src/Umbraco.Web.UI.Client/src/views/content/overlays/save.html +++ b/src/Umbraco.Web.UI.Client/src/views/content/overlays/save.html @@ -18,15 +18,18 @@
+ + + + - * @@ -36,11 +39,14 @@ - - + {{saveVariantSelectorForm.saveVariantSelector.errorMsg}} + + {{saveVariantSelectorForm.saveInvariant.errorMsg}} + From c1dd0046040d4a5c97ea6bed420709119c4a71ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Wed, 5 May 2021 11:15:23 +0200 Subject: [PATCH 8/8] use warning color for .show-validation-type-warning --- .../inlineblock/inlineblock.editor.less | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/blocklistentryeditors/inlineblock/inlineblock.editor.less b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/blocklistentryeditors/inlineblock/inlineblock.editor.less index 45a4c08598..ffadc21866 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/blocklistentryeditors/inlineblock/inlineblock.editor.less +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/blocklistentryeditors/inlineblock/inlineblock.editor.less @@ -60,8 +60,14 @@ ng-form.ng-invalid-val-server-match-content > .umb-block-list__block > .umb-block-list__block--content > div > & { > button { color: @formErrorText; + .show-validation-type-warning & { + color: @formWarningText; + } span.caret { border-top-color: @formErrorText; + .show-validation-type-warning & { + border-top-color: @formWarningText; + } } } } @@ -84,6 +90,9 @@ padding: 2px; line-height: 10px; background-color: @formErrorText; + .show-validation-type-warning & { + background-color: @formWarningText; + } font-weight: 900; animation-duration: 1.4s;