Wiki source code of Rendering Pages

Last modified by Eleni Cojocariu on 2026/10/09 18:39

Show last authors
1 {{velocity}}
2 #set ($Q = '"')
3 #set ($mappingClass = 'XWikiOrg.documentation-scripts-queries.MigratedPageClass')
4 #set ($redirectClass = 'XWiki.RedirectClass')
5 ## rendering.xwiki.org is a wiki of the same farm, so the farm-wide index answers for it with
6 ## 'wiki:rendering'. Three filters turn documents into pages: 'hidden:false' drops the technical
7 ## pages, '-name:WebPreferences' the per-space preference pages, and 'doclocale:""' the
8 ## translations -- the index holds one document per locale, and that matters here where it does not
9 ## on the other wikis of this dashboard: Main.WebHome alone is translated 19 times, which is the
10 ## whole difference between 119 documents and 66 pages.
11 #set ($base = "type:DOCUMENT AND wiki:rendering AND hidden:false AND -name:WebPreferences AND doclocale:${Q}${Q}")
12 ## Only the fields the tables read. The first five are mandatory whatever they show: SolrQueryExecutor
13 ## resolves every result to a DocumentReference to check view rights, and a result it cannot resolve
14 ## is dropped -- an incomplete 'fl' empties the table while the total still looks right. 'class' is
15 ## the multi-valued field holding every class the page carries an object of; the Main scope reads it
16 ## to know which pages are worth a getDocument() call.
17 #set ($fields = 'wiki,spaces,name,type,doclocale,fullname,title_,class')
18
19 ## Scopes, in display order; the first one is the default, so the page has something to show when it
20 ## is opened without a parameter -- same contract as the sibling 'details' and 'extensions-details'.
21 #set ($scopes = [])
22 #set ($discard = $scopes.add({'key': 'all', 'label': 'All pages', 'heading': 'Pages of rendering.xwiki.org', 'filter': ''}))
23 #set ($discard = $scopes.add({'key': 'main', 'label': 'Main', 'heading': 'Main space, page by page', 'filter': " AND space_prefix:${Q}Main${Q}"}))
24 #set ($requested = "$!request.get('scope')")
25 #set ($scope = '')
26 #foreach ($candidate in $scopes)
27 #if ($candidate.key == $requested)
28 #set ($scope = $candidate)
29 #end
30 #end
31 #if ($scope == '')
32 #set ($scope = $scopes.get(0))
33 #end
34 #set ($links = [])
35 #foreach ($candidate in $scopes)
36 #if ($candidate.key == $scope.key)
37 #set ($discard = $links.add("**$candidate.label**"))
38 #else
39 #set ($url = $doc.getURL('view', "scope=$candidate.key"))
40 #set ($discard = $links.add("[[$candidate.label>>path:$url]]"))
41 #end
42 #end
43 Scope: $stringtool.join($links, ' | ')
44
45 = $scope.heading =
46
47 #set ($query = $services.query.createQuery("${base}${scope.filter}", 'solr'))
48 #set ($discard = $query.setLimit(2000))
49 #set ($discard = $query.bindValue('fl', $fields))
50 #set ($discard = $query.bindValue('sort', 'fullname asc'))
51 #set ($results = $query.execute().get(0).results)
52
53 #if ($scope.key == 'main')
54 ## The same columns, and the same tests, as the 'details' page uses for the three legacy trees of
55 ## the main wiki, so the two can never disagree about what counts as done.
56 #set ($doneQuery = $services.query.createQuery("${base}${scope.filter} AND property.XWiki.TagClass.tags:done", 'solr'))
57 #set ($discard = $doneQuery.setLimit(2000))
58 #set ($discard = $doneQuery.bindValue('fl', $fields))
59 #set ($doneRefs = [])
60 #foreach ($row in $doneQuery.execute().get(0).results)
61 #set ($discard = $doneRefs.add($row.get('fullname')))
62 #end
63 #set ($redirectCount = 0)
64 ## Distinct replacement pages of the whole scope: several legacy pages often converge on the same
65 ## new page, so this is a count of labels already seen, not a sum of the rows.
66 #set ($allTargets = [])
67 (% class="table" %)
68 |=Page|=Done|=Converted into|=Redirects to
69 #foreach ($row in $results)
70 #set ($fullName = $row.get('fullname'))
71 #set ($title = "$!row.get('title_')")
72 #if ($title == '')
73 #set ($title = "$!row.get('name')")
74 #end
75 #set ($title = $title.replace('|', '~|'))
76 #set ($classes = $row.get('class'))
77 #set ($newPages = '')
78 #set ($redirect = '')
79 #if ($classes && ($classes.contains($mappingClass) || $classes.contains($redirectClass)))
80 ## 'fullname' is the reference inside its own wiki, so it has to be prefixed to be resolved
81 ## from here -- this page runs on the main wiki.
82 #set ($legacyDoc = $xwiki.getDocument("rendering:$fullName"))
83 #set ($mapping = $legacyDoc.getObject($mappingClass))
84 #if ($mapping)
85 #set ($newPages = "$!mapping.getValue('newPages')")
86 #end
87 #set ($redirectObject = $legacyDoc.getObject($redirectClass))
88 #if ($redirectObject)
89 #set ($redirect = "$!redirectObject.getValue('location')")
90 #end
91 #end
92 #if ($doneRefs.contains($fullName))
93 #set ($doneCell = '✅')
94 #else
95 #set ($doneCell = '❌')
96 #end
97 #set ($targets = [])
98 #set ($targetLabels = [])
99 #foreach ($line in $newPages.split('[\r\n]+'))
100 ## The field holds one wiki link per line, so that moving a replacement page rewrites it: the
101 ## rename job only follows links, and a bare reference it cannot see goes stale silently. Values
102 ## written before that change are still bare, hence unwrapping rather than parsing a link.
103 #set ($target = $line.trim().replaceAll('^\[\[', '').replaceAll('\]\]$', ''))
104 #set ($target = $target.replaceAll('\|\|.*$', '').replaceAll('^.*>>', ''))
105 #set ($target = $target.replaceAll('^doc:', '').trim())
106 #if ($target != '')
107 #set ($label = $target.replaceAll('^xwiki:', '').replaceAll('\.WebHome$', ''))
108 #set ($discard = $targetLabels.add($label))
109 #set ($discard = $targets.add("[[$label>>doc:$target]]"))
110 #if (!$allTargets.contains($label))
111 #set ($discard = $allTargets.add($label))
112 #end
113 #end
114 #end
115 ## A redirect names a replacement too, and it is the only one most pages here have: list it as
116 ## well, unless the mapping object already records it. Its 'location' may or may not name a wiki
117 ## -- the one redirect on this wiki points at the main one -- so prefixing it with 'rendering:'
118 ## unconditionally builds a reference that resolves to nothing and renders as a red link to a
119 ## page that does exist.
120 #if ($redirect == '')
121 #set ($redirectCell = '—')
122 #else
123 #set ($redirectCount = $redirectCount + 1)
124 #set ($redirectRef = $redirect.trim())
125 #if ($redirectRef.matches('^[^:]+:.*'))
126 #set ($redirectTarget = $redirectRef)
127 #else
128 #set ($redirectTarget = "rendering:$redirectRef")
129 #end
130 #set ($redirectLabel = $redirectTarget.replaceAll('^xwiki:', '').replaceAll('^rendering:', '').replaceAll('\.WebHome$', ''))
131 #set ($redirectCell = "[[$redirectLabel>>doc:$redirectTarget]]")
132 #if (!$targetLabels.contains($redirectLabel))
133 #set ($discard = $targets.add("[[$redirectLabel>>doc:$redirectTarget]] //(redirect)//"))
134 #end
135 #if (!$allTargets.contains($redirectLabel))
136 #set ($discard = $allTargets.add($redirectLabel))
137 #end
138 #end
139 #if ($targets.isEmpty())
140 #set ($targetCell = '—')
141 #else
142 #set ($targetCell = $stringtool.join($targets, '\\'))
143 #end
144 |[[$title>>doc:rendering:$fullName]]|$doneCell|$targetCell|$redirectCell
145 #end
146 |=**$results.size() pages**|=**$doneRefs.size() done**|=**$allTargets.size() new pages**|=**$redirectCount redirects**
147 #else
148 ## Grouped by top-level space, because half of this wiki is the flavor it was installed with (Help,
149 ## Sandbox, ColorThemes, Panels, XWiki) rather than rendering documentation, and only the grouping
150 ## shows which half is which. A sorted map keeps the groups in alphabetical order; the Solr 'sort'
151 ## keeps the rows inside each of them in reference order.
152 #set ($buckets = $collectiontool.sortedMap)
153 #foreach ($solrDoc in $results)
154 #set ($fullName = "$!solrDoc.getFirstValue('fullname')")
155 #set ($dot = $fullName.indexOf('.'))
156 #if ($dot > 0)
157 #set ($space = $fullName.substring(0, $dot))
158 #else
159 #set ($space = $fullName)
160 #end
161 #if (!$buckets.get($space))
162 #set ($discard = $buckets.put($space, []))
163 #end
164 #set ($discard = $buckets.get($space).add($solrDoc))
165 #end
166 #foreach ($space in $buckets.keySet())
167 #set ($list = $buckets.get($space))
168
169 == $space: $list.size() ==
170
171 (% class="table" %)
172 |=Page|=Reference
173 #foreach ($solrDoc in $list)
174 #set ($fullName = "$!solrDoc.getFirstValue('fullname')")
175 #set ($title = "$!solrDoc.getFirstValue('title_')")
176 #if ($title == '')
177 #set ($title = "$!solrDoc.getFirstValue('name')")
178 #end
179 #set ($title = $title.replace('|', '~|'))
180 |[[$title>>doc:rendering:$fullName]]|$fullName
181 #end
182 #end
183
184 == Total ==
185
186 **$results.size()** pages, in $buckets.size() top-level spaces.
187 #end
188 {{/velocity}}
189
190 A page counts as **done** when it carries the ##done## tag. //Converted into// is the ##newPages## field of its [[MigratedPageClass>>XWikiOrg.documentation-scripts-queries.MigratedPageClass]] object, so it stays empty until someone records where the content went. The total under //Converted into// counts the **distinct** replacement pages of the scope, so it is smaller than the sum of the rows whenever several pages were merged into one. //Redirects to// is the ##location## of an ##XWiki.RedirectClass## object: such a page already sends its readers elsewhere, whether or not anyone marked it as done. Neither the tag nor the mapping class has been used on this wiki yet, so the Main table currently shows the starting state: nothing done, one redirect.

Get Connected