diff options
Diffstat (limited to 'apps/files/src/views/Settings.vue')
-rw-r--r-- | apps/files/src/views/Settings.vue | 380 |
1 files changed, 326 insertions, 54 deletions
diff --git a/apps/files/src/views/Settings.vue b/apps/files/src/views/Settings.vue index 9a63fea4924..bfac8e0b3d6 100644 --- a/apps/files/src/views/Settings.vue +++ b/apps/files/src/views/Settings.vue @@ -1,36 +1,70 @@ <!-- - - @copyright Copyright (c) 2019 Gary Kim <gary@garykim.dev> - - - - @author Gary Kim <gary@garykim.dev> - - - - @license GNU AGPL version 3 or any later version - - - - 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/>. - - - --> + - SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors + - SPDX-License-Identifier: AGPL-3.0-or-later +--> <template> <NcAppSettingsDialog :open="open" :show-navigation="true" - :title="t('files', 'Files settings')" + :name="t('files', 'Files settings')" @update:open="onClose"> <!-- Settings API--> - <NcAppSettingsSection id="settings" :title="t('files', 'Files settings')"> - <NcCheckboxRadioSwitch :checked.sync="show_hidden" + <NcAppSettingsSection id="settings" :name="t('files', 'General')"> + <fieldset class="files-settings__default-view" + data-cy-files-settings-setting="default_view"> + <legend> + {{ t('files', 'Default view') }} + </legend> + <NcCheckboxRadioSwitch :model-value="userConfig.default_view" + name="default_view" + type="radio" + value="files" + @update:model-value="setConfig('default_view', $event)"> + {{ t('files', 'All files') }} + </NcCheckboxRadioSwitch> + <NcCheckboxRadioSwitch :model-value="userConfig.default_view" + name="default_view" + type="radio" + value="personal" + @update:model-value="setConfig('default_view', $event)"> + {{ t('files', 'Personal files') }} + </NcCheckboxRadioSwitch> + </fieldset> + <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 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 data-cy-files-settings-setting="folder_tree" + :checked="userConfig.folder_tree" + @update:checked="setConfig('folder_tree', $event)"> + {{ t('files', 'Folder tree') }} + </NcCheckboxRadioSwitch> + </NcAppSettingsSection> + + <!-- Appearance --> + <NcAppSettingsSection id="settings" :name="t('files', 'Appearance')"> + <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.sync="crop_image_previews" + <NcCheckboxRadioSwitch data-cy-files-settings-setting="show_mime_column" + :checked="userConfig.show_mime_column" + @update:checked="setConfig('show_mime_column', $event)"> + {{ t('files', 'Show file type column') }} + </NcCheckboxRadioSwitch> + <NcCheckboxRadioSwitch data-cy-files-settings-setting="show_files_extensions" + :checked="userConfig.show_files_extensions" + @update:checked="setConfig('show_files_extensions', $event)"> + {{ t('files', 'Show file extensions') }} + </NcCheckboxRadioSwitch> + <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> @@ -39,19 +73,21 @@ <!-- Settings API--> <NcAppSettingsSection v-if="settings.length !== 0" id="more-settings" - :title="t('files', 'Additional settings')"> + :name="t('files', 'Additional settings')"> <template v-for="setting in settings"> <Setting :key="setting.name" :el="setting.el" /> </template> </NcAppSettingsSection> <!-- Webdav URL--> - <NcAppSettingsSection id="webdav" :title="t('files', 'Webdav')"> + <NcAppSettingsSection id="webdav" :name="t('files', 'WebDAV')"> <NcInputField id="webdav-url-input" + :label="t('files', 'WebDAV URL')" :show-trailing-button="true" :success="webdavUrlCopied" - :trailing-button-label="t('files', 'Copy to clipboard')" + :trailing-button-label="t('files', 'Copy')" :value="webdavUrl" + class="webdav-url-input" readonly="readonly" type="url" @focus="$event.target.select()" @@ -61,34 +97,209 @@ </template> </NcInputField> <em> - <a :href="webdavDocs" target="_blank" rel="noreferrer noopener"> - {{ t('files', 'Use this address to access your Files via WebDAV') }} ↗ + <a class="setting-link" + :href="webdavDocs" + target="_blank" + rel="noreferrer noopener"> + {{ t('files', 'How to access files using WebDAV') }} ↗ </a> </em> + <br> + <em v-if="isTwoFactorEnabled"> + <a class="setting-link" :href="appPasswordUrl"> + {{ t('files', 'Two-Factor Authentication is enabled for your account, and therefore you need to use an app password to connect an external WebDAV client.') }} ↗ + </a> + </em> + </NcAppSettingsSection> + + <NcAppSettingsSection id="warning" :name="t('files', 'Warnings')"> + <NcCheckboxRadioSwitch type="switch" + :checked="userConfig.show_dialog_file_extension" + @update:checked="setConfig('show_dialog_file_extension', $event)"> + {{ t('files', 'Warn before changing a file extension') }} + </NcCheckboxRadioSwitch> + <NcCheckboxRadioSwitch type="switch" + :checked="userConfig.show_dialog_deletion" + @update:checked="setConfig('show_dialog_deletion', $event)"> + {{ t('files', 'Warn before deleting files') }} + </NcCheckboxRadioSwitch> + </NcAppSettingsSection> + + <NcAppSettingsSection id="shortcuts" + :name="t('files', 'Keyboard shortcuts')"> + + <h3>{{ t('files', 'Actions') }}</h3> + <dl> + <div> + <dt class="shortcut-key"> + <kbd>a</kbd> + </dt> + <dd class="shortcut-description"> + {{ t('files', 'File actions') }} + </dd> + </div> + <div> + <dt class="shortcut-key"> + <kbd>F2</kbd> + </dt> + <dd class="shortcut-description"> + {{ t('files', 'Rename') }} + </dd> + </div> + <div> + <dt class="shortcut-key"> + <kbd>Del</kbd> + </dt> + <dd class="shortcut-description"> + {{ t('files', 'Delete') }} + </dd> + </div> + <div> + <dt class="shortcut-key"> + <kbd>s</kbd> + </dt> + <dd class="shortcut-description"> + {{ t('files', 'Add or remove favorite') }} + </dd> + </div> + <div v-if="isSystemtagsEnabled"> + <dt class="shortcut-key"> + <kbd>t</kbd> + </dt> + <dd class="shortcut-description"> + {{ t('files', 'Manage tags') }} + </dd> + </div> + </dl> + + <h3>{{ t('files', 'Selection') }}</h3> + <dl> + <div> + <dt class="shortcut-key"> + <kbd>Ctrl</kbd> + <kbd>A</kbd> + </dt> + <dd class="shortcut-description"> + {{ t('files', 'Select all files') }} + </dd> + </div> + <div> + <dt class="shortcut-key"> + <kbd>ESC</kbd> + </dt> + <dd class="shortcut-description"> + {{ t('files', 'Deselect all') }} + </dd> + </div> + <div> + <dt class="shortcut-key"> + <kbd>Ctrl</kbd> + <kbd>Space</kbd> + </dt> + <dd class="shortcut-description"> + {{ t('files', 'Select or deselect') }} + </dd> + </div> + <div> + <dt class="shortcut-key"> + <kbd>Ctrl</kbd> + <kbd>Shift</kbd> <span>+ <kbd>Space</kbd></span> + </dt> + <dd class="shortcut-description"> + {{ t('files', 'Select a range') }} + </dd> + </div> + </dl> + + <h3>{{ t('files', 'Navigation') }}</h3> + <dl> + <div> + <dt class="shortcut-key"> + <kbd>Alt</kbd> + <kbd>↑</kbd> + </dt> + <dd class="shortcut-description"> + {{ t('files', 'Go to parent folder') }} + </dd> + </div> + <div> + <dt class="shortcut-key"> + <kbd>↑</kbd> + </dt> + <dd class="shortcut-description"> + {{ t('files', 'Go to file above') }} + </dd> + </div> + <div> + <dt class="shortcut-key"> + <kbd>↓</kbd> + </dt> + <dd class="shortcut-description"> + {{ t('files', 'Go to file below') }} + </dd> + </div> + <div> + <dt class="shortcut-key"> + <kbd>←</kbd> + </dt> + <dd class="shortcut-description"> + {{ t('files', 'Go left in grid') }} + </dd> + </div> + <div> + <dt class="shortcut-key"> + <kbd>→</kbd> + </dt> + <dd class="shortcut-description"> + {{ t('files', 'Go right in grid') }} + </dd> + </div> + </dl> + + <h3>{{ t('files', 'View') }}</h3> + <dl> + <div> + <dt class="shortcut-key"> + <kbd>V</kbd> + </dt> + <dd class="shortcut-description"> + {{ t('files', 'Toggle grid view') }} + </dd> + </div> + <div> + <dt class="shortcut-key"> + <kbd>D</kbd> + </dt> + <dd class="shortcut-description"> + {{ t('files', 'Open file sidebar') }} + </dd> + </div> + <div> + <dt class="shortcut-key"> + <kbd>?</kbd> + </dt> + <dd class="shortcut-description"> + {{ t('files', 'Show those shortcuts') }} + </dd> + </div> + </dl> </NcAppSettingsSection> </NcAppSettingsDialog> </template> <script> -import NcAppSettingsDialog from '@nextcloud/vue/dist/Components/NcAppSettingsDialog.js' -import NcAppSettingsSection from '@nextcloud/vue/dist/Components/NcAppSettingsSection.js' -import NcCheckboxRadioSwitch from '@nextcloud/vue/dist/Components/NcCheckboxRadioSwitch.js' -import Clipboard from 'vue-material-design-icons/Clipboard.vue' -import NcInputField from '@nextcloud/vue/dist/Components/NcInputField' -import Setting from '../components/Setting.vue' - -import { emit } from '@nextcloud/event-bus' -import { generateRemoteUrl, generateUrl } from '@nextcloud/router' import { getCurrentUser } from '@nextcloud/auth' -import { loadState } from '@nextcloud/initial-state' +import { getCapabilities } from '@nextcloud/capabilities' import { showError, showSuccess } from '@nextcloud/dialogs' -import { translate } from '@nextcloud/l10n' -import axios from '@nextcloud/axios' +import { loadState } from '@nextcloud/initial-state' +import { t } from '@nextcloud/l10n' +import { generateRemoteUrl, generateUrl } from '@nextcloud/router' +import { useHotKey } from '@nextcloud/vue/composables/useHotKey' -const userConfig = loadState('files', 'config', { - show_hidden: false, - crop_image_previews: true, -}) +import Clipboard from 'vue-material-design-icons/ContentCopy.vue' +import NcAppSettingsDialog from '@nextcloud/vue/components/NcAppSettingsDialog' +import NcAppSettingsSection from '@nextcloud/vue/components/NcAppSettingsSection' +import NcCheckboxRadioSwitch from '@nextcloud/vue/components/NcCheckboxRadioSwitch' +import NcInputField from '@nextcloud/vue/components/NcInputField' + +import { useUserConfigStore } from '../store/userconfig.ts' +import Setting from '../components/Setting.vue' export default { name: 'Settings', @@ -108,21 +319,55 @@ export default { }, }, - data() { + setup() { + const userConfigStore = useUserConfigStore() + const isSystemtagsEnabled = getCapabilities()?.systemtags?.enabled === true return { + isSystemtagsEnabled, + userConfigStore, + t, + } + }, - ...userConfig, - + data() { + return { // Settings API settings: window.OCA?.Files?.Settings?.settings || [], // Webdav infos webdavUrl: generateRemoteUrl('dav/files/' + encodeURIComponent(getCurrentUser()?.uid)), webdavDocs: 'https://docs.nextcloud.com/server/stable/go.php?to=user-webdav', + appPasswordUrl: generateUrl('/settings/user/security#generate-app-token-section'), webdavUrlCopied: false, + enableGridView: (loadState('core', 'config', [])['enable_non-accessible_features'] ?? true), + isTwoFactorEnabled: (loadState('files', 'isTwoFactorEnabled', false)), } }, + computed: { + userConfig() { + return this.userConfigStore.userConfig + }, + + sortedSettings() { + // Sort settings by name + return [...this.settings].sort((a, b) => { + if (a.order && b.order) { + return a.order - b.order + } + return a.name.localeCompare(b.name) + }) + }, + }, + + created() { + // ? opens the settings dialog on the keyboard shortcuts section + useHotKey('?', this.showKeyboardShortcuts, { + stop: true, + prevent: true, + }) + }, + beforeMount() { // Update the settings API entries state this.settings.forEach(setting => setting.open()) @@ -139,10 +384,7 @@ export default { }, setConfig(key, value) { - emit('files:config:updated', { key, value }) - axios.post(generateUrl('/apps/files/api/v1/config/' + key), { - value, - }) + this.userConfigStore.update(key, value) }, async copyCloudId() { @@ -156,17 +398,47 @@ export default { await navigator.clipboard.writeText(this.webdavUrl) this.webdavUrlCopied = true - showSuccess(t('files', 'Webdav URL copied to clipboard')) + showSuccess(t('files', 'WebDAV URL copied')) setTimeout(() => { this.webdavUrlCopied = false }, 5000) }, - t: translate, + async showKeyboardShortcuts() { + this.$emit('update:open', true) + + await this.$nextTick() + document.getElementById('settings-section_shortcuts').scrollIntoView({ + behavior: 'smooth', + inline: 'nearest', + }) + }, }, } </script> <style lang="scss" scoped> +.files-settings { + &__default-view { + margin-bottom: 0.5rem; + } +} + +.setting-link:hover { + text-decoration: underline; +} +.shortcut-key { + width: 160px; + // some shortcuts are too long to fit in one line + white-space: normal; + span { + // force portion of a shortcut on a new line for nicer display + white-space: nowrap; + } +} + +.webdav-url-input { + margin-block-end: 0.5rem; +} </style> |