aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--apps/files/src/main.ts6
-rw-r--r--apps/files/src/services/Recent.ts24
-rw-r--r--apps/files/src/store/index.ts25
-rw-r--r--apps/files/src/views/FilesList.vue8
-rw-r--r--apps/files/src/views/Settings.vue16
-rw-r--r--apps/files/src/views/recent.ts2
-rw-r--r--cypress/e2e/files/FilesUtils.ts4
-rw-r--r--cypress/e2e/files/files-settings.cy.ts97
8 files changed, 169 insertions, 13 deletions
diff --git a/apps/files/src/main.ts b/apps/files/src/main.ts
index 7b25c88a697..97b3b2f9651 100644
--- a/apps/files/src/main.ts
+++ b/apps/files/src/main.ts
@@ -1,8 +1,9 @@
-import Vue from 'vue'
-import { createPinia, PiniaVuePlugin } from 'pinia'
+import { PiniaVuePlugin } from 'pinia'
import { getNavigation } from '@nextcloud/files'
import { getRequestToken } from '@nextcloud/auth'
+import Vue from 'vue'
+import { pinia } from './store/index.ts'
import router from './router/router'
import RouterService from './services/RouterService'
import SettingsModel from './models/Setting.js'
@@ -30,7 +31,6 @@ Object.assign(window.OCP.Files, { Router })
// Init Pinia store
Vue.use(PiniaVuePlugin)
-const pinia = createPinia()
// Init Navigation Service
// This only works with Vue 2 - with Vue 3 this will not modify the source but return just a oberserver
diff --git a/apps/files/src/services/Recent.ts b/apps/files/src/services/Recent.ts
index 26c4babb5a2..47f31466dd2 100644
--- a/apps/files/src/services/Recent.ts
+++ b/apps/files/src/services/Recent.ts
@@ -20,17 +20,37 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
-import type { ContentsWithRoot } from '@nextcloud/files'
+import type { ContentsWithRoot, Node } from '@nextcloud/files'
import type { FileStat, ResponseDataDetailed } from 'webdav'
import { getCurrentUser } from '@nextcloud/auth'
import { Folder, Permission, davGetRecentSearch, davGetClient, davResultToNode, davRootPath, davRemoteURL } from '@nextcloud/files'
+import { useUserConfigStore } from '../store/userconfig.ts'
+import { pinia } from '../store/index.ts'
const client = davGetClient()
const lastTwoWeeksTimestamp = Math.round((Date.now() / 1000) - (60 * 60 * 24 * 14))
+/**
+ * Get recently changed nodes
+ *
+ * This takes the users preference about hidden files into account.
+ * If hidden files are not shown, then also recently changed files *in* hidden directories are filtered.
+ *
+ * @param path Path to search for recent changes
+ */
export const getContents = async (path = '/'): Promise<ContentsWithRoot> => {
+ const store = useUserConfigStore(pinia)
+ /**
+ * Filter function that returns only the visible nodes - or hidden if explicitly configured
+ * @param node The node to check
+ */
+ const filterHidden = (node: Node) =>
+ path !== '/' // We need to hide files from hidden directories in the root if not configured to show
+ || store.userConfig.show_hidden // If configured to show hidden files we can early return
+ || !node.dirname.split('/').some((dir) => dir.startsWith('.')) // otherwise only include the file if non of the parent directories is hidden
+
const contentsResponse = await client.getDirectoryContents(path, {
details: true,
data: davGetRecentSearch(lastTwoWeeksTimestamp),
@@ -53,6 +73,6 @@ export const getContents = async (path = '/'): Promise<ContentsWithRoot> => {
owner: getCurrentUser()?.uid || null,
permissions: Permission.READ,
}),
- contents: contents.map((r) => davResultToNode(r)),
+ contents: contents.map((r) => davResultToNode(r)).filter(filterHidden),
}
}
diff --git a/apps/files/src/store/index.ts b/apps/files/src/store/index.ts
new file mode 100644
index 00000000000..c97a09122ec
--- /dev/null
+++ b/apps/files/src/store/index.ts
@@ -0,0 +1,25 @@
+/**
+ * @copyright Copyright (c) 2024 Ferdinand Thiessen <opensource@fthiessen.de>
+ *
+ * @author Ferdinand Thiessen <opensource@fthiessen.de>
+ *
+ * @license AGPL-3.0-or-later
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+import { createPinia } from 'pinia'
+
+export const pinia = createPinia()
diff --git a/apps/files/src/views/FilesList.vue b/apps/files/src/views/FilesList.vue
index 66c81714860..f5bb45ede1d 100644
--- a/apps/files/src/views/FilesList.vue
+++ b/apps/files/src/views/FilesList.vue
@@ -214,6 +214,8 @@ export default defineComponent({
loading: true,
promise: null,
Type,
+
+ _unsubscribeStore: () => {},
}
},
@@ -454,10 +456,16 @@ export default defineComponent({
subscribe('files:node:updated', this.onUpdatedNode)
subscribe('nextcloud:unified-search.search', this.onSearch)
subscribe('nextcloud:unified-search.reset', this.onSearch)
+
+ // reload on settings change
+ this._unsubscribeStore = this.userConfigStore.$subscribe(() => this.fetchContent(), { deep: true })
},
unmounted() {
unsubscribe('files:node:updated', this.onUpdatedNode)
+ unsubscribe('nextcloud:unified-search.search', this.onSearch)
+ unsubscribe('nextcloud:unified-search.reset', this.onSearch)
+ this._unsubscribeStore()
},
methods: {
diff --git a/apps/files/src/views/Settings.vue b/apps/files/src/views/Settings.vue
index cefbdab4eec..cfb43c5c8f2 100644
--- a/apps/files/src/views/Settings.vue
+++ b/apps/files/src/views/Settings.vue
@@ -20,29 +20,35 @@
-
-->
<template>
- <NcAppSettingsDialog :open="open"
+ <NcAppSettingsDialog data-cy-files-navigation-settings
+ :open="open"
:show-navigation="true"
:name="t('files', 'Files settings')"
@update:open="onClose">
<!-- Settings API-->
<NcAppSettingsSection id="settings" :name="t('files', 'Files settings')">
- <NcCheckboxRadioSwitch :checked="userConfig.sort_favorites_first"
+ <NcCheckboxRadioSwitch data-cy-files-settings-setting="sort_favorites_first"
+ :checked="userConfig.sort_favorites_first"
@update:checked="setConfig('sort_favorites_first', $event)">
{{ t('files', 'Sort favorites first') }}
</NcCheckboxRadioSwitch>
- <NcCheckboxRadioSwitch :checked="userConfig.sort_folders_first"
+ <NcCheckboxRadioSwitch data-cy-files-settings-setting="sort_folders_first"
+ :checked="userConfig.sort_folders_first"
@update:checked="setConfig('sort_folders_first', $event)">
{{ t('files', 'Sort folders before files') }}
</NcCheckboxRadioSwitch>
- <NcCheckboxRadioSwitch :checked="userConfig.show_hidden"
+ <NcCheckboxRadioSwitch data-cy-files-settings-setting="show_hidden"
+ :checked="userConfig.show_hidden"
@update:checked="setConfig('show_hidden', $event)">
{{ t('files', 'Show hidden files') }}
</NcCheckboxRadioSwitch>
- <NcCheckboxRadioSwitch :checked="userConfig.crop_image_previews"
+ <NcCheckboxRadioSwitch data-cy-files-settings-setting="crop_image_previews"
+ :checked="userConfig.crop_image_previews"
@update:checked="setConfig('crop_image_previews', $event)">
{{ t('files', 'Crop image previews') }}
</NcCheckboxRadioSwitch>
<NcCheckboxRadioSwitch v-if="enableGridView"
+ data-cy-files-settings-setting="grid_view"
:checked="userConfig.grid_view"
@update:checked="setConfig('grid_view', $event)">
{{ t('files', 'Enable the grid view') }}
diff --git a/apps/files/src/views/recent.ts b/apps/files/src/views/recent.ts
index 08ae5db6f39..a49ce725b97 100644
--- a/apps/files/src/views/recent.ts
+++ b/apps/files/src/views/recent.ts
@@ -19,11 +19,11 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
+import { View, getNavigation } from '@nextcloud/files'
import { translate as t } from '@nextcloud/l10n'
import HistorySvg from '@mdi/svg/svg/history.svg?raw'
import { getContents } from '../services/Recent'
-import { View, getNavigation } from '@nextcloud/files'
export default () => {
const Navigation = getNavigation()
diff --git a/cypress/e2e/files/FilesUtils.ts b/cypress/e2e/files/FilesUtils.ts
index 0b664434e39..f7c4c33ccb4 100644
--- a/cypress/e2e/files/FilesUtils.ts
+++ b/cypress/e2e/files/FilesUtils.ts
@@ -27,8 +27,8 @@ export const getActionsForFile = (filename: string) => getRowForFile(filename).f
export const getActionButtonForFile = (filename: string) => getActionsForFile(filename).find('button[aria-label="Actions"]')
export const triggerActionForFile = (filename: string, actionId: string) => {
- getActionButtonForFile(filename).click()
- cy.get(`[data-cy-files-list-row-action="${CSS.escape(actionId)}"] > button`).should('exist').click()
+ getActionButtonForFile(filename).click({ force: true })
+ cy.get(`[data-cy-files-list-row-action="${CSS.escape(actionId)}"] > button`).should('be.visible').click({ force: true })
}
export const moveFile = (fileName: string, dirPath: string) => {
diff --git a/cypress/e2e/files/files-settings.cy.ts b/cypress/e2e/files/files-settings.cy.ts
new file mode 100644
index 00000000000..75f2bdb4700
--- /dev/null
+++ b/cypress/e2e/files/files-settings.cy.ts
@@ -0,0 +1,97 @@
+/**
+ * @copyright Copyright (c) 2024 Ferdinand Thiessen <opensource@fthiessen.de>
+ *
+ * @author Ferdinand Thiessen <opensource@fthiessen.de>
+ *
+ * @license AGPL-3.0-or-later
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+import type { User } from '@nextcloud/cypress'
+import { getRowForFile } from './FilesUtils'
+
+const showHiddenFiles = () => {
+ // Open the files settings
+ cy.get('[data-cy-files-navigation-settings-button] a').click({ force: true })
+ // Toggle the hidden files setting
+ cy.get('[data-cy-files-settings-setting="show_hidden"]').within(() => {
+ cy.get('input').should('not.be.checked')
+ cy.get('input').check({ force: true })
+ })
+ // Close the dialog
+ cy.get('[data-cy-files-navigation-settings] button[aria-label="Close"]').click()
+}
+
+describe('files: Hide or show hidden files', { testIsolation: true }, () => {
+ let user: User
+
+ const setupFiles = () => cy.createRandomUser().then(($user) => {
+ user = $user
+
+ cy.uploadContent(user, new Blob([]), 'text/plain', '/.file')
+ cy.uploadContent(user, new Blob([]), 'text/plain', '/visible-file')
+ cy.mkdir(user, '/.folder')
+ cy.login(user)
+ })
+
+ context('view: All files', { testIsolation: false }, () => {
+ before(setupFiles)
+
+ it('hides dot-files by default', () => {
+ cy.visit('/apps/files')
+
+ getRowForFile('visible-file').should('be.visible')
+ getRowForFile('.file').should('not.exist')
+ getRowForFile('.folder').should('not.exist')
+ })
+
+ it('can show hidden files', () => {
+ showHiddenFiles()
+ // Now the files should be visible
+ getRowForFile('.file').should('be.visible')
+ getRowForFile('.folder').should('be.visible')
+ })
+ })
+
+ context('view: Recent files', { testIsolation: false }, () => {
+ before(() => {
+ setupFiles().then(() => {
+ // also add hidden file in hidden folder
+ cy.uploadContent(user, new Blob([]), 'text/plain', '/.folder/other-file')
+ cy.login(user)
+ })
+ })
+
+ it('hides dot-files by default', () => {
+ cy.visit('/apps/files/recent')
+
+ getRowForFile('visible-file').should('be.visible')
+ getRowForFile('.file').should('not.exist')
+ getRowForFile('.folder').should('not.exist')
+ getRowForFile('other-file').should('not.exist')
+ })
+
+ it('can show hidden files', () => {
+ showHiddenFiles()
+
+ getRowForFile('visible-file').should('be.visible')
+ // Now the files should be visible
+ getRowForFile('.file').should('be.visible')
+ getRowForFile('.folder').should('be.visible')
+ getRowForFile('other-file').should('be.visible')
+ })
+ })
+})