Show mime icon, bump bundles, make the SearchResultEntry class non-abstract, Fix header search icon, various fixes

Signed-off-by: John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
This commit is contained in:
John Molakvoæ (skjnldsv) 2020-08-04 10:00:27 +02:00
parent 6eced42b7a
commit 71b62c4203
No known key found for this signature in database
GPG Key ID: 60C25B8C072916CF
62 changed files with 424 additions and 328 deletions

View File

@ -21,8 +21,7 @@ return array(
'OCA\\Comments\\Listener\\LoadSidebarScripts' => $baseDir . '/../lib/Listener/LoadSidebarScripts.php',
'OCA\\Comments\\Notification\\Listener' => $baseDir . '/../lib/Notification/Listener.php',
'OCA\\Comments\\Notification\\Notifier' => $baseDir . '/../lib/Notification/Notifier.php',
'OCA\\Comments\\Search\\CommentsSearchResultEntry' => $baseDir . '/../lib/Search/CommentsSearchResultEntry.php',
'OCA\\Comments\\Search\\CommentsSearchProvider' => $baseDir . '/../lib/Search/CommentsSearchProvider.php',
'OCA\\Comments\\Search\\LegacyProvider' => $baseDir . '/../lib/Search/LegacyProvider.php',
'OCA\\Comments\\Search\\Provider' => $baseDir . '/../lib/Search/Provider.php',
'OCA\\Comments\\Search\\Result' => $baseDir . '/../lib/Search/Result.php',
);

View File

