* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
+import type { RawLocation, Route } from 'vue-router'
+
import { generateUrl } from '@nextcloud/router'
import queryString from 'query-string'
-import Router, { RawLocation, Route } from 'vue-router'
+import Router from 'vue-router'
import Vue from 'vue'
import { ErrorHandler } from 'vue-router/types/router'
{
path: '/',
// Pretending we're using the default view
- redirect: { name: 'filelist' },
+ redirect: { name: 'filelist', params: { view: 'files' } },
},
{
- path: '/:view/:fileid?',
+ path: '/:view/:fileid(\\d+)?',
name: 'filelist',
props: true,
},
<template #list>
<NcAppNavigationItem v-for="view in parentViews"
:key="view.id"
- :allow-collapse="true"
+ allow-collapse
:data-cy-files-navigation-item="view.id"
- :exact="true"
+ :exact="useExactRouteMatching(view)"
:icon="view.iconClass"
:name="view.name"
:open="isExpanded(view)"
<NcAppNavigationItem v-for="child in childViews[view.id]"
:key="child.id"
:data-cy-files-navigation-item="child.id"
- :exact="true"
+ :exact-path="true"
:icon="child.iconClass"
:name="child.name"
:to="generateToNavigation(child)">
</template>
<script lang="ts">
+import type { View } from '@nextcloud/files'
+
import { emit } from '@nextcloud/event-bus'
import { translate } from '@nextcloud/l10n'
import Cog from 'vue-material-design-icons/Cog.vue'
import { setPageHeading } from '../../../../core/src/OCP/accessibility.js'
import { useViewConfigStore } from '../store/viewConfig.ts'
import logger from '../logger.js'
-import type { View } from '@nextcloud/files'
import NavigationQuota from '../components/NavigationQuota.vue'
import SettingsModal from './Settings.vue'
},
currentView(): View {
- return this.views.find(view => view.id === this.currentViewId)
+ return this.views.find(view => view.id === this.currentViewId)!
},
views(): View[] {
})
},
- childViews(): View[] {
+ childViews(): Record<string, View[]> {
return this.views
// filter parent views
.filter(view => !!view.parent)
// create a map of parents and their children
.reduce((list, view) => {
- list[view.parent] = [...(list[view.parent] || []), view]
+ list[view.parent!] = [...(list[view.parent!] || []), view]
// Sort children by order
- list[view.parent].sort((a, b) => {
+ list[view.parent!].sort((a, b) => {
return a.order - b.order
})
return list
- }, {})
+ }, {} as Record<string, View[]>)
},
},
currentView(view, oldView) {
if (view.id !== oldView?.id) {
this.$navigation.setActive(view)
- logger.debug('Navigation changed', { id: view.id, view })
+ logger.debug(`Navigation changed from ${oldView.id} to ${view.id}`, { from: oldView, to: view })
this.showView(view)
}
},
methods: {
+ /**
+ * Only use exact route matching on routes with child views
+ * Because if a view does not have children (like the files view) then multiple routes might be matched for it
+ * Like for the 'files' view this does not work because of optional 'fileid' param so /files and /files/1234 are both in the 'files' view
+ * @param view The view to check
+ */
+ useExactRouteMatching(view: View) {
+ return this.childViews[view.id]?.length > 0
+ },
+
showView(view: View) {
// Closing any opened sidebar
window?.OCA?.Files?.Sidebar?.close?.()
/**
* Expand/collapse a a view with children and permanently
* save this setting in the server.
- * @param view
+ * @param view View to toggle
*/
onToggleExpand(view: View) {
// Invert state
/**
* Check if a view is expanded by user config
* or fallback to the default value.
- * @param view
+ * @param view View to check if expanded
*/
isExpanded(view: View): boolean {
return typeof this.viewConfigStore.getConfig(view.id)?.expanded === 'boolean'
/**
* Generate the route to a view
- * @param view
+ * @param view View to generate "to" navigation for
*/
generateToNavigation(view: View) {
if (view.params) {