Improved the UI/UX of the package search
authorAlexander Ebert <ebert@woltlab.com>
Wed, 17 Apr 2019 18:04:14 +0000 (20:04 +0200)
committerAlexander Ebert <ebert@woltlab.com>
Wed, 17 Apr 2019 18:04:14 +0000 (20:04 +0200)
wcfsetup/install/files/acp/style/layout.scss
wcfsetup/install/files/acp/templates/packageSearchResultList.tpl
wcfsetup/install/files/acp/templates/packageStartInstall.tpl
wcfsetup/install/files/js/WoltLabSuite/Core/Acp/Ui/Package/Search.js [new file with mode: 0644]
wcfsetup/install/files/lib/data/package/update/PackageUpdateAction.class.php
wcfsetup/install/files/lib/data/package/update/ViewablePackageUpdate.class.php
wcfsetup/install/lang/de.xml
wcfsetup/install/lang/en.xml

index 81b75e6a8dd96952f0feb68a210ab03b031bd4b4..b0ced58e065a43a463828b4e65e45c8529646c6d 100644 (file)
@@ -464,3 +464,62 @@ $wcfAcpSubMenuWidth: 300px;
                text-decoration: underline;
        }
 }
+
+/* Search for Packages */
+.packageSearchName {
+       @include wcfFontHeadline;
+       @include wcfFontBold;
+}
+
+.packageSearchVersion {
+       color: $wcfContentDimmedText;
+       font-weight: 400;
+       padding-left: 5px;
+}
+
+.packageSearchPackage {
+       color: $wcfContentDimmedText;
+       font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
+       font-weight: 400;
+       
+       @include wcfFontSmall;
+}
+
+#packageSearchResultContainer {
+       &:not([data-status="idle"]) .packageSearchStatusIdle {
+               display: none;
+       }
+       
+       &:not([data-status="loading"]) .packageSearchStatusLoading {
+               display: none;
+       }
+       
+       &:not([data-status="noResults"]) .packageSearchStatusNoResults {
+               display: none;
+       }
+       
+       &:not([data-status="refreshDatabase"]) .packageSearchStatusRefreshDatabase {
+               display: none;
+       }
+       
+       &:not([data-status="showResults"]) {
+               #packageSearchResultCounter, 
+               #packageSearchResultList {
+                       display: none;
+               }
+       }
+}
+
+.packageSearchStatus  {
+       align-items: center;
+       display: flex;
+       flex-direction: column;
+       justify-content: center;
+       min-height: 120px;
+}
+
+.packageSearchStatusLabel {
+       margin-top: 10px;
+       
+       @include wcfFontHeadline;
+}
index 823d1c7d9b65f5175d47cad0e0f112c475f63af2..976964941aa8bf32faa85596c52fcccc6dc25eb1 100644 (file)
@@ -4,7 +4,6 @@
                        <tr>
                                <th colspan="2" class="columnTitle">{lang}wcf.acp.package.name{/lang}</th>
                                <th class="columnText">{lang}wcf.acp.package.author{/lang}</a></th>
-                               <th class="columnText">{lang}wcf.acp.package.version{/lang}</th>
                                <th class="columnText">{lang}wcf.acp.package.license{/lang}</th>
                                <th class="columnDate">{lang}wcf.acp.package.packageDate{/lang}</a></th>
                                
                                                        
                                                        {event name='buttons'}
                                                </td>
-                                               <td class="columnTitle" title="{$package->packageDescription}">{$package->packageName}</td>
-                                               <td class="columnText">{if $package->authorURL}<a href="{$package->authorURL}" class="externalURL">{$package->author}</a>{else}{$package->author}{/if}</td>
-                                               <td class="columnText">
-                                                       {$package->getAccessibleVersion()->packageVersion}
-                                                       {*if $package->getAccessibleVersion()->packageUpdateVersionID != $package->getLatestVersion()->packageUpdateVersionID}
-                                                               <span class="icon icon16 icon-info-sign jsTooltip" title="{lang packageVersion=$package->getLatestVersion()->packageVersion}wcf.acp.package.newerVersionAvailable{/lang}"></span>
-                                                       {/if*}
+                                               <td class="columnTitle" title="{$package->packageDescription}">
+                                                       <div class="packageSearchName">{$package->packageName} <span class="packageSearchVersion">{$package->getAccessibleVersion()->packageVersion}</span></div>
+                                                       <span class="packageSearchPackage">{$package->package}</span>
                                                </td>
