Skip to content

Commit 770b2b1

Browse files
authored
XWIKI-20437: Wrong order of categories in space administration (#4813)
* Split the code of the findCustomSectionsToConfigure macro to make it a bit more readable/reusable. * Made a second lookup to get all the categories in all the cases, so that we always get all the order information. * The structures used are complex for velocity, so deep copying was needed at some point. * The $query initialization was unnecessary on modern XS. * Added comments to explain a bit more the process.
1 parent 6f42836 commit 770b2b1

File tree

1 file changed

+105
-35
lines changed

1 file changed

+105
-35
lines changed

xwiki-platform-core/xwiki-platform-administration/xwiki-platform-administration-ui/src/main/resources/XWiki/ConfigurableClassMacros.xml

Lines changed: 105 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,12 @@
4242
#set($nameOfThisDocument = 'XWiki.ConfigurableClass')
4343

4444

45-
#*
45+
#**
4646
* Try to determine whether a document was edited by a user who has edit right on this page. This is tricky because
4747
* documents are imported with the name XWiki.XWikiGuest who has no access to anything after import.
4848
*
4949
* @param theDoc - Document who's editor should be checked for edit access on this document.
50-
*###
50+
*#
5151
#macro(checkDocumentSavedByAuthorizedUser, $docToCheck, $currentDoc, $hasAccess)
5252
## The system is started and the only user is XWikiGuest who has admin right but gives it up when he imports the default
5353
## documents, we are checking to see if this looks like the guest imported the document with the first import.
@@ -65,21 +65,18 @@
6565
#end
6666

6767

68-
#*
68+
#**
6969
* Find names of documents which contain objects of the class 'XWiki.ConfigurableClass'
7070
*
7171
* @param $section - String - Look for apps which specify that they should be configured in this section,
7272
* if null or "" then returns them for all sections.
73-
*
7473
* @param $globaladmin - boolean - If true then we will look for applications which should be configured globally.
75-
*
7674
* @param $space - String - If not looking for apps which are configured globally, then this is the space where we
7775
* will look for apps in. If null or "" or if $globaladmin is true, then all spaces will be
7876
* searched.
79-
*
8077
* @param $outputList - List - The returns from this macro will be put in this list, passing the list as a parameter
8178
* a safety measure because macros can't return values.
82-
*###
79+
*#
8380
#macro(findNamesOfAppsToConfigure, $section, $globaladmin, $space, $outputList)
8481
## We keep looking in the old configureGlobally property since we do not provide a migration for it:
8582
## this choice has been made to avoid any problem during the upgrade of old wikis.
@@ -169,27 +166,27 @@
169166
#end
170167
#end
171168

172-
#*
173-
* Augment the $adminMenu variable with all $nameOfThisDocument (i.e. XWiki.ConfigurableClass) xobjects found on this wiki.
174-
*###
175-
#macro(findCustomSectionsToConfigure $adminMenu)
176-
#set ($outputList = [])
177-
#set ($global = ($editor == 'globaladmin'))
178-
#findNamesOfAppsToConfigure('', $global, $currentSpace, $outputList)
179-
#set ($sectionsByName = {})
169+
#**
170+
* Utility for findCustomSectionsToConfigure to get an adminMenu.
171+
*
172+
* @param appNames (List of Strings) Name of applications to build the adminMenu from
173+
* @param adminMenu the pre-filled content for the administration menu (macro is non-destructive on this parameter)
174+
* @param outputList
175+
*#
176+
#macro(_buildAdminMenuFromNameOfApps, $appNames, $adminMenu, $outputList)
177+
## We start by copying what's already in the adminMenu.
178+
## We can't use addAll directly because we want to make a deep copy of the structure
179+
#set ($discard = $outputList.addAll($jsontool.fromString($jsontool.serialize($adminMenu))))
180+
## Reset the category and section helper hashmaps so that they point to $outputlist and not $adminMenu anymore.
180181
#set ($categoriesByName = {})
181-
#foreach ($category in $adminMenu)
182+
#set ($sectionsByName = {})
183+
#foreach ($category in $outputList)
182184
#set ($discard = $categoriesByName.put($category.id, $category))
183185
#foreach ($section in $category.children)
184186
#set ($discard = $sectionsByName.put($section.id, $section))
185187
#end
186188
#end
187-
##
188-
#set ($query = "editor=$escapetool.url(${editor})")
189-
#if ($editor != 'globaladmin')
190-
#set ($query = $query + "&space=$escapetool.url(${currentSpace})")
191-
#end
192-
#foreach ($appName in $outputList)
189+
#foreach ($appName in $appNames)
193190
##
194191
## Get the configurable application
195192
#set ($app = $xwiki.getDocument($appName))
@@ -220,7 +217,7 @@
220217
})
221218
#set ($discard = $categoriesByName.put($displayInCategory, $appCategory))
222219
## Insert the category at the end for now. We'll sort the categories after we add all of them.
223-
#set ($discard = $adminMenu.add($appCategory))
220+
#set ($discard = $outputList.add($appCategory))
224221
#end
225222
#set ($categoryIcon = $app.getValue('categoryIcon', $configurableObject))
226223
#if ("$!categoryIcon" != '')
@@ -290,15 +287,23 @@
290287
#end
291288
#end## Foreach configurable object in this app.
292289
#end## Foreach application which is configurable.
293-
##
294-
## Sort the categories
295-
##
296-
#foreach ($category in $adminMenu)
290+
#end
291+
292+
#**
293+
* Computes the scores of categories and sorts the list. The first category will be the one with the highest score.
294+
*
295+
* @param completeOrderMenu the list of categories, containing all of the necessary ordering information;
296+
* This macro is destructive on $completeOrderMenu.
297+
*#
298+
#macro(_computeScores, $completeOrderMenu)
299+
## Initialize scores
300+
#foreach ($category in $completeOrderMenu)
297301
#set ($category.score = 0)
298302
#end
299-
#foreach ($round in [1..$adminMenu.size()])
303+
## Compute scores
304+
#foreach ($round in [1..$completeOrderMenu.size()])
300305
#set ($scoreChanged = false)
301-
#foreach ($category in $adminMenu)
306+
#foreach ($category in $completeOrderMenu)
302307
#if ($category.displayBeforeCategory)
303308
#set ($newScore = $categoriesByName.get($category.displayBeforeCategory).score + 1)
304309
#if ($newScore && $newScore > $category.score)
@@ -311,17 +316,82 @@
311316
#break
312317
#end
313318
#end
314-
#set ($adminMenu = $collectiontool.sort($adminMenu, 'score:desc'))
315319
#end
316320

