aboutsummaryrefslogtreecommitdiffstats
path: root/apps/files/src
diff options
context:
space:
mode:
Diffstat (limited to 'apps/files/src')
-rw-r--r--apps/files/src/actions/deleteAction.ts2
-rw-r--r--apps/files/src/actions/moveOrCopyAction.ts4
-rw-r--r--apps/files/src/actions/renameAction.ts2
-rw-r--r--apps/files/src/actions/viewInFolderAction.ts9
-rw-r--r--apps/files/src/components/FileEntry/FileEntryName.vue11
-rw-r--r--apps/files/src/components/FileEntry/FileEntryPreview.vue2
-rw-r--r--apps/files/src/components/FileListFilter/FileListFilterModified.vue6
-rw-r--r--apps/files/src/components/FileListFilter/FileListFilterType.vue6
-rw-r--r--apps/files/src/components/FilesListVirtual.vue6
-rw-r--r--apps/files/src/components/NavigationQuota.vue2
-rw-r--r--apps/files/src/composables/useNavigation.spec.ts7
-rw-r--r--apps/files/src/newMenu/newFolder.ts7
-rw-r--r--apps/files/src/store/userconfig.ts1
-rw-r--r--apps/files/src/types.ts1
-rw-r--r--apps/files/src/views/FilesList.vue4
-rw-r--r--apps/files/src/views/Navigation.vue2
-rw-r--r--apps/files/src/views/Settings.vue30
-rw-r--r--apps/files/src/views/favorites.spec.ts27
-rw-r--r--apps/files/src/views/favorites.ts14
-rw-r--r--apps/files/src/views/files.ts2
-rw-r--r--apps/files/src/views/folderTree.ts2
-rw-r--r--apps/files/src/views/personal-files.ts2
22 files changed, 98 insertions, 51 deletions
diff --git a/apps/files/src/actions/deleteAction.ts b/apps/files/src/actions/deleteAction.ts
index 63f7fd442c5..3e9e441a63c 100644
--- a/apps/files/src/actions/deleteAction.ts
+++ b/apps/files/src/actions/deleteAction.ts
@@ -10,7 +10,7 @@ import PQueue from 'p-queue'
import CloseSvg from '@mdi/svg/svg/close.svg?raw'
import NetworkOffSvg from '@mdi/svg/svg/network-off.svg?raw'
-import TrashCanSvg from '@mdi/svg/svg/trash-can.svg?raw'
+import TrashCanSvg from '@mdi/svg/svg/trash-can-outline.svg?raw'
import { TRASHBIN_VIEW_ID } from '../../../files_trashbin/src/files_views/trashbinView.ts'
import { askConfirmation, canDisconnectOnly, canUnshareOnly, deleteNode, displayName, shouldAskForConfirmation } from './deleteUtils.ts'
diff --git a/apps/files/src/actions/moveOrCopyAction.ts b/apps/files/src/actions/moveOrCopyAction.ts
index 724b65fa515..af68120bb1b 100644
--- a/apps/files/src/actions/moveOrCopyAction.ts
+++ b/apps/files/src/actions/moveOrCopyAction.ts
@@ -16,8 +16,8 @@ import { openConflictPicker, hasConflict } from '@nextcloud/upload'
import { basename, join } from 'path'
import Vue from 'vue'
-import CopyIconSvg from '@mdi/svg/svg/folder-multiple.svg?raw'
-import FolderMoveSvg from '@mdi/svg/svg/folder-move.svg?raw'
+import CopyIconSvg from '@mdi/svg/svg/folder-multiple-outline.svg?raw'
+import FolderMoveSvg from '@mdi/svg/svg/folder-move-outline.svg?raw'
import { MoveCopyAction, canCopy, canMove, getQueue } from './moveOrCopyActionUtils'
import { getContents } from '../services/Files'
diff --git a/apps/files/src/actions/renameAction.ts b/apps/files/src/actions/renameAction.ts
index d421d18c473..715ecb7563e 100644
--- a/apps/files/src/actions/renameAction.ts
+++ b/apps/files/src/actions/renameAction.ts
@@ -5,7 +5,7 @@
import { emit } from '@nextcloud/event-bus'
import { Permission, type Node, FileAction, View } from '@nextcloud/files'
import { translate as t } from '@nextcloud/l10n'
-import PencilSvg from '@mdi/svg/svg/pencil.svg?raw'
+import PencilSvg from '@mdi/svg/svg/pencil-outline.svg?raw'
import { getPinia } from '../store'
import { useFilesStore } from '../store/files'
import { dirname } from 'path'
diff --git a/apps/files/src/actions/viewInFolderAction.ts b/apps/files/src/actions/viewInFolderAction.ts
index eb145dc409f..b22393c1152 100644
--- a/apps/files/src/actions/viewInFolderAction.ts
+++ b/apps/files/src/actions/viewInFolderAction.ts
@@ -2,10 +2,13 @@
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
-import { Node, FileType, Permission, View, FileAction } from '@nextcloud/files'
-import { translate as t } from '@nextcloud/l10n'
-import FolderMoveSvg from '@mdi/svg/svg/folder-move.svg?raw'
+import type { Node, View } from '@nextcloud/files'
+
import { isPublicShare } from '@nextcloud/sharing/public'
+import { FileAction, FileType, Permission } from '@nextcloud/files'
+import { t } from '@nextcloud/l10n'
+
+import FolderMoveSvg from '@mdi/svg/svg/folder-move-outline.svg?raw'
export const action = new FileAction({
id: 'view-in-folder',
diff --git a/apps/files/src/components/FileEntry/FileEntryName.vue b/apps/files/src/components/FileEntry/FileEntryName.vue
index 2fec9e5d556..418f9581eb6 100644
--- a/apps/files/src/components/FileEntry/FileEntryName.vue
+++ b/apps/files/src/components/FileEntry/FileEntryName.vue
@@ -30,7 +30,7 @@
<span class="files-list__row-name-text" dir="auto">
<!-- Keep the filename stuck to the extension to avoid whitespace rendering issues-->
<span class="files-list__row-name-" v-text="basename" />
- <span class="files-list__row-name-ext" v-text="extension" />
+ <span v-if="userConfigStore.userConfig.show_files_extensions" class="files-list__row-name-ext" v-text="extension" />
</span>
</component>
</template>
@@ -46,11 +46,12 @@ import { defineComponent, inject } from 'vue'
import NcTextField from '@nextcloud/vue/components/NcTextField'
-import { useNavigation } from '../../composables/useNavigation'
+import { getFilenameValidity } from '../../utils/filenameValidity.ts'
import { useFileListWidth } from '../../composables/useFileListWidth.ts'
-import { useRouteParameters } from '../../composables/useRouteParameters.ts'
+import { useNavigation } from '../../composables/useNavigation.ts'
import { useRenamingStore } from '../../store/renaming.ts'
-import { getFilenameValidity } from '../../utils/filenameValidity.ts'
+import { useRouteParameters } from '../../composables/useRouteParameters.ts'
+import { useUserConfigStore } from '../../store/userconfig.ts'
import logger from '../../logger.ts'
export default defineComponent({
@@ -95,6 +96,7 @@ export default defineComponent({
const { directory } = useRouteParameters()
const filesListWidth = useFileListWidth()
const renamingStore = useRenamingStore()
+ const userConfigStore = useUserConfigStore()
const defaultFileAction = inject<FileAction | undefined>('defaultFileAction')
@@ -105,6 +107,7 @@ export default defineComponent({
filesListWidth,
renamingStore,
+ userConfigStore,
}
},
diff --git a/apps/files/src/components/FileEntry/FileEntryPreview.vue b/apps/files/src/components/FileEntry/FileEntryPreview.vue
index 506677b49af..3d0fffe7584 100644
--- a/apps/files/src/components/FileEntry/FileEntryPreview.vue
+++ b/apps/files/src/components/FileEntry/FileEntryPreview.vue
@@ -64,7 +64,7 @@ import FolderIcon from 'vue-material-design-icons/Folder.vue'
import FolderOpenIcon from 'vue-material-design-icons/FolderOpen.vue'
import KeyIcon from 'vue-material-design-icons/Key.vue'
import LinkIcon from 'vue-material-design-icons/Link.vue'
-import NetworkIcon from 'vue-material-design-icons/Network.vue'
+import NetworkIcon from 'vue-material-design-icons/NetworkOutline.vue'
import TagIcon from 'vue-material-design-icons/Tag.vue'
import PlayCircleIcon from 'vue-material-design-icons/PlayCircle.vue'
diff --git a/apps/files/src/components/FileListFilter/FileListFilterModified.vue b/apps/files/src/components/FileListFilter/FileListFilterModified.vue
index f3a968dd56e..3a843b2bc3e 100644
--- a/apps/files/src/components/FileListFilter/FileListFilterModified.vue
+++ b/apps/files/src/components/FileListFilter/FileListFilterModified.vue
@@ -7,7 +7,7 @@
:filter-name="t('files', 'Modified')"
@reset-filter="resetFilter">
<template #icon>
- <NcIconSvgWrapper :path="mdiCalendarRange" />
+ <NcIconSvgWrapper :path="mdiCalendarRangeOutline" />
</template>
<NcActionButton v-for="preset of timePresets"
:key="preset.id"
@@ -25,7 +25,7 @@
import type { PropType } from 'vue'
import type { ITimePreset } from '../../filters/ModifiedFilter.ts'
-import { mdiCalendarRange } from '@mdi/js'
+import { mdiCalendarRangeOutline } from '@mdi/js'
import { translate as t } from '@nextcloud/l10n'
import { defineComponent } from 'vue'
@@ -50,7 +50,7 @@ export default defineComponent({
setup() {
return {
// icons used in template
- mdiCalendarRange,
+ mdiCalendarRangeOutline,
}
},
diff --git a/apps/files/src/components/FileListFilter/FileListFilterType.vue b/apps/files/src/components/FileListFilter/FileListFilterType.vue
index 53e46b48f8c..d3ad791513f 100644
--- a/apps/files/src/components/FileListFilter/FileListFilterType.vue
+++ b/apps/files/src/components/FileListFilter/FileListFilterType.vue
@@ -8,7 +8,7 @@
:filter-name="t('files', 'Type')"
@reset-filter="resetFilter">
<template #icon>
- <NcIconSvgWrapper :path="mdiFile" />
+ <NcIconSvgWrapper :path="mdiFileOutline" />
</template>
<NcActionButton v-for="fileType of typePresets"
:key="fileType.id"
@@ -27,7 +27,7 @@
import type { PropType } from 'vue'
import type { ITypePreset } from '../../filters/TypeFilter.ts'
-import { mdiFile } from '@mdi/js'
+import { mdiFileOutline } from '@mdi/js'
import { translate as t } from '@nextcloud/l10n'
import { defineComponent } from 'vue'
@@ -57,7 +57,7 @@ export default defineComponent({
setup() {
return {
- mdiFile,
+ mdiFileOutline,
t,
}
},
diff --git a/apps/files/src/components/FilesListVirtual.vue b/apps/files/src/components/FilesListVirtual.vue
index fbf614caede..47b8ef19b19 100644
--- a/apps/files/src/components/FilesListVirtual.vue
+++ b/apps/files/src/components/FilesListVirtual.vue
@@ -888,7 +888,7 @@ export default defineComponent({
}
.files-list__row-size {
- width: calc(var(--row-height) * 1.5);
+ width: calc(var(--row-height) * 2);
// Right align content/text
justify-content: flex-end;
}
@@ -898,11 +898,11 @@ export default defineComponent({
}
.files-list__row-mime {
- width: calc(var(--row-height) * 2.5);
+ width: calc(var(--row-height) * 3.5);
}
.files-list__row-column-custom {
- width: calc(var(--row-height) * 2);
+ width: calc(var(--row-height) * 2.5);
}
}
}
diff --git a/apps/files/src/components/NavigationQuota.vue b/apps/files/src/components/NavigationQuota.vue
index fd10af1c495..46c8e5c9af4 100644
--- a/apps/files/src/components/NavigationQuota.vue
+++ b/apps/files/src/components/NavigationQuota.vue
@@ -33,7 +33,7 @@ import { subscribe } from '@nextcloud/event-bus'
import { translate } from '@nextcloud/l10n'
import axios from '@nextcloud/axios'
-import ChartPie from 'vue-material-design-icons/ChartPie.vue'
+import ChartPie from 'vue-material-design-icons/ChartPieOutline.vue'
import NcAppNavigationItem from '@nextcloud/vue/components/NcAppNavigationItem'
import NcProgressBar from '@nextcloud/vue/components/NcProgressBar'
diff --git a/apps/files/src/composables/useNavigation.spec.ts b/apps/files/src/composables/useNavigation.spec.ts
index 569e61825e1..b9eb671a181 100644
--- a/apps/files/src/composables/useNavigation.spec.ts
+++ b/apps/files/src/composables/useNavigation.spec.ts
@@ -29,6 +29,7 @@ describe('Composables: useNavigation', () => {
describe('currentView', () => {
beforeEach(() => {
+ // eslint-disable-next-line import/namespace
navigation = new nextcloudFiles.Navigation()
spy.mockImplementation(() => navigation)
})
@@ -39,6 +40,7 @@ describe('Composables: useNavigation', () => {
})
it('should return already active navigation', async () => {
+ // eslint-disable-next-line import/namespace
const view = new nextcloudFiles.View({ getContents: () => Promise.reject(new Error()), icon: '<svg></svg>', id: 'view-1', name: 'My View 1', order: 0 })
navigation.register(view)
navigation.setActive(view)
@@ -48,6 +50,7 @@ describe('Composables: useNavigation', () => {
})
it('should be reactive on updating active navigation', async () => {
+ // eslint-disable-next-line import/namespace
const view = new nextcloudFiles.View({ getContents: () => Promise.reject(new Error()), icon: '<svg></svg>', id: 'view-1', name: 'My View 1', order: 0 })
navigation.register(view)
const wrapper = mount(TestComponent)
@@ -63,6 +66,7 @@ describe('Composables: useNavigation', () => {
describe('views', () => {
beforeEach(() => {
+ // eslint-disable-next-line import/namespace
navigation = new nextcloudFiles.Navigation()
spy.mockImplementation(() => navigation)
})
@@ -73,6 +77,7 @@ describe('Composables: useNavigation', () => {
})
it('should return already registered views', () => {
+ // eslint-disable-next-line import/namespace
const view = new nextcloudFiles.View({ getContents: () => Promise.reject(new Error()), icon: '<svg></svg>', id: 'view-1', name: 'My View 1', order: 0 })
// register before mount
navigation.register(view)
@@ -82,7 +87,9 @@ describe('Composables: useNavigation', () => {
})
it('should be reactive on registering new views', () => {
+ // eslint-disable-next-line import/namespace
const view = new nextcloudFiles.View({ getContents: () => Promise.reject(new Error()), icon: '<svg></svg>', id: 'view-1', name: 'My View 1', order: 0 })
+ // eslint-disable-next-line import/namespace
const view2 = new nextcloudFiles.View({ getContents: () => Promise.reject(new Error()), icon: '<svg></svg>', id: 'view-2', name: 'My View 2', order: 1 })
// register before mount
diff --git a/apps/files/src/newMenu/newFolder.ts b/apps/files/src/newMenu/newFolder.ts
index 9a8badb4eb7..bc82d389e54 100644
--- a/apps/files/src/newMenu/newFolder.ts
+++ b/apps/files/src/newMenu/newFolder.ts
@@ -12,7 +12,7 @@ import { showError, showInfo, showSuccess } from '@nextcloud/dialogs'
import { translate as t } from '@nextcloud/l10n'
import axios from '@nextcloud/axios'
-import FolderPlusSvg from '@mdi/svg/svg/folder-plus.svg?raw'
+import FolderPlusSvg from '@mdi/svg/svg/folder-plus-outline.svg?raw'
import { newNodeName } from '../utils/newNodeDialog'
import logger from '../logger'
@@ -43,8 +43,11 @@ export const entry = {
id: 'newFolder',
displayName: t('files', 'New folder'),
enabled: (context: Folder) => Boolean(context.permissions & Permission.CREATE) && Boolean(context.permissions & Permission.READ),
- iconSvgInline: FolderPlusSvg,
+
+ // Make the svg icon color match the primary element color
+ iconSvgInline: FolderPlusSvg.replace(/viewBox/gi, 'style="color: var(--color-primary-element)" viewBox'),
order: 0,
+
async handler(context: Folder, content: Node[]) {
const name = await newNodeName(t('files', 'New folder'), content)
if (name === null) {
diff --git a/apps/files/src/store/userconfig.ts b/apps/files/src/store/userconfig.ts
index 54e9a75eb8b..48fe01d5134 100644
--- a/apps/files/src/store/userconfig.ts
+++ b/apps/files/src/store/userconfig.ts
@@ -15,6 +15,7 @@ const initialUserConfig = loadState<UserConfig>('files', 'config', {
crop_image_previews: true,
default_view: 'files',
grid_view: false,
+ show_files_extensions: true,
show_hidden: false,
show_mime_column: true,
sort_favorites_first: true,
diff --git a/apps/files/src/types.ts b/apps/files/src/types.ts
index 6757b7f1f45..0096ecc0fdb 100644
--- a/apps/files/src/types.ts
+++ b/apps/files/src/types.ts
@@ -55,6 +55,7 @@ export interface UserConfig {
crop_image_previews: boolean
default_view: 'files' | 'personal'
grid_view: boolean
+ show_files_extensions: boolean
show_hidden: boolean
show_mime_column: boolean
sort_favorites_first: boolean
diff --git a/apps/files/src/views/FilesList.vue b/apps/files/src/views/FilesList.vue
index 15a7f93ddf0..3f993e24958 100644
--- a/apps/files/src/views/FilesList.vue
+++ b/apps/files/src/views/FilesList.vue
@@ -176,12 +176,12 @@ import NcEmptyContent from '@nextcloud/vue/components/NcEmptyContent'
import NcIconSvgWrapper from '@nextcloud/vue/components/NcIconSvgWrapper'
import NcLoadingIcon from '@nextcloud/vue/components/NcLoadingIcon'
-import AccountPlusIcon from 'vue-material-design-icons/AccountPlus.vue'
+import AccountPlusIcon from 'vue-material-design-icons/AccountPlusOutline.vue'
import IconAlertCircleOutline from 'vue-material-design-icons/AlertCircleOutline.vue'
import IconReload from 'vue-material-design-icons/Reload.vue'
import LinkIcon from 'vue-material-design-icons/Link.vue'
import ListViewIcon from 'vue-material-design-icons/FormatListBulletedSquare.vue'
-import ViewGridIcon from 'vue-material-design-icons/ViewGrid.vue'
+import ViewGridIcon from 'vue-material-design-icons/ViewGridOutline.vue'
import { action as sidebarAction } from '../actions/sidebarAction.ts'
import { useFileListWidth } from '../composables/useFileListWidth.ts'
diff --git a/apps/files/src/views/Navigation.vue b/apps/files/src/views/Navigation.vue
index c424a0d74b8..0f3c3647c6e 100644
--- a/apps/files/src/views/Navigation.vue
+++ b/apps/files/src/views/Navigation.vue
@@ -47,7 +47,7 @@ import { getNavigation } from '@nextcloud/files'
import { t, getCanonicalLocale, getLanguage } from '@nextcloud/l10n'
import { defineComponent } from 'vue'
-import IconCog from 'vue-material-design-icons/Cog.vue'
+import IconCog from 'vue-material-design-icons/CogOutline.vue'
import NcAppNavigation from '@nextcloud/vue/components/NcAppNavigation'
import NcAppNavigationItem from '@nextcloud/vue/components/NcAppNavigationItem'
import NcAppNavigationList from '@nextcloud/vue/components/NcAppNavigationList'
diff --git a/apps/files/src/views/Settings.vue b/apps/files/src/views/Settings.vue
index 49a348eabc3..0838d308af9 100644
--- a/apps/files/src/views/Settings.vue
+++ b/apps/files/src/views/Settings.vue
@@ -29,7 +29,6 @@
{{ 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)">
@@ -40,6 +39,15 @@
@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', 'Enable folder tree') }}
+ </NcCheckboxRadioSwitch>
+ </NcAppSettingsSection>
+
+ <!-- Visual settings -->
+ <NcAppSettingsSection id="settings" :name="t('files', 'Visual settings')">
<NcCheckboxRadioSwitch data-cy-files-settings-setting="show_hidden"
:checked="userConfig.show_hidden"
@update:checked="setConfig('show_hidden', $event)">
@@ -55,10 +63,10 @@
@update:checked="setConfig('crop_image_previews', $event)">
{{ t('files', 'Crop image previews') }}
</NcCheckboxRadioSwitch>
- <NcCheckboxRadioSwitch data-cy-files-settings-setting="folder_tree"
- :checked="userConfig.folder_tree"
- @update:checked="setConfig('folder_tree', $event)">
- {{ t('files', 'Enable folder tree') }}
+ <NcCheckboxRadioSwitch data-cy-files-settings-setting="show_files_extensions"
+ :checked="userConfig.show_files_extensions"
+ @update:checked="setConfig('show_files_extensions', $event)">
+ {{ t('files', 'Show files extensions') }}
</NcCheckboxRadioSwitch>
</NcAppSettingsSection>
@@ -79,6 +87,7 @@
:success="webdavUrlCopied"
:trailing-button-label="t('files', 'Copy to clipboard')"
:value="webdavUrl"
+ class="webdav-url-input"
readonly="readonly"
type="url"
@focus="$event.target.select()"
@@ -92,13 +101,13 @@
:href="webdavDocs"
target="_blank"
rel="noreferrer noopener">
- {{ t('files', 'Use this address to access your Files via WebDAV') }} ↗
+ {{ t('files', 'Use this address to access your Files via WebDAV.') }} ↗
</a>
</em>
<br>
- <em>
+ <em v-if="isTwoFactorEnabled">
<a class="setting-link" :href="appPasswordUrl">
- {{ t('files', 'If you have enabled 2FA, you must create and use a new app password by clicking here.') }} ↗
+ {{ 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>
@@ -333,6 +342,7 @@ export default {
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)),
}
},
@@ -429,4 +439,8 @@ export default {
white-space: nowrap;
}
}
+
+.webdav-url-input {
+ margin-block-end: 0.5rem;
+}
</style>
diff --git a/apps/files/src/views/favorites.spec.ts b/apps/files/src/views/favorites.spec.ts
index 64c3df0500a..f793eb9f54c 100644
--- a/apps/files/src/views/favorites.spec.ts
+++ b/apps/files/src/views/favorites.spec.ts
@@ -7,6 +7,7 @@
import type { Folder as CFolder, Navigation } from '@nextcloud/files'
import * as filesUtils from '@nextcloud/files'
+import * as filesDavUtils from '@nextcloud/files/dav'
import { CancelablePromise } from 'cancelable-promise'
import { basename } from 'path'
import { beforeEach, describe, expect, test, vi } from 'vitest'
@@ -16,6 +17,7 @@ import { action } from '../actions/favoriteAction'
import * as favoritesService from '../services/Favorites'
import { registerFavoritesView } from './favorites'
+// eslint-disable-next-line import/namespace
const { Folder, getNavigation } = filesUtils
vi.mock('@nextcloud/axios')
@@ -43,7 +45,7 @@ describe('Favorites view definition', () => {
test('Default empty favorite view', async () => {
vi.spyOn(eventBus, 'subscribe')
- vi.spyOn(filesUtils, 'getFavoriteNodes').mockReturnValue(CancelablePromise.resolve([]))
+ vi.spyOn(filesDavUtils, 'getFavoriteNodes').mockReturnValue(CancelablePromise.resolve([]))
vi.spyOn(favoritesService, 'getContents').mockReturnValue(CancelablePromise.resolve({ folder: {} as CFolder, contents: [] }))
await registerFavoritesView()
@@ -89,8 +91,14 @@ describe('Favorites view definition', () => {
source: 'http://nextcloud.local/remote.php/dav/files/admin/foo/bar',
owner: 'admin',
}),
+ new Folder({
+ id: 4,
+ root: '/files/admin',
+ source: 'http://nextcloud.local/remote.php/dav/files/admin/foo/bar/yabadaba',
+ owner: 'admin',
+ }),
]
- vi.spyOn(filesUtils, 'getFavoriteNodes').mockReturnValue(CancelablePromise.resolve(favoriteFolders))
+ vi.spyOn(filesDavUtils, 'getFavoriteNodes').mockReturnValue(CancelablePromise.resolve(favoriteFolders))
vi.spyOn(favoritesService, 'getContents').mockReturnValue(CancelablePromise.resolve({ folder: {} as CFolder, contents: [] }))
await registerFavoritesView()
@@ -98,9 +106,12 @@ describe('Favorites view definition', () => {
const favoriteFoldersViews = Navigation.views.filter(view => view.parent === 'favorites')
// one main view and 3 children
- expect(Navigation.views.length).toBe(4)
+ expect(Navigation.views.length).toBe(5)
expect(favoritesView).toBeDefined()
- expect(favoriteFoldersViews.length).toBe(3)
+ expect(favoriteFoldersViews.length).toBe(4)
+
+ // Sorted by basename: bar, bar, foo
+ const expectedOrder = [2, 0, 1, 3]
favoriteFolders.forEach((folder, index) => {
const favoriteView = favoriteFoldersViews[index]
@@ -108,7 +119,7 @@ describe('Favorites view definition', () => {
expect(favoriteView?.id).toBeDefined()
expect(favoriteView?.name).toBe(basename(folder.path))
expect(favoriteView?.icon).toMatch(/<svg.+<\/svg>/)
- expect(favoriteView?.order).toBe(index)
+ expect(favoriteView?.order).toBe(expectedOrder[index])
expect(favoriteView?.params).toStrictEqual({
dir: folder.path,
fileid: String(folder.fileid),
@@ -132,7 +143,7 @@ describe('Dynamic update of favorite folders', () => {
test('Add a favorite folder creates a new entry in the navigation', async () => {
vi.spyOn(eventBus, 'emit')
- vi.spyOn(filesUtils, 'getFavoriteNodes').mockReturnValue(CancelablePromise.resolve([]))
+ vi.spyOn(filesDavUtils, 'getFavoriteNodes').mockReturnValue(CancelablePromise.resolve([]))
vi.spyOn(favoritesService, 'getContents').mockReturnValue(CancelablePromise.resolve({ folder: {} as CFolder, contents: [] }))
await registerFavoritesView()
@@ -160,7 +171,7 @@ describe('Dynamic update of favorite folders', () => {
test('Remove a favorite folder remove the entry from the navigation column', async () => {
vi.spyOn(eventBus, 'emit')
- vi.spyOn(filesUtils, 'getFavoriteNodes').mockReturnValue(CancelablePromise.resolve([
+ vi.spyOn(filesDavUtils, 'getFavoriteNodes').mockReturnValue(CancelablePromise.resolve([
new Folder({
id: 42,
root: '/files/admin',
@@ -211,7 +222,7 @@ describe('Dynamic update of favorite folders', () => {
test('Renaming a favorite folder updates the navigation', async () => {
vi.spyOn(eventBus, 'emit')
- vi.spyOn(filesUtils, 'getFavoriteNodes').mockReturnValue(CancelablePromise.resolve([]))
+ vi.spyOn(filesDavUtils, 'getFavoriteNodes').mockReturnValue(CancelablePromise.resolve([]))
vi.spyOn(favoritesService, 'getContents').mockReturnValue(CancelablePromise.resolve({ folder: {} as CFolder, contents: [] }))
await registerFavoritesView()
diff --git a/apps/files/src/views/favorites.ts b/apps/files/src/views/favorites.ts
index cadc7704e14..cac776507ef 100644
--- a/apps/files/src/views/favorites.ts
+++ b/apps/files/src/views/favorites.ts
@@ -4,13 +4,15 @@
*/
import type { Folder, Node } from '@nextcloud/files'
+import { FileType, View, getNavigation } from '@nextcloud/files'
+import { getCanonicalLocale, getLanguage, t } from '@nextcloud/l10n'
+import { getFavoriteNodes } from '@nextcloud/files/dav'
import { subscribe } from '@nextcloud/event-bus'
-import { FileType, View, getFavoriteNodes, getNavigation } from '@nextcloud/files'
-import { getLanguage, translate as t } from '@nextcloud/l10n'
-import { client } from '../services/WebdavClient.ts'
+
import FolderSvg from '@mdi/svg/svg/folder.svg?raw'
-import StarSvg from '@mdi/svg/svg/star.svg?raw'
+import StarSvg from '@mdi/svg/svg/star-outline.svg?raw'
+import { client } from '../services/WebdavClient.ts'
import { getContents } from '../services/Favorites'
import { hashCode } from '../utils/hashUtils'
import logger from '../logger'
@@ -118,7 +120,7 @@ export const registerFavoritesView = async () => {
* update the order property of the existing views
*/
const updateAndSortViews = function() {
- favoriteFolders.sort((a, b) => a.path.localeCompare(b.path, getLanguage(), { ignorePunctuation: true }))
+ favoriteFolders.sort((a, b) => a.basename.localeCompare(b.basename, [getLanguage(), getCanonicalLocale()], { ignorePunctuation: true, numeric: true, usage: 'sort' }))
favoriteFolders.forEach((folder, index) => {
const view = favoriteFoldersViews.find((view) => view.id === generateIdFromPath(folder.path))
if (view) {
@@ -176,4 +178,6 @@ export const registerFavoritesView = async () => {
removePathFromFavorites(favoriteFolder.path)
addToFavorites(node)
}
+
+ updateAndSortViews()
}
diff --git a/apps/files/src/views/files.ts b/apps/files/src/views/files.ts
index 95450f0d71a..a94aab0f14b 100644
--- a/apps/files/src/views/files.ts
+++ b/apps/files/src/views/files.ts
@@ -10,7 +10,7 @@ import { getContents } from '../services/Files.ts'
import { useActiveStore } from '../store/active.ts'
import { defaultView } from '../utils/filesViews.ts'
-import FolderSvg from '@mdi/svg/svg/folder.svg?raw'
+import FolderSvg from '@mdi/svg/svg/folder-outline.svg?raw'
export const VIEW_ID = 'files'
diff --git a/apps/files/src/views/folderTree.ts b/apps/files/src/views/folderTree.ts
index c38e4721316..bdff1659080 100644
--- a/apps/files/src/views/folderTree.ts
+++ b/apps/files/src/views/folderTree.ts
@@ -13,7 +13,7 @@ import { isSamePath } from '@nextcloud/paths'
import { loadState } from '@nextcloud/initial-state'
import FolderSvg from '@mdi/svg/svg/folder.svg?raw'
-import FolderMultipleSvg from '@mdi/svg/svg/folder-multiple.svg?raw'
+import FolderMultipleSvg from '@mdi/svg/svg/folder-multiple-outline.svg?raw'
import {
folderTreeId,
diff --git a/apps/files/src/views/personal-files.ts b/apps/files/src/views/personal-files.ts
index 36888eb7ee0..241582057d1 100644
--- a/apps/files/src/views/personal-files.ts
+++ b/apps/files/src/views/personal-files.ts
@@ -8,7 +8,7 @@ import { View, getNavigation } from '@nextcloud/files'
import { getContents } from '../services/PersonalFiles.ts'
import { defaultView, hasPersonalFilesView } from '../utils/filesViews.ts'
-import AccountIcon from '@mdi/svg/svg/account.svg?raw'
+import AccountIcon from '@mdi/svg/svg/account-outline.svg?raw'
export const VIEW_ID = 'personal'