Skip to content

Commit 9f120d4

Browse files
committed
Fix unified search
Signed-off-by: John Molakvoæ (skjnldsv) <[email protected]>
1 parent 4987fe9 commit 9f120d4

21 files changed

+656
-64
lines changed

apps/comments/lib/Search/Provider.php

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
use OCP\IL10N;
2929
use OCP\IURLGenerator;
3030
use OCP\IUser;
31+
use OCP\IUserManager;
3132
use OCP\Search\IProvider;
3233
use OCP\Search\ISearchQuery;
3334
use OCP\Search\SearchResult;
@@ -36,6 +37,9 @@
3637

3738
class Provider implements IProvider {
3839

40+
/** @var IUserManager */
41+
private $userManager;
42+
3943
/** @var IL10N */
4044
private $l10n;
4145

@@ -45,9 +49,11 @@ class Provider implements IProvider {
4549
/** @var LegacyProvider */
4650
private $legacyProvider;
4751

48-
public function __construct(IL10N $l10n,
52+
public function __construct(IUserManager $userManager,
53+
IL10N $l10n,
4954
IURLGenerator $urlGenerator,
5055
LegacyProvider $legacyProvider) {
56+
$this->userManager = $userManager;
5157
$this->l10n = $l10n;
5258
$this->urlGenerator = $urlGenerator;
5359
$this->legacyProvider = $legacyProvider;
@@ -57,23 +63,30 @@ public function getId(): string {
5763
return 'comments';
5864
}
5965

66+
public function getName(): string {
67+
return $this->l10n->t('Comments');
68+
}
69+
6070
public function search(IUser $user, ISearchQuery $query): SearchResult {
6171
return SearchResult::complete(
6272
$this->l10n->t('Comments'),
6373
array_map(function (Result $result) {
6474
$path = $result->path;
6575
$pathInfo = pathinfo($path);
76+
$isUser = $this->userManager->userExists($result->authorId);
77+
$avatarUrl = $isUser
78+
? $this->urlGenerator->linkToRoute('core.avatar.getAvatar', ['userId' => $result->authorId, 'size' => 42])
79+
: $this->urlGenerator->linkToRoute('core.GuestAvatar.getAvatar', ['guestName' => $result->authorId, 'size' => 42]);
6680
return new CommentsSearchResultEntry(
67-
$this->urlGenerator->linkToRoute('core.Preview.getPreviewByFileId', ['x' => 32, 'y' => 32, 'fileId' => $result->id]),
81+
$avatarUrl,
6882
$result->name,
6983
$path,
70-
$this->urlGenerator->linkToRoute(
71-
'files.view.index',
72-
[
73-
'dir' => $pathInfo['dirname'],
74-
'scrollto' => $pathInfo['basename'],
75-
]
76-
)
84+
$this->urlGenerator->linkToRoute('files.view.index',[
85+
'dir' => $pathInfo['dirname'],
86+
'scrollto' => $pathInfo['basename'],
87+
]),
88+
'',
89+
true
7790
);
7891
}, $this->legacyProvider->search($query->getTerm()))
7992
);

apps/files/lib/Search/FilesSearchProvider.php

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,17 +57,43 @@ public function getId(): string {
5757
return 'files';
5858
}
5959

60+
public function getName(): string {
61+
return $this->l10n->t('Files');
62+
}
63+
6064
public function search(IUser $user, ISearchQuery $query): SearchResult {
6165
return SearchResult::complete(
6266
$this->l10n->t('Files'),
6367
array_map(function (FileResult $result) {
68+
// Generate thumbnail url
69+
$thumbnailUrl = $result->type === 'folder'
70+
? ''
71+
: $this->urlGenerator->linkToRoute('core.Preview.getPreviewByFileId', ['x' => 32, 'y' => 32, 'fileId' => $result->id]);
72+
6473
return new FilesSearchResultEntry(
65-
$this->urlGenerator->linkToRoute('core.Preview.getPreviewByFileId', ['x' => 32, 'y' => 32, 'fileId' => $result->id]),
74+
$thumbnailUrl,
6675
$result->name,
67-
$result->path,
68-
$result->link
76+
$this->formatSubline($result),
77+
$result->link,
78+
$result->type === 'folder' ? 'icon-folder' : 'icon-filetype-file'
6979
);
7080
}, $this->fileSearch->search($query->getTerm()))
7181
);
7282
}
83+
84+
/**
85+
* Format subline for files
86+
*
87+
* @param FileResult $result
88+
* @return string
89+
*/
90+
private function formatSubline($result): string {
91+
// Do not show the location if the file is in root
92+
if ($result->path === '/' . $result->name) {
93+
return '';
94+
}
95+
96+
$path = ltrim(dirname($result->path), '/');
97+
return $this->l10n->t('in %s', [$path]);
98+
}
7399
}

apps/files/lib/Search/FilesSearchResultEntry.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ class FilesSearchResultEntry extends ASearchResultEntry {
3131
public function __construct(string $thumbnailUrl,
3232
string $filename,
3333
string $path,
34-
string $url) {
35-
parent::__construct($thumbnailUrl, $filename, $path, $url);
34+
string $url,
35+
string $icon) {
36+
parent::__construct($thumbnailUrl, $filename, $path, $url, $icon, false);
3637
}
3738
}

core/Controller/UnifiedSearchController.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ public function search(string $providerId,
7878
?int $sortOrder = null,
7979
?int $limit = null,
8080
$cursor = null): JSONResponse {
81-
if (empty($term)) {
81+
if (empty(trim($term))) {
8282
return new JSONResponse(null, Http::STATUS_BAD_REQUEST);
8383
}
8484

core/css/css-variables.scss

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,6 @@
4646

4747
--animation-quick: $animation-quick;
4848
--animation-slow: $animation-slow;
49+
50+
--header-height: $header-height;
4951
}

core/css/icons.scss

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -384,20 +384,20 @@ audio, canvas, embed, iframe, img, input, object, video {
384384

385385
.icon-file,
386386
.icon-filetype-text {
387-
@include icon-color('text', 'filetypes', $color-black, 1, true);
387+
@include icon-color('text', 'filetypes', #969696, 1, true);
388388
}
389389

390390
.icon-filetype-file {
391-
@include icon-color('file', 'filetypes', $color-black, 1, true);
391+
@include icon-color('file', 'filetypes', #969696, 1, true);
392392
}
393393

394394
@include icon-black-white('folder', 'filetypes', 1, true);
395395
.icon-filetype-folder {
396-
@include icon-color('folder', 'filetypes', $color-black, 1, true);
396+
@include icon-color('folder', 'filetypes', $color-primary, 1, true);
397397
}
398398

399399
.icon-filetype-folder-drag-accept {
400-
@include icon-color('folder-drag-accept', 'filetypes', $color-black, 1, true);
400+
@include icon-color('folder-drag-accept', 'filetypes', $color-primary, 1, true);
401401
}
402402

403403

core/src/components/HeaderMenu.vue

Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
<!--
2+
- @copyright Copyright (c) 2020 John Molakvoæ <[email protected]>
3+
-
4+
- @author John Molakvoæ <[email protected]>
5+
-
6+
- @license GNU AGPL version 3 or any later version
7+
-
8+
- This program is free software: you can redistribute it and/or modify
9+
- it under the terms of the GNU Affero General Public License as
10+
- published by the Free Software Foundation, either version 3 of the
11+
- License, or (at your option) any later version.
12+
-
13+
- This program is distributed in the hope that it will be useful,
14+
- but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16+
- GNU Affero General Public License for more details.
17+
-
18+
- You should have received a copy of the GNU Affero General Public License
19+
- along with this program. If not, see <http://www.gnu.org/licenses/>.
20+
-
21+
-->
22+
<template>
23+
<div v-click-outside="closeMenu" :class="{ 'header-menu--opened': opened }" class="header-menu">
24+
<a class="header-menu__trigger"
25+
href="#"
26+
:aria-controls="`header-menu-${id}`"
27+
:aria-expanded="opened"
28+
aria-haspopup="true"
29+
@click.prevent="toggleMenu">
30+
<slot name="trigger" />
31+
</a>
32+
<div v-if="opened"
33+
:id="`header-menu-${id}`"
34+
class="header-menu__wrapper"
35+
role="menu">
36+
<div class="header-menu__carret" />
37+
<div class="header-menu__content">
38+
<slot />
39+
</div>
40+
</div>
41+
</div>
42+
</template>
43+
44+
<script>
45+
import { directive as ClickOutside } from 'v-click-outside'
46+
import { emit, subscribe, unsubscribe } from '@nextcloud/event-bus'
47+
48+
export default {
49+
name: 'HeaderMenu',
50+
51+
directives: {
52+
ClickOutside,
53+
},
54+
55+
props: {
56+
id: {
57+
type: String,
58+
required: true,
59+
},
60+
open: {
61+
type: Boolean,
62+
default: false,
63+
},
64+
},
65+
66+
data() {
67+
return {
68+
opened: this.open,
69+
}
70+
},
71+
72+
watch: {
73+
open(newVal) {
74+
this.opened = newVal
75+
this.$nextTick(() => {
76+
if (this.opened) {
77+
this.openMenu()
78+
} else {
79+
this.closeMenu()
80+
}
81+
})
82+
},
83+
},
84+
85+
mounted() {
86+
document.addEventListener('keydown', this.onKeyDown)
87+
},
88+
89+
beforeMount() {
90+
subscribe(`header-menu-${this.id}-close`, this.closeMenu)
91+
subscribe(`header-menu-${this.id}-open`, this.openMenu)
92+
},
93+
94+
beforeDestroy() {
95+
unsubscribe(`header-menu-${this.id}-close`, this.closeMenu)
96+
unsubscribe(`header-menu-${this.id}-open`, this.openMenu)
97+
},
98+
99+
methods: {
100+
/**
101+
* Toggle the current menu open state
102+
*/
103+
toggleMenu() {
104+
// Toggling current state
105+
if (!this.opened) {
106+
this.openMenu()
107+
} else {
108+
this.closeMenu()
109+
}
110+
},
111+
112+
/**
113+
* Close the current menu
114+
*/
115+
closeMenu() {
116+
if (!this.opened) {
117+
return
118+
}
119+
120+
this.opened = false
121+
this.$emit('close')
122+
this.$emit('update:open', false)
123+
emit(`header-menu-${this.id}-close`)
124+
},
125+
126+
/**
127+
* Open the current menu
128+
*/
129+
openMenu() {
130+
if (this.opened) {
131+
return
132+
}
133+
134+
this.opened = true
135+
this.$emit('open')
136+
this.$emit('update:open', true)
137+
emit(`header-menu-${this.id}-open`)
138+
},
139+
140+
onKeyDown(event) {
141+
// If opened and escape pressed, close
142+
if (event.key === 'Escape' && this.opened) {
143+
event.preventDefault()
144+
this.closeMenu()
145+
}
146+
},
147+
},
148+
}
149+
</script>
150+
151+
<style lang="scss" scoped>
152+
.header-menu {
153+
&__trigger {
154+
display: flex;
155+
align-items: center;
156+
justify-content: center;
157+
width: 50px;
158+
height: 100%;
159+
margin: 0;
160+
padding: 0;
161+
cursor: pointer;
162+
opacity: .6;
163+
}
164+
165+
&--opened &__trigger,
166+
&__trigger:hover,
167+
&__trigger:focus,
168+
&__trigger:active {
169+
opacity: 1;
170+
}
171+
172+
&__wrapper {
173+
position: absolute;
174+
z-index: 2000;
175+
top: 50px;
176+
right: 5px;
177+
box-sizing: border-box;
178+
margin: 0;
179+
border-radius: 0 0 var(--border-radius) var(--border-radius);
180+
background-color: var(--color-main-background);
181+
182+
filter: drop-shadow(0 1px 5px var(--color-box-shadow));
183+
}
184+
185+
&__carret {
186+
position: absolute;
187+
right: 10px;
188+
bottom: 100%;
189+
width: 0;
190+
height: 0;
191+
content: ' ';
192+
pointer-events: none;
193+
border: 10px solid transparent;
194+
border-bottom-color: var(--color-main-background);
195+
}
196+
197+
&__content {
198+
overflow: auto;
199+
width: 350px;
200+
max-width: 350px;
201+
min-height: calc(44px * 1.5);
202+
max-height: calc(100vh - 50px * 2);
203+
}
204+
}
205+
206+
</style>

0 commit comments

Comments
 (0)