summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJulius Härtl <github@jus.li>2017-10-10 14:57:35 +0200
committerGitHub <noreply@github.com>2017-10-10 14:57:35 +0200
commit0def38b50ea7281b1c887833a966ce42ff016c36 (patch)
tree1bc25ac5d2742ea30217bb7a29bc4a065da53d30
parent968d4f6396e30321a4f05f867edd581ba50c9e81 (diff)
parentbee9ef83c65689990dba852b1944b5cf472eae43 (diff)
downloadnextcloud-server-0def38b50ea7281b1c887833a966ce42ff016c36.tar.gz
nextcloud-server-0def38b50ea7281b1c887833a966ce42ff016c36.zip
Merge pull request #6739 from nextcloud/apps-management-updates
Add Updates section to app management
-rw-r--r--core/css/icons.scss7
-rw-r--r--lib/private/legacy/app.php2
-rw-r--r--settings/Controller/AppSettingsController.php29
-rw-r--r--settings/js/apps.js79
-rw-r--r--settings/templates/apps.php10
-rw-r--r--tests/Settings/Controller/AppSettingsControllerTest.php6
6 files changed, 115 insertions, 18 deletions
diff --git a/core/css/icons.scss b/core/css/icons.scss
index 7c47a3e12c8..6d855381fae 100644
--- a/core/css/icons.scss
+++ b/core/css/icons.scss
@@ -493,16 +493,23 @@ img, object, video, button, textarea, input, select {
.icon-category-installed {
background-image: url('../img/actions/user.svg?v=1');
}
+
.icon-category-enabled {
background-image: url('../img/actions/checkmark.svg?v=1');
}
+
.icon-category-disabled {
background-image: url('../img/actions/close.svg?v=1');
}
+
.icon-category-app-bundles {
background-image: url('../img/categories/bundles.svg?v=1');
}
+.icon-category-updates {
+ background-image: url('../img/actions/download.svg?v=1');
+}
+
.icon-category-files {
background-image: url('../img/categories/files.svg?v=1');
}
diff --git a/lib/private/legacy/app.php b/lib/private/legacy/app.php
index a33c9be20fc..627107a63a8 100644
--- a/lib/private/legacy/app.php
+++ b/lib/private/legacy/app.php
@@ -768,6 +768,8 @@ class OC_App {
}
}
+ $apps = array_unique($apps);
+
return $apps;
}
diff --git a/settings/Controller/AppSettingsController.php b/settings/Controller/AppSettingsController.php
index ac77b2e7dd6..da59461e5fa 100644
--- a/settings/Controller/AppSettingsController.php
+++ b/settings/Controller/AppSettingsController.php
@@ -52,6 +52,7 @@ class AppSettingsController extends Controller {
const CAT_DISABLED = 1;
const CAT_ALL_INSTALLED = 2;
const CAT_APP_BUNDLES = 3;
+ const CAT_UPDATES = 4;
/** @var \OCP\IL10N */
private $l10n;
@@ -130,8 +131,10 @@ class AppSettingsController extends Controller {
private function getAllCategories() {
$currentLanguage = substr($this->l10nFactory->findLanguage(), 0, 2);
+ $updateCount = count($this->getAppsWithUpdates());
$formattedCategories = [
['id' => self::CAT_ALL_INSTALLED, 'ident' => 'installed', 'displayName' => (string)$this->l10n->t('Your apps')],
+ ['id' => self::CAT_UPDATES, 'ident' => 'updates', 'displayName' => (string)$this->l10n->t('Updates'), 'counter' => $updateCount],
['id' => self::CAT_ENABLED, 'ident' => 'enabled', 'displayName' => (string)$this->l10n->t('Enabled apps')],
['id' => self::CAT_DISABLED, 'ident' => 'disabled', 'displayName' => (string)$this->l10n->t('Disabled apps')],
['id' => self::CAT_APP_BUNDLES, 'ident' => 'app-bundles', 'displayName' => (string)$this->l10n->t('App bundles')],
@@ -273,6 +276,28 @@ class AppSettingsController extends Controller {
return $formattedApps;
}
+ private function getAppsWithUpdates() {
+ $appClass = new \OC_App();
+ $apps = $appClass->listAllApps();
+ foreach($apps as $key => $app) {
+ $newVersion = \OC\Installer::isUpdateAvailable($app['id'], $this->appFetcher);
+ if($newVersion !== false) {
+ $apps[$key]['update'] = $newVersion;
+ } else {
+ unset($apps[$key]);
+ }
+ }
+ usort($apps, function ($a, $b) {
+ $a = (string)$a['name'];
+ $b = (string)$b['name'];
+ if ($a === $b) {
+ return 0;
+ }
+ return ($a < $b) ? -1 : 1;
+ });
+ return $apps;
+ }
+
/**
* Get all available apps in a category
*
@@ -301,6 +326,10 @@ class AppSettingsController extends Controller {
return ($a < $b) ? -1 : 1;
});
break;
+ // updates
+ case 'updates':
+ $apps = $this->getAppsWithUpdates();
+ break;
// enabled apps
case 'enabled':
$apps = $appClass->listAllApps();
diff --git a/settings/js/apps.js b/settings/js/apps.js
index 39e800636cb..6406e37cbcb 100644
--- a/settings/js/apps.js
+++ b/settings/js/apps.js
@@ -58,8 +58,15 @@ OC.Settings.Apps = OC.Settings.Apps || {
type:'GET',
success:function (jsondata) {
var html = template(jsondata);
+ var updateCategory = $.grep(jsondata, function(element, index) {
+ return element.ident === 'updates'
+ });
$('#apps-categories').html(html);
$('#app-category-' + OC.Settings.Apps.State.currentCategory).addClass('active');
+ if (updateCategory.length === 1) {
+ OC.Settings.Apps.State.availableUpdates = updateCategory[0].counter;
+ OC.Settings.Apps.refreshUpdateCounter();
+ }
},
complete: function() {
$('#app-navigation').removeClass('icon-loading');
@@ -84,7 +91,6 @@ OC.Settings.Apps = OC.Settings.Apps || {
$('#app-category-' + OC.Settings.Apps.State.currentCategory).removeClass('active');
$('#app-category-' + categoryId).addClass('active');
OC.Settings.Apps.State.currentCategory = categoryId;
- OC.Settings.Apps.State.availableUpdates = 0;
this._loadCategoryCall = $.ajax(OC.generateUrl('settings/apps/list?category={categoryId}', {
categoryId: categoryId
@@ -99,7 +105,7 @@ OC.Settings.Apps = OC.Settings.Apps || {
return _.extend({level: 0}, app);
});
var source;
- if (categoryId === 'enabled' || categoryId === 'disabled' || categoryId === 'installed' || categoryId === 'app-bundles') {
+ if (categoryId === 'enabled' || categoryId === 'updates' || categoryId === 'disabled' || categoryId === 'installed' || categoryId === 'app-bundles') {
source = $("#app-template-installed").html();
$('#apps-list').addClass('installed');
} else {
@@ -122,6 +128,7 @@ OC.Settings.Apps = OC.Settings.Apps || {
}
var firstExperimental = false;
+ var hasNewUpdates = false;
_.each(appList, function(app) {
if(app.level === 0 && firstExperimental === false) {
firstExperimental = true;
@@ -131,19 +138,28 @@ OC.Settings.Apps = OC.Settings.Apps || {
}
if (app.update) {
+ hasNewUpdates = true;
var $update = $('#app-' + app.id + ' .update');
$update.removeClass('hidden');
$update.val(t('settings', 'Update to %s').replace(/%s/g, app.update));
- OC.Settings.Apps.State.availableUpdates++;
}
});
-
- if (OC.Settings.Apps.State.availableUpdates > 0) {
- OC.Settings.Apps.State.$updateNotification = OC.Notification.show(n('settings', 'You have %n app update pending', 'You have %n app updates pending', OC.Settings.Apps.State.availableUpdates));
+ // reload updates if a list with new updates is loaded
+ if (hasNewUpdates) {
+ OC.Settings.Apps.reloadUpdates();
+ } else {
+ // hide update category after all updates are installed
+ // and the user is switching away from the empty updates view
+ OC.Settings.Apps.refreshUpdateCounter();
}
} else {
- $('#apps-list').addClass('hidden');
- $('#apps-list-empty').removeClass('hidden').find('h2').text(t('settings', 'No apps found for your version'));
+ if (categoryId === 'updates') {
+ OC.Settings.Apps.showEmptyUpdates();
+ } else {
+ $('#apps-list').addClass('hidden');
+ $('#apps-list-empty').removeClass('hidden').find('h2').text(t('settings', 'No apps found for your version'));
+ $('#app-list-empty-icon').addClass('icon-search').removeClass('icon-download');
+ }
}
$('.enable.needs-download').tooltip({
@@ -517,6 +533,12 @@ OC.Settings.Apps = OC.Settings.Apps || {
}
},
+ showEmptyUpdates: function() {
+ $('#apps-list').addClass('hidden');
+ $('#apps-list-empty').removeClass('hidden').find('h2').text(t('settings', 'No app updates available'));
+ $('#app-list-empty-icon').removeClass('icon-search').addClass('icon-download');
+ },
+
updateApp:function(appId, element) {
var oldButtonText = element.val();
element.val(t('settings','Updating....'));
@@ -539,13 +561,14 @@ OC.Settings.Apps = OC.Settings.Apps || {
var $version = $('#app-' + appId + ' .app-version');
$version.text(OC.Settings.Apps.State.apps[appId]['update']);
- if (OC.Settings.Apps.State.$updateNotification) {
- OC.Notification.hide(OC.Settings.Apps.State.$updateNotification);
- }
-
OC.Settings.Apps.State.availableUpdates--;
- if (OC.Settings.Apps.State.availableUpdates > 0) {
- OC.Settings.Apps.State.$updateNotification = OC.Notification.show(n('settings', 'You have %n app update pending', 'You have %n app updates pending', OC.Settings.Apps.State.availableUpdates));
+ OC.Settings.Apps.refreshUpdateCounter();
+
+ if (OC.Settings.Apps.State.currentCategory === 'updates') {
+ $('#app-' + appId).remove();
+ if (OC.Settings.Apps.State.availableUpdates === 0) {
+ OC.Settings.Apps.showEmptyUpdates();
+ }
}
}
},'json');
@@ -656,6 +679,33 @@ OC.Settings.Apps = OC.Settings.Apps || {
});
},
+ reloadUpdates: function() {
+ if (this._loadUpdatesCall) {
+ this._loadUpdatesCall.abort();
+ }
+ this._loadUpdatesCall = $.ajax(OC.generateUrl('settings/apps/list?category=updates'), {
+ type:'GET',
+ success: function (apps) {
+ OC.Settings.Apps.State.availableUpdates = apps.apps.length;
+ OC.Settings.Apps.refreshUpdateCounter();
+ }
+ });
+ },
+
+ refreshUpdateCounter: function() {
+ var $appCategoryUpdates = $('#app-category-updates');
+ var $updateCount = $appCategoryUpdates.find('.app-navigation-entry-utils-counter');
+ if (OC.Settings.Apps.State.availableUpdates > 0) {
+ $updateCount.html(OC.Settings.Apps.State.availableUpdates);
+ $appCategoryUpdates.show();
+ } else {
+ $updateCount.empty();
+ if (OC.Settings.Apps.State.currentCategory !== 'updates') {
+ $appCategoryUpdates.hide();
+ }
+ }
+ },
+
showErrorMessage: function(appId, message) {
$('div#app-'+appId+' .warning')
.show()
@@ -703,6 +753,7 @@ OC.Settings.Apps = OC.Settings.Apps || {
filter: function(query) {
var $appList = $('#apps-list'),
$emptyList = $('#apps-list-empty');
+ $('#app-list-empty-icon').addClass('icon-search').removeClass('icon-download');
$appList.removeClass('hidden');
$appList.find('.section').removeClass('hidden');
$emptyList.addClass('hidden');
diff --git a/settings/templates/apps.php b/settings/templates/apps.php
index 91a73fcbe56..5d519496598 100644
--- a/settings/templates/apps.php
+++ b/settings/templates/apps.php
@@ -19,6 +19,11 @@ script(
{{#each this}}
<li id="app-category-{{ident}}" data-category-id="{{ident}}" tabindex="0">
<a href="#" class="icon-category-{{ident}}">{{displayName}}</a>
+ <div class="app-navigation-entry-utils">
+ <ul>
+ <li class="app-navigation-entry-utils-counter">{{ counter }}</li>
+ </ul>
+ </div>
</li>
{{/each}}
@@ -65,9 +70,6 @@ script(
</div>
<div class="actions">
- <div class="app-dependencies update hidden">
- <p><?php p($l->t('This app has an update available.')); ?></p>
- </div>
<div class="warning hidden"></div>
<input class="update hidden" type="submit" value="<?php p($l->t('Update to %s', array('{{update}}'))); ?>" data-appid="{{id}}" />
{{#if canUnInstall}}
@@ -206,7 +208,7 @@ script(
</svg>
<div id="apps-list"></div>
<div id="apps-list-empty" class="hidden emptycontent emptycontent-search">
- <div class="icon-search"></div>
+ <div id="app-list-empty-icon" class="icon-search"></div>
<h2><?php p($l->t('No apps found for your version')) ?></h2>
</div>
</div>
diff --git a/tests/Settings/Controller/AppSettingsControllerTest.php b/tests/Settings/Controller/AppSettingsControllerTest.php
index 9633c771596..e264d0dfbfe 100644
--- a/tests/Settings/Controller/AppSettingsControllerTest.php
+++ b/tests/Settings/Controller/AppSettingsControllerTest.php
@@ -102,6 +102,12 @@ class AppSettingsControllerTest extends TestCase {
'displayName' => 'Your apps',
],
[
+ 'id' => 4,
+ 'ident' => 'updates',
+ 'displayName' => 'Updates',
+ 'counter' => 0,
+ ],
+ [
'id' => 0,
'ident' => 'enabled',
'displayName' => 'Enabled apps',