aboutsummaryrefslogtreecommitdiffstats
path: root/apps
diff options
context:
space:
mode:
authorFerdinand Thiessen <opensource@fthiessen.de>2025-02-06 01:13:40 +0100
committerFerdinand Thiessen <opensource@fthiessen.de>2025-02-08 14:28:42 +0100
commitfc9108b11abd58ba4d10f19a89ebfffa382c51e6 (patch)
tree1a8ee9c3f9b2253a5fbbad145b046c5708a50716 /apps
parentbeca0a19ee74efb4d3e1f8cc7e0490c88aa22a3f (diff)
downloadnextcloud-server-fc9108b11abd58ba4d10f19a89ebfffa382c51e6.tar.gz
nextcloud-server-fc9108b11abd58ba4d10f19a89ebfffa382c51e6.zip
fix(files): only send config update requests if user is logged in
Since we use the files app also for public shares it is not guaranteed that there is a user logged in, in that case the update for user / view config will fail. So ensure there is a user or do not send a request. Also refactor both stores to setup styles to fix (remove) initialization hack, which causes Typescript issues. Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
Diffstat (limited to 'apps')
-rw-r--r--apps/files/src/eventbus.d.ts3
-rw-r--r--apps/files/src/store/userconfig.ts78
-rw-r--r--apps/files/src/store/viewConfig.ts150
-rw-r--r--apps/files/src/types.ts8
-rw-r--r--apps/files/src/views/Navigation.vue14
5 files changed, 126 insertions, 127 deletions
diff --git a/apps/files/src/eventbus.d.ts b/apps/files/src/eventbus.d.ts
index e1fd8c73b4b..ce0611580fe 100644
--- a/apps/files/src/eventbus.d.ts
+++ b/apps/files/src/eventbus.d.ts
@@ -7,7 +7,8 @@ import type { IFileListFilter, Node } from '@nextcloud/files'
declare module '@nextcloud/event-bus' {
export interface NextcloudEvents {
// mapping of 'event name' => 'event type'
- 'files:config:updated': { key: string, value: unknown }
+ 'files:config:updated': { key: string, value: boolean }
+ 'files:view-config:updated': { key: string, value: string|number|boolean, view: string }
'files:favorites:removed': Node
'files:favorites:added': Node
diff --git a/apps/files/src/store/userconfig.ts b/apps/files/src/store/userconfig.ts
index ffe07a91bab..95829c849e8 100644
--- a/apps/files/src/store/userconfig.ts
+++ b/apps/files/src/store/userconfig.ts
@@ -2,15 +2,16 @@
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
-import type { UserConfig, UserConfigStore } from '../types'
-import { defineStore } from 'pinia'
+import type { UserConfig } from '../types'
+import { getCurrentUser } from '@nextcloud/auth'
import { emit, subscribe } from '@nextcloud/event-bus'
-import { generateUrl } from '@nextcloud/router'
import { loadState } from '@nextcloud/initial-state'
+import { generateUrl } from '@nextcloud/router'
+import { defineStore } from 'pinia'
+import { ref, set } from 'vue'
import axios from '@nextcloud/axios'
-import Vue from 'vue'
-const userConfig = loadState<UserConfig>('files', 'config', {
+const initialUserConfig = loadState<UserConfig>('files', 'config', {
show_hidden: false,
crop_image_previews: true,
sort_favorites_first: true,
@@ -18,45 +19,38 @@ const userConfig = loadState<UserConfig>('files', 'config', {
grid_view: false,
})
-export const useUserConfigStore = function(...args) {
- const store = defineStore('userconfig', {
- state: () => ({
- userConfig,
- } as UserConfigStore),
+export const useUserConfigStore = defineStore('userconfig', () => {
+ const userConfig = ref<UserConfig>({ ...initialUserConfig })
- actions: {
- /**
- * Update the user config local store
- * @param key
- * @param value
- */
- onUpdate(key: string, value: boolean) {
- Vue.set(this.userConfig, key, value)
- },
+ /**
+ * Update the user config local store
+ * @param key The config key
+ * @param value The new value
+ */
+ function onUpdate(key: string, value: boolean): void {
+ set(userConfig.value, key, value)
+ }
- /**
- * Update the user config local store AND on server side
- * @param key
- * @param value
- */
- async update(key: string, value: boolean) {
- await axios.put(generateUrl('/apps/files/api/v1/config/' + key), {
- value,
- })
- emit('files:config:updated', { key, value })
- },
- },
- })
+ /**
+ * Update the user config local store AND on server side
+ * @param key The config key
+ * @param value The new value
+ */
+ async function update(key: string, value: boolean): Promise<void> {
+ // only update if a user is logged in (not the case for public shares)
+ if (getCurrentUser() !== null) {
+ await axios.put(generateUrl('/apps/files/api/v1/config/{key}', { key }), {
+ value,
+ })
+ }
+ emit('files:config:updated', { key, value })
+ }
- const userConfigStore = store(...args)
+ // Register the event listener
+ subscribe('files:config:updated', ({ key, value }) => onUpdate(key, value))
- // Make sure we only register the listeners once
- if (!userConfigStore._initialized) {
- subscribe('files:config:updated', function({ key, value }: { key: string, value: boolean }) {
- userConfigStore.onUpdate(key, value)
- })
- userConfigStore._initialized = true
+ return {
+ userConfig,
+ update,
}
-
- return userConfigStore
-}
+})
diff --git a/apps/files/src/store/viewConfig.ts b/apps/files/src/store/viewConfig.ts
index 76786306d60..a902cedb6fa 100644
--- a/apps/files/src/store/viewConfig.ts
+++ b/apps/files/src/store/viewConfig.ts
@@ -2,95 +2,95 @@
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
-import { defineStore } from 'pinia'
+import type { ViewConfigs, ViewId, ViewConfig } from '../types'
+
+import { getCurrentUser } from '@nextcloud/auth'
import { emit, subscribe } from '@nextcloud/event-bus'
-import { generateUrl } from '@nextcloud/router'
import { loadState } from '@nextcloud/initial-state'
+import { generateUrl } from '@nextcloud/router'
+import { defineStore } from 'pinia'
+import { ref, set } from 'vue'
import axios from '@nextcloud/axios'
-import Vue from 'vue'
-import type { ViewConfigs, ViewConfigStore, ViewId, ViewConfig } from '../types'
+const initialViewConfig = loadState('files', 'viewConfigs', {}) as ViewConfigs
-const viewConfig = loadState('files', 'viewConfigs', {}) as ViewConfigs
+export const useViewConfigStore = defineStore('viewconfig', () => {
-export const useViewConfigStore = function(...args) {
- const store = defineStore('viewconfig', {
- state: () => ({
- viewConfig,
- } as ViewConfigStore),
+ const viewConfigs = ref({ ...initialViewConfig })
- getters: {
- getConfig: (state) => (view: ViewId): ViewConfig => state.viewConfig[view] || {},
+ /**
+ * Get the config for a specific view
+ * @param viewid Id of the view to fet the config for
+ */
+ function getConfig(viewid: ViewId): ViewConfig {
+ return viewConfigs.value[viewid] || {}
+ }
- getConfigs: (state) => (): ViewConfigs => state.viewConfig,
- },
+ /**
+ * Update the view config local store
+ * @param viewId The id of the view to update
+ * @param key The config key to update
+ * @param value The new value
+ */
+ function onUpdate(viewId: ViewId, key: string, value: string | number | boolean): void {
+ if (!(viewId in viewConfigs.value)) {
+ set(viewConfigs.value, viewId, {})
+ }
+ set(viewConfigs.value[viewId], key, value)
+ }
- actions: {
- /**
- * Update the view config local store
- * @param view
- * @param key
- * @param value
- */
- onUpdate(view: ViewId, key: string, value: string | number | boolean) {
- if (!this.viewConfig[view]) {
- Vue.set(this.viewConfig, view, {})
- }
- Vue.set(this.viewConfig[view], key, value)
- },
+ /**
+ * Update the view config local store AND on server side
+ * @param view Id of the view to update
+ * @param key Config key to update
+ * @param value New value
+ */
+ async function update(view: ViewId, key: string, value: string | number | boolean): Promise<void> {
+ if (getCurrentUser() !== null) {
+ await axios.put(generateUrl('/apps/files/api/v1/views'), {
+ value,
+ view,
+ key,
+ })
+ }
- /**
- * Update the view config local store AND on server side
- * @param view
- * @param key
- * @param value
- */
- async update(view: ViewId, key: string, value: string | number | boolean) {
- axios.put(generateUrl('/apps/files/api/v1/views'), {
- value,
- view,
- key,
- })
+ emit('files:view-config:updated', { view, key, value })
+ }
- emit('files:viewconfig:updated', { view, key, value })
- },
+ /**
+ * Set the sorting key AND sort by ASC
+ * The key param must be a valid key of a File object
+ * If not found, will be searched within the File attributes
+ * @param key Key to sort by
+ * @param view View to set the sorting key for
+ */
+ function setSortingBy(key = 'basename', view = 'files'): void {
+ // Save new config
+ update(view, 'sorting_mode', key)
+ update(view, 'sorting_direction', 'asc')
+ }
- /**
- * Set the sorting key AND sort by ASC
- * The key param must be a valid key of a File object
- * If not found, will be searched within the File attributes
- * @param key Key to sort by
- * @param view View to set the sorting key for
- */
- setSortingBy(key = 'basename', view = 'files') {
- // Save new config
- this.update(view, 'sorting_mode', key)
- this.update(view, 'sorting_direction', 'asc')
- },
+ /**
+ * Toggle the sorting direction
+ * @param viewId id of the view to set the sorting order for
+ */
+ function toggleSortingDirection(viewId = 'files'): void {
+ const config = viewConfigs.value[viewId] || { sorting_direction: 'asc' }
+ const newDirection = config.sorting_direction === 'asc' ? 'desc' : 'asc'
- /**
- * Toggle the sorting direction
- * @param view view to set the sorting order for
- */
- toggleSortingDirection(view = 'files') {
- const config = this.getConfig(view) || { sorting_direction: 'asc' }
- const newDirection = config.sorting_direction === 'asc' ? 'desc' : 'asc'
+ // Save new config
+ update(viewId, 'sorting_direction', newDirection)
+ }
- // Save new config
- this.update(view, 'sorting_direction', newDirection)
- },
- },
- })
+ // Initialize event listener
+ subscribe('files:view-config:updated', ({ view, key, value }) => onUpdate(view, key, value))
- const viewConfigStore = store(...args)
+ return {
+ viewConfigs,
- // Make sure we only register the listeners once
- if (!viewConfigStore._initialized) {
- subscribe('files:viewconfig:updated', function({ view, key, value }: { view: ViewId, key: string, value: boolean }) {
- viewConfigStore.onUpdate(view, key, value)
- })
- viewConfigStore._initialized = true
+ getConfig,
+ setSortingBy,
+ toggleSortingDirection,
+ update,
}
-
- return viewConfigStore
-}
+})
diff --git a/apps/files/src/types.ts b/apps/files/src/types.ts
index 673cb06e182..62ba53b89d2 100644
--- a/apps/files/src/types.ts
+++ b/apps/files/src/types.ts
@@ -50,7 +50,13 @@ export interface PathOptions {
// User config store
export interface UserConfig {
- [key: string]: boolean
+ [key: string]: boolean|undefined
+
+ show_hidden: boolean
+ crop_image_previews: boolean
+ sort_favorites_first: boolean
+ sort_folders_first: boolean
+ grid_view: boolean
}
export interface UserConfigStore {
userConfig: UserConfig
diff --git a/apps/files/src/views/Navigation.vue b/apps/files/src/views/Navigation.vue
index 4202a81c886..21b2bce2ccd 100644
--- a/apps/files/src/views/Navigation.vue
+++ b/apps/files/src/views/Navigation.vue
@@ -159,14 +159,12 @@ export default defineComponent({
methods: {
async loadExpandedViews() {
- const viewConfigs = this.viewConfigStore.getConfigs()
- const viewsToLoad: View[] = (Object.entries(viewConfigs) as Array<[string, ViewConfig]>)
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
- .filter(([viewId, config]) => config.expanded === true)
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
- .map(([viewId, config]) => this.views.find(view => view.id === viewId))
- .filter(Boolean) // Only registered views
- .filter(view => view.loadChildViews && !view.loaded)
+ const viewsToLoad: View[] = (Object.entries(this.viewConfigStore.viewConfigs) as Array<[string, ViewConfig]>)
+ .filter(([, config]) => config.expanded === true)
+ .map(([viewId]) => this.views.find(view => view.id === viewId))
+ // eslint-disable-next-line no-use-before-define
+ .filter(Boolean as unknown as ((u: unknown) => u is View))
+ .filter((view) => view.loadChildViews && !view.loaded)
for (const view of viewsToLoad) {
await view.loadChildViews(view)
}