mirror of
https://github.com/nextcloud/server.git
synced 2026-06-09 00:32:29 -04:00
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
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:
commit
5ccf133cbd
38 changed files with 364 additions and 409 deletions
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
6
apps/files/src/eventbus.d.ts
vendored
6
apps/files/src/eventbus.d.ts
vendored
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
}
|
||||
69
apps/files/src/models/Setting.ts
Normal file
69
apps/files/src/models/Setting.ts
Normal 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
|
||||
}
|
||||
}
|
||||
|
|
@ -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 }), {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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
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
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
1
dist/1489-1489.js.map.license
vendored
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
1489-1489.js.license
|
||||
2
dist/2005-2005.js
vendored
2
dist/2005-2005.js
vendored
File diff suppressed because one or more lines are too long
1
dist/2005-2005.js.map
vendored
1
dist/2005-2005.js.map
vendored
File diff suppressed because one or more lines are too long
1
dist/2005-2005.js.map.license
vendored
1
dist/2005-2005.js.map.license
vendored
|
|
@ -1 +0,0 @@
|
|||
2005-2005.js.license
|
||||
4
dist/core-common.js
vendored
4
dist/core-common.js
vendored
File diff suppressed because one or more lines are too long
2
dist/core-common.js.map
vendored
2
dist/core-common.js.map
vendored
File diff suppressed because one or more lines are too long
4
dist/dav-settings-example-content.js
vendored
4
dist/dav-settings-example-content.js
vendored
File diff suppressed because one or more lines are too long
2
dist/dav-settings-example-content.js.map
vendored
2
dist/dav-settings-example-content.js.map
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
4
dist/files-init.js
vendored
4
dist/files-init.js
vendored
File diff suppressed because one or more lines are too long
2
dist/files-init.js.map
vendored
2
dist/files-init.js.map
vendored
File diff suppressed because one or more lines are too long
4
dist/files-main.js
vendored
4
dist/files-main.js
vendored
File diff suppressed because one or more lines are too long
2
dist/files-main.js.map
vendored
2
dist/files-main.js.map
vendored
File diff suppressed because one or more lines are too long
4
dist/files_sharing-files_sharing_tab.js
vendored
4
dist/files_sharing-files_sharing_tab.js
vendored
File diff suppressed because one or more lines are too long
2
dist/files_sharing-files_sharing_tab.js.map
vendored
2
dist/files_sharing-files_sharing_tab.js.map
vendored
File diff suppressed because one or more lines are too long
4
dist/settings-users-3239.js
vendored
4
dist/settings-users-3239.js
vendored
File diff suppressed because one or more lines are too long
2
dist/settings-users-3239.js.map
vendored
2
dist/settings-users-3239.js.map
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
Loading…
Reference in a new issue