Merge pull request #56442 from nextcloud/refactor/files-settings
Some checks are pending
CodeQL Advanced / Analyze (actions) (push) Waiting to run
CodeQL Advanced / Analyze (javascript-typescript) (push) Waiting to run
Integration sqlite / changes (push) Waiting to run
Integration sqlite / integration-sqlite (stable32, 8.1, stable32, --tags ~@large files_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable32, 8.1, stable32, capabilities_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable32, 8.1, stable32, collaboration_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable32, 8.1, stable32, comments_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable32, 8.1, stable32, dav_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable32, 8.1, stable32, features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable32, 8.1, stable32, federation_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable32, 8.1, stable32, file_conversions) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable32, 8.1, stable32, filesdrop_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable32, 8.1, stable32, ldap_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable32, 8.1, stable32, openldap_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable32, 8.1, stable32, openldap_numerical_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable32, 8.1, stable32, remoteapi_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable32, 8.1, stable32, routing_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable32, 8.1, stable32, setup_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable32, 8.1, stable32, sharees_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable32, 8.1, stable32, sharing_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable32, 8.1, stable32, theming_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable32, 8.1, stable32, videoverification_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite-summary (push) Blocked by required conditions

[stable32] refactor(files): migrate app settings to new `NcForm*` components
This commit is contained in:
Stephan Orbaugh 2025-11-14 18:03:11 +01:00 committed by GitHub
commit 5ccf133cbd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
38 changed files with 364 additions and 409 deletions

View file

@ -0,0 +1,37 @@
<!--
- SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
- SPDX-License-Identifier: AGPL-3.0-or-later
-->
<script setup lang="ts">
import { t } from '@nextcloud/l10n'
import NcAppSettingsSection from '@nextcloud/vue/components/NcAppSettingsSection'
import NcFormBox from '@nextcloud/vue/components/NcFormBox'
import NcFormBoxSwitch from '@nextcloud/vue/components/NcFormBoxSwitch'
import { useUserConfigStore } from '../../store/userconfig.ts'
const store = useUserConfigStore()
</script>
<template>
<NcAppSettingsSection id="appearance" :name="t('files', 'Appearance')">
<NcFormBox>
<NcFormBoxSwitch
v-model="store.userConfig.show_hidden"
:label="t('files', 'Show hidden files')"
@update:modelValue="store.update('show_hidden', $event)" />
<NcFormBoxSwitch
v-model="store.userConfig.show_mime_column"
:label="t('files', 'Show file type column')"
@update:modelValue="store.update('show_mime_column', $event)" />
<NcFormBoxSwitch
v-model="store.userConfig.show_files_extensions"
:label="t('files', 'Show file extensions')"
@update:modelValue="store.update('show_files_extensions', $event)" />
<NcFormBoxSwitch
v-model="store.userConfig.crop_image_previews"
:label="t('files', 'Crop image previews')"
@update:modelValue="store.update('crop_image_previews', $event)" />
</NcFormBox>
</NcAppSettingsSection>
</template>

View file

@ -1,22 +0,0 @@
<!--
- SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors
- SPDX-License-Identifier: AGPL-3.0-or-later
-->
<template>
<div />
</template>
<script>
export default {
name: 'FilesAppSettingsEntry',
props: {
el: {
type: Function,
required: true,
},
},
mounted() {
this.$el.appendChild(this.el())
},
}
</script>

View file

