Allow multiple navigation links from info.xml

Signed-off-by: Joas Schilling <coding@schilljs.com>
This commit is contained in:
Joas Schilling 2017-03-26 21:15:25 +02:00
parent 7cc5130e82
commit e0b040d623
No known key found for this signature in database
GPG Key ID: E166FD8976B3BAC8
4 changed files with 119 additions and 91 deletions

View File

@ -55,10 +55,12 @@
<command>OCA\Files\Command\ScanAppData</command> <command>OCA\Files\Command\ScanAppData</command>
</commands> </commands>
<navigation> <navigations>
<name>Files</name> <navigation>
<route>files.view.index</route> <name>Files</name>
<order>0</order> <route>files.view.index</route>
</navigation> <order>0</order>
</navigation>
</navigations>
</info> </info>

View File

@ -48,7 +48,7 @@ class App {
\OC::$server->getGroupManager(), \OC::$server->getGroupManager(),
\OC::$server->getConfig() \OC::$server->getConfig()
); );
self::$navigationManager->noDefaultLinks(); self::$navigationManager->clear(false);
} }
return self::$navigationManager; return self::$navigationManager;
} }

View File

@ -118,24 +118,13 @@ class NavigationManager implements INavigationManager {
}); });
} }
/**
* Do not load the default links
* This is just a hack for the files app
* @internal
*/
public function noDefaultLinks() {
$this->entries = [];
$this->closureEntries = [];
$this->init = true;
}
/** /**
* removes all the entries * removes all the entries
*/ */
public function clear() { public function clear($loadDefaultLinks = true) {
$this->entries = []; $this->entries = [];
$this->closureEntries = []; $this->closureEntries = [];
$this->init = false; $this->init = !$loadDefaultLinks;
} }
/** /**
@ -242,45 +231,46 @@ class NavigationManager implements INavigationManager {
foreach ($this->appManager->getInstalledApps() as $app) { foreach ($this->appManager->getInstalledApps() as $app) {
// load plugins and collections from info.xml // load plugins and collections from info.xml
$info = $this->appManager->getAppInfo($app); $info = $this->appManager->getAppInfo($app);
if (!isset($info['navigation'])) { if (empty($info['navigations'])) {
continue; continue;
} }
$nav = $info['navigation']; foreach ($info['navigations'] as $nav) {
if (!isset($nav['name'])) { if (!isset($nav['name'])) {
continue; continue;
} }
if (!isset($nav['route'])) { if (!isset($nav['route'])) {
continue; continue;
} }
$role = isset($nav['@attributes']['role']) ? $nav['@attributes']['role'] : 'all'; $role = isset($nav['@attributes']['role']) ? $nav['@attributes']['role'] : 'all';
if ($role === 'admin' && !$this->isAdmin()) { if ($role === 'admin' && !$this->isAdmin()) {
continue; continue;
} }
$l = $this->l10nFac->get($app); $l = $this->l10nFac->get($app);
$order = isset($nav['order']) ? $nav['order'] : 100; $order = isset($nav['order']) ? $nav['order'] : 100;
$type = isset($nav['type']) ? $nav['type'] : 'link'; $type = isset($nav['type']) ? $nav['type'] : 'link';
$route = $this->urlGenerator->linkToRoute($nav['route']); $route = $this->urlGenerator->linkToRoute($nav['route']);
$icon = isset($nav['icon']) ? $nav['icon'] : 'app.svg'; $icon = isset($nav['icon']) ? $nav['icon'] : 'app.svg';
foreach ([$icon, "$app.svg"] as $i) { foreach ([$icon, "$app.svg"] as $i) {
try { try {
$icon = $this->urlGenerator->imagePath($app, $i); $icon = $this->urlGenerator->imagePath($app, $i);
break; break;
} catch (\RuntimeException $ex) { } catch (\RuntimeException $ex) {
// no icon? - ignore it then // no icon? - ignore it then
}
}
if ($icon === null) {
$icon = $this->urlGenerator->imagePath('core', 'default-app-icon');
} }
}
if ($icon === null) {
$icon = $this->urlGenerator->imagePath('core', 'default-app-icon');
}
$this->add([ $this->add([
'id' => $app, 'id' => $app,
'order' => $order, 'order' => $order,
'href' => $route, 'href' => $route,
'icon' => $icon, 'icon' => $icon,
'type' => $type, 'type' => $type,
'name' => $l->t($nav['name']), 'name' => $l->t($nav['name']),
]); ]);
}
} }
} }

View File

@ -14,7 +14,7 @@ namespace Test;
use OC\App\AppManager; use OC\App\AppManager;
use OC\NavigationManager; use OC\NavigationManager;
use OCP\App\IAppManager; use OCP\IConfig;
use OCP\IGroupManager; use OCP\IGroupManager;
use OCP\IL10N; use OCP\IL10N;
use OCP\IURLGenerator; use OCP\IURLGenerator;
@ -23,13 +23,41 @@ use OCP\IUserSession;
use OCP\L10N\IFactory; use OCP\L10N\IFactory;
class NavigationManagerTest extends TestCase { class NavigationManagerTest extends TestCase {
/** @var AppManager|\PHPUnit_Framework_MockObject_MockObject */
protected $appManager;
/** @var IURLGenerator|\PHPUnit_Framework_MockObject_MockObject */
protected $urlGenerator;
/** @var IFactory|\PHPUnit_Framework_MockObject_MockObject */
protected $l10nFac;
/** @var IUserSession|\PHPUnit_Framework_MockObject_MockObject */
protected $userSession;
/** @var IGroupManager|\PHPUnit_Framework_MockObject_MockObject */
protected $groupManager;
/** @var IConfig|\PHPUnit_Framework_MockObject_MockObject */
protected $config;
/** @var \OC\NavigationManager */ /** @var \OC\NavigationManager */
protected $navigationManager; protected $navigationManager;
protected function setUp() { protected function setUp() {
parent::setUp(); parent::setUp();
$this->navigationManager = new NavigationManager(); $this->appManager = $this->createMock(AppManager::class);
$this->urlGenerator = $this->createMock(IURLGenerator::class);
$this->l10nFac = $this->createMock(IFactory::class);
$this->userSession = $this->createMock(IUserSession::class);
$this->groupManager = $this->createMock(IGroupManager::class);
$this->config = $this->createMock(IConfig::class);
$this->navigationManager = new NavigationManager(
$this->appManager,
$this->urlGenerator,
$this->l10nFac,
$this->userSession,
$this->groupManager,
$this->config
);
$this->navigationManager->clear(false);
} }
public function addArrayData() { public function addArrayData() {
@ -41,6 +69,7 @@ class NavigationManagerTest extends TestCase {
'order' => 1, 'order' => 1,
'icon' => 'optional', 'icon' => 'optional',
'href' => 'url', 'href' => 'url',
'type' => 'settings',
], ],
[ [
'id' => 'entry id', 'id' => 'entry id',
@ -49,6 +78,7 @@ class NavigationManagerTest extends TestCase {
'icon' => 'optional', 'icon' => 'optional',
'href' => 'url', 'href' => 'url',
'active' => false, 'active' => false,
'type' => 'settings',
], ],
], ],
[ [
@ -67,6 +97,7 @@ class NavigationManagerTest extends TestCase {
'icon' => '', 'icon' => '',
'href' => 'url', 'href' => 'url',
'active' => false, 'active' => false,
'type' => 'link',
], ],
], ],
]; ];
@ -79,15 +110,15 @@ class NavigationManagerTest extends TestCase {
* @param array $expectedEntry * @param array $expectedEntry
*/ */
public function testAddArray(array $entry, array $expectedEntry) { public function testAddArray(array $entry, array $expectedEntry) {
$this->assertEmpty($this->navigationManager->getAll(), 'Expected no navigation entry exists'); $this->assertEmpty($this->navigationManager->getAll('all'), 'Expected no navigation entry exists');
$this->navigationManager->add($entry); $this->navigationManager->add($entry);
$navigationEntries = $this->navigationManager->getAll(); $navigationEntries = $this->navigationManager->getAll('all');
$this->assertEquals(1, sizeof($navigationEntries), 'Expected that 1 navigation entry exists'); $this->assertCount(1, $navigationEntries, 'Expected that 1 navigation entry exists');
$this->assertEquals($expectedEntry, $navigationEntries[0]); $this->assertEquals($expectedEntry, $navigationEntries[0]);
$this->navigationManager->clear(); $this->navigationManager->clear(false);
$this->assertEmpty($this->navigationManager->getAll(), 'Expected no navigation entry exists after clear()'); $this->assertEmpty($this->navigationManager->getAll('all'), 'Expected no navigation entry exists after clear()');
} }
/** /**
@ -109,18 +140,18 @@ class NavigationManagerTest extends TestCase {
$this->assertEquals(0, $testAddClosureNumberOfCalls, 'Expected that the closure is not called by add()'); $this->assertEquals(0, $testAddClosureNumberOfCalls, 'Expected that the closure is not called by add()');
$navigationEntries = $this->navigationManager->getAll(); $navigationEntries = $this->navigationManager->getAll('all');
$this->assertEquals(1, $testAddClosureNumberOfCalls, 'Expected that the closure is called by getAll()'); $this->assertEquals(1, $testAddClosureNumberOfCalls, 'Expected that the closure is called by getAll()');
$this->assertEquals(1, sizeof($navigationEntries), 'Expected that 1 navigation entry exists'); $this->assertCount(1, $navigationEntries, 'Expected that 1 navigation entry exists');
$this->assertEquals($expectedEntry, $navigationEntries[0]); $this->assertEquals($expectedEntry, $navigationEntries[0]);
$navigationEntries = $this->navigationManager->getAll(); $navigationEntries = $this->navigationManager->getAll('all');
$this->assertEquals(1, $testAddClosureNumberOfCalls, 'Expected that the closure is only called once for getAll()'); $this->assertEquals(1, $testAddClosureNumberOfCalls, 'Expected that the closure is only called once for getAll()');
$this->assertEquals(1, sizeof($navigationEntries), 'Expected that 1 navigation entry exists'); $this->assertCount(1, $navigationEntries, 'Expected that 1 navigation entry exists');
$this->assertEquals($expectedEntry, $navigationEntries[0]); $this->assertEquals($expectedEntry, $navigationEntries[0]);
$this->navigationManager->clear(); $this->navigationManager->clear(false);
$this->assertEmpty($this->navigationManager->getAll(), 'Expected no navigation entry exists after clear()'); $this->assertEmpty($this->navigationManager->getAll('all'), 'Expected no navigation entry exists after clear()');
} }
public function testAddArrayClearGetAll() { public function testAddArrayClearGetAll() {
@ -134,7 +165,7 @@ class NavigationManagerTest extends TestCase {
$this->assertEmpty($this->navigationManager->getAll(), 'Expected no navigation entry exists'); $this->assertEmpty($this->navigationManager->getAll(), 'Expected no navigation entry exists');
$this->navigationManager->add($entry); $this->navigationManager->add($entry);
$this->navigationManager->clear(); $this->navigationManager->clear(false);
$this->assertEmpty($this->navigationManager->getAll(), 'Expected no navigation entry exists after clear()'); $this->assertEmpty($this->navigationManager->getAll(), 'Expected no navigation entry exists after clear()');
} }
@ -160,7 +191,7 @@ class NavigationManagerTest extends TestCase {
}); });
$this->assertEquals(0, $testAddClosureNumberOfCalls, 'Expected that the closure is not called by add()'); $this->assertEquals(0, $testAddClosureNumberOfCalls, 'Expected that the closure is not called by add()');
$this->navigationManager->clear(); $this->navigationManager->clear(false);
$this->assertEquals(0, $testAddClosureNumberOfCalls, 'Expected that the closure is not called by clear()'); $this->assertEquals(0, $testAddClosureNumberOfCalls, 'Expected that the closure is not called by clear()');
$this->assertEmpty($this->navigationManager->getAll(), 'Expected no navigation entry exists after clear()'); $this->assertEmpty($this->navigationManager->getAll(), 'Expected no navigation entry exists after clear()');
$this->assertEquals(0, $testAddClosureNumberOfCalls, 'Expected that the closure is not called by getAll()'); $this->assertEquals(0, $testAddClosureNumberOfCalls, 'Expected that the closure is not called by getAll()');
@ -169,35 +200,29 @@ class NavigationManagerTest extends TestCase {
/** /**
* @dataProvider providesNavigationConfig * @dataProvider providesNavigationConfig
*/ */
public function testWithAppManager($expected, $config, $isAdmin = false) { public function testWithAppManager($expected, $navigation, $isAdmin = false) {
$appManager = $this->createMock(AppManager::class);
$urlGenerator = $this->createMock(IURLGenerator::class);
$l10nFac = $this->createMock(IFactory::class);
$userSession = $this->createMock(IUserSession::class);
$groupManager = $this->createMock(IGroupManager::class);
$l = $this->createMock(IL10N::class); $l = $this->createMock(IL10N::class);
$l->expects($this->any())->method('t')->willReturnCallback(function($text, $parameters = []) { $l->expects($this->any())->method('t')->willReturnCallback(function($text, $parameters = []) {
return vsprintf($text, $parameters); return vsprintf($text, $parameters);
}); });
$appManager->expects($this->once())->method('getInstalledApps')->willReturn(['test']); $this->appManager->expects($this->once())->method('getInstalledApps')->willReturn(['test']);
$appManager->expects($this->once())->method('getAppInfo')->with('test')->willReturn($config); $this->appManager->expects($this->once())->method('getAppInfo')->with('test')->willReturn($navigation);
$l10nFac->expects($this->exactly(count($expected)))->method('get')->with('test')->willReturn($l); $this->l10nFac->expects($this->exactly(count($expected) + 1))->method('get')->willReturn($l);
$urlGenerator->expects($this->any())->method('imagePath')->willReturnCallback(function($appName, $file) { $this->urlGenerator->expects($this->any())->method('imagePath')->willReturnCallback(function($appName, $file) {
return "/apps/$appName/img/$file"; return "/apps/$appName/img/$file";
}); });
$urlGenerator->expects($this->exactly(count($expected)))->method('linkToRoute')->willReturnCallback(function($route) { $this->urlGenerator->expects($this->exactly(count($expected)))->method('linkToRoute')->willReturnCallback(function() {
return "/apps/test/"; return "/apps/test/";
}); });
$user = $this->createMock(IUser::class); $user = $this->createMock(IUser::class);
$user->expects($this->any())->method('getUID')->willReturn('user001'); $user->expects($this->any())->method('getUID')->willReturn('user001');
$userSession->expects($this->any())->method('getUser')->willReturn($user); $this->userSession->expects($this->any())->method('getUser')->willReturn($user);
$groupManager->expects($this->any())->method('isAdmin')->willReturn($isAdmin); $this->groupManager->expects($this->any())->method('isAdmin')->willReturn($isAdmin);
$navigationManager = new NavigationManager($appManager, $urlGenerator, $l10nFac, $userSession, $groupManager); $this->navigationManager->clear();
$entries = $this->navigationManager->getAll('all');
$entries = $navigationManager->getAll();
$this->assertEquals($expected, $entries); $this->assertEquals($expected, $entries);
} }
@ -209,18 +234,29 @@ class NavigationManagerTest extends TestCase {
'href' => '/apps/test/', 'href' => '/apps/test/',
'icon' => '/apps/test/img/app.svg', 'icon' => '/apps/test/img/app.svg',
'name' => 'Test', 'name' => 'Test',
'active' => false 'active' => false,
]], ['navigation' => ['route' => 'test.page.index', 'name' => 'Test']]], 'type' => 'link',
]], ['navigations' => [['route' => 'test.page.index', 'name' => 'Test']]]],
'minimalistic-settings' => [[[
'id' => 'test',
'order' => 100,
'href' => '/apps/test/',
'icon' => '/apps/test/img/app.svg',
'name' => 'Test',
'active' => false,
'type' => 'settings',
]], ['navigations' => [['route' => 'test.page.index', 'name' => 'Test', 'type' => 'settings']]]],
'no admin' => [[[ 'no admin' => [[[
'id' => 'test', 'id' => 'test',
'order' => 100, 'order' => 100,
'href' => '/apps/test/', 'href' => '/apps/test/',
'icon' => '/apps/test/img/app.svg', 'icon' => '/apps/test/img/app.svg',
'name' => 'Test', 'name' => 'Test',
'active' => false 'active' => false,
]], ['navigation' => ['@attributes' => ['role' => 'admin'], 'route' => 'test.page.index', 'name' => 'Test']], true], 'type' => 'link',
'no name' => [[], ['navigation' => ['@attributes' => ['role' => 'admin'], 'route' => 'test.page.index']], true], ]], ['navigations' => [['@attributes' => ['role' => 'admin'], 'route' => 'test.page.index', 'name' => 'Test']]], true],
'admin' => [[], ['navigation' => ['@attributes' => ['role' => 'admin'], 'route' => 'test.page.index', 'name' => 'Test']]] 'no name' => [[], ['navigations' => [['@attributes' => ['role' => 'admin'], 'route' => 'test.page.index']]], true],
'admin' => [[], ['navigations' => [['@attributes' => ['role' => 'admin'], 'route' => 'test.page.index', 'name' => 'Test']]]]
]; ];
} }
} }