Skip to content

Commit 30689fc

Browse files
authored
Merge pull request #49301 from nextcloud/refactor/files-required-navigation
refactor(files): Adjust `useNavigation` composable to enforce active view
2 parents 67a02fa + ec1c4d8 commit 30689fc

File tree

9 files changed

+35
-29
lines changed

9 files changed

+35
-29
lines changed

apps/files/src/components/FileEntry.vue

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@
7474
<!-- View columns -->
7575
<td v-for="column in columns"
7676
:key="column.id"
77-
:class="`files-list__row-${currentView?.id}-${column.id}`"
77+
:class="`files-list__row-${currentView.id}-${column.id}`"
7878
class="files-list__row-column-custom"
7979
:data-cy-files-list-row-column-custom="column.id"
8080
@click="openDetailsIfAvailable">
@@ -135,7 +135,8 @@ export default defineComponent({
135135
const filesStore = useFilesStore()
136136
const renamingStore = useRenamingStore()
137137
const selectionStore = useSelectionStore()
138-
const { currentView } = useNavigation()
138+
// The file list is guaranteed to be only shown with active view - thus we can set the `loaded` flag
139+
const { currentView } = useNavigation(true)
139140
const {
140141
directory: currentDir,
141142
fileId: currentFileId,
@@ -180,7 +181,7 @@ export default defineComponent({
180181
if (this.filesListWidth < 512 || this.compact) {
181182
return []
182183
}
183-
return this.currentView?.columns || []
184+
return this.currentView.columns || []
184185
},
185186
186187
size() {

apps/files/src/components/FileEntry/FileEntryActions.vue

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,8 @@
7777
</template>
7878

7979
<script lang="ts">
80-
import type { PropType, ShallowRef } from 'vue'
81-
import type { FileAction, Node, View } from '@nextcloud/files'
80+
import type { PropType } from 'vue'
81+
import type { FileAction, Node } from '@nextcloud/files'
8282
8383
import { DefaultType, NodeStatus } from '@nextcloud/files'
8484
import { showError, showSuccess } from '@nextcloud/dialogs'
@@ -133,12 +133,12 @@ export default defineComponent({
133133
},
134134
135135
setup() {
136-
const { currentView } = useNavigation()
136+
// The file list is guaranteed to be only shown with active view - thus we can set the `loaded` flag
137+
const { currentView } = useNavigation(true)
137138
const enabledFileActions = inject<FileAction[]>('enabledFileActions', [])
138139
139140
return {
140-
// The file list is guaranteed to be only shown with active view
141-
currentView: currentView as ShallowRef<View>,
141+
currentView,
142142
enabledFileActions,
143143
}
144144
},

apps/files/src/components/FileEntry/FileEntryName.vue

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,8 @@ export default defineComponent({
9494
},
9595
9696
setup() {
97-
const { currentView } = useNavigation()
97+
// The file list is guaranteed to be only shown with active view - thus we can set the `loaded` flag
98+
const { currentView } = useNavigation(true)
9899
const { directory } = useRouteParameters()
99100
const renamingStore = useRenamingStore()
100101
@@ -143,7 +144,7 @@ export default defineComponent({
143144
}
144145
}
145146
146-
if (this.defaultFileAction && this.currentView) {
147+
if (this.defaultFileAction) {
147148
const displayName = this.defaultFileAction.displayName([this.source], this.currentView)
148149
return {
149150
is: 'button',
@@ -247,8 +248,8 @@ export default defineComponent({
247248
if (status) {
248249
showSuccess(t('files', 'Renamed "{oldName}" to "{newName}"', { oldName, newName }))
249250
this.$nextTick(() => {
250-
const nameContainter = this.$refs.basename as HTMLElement | undefined
251-
nameContainter?.focus()
251+
const nameContainer = this.$refs.basename as HTMLElement | undefined
252+
nameContainer?.focus()
252253
})
253254
} else {
254255
// Was cancelled - meaning the renaming state is just reset

apps/files/src/components/FileEntryGrid.vue

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,8 @@ export default defineComponent({
107107
const filesStore = useFilesStore()
108108
const renamingStore = useRenamingStore()
109109
const selectionStore = useSelectionStore()
110-
const { currentView } = useNavigation()
110+
// The file list is guaranteed to be only shown with active view - thus we can set the `loaded` flag
111+
const { currentView } = useNavigation(true)
111112
const {
112113
directory: currentDir,
113114
fileId: currentFileId,

apps/files/src/composables/useNavigation.spec.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@
22
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
33
* SPDX-License-Identifier: AGPL-3.0-or-later
44
*/
5+
import type { Navigation, View } from '@nextcloud/files'
6+
57
import { beforeEach, describe, expect, it, vi } from 'vitest'
68
import { mount } from '@vue/test-utils'
79
import { defineComponent } from 'vue'
810

911
import { useNavigation } from './useNavigation'
1012
import * as nextcloudFiles from '@nextcloud/files'
1113

12-
const { Navigation, View } = nextcloudFiles
13-
1414
// Just a wrapper so we can test the composable
1515
const TestComponent = defineComponent({
1616
template: '<div></div>',
@@ -29,7 +29,7 @@ describe('Composables: useNavigation', () => {
2929

3030
describe('currentView', () => {
3131
beforeEach(() => {
32-
navigation = new Navigation()
32+
navigation = new nextcloudFiles.Navigation()
3333
spy.mockImplementation(() => navigation)
3434
})
3535

@@ -39,7 +39,7 @@ describe('Composables: useNavigation', () => {
3939
})
4040

4141
it('should return already active navigation', async () => {
42-
const view = new View({ getContents: () => Promise.reject(new Error()), icon: '<svg></svg>', id: 'view-1', name: 'My View 1', order: 0 })
42+
const view = new nextcloudFiles.View({ getContents: () => Promise.reject(new Error()), icon: '<svg></svg>', id: 'view-1', name: 'My View 1', order: 0 })
4343
navigation.register(view)
4444
navigation.setActive(view)
4545
// Now the navigation is already set it should take the active navigation
@@ -48,7 +48,7 @@ describe('Composables: useNavigation', () => {
4848
})
4949

5050
it('should be reactive on updating active navigation', async () => {
51-
const view = new View({ getContents: () => Promise.reject(new Error()), icon: '<svg></svg>', id: 'view-1', name: 'My View 1', order: 0 })
51+
const view = new nextcloudFiles.View({ getContents: () => Promise.reject(new Error()), icon: '<svg></svg>', id: 'view-1', name: 'My View 1', order: 0 })
5252
navigation.register(view)
5353
const wrapper = mount(TestComponent)
5454

@@ -63,7 +63,7 @@ describe('Composables: useNavigation', () => {
6363

6464
describe('views', () => {
6565
beforeEach(() => {
66-
navigation = new Navigation()
66+
navigation = new nextcloudFiles.Navigation()
6767
spy.mockImplementation(() => navigation)
6868
})
6969

@@ -73,7 +73,7 @@ describe('Composables: useNavigation', () => {
7373
})
7474

7575
it('should return already registered views', () => {
76-
const view = new View({ getContents: () => Promise.reject(new Error()), icon: '<svg></svg>', id: 'view-1', name: 'My View 1', order: 0 })
76+
const view = new nextcloudFiles.View({ getContents: () => Promise.reject(new Error()), icon: '<svg></svg>', id: 'view-1', name: 'My View 1', order: 0 })
7777
// register before mount
7878
navigation.register(view)
7979
// now mount and check that the view is listed
@@ -82,8 +82,8 @@ describe('Composables: useNavigation', () => {
8282
})
8383

8484
it('should be reactive on registering new views', () => {
85-
const view = new View({ getContents: () => Promise.reject(new Error()), icon: '<svg></svg>', id: 'view-1', name: 'My View 1', order: 0 })
86-
const view2 = new View({ getContents: () => Promise.reject(new Error()), icon: '<svg></svg>', id: 'view-2', name: 'My View 2', order: 1 })
85+
const view = new nextcloudFiles.View({ getContents: () => Promise.reject(new Error()), icon: '<svg></svg>', id: 'view-1', name: 'My View 1', order: 0 })
86+
const view2 = new nextcloudFiles.View({ getContents: () => Promise.reject(new Error()), icon: '<svg></svg>', id: 'view-2', name: 'My View 2', order: 1 })
8787

8888
// register before mount
8989
navigation.register(view)

apps/files/src/composables/useNavigation.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,21 @@ import { onMounted, onUnmounted, shallowRef, triggerRef } from 'vue'
1111

1212
/**
1313
* Composable to get the currently active files view from the files navigation
14+
* @param _loaded If set enforce a current view is loaded
1415
*/
15-
export function useNavigation() {
16+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
17+
export function useNavigation<T extends boolean>(_loaded?: T) {
18+
type MaybeView = T extends true ? View : (View | null);
1619
const navigation = getNavigation()
1720
const views: ShallowRef<View[]> = shallowRef(navigation.views)
18-
const currentView: ShallowRef<View | null> = shallowRef(navigation.active)
21+
const currentView: ShallowRef<MaybeView> = shallowRef(navigation.active as MaybeView)
1922

2023
/**
2124
* Event listener to update the `currentView`
2225
* @param event The update event
2326
*/
2427
function onUpdateActive(event: CustomEvent<View|null>) {
25-
currentView.value = event.detail
28+
currentView.value = event.detail as MaybeView
2629
}
2730

2831
/**

dist/files-main.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/files-main.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/files_sharing-init.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)