@ -0,0 +1,44 @@
<!--
- SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
- SPDX-License-Identifier: AGPL-3.0-or-later
-->
<script setup lang="ts">
import { t } from '@nextcloud/l10n'
import NcAppSettingsSection from '@nextcloud/vue/components/NcAppSettingsSection'
import NcFormBox from '@nextcloud/vue/components/NcFormBox'
import NcFormBoxSwitch from '@nextcloud/vue/components/NcFormBoxSwitch'
import NcRadioGroup from '@nextcloud/vue/components/NcRadioGroup'
import NcRadioGroupButton from '@nextcloud/vue/components/NcRadioGroupButton'
import { useUserConfigStore } from '../../store/userconfig.ts'
const store = useUserConfigStore()
</script>
<template>
<NcAppSettingsSection
id="settings"
:name="t('files', 'General')">
<NcFormBox>
<NcFormBoxSwitch
v-model="store.userConfig.sort_favorites_first"
:label="t('files', 'Sort favorites first')"
@update:modelValue="store.update('sort_favorites_first', $event)" />
<NcFormBoxSwitch
v-model="store.userConfig.sort_folders_first"
:label="t('files', 'Sort folders before files')"
@update:modelValue="store.update('sort_folders_first', $event)" />
<NcFormBoxSwitch
v-model="store.userConfig.folder_tree"
:label="t('files', 'Enable folder tree view')"
@update:modelValue="store.update('folder_tree', $event)" />
</NcFormBox>
<NcRadioGroup
v-model="store.userConfig.default_view"
:label="t('files', 'Default view')"
@update:modelValue="store.update('default_view', $event)">
<NcRadioGroupButton :label="t('files', 'All files')" value="files" />
<NcRadioGroupButton :label="t('files', 'Personal files')" value="personal" />
</NcRadioGroup>
</NcAppSettingsSection>
</template>

View file

@ -0,0 +1,29 @@
<!--
- SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
- SPDX-License-Identifier: AGPL-3.0-or-later
-->
<script setup lang="ts">
import type Setting from '../../models/Setting.ts'
import { t } from '@nextcloud/l10n'
import NcAppSettingsSection from '@nextcloud/vue/components/NcAppSettingsSection'
import FilesAppSettingsLegacyApiEntry from './FilesAppSettingsLegacyApiEntry.vue'
const apiSettings = ((window.OCA?.Files?.Settings?.settings || []) as Setting[])
.sort((a, b) => {
if (a.order && b.order) {
return a.order - b.order
}
return a.name.localeCompare(b.name)
})
</script>
<template>
<NcAppSettingsSection
v-if="apiSettings.length !== 0"
id="api-settings"
:name="t('files', 'Additional settings')">
<FilesAppSettingsLegacyApiEntry v-for="setting in apiSettings" :key="setting.name" :setting="setting" />
</NcAppSettingsSection>
</template>

View file

@ -0,0 +1,26 @@
<!--
- SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
- SPDX-License-Identifier: AGPL-3.0-or-later
-->
<script setup lang="ts">
import type Setting from '../../models/Setting.ts'
import { onBeforeMount, onBeforeUnmount, onMounted, ref } from 'vue'
const props = defineProps<{
setting: Setting
}>()
const el = ref<HTMLElement>()
onBeforeMount(() => props.setting.open())
onBeforeUnmount(() => props.setting.close())
onMounted(() => {
el.value!.appendChild(props.setting.el())
})
</script>
<template>
<div ref="el" />
</template>

View file

@ -0,0 +1,29 @@
<!--
- SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
- SPDX-License-Identifier: AGPL-3.0-or-later
-->
<script lang="ts" setup>
import { t } from '@nextcloud/l10n'
import NcAppSettingsSection from '@nextcloud/vue/components/NcAppSettingsSection'
import NcFormBox from '@nextcloud/vue/components/NcFormBox'
import NcFormBoxSwitch from '@nextcloud/vue/components/NcFormBoxSwitch'
import { useUserConfigStore } from '../../store/userconfig.ts'
const store = useUserConfigStore()
</script>
<template>
<NcAppSettingsSection id="warning" :name="t('files', 'Warnings')">
<NcFormBox>
<NcFormBoxSwitch
v-model="store.userConfig.show_dialog_file_extension"
:label="t('files', 'Warn before changing a file extension')"
@update:modelValue="store.update('show_dialog_file_extension', $event)" />
<NcFormBoxSwitch
v-model="store.userConfig.show_dialog_deletion"
:label="t('files', 'Warn before deleting a file')"
@update:modelValue="store.update('show_dialog_deletion', $event)" />
</NcFormBox>
</NcAppSettingsSection>
</template>

View file