321+
#**
322+
* Utility macro to compute the full order of categories, which is contained sparsely through xobjects
323+
* that are not always retrieved when building the menu.
324+
*
325+
* @param adminMenu the list of categories to use in the menu (macro is non-destructive on this parameter)
326+
* @param outputList the full list of categories, in order. Even categories without any child will be returned.
327+
*#
328+
#macro(_getCategoriesInOrder, $adminMenu, $outputList)
329+
#set ($params = {
330+
'className' : $nameOfThisDocument,
331+
'global': ['WIKI','WIKI+ALL_SPACES']
332+
})
333+
#set ($appNames = [])
334+
#set ($discard = $appNames.addAll($services.query.hql($statement).bindValues($params).execute()))
335+
## $completeOrderMenu contains a menu that contains all the information needed for sorting, no matter what.
336+
#set ($completeOrderMenu = [])
337+
#_buildAdminMenuFromNameOfApps($appNames, $adminMenu, $completeOrderMenu)
338+
## We use $completeOrderMenu to set the score of each category.
339+
#_computeScores($completeOrderMenu)
340+
#set ($completeOrderMenu = $collectiontool.sort($completeOrderMenu, 'score:desc'))
341+
## Write the now sorted $completeOrderMenu to the output variable.
342+
#set ($discard = $outputList.addAll($completeOrderMenu))
343+
#end
317344

318-
#*
319-
* Show the heading for configuration for a given application.
345+
#**
346+
* Augment the $adminMenu variable with all $nameOfThisDocument (i.e. XWiki.ConfigurableClass)
347+
* XObjects found on this wiki.
320348
*
321-
* $appName (String) Name of the application to show configuration heading for.
349+
* @param adminMenu the basis of the menu on which to add on (the macro makes hard to reverse changes on $adminMenu)
350+
*#
351+
#macro(findCustomSectionsToConfigure $adminMenu)
352+
#set ($appNames = [])
353+
#set ($global = ($editor == 'globaladmin'))
354+
#findNamesOfAppsToConfigure('', $global, $currentSpace, $appNames)
355+
##
356+
## $completedAdminMenu contains most of the info needed to build the administration menu.
357+
#set ($completedAdminMenu = [])
358+
#_buildAdminMenuFromNameOfApps($appNames, $adminMenu, $completedAdminMenu)
359+
#set ($adminMenu = [])
360+
#set ($discard = $adminMenu.addAll($completedAdminMenu))
361+
## Sort the categories
362+
## The information in $adminMenu is sometimes not enough to create a full order
363+
## in those case we need to retrieve more information to build the full order.
364+
## $categoriesFullOrder contains all the categories and their associated ordering information
365+
#if (!$global)
366+
#set ($categoriesFullOrder = [])
367+
#_getCategoriesInOrder($adminMenu, $categoriesFullOrder)
368+
## Once it's retrieved, we use this total order on the categories in contained $adminMenu.
369+
#set ($sortedAdminMenu = [])
370+
#foreach ($orderedCategory in $categoriesFullOrder)
371+
#foreach ($menuCategory in $adminMenu)
372+
#if ($orderedCategory.id == $menuCategory.id)
373+
#set ($discard = $sortedAdminMenu.add($menuCategory))
374+
#break
375+
#end
376+
#end
377+
#end
378+
#set ($adminMenu = [])
379+
#set ($discard = $adminMenu.addAll($sortedAdminMenu))
380+
#else
381+
## We're in the case where all the categories and sections are already in $adminMenu
382+
## We can easily figure out an order
383+
#_computeScores($adminMenu)
384+
#set ($adminMenu = $collectiontool.sort($adminMenu, 'score:desc'))
385+
#end
386+
#end
387+
388+
389+
#**
390+
* Show the heading for configuration for a given application.
322391
*
323-
* $headingAlreadyShowing (boolean) If true then we don't make another heading. Otherwise it is set to true.
324-
*###
392+
* @param appName (String) Name of the application to show configuration heading for.
393+
* @param headingAlreadyShowing (boolean) If true then we don't make another heading. Otherwise it is set to true.
394+
*#
325395
#macro(showHeading, $appName, $headingAlreadyShowing)
326396
#if(!$headingAlreadyShowing)
327397
#set($headingAlreadyShowing = true)

0 commit comments

Comments
 (0)