Skip to content

Commit 30a4fb8

Browse files
committed
fixup! fixup! feat(files): add Home view
Signed-off-by: skjnldsv <[email protected]>
1 parent 3664761 commit 30a4fb8

15 files changed

+293
-141
lines changed

apps/files/src/actions/openInFilesAction.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,21 @@
33
* SPDX-License-Identifier: AGPL-3.0-or-later
44
*/
55

6-
import type { Node } from '@nextcloud/files'
6+
import type { Node, View } from '@nextcloud/files'
77

88
import { t } from '@nextcloud/l10n'
99
import { FileType, FileAction, DefaultType } from '@nextcloud/files'
10+
import { VIEW_ID as HOME_VIEW_ID } from '../views/home'
11+
import { VIEW_ID as RECENT_VIEW_ID } from '../views/recent'
1012
import { VIEW_ID as SEARCH_VIEW_ID } from '../views/search'
1113

1214
export const action = new FileAction({
1315
id: 'open-in-files',
1416
displayName: () => t('files', 'Open in Files'),
1517
iconSvgInline: () => '',
1618

17-
enabled: (nodes, view: View) => [
18-
'home',
19-
'recent',
19+
enabled: (nodes: Node[], view: View) => [
20+
RECENT_VIEW_ID,
2021
SEARCH_VIEW_ID,
2122
].includes(view.id),
2223

apps/files/src/components/FilesListVirtual.vue

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,11 @@
4848
:nodes="nodes" />
4949
</template>
5050

51+
<!-- Body replacement if no files are available -->
52+
<template #empty>
53+
<slot name="empty" />
54+
</template>
55+
5156
<!-- Tfoot-->
5257
<template #footer>
5358
<FilesListTableFooter :current-view="currentView"
@@ -474,6 +479,8 @@ export default defineComponent({
474479
--icon-preview-size: 32px;
475480
476481
--fixed-block-start-position: var(--default-clickable-area);
482+
display: flex;
483+
flex-direction: column;
477484
overflow: auto;
478485
height: 100%;
479486
will-change: scroll-position;
@@ -570,6 +577,16 @@ export default defineComponent({
570577
top: var(--fixed-block-start-position);
571578
}
572579
580+
// Empty content
581+
.files-list__empty {
582+
display: flex;
583+
flex-direction: column;
584+
align-items: center;
585+
justify-content: center;
586+
width: 100%;
587+
height: 100%;
588+
}
589+
573590
tr {
574591
position: relative;
575592
display: flex;

apps/files/src/components/FilesNavigationItem.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ export default defineComponent({
104104
105105
methods: {
106106
filterVisible(views: View[]) {
107-
return views.filter(({ _view, id }) => id === this.currentView?.id || _view.hidden !== true)
107+
return views.filter(({ hidden, id }) => id === this.currentView?.id || hidden !== true)
108108
},
109109
110110
hasChildViews(view: View): boolean {

apps/files/src/components/FilesNavigationSearch.vue

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ onBeforeNavigation((to, from, next) => {
5353
* Are we currently on the search view.
5454
* Needed to disable the action menu (we cannot change the search mode there)
5555
*/
56-
const isSearchView = computed(() => currentView.value.id === VIEW_ID)
56+
const isSearchView = computed(() => currentView.value?.id === VIEW_ID)
5757
5858
/**
5959
* Local search is only possible on real DAV resources within the files root
@@ -63,7 +63,7 @@ const canSearchLocally = computed(() => {
6363
return true
6464
}
6565
66-
const folder = filesStore.getDirectoryByPath(currentView.value.id, directory.value)
66+
const folder = filesStore.getDirectoryByPath(currentView.value?.id, directory.value)
6767
return folder?.isDavResource && folder?.root?.startsWith('/files/')
6868
})
6969
@@ -84,7 +84,7 @@ const searchLabel = computed(() => {
8484
* @param value - The new value
8585
*/
8686
function onUpdateSearch(value: string) {
87-
if (searchStore.scope === 'locally' && currentView.value.id !== VIEW_ID) {
87+
if (searchStore.scope === 'locally' && currentView.value?.id !== VIEW_ID) {
8888
searchStore.base = filesStore.getDirectoryByPath(currentView.value.id, directory.value)
8989
}
9090
searchStore.query = value

apps/files/src/components/VirtualList.vue

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,14 @@
2020
<slot name="header-overlay" />
2121
</div>
2222

23-
<table class="files-list__table" :class="{ 'files-list__table--with-thead-overlay': !!$scopedSlots['header-overlay'] }">
23+
<div v-if="dataSources.length === 0"
24+
class="files-list__empty">
25+
<slot name="empty" />
26+
</div>
27+
28+
<table v-else
29+
class="files-list__table"
30+
:class="{ 'files-list__table--with-thead-overlay': !!$scopedSlots['header-overlay'] }">
2431
<!-- Accessibility table caption for screen readers -->
2532
<caption v-if="caption" class="hidden-visually">
2633
{{ caption }}
@@ -62,6 +69,7 @@ import debounce from 'debounce'
6269
6370
import { useFileListWidth } from '../composables/useFileListWidth.ts'
6471
import logger from '../logger.ts'
72+
import { data } from 'jquery'
6573
6674
interface RecycledPoolItem {
6775
key: string,

apps/files/src/services/RecommendedFiles.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ const isRecommendationEnabled = getCapabilities()?.recommendations?.enabled ===
2020
if (isRecommendationEnabled) {
2121
registerDavProperty('nc:recommendation-reason', { nc: 'http://nextcloud.org/ns' })
2222
registerDavProperty('nc:recommendation-reason-label', { nc: 'http://nextcloud.org/ns' })
23+
registerDavProperty('nc:recommendation-original-location', { nc: 'http://nextcloud.org/ns' })
2324
}
2425

2526
export const getContents = (): CancelablePromise<ContentsWithRoot> => {
@@ -54,7 +55,9 @@ export const getContents = (): CancelablePromise<ContentsWithRoot> => {
5455
}),
5556
contents: contents.map((result) => {
5657
try {
57-
return resultToNode(result, root)
58+
// Force the sources to be in the user's root context
59+
result.filename = `/files/${getCurrentUser()?.uid}` + result?.props?.['recommendation-original-location']
60+
return resultToNode(result, `/files/${getCurrentUser()?.uid}`)
5861
} catch (error) {
5962
logger.error(`Invalid node detected '${result.basename}'`, { error })
6063
return null

apps/files/src/services/Search.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import { getPinia } from '../store/index.ts'
1717
/**
1818
* Get the contents for a search view
1919
*/
20-
export function getContents(): CancelablePromise<ContentsWithRoot> {
20+
export function getContents(query = ''): CancelablePromise<ContentsWithRoot> {
2121
const controller = new AbortController()
2222

2323
const searchStore = useSearchStore(getPinia())
@@ -26,7 +26,7 @@ export function getContents(): CancelablePromise<ContentsWithRoot> {
2626
return new CancelablePromise<ContentsWithRoot>(async (resolve, reject, cancel) => {
2727
cancel(() => controller.abort())
2828
try {
29-
const contents = await searchNodes(searchStore.query, { dir, signal: controller.signal })
29+
const contents = await searchNodes(query || searchStore.query, { dir, signal: controller.signal })
3030
resolve({
3131
contents,
3232
folder: new Folder({
@@ -37,6 +37,12 @@ export function getContents(): CancelablePromise<ContentsWithRoot> {
3737
}),
3838
})
3939
} catch (error) {
40+
// Be silent if the request was canceled
41+
if (error?.name === 'AbortError') {
42+
logger.debug('Search request was canceled', { query, dir })
43+
reject(error)
44+
return
45+
}
4046
logger.error('Failed to fetch search results', { error })
4147
reject(error)
4248
}

apps/files/src/services/WebDavSearch.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* SPDX-License-Identifier: AGPL-3.0-or-later
44
*/
55

6-
import type { INode } from '@nextcloud/files'
6+
import type { Node } from '@nextcloud/files'
77
import type { ResponseDataDetailed, SearchResult } from 'webdav'
88

99
import { getCurrentUser } from '@nextcloud/auth'
@@ -17,6 +17,8 @@ export interface SearchNodesOptions {
1717
signal?: AbortSignal
1818
}
1919

20+
export const MIN_SEARCH_LENGTH = 3
21+
2022
/**
2123
* Search for nodes matching the given query.
2224
*
@@ -25,16 +27,18 @@ export interface SearchNodesOptions {
2527
* @param options.dir - The base directory to scope the search to
2628
* @param options.signal - Abort signal for the request
2729
*/
28-
export async function searchNodes(query: string, { dir, signal }: SearchNodesOptions): Promise<INode[]> {
30+
export async function searchNodes(query: string, { dir, signal }: SearchNodesOptions): Promise<Node[]> {
2931
const user = getCurrentUser()
3032
if (!user) {
3133
// the search plugin only works for user roots
34+
logger.debug('No user found for search', { query, dir })
3235
return []
3336
}
3437

3538
query = query.trim()
36-
if (query.length < 3) {
39+
if (query.length < MIN_SEARCH_LENGTH) {
3740
// the search plugin only works with queries of at least 3 characters
41+
logger.debug('Search query too short', { query })
3842
return []
3943
}
4044

@@ -75,6 +79,7 @@ export async function searchNodes(query: string, { dir, signal }: SearchNodesOpt
7579

7680
// check if the request was aborted
7781
if (signal?.aborted) {
82+
logger.debug('Search request aborted', { query, dir })
7883
return []
7984
}
8085

apps/files/src/store/files.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ export const useFilesStore = function(...args) {
9696
updateNodes(nodes: Node[]) {
9797
// Update the store all at once
9898
const files = nodes.reduce((acc, node) => {
99-
if (!node.fileid) {
99+
if (typeof node.fileid !== 'number') {
100100
logger.error('Trying to update/set a node without fileid', { node })
101101
return acc
102102
}
@@ -129,7 +129,7 @@ export const useFilesStore = function(...args) {
129129
},
130130

131131
onMovedNode({ node, oldSource }: { node: Node, oldSource: string }) {
132-
if (!node.fileid) {
132+
if (typeof node.fileid !== 'number') {
133133
logger.error('Trying to update/set a node without fileid', { node })
134134
return
135135
}
@@ -140,7 +140,7 @@ export const useFilesStore = function(...args) {
140140
},
141141

142142
async onUpdatedNode(node: Node) {
143-
if (!node.fileid) {
143+
if (typeof node.fileid !== 'number') {
144144
logger.error('Trying to update/set a node without fileid', { node })
145145
return
146146
}
@@ -154,7 +154,7 @@ export const useFilesStore = function(...args) {
154154
}
155155

156156
// If we have only one node with the file ID, we can update it directly
157-
if (node.source === nodes[0].source) {
157+
if (node?.source === nodes[0]?.source) {
158158
this.updateNodes([node])
159159
return
160160
}

apps/files/src/store/search.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ export const useSearchStore = defineStore('search', () => {
2929
* Scope of the search.
3030
* Scopes:
3131
* - filter: only filter current file list
32-
* - locally: search from current location recursivly
32+
* - locally: search from current location recursively
3333
* - globally: search everywhere
3434
*/
3535
const scope = ref<SearchScope>('filter')

0 commit comments

Comments
 (0)