Gets success notifications showing in the save/publish dialogs
This commit is contained in:
@@ -1 +0,0 @@
|
||||
src/common/services/util.service.js
|
||||
@@ -252,6 +252,19 @@
|
||||
});
|
||||
}
|
||||
|
||||
function clearNotifications(content) {
|
||||
if (content.notifications) {
|
||||
content.notifications = [];
|
||||
}
|
||||
if (content.variants) {
|
||||
for (var i = 0; i < content.variants.length; i++) {
|
||||
if (content.variants[i].notifications) {
|
||||
content.variants[i].notifications = [];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function resetLastListPageNumber(content) {
|
||||
// We're using rootScope to store the page number for list views, so if returning to the list
|
||||
// we can restore the page. If we've moved on to edit a piece of content that's not the list or it's children
|
||||
@@ -341,7 +354,7 @@
|
||||
};
|
||||
|
||||
$scope.saveAndPublish = function () {
|
||||
|
||||
clearNotifications($scope.content);
|
||||
// TODO: Add "..." to publish 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 (showSaveOrPublishDialog()) {
|
||||
//before we launch the dialog we want to execute all client side validations first
|
||||
@@ -355,13 +368,16 @@
|
||||
submitButtonLabel: "Publish",
|
||||
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: contentResource.publish,
|
||||
action: "publish",
|
||||
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);
|
||||
},
|
||||
@@ -369,7 +385,6 @@
|
||||
model.submitButtonState = "error";
|
||||
//re-map the dialog model since we've re-bound the properties
|
||||
dialog.variants = $scope.content.variants;
|
||||
|
||||
//don't reject, we've handled the error
|
||||
return $q.when(err);
|
||||
});
|
||||
@@ -390,7 +405,7 @@
|
||||
};
|
||||
|
||||
$scope.save = function () {
|
||||
|
||||
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 (showSaveOrPublishDialog()) {
|
||||
//before we launch the dialog we want to execute all client side validations first
|
||||
@@ -404,13 +419,16 @@
|
||||
submitButtonLabel: "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
|
||||
}).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);
|
||||
},
|
||||
@@ -418,7 +436,6 @@
|
||||
model.submitButtonState = "error";
|
||||
//re-map the dialog model since we've re-bound the properties
|
||||
dialog.variants = $scope.content.variants;
|
||||
|
||||
//don't reject, we've handled the error
|
||||
return $q.when(err);
|
||||
});
|
||||
|
||||
@@ -26,12 +26,14 @@
|
||||
function contentResource($q, $http, umbDataFormatter, umbRequestHelper) {
|
||||
|
||||
/** internal method process the saving of data and post processing the result */
|
||||
function saveContentItem(content, action, files, restApiUrl) {
|
||||
function saveContentItem(content, action, files, restApiUrl, showNotifications) {
|
||||
|
||||
return umbRequestHelper.postSaveContent({
|
||||
restApiUrl: restApiUrl,
|
||||
content: content,
|
||||
action: action,
|
||||
files: files,
|
||||
showNotifications: showNotifications,
|
||||
dataFormatter: function (c, a) {
|
||||
return umbDataFormatter.formatContentPostData(c, a);
|
||||
}
|
||||
@@ -632,22 +634,23 @@ function contentResource($q, $http, umbDataFormatter, umbRequestHelper) {
|
||||
*
|
||||
* @param {Object} content The content item object with changes applied
|
||||
* @param {Bool} isNew set to true to create a new item or to update an existing
|
||||
* @param {Array} files collection of files for the document
|
||||
* @param {Array} files collection of files for the document
|
||||
* @param {Bool} showNotifications an option to disable/show notifications (default is true)
|
||||
* @returns {Promise} resourcePromise object containing the saved content item.
|
||||
*
|
||||
*/
|
||||
save: function (content, isNew, files) {
|
||||
save: function (content, isNew, files, showNotifications) {
|
||||
var endpoint = umbRequestHelper.getApiUrl(
|
||||
"contentApiBaseUrl",
|
||||
"PostSave");
|
||||
return saveContentItem(content, "save" + (isNew ? "New" : ""), files, endpoint);
|
||||
return saveContentItem(content, "save" + (isNew ? "New" : ""), files, endpoint, showNotifications);
|
||||
},
|
||||
|
||||
saveBlueprint: function (content, isNew, files) {
|
||||
saveBlueprint: function (content, isNew, files, showNotifications) {
|
||||
var endpoint = umbRequestHelper.getApiUrl(
|
||||
"contentApiBaseUrl",
|
||||
"PostSaveBlueprint");
|
||||
return saveContentItem(content, "save" + (isNew ? "New" : ""), files, endpoint);
|
||||
return saveContentItem(content, "save" + (isNew ? "New" : ""), files, endpoint, showNotifications);
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -674,15 +677,16 @@ function contentResource($q, $http, umbDataFormatter, umbRequestHelper) {
|
||||
*
|
||||
* @param {Object} content The content item object with changes applied
|
||||
* @param {Bool} isNew set to true to create a new item or to update an existing
|
||||
* @param {Array} files collection of files for the document
|
||||
* @param {Array} files collection of files for the document
|
||||
* @param {Bool} showNotifications an option to disable/show notifications (default is true)
|
||||
* @returns {Promise} resourcePromise object containing the saved content item.
|
||||
*
|
||||
*/
|
||||
publish: function (content, isNew, files) {
|
||||
publish: function (content, isNew, files, showNotifications) {
|
||||
var endpoint = umbRequestHelper.getApiUrl(
|
||||
"contentApiBaseUrl",
|
||||
"PostSave");
|
||||
return saveContentItem(content, "publish" + (isNew ? "New" : ""), files, endpoint);
|
||||
return saveContentItem(content, "publish" + (isNew ? "New" : ""), files, endpoint, showNotifications);
|
||||
},
|
||||
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, notifica
|
||||
|
||||
args.scope.busy = true;
|
||||
|
||||
return args.saveMethod(args.content, $routeParams.create, fileManager.getFiles())
|
||||
return args.saveMethod(args.content, $routeParams.create, fileManager.getFiles(), args.showNotifications)
|
||||
.then(function (data) {
|
||||
|
||||
formHelper.resetForm({ scope: args.scope });
|
||||
@@ -439,8 +439,7 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, notifica
|
||||
var shouldIgnore = function (propName) {
|
||||
return _.some([
|
||||
"variants",
|
||||
"notifications",
|
||||
"ModelState",
|
||||
|
||||
"tabs",
|
||||
"properties",
|
||||
"apps",
|
||||
|
||||
@@ -136,8 +136,8 @@ function umbRequestHelper($http, $q, umbDataFormatter, angularHelper, dialogServ
|
||||
|
||||
//create the callbacs based on whats been passed in.
|
||||
var callbacks = {
|
||||
success: ((!opts || !opts.success) ? defaultSuccess : opts.success),
|
||||
error: ((!opts || !opts.error) ? defaultError : opts.error)
|
||||
success: (!opts || !opts.success) ? defaultSuccess : opts.success,
|
||||
error: (!opts || !opts.error ? defaultError : opts.error)
|
||||
};
|
||||
|
||||
return httpPromise.then(function (response) {
|
||||
@@ -156,7 +156,7 @@ function umbRequestHelper($http, $q, umbDataFormatter, angularHelper, dialogServ
|
||||
//this is a JS/angular error that we should deal with
|
||||
return $q.reject({
|
||||
errorMsg: response.message
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
//invoke the callback
|
||||
@@ -188,12 +188,22 @@ function umbRequestHelper($http, $q, umbDataFormatter, angularHelper, dialogServ
|
||||
errorMsg: result.errorMsg,
|
||||
data: result.data,
|
||||
status: result.status
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
/** Used for saving content/media/members specifically */
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.resources.contentResource#postSaveContent
|
||||
* @methodOf umbraco.resources.contentResource
|
||||
*
|
||||
* @description
|
||||
* Used for saving content/media/members specifically
|
||||
*
|
||||
* @param {Object} args arguments object
|
||||
* @returns {Promise} http promise object.
|
||||
*/
|
||||
postSaveContent: function (args) {
|
||||
|
||||
if (!args.restApiUrl) {
|
||||
@@ -211,6 +221,9 @@ function umbRequestHelper($http, $q, umbDataFormatter, angularHelper, dialogServ
|
||||
if (!args.dataFormatter) {
|
||||
throw "args.dataFormatter is a required argument";
|
||||
}
|
||||
if (args.showNotifications === null || args.showNotifications === undefined) {
|
||||
args.showNotifications = true;
|
||||
}
|
||||
|
||||
//save the active tab id so we can set it when the data is returned.
|
||||
var activeTab = _.find(args.content.tabs, function (item) {
|
||||
@@ -246,7 +259,9 @@ function umbRequestHelper($http, $q, umbDataFormatter, angularHelper, dialogServ
|
||||
response.data.tabs[activeTabIndex].active = true;
|
||||
}
|
||||
|
||||
formHelper.showNotifications(response.data);
|
||||
if (args.showNotifications) {
|
||||
formHelper.showNotifications(response.data);
|
||||
}
|
||||
|
||||
//TODO: Do we need to pass the result through umbDataFormatter.formatContentGetData? Right now things work so not sure but we should check
|
||||
|
||||
@@ -278,7 +293,7 @@ function umbRequestHelper($http, $q, umbDataFormatter, angularHelper, dialogServ
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
else if (args.showNotifications) {
|
||||
formHelper.showNotifications(response.data);
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
<strong ng-if="variant.language.isMandatory" class="umb-control-required">*</strong>
|
||||
</label>
|
||||
|
||||
<div ng-if="!publishVariantSelectorForm.publishVariantSelector.$invalid">
|
||||
<div ng-if="!publishVariantSelectorForm.publishVariantSelector.$invalid && !(variant.notifications && variant.notifications.length > 0)">
|
||||
<umb-variant-state class="umb-permission__description" variant="variant"></umb-variant-state>
|
||||
</div>
|
||||
|
||||
@@ -35,6 +35,10 @@
|
||||
<div class="umb-permission__description" style="color: #F02E28;" ng-message="valServerField">{{publishVariantSelectorForm.publishVariantSelector.errorMsg}}</div>
|
||||
</div>
|
||||
|
||||
<div ng-repeat="notification in variant.notifications">
|
||||
<div class="umb-permission__description" style="color: #1FB572;">{{notification.message}}</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -27,14 +27,18 @@
|
||||
<strong ng-if="variant.language.isMandatory" class="umb-control-required">*</strong>
|
||||
</label>
|
||||
|
||||
<div ng-if="!saveVariantSelectorForm.saveVariantSelector.$invalid">
|
||||
<div ng-if="!saveVariantSelectorForm.saveVariantSelector.$invalid && !(variant.notifications && variant.notifications.length > 0)">
|
||||
<umb-variant-state class="umb-permission__description" variant="variant"></umb-variant-state>
|
||||
</div>
|
||||
|
||||
<div ng-messages="saveVariantSelectorForm.saveVariantSelector.$error" show-validation-on-submit>
|
||||
<div class="umb-permission__description" style="color: #F02E28;" ng-message="valServerField">{{saveVariantSelectorForm.saveVariantSelector.errorMsg}}</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div ng-repeat="notification in variant.notifications">
|
||||
<div class="umb-permission__description" style="color: #1FB572;">{{notification.message}}</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1396,15 +1396,15 @@ To manage your website, simply open the Umbraco back office and start adding con
|
||||
<key alias="dataTypeSaved">Datatype saved</key>
|
||||
<key alias="dictionaryItemSaved">Dictionary item saved</key>
|
||||
<key alias="editContentPublishedFailedByParent">Publishing failed because the parent page isn't published</key>
|
||||
<key alias="editVariantContentPublishedHeader">%0% variant published</key>
|
||||
<key alias="editContentPublishedHeader">Content published</key>
|
||||
<key alias="editContentPublishedText">and visible on the website</key>
|
||||
<key alias="editVariantSavedHeader">%0% variant saved</key>
|
||||
<key alias="editContentPublishedText">and is visible on the website</key>
|
||||
<key alias="editVariantPublishedText">%0% published and visible on the website</key>
|
||||
<key alias="editContentSavedHeader">Content saved</key>
|
||||
<key alias="editContentSavedText">Remember to publish to make changes visible</key>
|
||||
<key alias="editVariantSavedText">%0% saved</key>
|
||||
<key alias="editContentSendToPublish">Sent For Approval</key>
|
||||
<key alias="editContentSendToPublishText">Changes have been sent for approval</key>
|
||||
<key alias="editVariantSendToPublishText">%0% variant changes have been sent for approval</key>
|
||||
<key alias="editVariantSendToPublishText">%0% changes have been sent for approval</key>
|
||||
<key alias="editMediaSaved">Media saved</key>
|
||||
<key alias="editMediaSavedText">Media saved without any errors</key>
|
||||
<key alias="editMemberSaved">Member saved</key>
|
||||
|
||||
@@ -8,6 +8,7 @@ using System.Text;
|
||||
using System.Web.Http;
|
||||
using System.Web.Http.Controllers;
|
||||
using System.Web.Http.ModelBinding;
|
||||
using System.Web.Http.ValueProviders;
|
||||
using AutoMapper;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Logging;
|
||||
@@ -644,7 +645,12 @@ namespace Umbraco.Web.Editors
|
||||
bool wasCancelled;
|
||||
|
||||
//used to track successful notifications
|
||||
var notifications = new SimpleNotificationModel();
|
||||
var globalNotifications = new SimpleNotificationModel();
|
||||
var notifications = new Dictionary<string, SimpleNotificationModel>
|
||||
{
|
||||
//global (non variant specific) notifications
|
||||
[string.Empty] = globalNotifications
|
||||
};
|
||||
|
||||
switch (contentItem.Action)
|
||||
{
|
||||
@@ -659,14 +665,14 @@ namespace Umbraco.Web.Editors
|
||||
var cultureErrors = ModelState.GetCulturesWithPropertyErrors();
|
||||
foreach (var c in contentItem.Variants.Where(x => x.Save && !cultureErrors.Contains(x.Culture)).Select(x => x.Culture).ToArray())
|
||||
{
|
||||
notifications.AddSuccessNotification(
|
||||
Services.TextService.Localize("speechBubbles/editVariantSavedHeader", new[] {_allLangs.Value[c].CultureName}),
|
||||
Services.TextService.Localize("speechBubbles/editContentSavedText"));
|
||||
AddSuccessNotification(notifications, c,
|
||||
Services.TextService.Localize("speechBubbles/editContentSavedHeader"),
|
||||
Services.TextService.Localize("speechBubbles/editVariantSavedText", new[] {_allLangs.Value[c].CultureName}));
|
||||
}
|
||||
}
|
||||
else if (ModelState.IsValid)
|
||||
{
|
||||
notifications.AddSuccessNotification(
|
||||
globalNotifications.AddSuccessNotification(
|
||||
Services.TextService.Localize("speechBubbles/editContentSavedHeader"),
|
||||
Services.TextService.Localize("speechBubbles/editContentSavedText"));
|
||||
}
|
||||
@@ -683,14 +689,14 @@ namespace Umbraco.Web.Editors
|
||||
var cultureErrors = ModelState.GetCulturesWithPropertyErrors();
|
||||
foreach (var c in contentItem.Variants.Where(x => x.Save && !cultureErrors.Contains(x.Culture)).Select(x => x.Culture).ToArray())
|
||||
{
|
||||
notifications.AddSuccessNotification(
|
||||
AddSuccessNotification(notifications, c,
|
||||
Services.TextService.Localize("speechBubbles/editContentSendToPublish"),
|
||||
Services.TextService.Localize("speechBubbles/editVariantSendToPublishText", new[] { _allLangs.Value[c].CultureName }));
|
||||
}
|
||||
}
|
||||
else if (ModelState.IsValid)
|
||||
{
|
||||
notifications.AddSuccessNotification(
|
||||
globalNotifications.AddSuccessNotification(
|
||||
Services.TextService.Localize("speechBubbles/editContentSendToPublish"),
|
||||
Services.TextService.Localize("speechBubbles/editContentSendToPublishText"));
|
||||
}
|
||||
@@ -699,7 +705,13 @@ namespace Umbraco.Web.Editors
|
||||
case ContentSaveAction.Publish:
|
||||
case ContentSaveAction.PublishNew:
|
||||
PublishInternal(contentItem, ref publishStatus, out wasCancelled, out var successfulCultures);
|
||||
AddMessageForPublishStatus(publishStatus, notifications, successfulCultures);
|
||||
//global notifications
|
||||
AddMessageForPublishStatus(publishStatus, globalNotifications, successfulCultures);
|
||||
//variant specific notifications
|
||||
foreach (var c in successfulCultures)
|
||||
{
|
||||
AddMessageForPublishStatus(publishStatus, notifications.GetOrCreate(c), successfulCultures);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
@@ -709,7 +721,12 @@ namespace Umbraco.Web.Editors
|
||||
var display = MapToDisplay(contentItem.PersistedContent);
|
||||
|
||||
//merge the tracked success messages with the outgoing model
|
||||
display.Notifications.AddRange(notifications.Notifications);
|
||||
display.Notifications.AddRange(globalNotifications.Notifications);
|
||||
foreach (var v in display.Variants)
|
||||
{
|
||||
if (notifications.TryGetValue(v.Language.IsoCode, out var n))
|
||||
v.Notifications.AddRange(n.Notifications);
|
||||
}
|
||||
|
||||
//lasty, if it is not valid, add the modelstate to the outgoing object and throw a 403
|
||||
HandleInvalidModelState(display);
|
||||
@@ -731,6 +748,25 @@ namespace Umbraco.Web.Editors
|
||||
return display;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used to add success notifications globally and for the culture
|
||||
/// </summary>
|
||||
/// <param name="notifications"></param>
|
||||
/// <param name="culture"></param>
|
||||
/// <param name="header"></param>
|
||||
/// <param name="msg"></param>
|
||||
/// <remarks>
|
||||
/// global notifications will be shown if all variant processing is successful and the save/publish dialog is closed, otherwise
|
||||
/// variant specific notifications are used to show success messagse in the save/publish dialog.
|
||||
/// </remarks>
|
||||
private static void AddSuccessNotification(IDictionary<string, SimpleNotificationModel> notifications, string culture, string header, string msg)
|
||||
{
|
||||
//add the global notification (which will display globally if all variants are successfully processed)
|
||||
notifications[string.Empty].AddSuccessNotification(header, msg);
|
||||
//add the variant specific notification (which will display in the dialog if all variants are not successfully processed)
|
||||
notifications.GetOrCreate(culture).AddSuccessNotification(header, msg);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs the publishing operation for a content item
|
||||
/// </summary>
|
||||
@@ -1412,8 +1448,8 @@ namespace Umbraco.Web.Editors
|
||||
foreach (var c in successfulCultures)
|
||||
{
|
||||
display.AddSuccessNotification(
|
||||
Services.TextService.Localize("speechBubbles/editVariantContentPublishedHeader", new[]{ _allLangs.Value[c].CultureName}),
|
||||
Services.TextService.Localize("speechBubbles/editContentPublishedText"));
|
||||
Services.TextService.Localize("speechBubbles/editContentPublishedHeader"),
|
||||
Services.TextService.Localize("speechBubbles/editVariantPublishedText", new[] { _allLangs.Value[c].CultureName }));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
@@ -12,11 +13,12 @@ namespace Umbraco.Web.Models.ContentEditing
|
||||
/// Represents the variant info for a content item
|
||||
/// </summary>
|
||||
[DataContract(Name = "contentVariant", Namespace = "")]
|
||||
public class ContentVariantDisplay : ITabbedContent<ContentPropertyDisplay>, IContentProperties<ContentPropertyDisplay>
|
||||
public class ContentVariantDisplay : ITabbedContent<ContentPropertyDisplay>, IContentProperties<ContentPropertyDisplay>, INotificationModel
|
||||
{
|
||||
public ContentVariantDisplay()
|
||||
{
|
||||
Tabs = new List<Tab<ContentPropertyDisplay>>();
|
||||
Notifications = new List<Notification>();
|
||||
}
|
||||
|
||||
[DataMember(Name = "name", IsRequired = true)]
|
||||
@@ -59,6 +61,16 @@ namespace Umbraco.Web.Models.ContentEditing
|
||||
|
||||
[DataMember(Name = "publishDate")]
|
||||
public DateTime? PublishDate { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// This is used to add custom localized messages/strings to the response for the app to use for localized UI purposes.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The notifications assigned to a variant are currently only used to show custom messagse in the save/publish dialogs.
|
||||
/// </remarks>
|
||||
[DataMember(Name = "notifications")]
|
||||
[ReadOnly(true)]
|
||||
public List<Notification> Notifications { get; private set; }
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,9 +20,12 @@ namespace Umbraco.Web.Models.ContentEditing
|
||||
|
||||
[DataMember(Name = "header")]
|
||||
public string Header { get; set; }
|
||||
|
||||
[DataMember(Name = "message")]
|
||||
public string Message { get; set; }
|
||||
|
||||
[DataMember(Name = "type")]
|
||||
public SpeechBubbleIcon NotificationType { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user