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:
Johannes Lantz
2022-04-04 17:14:03 +02:00
committed by GitHub
parent 534ca928b4
commit 057b304a5a
7 changed files with 206 additions and 1 deletions

View File

@@ -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>

View File

@@ -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));

View File

@@ -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
};

View File

@@ -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();
};
});

View 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>&nbsp;<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>&nbsp;<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>

View File

@@ -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>

View File

@@ -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>