Added "move" action for dictionaries (#12193)
* Added "move" action for dictionaries * Replaced DictionaryMove with MoveOrCopy for PostMove * Removed int parse for dictionary postmove id & parentId, changed paramtype for move in dictionary.resource * Added localizedText for new dictionary validationProblems & adjusted nullcheck for move.ParentId * Fixed logic for move dictionary parent
This commit is contained in:
@@ -3,6 +3,8 @@ using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Net.Mime;
|
||||
using System.Text;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
@@ -191,6 +193,39 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
return _umbracoMapper.Map<IDictionaryItem, DictionaryDisplay>(dictionary);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Changes the structure for dictionary items
|
||||
/// </summary>
|
||||
/// <param name="move"></param>
|
||||
/// <returns></returns>
|
||||
public IActionResult PostMove(MoveOrCopy move)
|
||||
{
|
||||
var dictionaryItem = _localizationService.GetDictionaryItemById(move.Id);
|
||||
if (dictionaryItem == null)
|
||||
return ValidationProblem(_localizedTextService.Localize("dictionary", "itemDoesNotExists"));
|
||||
|
||||
var parent = _localizationService.GetDictionaryItemById(move.ParentId);
|
||||
if (parent == null)
|
||||
{
|
||||
if (move.ParentId == Constants.System.Root)
|
||||
dictionaryItem.ParentId = null;
|
||||
else
|
||||
return ValidationProblem(_localizedTextService.Localize("dictionary", "parentDoesNotExists"));
|
||||
}
|
||||
else
|
||||
{
|
||||
dictionaryItem.ParentId = parent.Key;
|
||||
if (dictionaryItem.Key == parent.ParentId)
|
||||
return ValidationProblem(_localizedTextService.Localize("moveOrCopy", "notAllowedByPath"));
|
||||
}
|
||||
|
||||
_localizationService.Save(dictionaryItem);
|
||||
|
||||
var model = _umbracoMapper.Map<IDictionaryItem, DictionaryDisplay>(dictionaryItem);
|
||||
|
||||
return Content(model.Path, MediaTypeNames.Text.Plain, Encoding.UTF8);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves a dictionary item
|
||||
/// </summary>
|
||||
|
||||
@@ -126,7 +126,11 @@ namespace Umbraco.Cms.Web.BackOffice.Trees
|
||||
menu.Items.Add<ActionNew>(LocalizedTextService, opensDialog: true);
|
||||
|
||||
if (id != Constants.System.RootString)
|
||||
{
|
||||
menu.Items.Add<ActionDelete>(LocalizedTextService, true, opensDialog: true);
|
||||
menu.Items.Add<ActionMove>(LocalizedTextService, true, opensDialog: true);
|
||||
}
|
||||
|
||||
|
||||
menu.Items.Add(new RefreshNode(LocalizedTextService, true));
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/**
|
||||
/**
|
||||
* @ngdoc service
|
||||
* @name umbraco.resources.dictionaryResource
|
||||
* @description Loads in data for dictionary items
|
||||
@@ -96,6 +96,48 @@ function dictionaryResource($q, $http, $location, umbRequestHelper, umbDataForma
|
||||
"Failed to get item " + id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.resources.dictionaryResource#move
|
||||
* @methodOf umbraco.resources.dictionaryResource
|
||||
*
|
||||
* @description
|
||||
* Moves a dictionary item underneath a new parentId
|
||||
*
|
||||
* ##usage
|
||||
* <pre>
|
||||
* dictionaryResource.move({ parentId: 1244, id: 123 })
|
||||
* .then(function() {
|
||||
* alert("node was moved");
|
||||
* }, function(err){
|
||||
* alert("node didnt move:" + err.data.Message);
|
||||
* });
|
||||
* </pre>
|
||||
* @param {Object} args arguments object
|
||||
* @param {int} args.id the int of the dictionary item to move
|
||||
* @param {int} args.parentId the int of the parent dictionary item to move to
|
||||
* @returns {Promise} resourcePromise object.
|
||||
*
|
||||
*/
|
||||
function move (args) {
|
||||
if (!args) {
|
||||
throw "args cannot be null";
|
||||
}
|
||||
if (!args.parentId) {
|
||||
throw "args.parentId cannot be null";
|
||||
}
|
||||
if (!args.id) {
|
||||
throw "args.id cannot be null";
|
||||
}
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.post(umbRequestHelper.getApiUrl("dictionaryApiBaseUrl", "PostMove"),
|
||||
{
|
||||
parentId: args.parentId,
|
||||
id: args.id
|
||||
}, { responseType: 'text' }));
|
||||
}
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.resources.dictionaryResource#save
|
||||
@@ -151,6 +193,7 @@ function dictionaryResource($q, $http, $location, umbRequestHelper, umbDataForma
|
||||
create: create,
|
||||
getById: getById,
|
||||
save: save,
|
||||
move: move,
|
||||
getList : getList
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
angular.module("umbraco")
|
||||
.controller("Umbraco.Editors.Dictionary.MoveController",
|
||||
function ($scope, dictionaryResource, treeService, navigationService, notificationsService, appState, eventsService) {
|
||||
|
||||
$scope.dialogTreeApi = {};
|
||||
$scope.source = _.clone($scope.currentNode);
|
||||
|
||||
function nodeSelectHandler(args) {
|
||||
args.event.preventDefault();
|
||||
args.event.stopPropagation();
|
||||
|
||||
if ($scope.target) {
|
||||
//un-select if there's a current one selected
|
||||
$scope.target.selected = false;
|
||||
}
|
||||
$scope.target = args.node;
|
||||
$scope.target.selected = true;
|
||||
}
|
||||
|
||||
$scope.move = function () {
|
||||
|
||||
$scope.busy = true;
|
||||
$scope.error = false;
|
||||
|
||||
dictionaryResource.move({ parentId: $scope.target.id, id: $scope.source.id })
|
||||
.then(function (path) {
|
||||
$scope.error = false;
|
||||
$scope.success = true;
|
||||
$scope.busy = false;
|
||||
|
||||
//first we need to remove the node that launched the dialog
|
||||
treeService.removeNode($scope.currentNode);
|
||||
|
||||
//get the currently edited node (if any)
|
||||
var activeNode = appState.getTreeState("selectedNode");
|
||||
|
||||
//we need to do a double sync here: first sync to the moved content - but don't activate the node,
|
||||
//then sync to the currenlty edited content (note: this might not be the content that was moved!!)
|
||||
|
||||
navigationService.syncTree({ tree: "dictionary", path: path, forceReload: true, activate: false }).then(function (args) {
|
||||
if (activeNode) {
|
||||
var activeNodePath = treeService.getPath(activeNode).join();
|
||||
//sync to this node now - depending on what was copied this might already be synced but might not be
|
||||
navigationService.syncTree({ tree: "dictionary", path: activeNodePath, forceReload: false, activate: true });
|
||||
}
|
||||
});
|
||||
|
||||
eventsService.emit('app.refreshEditor');
|
||||
|
||||
}, function (err) {
|
||||
$scope.success = false;
|
||||
$scope.error = err;
|
||||
$scope.busy = false;
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
$scope.onTreeInit = function () {
|
||||
$scope.dialogTreeApi.callbacks.treeNodeSelect(nodeSelectHandler);
|
||||
};
|
||||
|
||||
$scope.close = function() {
|
||||
navigationService.hideDialog();
|
||||
};
|
||||
|
||||
});
|
||||
53
src/Umbraco.Web.UI.Client/src/views/dictionary/move.html
Normal file
53
src/Umbraco.Web.UI.Client/src/views/dictionary/move.html
Normal file
@@ -0,0 +1,53 @@
|
||||
<div class="umb-dialog" ng-controller="Umbraco.Editors.Dictionary.MoveController">
|
||||
|
||||
<div class="umb-dialog-body">
|
||||
<div class="umb-pane">
|
||||
|
||||
<p class="abstract" ng-hide="success">
|
||||
<localize key="actions_chooseWhereToMove">Choose where to move </localize> <strong>{{source.name}}</strong> <localize key="contentTypeEditor_structureBelow">to in the tree structure below</localize>
|
||||
</p>
|
||||
|
||||
<umb-loader ng-show="busy"></umb-loader>
|
||||
|
||||
<div ng-show="error">
|
||||
<div class="alert alert-error">
|
||||
<div><strong>{{error.errorMsg}}</strong></div>
|
||||
<div>{{error.data.message}}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div ng-show="success">
|
||||
<div class="alert alert-success">
|
||||
<strong>{{source.name}}</strong> <localize key="contentTypeEditor_movedUnderneath">was moved underneath</localize> <strong>{{target.name}}</strong>
|
||||
</div>
|
||||
<button type="button" class="btn btn-primary" ng-click="close()">Ok</button>
|
||||
</div>
|
||||
|
||||
<div ng-hide="success">
|
||||
|
||||
<div>
|
||||
<umb-tree section="translation"
|
||||
treealias="dictionary"
|
||||
customtreeparams="foldersonly=1"
|
||||
hideheader="false"
|
||||
hideoptions="true"
|
||||
isdialog="true"
|
||||
api="dialogTreeApi"
|
||||
on-init="onTreeInit()"
|
||||
enablecheckboxes="true">
|
||||
</umb-tree>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="umb-dialog-footer btn-toolbar umb-btn-toolbar" ng-hide="success">
|
||||
<button type="button" class="btn btn-link" ng-click="close()" ng-show="!busy">
|
||||
<localize key="general_cancel">Cancel</localize>
|
||||
</button>
|
||||
<button class="btn btn-primary" ng-click="move()" ng-disabled="busy || !target">
|
||||
<localize key="actions_move">Move</localize>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -569,6 +569,8 @@
|
||||
<key alias="deletingALayout">Modifying layout will result in loss of data for any existing content that is based on this configuration.</key>
|
||||
</area>
|
||||
<area alias="dictionary">
|
||||
<key alias="itemDoesNotExists">Dictionary item does not exist.</key>
|
||||
<key alias="parentDoesNotExists">Parent item does not exist.</key>
|
||||
<key alias="noItems">There are no dictionary items.</key>
|
||||
<key alias="createNew">Create dictionary item</key>
|
||||
</area>
|
||||
|
||||
@@ -579,6 +579,8 @@
|
||||
<key alias="deletingALayout">Modifying layout will result in loss of data for any existing content that is based on this configuration.</key>
|
||||
</area>
|
||||
<area alias="dictionary">
|
||||
<key alias="itemDoesNotExists">Dictionary item does not exist.</key>
|
||||
<key alias="parentDoesNotExists">Parent item does not exist.</key>
|
||||
<key alias="noItems">There are no dictionary items.</key>
|
||||
<key alias="createNew">Create dictionary item</key>
|
||||
</area>
|
||||
|
||||
Reference in New Issue
Block a user