@ -0,0 +1,38 @@
<!--
- SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
- SPDX-License-Identifier: AGPL-3.0-or-later
-->
<script lang="ts" setup>
import { getCurrentUser } from '@nextcloud/auth'
import { loadState } from '@nextcloud/initial-state'
import { t } from '@nextcloud/l10n'
import { generateRemoteUrl, generateUrl } from '@nextcloud/router'
import NcAppSettingsSection from '@nextcloud/vue/components/NcAppSettingsSection'
import NcFormBox from '@nextcloud/vue/components/NcFormBox'
import NcFormBoxButton from '@nextcloud/vue/components/NcFormBoxButton'
import NcFormBoxCopyButton from '@nextcloud/vue/components/NcFormBoxCopyButton'
const webDavUrl = generateRemoteUrl('dav/files/' + encodeURIComponent(getCurrentUser()!.uid))
const webDavDocsUrl = 'https://docs.nextcloud.com/server/stable/go.php?to=user-webdav'
const appPasswordUrl = generateUrl('/settings/user/security#generate-app-token-section')
const isTwoFactorEnabled = loadState('files', 'isTwoFactorEnabled', false)
</script>
<template>
<NcAppSettingsSection id="webdav" name="WebDAV">
<NcFormBox>
<NcFormBoxCopyButton :label="t('files', 'WebDAV URL')" :value="webDavUrl" />
<NcFormBoxButton
v-if="isTwoFactorEnabled"
:label="t('files', 'Create an app password')"
:description="t('files', 'Required for WebDAV authentication because Two-Factor Authentication is enabled for this account.')"
:href="appPasswordUrl"
target="_blank" />
<NcFormBoxButton
:label="t('files', 'How to access files using WebDAV')"
:href="webDavDocsUrl"
target="_blank" />
</NcFormBox>
</NcAppSettingsSection>
</template>

View file

@ -4,13 +4,13 @@
*/
import type { IFileListFilter, Node, View } from '@nextcloud/files'
import type { SearchScope } from './types'
import type { SearchScope, UserConfig } from './types.ts'
declare module '@nextcloud/event-bus' {
export interface NextcloudEvents {
// mapping of 'event name' => 'event type'
'files:config:updated': { key: string, value: boolean }
'files:view-config:updated': { key: string, value: string|number|boolean, view: string }
'files:config:updated': { key: string, value: UserConfig[string] }
'files:view-config:updated': { key: string, value: string | number | boolean, view: string }
'files:favorites:removed': Node
'files:favorites:added': Node

View file

@ -2,15 +2,15 @@
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import { getCSPNonce } from '@nextcloud/auth'
import { PiniaVuePlugin } from 'pinia'
import Vue from 'vue'
import { getPinia } from './store/index.ts'
import FilesApp from './FilesApp.vue'
import router from './router/router'
import RouterService from './services/RouterService'
import SettingsModel from './models/Setting.js'
import SettingsModel from './models/Setting.ts'
import SettingsService from './services/Settings.js'
__webpack_nonce__ = getCSPNonce()

View file

@ -1,73 +0,0 @@
/**
* SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
export default class Setting {
_close
_el
_name
_open
_order
/**
* Create a new files app setting
*
* @since 19.0.0
* @param {string} name the name of this setting
* @param {object} component the component
* @param {Function} component.el function that returns an unmounted dom element to be added
* @param {Function} [component.open] callback for when setting is added
* @param {Function} [component.close] callback for when setting is closed
* @param {number} [component.order] the order of this setting, lower numbers are shown first
*/
constructor(name, { el, open, close, order }) {
this._name = name
this._el = el
this._open = open
this._close = close
this._order = order || 0
if (typeof this._open !== 'function') {
this._open = () => {}
}
if (typeof this._close !== 'function') {
this._close = () => {}
}
if (typeof this._el !== 'function') {
throw new Error('Setting must have an `el` function that returns a DOM element')
}
if (typeof this._name !== 'string') {
throw new Error('Setting must have a `name` string')
}
if (typeof this._order !== 'number') {
throw new Error('Setting must have an `order` number')
}
}
get name() {
return this._name
}
get el() {
return this._el
}
get open() {
return this._open
}
get close() {
return this._close
}
get order() {
return this._order
}
}

View file

@ -0,0 +1,69 @@
/**
* SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
export interface SettingData {
el: () => HTMLElement
open?: () => void
close?: () => void
order?: number
}
export default class Setting {
#name: string
#options: Required<SettingData>
/**
* Create a new files app setting
*
* @param name - The name of this setting
* @param options - The setting options
* @param options.el - Function that returns an unmounted dom element to be added
* @param options.open - Callback for when setting is added
* @param options.close - Callback for when setting is closed
* @param options.order - The order of this setting, lower numbers are shown first
* @since 19.0.0
*/
constructor(name: string, options: SettingData) {
this.#name = name
this.#options = {
open: () => {},
close: () => {},
order: 0,
...options,
}
if (typeof this.#options.el !== 'function') {
throw new Error('Setting must have an `el` function that returns a DOM element')
}
if (typeof this.#name !== 'string') {
throw new Error('Setting must have a `name` string')
}
if (typeof this.#options.order !== 'number') {
throw new Error('Setting must have an `order` number')
}
}
get name() {
return this.#name
}
get el() {
return this.#options.el
}
get open() {
return this.#options.open
}
get close() {
return this.#options.close
}
get order() {
return this.#options.order
}
}

