Modifications pour le document AdminUsersSheet

Modifié par Florent Charton le 2025/08/19 15:15

Depuis la version 3.1
modifié par Florent Charton
sur 2025/07/04 23:28
Commentaire de modification : Install extension [org.xwiki.platform:xwiki-platform-administration-ui/16.10.9]
À la version 2.1
modifié par Florent Charton
sur 2024/08/08 18:43
Commentaire de modification : Install extension [org.xwiki.platform:xwiki-platform-administration-ui/15.10.11]

Résumé

Détails

Propriétés de la Page
Syntaxe
... ... @@ -1,1 +1,1 @@
1 -XWiki 2.1
1 +XWiki 2.0
Contenu
... ... @@ -1,88 +1,49 @@
1 1  {{velocity output="false"}}
2 -#macro (displayUsersLiveData)
3 - #set ($properties = ['name', 'first_name', 'last_name', '_actions'])
4 - #set ($sourceParameters = {
5 - 'template': 'getusers.vm',
6 - 'translationPrefix': 'xe.admin.users.'
2 +#macro (userScopeFilter)
3 + <select name="wiki">
4 + <option selected="selected" value="local">
5 + $escapetool.xml($services.localization.render('rightsmanager.local'))
6 + </option>
7 + <option value="global">
8 + $escapetool.xml($services.localization.render('rightsmanager.global'))
9 + </option>
10 + <option value="both">
11 + $escapetool.xml($services.localization.render('rightsmanager.both'))
12 + </option>
13 + </select>
14 +#end
15 +
16 +#macro (displayUsersLiveTable)
17 + #set ($columnOptions = {
18 + 'name': {'type': 'text', 'sortable': false, 'html': true},
19 + 'first_name': {'type': 'text', 'sortable': false},
20 + 'last_name': {'type': 'text', 'sortable': false},
21 + 'scope': {'type': 'list', 'sortable': false},
22 + '_actions': {
23 + 'actions': [
24 + 'edit',
25 + {'id': 'disable', 'icon': 'lock'},
26 + {'id': 'enable', 'icon': 'unlock'},
27 + 'delete'
28 + ],
29 + 'labels': false
30 + }
7 7   })
32 + #set ($columns = ['name', 'first_name', 'last_name', '_actions'])
33 + #set ($liveTableOptions = {
34 + 'url': $doc.getURL('view', 'xpage=getusers'),
35 + 'translationPrefix': 'xe.admin.users.',
36 + 'outputOnlyHtml': true
37 + })
8 8   #if (!$xcontext.isMainWiki())
9 - #set ($discard = $properties.add(3, 'scope'))
39 + #set ($discard = $columns.add(3, 'scope'))
40 + ## We use the top filters option to show only the local users by default because the JavaScript code from the sheet
41 + ## is executed after the livetable is loaded. The JavaScript code removes the top filters and updates the scope filter
42 + ## afterwards.
43 + #set ($liveTableOptions.topFilters = "#userScopeFilter")
10 10   #end
11 11   <div class="medium-avatars">
12 - $services.liveData.render({
13 - 'id': 'userstable',
14 - 'source': 'liveTable',
15 - 'properties': $stringtool.join($properties, ','),
16 - 'sourceParameters': $escapetool.url($sourceParameters)
17 - }, {
18 - 'query': {
19 - 'filters': [
20 - {
21 - 'property': 'scope',
22 - 'constraints': [{
23 - 'operator': 'contains',
24 - 'value': 'local'
25 - }]
26 - }
27 - ]
28 - },
29 - 'meta': {
30 - 'propertyDescriptors': [
31 - {
32 - 'id': 'name',
33 - 'displayer': 'html',
34 - 'sortable': false,
35 - 'editable': false
36 - },
37 - {
38 - 'id': 'first_name',
39 - 'sortable': false,
40 - 'editable': false
41 - },
42 - {
43 - 'id': 'last_name',
44 - 'sortable': false,
45 - 'editable': false
46 - },
47 - {
48 - 'id': 'scope',
49 - 'sortable': false,
50 - 'editable': false,
51 - 'filter': {
52 - 'id': 'list',
53 - 'options': [
54 - {'value': 'local', 'label': $services.localization.render('rightsmanager.local')},
55 - {'value': 'global', 'label': $services.localization.render('rightsmanager.global')},
56 - {'value': 'both', 'label': $services.localization.render('rightsmanager.both')}
57 - ]
58 - }
59 - },
60 - {
61 - 'id': '_actions',
62 - 'displayer': {
63 - 'id': 'actions',
64 - 'actions': ['edit', 'disable', 'enable', 'delete']
65 - }
66 - }
67 - ],
68 - 'actions': [
69 - {
70 - 'id': 'disable',
71 - 'icon': 'lock',
72 - 'allowProperty': 'doc.hasdisable',
73 - 'urlProperty': 'doc.disable_url',
74 - 'extraIconClasses': 'text-warning'
75 - },
76 - {
77 - 'id': 'enable',
78 - 'icon': 'unlock',
79 - 'allowProperty': 'doc.hasenable',
80 - 'urlProperty': 'doc.enable_url',
81 - 'extraIconClasses': 'text-success'
82 - }
83 - ]
84 - }
85 - })
46 + #livetable('userstable' $columns $columnOptions $liveTableOptions)
86 86   </div>
87 87   <p>
88 88   <button type="button" class="btn btn-primary" data-toggle="modal" data-target="${escapetool.h}createUserModal"
... ... @@ -122,7 +122,7 @@
122 122  
123 123  #macro (editUserModal)
124 124   <div class="modal" id="editUserModal" tabindex="-1" role="dialog" aria-labelledby="editUserModal-label"
125 - data-backdrop="static" data-keyboard="false" data-live-data="#userstable" data-live-data-action="edit">
86 + data-backdrop="static" data-keyboard="false" data-liveTable="#userstable" data-liveTableAction="edit">
126 126   <div class="modal-dialog modal-lg" role="document">
127 127   <div class="modal-content">
128 128   <div class="modal-header">
... ... @@ -152,7 +152,7 @@
152 152   ## have script or programming rights.
153 153   #userPicker_import
154 154   <div class="modal" id="deleteUserModal" tabindex="-1" role="dialog" aria-labelledby="deleteUserModal-label"
155 - data-live-data="#userstable" data-live-data-action="delete">
116 + data-liveTable="#userstable" data-liveTableAction="delete">
156 156   <div class="modal-dialog" role="document">
157 157   <div class="modal-content">
158 158   <div class="modal-header">
... ... @@ -209,7 +209,8 @@
209 209   <div class="box errormessage xform">
210 210   #set ($pageIndexReference = $services.model.createDocumentReference(
211 211   $userReference.wikiReference.name, 'Main', 'AllDocs'))
212 - #set ($pageIndexURL = $xwiki.getURL($pageIndexReference, 'view', "doc.author=${escapetool.url($services.model.serialize($userReference, 'local'))}"))
173 + #set ($pageIndexURL = $xwiki.getURL($pageIndexReference) + '#|t=alldocs&doc.author=' +
174 + $escapetool.url($services.model.serialize($userReference, 'local')))
213 213   #set ($translationKey = "administration.section.users.deleteUser.${right}RightsWarning")
214 214   $services.localization.render($translationKey, ["<a href='$pageIndexURL'>", $pageCount, '</a>'])
215 215   <dl>
... ... @@ -287,10 +287,10 @@
287 287   #set ($discard = $xwiki.jsx.use("XWiki.AdminUsersSheet"))
288 288  
289 289   {{html clean="false"}}
290 - #displayUsersLiveData()
291 - #createUserModal()
292 - #editUserModal()
293 - #deleteUserModal()
252 + #displayUsersLiveTable
253 + #createUserModal
254 + #editUserModal
255 + #deleteUserModal
294 294   {{/html}}
295 295   #end
296 296  #end
XWiki.JavaScriptExtension[0]
Code
... ... @@ -1,10 +1,19 @@
1 1  require.config({
2 2   paths: {
3 - 'xwiki-livedata-modal': new XWiki.Document('AdminGroupsSheet', 'XWiki').getURL('jsx', 'r=1')
3 + 'xwiki-livetable-modal': new XWiki.Document('AdminGroupsSheet', 'XWiki').getURL('jsx', 'r=1')
4 4   }
5 5  });
6 6  
7 -require(['jquery', 'xwiki-meta', 'xwiki-livedata-modal', 'xwiki-events-bridge'], function($, xm) {
7 +//
8 +// Scope Filtering
9 +//
10 +require(['jquery'], function($) {
11 + var options = $('#userstable').prev('.tipfilters').remove().find('select[name="wiki"]').html();
12 + var scopeFilter = $('#userstable .xwiki-livetable-display-filters select[name="scope"]')
13 + scopeFilter.attr('name', 'wiki').html(options);
14 +});
15 +
16 +require(['jquery', 'xwiki-meta', 'xwiki-livetable-modal', 'xwiki-events-bridge'], function($, xm) {
8 8   //
9 9   // User Creation
10 10   //
... ... @@ -45,7 +45,7 @@
45 45   notification.replace(new XWiki.widgets.Notification(errorMessage.text(), 'error'));
46 46   } else {
47 47   createUserModal.modal('hide');
48 - $('#userstable').data('liveData').updateEntries();
57 + window.livetable_userstable.refresh();
49 49   $('#userstable').trigger('xwiki:user:created');
50 50   notification.replace(new XWiki.widgets.Notification(
51 51   $jsontool.serialize($services.localization.render('xe.admin.users.create.done')),
... ... @@ -69,7 +69,7 @@
69 69   var loadEditForm = function(forceLock) {
70 70   var saveButton = editUserModal.find('.btn-primary').prop('disabled', true);
71 71   var rowData = editUserModal.data('rowData');
72 - var userReference = XWiki.Model.resolve(rowData['doc.fullName'], XWiki.EntityType.DOCUMENT, [rowData['doc.wiki']]);
81 + var userReference = XWiki.Model.resolve(rowData.doc_fullName, XWiki.EntityType.DOCUMENT, [rowData.doc_wiki]);
73 73   var userDocument = new XWiki.Document(userReference);
74 74   var editUserURL = userDocument.getURL('edit');
75 75   var parameters = {xpage: 'edituser'};
... ... @@ -103,7 +103,7 @@
103 103   $(document).trigger('xwiki:actions:beforeSave');
104 104   $.post(editForm.attr('action'), editForm.serialize()).then(() => {
105 105   $(document).trigger('xwiki:document:saved');
106 - editUserModal.modal('hide').data('liveDataElement').data('liveData').updateEntries();
115 + editUserModal.modal('hide').data('liveTable').refresh();
107 107   notification.replace(new XWiki.widgets.Notification(
108 108   $jsontool.serialize($services.localization.render('core.editors.saveandcontinue.notification.done')),
109 109   'done'
... ... @@ -137,32 +137,30 @@
137 137   failed: $jsontool.serialize($services.localization.render('administration.section.users.disableUser.failed'))
138 138   }
139 139   }
140 -
141 - function onToggleUser(action) {
142 - return function (event) {
143 - event.preventDefault();
144 - var actionTrigger = $(this);
145 - if (actionTrigger.hasClass('pending')) {
146 - // Another request is already in progress.
147 - return;
148 - }
149 - actionTrigger.addClass('pending');
150 - var notification = new XWiki.widgets.Notification(notificationMessage[action].inProgress, 'inprogress');
151 - // The enable and disable actions redirect to the user profile by default which may take a lot of time to
152 - // render so we redirect to a URL that doesn't render anything.
153 - var emptyResponseURL = new XWiki.Document('AdminUsersSheet', 'XWiki').getURL('get', 'outputSyntax=plain');
154 - Promise.resolve($.post(actionTrigger.attr('href'), {'xredirect': emptyResponseURL})).then(function () {
155 - $('#userstable').data('liveData').updateEntries();
156 - notification.replace(new XWiki.widgets.Notification(notificationMessage[action].done, 'done'));
157 - }).catch(function () {
158 - notification.replace(new XWiki.widgets.Notification(notificationMessage[action].failed, 'error'));
159 - }).finally(function () {
160 - actionTrigger.removeClass('pending');
161 - });
162 - };
163 - }
164 - $(document).on('click', '#userstable a.action_enable', onToggleUser('enable'));
165 - $(document).on('click', '#userstable a.action_disable', onToggleUser('disable'));
149 + var onToggleUser = function(event) {
150 + event.preventDefault();
151 + var actionTrigger = $(this);
152 + if (actionTrigger.hasClass('pending')) {
153 + // Another request is already in progress.
154 + return;
155 + }
156 + actionTrigger.addClass('pending');
157 + var action = event.data.action;
158 + var notification = new XWiki.widgets.Notification(notificationMessage[action].inProgress, 'inprogress');
159 + // The enable and disable actions redirect to the user profile by default which may take a lot of time to render so
160 + // we redirect to a URL that doesn't render anything.
161 + var emptyResponseURL = new XWiki.Document('AdminUsersSheet', 'XWiki').getURL('get', 'outputSyntax=plain');
162 + Promise.resolve($.post(actionTrigger.attr('href'), {'xredirect': emptyResponseURL})).then(function() {
163 + window['livetable_userstable'].refresh();
164 + notification.replace(new XWiki.widgets.Notification(notificationMessage[action].done, 'done'));
165 + }).catch(function() {
166 + notification.replace(new XWiki.widgets.Notification(notificationMessage[action].failed, 'error'));
167 + }).finally(function() {
168 + actionTrigger.removeClass('pending');
169 + });
170 + };
171 + $('#userstable').on('click', 'a.actionenable', {action: 'enable'}, onToggleUser);
172 + $('#userstable').on('click', 'a.actiondisable', {action: 'disable'}, onToggleUser);
166 166   })();
167 167  
168 168   //
... ... @@ -196,9 +196,9 @@
196 196  
197 197   deleteUserModal.on('show.bs.modal', function() {
198 198   var rowData = deleteUserModal.data('rowData');
199 - var userReference = rowData['doc.fullName'];
200 - if (XWiki.currentWiki !== rowData['doc.wiki']) {
201 - userReference = XWiki.Model.resolve(userReference, XWiki.EntityType.DOCUMENT, [rowData['doc.wiki']]);
206 + var userReference = rowData.doc_fullName;
207 + if (XWiki.currentWiki !== rowData.doc_wiki) {
208 + userReference = XWiki.Model.resolve(userReference, XWiki.EntityType.DOCUMENT, [rowData.doc_wiki]);
202 202   userReference = XWiki.Model.serialize(userReference);
203 203   }
204 204   deleteUserModal.data('userReference', userReference);
... ... @@ -252,8 +252,8 @@
252 252   newAuthor: deleteUserModal.find('#newAuthor').val(),
253 253   form_token: xm.form_token
254 254   }).then(() => {
255 - deleteUserModal.data('liveDataElement').data('liveData').updateEntries();
256 - deleteUserModal.data('liveDataElement').trigger('xwiki:user:deleted', {reference: userReference});
262 + deleteUserModal.data('liveTable').deleteRow(deleteUserModal.data('rowIndex'));
263 + deleteUserModal.data('liveTableElement').trigger('xwiki:user:deleted', {reference: userReference});
257 257   notification.replace(new XWiki.widgets.Notification(
258 258   $jsontool.serialize($services.localization.render('xe.admin.users.delete.done')),
259 259   'done'
XWiki.StyleSheetExtension[0]
Code
... ... @@ -1,4 +1,19 @@
1 +#template('colorThemeInit.vm')
2 +
1 1  /**
4 + * Users Live Table
5 + */
6 +#userstable td[data-title] {
7 + vertical-align: middle;
8 +}
9 +#userstable .actiondisable .action-icon {
10 + color: $theme.notificationWarningColor;
11 +}
12 +#userstable .actionenable .action-icon {
13 + color: $theme.notificationSuccessColor;
14 +}
15 +
16 +/**
2 2   * Delete User Modal
3 3   */
4 4  #deleteUserModal .userName {
Content Type
... ... @@ -1,1 +1,1 @@
1 -LESS
1 +CSS
Parser le contenu
... ... @@ -1,1 +1,1 @@
1 -Non
1 +Oui