Wiki source code of Nested Pages Migration
Last modified by Sascha Hoppe on 2023/07/06 12:45
Show last authors
author | version | line-number | content |
---|---|---|---|
1 | {{velocity output="false"}} | ||
2 | #************************************************************************ | ||
3 | * Compute and return the maximum authorized length for the full name. | ||
4 | ************************************************************************# | ||
5 | #macro(getLocalReferenceMaxLength) | ||
6 | #set ($localReferenceMaxLength = '255') | ||
7 | ## Available since XWiki 11.4RC1. | ||
8 | #if ($doc.localReferenceMaxLength) | ||
9 | #set ($localReferenceMaxLength = $doc.localReferenceMaxLength) | ||
10 | #end | ||
11 | ## The document reference size limit was increased from 255 to 768 (the maximum supported by MySQL) in XWiki 13.2. | ||
12 | #if ($services.extension.core.getCoreExtension('org.xwiki.platform:xwiki-platform-model').id.version.compareTo('13.2') >= 0) | ||
13 | #set ($localReferenceMaxLength = $mathtool.sub($localReferenceMaxLength, $xcontext.database.length())) | ||
14 | #else | ||
15 | ## To avoid issues with documents with path too long, take some extra margin, higher than the wiki name length. | ||
16 | #set ($localReferenceMaxLength = $mathtool.sub($localReferenceMaxLength, 50)) | ||
17 | #end | ||
18 | $localReferenceMaxLength | ||
19 | #end | ||
20 | {{/velocity}} | ||
21 | |||
22 | {{velocity}} | ||
23 | #if (!$services.security.authorization.hasAccess('admin', $xcontext.userReference, $doc.documentReference.wikiReference)) | ||
24 | {{error}} | ||
25 | You don't have the right to use this tool on this wiki. You need to be administrator. | ||
26 | {{/error}} | ||
27 | #else | ||
28 | ## Both job.css and extension.css are needed because the ui-progress classes that we need to display | ||
29 | ## a progress bar are in one of these 2 files depending on the XWiki version | ||
30 | #set ($discard = $xwiki.ssfx.use('uicomponents/job/job.css', true)) | ||
31 | #set ($discard = $xwiki.ssfx.use('uicomponents/extension/extension.css', true)) | ||
32 | #set ($discard = $xwiki.ssfx.use('uicomponents/logging/logging.css', true)) | ||
33 | #set ($discard = $xwiki.linkx.use($services.webjars.url('org.xwiki.platform:xwiki-platform-tree-webjar', 'tree.min.css', | ||
34 | {'evaluate': true}), {'type': 'text/css', 'rel': 'stylesheet'})) | ||
35 | {{html clean="false"}} | ||
36 | <!------------------------------------------ | ||
37 | Migration Action Template | ||
38 | -------------------------------------------> | ||
39 | <script id="MigrationActionTemplate" type="text/html"> | ||
40 | <!-- ko foreach: ${escapetool.d}data.actions --> | ||
41 | <li class="jstree-node" data-bind=" | ||
42 | visible: (!targetDocument.equals(sourceDocument) || getNumberOfChildren() > 0 || getNumberOfPreferences() > 0 || getNumberOfRights()> 0), | ||
43 | css: { | ||
44 | 'jstree-closed': !displayChildren(), | ||
45 | 'jstree-open' : displayChildren(), | ||
46 | 'jstree-leaf' : getNumberOfChildren() == 0 && getNumberOfPreferences() == 0, | ||
47 | 'jstree-last' : ${escapetool.d}index() == ${escapetool.d}parent.actions.length - 1 | ||
48 | }"> | ||
49 | ## Display the tree branch | ||
50 | <i class="jstree-icon jstree-ocl" role="presentation" data-bind="click: toggleDisplayChildren"></i> | ||
51 | ## Display the checbox | ||
52 | <input type="checkbox" data-bind="checked: enabled" /> | ||
53 | ## Display the 'all' link | ||
54 | <a href="#" data-bind="visible: !enabled() && (getNumberOfChildren() > 0 || getNumberOfPreferences() > 0 || getNumberOfRights()> 0), click: enableWithChildren" >(all)</a> | ||
55 | ## Display the document name | ||
56 | <strong class="documentName" data-bind="text: getTargetName(), click: toggleDisplayChildren, css: { 'bg-danger': isTooLong() }"></strong> | ||
57 | ## Display the target location | ||
58 | [<span data-bind="text: serializedTargetDocument()" class="monospace"></span>] | ||
59 | ## Display if the action is a change or not | ||
60 | <em data-bind="visible: targetDocument.equals(sourceDocument)">(unchanged)</em> | ||
61 | ## Display if a previous document will be deleted | ||
62 | <strong data-bind="visible: deletePrevious">(duplicated document will be deleted)</strong> | ||
63 | ## Display the exclude page button | ||
64 | <button class="btn btn-default btn-xs" data-bind="click: ${escapetool.d}root.excludePage, disable: targetDocument.equals(sourceDocument)">exclude page</button> | ||
65 | ## Display the exclude space button | ||
66 | <button class="btn btn-default btn-xs" data-bind="click: ${escapetool.d}root.excludeSpace">exclude space</button> | ||
67 | ## Display th button to change the parent of ht document | ||
68 | <button class="btn btn-default btn-xs" data-bind="click: ${escapetool.d}root.setParent">set parent</button> | ||
69 | ## Display the number of children | ||
70 | (<span data-bind="text: getNumberOfChildren()"></span> children, | ||
71 | ## Display the number of preferences | ||
72 | <span data-bind="text: getNumberOfPreferences()"></span> preferences, | ||
73 | ## Display the number of rights | ||
74 | <span data-bind="text: getNumberOfRights()"></span> rights) | ||
75 | ## Display the original location | ||
76 | from <a target="_blank" class="monospace" data-bind="text: serializedSourceDocument(), attr: {href: getSourceLink()}"></a> | ||
77 | ## Display all children | ||
78 | <!-- ko if: displayChildren() --> | ||
79 | ## Display preferences | ||
80 | <!-- ko if: preferences.length > 0 --> | ||
81 | <ul data-bind="foreach: preferences" class="jstree-children"> | ||
82 | <li class="text-warning jstree-node jstree-leaf"> | ||
83 | <i class="jstree-icon jstree-ocl" role="presentation"></i> | ||
84 | <input type="checkbox" data-bind="checked: enabled"/> <strong>[Preferences] <span data-bind="text: property"></span> : <span data-bind="text: value"></span></strong> (coming from <a target="_blank" class="monospace" data-bind="text: getSerializedOrigin(), attr: {href: getOriginLink()}"></a>) | ||
85 | </li> | ||
86 | </ul> | ||
87 | <!-- /ko --> | ||
88 | ## Display rights | ||
89 | <!-- ko if: rights.length > 0 --> | ||
90 | <ul data-bind="foreach: rights" class="jstree-children"> | ||
91 | <li class="text-danger jstree-node jstree-leaf"> | ||
92 | <i class="jstree-icon jstree-ocl" role="presentation"></i> | ||
93 | <input type="checkbox" data-bind="checked: enabled"/> <strong>[Right] <span data-bind="text: toString()"></span></strong> (coming from <a target="_blank" class="monospace" data-bind="text: getSerializedOrigin(), attr: {href: getOriginLink()}"></a>) | ||
94 | </li> | ||
95 | </ul> | ||
96 | <!-- /ko --> | ||
97 | ## Display children documents | ||
98 | <ul data-bind="template: { name: 'MigrationActionTemplate', data: {'actions': children()} }" class="jstree-children"/> | ||
99 | <!-- /ko --> | ||
100 | </li> | ||
101 | <!-- /ko --> | ||
102 | </script> | ||
103 | <!------------------------------------------ | ||
104 | Display Logs | ||
105 | -------------------------------------------> | ||
106 | <script id="DisplayLogs" type="text/html"> | ||
107 | <h2 class="log-title">Logs: </h2> | ||
108 | <ul class="log" data-bind="if: logs().length > 0"> | ||
109 | <!-- ko foreach: logs --> | ||
110 | <li class="log-item" data-bind="css: getClass()"> | ||
111 | <div data-bind="text: message"></div> | ||
112 | <!-- ko if: stackTrace --> | ||
113 | <pre data-bind="text: stackTrace"></pre> | ||
114 | <!-- /ko --> | ||
115 | </li> | ||
116 | <!-- /ko --> | ||
117 | </ul> | ||
118 | </script> | ||
119 | <!------------------------------------------ | ||
120 | Display plan | ||
121 | -------------------------------------------> | ||
122 | <script id="DisplayPlan" type="text/html"> | ||
123 | <h2>Plan</h2> | ||
124 | <div class="migration-plan box"> | ||
125 | <div data-bind="if: isComputing()" id="planComputing"> | ||
126 | <p>The plan is being computed and it could take some time. Please wait...</p> | ||
127 | <div class="ui-progress-background"> | ||
128 | <div class="ui-progress-bar green" data-bind="style: {width: progress() + '%'}"></div> | ||
129 | </div> | ||
130 | </div> | ||
131 | <div class="box warningmessage" data-bind="visible: duplicates().length > 0"> | ||
132 | <p>The migration have detected some duplicated documents, that are probably the consequences of a failed attempt to run the migrator.<br /> | ||
133 | <p>If it's the first time you run the migrator, you might have a problem.</p> | ||
134 | <p>Theses documents are:</p> | ||
135 | <ul data-bind="foreach: {data: duplicates(), as: 'doc'}"> | ||
136 | <li data-bind="text: doc"></li> | ||
137 | </ul> | ||
138 | <p>If you are ok with it, just run the migrator and these documents will be overwritten.</p> | ||
139 | </div> | ||
140 | <div class="box errormessage" data-bind="visible: tooLongs().length > 0"> | ||
141 | <p>We have detected some pages that will have too long path after the migration (limit is #getLocalReferenceMaxLength()). You should rename them (or rename one of their parents) before computing a new plan.</p> | ||
142 | <p>Theses pages are:</p> | ||
143 | <ul data-bind="foreach: {data: tooLongs(), as: 'action'}"> | ||
144 | <li class="monospace"><a data-bind="attr: {href: action.getSourceLink()}" target="_blank"><span data-bind="text: action.serializedSourceDocument()"></span></a> -> <span data-bind="text: action.serializedTargetDocument()"></span></li> | ||
145 | </ul> | ||
146 | </div> | ||
147 | <ul data-bind="if: actions() && !isComputing() && !isPlanEmpty()" id="planTree" class="jstree jstree-xwiki jstree-xwiki-responsive jstree-container-ul"> | ||
148 | <!-- ko template: {name: 'MigrationActionTemplate', data: {'actions': actions() }} --> | ||
149 | <!-- /ko --> | ||
150 | </ul> | ||
151 | <!-- ko if: !isComputing() && isPlanEmpty() --> | ||
152 | <div class="box infomessage"> | ||
153 | <p>There is nothing to do!</p> | ||
154 | </div> | ||
155 | <!-- /ko --> | ||
156 | <!-- ko template: {name: 'DisplayLogs', data: ${escapetool.d}root} --> | ||
157 | <!-- /ko --> | ||
158 | </div> | ||
159 | </Script> | ||
160 | <!------------------------------------------ | ||
161 | Display configuration | ||
162 | -------------------------------------------> | ||
163 | <h2>Configuration</h2> | ||
164 | <form class="xform"> | ||
165 | <div class="row"> | ||
166 | <div class="col-xs-12 col-md-6"> | ||
167 | <dl> | ||
168 | <!-- Excluded pages --> | ||
169 | <dt><label for="excludedPages">Excluded pages</label></dt> | ||
170 | <dd> | ||
171 | <p class="xHint">Page references separated by commas (',')</p> | ||
172 | <p><input type="text" id="excludedPages" data-bind="value: configuration.excludedPages"></p> | ||
173 | </dd> | ||
174 | <!-- Excluded spaces --> | ||
175 | <dt><label for="excludedSpaces">Excluded spaces</label></dt> | ||
176 | <dd> | ||
177 | <p class="xHint">Space references separated by commas (',')</p> | ||
178 | <p><input type="text" id="excludedSpaces" data-bind="value: configuration.excludedSpaces"> </p> | ||
179 | </dd> | ||
180 | <!-- Included spaces --> | ||
181 | <dt><label for="includedSpaces">Included spaces</label></dt> | ||
182 | <dd> | ||
183 | <p class="xHint">Space references separated by commas (',')</p> | ||
184 | <p><input type="text" id="includedSpaces" data-bind="value: configuration.includedSpaces"> </p> | ||
185 | </dd> | ||
186 | </dl> | ||
187 | </div> | ||
188 | <div class="col-xs-12 col-md-6"> | ||
189 | <p><button class="btn btn-default" type="button" data-toggle="collapse" data-target="#advancedSettings" aria-expanded="false" aria-controls="advancedSettings">Advanced Settings</button></p> | ||
190 | <dl id="advancedSettings" class="collapse well"> | ||
191 | <!-- Exclude hidden pages --> | ||
192 | <dt><input type="checkbox" id="excludeHiddenPages" data-bind="checked: configuration.excludeHiddenPages"> <label for="excludeHiddenPages">Exclude hidden pages</label></dt> | ||
193 | <dd><span class="xHint">Most of the hidden pages are techinal content. Moving them can break applications.</span></dd> | ||
194 | <!-- Exclude class pages --> | ||
195 | <dt><input type="checkbox" id="excludeClassPages" data-bind="checked: configuration.excludeClassPages"> <label for="excludeClassPages">Exclude pages having a class</label></dt> | ||
196 | <dd><span class="xHint">The pages are technical and moving them can break applications.</span></dd> | ||
197 | <!-- Don't move children --> | ||
198 | <dt><input type="checkbox" id="dontMoveChildren" data-bind="checked: configuration.dontMoveChildren"> <label for="dontMoveChildren">Do not move children</label></dt> | ||
199 | <dd><span class="xHint">Only convert terminal pages to nested pages, without moving them under their parent.</span></dd> | ||
200 | <!-- Add redirection --> | ||
201 | <dt><input type="checkbox" id="addRedirection" data-bind="checked: configuration.addRedirection"> <label for="addRedirection">Add redirection</label></dt> | ||
202 | <dd><span class="xHint">Add a redirection in the old location.</span></dd> | ||
203 | <!-- Convert preferences --> | ||
204 | <dt><input type="checkbox" id="convertPreferences" data-bind="checked: configuration.convertPreferences"> <label for="convertPreferences">Convert preferences</label></dt> | ||
205 | <dd><span class="xHint">Make sure that the preferences applied on the page remain the same after the move, by dupplicating the preferences on the target document.</span></dd> | ||
206 | <!-- Convert rights --> | ||
207 | <dt><input type="checkbox" id="convertRights" data-bind="checked: configuration.convertRights"> <label for="convertRights">Convert rights (experimental)</label></dt> | ||
208 | <dd><span class="xHint">Make sure that the rights applied on the page remain the same after the move <span class="text-danger">(Currently bugged)</span>.</span></dd> | ||
209 | <!-- Excluded Object Classes --> | ||
210 | <dt><label for="excludedObjectClasses" data-bind="click: toggleXClassList">Exclude classes</label></dt> | ||
211 | <dd> | ||
212 | <p class="xHint" data-bind="click: toggleXClassList">Exclude pages holding an object of one of the specified classes (separated by a coma ',').</p> | ||
213 | <p><textarea id="excludedObjectClasses" data-bind="textInput: configuration.excludedObjectClasses, click: showXClassList" data-localReferenceMaxLength="#getLocalReferenceMaxLength()" data-xclasses="#foreach($class in $xwiki.classList)#if($foreach.count>1),#end${class}#end"></textarea></p> | ||
214 | <div data-bind="visible: xclassListVisible"> | ||
215 | <a data-bind="click: hideXClassList" href="#">$services.icon.renderHTML('remove') Hide</a> | ||
216 | <ul data-bind="foreach: {data: xclasses, as: 'xclass'}" style="list-style-type: none; padding: 0;"> | ||
217 | <li><label><input type="checkbox" data-bind="checked: xclass.selected"/> <span data-bind="text: xclass.name"</span></label></li> | ||
218 | </ul> | ||
219 | </div> | ||
220 | </dd> | ||
221 | </dl> | ||
222 | </div> | ||
223 | </div> | ||
224 | <div class="clearfix"> | ||
225 | <h2>Actions</h2> | ||
226 | <button class="btn btn-success" data-bind="click: startBreakageDetection, disable: isComputing() || isPlanExecuting()">Detect breakages</button> | ||
227 | <button class="btn btn-primary" data-bind="click: computePlan, disable: isComputing() || isPlanExecuting()">Compute plan</button> | ||
228 | <button class="btn btn-primary" data-bind="disable: actions().length == 0 || isPlanExecuting() || tooLongs().length > 0, click: executePlan">Execute plan</button> | ||
229 | <button class="btn btn-default" data-bind="disable: actions().length == 0 || isPlanExecuting(), click: cleanPlan">Clean plan (to free the memory)</button> | ||
230 | </div> | ||
231 | </form> | ||
232 | <!------------------------------------------ | ||
233 | Display plan | ||
234 | -------------------------------------------> | ||
235 | <div data-bind="if: isPlanRequested() && !isPlanExecuting()"> | ||
236 | ## We escape the dollar of the knockout variable '$root' because $root also exists in velocity | ||
237 | <!-- ko template: {name: 'DisplayPlan', data: ${escapetool.d}root} --> | ||
238 | <!-- /ko --> | ||
239 | </div> | ||
240 | <!------------------------------------------ | ||
241 | Execute Plan | ||
242 | -------------------------------------------> | ||
243 | <!-- ko if: isPlanExecuting() && !success()--> | ||
244 | <div class="box" id="planExecuting"> | ||
245 | <p>The plan is being executed and it could take some time. Please wait...</p> | ||
246 | <div class="ui-progress-background"> | ||
247 | <div class="ui-progress-bar green" data-bind="style: {width: progress() + '%'}"></div> | ||
248 | </div> | ||
249 | <!-- ko template: {name: 'DisplayLogs', data: ${escapetool.d}root} --> | ||
250 | <!-- /ko --> | ||
251 | </div> | ||
252 | <!-- /ko --> | ||
253 | <!------------------------------------------ | ||
254 | Display breakages | ||
255 | -------------------------------------------> | ||
256 | <!-- ko if: isBreakageListRequested--> | ||
257 | <h2>Breakages</h2> | ||
258 | <div class="box"> | ||
259 | <div data-bind="if: isComputing"> | ||
260 | <p>The list of broken pages is being computed, please wait...</p> | ||
261 | <div class="ui-progress-background"> | ||
262 | <div class="ui-progress-bar green" data-bind="style: {width: progress() + '%'}"></div> | ||
263 | </div> | ||
264 | <!-- ko template: {name: 'DisplayLogs', data: ${escapetool.d}root} --> | ||
265 | <!-- /ko --> | ||
266 | </div> | ||
267 | <div data-bind="ifnot: isComputing"> | ||
268 | <p>If you don't migrate your pages, <strong data-bind="text: breakageList().size()"></strong> documents will lose their current parent.</p> | ||
269 | <ul data-bind="foreach: breakageList"> | ||
270 | <li>Page <span data-bind="text: document" class="monospace box infomessage" ></span> will lose its current parent <span data-bind="text: actualParent" class="monospace box infomessage"></span> because its location parent is <span data-bind="text: locationParent" class="monospace box infomessage"></span>.</li> | ||
271 | </ul> | ||
272 | </div> | ||
273 | </div> | ||
274 | <!-- /ko --> | ||
275 | <!------------------------------------------ | ||
276 | End message | ||
277 | -------------------------------------------> | ||
278 | <!-- ko if: success() --> | ||
279 | <div class="box successmessage" id="planExecuted"> | ||
280 | The plan have been executed! | ||
281 | </div> | ||
282 | <!-- ko template: {name: 'DisplayLogs', data: ${escapetool.d}root} --> | ||
283 | <!-- /ko --> | ||
284 | <!-- /ko --> | ||
285 | {{/html}} | ||
286 | #end | ||
287 | {{/velocity}} |