diff options
-rw-r--r-- | settings/controller/appsettingscontroller.php | 47 | ||||
-rw-r--r-- | settings/js/apps.js | 78 | ||||
-rw-r--r-- | settings/templates/apps.php | 4 | ||||
-rw-r--r-- | settings/tests/js/appsSpec.js | 70 | ||||
-rw-r--r-- | tests/settings/controller/AppSettingsControllerTest.php | 41 |
5 files changed, 206 insertions, 34 deletions
diff --git a/settings/controller/appsettingscontroller.php b/settings/controller/appsettingscontroller.php index f5cb043da20..bde00df062f 100644 --- a/settings/controller/appsettingscontroller.php +++ b/settings/controller/appsettingscontroller.php @@ -42,6 +42,8 @@ use OCP\IConfig; * @package OC\Settings\Controller */ class AppSettingsController extends Controller { + const CAT_ENABLED = 0; + const CAT_DISABLED = 1; /** @var \OCP\IL10N */ private $l10n; @@ -95,12 +97,41 @@ class AppSettingsController extends Controller { } /** + * @param string|int $category + * @return int + */ + protected function getCategory($category) { + if (is_string($category)) { + foreach ($this->listCategories() as $cat) { + if (isset($cat['ident']) && $cat['ident'] === $category) { + $category = (int) $cat['id']; + break; + } + } + + // Didn't find the category, falling back to enabled + if (is_string($category)) { + $category = self::CAT_ENABLED; + } + } + return (int) $category; + } + + /** * @NoCSRFRequired + * @param string $category * @return TemplateResponse */ - public function viewApps() { + public function viewApps($category = '') { + $categoryId = $this->getCategory($category); + if ($categoryId === self::CAT_ENABLED) { + // Do not use an arbitrary input string, because we put the category in html + $category = 'enabled'; + } + $params = []; $params['experimentalEnabled'] = $this->config->getSystemValue('appstore.experimental.enabled', false); + $params['category'] = $category; $this->navigationManager->setActiveEntry('core_apps'); $templateResponse = new TemplateResponse($this->appName, 'apps', $params, 'user'); @@ -121,8 +152,8 @@ class AppSettingsController extends Controller { return $this->cache->get('listCategories'); } $categories = [ - ['id' => 0, 'displayName' => (string)$this->l10n->t('Enabled')], - ['id' => 1, 'displayName' => (string)$this->l10n->t('Not enabled')], + ['id' => self::CAT_ENABLED, 'ident' => 'enabled', 'displayName' => (string)$this->l10n->t('Enabled')], + ['id' => self::CAT_DISABLED, 'ident' => 'disabled', 'displayName' => (string)$this->l10n->t('Not enabled')], ]; if($this->ocsClient->isAppStoreEnabled()) { @@ -130,9 +161,12 @@ class AppSettingsController extends Controller { $ocs = $this->ocsClient->getCategories(\OC_Util::getVersion()); if ($ocs) { foreach($ocs as $k => $v) { + $name = str_replace('ownCloud ', '', $v); + $ident = str_replace(' ', '-', urlencode(strtolower($name))); $categories[] = [ 'id' => $k, - 'displayName' => str_replace('ownCloud ', '', $v) + 'ident' => $ident, + 'displayName' => $name, ]; } } @@ -146,12 +180,13 @@ class AppSettingsController extends Controller { /** * Get all available apps in a category * - * @param int $category + * @param string $category * @param bool $includeUpdateInfo Should we check whether there is an update * in the app store? * @return array */ - public function listApps($category = 0, $includeUpdateInfo = true) { + public function listApps($category = '', $includeUpdateInfo = true) { + $category = $this->getCategory($category); $cacheName = 'listApps-' . $category . '-' . (int) $includeUpdateInfo; if(!is_null($this->cache->get($cacheName))) { diff --git a/settings/js/apps.js b/settings/js/apps.js index 987153b778c..9ffa74c7d93 100644 --- a/settings/js/apps.js +++ b/settings/js/apps.js @@ -40,7 +40,8 @@ OC.Settings.Apps = OC.Settings.Apps || { } var categories = [ - {displayName: 'Enabled', id: '0'} + {displayName: t('settings', 'Enabled'), ident: 'enabled', id: '0'}, + {displayName: t('settings', 'Not enabled'), ident: 'disabled', id: '1'} ]; var source = $("#categories-template").html(); @@ -48,7 +49,7 @@ OC.Settings.Apps = OC.Settings.Apps || { var html = template(categories); $('#apps-categories').html(html); - OC.Settings.Apps.loadCategory(0); + OC.Settings.Apps.loadCategory($('#app-navigation').attr('data-category')); this._loadCategoriesCall = $.ajax(OC.generateUrl('settings/apps/categories'), { data:{}, @@ -115,7 +116,7 @@ OC.Settings.Apps = OC.Settings.Apps || { }); } else { $('#apps-list').addClass('hidden'); - $('#apps-list-empty').removeClass('hidden'); + $('#apps-list-empty').removeClass('hidden').find('h2').text(t('settings', 'No apps found for your version')); } $('.app-level .official').tipsy({fallback: t('settings', 'Official apps are developed by and within the ownCloud community. They offer functionality central to ownCloud and are ready for production use.')}); @@ -398,14 +399,14 @@ OC.Settings.Apps = OC.Settings.Apps || { .text(''); }, - showReloadMessage: function(appId) { + showReloadMessage: function() { OC.dialogs.info( t( 'settings', 'The app has been enabled but needs to be updated. You will be redirected to the update page in 5 seconds.' ), t('settings','App update'), - function (result) { + function () { window.location.reload(); }, true @@ -413,24 +414,74 @@ OC.Settings.Apps = OC.Settings.Apps || { }, filter: function(query) { + var $appList = $('#apps-list'), + $emptyList = $('#apps-list-empty'); + $appList.removeClass('hidden'); + $appList.find('.section').removeClass('hidden'); + $emptyList.addClass('hidden'); + + if (query === '') { + return; + } + query = query.toLowerCase(); - $('#apps-list').find('.section').addClass('hidden'); + $appList.find('.section').addClass('hidden'); + // App Name var apps = _.filter(OC.Settings.Apps.State.apps, function (app) { return app.name.toLowerCase().indexOf(query) !== -1; }); + // App Description apps = apps.concat(_.filter(OC.Settings.Apps.State.apps, function (app) { return app.description.toLowerCase().indexOf(query) !== -1; })); + // Author Name + apps = apps.concat(_.filter(OC.Settings.Apps.State.apps, function (app) { + return app.author.toLowerCase().indexOf(query) !== -1; + })); + + // App status + if (t('settings', 'Official').toLowerCase().indexOf(query) !== -1) { + apps = apps.concat(_.filter(OC.Settings.Apps.State.apps, function (app) { + return app.level === 200; + })); + } + if (t('settings', 'Approved').toLowerCase().indexOf(query) !== -1) { + apps = apps.concat(_.filter(OC.Settings.Apps.State.apps, function (app) { + return app.level === 100; + })); + } + if (t('settings', 'Experimental').toLowerCase().indexOf(query) !== -1) { + apps = apps.concat(_.filter(OC.Settings.Apps.State.apps, function (app) { + return app.level !== 100 && app.level !== 200; + })); + } + apps = _.uniq(apps, function(app){return app.id;}); - _.each(apps, function (app) { - $('#app-' + app.id).removeClass('hidden'); - }); + if (apps.length === 0) { + $appList.addClass('hidden'); + $emptyList.removeClass('hidden'); + $emptyList.removeClass('hidden').find('h2').text(t('settings', 'No apps found for "{query}"', { + query: query + })); + } else { + _.each(apps, function (app) { + $('#app-' + app.id).removeClass('hidden'); + }); - $('#searchresults').hide(); + $('#searchresults').hide(); + } + }, + + _onPopState: function(params) { + params = _.extend({ + category: 'enabled' + }, params); + + OC.Settings.Apps.loadCategory(params.category); }, /** @@ -439,10 +490,15 @@ OC.Settings.Apps = OC.Settings.Apps || { initialize: function($el) { OC.Plugins.register('OCA.Search', OC.Settings.Apps.Search); OC.Settings.Apps.loadCategories(); + OC.Util.History.addOnPopStateHandler(_.bind(this._onPopState, this)); $(document).on('click', 'ul#apps-categories li', function () { var categoryId = $(this).data('categoryId'); OC.Settings.Apps.loadCategory(categoryId); + OC.Util.History.pushState({ + category: categoryId + }); + $('#searchbox').val(''); }); $(document).on('click', '.app-description-toggle-show', function () { @@ -508,7 +564,7 @@ OC.Settings.Apps = OC.Settings.Apps || { }); $(document).on('click', '#enable-experimental-apps', function () { - var state = $(this).prop('checked') + var state = $(this).prop('checked'); $.ajax(OC.generateUrl('settings/apps/experimental'), { data: {state: state}, type: 'POST', diff --git a/settings/templates/apps.php b/settings/templates/apps.php index 7e6c151fa65..bb01d991e5e 100644 --- a/settings/templates/apps.php +++ b/settings/templates/apps.php @@ -24,7 +24,7 @@ script( ?> <script id="categories-template" type="text/x-handlebars-template"> {{#each this}} - <li id="app-category-{{id}}" data-category-id="{{id}}" tabindex="0"> + <li id="app-category-{{ident}}" data-category-id="{{ident}}" tabindex="0"> <a>{{displayName}}</a> </li> {{/each}} @@ -127,7 +127,7 @@ script( </div> </script> -<div id="app-navigation" class="icon-loading"> +<div id="app-navigation" class="icon-loading" data-category="<?php p($_['category']);?>"> <ul id="apps-categories"> </ul> diff --git a/settings/tests/js/appsSpec.js b/settings/tests/js/appsSpec.js index 907d441ff4d..d2ca1fb5c8b 100644 --- a/settings/tests/js/appsSpec.js +++ b/settings/tests/js/appsSpec.js @@ -24,6 +24,7 @@ describe('OC.Settings.Apps tests', function() { beforeEach(function() { var $el = $('<div id="apps-list"></div>' + + '<div id="apps-list-empty" class="hidden"></div>' + '<div id="app-template">' + // dummy template for testing '<div id="app-{{id}}" data-id="{{id}}" class="section">{{name}}</div>' + @@ -59,22 +60,33 @@ describe('OC.Settings.Apps tests', function() { beforeEach(function() { loadApps([ - {id: 'appone', name: 'App One', description: 'The first app'}, - {id: 'apptwo', name: 'App Two', description: 'The second app'}, - {id: 'appthree', name: 'App Three', description: 'Third app'}, - {id: 'somestuff', name: 'Some Stuff', description: 'whatever'} + {id: 'appone', name: 'App One', description: 'The first app', author: 'author1', level: 200}, + {id: 'apptwo', name: 'App Two', description: 'The second app', author: 'author2', level: 100}, + {id: 'appthree', name: 'App Three', description: 'Third app', author: 'author3', level: 0}, + {id: 'somestuff', name: 'Some Stuff', description: 'whatever', author: 'author4', level: 0} ]); }); - it('does not filter when no query passed', function() { - Apps.filter(''); - expect(getResultsFromDom().length).toEqual(4); - }); it('returns no results when query does not match anything', function() { + expect(getResultsFromDom().length).toEqual(4); + expect($('#apps-list:not(.hidden)').length).toEqual(1); + expect($('#apps-list-empty:not(.hidden)').length).toEqual(0); + Apps.filter('absurdity'); expect(getResultsFromDom().length).toEqual(0); + expect($('#apps-list:not(.hidden)').length).toEqual(0); + expect($('#apps-list-empty:not(.hidden)').length).toEqual(1); + + Apps.filter(''); + expect(getResultsFromDom().length).toEqual(4); + expect($('#apps-list:not(.hidden)').length).toEqual(1); + expect($('#apps-list-empty:not(.hidden)').length).toEqual(0); + expect(getResultsFromDom().length).toEqual(4); }); it('returns relevant results when query matches name', function() { + expect($('#apps-list:not(.hidden)').length).toEqual(1); + expect($('#apps-list-empty:not(.hidden)').length).toEqual(0); + var results; Apps.filter('app'); results = getResultsFromDom(); @@ -82,6 +94,9 @@ describe('OC.Settings.Apps tests', function() { expect(results[0]).toEqual('appone'); expect(results[1]).toEqual('apptwo'); expect(results[2]).toEqual('appthree'); + + expect($('#apps-list:not(.hidden)').length).toEqual(1); + expect($('#apps-list-empty:not(.hidden)').length).toEqual(0); }); it('returns relevant result when query matches name', function() { var results; @@ -97,6 +112,45 @@ describe('OC.Settings.Apps tests', function() { expect(results.length).toEqual(1); expect(results[0]).toEqual('somestuff'); }); + it('returns relevant results when query matches author name', function() { + var results; + Apps.filter('author'); + results = getResultsFromDom(); + expect(results.length).toEqual(4); + expect(results[0]).toEqual('appone'); + expect(results[1]).toEqual('apptwo'); + expect(results[2]).toEqual('appthree'); + expect(results[3]).toEqual('somestuff'); + }); + it('returns relevant result when query matches author name', function() { + var results; + Apps.filter('thor3'); + results = getResultsFromDom(); + expect(results.length).toEqual(1); + expect(results[0]).toEqual('appthree'); + }); + it('returns relevant result when query matches level name', function() { + var results; + Apps.filter('Offic'); + results = getResultsFromDom(); + expect(results.length).toEqual(1); + expect(results[0]).toEqual('appone'); + }); + it('returns relevant result when query matches level name', function() { + var results; + Apps.filter('Appro'); + results = getResultsFromDom(); + expect(results.length).toEqual(1); + expect(results[0]).toEqual('apptwo'); + }); + it('returns relevant result when query matches level name', function() { + var results; + Apps.filter('Exper'); + results = getResultsFromDom(); + expect(results.length).toEqual(2); + expect(results[0]).toEqual('appthree'); + expect(results[1]).toEqual('somestuff'); + }); }); describe('loading categories', function() { diff --git a/tests/settings/controller/AppSettingsControllerTest.php b/tests/settings/controller/AppSettingsControllerTest.php index d6379deb9c8..09595d05661 100644 --- a/tests/settings/controller/AppSettingsControllerTest.php +++ b/tests/settings/controller/AppSettingsControllerTest.php @@ -132,10 +132,12 @@ class AppSettingsControllerTest extends TestCase { $expected = [ [ 'id' => 0, + 'ident' => 'enabled', 'displayName' => 'Enabled', ], [ 'id' => 1, + 'ident' => 'disabled', 'displayName' => 'Not enabled', ], ]; @@ -157,27 +159,33 @@ class AppSettingsControllerTest extends TestCase { $expected = [ [ 'id' => 0, + 'ident' => 'enabled', 'displayName' => 'Enabled', ], [ 'id' => 1, + 'ident' => 'disabled', 'displayName' => 'Not enabled', ], [ 'id' => 0, + 'ident' => 'tools', 'displayName' => 'Tools', ], [ 'id' => 1, - 'displayName' => 'Awesome Games', + 'ident' => 'games', + 'displayName' => 'Games', ], [ 'id' => 2, - 'displayName' => 'PIM', + 'ident' => 'productivity', + 'displayName' => 'Productivity', ], [ 'id' => 3, - 'displayName' => 'Papershop', + 'ident' => 'multimedia', + 'displayName' => 'Multimedia', ], ]; @@ -201,9 +209,9 @@ class AppSettingsControllerTest extends TestCase { ->will($this->returnValue( [ 'ownCloud Tools', - 'Awesome Games', - 'ownCloud PIM', - 'Papershop', + 'Games', + 'ownCloud Productivity', + 'Multimedia', ] )); @@ -223,9 +231,28 @@ class AppSettingsControllerTest extends TestCase { $policy = new ContentSecurityPolicy(); $policy->addAllowedImageDomain('https://apps.owncloud.com'); - $expected = new TemplateResponse('settings', 'apps', ['experimentalEnabled' => false], 'user'); + $expected = new TemplateResponse('settings', 'apps', ['experimentalEnabled' => false, 'category' => 'enabled'], 'user'); $expected->setContentSecurityPolicy($policy); $this->assertEquals($expected, $this->appSettingsController->viewApps()); } + + public function testViewAppsNotEnabled() { + $this->config + ->expects($this->once()) + ->method('getSystemValue') + ->with('appstore.experimental.enabled', false); + $this->navigationManager + ->expects($this->once()) + ->method('setActiveEntry') + ->with('core_apps'); + + $policy = new ContentSecurityPolicy(); + $policy->addAllowedImageDomain('https://apps.owncloud.com'); + + $expected = new TemplateResponse('settings', 'apps', ['experimentalEnabled' => false, 'category' => 'disabled'], 'user'); + $expected->setContentSecurityPolicy($policy); + + $this->assertEquals($expected, $this->appSettingsController->viewApps('disabled')); + } } |