View file

@ -14,6 +14,7 @@ import axios from '@nextcloud/axios'
const initialUserConfig = loadState<UserConfig>('files', 'config', {
crop_image_previews: true,
default_view: 'files',
folder_tree: true,
grid_view: false,
show_files_extensions: true,
show_hidden: false,
@ -33,7 +34,7 @@ export const useUserConfigStore = defineStore('userconfig', () => {
* @param key The config key
* @param value The new value
*/
function onUpdate(key: string, value: boolean): void {
function onUpdate<Key extends string>(key: Key, value: UserConfig[Key]): void {
set(userConfig.value, key, value)
}
@ -42,7 +43,7 @@ export const useUserConfigStore = defineStore('userconfig', () => {
* @param key The config key
* @param value The new value
*/
async function update(key: string, value: boolean): Promise<void> {
async function update<Key extends string>(key: Key, value: UserConfig[Key]): 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 }), {

View file

@ -54,13 +54,14 @@ export interface UserConfig {
crop_image_previews: boolean
default_view: 'files' | 'personal'
folder_tree: boolean
grid_view: boolean
show_files_extensions: boolean
show_hidden: boolean
show_mime_column: boolean
sort_favorites_first: boolean
sort_folders_first: boolean
show_files_extensions: boolean
show_hidden: boolean
show_mime_column: boolean
show_dialog_deletion: boolean
show_dialog_file_extension: boolean,
}

View file

@ -2,288 +2,61 @@
- SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
- SPDX-License-Identifier: AGPL-3.0-or-later
-->
<template>
<NcAppSettingsDialog :open="open"
:show-navigation="true"
:name="t('files', 'Files settings')"
@update:open="onClose">
<!-- Settings API-->
<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="appearance" :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 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>
</NcAppSettingsSection>
<!-- Settings API-->
<NcAppSettingsSection v-if="settings.length !== 0"
id="more-settings"
:name="t('files', 'Additional settings')">
<FilesAppSettingsEntry v-for="setting in settings" :key="setting.name" :el="setting.el" />
</NcAppSettingsSection>
<!-- Webdav URL-->
<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')"
:value="webdavUrl"
class="webdav-url-input"
readonly="readonly"
type="url"
@focus="$event.target.select()"
@trailing-button-click="copyCloudId">
<template #trailing-button-icon>
<Clipboard :size="20" />
</template>
</NcInputField>
<em>
<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>
<FilesAppSettingsShortcuts />
</NcAppSettingsDialog>
</template>
<script>
import { getCurrentUser } from '@nextcloud/auth'
import { getCapabilities } from '@nextcloud/capabilities'
import { showError, showSuccess } from '@nextcloud/dialogs'
import { loadState } from '@nextcloud/initial-state'
<script setup lang="ts">
import { t } from '@nextcloud/l10n'
import { generateRemoteUrl, generateUrl } from '@nextcloud/router'
import { useHotKey } from '@nextcloud/vue/composables/useHotKey'
import Clipboard from 'vue-material-design-icons/ContentCopy.vue'
import { nextTick } from '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 FilesAppSettingsEntry from '../components/FilesAppSettings/FilesAppSettingsEntry.vue'
import FilesAppSettingsAppearance from '../components/FilesAppSettings/FilesAppSettingsAppearance.vue'
import FilesAppSettingsGeneral from '../components/FilesAppSettings/FilesAppSettingsGeneral.vue'
import FilesAppSettingsLegacyApi from '../components/FilesAppSettings/FilesAppSettingsLegacyApi.vue'
import FilesAppSettingsShortcuts from '../components/FilesAppSettings/FilesAppSettingsShortcuts.vue'
import { useUserConfigStore } from '../store/userconfig.ts'
import FilesAppSettingsWarnings from '../components/FilesAppSettings/FilesAppSettingsWarnings.vue'
import FilesAppSettingsWebDav from '../components/FilesAppSettings/FilesAppSettingsWebDav.vue'
export default {
name: 'Settings',
components: {
Clipboard,
FilesAppSettingsEntry,
FilesAppSettingsShortcuts,
NcAppSettingsDialog,
NcAppSettingsSection,
NcCheckboxRadioSwitch,
NcInputField,
},
defineProps<{
open: boolean
}>()
props: {
open: {
type: Boolean,
default: false,
},
},
const emit = defineEmits<{
(e: 'close'): void
(e: 'update:open', open: boolean): void
}>()
setup() {
const userConfigStore = useUserConfigStore()
const isSystemtagsEnabled = getCapabilities()?.systemtags?.enabled === true
return {
isSystemtagsEnabled,
userConfigStore,
t,
}
},
// ? opens the settings dialog on the keyboard shortcuts section
useHotKey('?', showKeyboardShortcuts, {
stop: true,
prevent: true,
})
data() {
return {
// Settings API
settings: window.OCA?.Files?.Settings?.settings || [],
/**
* Opens the settings dialog and scrolls to the keyboard shortcuts section
*/
async function showKeyboardShortcuts() {
emit('update:open', true)
// 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())
},
beforeUnmount() {
// Update the settings API entries state
this.settings.forEach(setting => setting.close())
},
methods: {
onClose() {
this.$emit('close')
},
setConfig(key, value) {
this.userConfigStore.update(key, value)
},
async copyCloudId() {
document.querySelector('input#webdav-url-input').select()
if (!navigator.clipboard) {
// Clipboard API not available
showError(t('files', 'Clipboard is not available'))
return
}
await navigator.clipboard.writeText(this.webdavUrl)
this.webdavUrlCopied = true
showSuccess(t('files', 'WebDAV URL copied'))
setTimeout(() => {
this.webdavUrlCopied = false
}, 5000)
},
async showKeyboardShortcuts() {
this.$emit('update:open', true)
await this.$nextTick()
document.getElementById('settings-section_shortcuts').scrollIntoView({
behavior: 'smooth',
inline: 'nearest',
})
},
},
await nextTick()
document.getElementById('settings-section_keyboard-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>
<template>
<NcAppSettingsDialog
:legacy="false"
:name="t('files', 'Files settings')"
no-version
:open="open"
show-navigation
@update:open="emit('close')">
<FilesAppSettingsGeneral />
<FilesAppSettingsAppearance />
<FilesAppSettingsLegacyApi />
<FilesAppSettingsWarnings />
<FilesAppSettingsWebDav />
<FilesAppSettingsShortcuts />
</NcAppSettingsDialog>
</template>

View file

@ -149,10 +149,13 @@ function 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 })
})
cy.findByRole('switch', { name: /show hidden files/i })
.as('hiddenFiles')
.scrollIntoView()
cy.get('@hiddenFiles')
.should('not.be.checked')
.check({ force: true })
// Close the dialog
cy.get('[data-cy-files-navigation-settings] button[aria-label="Close"]').click()
}

2
dist/1489-1489.js vendored Normal file

File diff suppressed because one or more lines are too long

1
dist/1489-1489.js.map vendored Normal file

File diff suppressed because one or more lines are too long

1
dist/1489-1489.js.map.license vendored Symbolic link
View file

@ -0,0 +1 @@
1489-1489.js.license

2
dist/2005-2005.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1 +0,0 @@
2005-2005.js.license

4
dist/core-common.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

4
dist/files-init.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

4
dist/files-main.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long