diff options
Diffstat (limited to 'apps/files/src')
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' |