From 8d1b32e59788633dc6ab77e736a72f00625a389d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Tue, 3 Oct 2017 14:56:41 +0200 Subject: [PATCH 1/5] App management: add update section MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- core/css/icons.scss | 7 +++++ settings/Controller/AppSettingsController.php | 29 +++++++++++++++++++ settings/js/apps.js | 26 ++++++++--------- settings/templates/apps.php | 8 +++-- .../Controller/AppSettingsControllerTest.php | 6 ++++ 5 files changed, 60 insertions(+), 16 deletions(-) diff --git a/core/css/icons.scss b/core/css/icons.scss index 7c47a3e12c875..6d855381fae99 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/settings/Controller/AppSettingsController.php b/settings/Controller/AppSettingsController.php index ac77b2e7dd6ef..da59461e5fa79 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 @@ public function viewApps($category = '') { 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 @@ private function getAppsForCategory($requestedCategory) { 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 @@ public function listApps($category = '') { 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 39e800636cb04..ab0a4da558597 100644 --- a/settings/js/apps.js +++ b/settings/js/apps.js @@ -42,6 +42,7 @@ OC.Settings.Apps = OC.Settings.Apps || { var categories = [ {displayName: t('settings', 'Your apps'), ident: 'installed', id: '0'}, + {displayName: t('settings', 'Updates'), ident: 'updates', id: '3'}, {displayName: t('settings', 'Enabled apps'), ident: 'enabled', id: '1'}, {displayName: t('settings', 'Disabled apps'), ident: 'disabled', id: '2'} ]; @@ -58,6 +59,12 @@ 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' + }); + if (updateCategory.length === 1) { + OC.Settings.Apps.State.availableUpdates = updateCategory[0].counter; + } $('#apps-categories').html(html); $('#app-category-' + OC.Settings.Apps.State.currentCategory).addClass('active'); }, @@ -99,7 +106,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 { @@ -134,13 +141,8 @@ OC.Settings.Apps = OC.Settings.Apps || { 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)); - } } else { $('#apps-list').addClass('hidden'); $('#apps-list-empty').removeClass('hidden').find('h2').text(t('settings', 'No apps found for your version')); @@ -539,14 +541,8 @@ 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(); } },'json'); }, @@ -656,6 +652,10 @@ OC.Settings.Apps = OC.Settings.Apps || { }); }, + refreshUpdateCounter: function() { + $('#app-category-updates').find('.app-navigation-entry-utils-counter').html(OC.Settings.Apps.State.availableUpdates); + }, + showErrorMessage: function(appId, message) { $('div#app-'+appId+' .warning') .show() diff --git a/settings/templates/apps.php b/settings/templates/apps.php index 91a73fcbe5685..f0fc5791e5ab5 100644 --- a/settings/templates/apps.php +++ b/settings/templates/apps.php @@ -19,6 +19,11 @@ {{#each this}}
  • {{displayName}} +
    +
      +
    • {{ counter }}
    • +
    +
  • {{/each}} @@ -65,9 +70,6 @@
    - {{#if canUnInstall}} diff --git a/tests/Settings/Controller/AppSettingsControllerTest.php b/tests/Settings/Controller/AppSettingsControllerTest.php index 9633c77159698..e264d0dfbfe06 100644 --- a/tests/Settings/Controller/AppSettingsControllerTest.php +++ b/tests/Settings/Controller/AppSettingsControllerTest.php @@ -101,6 +101,12 @@ public function testListCategories() { 'ident' => 'installed', 'displayName' => 'Your apps', ], + [ + 'id' => 4, + 'ident' => 'updates', + 'displayName' => 'Updates', + 'counter' => 0, + ], [ 'id' => 0, 'ident' => 'enabled', From ec0091d499c9790faa965dfb9a2bbe443581e96f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Tue, 3 Oct 2017 15:03:11 +0200 Subject: [PATCH 2/5] Do not return app names multiple times MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- lib/private/legacy/app.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/private/legacy/app.php b/lib/private/legacy/app.php index a33c9be20fc58..627107a63a84f 100644 --- a/lib/private/legacy/app.php +++ b/lib/private/legacy/app.php @@ -768,6 +768,8 @@ public static function getAllApps() { } } + $apps = array_unique($apps); + return $apps; } From 6f7fb2e87b031e7a1e8c93ef79e1c17aeae1c461 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Tue, 3 Oct 2017 16:50:13 +0200 Subject: [PATCH 3/5] App management: do not reset update counter to 0 on category change MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- settings/js/apps.js | 1 - 1 file changed, 1 deletion(-) diff --git a/settings/js/apps.js b/settings/js/apps.js index ab0a4da558597..9dd27bcd5e1ac 100644 --- a/settings/js/apps.js +++ b/settings/js/apps.js @@ -91,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 From a3502c5c670456e1c3ea2476b31f681a37839e8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Tue, 3 Oct 2017 18:15:14 +0200 Subject: [PATCH 4/5] App management: Show proper message when no updates are available MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- settings/js/apps.js | 35 ++++++++++++++++++++++++++++++----- settings/templates/apps.php | 2 +- 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/settings/js/apps.js b/settings/js/apps.js index 9dd27bcd5e1ac..ea6bd6ea5c633 100644 --- a/settings/js/apps.js +++ b/settings/js/apps.js @@ -62,11 +62,13 @@ OC.Settings.Apps = OC.Settings.Apps || { 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) { + console.log(updateCategory); OC.Settings.Apps.State.availableUpdates = updateCategory[0].counter; + OC.Settings.Apps.refreshUpdateCounter(); } - $('#apps-categories').html(html); - $('#app-category-' + OC.Settings.Apps.State.currentCategory).addClass('active'); }, complete: function() { $('#app-navigation').removeClass('icon-loading'); @@ -143,8 +145,13 @@ OC.Settings.Apps = OC.Settings.Apps || { } }); } 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({ @@ -518,6 +525,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....')); @@ -542,6 +555,13 @@ OC.Settings.Apps = OC.Settings.Apps || { 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'); }, @@ -652,7 +672,12 @@ OC.Settings.Apps = OC.Settings.Apps || { }, refreshUpdateCounter: function() { - $('#app-category-updates').find('.app-navigation-entry-utils-counter').html(OC.Settings.Apps.State.availableUpdates); + var $updateCount = $('#app-category-updates').find('.app-navigation-entry-utils-counter'); + if (OC.Settings.Apps.State.availableUpdates > 0) { + $updateCount.html(OC.Settings.Apps.State.availableUpdates); + } else { + $updateCount.empty(); + } }, showErrorMessage: function(appId, message) { diff --git a/settings/templates/apps.php b/settings/templates/apps.php index f0fc5791e5ab5..5d5194965985b 100644 --- a/settings/templates/apps.php +++ b/settings/templates/apps.php @@ -208,7 +208,7 @@
    From bee9ef83c65689990dba852b1944b5cf472eae43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Wed, 4 Oct 2017 14:23:51 +0200 Subject: [PATCH 5/5] App management: Do not show udpdate category if no updates are available MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- settings/js/apps.js | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/settings/js/apps.js b/settings/js/apps.js index ea6bd6ea5c633..6406e37cbcbcd 100644 --- a/settings/js/apps.js +++ b/settings/js/apps.js @@ -42,7 +42,6 @@ OC.Settings.Apps = OC.Settings.Apps || { var categories = [ {displayName: t('settings', 'Your apps'), ident: 'installed', id: '0'}, - {displayName: t('settings', 'Updates'), ident: 'updates', id: '3'}, {displayName: t('settings', 'Enabled apps'), ident: 'enabled', id: '1'}, {displayName: t('settings', 'Disabled apps'), ident: 'disabled', id: '2'} ]; @@ -65,7 +64,6 @@ OC.Settings.Apps = OC.Settings.Apps || { $('#apps-categories').html(html); $('#app-category-' + OC.Settings.Apps.State.currentCategory).addClass('active'); if (updateCategory.length === 1) { - console.log(updateCategory); OC.Settings.Apps.State.availableUpdates = updateCategory[0].counter; OC.Settings.Apps.refreshUpdateCounter(); } @@ -130,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; @@ -139,11 +138,20 @@ 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)); } }); + // 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 { if (categoryId === 'updates') { OC.Settings.Apps.showEmptyUpdates(); @@ -671,12 +679,30 @@ 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 $updateCount = $('#app-category-updates').find('.app-navigation-entry-utils-counter'); + 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(); + } } }, @@ -727,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');