+                                               <td class="columnText">{if $package->authorURL}<a href="{$package->authorURL}" class="externalURL">{$package->author}</a>{else}{$package->author}{/if}</td>
                                                <td class="columnText">{if $package->getAccessibleVersion()->licenseURL}<a href="{$package->getAccessibleVersion()->licenseURL}" class="externalURL">{$package->getAccessibleVersion()->license}</a>{else}{$package->getAccessibleVersion()->license}{/if}</td>
                                                <td class="columnDate">{@$package->getAccessibleVersion()->packageDate|time}</td>
                                                
index 45ff40e570d8284fbcb9f66e67e578393b0735e8..3c4b55e79386d3d8c6d101f2e42a029552c2fb6b 100644 (file)
@@ -6,13 +6,13 @@
 {include file='header'}
 
 <script data-relocate="true">
-       $(function() {
-               WCF.Language.addObject({
+       require(['Language', 'WoltLabSuite/Core/Acp/Ui/Package/Search'], function(Language, AcpUiPackageSearch) {
+               Language.addObject({
                        'wcf.acp.package.install.title': '{lang}wcf.acp.package.install.title{/lang}',
                        'wcf.acp.package.update.unauthorized': '{lang}wcf.acp.package.update.unauthorized{/lang}'
                });
                
-               new WCF.ACP.Package.Search();
+               new AcpUiPackageSearch();
        });
 </script>
 
 {include file='formError'}
 
 <div class="section">
-       <section class="section">
+       <section class="section" id="packageSearch">
                <h2 class="sectionTitle">{lang}wcf.acp.package.search{/lang}</h2>
                
                <dl>
-                       <dt><label for="packageName">{lang}wcf.acp.package.search.packageName{/lang}</label></dt>
-                       <dd><input type="text" id="packageName" value="" class="long" data-search-name="packageName"></dd>
-               </dl>
-               <dl>
-                       <dt><label for="packageDescription">{lang}wcf.acp.package.search.packageDescription{/lang}</label></dt>
-                       <dd><input type="text" id="packageDescription" value="" class="long" data-search-name="packageDescription"></dd>
-               </dl>
-               <dl>
-                       <dt><label for="package">{lang}wcf.acp.package.search.package{/lang}</label></dt>
+                       <dt><label for="packageSearchInput">{lang}wcf.acp.package.search.input{/lang}</label></dt>
                        <dd>
-                               <input type="text" id="package" value="" class="medium" data-search-name="package">
-                               <small>{lang}wcf.acp.package.search.package.description{/lang}</small>
+                               <input type="text" id="packageSearchInput" value="" class="long" autocomplete="off">
+                               <small>{lang}wcf.acp.package.search.input.description{/lang}</small>
                        </dd>
                </dl>
-               
-               <div class="formSubmit">
-                       <button class="jsButtonPackageSearch">{lang}wcf.global.button.submit{/lang}</button>
-               </div>
        </section>
        
-       <section class="section tabularBox" id="packageSearchResultContainer" style="display: none;">
-               <h2 class="sectionTitle">{lang}wcf.acp.package.search.resultList{/lang} <span class="badge">0</span></h2>
+       <section class="section tabularBox" id="packageSearchResultContainer" data-status="idle">
+               <h2 class="sectionTitle">{lang}wcf.acp.package.search.resultList{/lang} <span class="badge" id="packageSearchResultCounter">0</span></h2>
+               
+               <div class="packageSearchStatus packageSearchStatusIdle">
+                       <span class="packageSearchStatusLabel">{lang}wcf.acp.package.search.status.idle{/lang}</span>
+               </div>
+               
+               <div class="packageSearchStatus packageSearchStatusRefreshDatabase">
+                       <span class="icon icon64 fa-spinner"></span>
+                       <span class="packageSearchStatusLabel">{lang}wcf.acp.package.search.status.refreshDatabase{/lang}</span>
+               </div>
+               
+               <div class="packageSearchStatus packageSearchStatusLoading">
+                       <span class="icon icon64 fa-spinner"></span>
+                       <span class="packageSearchStatusLabel">{lang}wcf.acp.package.search.status.loading{/lang}</span>
+               </div>
+               
+               <div class="packageSearchStatus packageSearchStatusNoResults">
+                       <span class="packageSearchStatusLabel">{lang}wcf.acp.package.search.status.noResults{/lang}</span>
+               </div>
                
                <div id="packageSearchResultList"></div>
        </section>
diff --git a/wcfsetup/install/files/js/WoltLabSuite/Core/Acp/Ui/Package/Search.js b/wcfsetup/install/files/js/WoltLabSuite/Core/Acp/Ui/Package/Search.js
new file mode 100644 (file)
index 0000000..96ab6bd
--- /dev/null
@@ -0,0 +1,120 @@
+/**
+ * 
+ * 
+ * @author      Alexander Ebert
+ * @copyright   2001-2019 WoltLab GmbH
+ * @license     GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @module      WoltLabSuite/Core/Acp/Ui/Package/Search
+ */
+define(['Ajax'], function(Ajax) {
+       'use strict';
+       
+       function AcpUiPackageSearch() { this.init(); }
+       AcpUiPackageSearch.prototype = {
+               init: function () {
+                       this._input = elById('packageSearchInput');
+                       this._isBusy = false;
+                       this._isFirstRequest = true;
+                       this._lastValue = '';
+                       this._options = {
+                               delay: 300,
+                               minLength: 3
+                       };
+                       this._request = null;
+                       this._resultList = elById('packageSearchResultList');
+                       this._resultListContainer = elById('packageSearchResultContainer');
+                       this._resultCounter = elById('packageSearchResultCounter');
+                       this._timerDelay = null;
+                       
+                       this._input.addEventListener('keyup', this._keyup.bind(this));
+               },
+               
+               _keyup: function () {
+                       var value = this._input.value.trim();
+                       if (this._lastValue === value) {
+                               return;
+                       }
+                       
+                       this._lastValue = value;
+                       
+                       if (value.length < this._options.minLength) {
+                               this._setStatus('idle');
+                               return;
+                       }
+                       
+                       if (this._isFirstRequest) {
+                               if (!this._isBusy) {
+                                       this._isBusy = true;
+                                       
+                                       this._setStatus('refreshDatabase');
+                                       
+                                       Ajax.api(this, {
+                                               actionName: 'refreshDatabase'
+                                       });
+                               }
+                               
+                               return;
+                       }
+                       
+                       if (this._timerDelay !== null) {
+                               window.clearTimeout(this._timerDelay);
+                       }
+                       
+                       this._timerDelay = window.setTimeout((function() {
+                               this._setStatus('loading');
+                               this._search(value);
+                       }).bind(this), this._options.delay);
+               },
+               
+               _search: function(value) {
+                       if (this._request) {
+                               this._request.abortPrevious();
+                       }
+                       
+                       this._request = Ajax.api(this, {
+                               parameters: {
+                                       searchString: value
+                               }
+                       });
+               },
+               
+               _setStatus: function (status) {
+                       elData(this._resultListContainer, 'status', status);
+               },
+               
+               _ajaxSuccess: function(data) {
+                       switch (data.actionName) {
+                               case 'refreshDatabase':
+                                       this._isFirstRequest = false;
+                                       
+                                       this._lastValue = '';
+                                       this._keyup();
+                                       break;
+                               
+                               case 'search':
+                                       if (data.returnValues.count > 0) {
+                                               this._resultList.innerHTML = data.returnValues.template;
+                                               this._resultCounter.textContent = data.returnValues.count;
+                                               
+                                               this._setStatus('showResults');
+                                       }
+                                       else {
+                                               this._setStatus('noResults');
+                                       }
+                                       break;
+                       }
+               },
+               
+               _ajaxSetup: function() {
+                       return {
+                               data: {
+                                       actionName: 'search',
+                                       className: 'wcf\\data\\package\\update\\PackageUpdateAction'
+                               },
+                               silent: true
+                       };
+               }
+       };
+       
+       return AcpUiPackageSearch;
+});
index 8c5ad4c069cc9371235cd39e1a4c6c1d663277b6..a94d9b8750caf21ed410b40b951d0727c41e8821 100644 (file)
@@ -54,14 +54,7 @@ class PackageUpdateAction extends AbstractDatabaseObjectAction {
        public function validateSearch() {
                WCF::getSession()->checkPermissions(['admin.configuration.package.canInstallPackage']);
                
-               $this->readString('package', true);
-               $this->readString('packageDescription', true);
-               $this->readString('packageName', true);
-               $this->readBoolean('searchDescription', true);
-               
-               if (empty($this->parameters['package']) && empty($this->parameters['packageDescription']) && empty($this->parameters['packageName'])) {
-                       throw new PermissionDeniedException();
-               }
+               $this->readString('searchString');
        }
        
        /**
@@ -70,7 +63,6 @@ class PackageUpdateAction extends AbstractDatabaseObjectAction {
         * @return      array
         */
        public function search() {
-               PackageUpdateDispatcher::getInstance()->refreshPackageDatabase();
                $availableUpdateServers = PackageUpdateServer::getActiveUpdateServers();
                
                // there are no available package update servers
@@ -82,15 +74,8 @@ class PackageUpdateAction extends AbstractDatabaseObjectAction {
                
                $conditions = new PreparedStatementConditionBuilder();
                $conditions->add("package_update.packageUpdateServerID IN (?)", [array_keys($availableUpdateServers)]);
-               if (!empty($this->parameters['package'])) {
-                       $conditions->add("package_update.package LIKE ?", ['%' . $this->parameters['package'] . '%']);
-               }
-               if (!empty($this->parameters['packageDescription'])) {
-                       $conditions->add("package_update.packageDescription LIKE ?", ['%' . $this->parameters['packageDescription'] . '%']);
-               }
-               if (!empty($this->parameters['packageName'])) {
-                       $conditions->add("package_update.packageName LIKE ?", ['%' . $this->parameters['packageName'] . '%']);
-               }
+               $searchString = '%' . $this->parameters['searchString'] . '%';
+               $conditions->add("(package_update.package LIKE ? OR package_update.packageDescription LIKE ? OR package_update.packageName LIKE ?)", [$searchString, $searchString, $searchString]);
                $conditions->add("package.packageID IS NULL");
                
                // find matching packages
@@ -208,7 +193,7 @@ class PackageUpdateAction extends AbstractDatabaseObjectAction {
                                while ($row = $statement->fetchArray()) {
                                        $packageVersions[$row['packageUpdateVersionID']] = [
                                                'packageUpdateID' => $row['packageUpdateID'],
-                                               'packageVersion' => $row['packageVersion']
+                                               'packageVersion' => $row['packageVersion'],
                                        ];
                                }
                                
@@ -232,21 +217,7 @@ class PackageUpdateAction extends AbstractDatabaseObjectAction {
                        }
                }
                
-               $search = SearchEditor::create([
-                       'userID' => WCF::getUser()->userID,
-                       'searchData' => serialize($packageUpdates),
-                       'searchTime' => TIME_NOW,
-                       'searchType' => 'acpPackageSearch'
-               ]);
-               
-               // forward call to build the actual result list
-               $updateAction = new PackageUpdateAction([], 'getResultList', [
-                       'pageNo' => 1,
-                       'search' => $search
-               ]);
-               
-               $returnValues = $updateAction->executeAction();
-               return $returnValues['returnValues'];
+               return $this->getResultList($availableUpdateServers, $packageUpdates);
        }
        
        /**
@@ -332,7 +303,7 @@ class PackageUpdateAction extends AbstractDatabaseObjectAction {
                        if (!isset($packageVersions[$package][$packageUpdateID])) {
                                $packageVersions[$package][$packageUpdateID] = [
                                        'accessible' => [],
-                                       'existing' => []
+                                       'existing' => [],
                                ];
                        }
                        
@@ -385,7 +356,7 @@ class PackageUpdateAction extends AbstractDatabaseObjectAction {
                        $existing = array_pop($existing);
                        $packageUpdates[$versions[$accessible]] = [
                                'accessible' => $accessible,
-                               'existing' => $existing
+                               'existing' => $existing,
                        ];
                }
                
@@ -438,32 +409,14 @@ class PackageUpdateAction extends AbstractDatabaseObjectAction {
                return $packageUpdates;
        }
        
-       /**
-        * Validates parameters to return a result list for a previous search.
-        */
-       public function validateGetResultList() {
-               WCF::getSession()->checkPermissions(['admin.configuration.package.canInstallPackage']);
-               
-               $this->readInteger('pageNo');
-               $this->readInteger('searchID');
-               
-               $this->search = new Search($this->parameters['searchID']);
-               if (!$this->search->searchID || $this->search->userID != WCF::getUser()->userID) {
-                       throw new UserInputException('searchID');
-               }
-       }
-       
        /**
         * Returns a result list for a previous search.
         * 
+        * @param       PackageUpdateServer[]   $updateServers
+        * @param       array                   $updateData
         * @return      array
         */
-       public function getResultList() {
-               if ($this->search === null && isset($this->parameters['search']) && $this->parameters['search'] instanceof Search) {
-                       $this->search = $this->parameters['search'];
-               }
-               $updateData = unserialize($this->search->searchData);
-               
+       protected function getResultList(array $updateServers, array $updateData) {
                // get package updates
                $conditions = new PreparedStatementConditionBuilder();
                $conditions->add("packageUpdateID IN (?)", [array_keys($updateData)]);
@@ -471,7 +424,7 @@ class PackageUpdateAction extends AbstractDatabaseObjectAction {
                $sql = "SELECT  *
                        FROM    wcf".WCF_N."_package_update
                        ".$conditions;
-               $statement = WCF::getDB()->prepareStatement($sql, 20, ($this->parameters['pageNo'] - 1) * 20);
+               $statement = WCF::getDB()->prepareStatement($sql);
                $statement->execute($conditions->getParameters());
                $packageUpdates = $packageVersionIDs = [];
                while ($packageUpdate = $statement->fetchObject(PackageUpdate::class)) {
@@ -497,22 +450,35 @@ class PackageUpdateAction extends AbstractDatabaseObjectAction {
                $updateVersions = $statement->fetchObjects(PackageUpdateVersion::class, 'packageUpdateVersionID');
                
                // assign versions
+               /**
+                * @var int $packageUpdateID
+                * @var ViewablePackageUpdate $packageUpdate
+                */
                foreach ($packageUpdates as $packageUpdateID => $packageUpdate) {
                        $versionIDs = $updateData[$packageUpdate->packageUpdateID];
                        $packageUpdate->setAccessibleVersion($updateVersions[$versionIDs['accessible']]);
                        $packageUpdate->setLatestVersion($updateVersions[$versionIDs['existing']]);
+                       $packageUpdate->setUpdateServer($updateServers[$packageUpdate->packageUpdateServerID]);
                }
                
+               uasort($packageUpdates, function(ViewablePackageUpdate $a, ViewablePackageUpdate $b) {
+                       $aIsTrusted = $a->getUpdateServer()->isTrustedServer() || $a->getUpdateServer()->isWoltLabStoreServer();
+                       $bIsTrusted = $b->getUpdateServer()->isTrustedServer() || $b->getUpdateServer()->isWoltLabStoreServer();
+                       
+                       if ($aIsTrusted === $bIsTrusted) {
+                               return strnatcasecmp($a->getName(), $b->getName());
+                       }
+                       
+                       return $aIsTrusted ? -1 : 1;
+               });
+               
                WCF::getTPL()->assign([
-                       'packageUpdates' => $packageUpdates
+                       'packageUpdates' => $packageUpdates,
                ]);
                
-               $count = count($updateData);
                return [
-                       'count' => $count,
-                       'pageCount' => ceil($count / 20),
-                       'searchID' => $this->search->searchID,
-                       'template' => WCF::getTPL()->fetch('packageSearchResultList')
+                       'count' => count($updateData),
+                       'template' => WCF::getTPL()->fetch('packageSearchResultList'),
                ];
        }
        
@@ -544,7 +510,7 @@ class PackageUpdateAction extends AbstractDatabaseObjectAction {
                }
                
                return [
-                       'url' => $url
+                       'url' => $url,
                ];
        }
        
@@ -630,6 +596,20 @@ class PackageUpdateAction extends AbstractDatabaseObjectAction {
                return $this->createQueue('install');
        }
        
+       public function validateRefreshDatabase() {
+               WCF::getSession()->checkPermissions(['admin.configuration.package.canInstallPackage']);
+               
+               $this->readBoolean('ignoreCache', true);
+               
+               if (ENABLE_BENCHMARK) {
+                       throw new NamedUserException(WCF::getLanguage()->getDynamicVariable('wcf.acp.package.searchForUpdates.benchmark'));
+               }
+       }
+       
+       public function refreshDatabase() {
+               PackageUpdateDispatcher::getInstance()->refreshPackageDatabase();
+       }
+       
        /**
         * Creates a new package installation queue.
         * 
@@ -649,7 +629,7 @@ class PackageUpdateAction extends AbstractDatabaseObjectAction {
                }
                catch (PackageUpdateUnauthorizedException $e) {
                        return [
-                               'template' => $e->getRenderedTemplate()
+                               'template' => $e->getRenderedTemplate(),
                        ];
                }
                
@@ -660,7 +640,7 @@ class PackageUpdateAction extends AbstractDatabaseObjectAction {
                        if (!empty($excludedPackages)) {
                                return [
                                        'excludedPackages' => true,
-                                       'template' => WCF::getTPL()->fetch('packageUpdateExcludedPackages', 'wcf', ['excludedPackages' => $excludedPackages])
+                                       'template' => WCF::getTPL()->fetch('packageUpdateExcludedPackages', 'wcf', ['excludedPackages' => $excludedPackages]),
                                ];
                        }
                }
@@ -702,7 +682,7 @@ class PackageUpdateAction extends AbstractDatabaseObjectAction {
                                        'packageName' => $package['packageName'],
                                        'packageID' => $package['packageID'] ?: null,
                                        'archive' => $package['archive'],
-                                       'action' => $package['action']
+                                       'action' => $package['action'],
                                ]);
                                $parentQueueID = $queue->queueID;
                                
@@ -713,7 +693,7 @@ class PackageUpdateAction extends AbstractDatabaseObjectAction {
                }
                
                return [
-                       'queueID' => $queueID
+                       'queueID' => $queueID,
                ];
        }
 }
index 1cd6e599e7441229f932dc99aa8c06ef86f87228..17baebeeeabbe6495773f78d5097eb63220fc058 100644 (file)
@@ -1,5 +1,6 @@
 <?php
 namespace wcf\data\package\update;
+use wcf\data\package\update\server\PackageUpdateServer;
 use wcf\data\package\update\version\PackageUpdateVersion;
 use wcf\data\DatabaseObjectDecorator;
 
@@ -24,13 +25,18 @@ class ViewablePackageUpdate extends DatabaseObjectDecorator {
         * latest accessible package update version object
         * @var PackageUpdateVersion
         */
-       protected $accessibleVersion = null;
+       protected $accessibleVersion;
        
        /**
         * latest package update version object
         * @var PackageUpdateVersion
         */
-       protected $latestVersion = null;
+       protected $latestVersion;
+       
+       /**
+        * @var PackageUpdateServer
+        */
+       protected $updateServer;
        
        /**
         * Sets latest accessible package update version object.
@@ -67,4 +73,20 @@ class ViewablePackageUpdate extends DatabaseObjectDecorator {
        public function getLatestVersion() {
                return $this->latestVersion;
        }
+       
+       /**
+        * @param PackageUpdateServer $updateServer
+        * @since 5.2
+        */
+       public function setUpdateServer(PackageUpdateServer $updateServer) {
+               $this->updateServer = $updateServer;
+       }
+       
+       /**
+        * @return PackageUpdateServer
+        * @since 5.2
+        */
+       public function getUpdateServer() {
+               return $this->updateServer;
+       }
 }
index 1cb95f8ac6d0267ed9c29a6694d73fd515cbbf86..16ce3e6041754d4fce204ab2131e5698be4a751b 100644 (file)
@@ -1916,6 +1916,12 @@ Die Datenbestände werden sorgfältig gepflegt, aber es ist nicht ausgeschlossen
        {/foreach}
 </ul>
 {if LANGUAGE_USE_INFORMAL_VARIANT}Solltest du{else}Sollten Sie{/if} die <strong>Lizenz für die jeweilige App bereits erworben</strong> haben, so reicht es aus, alle kommenden Updates zu installieren. <strong>Die Testversion wird in diesem Fall automatisch in die Vollversion umgewandelt.</strong>]]></item>
+               <item name="wcf.acp.package.search.input"><![CDATA[Suchbegriff eingeben]]></item>
+               <item name="wcf.acp.package.search.input.description"><![CDATA[Es wird nach Teilübereinstimmungen des Paketnamens, dessen Beschreibung sowie dem internen Bezeichner gesucht.]]></item>
+               <item name="wcf.acp.package.search.status.idle"><![CDATA[Geben Sie mehr als drei Buchstaben ein, um die Suche zu starten.]]></item>
+               <item name="wcf.acp.package.search.status.loading"><![CDATA[Suche läuft…]]></item>
+               <item name="wcf.acp.package.search.status.noResults"><![CDATA[Die Suche ergab keine Treffer.]]></item>
+               <item name="wcf.acp.package.search.status.refreshDatabase"><![CDATA[Die Paketlisten werden aktualisiert…]]></item>
        </category>
        <category name="wcf.acp.page">
                <item name="wcf.acp.page.add"><![CDATA[Seite hinzufügen]]></item>
index 833cf425071650a13b036ed78bcad10072ceb23e..9dd1ed71828141c69739fe57bb6caaccb672e78f 100644 (file)
@@ -1902,6 +1902,12 @@ The database is carefully maintained, but it there will be always be a margin of
        {/foreach}
 </ul>
 If you have <strong>already bought the licenses for the listed apps</strong>, then it is enough to install all upcoming updates. <strong>The evaluation copy will automatically be upgraded to the full version.</strong>]]></item>
+               <item name="wcf.acp.package.search.input"><![CDATA[Search term]]></item>
+               <item name="wcf.acp.package.search.input.description"><![CDATA[Partial matches are performed against the package name, its description and its internal identifier.]]></item>
+               <item name="wcf.acp.package.search.status.idle"><![CDATA[Enter three or more characters to start searching.]]></item>
+               <item name="wcf.acp.package.search.status.loading"><![CDATA[Searching…]]></item>
+               <item name="wcf.acp.package.search.status.noResults"><![CDATA[There were no matches.]]></item>
+               <item name="wcf.acp.package.search.status.refreshDatabase"><![CDATA[Retrieving the package lists…]]></item>
        </category>
        <category name="wcf.acp.paidSubscription">
                <item name="wcf.acp.paidSubscription.list"><![CDATA[Paid Subscriptions]]></item>