Skip to content

Commit 69460c9

Browse files
skjnldsvbackportbot[bot]
authored andcommitted
fix(files): highlight previous folder on history up
Signed-off-by: skjnldsv <skjnldsv@protonmail.com>
1 parent ad2470b commit 69460c9

2 files changed

Lines changed: 117 additions & 0 deletions

File tree

apps/files/src/router/router.ts

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,16 @@
33
* SPDX-License-Identifier: AGPL-3.0-or-later
44
*/
55
import type { RawLocation, Route } from 'vue-router'
6+
67
import { generateUrl } from '@nextcloud/router'
8+
import { relative } from 'path'
79
import queryString from 'query-string'
810
import Router, { isNavigationFailure, NavigationFailureType } from 'vue-router'
911
import Vue from 'vue'
12+
13+
import { useFilesStore } from '../store/files'
14+
import { useNavigation } from '../composables/useNavigation'
15+
import { usePathsStore } from '../store/paths'
1016
import logger from '../logger'
1117

1218
Vue.use(Router)
@@ -68,4 +74,60 @@ const router = new Router({
6874
},
6975
})
7076

77+
// If navigating back from a folder to a parent folder,
78+
// we need to keep the current dir fileid so it's highlighted
79+
// and scrolled into view.
80+
router.beforeEach((to, from, next) => {
81+
if (to.params?.parentIntercept) {
82+
delete to.params.parentIntercept
83+
next()
84+
return
85+
}
86+
87+
const fromDir = (from.query?.dir || '/') as string
88+
const toDir = (to.query?.dir || '/') as string
89+
90+
// We are going back to a parent directory
91+
if (relative(fromDir, toDir) === '..') {
92+
const { currentView } = useNavigation()
93+
const { getNode } = useFilesStore()
94+
const { getPath } = usePathsStore()
95+
96+
if (!currentView.value?.id) {
97+
logger.error('No current view id found, cannot navigate to parent directory', { fromDir, toDir })
98+
return next()
99+
}
100+
101+
// Get the previous parent's file id
102+
const fromSource = getPath(currentView.value?.id, fromDir)
103+
if (!fromSource) {
104+
logger.error('No source found for the parent directory', { fromDir, toDir })
105+
return next()
106+
}
107+
108+
const fileId = getNode(fromSource)?.fileid
109+
if (!fileId) {
110+
logger.error('No fileid found for the parent directory', { fromDir, toDir, fromSource })
111+
return next()
112+
}
113+
114+
logger.debug('Navigating back to parent directory', { fromDir, toDir, fileId })
115+
next({
116+
name: 'filelist',
117+
query: to.query,
118+
params: {
119+
...to.params,
120+
fileid: String(fileId),
121+
// Prevents the beforeEach from being called again
122+
parentIntercept: 'true',
123+
},
124+
// Replace the current history entry
125+
replace: true,
126+
})
127+
}
128+
129+
// else, we just continue
130+
next()
131+
})
132+
71133
export default router
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*!
2+
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
3+
* SPDX-License-Identifier: AGPL-3.0-or-later
4+
*/
5+
6+
import type { User } from '@nextcloud/cypress'
7+
import { getRowForFile, navigateToFolder } from './FilesUtils.ts'
8+
9+
describe('files: Navigate through folders and observe behavior', () => {
10+
let user: User
11+
12+
before(() => {
13+
cy.createRandomUser().then(($user) => {
14+
user = $user
15+
cy.mkdir(user, '/foo')
16+
cy.mkdir(user, '/foo/bar')
17+
cy.mkdir(user, '/foo/bar/baz')
18+
})
19+
})
20+
21+
it('Shows root folder and we can navigate to the last folder', () => {
22+
cy.login(user)
23+
cy.visit('/apps/files/')
24+
25+
getRowForFile('foo').should('be.visible')
26+
navigateToFolder('/foo/bar/baz')
27+
28+
// Last folder is empty
29+
cy.get('[data-cy-files-list-row-fileid]').should('not.exist')
30+
})
31+
32+
it('Highlight the previous folder when navigating back', () => {
33+
cy.go('back')
34+
getRowForFile('baz').should('be.visible')
35+
.invoke('attr', 'class').should('contain', 'active')
36+
37+
cy.go('back')
38+
getRowForFile('bar').should('be.visible')
39+
.invoke('attr', 'class').should('contain', 'active')
40+
41+
cy.go('back')
42+
getRowForFile('foo').should('be.visible')
43+
.invoke('attr', 'class').should('contain', 'active')
44+
})
45+
46+
it('Can navigate forward again', () => {
47+
cy.go('forward')
48+
getRowForFile('bar').should('be.visible')
49+
.invoke('attr', 'class').should('contain', 'active')
50+
51+
cy.go('forward')
52+
getRowForFile('baz').should('be.visible')
53+
.invoke('attr', 'class').should('contain', 'active')
54+
})
55+
})

0 commit comments

Comments
 (0)