@ -36,9 +36,8 @@ class ComposerStaticInitComments
'OCA\\Comments\\Listener\\LoadSidebarScripts' => __DIR__ . '/..' . '/../lib/Listener/LoadSidebarScripts.php',
'OCA\\Comments\\Notification\\Listener' => __DIR__ . '/..' . '/../lib/Notification/Listener.php',
'OCA\\Comments\\Notification\\Notifier' => __DIR__ . '/..' . '/../lib/Notification/Notifier.php',
'OCA\\Comments\\Search\\CommentsSearchResultEntry' => __DIR__ . '/..' . '/../lib/Search/CommentsSearchResultEntry.php',
'OCA\\Comments\\Search\\CommentsSearchProvider' => __DIR__ . '/..' . '/../lib/Search/CommentsSearchProvider.php',
'OCA\\Comments\\Search\\LegacyProvider' => __DIR__ . '/..' . '/../lib/Search/LegacyProvider.php',
'OCA\\Comments\\Search\\Provider' => __DIR__ . '/..' . '/../lib/Search/Provider.php',
'OCA\\Comments\\Search\\Result' => __DIR__ . '/..' . '/../lib/Search/Result.php',
);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -37,7 +37,7 @@ use OCA\Comments\Listener\LoadAdditionalScripts;
use OCA\Comments\Listener\LoadSidebarScripts;
use OCA\Comments\Notification\Notifier;
use OCA\Comments\Search\LegacyProvider;
use OCA\Comments\Search\Provider;
use OCA\Comments\Search\CommentsSearchProvider;
use OCA\Files\Event\LoadAdditionalScriptsEvent;
use OCA\Files\Event\LoadSidebar;
use OCP\AppFramework\App;
@ -74,7 +74,7 @@ class Application extends App implements IBootstrap {
CommentsEntityEvent::EVENT_ENTITY,
CommentsEntityEventListener::class
);
$context->registerSearchProvider(Provider::class);
$context->registerSearchProvider(CommentsSearchProvider::class);
}
public function boot(IBootContext $context): void {

View File

@ -32,10 +32,11 @@ use OCP\IUserManager;
use OCP\Search\IProvider;
use OCP\Search\ISearchQuery;
use OCP\Search\SearchResult;
use OCP\Search\SearchResultEntry;
use function array_map;
use function pathinfo;
class Provider implements IProvider {
class CommentsSearchProvider implements IProvider {
/** @var IUserManager */
private $userManager;
@ -59,14 +60,30 @@ class Provider implements IProvider {
$this->legacyProvider = $legacyProvider;
}
/**
* @inheritDoc
*/
public function getId(): string {
return 'comments';
}
/**
* @inheritDoc
*/
public function getName(): string {
return $this->l10n->t('Comments');
}
/**
* @inheritDoc
*/
public function getOrder(): int {
return 10;
}
/**
* @inheritDoc
*/
public function search(IUser $user, ISearchQuery $query): SearchResult {
return SearchResult::complete(
$this->l10n->t('Comments'),
@ -77,7 +94,7 @@ class Provider implements IProvider {
$avatarUrl = $isUser
? $this->urlGenerator->linkToRoute('core.avatar.getAvatar', ['userId' => $result->authorId, 'size' => 42])
: $this->urlGenerator->linkToRoute('core.GuestAvatar.getAvatar', ['guestName' => $result->authorId, 'size' => 42]);
return new CommentsSearchResultEntry(
return new SearchResultEntry(
$avatarUrl,
$result->name,
$path,

View File

@ -1,31 +0,0 @@
<?php
declare(strict_types=1);
/**
* @copyright 2020 Christoph Wurst <christoph@winzerhof-wurst.at>
*
* @author 2020 Christoph Wurst <christoph@winzerhof-wurst.at>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace OCA\Comments\Search;
use OCP\Search\ASearchResultEntry;
class CommentsSearchResultEntry extends ASearchResultEntry {
}

View File

@ -212,11 +212,8 @@ return array(
'OCA\\DAV\\RootCollection' => $baseDir . '/../lib/RootCollection.php',
'OCA\\DAV\\Search\\ACalendarSearchProvider' => $baseDir . '/../lib/Search/ACalendarSearchProvider.php',
'OCA\\DAV\\Search\\ContactsSearchProvider' => $baseDir . '/../lib/Search/ContactsSearchProvider.php',
'OCA\\DAV\\Search\\ContactsSearchResultEntry' => $baseDir . '/../lib/Search/ContactsSearchResultEntry.php',
'OCA\\DAV\\Search\\EventsSearchProvider' => $baseDir . '/../lib/Search/EventsSearchProvider.php',
'OCA\\DAV\\Search\\EventsSearchResultEntry' => $baseDir . '/../lib/Search/EventsSearchResultEntry.php',
'OCA\\DAV\\Search\\TasksSearchProvider' => $baseDir . '/../lib/Search/TasksSearchProvider.php',
'OCA\\DAV\\Search\\TasksSearchResultEntry' => $baseDir . '/../lib/Search/TasksSearchResultEntry.php',
'OCA\\DAV\\Server' => $baseDir . '/../lib/Server.php',
'OCA\\DAV\\Settings\\CalDAVSettings' => $baseDir . '/../lib/Settings/CalDAVSettings.php',
'OCA\\DAV\\Storage\\PublicOwnerWrapper' => $baseDir . '/../lib/Storage/PublicOwnerWrapper.php',

View File

@ -227,11 +227,8 @@ class ComposerStaticInitDAV
'OCA\\DAV\\RootCollection' => __DIR__ . '/..' . '/../lib/RootCollection.php',
'OCA\\DAV\\Search\\ACalendarSearchProvider' => __DIR__ . '/..' . '/../lib/Search/ACalendarSearchProvider.php',
'OCA\\DAV\\Search\\ContactsSearchProvider' => __DIR__ . '/..' . '/../lib/Search/ContactsSearchProvider.php',
'OCA\\DAV\\Search\\ContactsSearchResultEntry' => __DIR__ . '/..' . '/../lib/Search/ContactsSearchResultEntry.php',
'OCA\\DAV\\Search\\EventsSearchProvider' => __DIR__ . '/..' . '/../lib/Search/EventsSearchProvider.php',
'OCA\\DAV\\Search\\EventsSearchResultEntry' => __DIR__ . '/..' . '/../lib/Search/EventsSearchResultEntry.php',
'OCA\\DAV\\Search\\TasksSearchProvider' => __DIR__ . '/..' . '/../lib/Search/TasksSearchProvider.php',
'OCA\\DAV\\Search\\TasksSearchResultEntry' => __DIR__ . '/..' . '/../lib/Search/TasksSearchResultEntry.php',
'OCA\\DAV\\Server' => __DIR__ . '/..' . '/../lib/Server.php',
'OCA\\DAV\\Settings\\CalDAVSettings' => __DIR__ . '/..' . '/../lib/Settings/CalDAVSettings.php',
'OCA\\DAV\\Storage\\PublicOwnerWrapper' => __DIR__ . '/..' . '/../lib/Storage/PublicOwnerWrapper.php',

View File

@ -32,6 +32,7 @@ use OCP\IUser;
use OCP\Search\IProvider;
use OCP\Search\ISearchQuery;
use OCP\Search\SearchResult;
use OCP\Search\SearchResultEntry;
use Sabre\VObject\Component\VCard;
use Sabre\VObject\Reader;
@ -92,6 +93,13 @@ class ContactsSearchProvider implements IProvider {
return $this->l10n->t('Contacts');
}
/**
* @inheritDoc
*/
public function getOrder(): int {
return 7;
}
/**
* @inheritDoc
*/
@ -116,7 +124,7 @@ class ContactsSearchProvider implements IProvider {
'offset' => $query->getCursor(),
]
);
$formattedResults = \array_map(function (array $contactRow) use ($addressBooksById):ContactsSearchResultEntry {
$formattedResults = \array_map(function (array $contactRow) use ($addressBooksById):SearchResultEntry {
$addressBook = $addressBooksById[$contactRow['addressbookid']];
/** @var VCard $vCard */
@ -130,7 +138,7 @@ class ContactsSearchProvider implements IProvider {
$subline = $this->generateSubline($vCard);
$resourceUrl = $this->getDeepLinkToContactsApp($addressBook['uri'], (string) $vCard->UID);
return new ContactsSearchResultEntry($thumbnailUrl, $title, $subline, $resourceUrl, 'icon-contacts-dark', true);
return new SearchResultEntry($thumbnailUrl, $title, $subline, $resourceUrl, 'icon-contacts-dark', true);
}, $searchResults);
return SearchResult::paginated(

View File

@ -1,30 +0,0 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2020, Georg Ehrke
*
* @author Georg Ehrke <oc.list@georgehrke.com>
*
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License, version 3,
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
namespace OCA\DAV\Search;
use OCP\Search\ASearchResultEntry;
class ContactsSearchResultEntry extends ASearchResultEntry {
}

View File

@ -28,6 +28,7 @@ use OCA\DAV\CalDAV\CalDavBackend;
use OCP\IUser;
use OCP\Search\ISearchQuery;
use OCP\Search\SearchResult;
use OCP\Search\SearchResultEntry;
use Sabre\VObject\Component;
use Sabre\VObject\DateTimeParser;
use Sabre\VObject\Property;
@ -78,6 +79,13 @@ class EventsSearchProvider extends ACalendarSearchProvider {
return $this->l10n->t('Events');
}
/**
* @inheritDoc
*/
public function getOrder(): int {
return 10;
}
/**
* @inheritDoc
*/
@ -102,7 +110,7 @@ class EventsSearchProvider extends ACalendarSearchProvider {
'offset' => $query->getCursor(),
]
);
$formattedResults = \array_map(function (array $eventRow) use ($calendarsById, $subscriptionsById):EventsSearchResultEntry {
$formattedResults = \array_map(function (array $eventRow) use ($calendarsById, $subscriptionsById):SearchResultEntry {
$component = $this->getPrimaryComponent($eventRow['calendardata'], self::$componentType);
$title = (string)($component->SUMMARY ?? $this->l10n->t('Untitled event'));
$subline = $this->generateSubline($component);
@ -114,7 +122,7 @@ class EventsSearchProvider extends ACalendarSearchProvider {
}
$resourceUrl = $this->getDeepLinkToCalendarApp($calendar['principaluri'], $calendar['uri'], $eventRow['uri']);
return new EventsSearchResultEntry('', $title, $subline, $resourceUrl, 'icon-calendar-dark', false);
return new SearchResultEntry('', $title, $subline, $resourceUrl, 'icon-calendar-dark', false);
}, $searchResults);
return SearchResult::paginated(

View File

@ -1,30 +0,0 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2020, Georg Ehrke
*
* @author Georg Ehrke <oc.list@georgehrke.com>
*
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License, version 3,
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
namespace OCA\DAV\Search;
use OCP\Search\ASearchResultEntry;
class EventsSearchResultEntry extends ASearchResultEntry {
}

View File

@ -28,6 +28,7 @@ use OCA\DAV\CalDAV\CalDavBackend;
use OCP\IUser;
use OCP\Search\ISearchQuery;
use OCP\Search\SearchResult;
use OCP\Search\SearchResultEntry;
use Sabre\VObject\Component;
/**
@ -70,6 +71,13 @@ class TasksSearchProvider extends ACalendarSearchProvider {
return $this->l10n->t('Tasks');
}
/**
* @inheritDoc
*/
public function getOrder(): int {
return 10;
}
/**
* @inheritDoc
*/
@ -94,7 +102,7 @@ class TasksSearchProvider extends ACalendarSearchProvider {
'offset' => $query->getCursor(),
]
);
$formattedResults = \array_map(function (array $taskRow) use ($calendarsById, $subscriptionsById):TasksSearchResultEntry {
$formattedResults = \array_map(function (array $taskRow) use ($calendarsById, $subscriptionsById):SearchResultEntry {
$component = $this->getPrimaryComponent($taskRow['calendardata'], self::$componentType);
$title = (string)($component->SUMMARY ?? $this->l10n->t('Untitled task'));
$subline = $this->generateSubline($component);
@ -106,7 +114,7 @@ class TasksSearchProvider extends ACalendarSearchProvider {
}
$resourceUrl = $this->getDeepLinkToTasksApp($calendar['uri'], $taskRow['uri']);
return new TasksSearchResultEntry('', $title, $subline, $resourceUrl, 'icon-checkmark', false);
return new SearchResultEntry('', $title, $subline, $resourceUrl, 'icon-checkmark', false);
}, $searchResults);
return SearchResult::paginated(

View File

@ -1,30 +0,0 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2020, Georg Ehrke
*
* @author Georg Ehrke <oc.list@georgehrke.com>
*
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License, version 3,
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
namespace OCA\DAV\Search;
use OCP\Search\ASearchResultEntry;
class TasksSearchResultEntry extends ASearchResultEntry {
}

View File

@ -26,13 +26,13 @@ namespace OCA\DAV\Tests\unit;
use OCA\DAV\CardDAV\CardDavBackend;
use OCA\DAV\Search\ContactsSearchProvider;
use OCA\DAV\Search\ContactsSearchResultEntry;
use OCP\App\IAppManager;
use OCP\IL10N;
use OCP\IURLGenerator;
use OCP\IUser;
use OCP\Search\ISearchQuery;
use OCP\Search\SearchResult;
use OCP\Search\SearchResultEntry;
use Sabre\VObject\Reader;
use Test\TestCase;
@ -216,20 +216,20 @@ class ContactsSearchProviderTest extends TestCase {
$result1 = $data['entries'][1];
$result1Data = $result1->jsonSerialize();
$this->assertInstanceOf(ContactsSearchResultEntry::class, $result0);
$this->assertInstanceOf(SearchResultEntry::class, $result0);
$this->assertEquals('', $result0Data['thumbnailUrl']);
$this->assertEquals('FN of Test', $result0Data['title']);
$this->assertEquals('subline', $result0Data['subline']);
$this->assertEquals('deep-link-to-contacts', $result0Data['resourceUrl']);
$this->assertEquals('icon-contacts-dark', $result0Data['iconClass']);
$this->assertEquals('icon-contacts-dark', $result0Data['icon']);
$this->assertTrue($result0Data['rounded']);
$this->assertInstanceOf(ContactsSearchResultEntry::class, $result1);
$this->assertInstanceOf(SearchResultEntry::class, $result1);
$this->assertEquals('absolute-thumbnail-url?photo', $result1Data['thumbnailUrl']);
$this->assertEquals('FN of Test2', $result1Data['title']);
$this->assertEquals('subline', $result1Data['subline']);
$this->assertEquals('deep-link-to-contacts', $result1Data['resourceUrl']);
$this->assertEquals('icon-contacts-dark', $result1Data['iconClass']);
$this->assertEquals('icon-contacts-dark', $result1Data['icon']);
$this->assertTrue($result1Data['rounded']);
}

View File

@ -26,13 +26,13 @@ namespace OCA\DAV\Tests\unit\Search;
use OCA\DAV\CalDAV\CalDavBackend;
use OCA\DAV\Search\EventsSearchProvider;
use OCA\DAV\Search\EventsSearchResultEntry;
use OCP\App\IAppManager;
use OCP\IL10N;
use OCP\IURLGenerator;
use OCP\IUser;
use OCP\Search\ISearchQuery;
use OCP\Search\SearchResult;
use OCP\Search\SearchResultEntry;
use Sabre\VObject\Reader;
use Test\TestCase;
@ -392,28 +392,28 @@ class EventsSearchProviderTest extends TestCase {
$result2 = $data['entries'][2];
$result2Data = $result2->jsonSerialize();
$this->assertInstanceOf(EventsSearchResultEntry::class, $result0);
$this->assertInstanceOf(SearchResultEntry::class, $result0);
$this->assertEmpty($result0Data['thumbnailUrl']);
$this->assertEquals('Untitled event', $result0Data['title']);
$this->assertEquals('subline', $result0Data['subline']);
$this->assertEquals('deep-link-to-calendar', $result0Data['resourceUrl']);
$this->assertEquals('icon-calendar-dark', $result0Data['iconClass']);
$this->assertEquals('icon-calendar-dark', $result0Data['icon']);
$this->assertFalse($result0Data['rounded']);
$this->assertInstanceOf(EventsSearchResultEntry::class, $result1);
$this->assertInstanceOf(SearchResultEntry::class, $result1);
$this->assertEmpty($result1Data['thumbnailUrl']);
$this->assertEquals('Test Europe Berlin', $result1Data['title']);
$this->assertEquals('subline', $result1Data['subline']);
$this->assertEquals('deep-link-to-calendar', $result1Data['resourceUrl']);
$this->assertEquals('icon-calendar-dark', $result1Data['iconClass']);
$this->assertEquals('icon-calendar-dark', $result1Data['icon']);
$this->assertFalse($result1Data['rounded']);
$this->assertInstanceOf(EventsSearchResultEntry::class, $result2);
$this->assertInstanceOf(SearchResultEntry::class, $result2);
$this->assertEmpty($result2Data['thumbnailUrl']);
$this->assertEquals('Test Europe Berlin', $result2Data['title']);
$this->assertEquals('subline', $result2Data['subline']);
$this->assertEquals('deep-link-to-calendar', $result2Data['resourceUrl']);
$this->assertEquals('icon-calendar-dark', $result2Data['iconClass']);
$this->assertEquals('icon-calendar-dark', $result2Data['icon']);
$this->assertFalse($result2Data['rounded']);
}

View File

@ -26,13 +26,13 @@ namespace OCA\DAV\Tests\unit\Search;
use OCA\DAV\CalDAV\CalDavBackend;
use OCA\DAV\Search\TasksSearchProvider;
use OCA\DAV\Search\TasksSearchResultEntry;
use OCP\App\IAppManager;
use OCP\IL10N;
use OCP\IURLGenerator;
use OCP\IUser;
use OCP\Search\ISearchQuery;
use OCP\Search\SearchResult;
use OCP\Search\SearchResultEntry;
use Sabre\VObject\Reader;
use Test\TestCase;
@ -276,28 +276,28 @@ class TasksSearchProviderTest extends TestCase {
$result2 = $data['entries'][2];
$result2Data = $result2->jsonSerialize();
$this->assertInstanceOf(TasksSearchResultEntry::class, $result0);
$this->assertInstanceOf(SearchResultEntry::class, $result0);
$this->assertEmpty($result0Data['thumbnailUrl']);
$this->assertEquals('Untitled task', $result0Data['title']);
$this->assertEquals('subline', $result0Data['subline']);
$this->assertEquals('deep-link-to-tasks', $result0Data['resourceUrl']);
$this->assertEquals('icon-checkmark', $result0Data['iconClass']);
$this->assertEquals('icon-checkmark', $result0Data['icon']);
$this->assertFalse($result0Data['rounded']);
$this->assertInstanceOf(TasksSearchResultEntry::class, $result1);
$this->assertInstanceOf(SearchResultEntry::class, $result1);
$this->assertEmpty($result1Data['thumbnailUrl']);
$this->assertEquals('Task title', $result1Data['title']);
$this->assertEquals('subline', $result1Data['subline']);
$this->assertEquals('deep-link-to-tasks', $result1Data['resourceUrl']);
$this->assertEquals('icon-checkmark', $result1Data['iconClass']);
$this->assertEquals('icon-checkmark', $result1Data['icon']);
$this->assertFalse($result1Data['rounded']);
$this->assertInstanceOf(TasksSearchResultEntry::class, $result2);
$this->assertInstanceOf(SearchResultEntry::class, $result2);
$this->assertEmpty($result2Data['thumbnailUrl']);
$this->assertEquals('Task title', $result2Data['title']);
$this->assertEquals('subline', $result2Data['subline']);
$this->assertEquals('deep-link-to-tasks', $result2Data['resourceUrl']);
$this->assertEquals('icon-checkmark', $result2Data['iconClass']);
$this->assertEquals('icon-checkmark', $result2Data['icon']);
$this->assertFalse($result2Data['rounded']);
}

View File

@ -48,7 +48,6 @@ return array(
'OCA\\Files\\Migration\\Version11301Date20191205150729' => $baseDir . '/../lib/Migration/Version11301Date20191205150729.php',
'OCA\\Files\\Notification\\Notifier' => $baseDir . '/../lib/Notification/Notifier.php',
'OCA\\Files\\Search\\FilesSearchProvider' => $baseDir . '/../lib/Search/FilesSearchProvider.php',
'OCA\\Files\\Search\\FilesSearchResultEntry' => $baseDir . '/../lib/Search/FilesSearchResultEntry.php',
'OCA\\Files\\Service\\DirectEditingService' => $baseDir . '/../lib/Service/DirectEditingService.php',
'OCA\\Files\\Service\\OwnershipTransferService' => $baseDir . '/../lib/Service/OwnershipTransferService.php',
'OCA\\Files\\Service\\TagService' => $baseDir . '/../lib/Service/TagService.php',

View File

@ -63,7 +63,6 @@ class ComposerStaticInitFiles
'OCA\\Files\\Migration\\Version11301Date20191205150729' => __DIR__ . '/..' . '/../lib/Migration/Version11301Date20191205150729.php',
'OCA\\Files\\Notification\\Notifier' => __DIR__ . '/..' . '/../lib/Notification/Notifier.php',
'OCA\\Files\\Search\\FilesSearchProvider' => __DIR__ . '/..' . '/../lib/Search/FilesSearchProvider.php',
'OCA\\Files\\Search\\FilesSearchResultEntry' => __DIR__ . '/..' . '/../lib/Search/FilesSearchResultEntry.php',
'OCA\\Files\\Service\\DirectEditingService' => __DIR__ . '/..' . '/../lib/Service/DirectEditingService.php',
'OCA\\Files\\Service\\OwnershipTransferService' => __DIR__ . '/..' . '/../lib/Service/OwnershipTransferService.php',
'OCA\\Files\\Service\\TagService' => __DIR__ . '/..' . '/../lib/Service/TagService.php',

View File

@ -27,12 +27,14 @@ namespace OCA\Files\Search;
use OC\Search\Provider\File;
use OC\Search\Result\File as FileResult;
use OCP\Files\IMimeTypeDetector;
use OCP\IL10N;
use OCP\IURLGenerator;
use OCP\IUser;
use OCP\Search\IProvider;
use OCP\Search\ISearchQuery;
use OCP\Search\SearchResult;
use OCP\Search\SearchResultEntry;
class FilesSearchProvider implements IProvider {
@ -45,37 +47,58 @@ class FilesSearchProvider implements IProvider {
/** @var IURLGenerator */
private $urlGenerator;
/** @var IMimeTypeDetector */
private $mimeTypeDetector;
public function __construct(File $fileSearch,
IL10N $l10n,
IURLGenerator $urlGenerator) {
IURLGenerator $urlGenerator,
IMimeTypeDetector $mimeTypeDetector) {
$this->l10n = $l10n;
$this->fileSearch = $fileSearch;
$this->urlGenerator = $urlGenerator;
$this->mimeTypeDetector = $mimeTypeDetector;
}
/**
* @inheritDoc
*/
public function getId(): string {
return 'files';
}
/**
* @inheritDoc
*/
public function getName(): string {
return $this->l10n->t('Files');
}
/**
* @inheritDoc
*/
public function getOrder(): int {
return 5;
}
/**
* @inheritDoc
*/
public function search(IUser $user, ISearchQuery $query): SearchResult {
return SearchResult::complete(
$this->l10n->t('Files'),
array_map(function (FileResult $result) {
// Generate thumbnail url
$thumbnailUrl = $result->type === 'folder'
? ''
: $this->urlGenerator->linkToRoute('core.Preview.getPreviewByFileId', ['x' => 32, 'y' => 32, 'fileId' => $result->id]);
$thumbnailUrl = $result->has_preview
? $this->urlGenerator->linkToRoute('core.Preview.getPreviewByFileId', ['x' => 32, 'y' => 32, 'fileId' => $result->id])
: '';
return new FilesSearchResultEntry(
return new SearchResultEntry(
$thumbnailUrl,
$result->name,
$this->formatSubline($result),
$result->link,
$result->type === 'folder' ? 'icon-folder' : 'icon-filetype-file'
$result->type === 'folder' ? 'icon-folder' : $this->mimeTypeDetector->mimeTypeIcon($result->mime_type)
);
}, $this->fileSearch->search($query->getTerm()))
);

View File

@ -1,38 +0,0 @@
<?php
declare(strict_types=1);
/**
* @copyright 2020 Christoph Wurst <christoph@winzerhof-wurst.at>
*
* @author 2020 Christoph Wurst <christoph@winzerhof-wurst.at>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace OCA\Files\Search;
use OCP\Search\ASearchResultEntry;
class FilesSearchResultEntry extends ASearchResultEntry {
public function __construct(string $thumbnailUrl,
string $filename,
string $path,
string $url,
string $icon) {
parent::__construct($thumbnailUrl, $filename, $path, $url, $icon, false);
}
}

View File

@ -31,7 +31,6 @@ return array(
'OCA\\Settings\\Hooks' => $baseDir . '/../lib/Hooks.php',
'OCA\\Settings\\Mailer\\NewUserMailHelper' => $baseDir . '/../lib/Mailer/NewUserMailHelper.php',
'OCA\\Settings\\Middleware\\SubadminMiddleware' => $baseDir . '/../lib/Middleware/SubadminMiddleware.php',
'OCA\\Settings\\Search\\SectionResult' => $baseDir . '/../lib/Search/SectionResult.php',
'OCA\\Settings\\Search\\SectionSearch' => $baseDir . '/../lib/Search/SectionSearch.php',
'OCA\\Settings\\Sections\\Admin\\Additional' => $baseDir . '/../lib/Sections/Admin/Additional.php',
'OCA\\Settings\\Sections\\Admin\\Groupware' => $baseDir . '/../lib/Sections/Admin/Groupware.php',

View File

@ -46,7 +46,6 @@ class ComposerStaticInitSettings
'OCA\\Settings\\Hooks' => __DIR__ . '/..' . '/../lib/Hooks.php',
'OCA\\Settings\\Mailer\\NewUserMailHelper' => __DIR__ . '/..' . '/../lib/Mailer/NewUserMailHelper.php',
'OCA\\Settings\\Middleware\\SubadminMiddleware' => __DIR__ . '/..' . '/../lib/Middleware/SubadminMiddleware.php',
'OCA\\Settings\\Search\\SectionResult' => __DIR__ . '/..' . '/../lib/Search/SectionResult.php',
'OCA\\Settings\\Search\\SectionSearch' => __DIR__ . '/..' . '/../lib/Search/SectionSearch.php',
'OCA\\Settings\\Sections\\Admin\\Additional' => __DIR__ . '/..' . '/../lib/Sections/Admin/Additional.php',
'OCA\\Settings\\Sections\\Admin\\Groupware' => __DIR__ . '/..' . '/../lib/Sections/Admin/Groupware.php',

View File

@ -1,29 +0,0 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2020 Joas Schilling <coding@schilljs.com>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\Settings\Search;
use OCP\Search\ASearchResultEntry;
class SectionResult extends ASearchResultEntry {
}

View File

@ -30,7 +30,7 @@ use OCP\IUser;
use OCP\Search\IProvider;
use OCP\Search\ISearchQuery;
use OCP\Search\SearchResult;
use OCP\Settings\IIconSection;
use OCP\Search\SearchResultEntry;
use OCP\Settings\ISection;
use OCP\Settings\IManager;
@ -38,10 +38,13 @@ class SectionSearch implements IProvider {
/** @var IManager */
protected $settingsManager;
/** @var IGroupManager */
protected $groupManager;
/** @var IURLGenerator */
protected $urlGenerator;
/** @var IL10N */
protected $l;
@ -69,6 +72,13 @@ class SectionSearch implements IProvider {
return $this->l->t('Settings');
}
/**
* @inheritDoc
*/
public function getOrder(): int {
return 20;
}
/**
* @inheritDoc
*/
@ -115,16 +125,20 @@ class SectionSearch implements IProvider {
continue;
}
$iconUrl = '';
if ($section instanceof IIconSection) {
$iconUrl = $section->getIcon();
}
/**
* We can't use the icon URL at the moment as they don't invert correctly for dark theme
* $iconUrl = '';
* if ($section instanceof IIconSection) {
* $iconUrl = $section->getIcon();
* }
*/
$result[] = new SectionResult(
$iconUrl,
$result[] = new SearchResultEntry(
'',
$section->getName(),
$subline,
$this->urlGenerator->linkToRouteAbsolute($routeName, ['section' => $section->getID()])
$this->urlGenerator->linkToRouteAbsolute($routeName, ['section' => $section->getID()]),
'icon-settings'
);
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -2,22 +2,28 @@
<a :href="resourceUrl || '#'"
class="unified-search__result"
:class="{
'unified-search__result--focused': focused
'unified-search__result--focused': focused,
}"
@click="reEmitEvent"
@focus="reEmitEvent">
<!-- Icon describing the result -->
<div class="unified-search__result-icon"
:class="{
'unified-search__result-icon--rounded': rounded,
'unified-search__result-icon--no-preview': !hasValidThumbnail && !loaded,
'unified-search__result-icon--with-thumbnail': hasValidThumbnail && loaded,
[iconClass]: true
[icon]: !loaded && !isIconUrl,
}"
:style="{
backgroundImage: isIconUrl ? `url(${icon})` : '',
}"
role="img">
<img v-if="hasValidThumbnail"
v-show="loaded"
:src="thumbnailUrl"
:alt="t('core', 'Thumbnail for {result}', {result: title})"
alt=""
@error="onError"
@load="onLoad">
</div>
@ -59,7 +65,7 @@ export default {
type: String,
default: null,
},
iconClass: {
icon: {
type: String,
default: '',
},
@ -90,6 +96,24 @@ export default {
}
},
computed: {
isIconUrl() {
// If we're facing an absolute url
if (this.icon.startsWith('/')) {
return true
}
// Otherwise, let's check if this is a valid url
try {
// eslint-disable-next-line no-new
new URL(this.icon)
} catch {
return false
}
return true
},
},
watch: {
// Make sure to reset state on change even when vue recycle the component
thumbnailUrl() {
@ -148,6 +172,7 @@ $margin: 10px;
width: $clickable-area;
height: $clickable-area;
border-radius: var(--border-radius);
background-repeat: no-repeat;
background-position: center center;
background-size: 32px;
&--rounded {
@ -195,7 +220,7 @@ $margin: 10px;
&-line-two {
overflow: hidden;
flex: 1 1 100%;
margin: 0;
margin: 1px 0;
white-space: nowrap;
text-overflow: ellipsis;
// Use the same color as the `a`

View File

@ -0,0 +1,68 @@
<template>
<svg
class="unified-search__result-placeholder"
xmlns="http://www.w3.org/2000/svg"
fill="url(#unified-search__result-placeholder-gradient)">
<defs>
<linearGradient id="unified-search__result-placeholder-gradient">
<stop offset="0%" stop-color="#ededed"><animate attributeName="stop-color"
values="#ededed; #ededed; #cccccc; #cccccc; #ededed"
dur="2s"
repeatCount="indefinite" /></stop>
<stop offset="100%" stop-color="#cccccc"><animate attributeName="stop-color"
values="#cccccc; #ededed; #ededed; #cccccc; #cccccc"
dur="2s"
repeatCount="indefinite" /></stop>
</linearGradient>
</defs>
<rect class="unified-search__result-placeholder-icon" />
<rect class="unified-search__result-placeholder-line-one" />
<rect class="unified-search__result-placeholder-line-two" :style="{width: `calc(${randWidth}%)`}" />
</svg>
</template>
<script>
export default {
name: 'SearchResultPlaceholder',
data() {
return {
randWidth: Math.floor(Math.random() * 20) + 30,
}
},
}
</script>
<style lang="scss" scoped>
$clickable-area: 44px;
$margin: 10px;
.unified-search__result-placeholder {
width: calc(100% - 2 * #{$margin});
height: $clickable-area;
margin: $margin;
&-icon {
width: $clickable-area;
height: $clickable-area;
rx: var(--border-radius);
ry: var(--border-radius);
}
&-line-one,
&-line-two {
width: calc(100% - #{$margin + $clickable-area});
height: 1em;
x: $margin + $clickable-area;
}
&-line-one {
y: 5px;
}
&-line-two {
y: 25px;
}
}
</style>

View File

@ -24,15 +24,18 @@ import { loadState } from '@nextcloud/initial-state'
import axios from '@nextcloud/axios'
export const defaultLimit = loadState('unified-search', 'limit-default')
export const activeApp = loadState('core', 'active-app')
/**
* Get the list of available search providers
*
* @returns {Array}
*/
export async function getTypes() {
try {
const { data } = await axios.get(generateUrl('/search/providers'))
if (Array.isArray(data) && data.length > 0) {
return data
return sortProviders(data)
}
} catch (error) {
console.error(error)
@ -40,6 +43,29 @@ export async function getTypes() {
return []
}
/**
* Sort the providers by the current active app
*
* @param {Array} providers the providers list
* @returns {Array}
*/
export function sortProviders(providers) {
providers.sort((a, b) => {
if (a.id.startsWith(activeApp) && b.id.startsWith(activeApp)) {
return a.order - b.order
}
if (a.id.startsWith(activeApp)) {
return -1
}
if (b.id.startsWith(activeApp)) {
return 1
}
return 0
})
return providers
}
/**
* Get the list of available search providers
*

View File

@ -27,7 +27,7 @@
@close="onClose">
<!-- Header icon -->
<template #trigger>
<span class="icon-search-white" />
<Magnify class="unified-search__trigger" :size="20" fill-color="var(--color-primary-text)" />
</template>
<!-- Search input -->
@ -36,17 +36,20 @@
v-model="query"
class="unified-search__input"
type="search"
:placeholder="t('core', 'Search for {types} …', { types: typesNames.join(', ') })"
:placeholder="t('core', 'Search {types} …', { types: typesNames.join(', ').toLowerCase() })"
@input="onInputDebounced"
@keypress.enter.prevent.stop="onInputEnter">
</div>
<EmptyContent v-if="isLoading" icon="icon-loading">
{{ t('core', 'Searching …') }}
</EmptyContent>
<template v-if="!hasResults">
<!-- Loading placeholders -->
<ul v-if="isLoading">
<li v-for="placeholder in [1, 2, 3]" :key="placeholder">
<SearchResultPlaceholder />
</li>
</ul>
<template v-else-if="!hasResults">
<EmptyContent v-if="isValidQuery && isDoneSearching" icon="icon-search">
<EmptyContent v-else-if="isValidQuery && isDoneSearching" icon="icon-search">
{{ t('core', 'No results for {query}', {query}) }}
</EmptyContent>
@ -64,7 +67,7 @@
<!-- Grouped search results -->
<template v-else>
<ul v-for="(list, type, typesIndex) in results"
<ul v-for="(list, type, typesIndex) in orderedResults"
:key="type"
class="unified-search__results"
:class="`unified-search__results-${type}`"
@ -94,13 +97,14 @@
</template>
<script>
import { getTypes, search, defaultLimit } from '../services/UnifiedSearchService'
import { getTypes, search, defaultLimit, activeApp } from '../services/UnifiedSearchService'
import EmptyContent from '@nextcloud/vue/dist/Components/EmptyContent'
import Magnify from 'vue-material-design-icons/Magnify'
import debounce from 'debounce'
import HeaderMenu from '../components/HeaderMenu'
import SearchResult from '../components/UnifiedSearch/SearchResult'
import SearchResultPlaceholder from '../components/UnifiedSearch/SearchResultPlaceholder'
const minSearchLength = 2
@ -110,7 +114,9 @@ export default {
components: {
EmptyContent,
HeaderMenu,
Magnify,
SearchResult,
SearchResultPlaceholder,
},
data() {
@ -126,6 +132,7 @@ export default {
query: '',
focused: null,
activeApp,
defaultLimit,
minSearchLength,
@ -155,6 +162,32 @@ export default {
return Object.keys(this.results).length !== 0
},
/**
* Order results by putting the active app first
* @returns {Object}
*/
orderedResults() {
const ordered = {}
Object.keys(this.results)
.sort((a, b) => {
if (a.startsWith(activeApp) && b.startsWith(activeApp)) {
return this.typesMap[a].order - this.typesMap[b].order
}
if (a.startsWith(activeApp)) {
return -1
}
if (b.startsWith(activeApp)) {
return 1
}
return 0
})
.forEach(type => {
ordered[type] = this.results[type]
})
return ordered
},
/**
* Is the current search too short
* @returns {boolean}
@ -176,7 +209,7 @@ export default {
* @returns {boolean}
*/
isDoneSearching() {
return Object.values(this.reached).indexOf(false) === -1
return Object.values(this.reached).every(state => state === false)
},
/**
@ -184,7 +217,7 @@ export default {
* @returns {boolean}
*/
isLoading() {
return Object.values(this.loading).indexOf(true) !== -1
return Object.values(this.loading).some(state => state === true)
},
},
@ -465,6 +498,11 @@ $margin: 10px;
$input-padding: 6px;
.unified-search {
&__trigger {
width: 20px;
height: 20px;
}
&__input-wrapper {
position: sticky;
// above search results
@ -479,7 +517,14 @@ $input-padding: 6px;
height: 34px;
margin: $margin;
padding: $input-padding;
text-overflow: ellipsis;
&,
&[placeholder],
&::placeholder {
overflow: hidden;
text-overflow:ellipsis;
white-space: nowrap;
}
}
&__results {
@ -488,7 +533,7 @@ $input-padding: 6px;
margin: $margin;
margin-left: $margin + $input-padding;
content: attr(aria-label);
color: var(--color-primary);
color: var(--color-primary-element);
}
}

View File

@ -439,13 +439,13 @@ return array(
'OCP\\Route\\IRouter' => $baseDir . '/lib/public/Route/IRouter.php',
'OCP\\SabrePluginEvent' => $baseDir . '/lib/public/SabrePluginEvent.php',
'OCP\\SabrePluginException' => $baseDir . '/lib/public/SabrePluginException.php',
'OCP\\Search\\ASearchResultEntry' => $baseDir . '/lib/public/Search/ASearchResultEntry.php',
'OCP\\Search\\IProvider' => $baseDir . '/lib/public/Search/IProvider.php',
'OCP\\Search\\ISearchQuery' => $baseDir . '/lib/public/Search/ISearchQuery.php',
'OCP\\Search\\PagedProvider' => $baseDir . '/lib/public/Search/PagedProvider.php',
'OCP\\Search\\Provider' => $baseDir . '/lib/public/Search/Provider.php',
'OCP\\Search\\Result' => $baseDir . '/lib/public/Search/Result.php',
'OCP\\Search\\SearchResult' => $baseDir . '/lib/public/Search/SearchResult.php',
'OCP\\Search\\SearchResultEntry' => $baseDir . '/lib/public/Search/SearchResultEntry.php',
'OCP\\Security\\CSP\\AddContentSecurityPolicyEvent' => $baseDir . '/lib/public/Security/CSP/AddContentSecurityPolicyEvent.php',
'OCP\\Security\\Events\\GenerateSecurePasswordEvent' => $baseDir . '/lib/public/Security/Events/GenerateSecurePasswordEvent.php',
'OCP\\Security\\Events\\ValidatePasswordPolicyEvent' => $baseDir . '/lib/public/Security/Events/ValidatePasswordPolicyEvent.php',

View File

@ -468,13 +468,13 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
'OCP\\Route\\IRouter' => __DIR__ . '/../../..' . '/lib/public/Route/IRouter.php',
'OCP\\SabrePluginEvent' => __DIR__ . '/../../..' . '/lib/public/SabrePluginEvent.php',
'OCP\\SabrePluginException' => __DIR__ . '/../../..' . '/lib/public/SabrePluginException.php',
'OCP\\Search\\ASearchResultEntry' => __DIR__ . '/../../..' . '/lib/public/Search/ASearchResultEntry.php',
'OCP\\Search\\IProvider' => __DIR__ . '/../../..' . '/lib/public/Search/IProvider.php',
'OCP\\Search\\ISearchQuery' => __DIR__ . '/../../..' . '/lib/public/Search/ISearchQuery.php',
'OCP\\Search\\PagedProvider' => __DIR__ . '/../../..' . '/lib/public/Search/PagedProvider.php',
'OCP\\Search\\Provider' => __DIR__ . '/../../..' . '/lib/public/Search/Provider.php',
'OCP\\Search\\Result' => __DIR__ . '/../../..' . '/lib/public/Search/Result.php',
'OCP\\Search\\SearchResult' => __DIR__ . '/../../..' . '/lib/public/Search/SearchResult.php',
'OCP\\Search\\SearchResultEntry' => __DIR__ . '/../../..' . '/lib/public/Search/SearchResultEntry.php',
'OCP\\Security\\CSP\\AddContentSecurityPolicyEvent' => __DIR__ . '/../../..' . '/lib/public/Security/CSP/AddContentSecurityPolicyEvent.php',
'OCP\\Security\\Events\\GenerateSecurePasswordEvent' => __DIR__ . '/../../..' . '/lib/public/Security/Events/GenerateSecurePasswordEvent.php',
'OCP\\Security\\Events\\ValidatePasswordPolicyEvent' => __DIR__ . '/../../..' . '/lib/public/Security/Events/ValidatePasswordPolicyEvent.php',

View File

@ -79,12 +79,7 @@ class NavigationManager implements INavigationManager {
}
/**
* Creates a new navigation entry
*
* @param array|\Closure $entry Array containing: id, name, order, icon and href key
* The use of a closure is preferred, because it will avoid
* loading the routing of your app, unless required.
* @return void
* @inheritDoc
*/
public function add($entry) {
if ($entry instanceof \Closure) {
@ -106,10 +101,7 @@ class NavigationManager implements INavigationManager {
}
/**
* Get a list of navigation entries
*
* @param string $type type of the navigation entries
* @return array
* @inheritDoc
*/
public function getAll(string $type = 'link'): array {
$this->init();
@ -171,19 +163,14 @@ class NavigationManager implements INavigationManager {
}
/**
* Sets the current navigation entry of the currently running app
* @param string $id of the app entry to activate (from added $entry)
* @inheritDoc
*/
public function setActiveEntry($id) {
$this->activeEntry = $id;
}
/**
* gets the active Menu entry
* @return string id or empty string
*
* This function returns the id of the active navigation entry (set by
* setActiveEntry
* @inheritDoc
*/
public function getActiveEntry() {
return $this->activeEntry;

View File

@ -39,7 +39,7 @@ class File extends \OCP\Search\Provider {
/**
* Search for files and folders matching the given query
* @param string $query
* @return \OCP\Search\Result
* @return \OCP\Search\Result[]
* @deprecated 20.0.0
*/
public function search($query) {

View File

@ -28,6 +28,8 @@ namespace OC\Search\Result;
use OCP\Files\FileInfo;
use OCP\Files\Folder;
use OCP\IPreview;
use OCP\IUserSession;
/**
* A found file
@ -78,6 +80,14 @@ class File extends \OCP\Search\Result {
*/
public $permissions;
/**
* Has a preview
*
* @var string
* @deprecated 20.0.0
*/
public $has_preview;
/**
* Create a new file search result
* @param FileInfo $data file data given by provider
@ -101,6 +111,7 @@ class File extends \OCP\Search\Result {
$this->size = $data->getSize();
$this->modified = $data->getMtime();
$this->mime_type = $data->getMimetype();
$this->has_preview = $this->hasPreview($data);
}
/**
@ -118,9 +129,21 @@ class File extends \OCP\Search\Result {
*/
protected function getRelativePath($path) {
if (!isset(self::$userFolderCache)) {
$user = \OC::$server->getUserSession()->getUser()->getUID();
self::$userFolderCache = \OC::$server->getUserFolder($user);
$userSession = \OC::$server->get(IUserSession::class);
$userID = $userSession->getUser()->getUID();
self::$userFolderCache = \OC::$server->getUserFolder($userID);
}
return self::$userFolderCache->getRelativePath($path);
}
/**
* Is the preview available
* @param FileInfo $data
* @return bool
* @deprecated 20.0.0
*/
protected function hasPreview($data) {
$previewManager = \OC::$server->get(IPreview::class);
return $previewManager->isAvailable($data);
}
}

View File

@ -107,22 +107,31 @@ class SearchComposer {
/**
* Get a list of all provider IDs & Names for the consecutive calls to `search`
* Sort the list by the order property
*
* @return array
*/
public function getProviders(): array {
$this->loadLazyProviders();
/**
* Return an array with the IDs, but strip the associative keys
*/
return array_values(
$providers = array_values(
array_map(function (IProvider $provider) {
return [
'id' => $provider->getId(),
'name' => $provider->getName()
'name' => $provider->getName(),
'order' => $provider->getOrder()
];
}, $this->providers));
}, $this->providers)
);
usort($providers, function ($provider1, $provider2) {
return $provider1['order'] <=> $provider2['order'];
});
/**
* Return an array with the IDs, but strip the associative keys
*/
return $providers;
}
/**

View File

@ -52,6 +52,7 @@ use OCP\AppFramework\Http\TemplateResponse;
use OCP\Defaults;
use OCP\IConfig;
use OCP\IInitialStateService;
use OCP\INavigationManager;
use OCP\Support\Subscription\IRegistry;
use OCP\Util;
@ -64,6 +65,9 @@ class TemplateLayout extends \OC_Template {
/** @var IInitialStateService */
private $initialState;
/** @var INavigationManager */
private $navigationManager;
/**
* @param string $renderAs
* @param string $appId application id
@ -74,7 +78,7 @@ class TemplateLayout extends \OC_Template {
$this->config = \OC::$server->get(IConfig::class);
/** @var IInitialStateService */
$this->initialState = \OC::$server->get(InitialStateService::class);
$this->initialState = \OC::$server->get(IInitialStateService::class);
if (Util::isIE()) {
Util::addStyle('ie');
@ -82,6 +86,9 @@ class TemplateLayout extends \OC_Template {
// Decide which page we show
if ($renderAs === TemplateResponse::RENDER_AS_USER) {
/** @var INavigationManager */
$this->navigationManager = \OC::$server->get(INavigationManager::class);
parent::__construct('core', 'layout.user');
if (in_array(\OC_App::getCurrentApp(), ['settings','admin', 'help']) !== false) {
$this->assign('bodyid', 'body-settings');
@ -89,16 +96,19 @@ class TemplateLayout extends \OC_Template {
$this->assign('bodyid', 'body-user');
}
$this->initialState->provideInitialState('core', 'active-app', $this->navigationManager->getActiveEntry());
$this->initialState->provideInitialState('unified-search', 'limit-default', SearchQuery::LIMIT_DEFAULT);
Util::addScript('dist/unified-search', null, true);
// Add navigation entry
$this->assign('application', '');
$this->assign('appid', $appId);
$navigation = \OC::$server->getNavigationManager()->getAll();
$navigation = $this->navigationManager->getAll();
$this->assign('navigation', $navigation);
$settingsNavigation = \OC::$server->getNavigationManager()->getAll('settings');
$settingsNavigation = $this->navigationManager->getAll('settings');
$this->assign('settingsnavigation', $settingsNavigation);
foreach ($navigation as $entry) {
if ($entry['active']) {
$this->assign('application', $entry['name']);

View File

@ -81,6 +81,13 @@ interface INavigationManager {
*/
public function setActiveEntry($appId);
/**
* Get the current navigation entry of the currently running app
* @return string
* @since 20.0.0
*/
public function getActiveEntry();
/**
* Get a list of navigation entries
*

View File

@ -64,6 +64,16 @@ interface IProvider {
*/
public function getName(): string;
/**
* Get the search provider order
* The lower the int, the higher it will be sorted (0 will be before 10)
*
* @return int
*
* @since 20.0.0
*/
public function getOrder(): int;
/**
* Find matching search entries in an app
*

View File

@ -38,7 +38,7 @@ final class SearchResult implements JsonSerializable {
/** @var bool */
private $isPaginated;
/** @var ASearchResultEntry[] */
/** @var SearchResultEntry[] */
private $entries;
/** @var int|string|null */
@ -47,7 +47,7 @@ final class SearchResult implements JsonSerializable {
/**
* @param string $name the translated name of the result section or group, e.g. "Mail"
* @param bool $isPaginated
* @param ASearchResultEntry[] $entries
* @param SearchResultEntry[] $entries
* @param null $cursor
*
* @since 20.0.0
@ -63,7 +63,7 @@ final class SearchResult implements JsonSerializable {
}
/**
* @param ASearchResultEntry[] $entries
* @param SearchResultEntry[] $entries
*
* @return static
*
@ -78,7 +78,7 @@ final class SearchResult implements JsonSerializable {
}
/**
* @param ASearchResultEntry[] $entries
* @param SearchResultEntry[] $entries
* @param int|string $cursor
*
* @return static

View File

@ -34,7 +34,7 @@ use JsonSerializable;
* The app providing the results has to extend this class for customization. In
* most cases apps do not have to add any additional code.
*
* @example ``class MailResultEntry extends ASearchResultEntry {}`
* @example ``class MailResultEntry extends SearchResultEntry {}`
*
* This approach was chosen over a final class as it allows Nextcloud to later
* add new optional properties of an entry without having to break the usage of
@ -42,7 +42,7 @@ use JsonSerializable;
*
* @since 20.0.0
*/
abstract class ASearchResultEntry implements JsonSerializable {
class SearchResultEntry implements JsonSerializable {
/**
* @var string
@ -72,7 +72,7 @@ abstract class ASearchResultEntry implements JsonSerializable {
* @var string
* @since 20.0.0
*/
protected $iconClass;
protected $icon;
/**
* @var boolean
@ -85,7 +85,7 @@ abstract class ASearchResultEntry implements JsonSerializable {
* @param string $title a main title of the entry
* @param string $subline the secondary line of the entry
* @param string $resourceUrl the URL where the user can find the detail, like a deep link inside the app
* @param string $iconClass the icon class fallback
* @param string $icon the icon class or url to the icon
* @param boolean $rounded is the thumbnail rounded
*
* @since 20.0.0
@ -94,13 +94,13 @@ abstract class ASearchResultEntry implements JsonSerializable {
string $title,
string $subline,
string $resourceUrl,
string $iconClass = '',
string $icon = '',
bool $rounded = false) {
$this->thumbnailUrl = $thumbnailUrl;
$this->title = $title;
$this->subline = $subline;
$this->resourceUrl = $resourceUrl;
$this->iconClass = $iconClass;
$this->icon = $icon;
$this->rounded = $rounded;
}
@ -115,7 +115,7 @@ abstract class ASearchResultEntry implements JsonSerializable {
'title' => $this->title,
'subline' => $this->subline,
'resourceUrl' => $this->resourceUrl,
'iconClass' => $this->iconClass,
'icon' => $this->icon,
'rounded' => $this->rounded,
];
}

5
package-lock.json generated
View File

@ -9888,6 +9888,11 @@
"resolved": "https://registry.npmjs.org/vue-localstorage/-/vue-localstorage-0.6.2.tgz",
"integrity": "sha512-29YQVVkIdoS6BZBCJAyu9d0OR0eKSm5gk5OjsLssV1+NM4zJnf9cxhN1AVeXkUHJLqOonECweuaR8PZ2x307dw=="
},
"vue-material-design-icons": {
"version": "4.8.0",
"resolved": "https://registry.npmjs.org/vue-material-design-icons/-/vue-material-design-icons-4.8.0.tgz",
"integrity": "sha512-NNbwK/a14mk92ofBvJa6oBdWi+SO2f27pimoCWziirrbN5Nmt9q0pzELOfvqyy0ncoMJ2BLkd8KfQuXIAhL3Fw=="
},
"vue-multiselect": {
"version": "2.1.6",
"resolved": "https://registry.npmjs.org/vue-multiselect/-/vue-multiselect-2.1.6.tgz",

View File

@ -79,6 +79,7 @@
"vue-clipboard2": "^0.3.1",
"vue-infinite-loading": "^2.4.5",
"vue-localstorage": "^0.6.2",
"vue-material-design-icons": "^4.8.0",
"vue-multiselect": "^2.1.6",
"vue-router": "^3.3.4",
"vuex": "^3.5.1",

View File

@ -81,7 +81,9 @@ module.exports = []
{
test: /\.vue$/,
loader: 'vue-loader',
exclude: /node_modules/,
exclude: BabelLoaderExcludeNodeModulesExcept([
'vue-material-design-icons',
]),
},
{
test: /\.js$/,