diff options
-rw-r--r-- | apps/files/src/main.ts | 6 | ||||
-rw-r--r-- | apps/files/src/services/Recent.ts | 24 | ||||
-rw-r--r-- | apps/files/src/store/index.ts | 25 | ||||
-rw-r--r-- | apps/files/src/views/FilesList.vue | 8 | ||||
-rw-r--r-- | apps/files/src/views/Settings.vue | 16 | ||||
-rw-r--r-- | apps/files/src/views/recent.ts | 2 | ||||
-rw-r--r-- | cypress/e2e/files/FilesUtils.ts | 4 | ||||
-rw-r--r-- | cypress/e2e/files/files-settings.cy.ts | 97 |
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') + }) + }) +}) |