%PDF- %PDF-
| Direktori : /home/waritko/jetty-distribution-9.4.21.v20190926/webapps/ROOT/templates/ |
| Current File : //home/waritko/jetty-distribution-9.4.21.v20190926/webapps/ROOT/templates/extension.vm |
## Make sure the browser won't keep the same version of the resource in cache from one version of XWiki to another
#set($environmentVersion = $services.extension.core.repository.environmentExtension.id.version)
#set ($discard = $xwiki.ssfx.use('uicomponents/extension/extension.css', {'forceSkinAction': true, 'version': $environmentVersion}))
#set ($discard = $xwiki.jsfx.use('uicomponents/extension/extension.js', {'forceSkinAction': true, 'version': $environmentVersion}))
#set ($discard = $xwiki.ssfx.use('uicomponents/viewers/diff.css', {'forceSkinAction': true, 'version': $environmentVersion}))
#set ($discard = $xwiki.jsfx.use('uicomponents/viewers/diff.js', {'forceSkinAction': true, 'version': $environmentVersion}))
#set ($discard = $xwiki.ssfx.use('uicomponents/widgets/buttonGroup.css', {'forceSkinAction': true, 'version': $environmentVersion}))
#set ($discard = $xwiki.jsfx.use('uicomponents/widgets/buttonGroup.js', {'forceSkinAction': true, 'version': $environmentVersion}))
#set($discard = $services.template.execute('job_macros.vm'))
#set($discard = $services.template.execute('rating_macros.vm'))
## Various configuration of extension.vm behavior
## * skipCheckRight: skip right validation when executing a action (install plan, install, etc.)
## * skipCurrentUser: don't take into account context use (XAR extension documents will keep their author for example)
## * installJAROnRoot: force installing JAR extensions on root namespaces
#if (!$extensionConfig)
#set ($extensionConfig = {})
#end
#set ($extensionManager = $services.extension)
## From the main wiki we can manage other namespaces.
#if ($xcontext.isMainWiki() && "$!request.extensionNamespace" != '')
#set ($extensionNamespace = $request.extensionNamespace)
#else
#set ($extensionNamespace = "wiki:$xcontext.database")
#end
#set ($isAjaxRequest = $request.getHeader('X-Requested-With') == 'XMLHttpRequest')
#macro (displayExtensionSearchBar)
<div class="extension-search-bar">
## Simple search form.
<form action="$xwiki.relativeRequestURL" id="extension-search-simple" class="form-inline">
<div>
#if ($request.section)
<input type="hidden" name="section" value="$escapetool.xml($request.section)" />
#end
<label class="hidden" for="extensionSearchInput">$services.localization.render('extensions.search.tip')</label>
<input type="text" id="extensionSearchInput" name="search"
#if ("$!request.search" != '') value="$escapetool.xml($request.search)"#{end}
placeholder="$services.localization.render('extensions.search.tip')"/>
<label class="hidden" for="extensionSearchRepositoryList">$services.localization.render('extensions.search.repository.label')</label>
#set ($selectedRepositoryId = 'recommended')
#if ($request.repo)
#set ($selectedRepositoryId = $request.repo)
#end
<select id="extensionSearchRepositoryList" name="repo">
<optgroup label="$services.localization.render('extension.search.repositoryGroup.remote.label')">
## Remote extensions repository
<option value=""#if ($selectedRepositoryId == '') selected="selected"#end>
$services.localization.render('extensions.search.repository.remote.label')
</option>
## Recommended extensions repository (default)
<option value="recommended"#if ($selectedRepositoryId == 'recommended') selected="selected"#end>
$services.localization.render("extensions.search.repository.recommended.label")
</option>
</optgroup>
<optgroup label="$services.localization.render('extension.search.repositoryGroup.local.label')">
## Local repositories
#foreach ($repositoryId in ['installed', 'local', 'core'])
<option value="$repositoryId"#if ($selectedRepositoryId == $repositoryId) selected="selected"#end>
$services.localization.render("extensions.search.repository.${repositoryId}.label")</option>
#end
</optgroup>
</select>
## We don't use #em_submitButton because we want to use <button> instead of <input type="submit">, in order to
## be able to use HTML content inside the text of the button (the search icon and the hidden span for screen readers).
<span class="buttonwrapper">
<button class="primary" type="submit">$services.icon.renderHTML('search') <span class="hidden">$escapetool.xml($services.localization.render('extensions.advancedSearch.actions.submit'))</span></button>
</span>
</div>
</form>
## Advanced search form.
<form action="$xwiki.relativeRequestURL" class="xform">
<fieldset id="extension-search-advanced">
<legend><a href="#extension-search-advanced-body">$services.localization.render('extensions.advancedSearch.title')</a></legend>
<div id="extension-search-advanced-body"></div>
<div class="plainmessage extension-search-advanced-popup hidden">
#if ($request.section)
<input type="hidden" name="section" value="$escapetool.xml($request.section)" />
#end
<dl>
<dt><label for="advancedExtensionSearch-id">$services.localization.render('extensions.advancedSearch.id.label')</label></dt>
<dd><input type="text" name="extensionId" id="advancedExtensionSearch-id" value="" /></dd>
<dt><label for="advancedExtensionSearch-version">$services.localization.render('extensions.advancedSearch.version.label')</label></dt>
<dd><input type="text" name="extensionVersion" id="advancedExtensionSearch-version" value="" /></dd>
</dl>
<p>
#em_submitButton('extensions.advancedSearch.actions.submit')
#em_linkButton('#extension-search-simple' 'extensions.advancedSearch.actions.cancel' 'actionCancel')
</p>
</div>
</fieldset>
</form>
<div class="clearfloats"></div>
</div>
#end
#macro (displayExtensionName $extension)
#set ($name = "$!{extension.name}")
#if ($name == '')
#set ($name = "$!{extension.id.id}")
#if ($name.indexOf(':') >= 0)
#set ($name = $name.substring($mathtool.add($name.indexOf(':'), 1)))
#end
#end
${name}##
#end
#macro (displayExtensionActionButtons $extension $readOnly)
<div class="extension-actions">
#displayExtensionActionButtons_detailsToggle($extension)
#if (!$readOnly)
## Group the buttons that trigger an extension job.
<span class="dynamic-button-group">
#displayExtensionActionButtons_jobTriggers($extension)
</span>
#end
</div>
#end
#macro (displayExtensionActionButtons_detailsToggle $extension)
#computeXBack()
#if ($showExtensionDetails)
#if ($isAjaxRequest)
## AJAX request to show extension details.
#extensionActionButton('showDetails' true 'visibilityAction')
#extensionActionButton('hideDetails' true 'visibilityAction')
#else
## The given extension is displayed alone.
#em_linkButton($xback 'extensions.actions.back' 'extension-link')
#end
#else
## The given extension is displayed in a list of extensions.
#extensionActionButton('showDetails' true)
#end
## Make sure the URL to get back is preserved when we submit an extension action.
<input type="hidden" name="xback" value="$escapetool.xml($xback)" />
#end
#macro (displayExtensionActionButtons_jobTriggers $extension)
#if(!$extensionStatus)
#determineExtensionStatus($extension $extensionStatus $extensionStatusMessage)
#end
## Determine if there is an extension job waiting to be resumed or a previously created job plan that can be executed.
#set ($showContinueButton = $jobState == 'WAITING')
#if (!$showContinueButton)
#isExtensionPlan($jobStatus $showContinueButton)
#end
#if ($showContinueButton)
## One of the following statements is true:
## * the current extension job is waiting for user input and the user needs a button to resume the job,
## * an extension job plan was previously computed and the user needs a button to execute the plan.
#extensionActionButton('continue')
<input name="form_token" value="$!services.csrf.getToken()" type="hidden" />
#if ($jobState == 'WAITING')
## Only the Continue button should be available when a job is waiting.
#break
#end
#end
## Note that the Continue button doesn't exclude the following buttons, unless a job is waiting. The user should be
## able for instance to recompute the install plan.
#if ($extensionStatus.startsWith('installed'))
## The given extension object could be an instance of LocalExtension so make sure we use an InstalledExtension instance.
#getInstalledExtension($extension $extensionNamespace $installedExtension)
## If the installed extension might be invalid and need repairing
#extensionRepairButtons($installedExtension)
## This extension can be uninstalled
#extensionUninstallButtons($installedExtension)
## XAR specific buttons
#extensionActionXARButtons($installedExtension)
## If the extension is not installed on farm propose it
#if (!$installedExtension.isInstalled($NULL))
#extensionActionGlobalButton('install' false)
#end
#elseif ($extensionStatus == 'remote')
## Installable extension.
#if ($xcontext.action == 'distribution' && $showRepairXARButton)
## NOTE: This code is normally reached only when JavaScript is disabled since otherwise the button is added from JavaScript.
## TODO: Find a better way to 'force' the repair XAR extension button.
#set ($showRepairXARButton = $NULL)
#extensionActionButton('repairXAR')
## The repair job is executed without confirmation (i.e. without a plan).
<input name="form_token" value="$!services.csrf.getToken()" type="hidden" />
#else
#extensionInstallButtons($extension)
#end
#elseif ($extensionStatus.startsWith('remote-installed'))
## An extension that can be either upgraded or downgraded.
## Compare this version with the version that is currently installed to determine which button to display.
#getInstalledExtension($extension $extensionNamespace $installedExtension)
#if ($extension.compareTo($installedExtension) > 0)
#extensionUpgradeButtons($installedExtension 'upgrade')
#else
#extensionUpgradeButtons($installedExtension 'downgrade' true)
#end
## If the extension is not installed on farm propose it
#if (!$installedExtension.isInstalled($NULL))
#extensionActionGlobalButton('install' false)
#end
#end
#end
#macro(extensionInstallButtons $extension)
#set($isGlobalActionSecondary = false)
#if ($services.extension.isAllowed($extension, $extensionNamespace))
#extensionActionButton('install')
#set($isGlobalActionSecondary = true)
#end
#if ($services.extension.isAllowed($extension, $NULL))
#extensionActionGlobalButton('install' $isGlobalActionSecondary)
#end
#end
#macro(extensionUpgradeButtons $installedExtension $displayHint $secondary)
#if ($installedExtension.isInstalled($NULL))
## It's installed on root, lets upgrade on root
#extensionActionGlobalButtonWithDisplayHint('install' $displayHint $secondary)
## Also propose to install it on farm
#extensionActionButton('install' true)
#elseif ($installedExtension.isInstalled($extensionNamespace))
## It's installed on provided namespace, lets upgrade on provided namespace
#extensionActionButtonWithDisplayHint('install' $displayHint $secondary)
#end
#end
#macro(extensionRepairButtons $installedExtension)
#if ($installedExtension.isInstalled($NULL))
#if (!$installedExtension.isValid($NULL))
## It's invalid on root namespace
#extensionActionGlobalButtonWithDisplayHint('install' 'repair')
#end
#elseif ($installedExtension.isInstalled($extensionNamespace)
&& !$installedExtension.isValid($extensionNamespace))
## It's invalid on provided namespace
#extensionActionButtonWithDisplayHint('install' 'repair')
#end
#end
#macro(extensionUninstallButtons $installedExtension)
#if (!$installedExtension.isInstalled($NULL) && $installedExtension.isInstalled($extensionNamespace))
## It's installed on provided namespace
#extensionActionButton('uninstall' true)
#end
## It might be installed somewhere else, propose to remove it from the whole farm
#extensionActionGlobalButton('uninstall' true)
#end
#macro(extensionActionXARButtons $installedExtension)
#if ($installedExtension.type == 'xar' && $installedExtension.isInstalled($extensionNamespace))
## Add the button that can be used to compute the differences between the documents from the XAR and the documents
## from the database.
#extensionActionButton('diffXAR' true)
#end
#end
#macro (displayExtensionRating $extension)
#set ($rating = $extension.getRating())
#if ($rating != $NULL)
#set($id = $xwiki.getUniquePageName("string").replaceAll("[0-9]*", "").toLowerCase())
<div class="extension-rating">
#ratingstars($id "" "" $rating.averageVote $rating.totalVotes true)
</div>
#end
#end
#macro (displayExtensionAuthors $extension)
#set ($authors = [])
#foreach ($author in $extension.authors)
#if ($author.name == 'devs')
#set ($discard = $authors.add("<a class=""extension-author"" href=""http://www.xwiki.org/"">$services.localization.render('extensions.info.authors.xwikiorg')</a>"))
#elseif ("$!author.url" != '' && "$!author.name" != '')
#set ($discard = $authors.add("<a class=""extension-author"" href=""$author.url"">$escapetool.xml($author.name)</a>"))
#else
#set ($discard = $authors.add("<span class=""extension-author"">$escapetool.xml($author.name)</span>"))
#end
#end
#if (!$authors.isEmpty())
<p class="extension-authors">$services.localization.render('extensions.info.authors') $stringtool.join($authors, ', ')</p>
#end
#end
#macro (displayProgressBar $extension)
#if (!$jobStatus || !$jobStatus.request.extensions.contains($extension.id))
#getExtensionJobStatus($extension.id.id $extension.id.version.value $jobStatus)
#set ($jobState = $jobStatus.state)
#end
#if ($jobStatus && $jobState != 'FINISHED')
#displayJobProgressBar($jobStatus)
#end
#end
#macro (displayExtensionDetails_menuLink $detail $selected)
<a href="#extension-body-${detail}-$extensionIdHashCode"#if ($selected) class="current"#end>
$services.localization.render("extensions.info.category.${detail}")
</a>
#end
#macro (displayExtensionDetails_menu $extension)
#if (!$jobStatus || !$jobStatus.request.extensions.contains($extension.id))
#getExtensionJobStatus($extension.id.id $extension.id.version.value $jobStatus)
#set ($jobState = $jobStatus.state)
#end
<ul class="innerMenu">
<li>#displayExtensionDetails_menuLink('description')</li>##
##
#if ($extension.dependencies.size() > 0 || $backwardDependencies.size() > 0)
<li>#displayExtensionDetails_menuLink('dependencies')</li>##
#end
##
#if ($jobStatus)
#if ($jobState == 'FINISHED' && $jobStatus.documentDiffs)
<li>#displayExtensionDetails_menuLink('changes')</li>##
#end
#set ($selected = $jobState != 'FINISHED' || $request.extensionSection == 'progress')
<li>#displayExtensionDetails_menuLink('progress' $selected)</li>##
#end
</ul>
#end
#macro (displayExtensionDetails_description $extension)
<div id="extension-body-description-$extensionIdHashCode"></div>
<dl class="extension-body-description extension-body-section">
<dt>$services.localization.render('extensions.info.id')</dt>
<dd>$extension.id.id</dd>
#if ($extension.extensionFeatures.size() > 0)
<dt>$services.localization.render('extensions.info.features', [$extension.extensionFeatures.size()])</dt>
<dd>
#if ($extension.extensionFeatures.size() == 1)
$escapetool.xml($extension.extensionFeatures.iterator().next().id)
#else
<ul>
#foreach ($feature in $extension.extensionFeatures)
<li>$escapetool.xml($feature.id)</li>
#end
</ul>
#end
</dd>
#end
<dt>$services.localization.render('extensions.info.type')</dt>
<dd>$extension.type</dd>
<dt>$services.localization.render('extensions.info.license', [$extension.licenses.size()])</dt>
#if ($extension.licenses.size() > 0)
<dd>
#if ($extension.licenses.size() == 1)
$extension.licenses.iterator().next().name
#else
<ul>
#foreach ($license in $extension.licenses)
<li>$license.name</li>
#end
</ul>
#end
</dd>
#end
#if ("$!{extension.webSite}" != '')
<dt>$services.localization.render('extensions.info.website')</dt>
<dd><a href="$extension.webSite">$escapetool.xml($extension.webSite.replaceAll('^[^/]++//([^/\?]++)[/\?]?.*+$', '$1'))</a></dd>
#end
#if ($extension.repository.descriptor.URI && $extension.repository.descriptor.URI.scheme != 'file')
<dt>$services.localization.render('extensions.info.repository')</dt>
<dd><a href="$extension.repository.descriptor.URI">$escapetool.xml($extension.repository.descriptor.id)</a></dd>
#end
#if ($extension.scm)
#if ($extension.scm.url)
<dt>$services.localization.render('extensions.info.scm')</dt>
<dd><a href="$extension.scm.url">$escapetool.xml($extension.scm.url.replaceAll('^[^/]++//([^/\?]++)[/\?]?.*+$', '$1'))</a></dd>
#elseif ($extension.scm.connection)
<dt>$services.localization.render('extensions.info.scm')</dt>
<dd><a href="$extension.scm.connection.path">$escapetool.xml($extension.scm.connection.system)</a></dd>
#end
#end
#if ($extension.issueManagement.getURL())
<dt>$services.localization.render('extensions.info.issueManagement')</dt>
<dd><a href="$extension.issueManagement.getURL()">#if($extension.issueManagement.system)$escapetool.xml($extension.issueManagement.system)#else$escapetool.xml($extension.issueManagement.getURL())#end</a></dd>
#end
#if ($extension.isInstalled())
#displayExtensionDetails_description_wikis($extension)
#end
#if ($extensionStatus != 'loading')
#displayExtensionDetails_description_versions($extension)
#end
##
## TODO: need a decision on what exactly is the description and how it should be safely displayed (wiki syntax,
## server side generated HTML, etc.)
## <dt>Description</dt>
## <dd>$!extension.description</dd>
</dl>
#end
#macro (displayExtensionDetails_description_wikis $extension)
#if (!$extension.namespaces || $extension.namespaces.isEmpty())
## The given extension was installed globally.
#getInstallInfo($extension $NULL $install)
#if ($install.date)
<dt>$services.localization.render('extensions.info.installedGloballyBy',
[$xwiki.getUserName($install.userReference), $xwiki.formatDate($install.date)])</dt>
#else
<dt>$services.localization.render('extensions.info.namespaces.global')</dt>
#end
#elseif ($xcontext.isMainWiki())
## Display the list of namespaces where the given extension is installed only if we are on the main wiki.
<dt>$services.localization.render('extensions.info.namespaces.list')</dt>
<dd><ul>
#foreach ($namespace in $extension.namespaces)
#getInstallInfo($extension $namespace $install)
#if ($install.date)
<li>$services.localization.render('extensions.info.installedOnNamespaceBy', [
"#displayExtensionNamespace($namespace)",
$xwiki.getUserName($install.userReference),
$xwiki.formatDate($install.date)
])</li>
#else
<li>#displayExtensionNamespace($namespace)</li>
#end
#end
</ul></dd>
#else
#getInstallInfo($extension $extensionNamespace $install)
#if ($install.date)
<dt>$services.localization.render('extensions.info.installedBy',
[$xwiki.getUserName($install.userReference), $xwiki.formatDate($install.date)])</dt>
#end
#end
#end
#macro (getInstallInfo $installedExtension $namespace $return)
#set ($install = {'date': $installedExtension.getInstallDate($namespace)})
#if ($install.date)
#set ($install.userReference = $installedExtension.getUserReference($namespace))
#else
#set ($installJobStatus = $extensionManager.getExtensionJobStatus($installedExtension.id.id, $namespace))
#if ($installJobStatus && $installJobStatus.jobType == 'install')
#set ($install.date = $installJobStatus.startDate)
#set ($install.userReference = $installJobStatus.request.getProperty('user.reference'))
#end
#end
#set ($return = $NULL)
#setVariable("$return" $install)
#end
#macro (displayExtensionNamespace $namespace)
#if ("$!namespace" == '' && $namespace != '')
$services.localization.render('extensions.info.globalNamespace')##
#elseif ($namespace.startsWith('wiki:'))
#wikiHomePageLink($namespace)##
#else
$namespace##
#end
#end
#macro (displayExtensionDetails_description_versions $extension)
<dt>$services.localization.render('extensions.info.stableVersions.label')</dt>
<dd>
#if (!$request.listVersions)
<a href="#getExtensionURL($extension.id.id $extension.id.version.value {'listVersions': true})"
class="extension-versions-link">
$services.localization.render('extensions.info.stableVersions.linkLabel')
</a>
#else
#set ($stableVersions = [])
#foreach ($version in $extensionManager.resolveVersions($extension.id.id, 0, -1))
#if ($version.type == 'STABLE')
#set ($discard = $stableVersions.add($version.value))
#end
#end
#if ($stableVersions.size() > 0)
<ul>
## Latest version first.
#foreach ($i in [$mathtool.sub($stableVersions.size(), 1)..0])
#set ($version = $stableVersions.get($i))
<li><a href="#getExtensionURL($extension.id.id $version)" class="extension-link">$version</a></li>
#end
</ul>
#else
$services.localization.render('extensions.info.stableVersions.noResults')
#end
#end
</dd>
#end
#**
* NOTE: We explicitly overwrite the $extensionNamespace global variable because we want the dependency status to be
* determined for the given namespace. See #determineExtensionStatus() macro.
*#
#macro (displayDependency $dependencyOrExtension $extensionNamespace $resolveRemotely)
#if ($dependencyOrExtension.versionConstraint)
## Dependency object.
#set ($dependencyId = $dependencyOrExtension.id)
#set ($dependencyVersion = $dependencyOrExtension.versionConstraint)
#if ($resolveRemotely)
#set ($dependencyExtension = $extensionManager.resolve($dependencyOrExtension, $extensionNamespace))
#else
## Search for the dependency only in the core and local repositories.
## TODO: Check also the remote extensions that have been partially cached locally (e.g. only their pom has been
## downloaded). We need a resolve method that doesn't perform any remote calls.
#set ($dependencyExtension = $extensionManager.getRepository('core').resolve($dependencyOrExtension))
#if (!$dependencyExtension)
#set ($dependencyExtension = $extensionManager.getRepository('local').resolve($dependencyOrExtension))
#end
#end
#else
## Extension object.
#set ($dependencyId = $dependencyOrExtension.id.id)
#set ($dependencyVersion = $dependencyOrExtension.id.version.value)
#set ($dependencyExtension = $dependencyOrExtension)
#end
#set ($dependencyStatus = 'unknown')
#set ($dependencyStatusMessage = $NULL)
#set ($dependencyName = $dependencyId)
#if ($dependencyExtension)
## The extension status is determined for the $extensionNamespace . The name of this parameter is very important
## because it has to overwrite the global variable with the same name.
#determineExtensionStatus($dependencyExtension $dependencyStatus $dependencyStatusMessage $dependencyOrExtension.versionConstraint)
#set ($dependencyURL = "#getExtensionURL($dependencyId $dependencyVersion)")
#set ($dependencyName = "<a href=""$dependencyURL"" class=""extension-link"">#displayExtensionName($dependencyExtension)</a>")
#end
<div class="dependency-item extension-item-$dependencyStatus">
<span class="extension-name">${dependencyName}</span><span class="extension-version">$!dependencyVersion</span>
#if ($extensionNamespace.startsWith('wiki:'))
<span class="extension-namespace">$services.localization.render('extensions.info.dependency.wiki', ["#wikiHomePageLink($extensionNamespace)"])</span>
#end
#if ("$!dependencyStatusMessage" != '')
<span class="extension-status">$dependencyStatusMessage</span>
#end
</div>
#end
#macro (displayExtensionDetails_dependencies_upstream $extension)
#if ($extension.dependencies.size() > 0)
<dt>$services.localization.render('extensions.info.dependencies.directDependencies', [$extension.dependencies.size()])</dt>
<dd>
<ul class="dependencies">
#foreach ($dependency in $extension.dependencies)
<li>#displayDependency($dependency $extensionNamespace)</li>
#end
</ul>
</dd>
#end
#end
#macro (displayExtensionDetails_dependencies_downstream $backwardDependencies)
#if ($backwardDependencies.size() > 0)
<dt>$services.localization.render('extensions.info.dependencies.backwardDependencies', [$backwardDependencies.size()])</dt>
<dd>
<ul class="dependencies">
#foreach ($namespace in $backwardDependencies.entrySet())
#foreach ($dependency in $namespace.value)
<li>#displayDependency($dependency $namespace.key)</li>
#end
#end
</ul>
</dd>
#end
#end
#macro (displayExtensionDetails_dependencies $extension $backwardDependencies)
#if ($extension.dependencies.size() > 0 || $backwardDependencies.size() > 0)
<div id="extension-body-dependencies-$extensionIdHashCode"></div>
#computeXBack()
<dl class="extension-body-dependencies extension-body-section">
#displayExtensionDetails_dependencies_upstream($extension)
#displayExtensionDetails_dependencies_downstream($backwardDependencies)
</dl>
#end
#end
#macro (displayExtensionDetails_changes $extension)
#if (!$jobStatus || !$jobStatus.request.extensions.contains($extension.id))
#getExtensionJobStatus($extension.id.id $extension.id.version.value $jobStatus)
#set ($jobState = $jobStatus.state)
#end
#set ($documentDiffs = $jobStatus.documentDiffs)
#if ($jobState == 'FINISHED' && $documentDiffs)
## Need csrf token for reverts
<input name="form_token" value="$!services.csrf.getToken()" type="hidden" />
<div id="extension-body-changes-$extensionIdHashCode"></div>
<div class="extension-body-changes extension-body-section">
#template('diff_macros.vm')
#displayDocumentUnifiedDiffsWithSummary($documentDiffs 3)
</div>
#end
#end
#macro (displayExtensionDetails_progress $extension)
#if (!$jobStatus || !$jobStatus.request.extensions.contains($extension.id))
#getExtensionJobStatus($extension.id.id $extension.id.version.value $jobStatus)
#set ($jobState = $jobStatus.state)
#end
#if ($jobStatus)
<div id="extension-body-progress-$extensionIdHashCode"></div>
<div class="extension-body-progress extension-body-section">
#displayExtensionJobStatus($jobStatus)
#if ($jobState == 'WAITING')
<div class="extension-question xform">
#displayExtensionDetails_progressQuestion($extension $jobStatus)
</div>
#end
</div>
#end
#end
#macro (displayExtensionJobStatus $jobStatus)
#isExtensionPlan($jobStatus $isExtensionPlan)
#if ($isExtensionPlan)
#displayExtensionPlan($jobStatus)
#else
## Display any incompatibility errors
#set ($jobStatusCollapsed = false)
#if ($jobStatus.state == 'FINISHED')
#if ($jobStatus.error && $exceptiontool.getRootCauseMessage($jobStatus.error).contains('not compatible'))
#set ($jobStatusCollapsed = true)
#set ($errorMessage = $services.localization.render('platform.extension.info.error.versionNotCompatible'))
#set ($errorMessage = "${errorMessage}<br/>")
#set ($errorMessage = "${errorMessage}${services.localization.render('platform.extension.info.error.versionNotCompatibleHint')}")
<p>#error($errorMessage)</p>
#end
#end
#displayJobStatusLog($jobStatus, $jobStatusCollapsed)
#end
#end
#macro (isExtensionPlan $jobStatus $return)
#set ($isExtensionPlan = $jobStatus.state == 'FINISHED' && $jobStatus.actions && !$jobStatus.error)
#set ($return = $NULL)
#setVariable ("$return" $isExtensionPlan)
#end
#macro (displayExtensionPlan $plan)
## Group the extensions by the actions that will be performed on them.
#set($extensionsByAction = {'INSTALL': [], 'UPGRADE': [], 'DOWNGRADE': [], 'UNINSTALL': [], 'REPAIR': []})
#set ($noAction = true)
#foreach($planAction in $plan.actions)
#set ($targetExtensions = $extensionsByAction.get($planAction.action.name()))
#if ($targetExtensions)
#set ($discard = $targetExtensions.add($planAction))
#set ($noAction = false)
#end
#end
##
#if ($noAction)
#set ($emptyPlanMessageKeys = {
'installplan': 'extensions.install.error.alreadyInstalled',
'uninstallplan': 'extensions.uninstall.error.notInstalled'
})
<div class="infomessage">$services.localization.render($emptyPlanMessageKeys.get($plan.jobType))</div>
#else
<dl>
#foreach($entry in $extensionsByAction.entrySet())
#if (!$entry.value.isEmpty())
<dt>$services.localization.render("extensions.install.list.${entry.key.toLowerCase()}")</dt>
<dd>
<ul class="dependencies">
#foreach ($planAction in $entry.value)
<li>#displayDependency($planAction.extension $planAction.namespace)</li>
#end
</ul>
</dd>
#end
#end
</dl>
#end
#end
#macro (displayExtensionDetails_progressQuestion $extension $jobStatus)
#set ($question = $jobStatus.question)
#set ($questionType = $question.getClass().getName())
#if ($questionType.endsWith('.ConflictQuestion'))
#displayExtensionDetails_mergeConflictQuestion($question)
#elseif ($questionType.endsWith('.CleanPagesQuestion'))
#displayExtensionDetails_cleanPagesQuestion($question)
#elseif ($questionType.endsWith('.DefaultConflictActionQuestion'))
#displayExtensionDetails_defaultConflictActionQuestion($question)
#end
#end
#macro (displayExtensionDetails_mergeConflictQuestion $question)
<dl>
<dt>
<label>$services.localization.render('extensions.upgrade.mergeConflict.label')</label>
<span class="xHint">$services.localization.render('extensions.upgrade.mergeConflict.hint',
["<a href=""$xwiki.getURL($question.currentDocument.documentReference)"">$question.currentDocument</a>"])</span>
</dt>
<dd>
<select name="versionToKeep">
#set ($versions = {
'NEXT': $question.nextDocument,
'MERGED': $question.mergedDocument,
'CURRENT': $question.currentDocument
})
#foreach($entry in $versions.entrySet())
## Make sure that each version has a document associated. We don't have for instance a merged document when
## there is no previous installed version of a XAR extension but the imported documents already exist in the wiki.
#if ($entry.value)
<option value="$entry.key"#if ($question.globalAction == $entry.key) selected="selected"#end>
$services.localization.render("extensions.upgrade.mergeConflict.versionToKeep.${entry.key.toLowerCase()}")
</option>
#end
#end
</select>
</dd>
<dt>
<label>
<input type="checkbox" name="autoResolve" value="true" />
$services.localization.render('extensions.upgrade.mergeConflict.autoResolve')
</label>
<span class="xHint">$services.localization.render('extensions.upgrade.mergeConflict.autoResolve.hint')</span>
</dt>
</dl>
#displayExtensionDetails_mergeConflictChanges($question)
#end
#macro (displayExtensionDetails_mergeConflictChanges $question)
<h3 class="extension-diff-title">$services.localization.render('extensions.upgrade.mergeConflict.changes.title',
["<a href=""$xwiki.getURL($question.currentDocument.documentReference)"">$question.currentDocument</a>"])</h3>
<div class="extension-diff-options">
#set ($versions = {
'PREVIOUS': $question.previousDocument,
'CURRENT': $question.currentDocument,
'NEXT': $question.nextDocument,
'MERGED': $question.mergedDocument
})
<span class="label">$services.localization.render('extensions.upgrade.mergeConflict.changes.original')</span><select name="original">
#if ("$!request.original" != '')
#set ($originalVersion = $request.original)
#else
#set ($originalVersion = 'CURRENT')
#end
#set ($originalDocument = $versions.get($originalVersion))
#foreach($entry in $versions.entrySet())
#if ($entry.value)
<option value="$entry.key"#if ($entry.key == $originalVersion) selected="selected"#end>
$services.localization.render("extensions.upgrade.mergeConflict.changes.versionToCompare.${entry.key.toLowerCase()}")
</option>
#end
#end
</select><span class="label">$services.localization.render('extensions.upgrade.mergeConflict.changes.revised')</span><select name="revised">
#if ("$!request.revised" != '')
#set ($revisedVersion = $request.revised)
#elseif ($question.mergedDocument)
#set ($revisedVersion = 'MERGED')
#else
#set ($revisedVersion = 'NEXT')
#end
#set ($revisedDocument = $versions.get($revisedVersion))
#foreach($entry in $versions.entrySet())
#if ($entry.value)
<option value="$entry.key"#if ($entry.key == $revisedVersion) selected="selected"#end>
$services.localization.render("extensions.upgrade.mergeConflict.changes.versionToCompare.${entry.key.toLowerCase()}")
</option>
#end
#end
</select>#extensionActionButton('diff' true)
</div>
#if ($originalDocument && $revisedDocument)
<div id="changescontent">
#set ($conflictsList = $question.documentConflicts)
#set ($rev1 = $originalVersion.toLowerCase())
#set ($rev2 = $revisedVersion.toLowerCase())
#set ($wrappedDocs = $xwiki.wrapDocs([$originalDocument, $revisedDocument]))
#set ($origdoc = $wrappedDocs.get(0))
#set ($newdoc = $wrappedDocs.get(1))
#set ($headingLevel = 4)
#template('changesdoc.vm')
</div>
#end
#end
#macro (displayExtensionDetails_cleanPagesQuestion $question)
<dl>
<dt>
<label>$escapetool.xml($services.localization.render('extensions.uninstall.cleanPages.label'))</label>
<span class="xHint">$escapetool.xml($services.localization.render('extensions.uninstall.cleanPages.hint'))</span>
</dt>
<dd>
#set ($entityReferenceTree = $services.model.toTree($question.pages.keySet()))
#displayDocumentTree($entityReferenceTree $question.pages)
</dd>
</dl>
#end
#macro (displayDocumentTree $entityReferenceTree $mapOfSelectedDocuments)
#set ($currentLocale = $services.localization.currentLocale)
#displayDocumentTreeNode($entityReferenceTree $mapOfSelectedDocuments)
#end
#macro (displayDocumentTreeNode $node $mapOfSelectedDocuments)
#if ($node.reference)
#set ($nodeLabel = $node.reference.name)
#if ("$node.reference.type" == 'WIKI')
#set ($wikiPrettyName = $services.wiki.getById($node.reference.name).prettyName)
#if ("$!wikiPrettyName.trim()" != '')
#set ($nodeLabel = $wikiPrettyName)
#end
#end
<div class="$!node.reference.type.toString().toLowerCase() node">$escapetool.xml($nodeLabel)
#if ("$node.reference.type" == 'DOCUMENT')
## Currently there's no string representation of a document reference with parameters (such as locale) that can
## be resolved so we need to submit a set of (document reference without locale, locale) pairs.
#set ($name = $escapetool.xml($services.model.serialize($node.reference, 'default')))
## We don't display the locale child nodes if there is only one locale. We display just the document node.
#if ($node.locales && $node.locales.size() == 1)
#set ($documentReference = $node.locales.iterator().next())
#if ("$!documentReference.locale" != '')
## Display the locale if it's not the default one.
<span class="locale">$escapetool.xml($documentReference.locale.getDisplayName($currentLocale))</span>
#end
<span class="actions">
<input type="checkbox" name="$name" value="$escapetool.xml("$!documentReference.locale")"
#if ($mapOfSelectedDocuments.get($documentReference)) checked="checked"#end />
</span>
#end
#end
</div>
#end
#if ($node.children && $node.children.size() > 0)
<ul#if (!$node.reference) class="collapsible selectable document-tree"#end>
#foreach ($child in $node.children)
<li#if ("$!child.reference.type" == 'DOCUMENT') class="collapsed"#end>
#displayDocumentTreeNode($child $mapOfSelectedDocuments)
</li>
#end
</ul>
#elseif ($node.locales && $node.locales.size() > 1)
<ul>
#foreach ($documentReference in $node.locales)
#if ("$!documentReference.locale" == '')
#set ($locale = $services.localization.render(
'platform.extension.distributionWizard.reportStepDocumentsDefaultLanguage'))
#else
#set ($locale = $documentReference.locale.getDisplayName($currentLocale))
#end
<li class="locale node">$escapetool.xml($locale)
<span class="actions">
<input type="checkbox" name="$name" value="$escapetool.xml("$!documentReference.locale")"
#if ($mapOfSelectedDocuments.get($documentReference)) checked="checked"#end />
</span>
</li>
#end
</ul>
#end
#end
#macro (displayExtensionDetails_defaultConflictActionQuestion $question)
<dl>
<dt>
<label>$services.localization.render('extension.xar.question.defaultConflictAction.label')</label>
<span class="xHint">$services.localization.render('extension.xar.question.defaultConflictAction.hint')</span>
</dt>
<dd>
<dl>
#foreach ($conflictType in $services.extension.xar.conflictTypes)
#set ($defaultConflictAction = $question.getConflictAction($conflictType))
<dt>
<label>$services.localization.render("extension.xar.conflict.${conflictType}.label")</label>
<span class="xHint">$services.localization.render("extension.xar.conflict.${conflictType}.hint")</span>
</dt>
<dd>
<select name="defaultConflictAction_$conflictType">
#foreach ($conflictAction in $conflictType.actions)
<option value="$conflictAction" label="$services.localization.render("extension.xar.conflict.action.${conflictAction}.hint")"#if ($conflictAction == $defaultConflictAction) selected="selected"#end>
$services.localization.render("extension.xar.conflict.action.${conflictAction}.label")
</option>
#end
</select>
</dd>
#end
</dl>
</dd>
</dl>
#end
#macro (answerExtensionJobQuestion_defaultConflictActionQuestion $question)
#foreach ($conflictType in $services.extension.xar.conflictTypes)
#set ($conflictAction = $request.getParameter("defaultConflictAction_$conflictType"))
#if ($conflictAction)
#set ($void = $question.setConflictAction($conflictType, $conflictAction))
#end
#end
#end
#macro (getBackwardDependencies $extension $return)
#getInstalledExtension($extension $extensionNamespace $installedExtension)
#if ($installedExtension.isInstalled($NULL))
## The extension is installed in the root namespace so it can have backward dependencies on multiple namespaces.
#set ($backwardDependencies = $services.extension.installed.getBackwardDependencies($installedExtension.id))
#if ($backwardDependencies && ($xcontext.isMainWiki() || $backwardDependencies.containsKey($extensionNamespace)))
#if (!$xcontext.isMainWiki())
## If we're not on the main wiki then display only the backward dependencies from the current namespace.
#set ($backwardDependencies = {$extensionNamespace: $backwardDependencies.get($extensionNamespace)})
#end
#else
#set ($backwardDependencies = {})
#end
#elseif ($installedExtension)
## The extension is installed on the current namespace.
#set ($backwardDependencies = $services.extension.installed.getBackwardDependencies($installedExtension.id.id,
$extensionNamespace))
#if ($backwardDependencies && $backwardDependencies.size() > 0)
#set ($backwardDependencies = {$extensionNamespace: $backwardDependencies})
#else
#set ($backwardDependencies = {})
#end
#else
#set ($backwardDependencies = {})
#end
#set ($return = $NULL)
#setVariable("$return" $backwardDependencies)
#end
#macro (displayExtensionDetails $extension)
<div class="extension-body">
#set ($extensionIdHashCode = "$extensionNamespace/$extension.id.id/$extension.id.version.value")
#set ($extensionIdHashCode = $extensionIdHashCode.hashCode())
#getBackwardDependencies($extension $backwardDependencies)
#displayExtensionDetails_menu($extension)
#displayExtensionDetails_description($extension)
#displayExtensionDetails_dependencies($extension $backwardDependencies)
#displayExtensionDetails_changes($extension)
#displayExtensionDetails_progress($extension)
</div>
#end
#macro (displayExtension $extension $readOnly)
## The job status can change while the extension is displayed so we cache it. Let's reset the cache.
#set ($jobStatus = $NULL)
#isShowingExtensionDetails($extension $showExtensionDetails)
#determineExtensionStatus($extension $extensionStatus $extensionStatusMessage)
<form action="$xwiki.relativeRequestURL" method="post" class="extension-item extension-item-${extensionStatus}">
<div class="hidden">
<input name="readOnly" value="$!readOnly" type="hidden" />
<input name="extensionId" value="$!escapetool.xml($extension.id.id)" type="hidden" />
<input name="extensionVersion" value="$!escapetool.xml($extension.id.version.value)" type="hidden" />
<input name="extensionNamespace" value="$!escapetool.xml($extensionNamespace)" type="hidden" />
#if ($request.section)
<input name="section" value="$escapetool.xml($request.section)" type="hidden" />
#end
#if ($request.viewer)
## Send the AJAX requests to the specified viewer (Velocity template). This is needed for instance when the
## Extension Manager UI is not installed.
<input name="xpage" value="$escapetool.xml($request.viewer)" type="hidden" />
#end
</div>
<div class="extension-header">
<h2 class="extension-title">
<span class="extension-name">#displayExtensionName($extension)</span>
<span class="extension-version">$escapetool.xml($extension.id.version)</span>
</h2>
#if ($extensionStatusMessage)
<p class="extension-status">$escapetool.xml($extensionStatusMessage)</p>
#end
#displayExtensionActionButtons($extension, $readOnly)
#displayExtensionRating($extension)
#if ($extension.authors.size() > 0)
#displayExtensionAuthors($extension)
#end
#if ("$!extension.summary" != '')
<div class="extension-summary">$escapetool.xml($extension.summary)</div>
#end
#if ($extension.isRecommended())
<div class="extension-recommended">$services.localization.render('extensions.info.recommended')</div>
#end
#displayProgressBar($extension)
<div class="clearfloats"></div>
</div>
#if ($showExtensionDetails)
#displayExtensionDetails($extension)
#end
</form>
#end
#macro (handleExtensionRequest)
#if ($request.form_token)
#if ($services.csrf.isTokenValid($request.form_token))
#handleExtensionAction(true)
#elseif ($isAjaxRequest)
## The CSRF token expired. We only redisplay the extension because the resubmission confirmation doesn't fit nicely in-line.
$response.sendRedirect("#getExtensionURL()")
#else
$response.sendRedirect($services.csrf.getResubmissionURL())
#end
#else
#handleExtensionAction(false)
#end
#end
#macro (handleExtensionAction $withValidToken)
#if ($request.extensionAction == 'continue' && $withValidToken)
#continueExtensionJob($request.extensionId $request.extensionVersion)
#elseif ($request.extensionAction == 'repairXAR' && $withValidToken)
#repairXarExtension($request.extensionId $request.extensionVersion)
#elseif ($request.extensionAction == 'install' || $request.extensionAction == 'upgrade'
|| $request.extensionAction == 'downgrade')
#computeInstallPlan($request.extensionId $request.extensionVersion $extensionNamespace)
#elseif ($request.extensionAction == 'installGlobally')
#computeInstallPlan($request.extensionId $request.extensionVersion $NULL)
#elseif ($request.extensionAction == 'upgradeGlobally' || $request.extensionAction == 'downgradeGlobally')
#computeUpgradePlan($request.extensionId $request.extensionVersion)
#elseif ($request.extensionAction == 'uninstall')
#computeUninstallPlan($request.extensionId $request.extensionVersion $extensionNamespace)
#elseif ($request.extensionAction == 'uninstallGlobally')
#computeUninstallPlan($request.extensionId $request.extensionVersion $NULL)
#elseif ($request.extensionAction == 'diffXAR')
#diffXarExtension($request.extensionId $request.extensionVersion)
#elseif ($request.extensionAction == 'revertDocument' && $withValidToken)
#revertDocument($request.documentReference $request.documentLocale $request.documentExtensionId $request.documentExtensionVersion, $request.extensionId)
#elseif ($request.extensionVersionConstraint)
#set ($dependency = $extensionManager.createExtensionDependency($request.extensionId, $request.extensionVersionConstraint))
#displayDependency($dependency $extensionNamespace true)
#else
## Display the extension.
## Create a dependency in order to support version constraints (e.g. a version range).
#set ($readOnly = $request.readOnly == 'true')
#set ($dependency = $extensionManager.createExtensionDependency($request.extensionId, $request.extensionVersion))
#if ($dependency.versionConstraint.version && $dependency.versionConstraint.ranges.isEmpty())
## A precise version was specified so we resolve the requested extension.
#set ($extension = $extensionManager.resolve($request.extensionId, $request.extensionVersion))
#else
## A version range was specified so we resolve the requested extension dependency. Note that the result might not
## be exactly the requested extension but some extension that provides / features the requested extension.
#set ($extension = $extensionManager.resolve($dependency, $extensionNamespace))
#end
#if ($extension)
#displayExtension($extension, $readOnly)
#else
<div class="infomessage">$services.localization.render('extensions.advancedSearch.noResults',
["<strong>$!escapetool.xml($request.extensionId)</strong>",
"<strong>$!escapetool.xml($request.extensionVersion)</strong>"])</div>
## DEBUG START: Check if there is any job status associated with the specified extension.
#getExtensionJobStatus($request.extensionId, $request.extensionVersion $jobStatus)
#if ($jobStatus)
## Normally we shouldn't get here.
<div class="errormessage">We found an extension job associated with the missing extension:</div>
#displayExtensionJobStatus($jobStatus)
#end
## DEBUG STOP
#end
#end
#end
#macro (computeInstallPlan $extensionId $extensionVersion $extensionNamespace)
#set ($installPlanRequest = $extensionManager.createInstallPlanRequest($extensionId, $extensionVersion, $extensionNamespace))
#if ($extensionConfig.skipCheckRight)
#set ($discard = $installPlanRequest.removeProperty('checkrights'))
#end
#if ($extensionConfig.skipCurrentUser)
#set ($discard = $installPlanRequest.removeProperty('user.reference'))
#end
#if ($extensionConfig.installJAROnRoot)
#set ($discard = $installPlanRequest.rewriter.installExtensionTypeOnRootNamespace('jar'))
#set ($discard = $installPlanRequest.rewriter.installExtensionTypeOnRootNamespace('webjar'))
#end
#set ($discard = $extensionManager.createInstallPlan($installPlanRequest))
#handleExtensionJobStartFailure('extensions.install.error.prepareFailure')
#end
#macro (computeUpgradePlan $extensionId $extensionVersion)
## Upgrade all the namespaces were the specified extension is installed.
#set ($namespaces = [])
#foreach ($extension in $extensionManager.installedExtensions)
#if ($extension.id.id == $extensionId)
#if ($extension.isInstalled($NULL))
#set ($discard = $namespaces.clear())
#break
#else
#foreach ($namespace in $extension.namespaces)
#set ($discard = $namespaces.add($namespace))
#end
#end
#end
#end
## The namespace that will appear in the job id.
#set ($jobIdNamespace = $NULL)
#if ($namespaces.size() == 1)
#set ($jobIdNamespace = $namespaces.get(0))
#end
#set ($installPlanRequest = $extensionManager.createInstallPlanRequest($extensionId, $extensionVersion, $jobIdNamespace))
#foreach ($namespace in $namespaces)
#set ($discard = $installPlanRequest.addNamespace($namespace))
#end
#set ($discard = $extensionManager.createInstallPlan($installPlanRequest))
#handleExtensionJobStartFailure('extensions.install.error.prepareFailure')
#end
#macro (computeUninstallPlan $extensionId $extensionVersion $extensionNamespace)
#set ($discard = $extensionManager.createUninstallPlan($extensionId, $extensionNamespace))
#handleExtensionJobStartFailure('extensions.uninstall.error.prepareFailure')
#end
#macro (continueExtensionJob $extensionId $extensionVersion)
#getExtensionJobStatus($extensionId $extensionVersion $jobStatus)
#set ($jobState = $jobStatus.state)
#set ($jobType = $jobStatus.jobType)
#if ($jobState == 'FINISHED')
#isExtensionPlan($jobStatus $isExtensionPlan)
#if ($isExtensionPlan)
## Execute the latest extension job plan.
## TODO: Would be nice to reuse somehow the job request that was used to create the plan.
#if ($jobType == 'installplan')
#installExtension($extensionId $extensionVersion $jobStatus.request)
#break
#elseif ($jobType == 'uninstallplan')
#uninstallExtension($extensionId $extensionVersion $jobStatus.request)
#break
#end
#end
#elseif ($jobState == 'WAITING')
#answerExtensionJobQuestion($jobStatus)
#end
## Redirect to extension display.
$response.sendRedirect("#getExtensionURL()")
#end
#macro(revertDocument $documentReference $documentLocale $documentExtensionId $documentExtensionVersion $jobExtensionId)
## Create instance of ExtensionId
#set ($extensionId = $services.extension.createExtensionId($documentExtensionId, $documentExtensionVersion))
## Create instance of DocumentRefernce with the Locale
#set ($documentReferenceWithLocale = $services.model.createDocumentReference($services.model.resolveDocument($documentReference), $services.localization.toLocale($documentLocale)))
## Revert the document to the extension state
#if (!$services.extension.xar.reset($documentReferenceWithLocale, $extensionId, $services.extension.xar.getDiffJobId($jobExtensionId, $extensionNamespace)))
$response.sendError(500, $services.localization.render('extensions.xar.resetDocument.error'))
#end
#end
#macro (answerExtensionJobQuestion $jobStatus)
## Continue an interactive extension job using the data submitted by the user.
#set ($question = $jobStatus.question)
#set ($questionType = $question.getClass().getName())
#if ($questionType.endsWith('.ConflictQuestion'))
## A merge conflict occurred during installation.
#set ($discard = $question.setGlobalAction($request.versionToKeep))
#set ($discard = $question.setAlways($request.autoResolve.equals('true')))
#set ($allDecisions = $request.getParameterValues("conflict_decision_select"));
#set ($allCustoms = $request.getParameterValues("conflict_decision_value_custom"))
#foreach($conflictReference in $request.getParameterValues("conflict_id"))
#set ($decision = $allDecisions[$foreach.index])
#set ($custom = $allCustoms[$foreach.index])
#set ($discard = $question.setConflictDecision($conflictReference, $decision, $custom))
#end
#elseif ($questionType.endsWith('.CleanPagesQuestion'))
#foreach ($entry in $question.pages.entrySet())
## Currently there's no string representation of a document reference with parameters (such as locale) that can
## be resolved so what has been submitted is a set of (document reference without locale, locale) pairs.
#set ($stringReferenceWithoutLocale = $services.model.serialize($entry.key, 'default'))
#set ($localesToDelete = $request.getParameterValues($stringReferenceWithoutLocale))
#set ($delete = $localesToDelete && $localesToDelete.contains($entry.key.locale.toString()))
#set ($discard = $entry.setValue($delete))
#end
#elseif ($questionType.endsWith('.DefaultConflictActionQuestion'))
#answerExtensionJobQuestion_defaultConflictActionQuestion($question)
#end
#set ($discard = $jobStatus.answered())
#end
#macro (installExtension $extensionId $extensionVersion $installRequest)
#set ($discard = $extensionManager.install($installRequest))
#handleExtensionJobStartFailure('extensions.install.error.installFailure')
#end
#macro (uninstallExtension $extensionId $extensionVersion $uninstallRequest)
#set ($discard = $extensionManager.uninstall($uninstallRequest))
#handleExtensionJobStartFailure('extensions.uninstall.error.uninstallFailure')
#end
#macro (repairXarExtension $extensionId $extensionVersion)
#if ($extensionNamespace.startsWith('wiki:'))
#set ($wikiName = $extensionNamespace.substring(5))
#else
#set ($wikiName = $xcontext.database)
#end
#set ($discard = $services.extension.xar.repairInstalledExtension($extensionId, $extensionVersion, $wikiName))
#handleExtensionJobStartFailure('extensions.install.error.repairXarFailure' $services.extension.xar)
#end
#macro (diffXarExtension $extensionId $extensionVersion)
#if ($extensionNamespace.startsWith('wiki:'))
#set ($wikiName = $extensionNamespace.substring(5))
#else
#set ($wikiName = $xcontext.database)
#end
#set ($discard = $services.extension.xar.diff($extensionId, $wikiName))
#handleExtensionJobStartFailure('extensions.install.error.diffXarFailure' $services.extension.xar)
#end
#macro (handleExtensionJobStartFailure $errorMessageKey $scriptService)
#if ($scriptService)
#set ($lastError = $scriptService.lastError)
#else
#set ($lastError = $extensionManager.lastError)
#end
#if ($lastError)
#set ($errorMessage = $services.localization.render($errorMessageKey, [$extensionId, $extensionVersion]))
#if ($isAjaxRequest)
## Send error back.
$response.sendError(400, $errorMessage)
#else
<div class="errormessage">$errorMessage #printThrowable($lastError)</div>
#end
#else
## Redirect to extension display.
$response.sendRedirect("#getExtensionURL($extensionId $extensionVersion {'extensionSection': 'progress'})")
#end
#end
#macro (determineExtensionStatus $extension $_extensionStatus $_extensionStatusMessage $versionConstraint)
#set ($currentVersion = $NULL)
#if (!$jobStatus || !$jobStatus.request.extensions.contains($extension.id))
#getExtensionJobStatus($extension.id.id $extension.id.version.value $jobStatus)
#set ($jobState = $jobStatus.state)
#end
#if ($jobStatus && $jobState != 'FINISHED')
#set ($status = 'loading')
#else
#if ($extension.isInstalled($extensionNamespace))
## Determine if the extension is still valid.
#if ("$!extension.isValid($extensionNamespace)" == 'false')
#set ($status = 'installed-invalid')
#elseif ($extension.isDependency($extensionNamespace))
#set ($status = 'installed-dependency')
#else
#set ($status = 'installed')
#end
#elseif ($extension.repository.descriptor.id == 'core')
#set ($status = 'core')
#else
## An extension, either local or remote, that might be available to install.
## Check if a different version of this extension is installed or is a core dependency.
#set ($currentVersion = $services.extension.core.getCoreExtension($extension.id.id))
#if (!$currentVersion)
#getInstalledExtension($extension $extensionNamespace $currentVersion)
#end
#if ($currentVersion)
#set ($status = "#determineVersionCompatibility($extension $currentVersion $versionConstraint)")
#else
#set ($status = 'remote')
#end
#end
#end
#set ($message = $NULL)
#if ($status != 'remote' && $status != 'loading')
#set ($message = $services.localization.render("extensions.info.status.${status}", [$currentVersion.id.version.value]))
#end
#set ($_extensionStatus = $NULL)
#setVariable ("$_extensionStatus" $status)
#set ($_extensionStatusMessage = $NULL)
#setVariable ("$_extensionStatusMessage" $message)
#end
#macro (determineVersionCompatibility $alice $bob $versionConstraint)
#set ($prefix = '')
#if (!$alice.id.equals($bob.id))
#set ($prefix = 'remote-')
#end
#set ($suffix = '')
#if ($versionConstraint && !$versionConstraint.isCompatible($bob.id.version))
#set ($suffix = '-incompatible')
#elseif ("$!bob.isValid($extensionNamespace)" == 'false')
#set ($suffix = '-invalid')
#elseif ($bob.isDependency($extensionNamespace))
#set ($suffix = '-dependency')
#end
${prefix}${bob.repository.descriptor.id}${suffix}##
#end
#macro (getExtensionJobStatus $extensionId $extensionVersion $return)
## Retrieve the job status for the current wiki and for the entire farm (if the current wiki is the main wiki).
#getExtensionJobStatusForNamespace($extensionId $extensionVersion $extensionNamespace $jobStatusForWiki)
#if ($xcontext.isMainWiki())
#getExtensionJobStatusForNamespace($extensionId $extensionVersion $NULL $jobStatusForFarm)
#end
#set ($return = $NULL)
#if (!$jobStatusForWiki)
#setVariable ("$return" $jobStatusForFarm)
#elseif (!$jobStatusForFarm)
#setVariable ("$return" $jobStatusForWiki)
## Return the most recent job status.
## No start date means the job was scheduled but hasn't started yet.
#elseif (!$jobStatusForFarm.startDate || ($jobStatusForWiki.startDate
&& $jobStatusForFarm.startDate.after($jobStatusForWiki.startDate)))
#setVariable ("$return" $jobStatusForFarm)
#else
#setVariable ("$return" $jobStatusForWiki)
#end
#end
#macro (getExtensionJobStatusForNamespace $extensionId $extensionVersion $extensionNamespace $return)
## Retrieve the latest job status stored for the specified extension.
#set ($_jobStatus = $extensionManager.getExtensionJobStatus($extensionId, $extensionNamespace))
#if ($_jobStatus)
## Check if the job status matches the extension version.
#set ($targetVersion = $_jobStatus.request.extensions.get(0).version)
#if (!$targetVersion)
## Some jobs don't require the extension version. Let's determine the currently available version.
#set ($_extension = $services.extension.resolve($extensionId, $extensionVersion))
#getInstalledExtension($_extension $extensionNamespace $installedExtension)
#set ($targetVersion = $installedExtension.id.version)
#end
#if ($targetVersion && $extensionVersion != $targetVersion.value)
#set ($_jobStatus = $NULL)
#end
#end
## Retrieve the latest plan stored for the specified extension.
#set ($_plan = $extensionManager.getExtensionPlanJobStatus($extensionId, $extensionNamespace))
#if ($_plan)
## Check if the plan matches the extension version.
#set ($targetVersion = $_plan.request.extensions.get(0).version)
#if (!$targetVersion)
## Some jobs don't require the extension version. Let's determine the currently available version.
#set ($_extension = $services.extension.resolve($extensionId, $extensionVersion))
#getInstalledExtension($_extension $extensionNamespace $installedExtension)
#set ($targetVersion = $installedExtension.id.version)
#end
#if ($targetVersion && $extensionVersion != $targetVersion.value)
#set ($_plan = $NULL)
#end
#end
#set ($return = $NULL)
#if (!$_jobStatus)
#setVariable ("$return" $_plan)
#elseif (!$_plan)
#setVariable ("$return" $_jobStatus)
## Return the most recent one between the job status and the plan.
## No start date means the job/plan was scheduled but hasn't started yet.
#elseif (!$_jobStatus.startDate || ($_plan.startDate && $_jobStatus.startDate.after($_plan.startDate)))
#setVariable ("$return" $_jobStatus)
#else
#setVariable ("$return" $_plan)
#end
#end
#macro (getInstalledExtension $_extension $namespace $installedExtension)
#set ($features = [])
#if ($_extension)
#set ($discard = $features.addAll($_extension.extensionFeatures))
#set ($discard = $features.add($_extension.id))
#end
#set ($discard = $collectionstool.reverse($features))
#set ($return = $NULL)
#foreach ($feature in $features)
#set ($return = $services.extension.installed.getInstalledExtension($feature.id, $namespace))
#if ($return)
#break
#end
#end
#set ($installedExtension = $NULL)
#setVariable("$installedExtension" $return)
#end
#macro (getExtensionURL $extensionId $extensionVersion $extraParams)
#set ($parameters = {})
##
#if ($extraParams)
#set ($discard = $parameters.putAll($extraParams))
#end
##
#if ($extensionId)
#set ($discard = $parameters.put('extensionId', $extensionId))
#elseif ($request.extensionId)
#set ($discard = $parameters.put('extensionId', $request.extensionId))
#end
##
#if ($extensionVersion)
#set ($discard = $parameters.put('extensionVersion', $extensionVersion))
#elseif ($request.extensionVersion)
#set ($discard = $parameters.put('extensionVersion', $request.extensionVersion))
#end
##
#if ($request.extensionNamespace)
#set ($discard = $parameters.put('extensionNamespace', $request.extensionNamespace))
#end
##
#if ($xback)
#set ($discard = $parameters.put('xback', $xback))
#elseif ($request.xback)
#set ($discard = $parameters.put('xback', $request.xback))
#end
##
## Copy known parameters.
#foreach ($paramName in ['section', 'xpage', 'viewer'])
#set ($paramValue = $request.getParameter($paramName))
#if ("$!paramValue" != '')
#set ($discard = $parameters.put($paramName, $paramValue))
#end
#end
##
$doc.getURL($xcontext.action, $escapetool.url($parameters))##
#end
#macro (computeXBack)
#set ($xback = "$!{request.xback}")
#if ($xback == '')
#set ($params = '')
#foreach ($parameterName in $request.parameterNames)
#if (!$parameterName.startsWith('extension'))
#foreach ($value in $request.getParameterValues($parameterName))
#set ($params = "${params}&${parameterName}=${value}")
#end
#end
#end
#if ($params.length() > 0)
#set ($params = $params.substring(1))
#end
#set ($xback = $doc.getURL($xcontext.action, $params))
#end
#end
#macro (em_submitButton $value $_name $secondary $extraClassName)
<span class="buttonwrapper">
<input type="submit" value="$escapetool.xml($services.localization.render($value))"#if($_name) name="$escapetool.xml($_name)"#end
class="button#if($secondary) secondary#end#if($extraClassName) $!escapetool.xml($extraClassName)#end"/>
</span>
#end
#macro (em_linkButton $href $label $extraClassName)
<span class="buttonwrapper">
<a href="$escapetool.xml($href)" class="button secondary#if($extraClassName) $!escapetool.xml($extraClassName)#end">
$services.localization.render($label)
</a>
</span>
#end
#macro(extensionActionButtons $extension $action $secondary)
#extensionActionButtonsWithDisplayHint($extension $action $action $secondary $extraClassName)
#end
#macro(extensionActionButtonsWithDisplayHint $extension $action $displayHint $secondary)
#set ($isGlobalActionSecondary = $secondary)
#set ($globalActionExtraClassName = $NULL)
#if (!$installedExtension || ($installedExtension.isInstalled($extensionNamespace)
&& !$installedExtension.isInstalled($NULL)))
## Button that targets only the current wiki.
#extensionActionButtonWithDisplayHint($action $displayHint $secondary)
#set ($isGlobalActionSecondary = true)
## Indicate that the local action is available.
#set ($globalActionExtraClassName = 'alternative-action')
#end
## Button that targets the entire farm.
#extensionActionGlobalButtonWithDisplayHint($action $displayHint, $isGlobalActionSecondary $globalActionExtraClassName)
#end
#macro (extensionActionGlobalButton $action $secondary $extraClassName)
#extensionActionGlobalButtonWithDisplayHint($action $action $secondary $extraClassName)
#end
#macro (extensionActionGlobalButtonWithDisplayHint $action $displayHint $secondary $extraClassName)
#if ($xcontext.isMainWiki())
#extensionActionButtonWithDisplayHint("${action}Globally" "${displayHint}Globally", $secondary $extraClassName)
#end
#end
#macro (extensionActionButton $action $secondary $extraClassName)
#extensionActionButtonWithDisplayHint($action $action $secondary $extraClassName)
#end
#macro (extensionActionButtonWithDisplayHint $action $displayHint $secondary $extraClassName)
#set ($classNames = [])
#if ($secondary)
#set ($discard = $classNames.add('secondary'))
#end
#if ($extraClassName)
#set ($discard = $classNames.add($extraClassName))
#end
#set ($hintKey = "extensions.actions.${displayHint}.hint")
<span class="buttonwrapper">
<button type="submit" name="extensionAction" value="$escapetool.xml($action)"
#if ($classNames.size() > 0) class="$escapetool.xml($stringtool.join($classNames, ' '))"#end
#if ($services.localization.get($hintKey)) title="$escapetool.xml($services.localization.render($hintKey))"#end>
$escapetool.xml($services.localization.render("extensions.actions.${displayHint}"))</button>
</span>
#end
#macro (wikiHomePageLink $namespace)
#set ($wikiName = $stringtool.removeStart($namespace, 'wiki:'))
#set ($wikiReference = $services.model.createDocumentReference($wikiName, '', '').wikiReference)
#set ($wikiHomeDocumentReference = $services.model.resolveDocument('', 'default', $wikiReference))
#set ($wikiPrettyName = $services.wiki.getById($wikiName).prettyName)
#if ("$!wikiPrettyName.trim()" == '')
#set ($wikiPrettyName = $wikiName)
#end
<a href="$escapetool.xml($xwiki.getURL($wikiHomeDocumentReference))">$escapetool.xml($wikiPrettyName)</a>##
#end
#macro (isShowingExtensionDetails $extension $_showDetails)
## Show the extension details if this extension has been explicitely requested.
#set ($return = "$!request.hideExtensionDetails" != 'true' && $request.extensionId == $extension.id.id
&& $request.extensionVersion == $extension.id.version.value)
#if (!$return)
#if (!$jobStatus || !$jobStatus.request.extensions.contains($extension.id))
#getExtensionJobStatus($extension.id.id $extension.id.version.value $jobStatus)
#set ($jobState = $jobStatus.state)
#end
## Always show the extension details if the extension has a job waiting.
#set ($return = $jobState == 'WAITING')
#end
#set ($_showDetails = $NULL)
#setVariable("$_showDetails" $return)
#end
#macro (displayExtensionUpdaterPlan $plan)
#if ($plan.error)
#displayExtensionUpdaterPlanStatus($plan)
#else
## Group extensions by status (invalid/outdated) and by namespace.
#set ($invalid = {})
#set ($outdated = {})
## Iterate the first level nodes from the upgrade plan tree.
#foreach ($firstLevelNode in $plan.tree)
#set ($planAction = $firstLevelNode.action)
#set ($status = $NULL)
#getInstalledExtension($planAction.extension $planAction.namespace $installedVersion)
#if (!$installedVersion.isValid($planAction.namespace))
#set ($status = $invalid)
## Check if the latest version has been installed after the upgrade plan was created.
#elseif ($installedVersion.id.version.value != $planAction.extension.id.version.value)
#set ($status = $outdated)
#end
#if ($status)
#set ($statusForNamespace = $status.get($planAction.namespace))
#if (!$statusForNamespace)
#set ($statusForNamespace = [])
#set ($discard = $status.put($planAction.namespace, $statusForNamespace))
#end
#set ($discard = $statusForNamespace.add($planAction))
#end
#end
##
#if ($outdated.isEmpty() && $invalid.isEmpty())
<div class="successmessage">
$services.localization.render('platform.extension.updater.noUpdatesAvailable')
</div>
#else
#displayExtensionUpdaterPlanActionByNamespace($invalid 'invalid')
#displayExtensionUpdaterPlanActionByNamespace($outdated 'outdated')
#end
#end
#end
#macro(displayExtensionUpdaterPlanStatus $status)
## The status is null after the job is created, until the job is scheduled.
#set ($isLoading = !$status || ($status.log.isEmpty() && $status.state != 'FINISHED'))
<div class="extension-body-progress#if ($isLoading) loading#end">
#if ($status)
#printStatusLog($status)
#end
</div>
#end
#macro(displayExtensionUpdaterPlanActionByNamespace $actionByNamespace $key)
#if (!$actionByNamespace.isEmpty())
<div class="xLabel">
$services.localization.render("platform.extension.updater.${key}ExtensionsLabel")
</div>
#end
## Sort the extensions by namespace and by their name.
#set ($items = [])
#foreach ($entry in $actionByNamespace.entrySet())
#foreach ($planAction in $entry.value)
#set ($namespace = $entry.key)
#set ($namespacePrettyName = $namespace)
#if ($stringtool.indexOf($namespace, ':') >= 0)
#set ($namespacePrettyName = $stringtool.substringAfter($namespace, ':'))
#if ($namespace.startsWith('wiki:'))
#set ($wikiPrettyName = $services.wiki.getById($namespacePrettyName).prettyName)
#if ("$!wikiPrettyName.trim()" != '')
#set ($namespacePrettyName = $wikiPrettyName)
#end
#end
#end
#set ($extension = $planAction.extension)
#set ($extensionName = "#displayExtensionName($extension)")
#set ($discard = $items.add({
'namespace': $namespace,
'namespacePrettyName': "$!namespacePrettyName",
'extension': $extension,
'extensionName': $extensionName.trim()
}))
#end
#end
#set ($items = $sorttool.sort($items, ['namespacePrettyName', 'extensionName']))
## Paginate the extensions.
#set ($hasPagination = false)
## We don't load the pagination CSS here (noSx:true) because the upgrade plan can be loaded through AJAX so
## the Skin Extension hooks might not be available. We load the pagination CSS elsewhere.
#set ($paginationParams = {
'defaultItemsPerPage': 5,
'itemParamName': "${key}FirstIndex",
'itemsPerPageParamName': "${key}PerPage",
'noSx': true
})
#paginationPrepareParams($paginationParams)
#set ($hasPagination = $items.size() > $paginationParams.itemsPerPage)
#set ($indexOutOfRange = $items.size() > 0 && $paginationParams.firstItem >= $items.size())
#if ($hasPagination || $indexOutOfRange)
#set ($paginationParams.totalItems = $items.size())
#set ($requestParams = {})
#set ($discard = $requestParams.putAll($request.getParameterMap()))
#set ($discard = $requestParams.remove($paginationParams.itemParamName))
#set ($discard = $requestParams.remove($paginationParams.itemsPerPageParamName))
#if ($indexOutOfRange)
#if ($!request.get("${key}PagingReset"))
## it seems we already got redirected. how this?
#set ($paginationParams.firstItem = 0)
#else
#set ($discard = $requestParams.put("${key}PagingReset", "1"))
#set ($redirectUrl = $doc.getURL($xcontext.action, $escapetool.url($requestParams)))
#set ($discard = $response.sendRedirect($redirectUrl))
#stop
#end
#else
#set ($discard = $requestParams.remove("${key}PagingReset"))
#end
#end
#if($hasPagination)
#set ($paginationParams.url = $doc.getURL($xcontext.action, $escapetool.url($requestParams)))
#pagination($paginationParams)
#end
#set ($lastItem = $mathtool.min($items.size(), $mathtool.add($paginationParams.firstItem,
$paginationParams.itemsPerPage)))
#if ($request.get("${key}PagingReset"))
<div class="box infomessage">$escapetool.xml($services.localization.render('platform.extension.updater.pagingrestart'))</div>
#end
#set ($items = $items.subList($paginationParams.firstItem, $lastItem))
#foreach ($item in $items)
#if ($foreach.index == 0 || $item.namespace != $extensionNamespace)
#if ($foreach.index > 0)
## Close the previous group of extensions.
</div>
#end
## Start a new group of extensions.
<div class="xHint">
$services.localization.render("platform.extension.updater.${key}ExtensionsHint",
["#displayExtensionNamespace($item.namespace)"])
</div>
<div class="${key}Extensions">
#set ($extensionNamespace = $item.namespace)
#end
#displayExtension($item.extension)
#end
#if ($items.size() > 0)
## Close the last group of extensions.
</div>
#end
#if ($hasPagination)
#set ($paginationParams.position = 'bottom')
#pagination($paginationParams)
#end
#end
#macro (getExtensionUpdaterPlan $_plan)
#set ($localPlan = $extensionManager.getExtensionPlanJobStatus($NULL, $extensionNamespace))
#if ($xcontext.isMainWiki())
#set ($globalPlan = $extensionManager.getExtensionPlanJobStatus($NULL, $NULL))
#else
#set ($globalPlan = $NULL)
#end
#set ($_plan = $NULL)
#if (!$globalPlan)
#setVariable ("$_plan" $localPlan)
#elseif (!$localPlan)
#setVariable ("$_plan" $globalPlan)
## Return the most recent one between the local plan and the global plan.
## No start date means the plan was scheduled but hasn't started yet.
#elseif (!$localPlan.startDate || ($globalPlan.startDate && $localPlan.startDate.after($globalPlan.startDate)))
#setVariable ("$_plan" $localPlan)
#else
#setVariable ("$_plan" $globalPlan)
#end
#end
#macro(computeExtensionUpdaterPlan $_plan $globally)
#if ($globally && $xcontext.isMainWiki())
## Create the upgrade plan for the entire farm.
#set ($upgradePlanJob = $extensionManager.createUpgradePlan())
#else
## Create the upgrade plan only for the current wiki.
#set ($upgradePlanRequest = $extensionManager.createUpgradePlanRequest($extensionNamespace))
#if ($xcontext.isMainWiki())
## From the main wiki we can also upgrade the extensions that are installed globally (on the root namespace).
#set ($discard = $upgradePlanRequest.addNamespace($NULL))
#end
#set ($upgradePlanJob = $extensionManager.createUpgradePlan($upgradePlanRequest))
#end
#set ($_plan = $NULL)
#setVariable("$_plan" $upgradePlanJob.status)
#end
#macro (displayExtensionUpdaterTrigger $plan)
<form action="$xwiki.relativeRequestURL" method="post">
<div class="hidden">
#if ($xcontext.action == 'view' || $xcontext.action == 'admin')
#set ($docAction = 'get')
#else
#set ($docAction = $xcontext.action)
#end
## Compute the URL that will be used to submit the request asynchronously.
#if ("$!request.section" != '')
## Administration section.
#set ($asyncURL = $xwiki.getURL($request.section, $docAction, $escapetool.url({
'section': $request.section
})))
#else
## Stand-alone or Distribution Wizard.
#set ($asyncURL = $doc.getURL($docAction))
#end
<input type="hidden" name="asyncURL" value="$!escapetool.xml($asyncURL)" disabled="disabled" />
## Redirect back to view mode after a POST request.
<input type="hidden" name="xredirect" value="$!escapetool.xml($xwiki.relativeRequestURL)" />
</div>
#set ($disabled = $plan && $plan.state != 'FINISHED')
<p class="buttons dynamic-button-group">
#if ($xcontext.isMainWiki() && $plan && !$plan.request.hasNamespaces())
## The latest upgrade plan was computed for the entire farm so we display the global button first.
#displayExtensionUpdaterButton('checkForUpdatesGlobally' $disabled)
#end
#displayExtensionUpdaterButton('checkForUpdates' $disabled)
#if ($xcontext.isMainWiki() && (!$plan || $plan.request.hasNamespaces()))
## On the main wiki we can also compute the upgrade plan for the entire farm.
#displayExtensionUpdaterButton('checkForUpdatesGlobally' $disabled)
#end
</p>
</form>
#end
#macro (displayExtensionUpdaterButton $value $disabled)
<span class="buttonwrapper">
<button name="action" value="$value"#if ($disabled) disabled="disabled"#end>
$escapetool.xml($services.localization.render("platform.extension.updater.$value"))
</button>
</span>
#end
#macro (extensionUpdater)
#set ($plan = $NULL)
#set ($error = $NULL)
#if ($request.action.startsWith('checkForUpdates'))
#computeExtensionUpdaterPlan($plan $request.action.equals('checkForUpdatesGlobally'))
#set ($error = $extensionManager.lastError)
#if ("$!request.xredirect" != '' && !$error)
#set ($discard = $response.sendRedirect($request.xredirect))
#break
#end
#end
#if (!$plan)
#getExtensionUpdaterPlan($plan)
#end
#if (!$isAjaxRequest)
## The list of outdated/invalid extensions is paginated so we load the CSS here because the request is not AJAX.
## Make sure the browser won't keep the same version of the resource in cache from one version of XWiki to another
#set ($discard = $xwiki.ssfx.use('uicomponents/pagination/pagination.css', {'forceSkinAction': true, 'version': $environmentVersion}))
<p class="noitems">
$escapetool.xml($services.localization.render('extension.updater.hint'))
</p>
#displayExtensionUpdaterTrigger($plan)
#end
<div class="extensionUpdater">
#if ($error)
<div class="errormessage">
$services.localization.render('platform.extension.updater.createUpgradePlanFailure')
#printThrowable($error)
</div>
#elseif ($plan.state == 'FINISHED')
<div class="xHint">
$escapetool.xml($services.localization.render('platform.extension.updater.lastCheckDate',
[$xwiki.formatDate($plan.endDate)]))
</div>
#displayExtensionUpdaterPlan($plan)
#elseif ($plan)
<div class="xHint">$services.localization.render('platform.extension.updater.loading')</div>
#displayJobProgressBar($plan)
#displayExtensionUpdaterPlanStatus($plan)
#end
</div>
#end