mirror of
https://github.com/nextcloud/server.git
synced 2026-10-20 07:19:44 +02:00
Signed-off-by: nextcloud-command <nextcloud-command@users.noreply.github.com>
1 line
140 KiB
Plaintext
1 line
140 KiB
Plaintext
{"version":3,"mappings":"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","names":["AutoRenewSvg","queue","PQueue","requestConversion","fileId","targetMimeType","axios","generateOcsUrl","convertFiles","fileIds","conversions","toast","showLoading","t","results","failed","result","messages","logger","showError","n","showSuccess","currentDir","newPaths","path","fetchNode","file","emit","newFileId","error","convertFile","newFile","isAxiosError","ACTION_CONVERT","registerConvertActions","actions","getCapabilities","to","from","displayName","generateIconSvg","nodes","folder","isPublicShare","Permission","node","registerFileAction","context","action","mime","generateUrl","CloseSvg","NetworkOffSvg","isTrashbinEnabled","canUnshareOnly","canDisconnectOnly","isMixedUnshareAndDelete","hasSharedItems","hasDeleteItems","isAllFiles","FileType","isAllFolders","view","shouldAskForConfirmation","useUserConfigStore","pinia","askConfirmation","message","resolve","decision","deleteNode","TRASHBIN_VIEW_ID","ACTION_DELETE","TrashCanSvg","loadState","permission","trigger","confirm","promises","ArrowDownSvg","DefaultType","isDownloadable","downloadNodes","directory","getCurrentDirectory","triggerDownload","url","name","hiddenElement","longestCommonPath","first","second","firstSegments","secondSegments","base","index","segment","filenames","filesStore","useFilesStore","pathsStore","usePathsStore","ACTION_FAVORITE","shouldFavorite","StarOutlineSvg","StarSvg","willFavorite","favoriteNode","encodePath","isFavoritesRoot","svgFolder","FolderSvg","SEARCH_VIEW_ID","dir","LaptopSvg","IconWeb","localClientEnabled","isSyncable","contents","attemptOpenLocalClient","openLocalClient","confirmLocalEditDialog","files","entry","getViewer","link","getCurrentUser","dialog","DialogBuilder","PencilSvg","ACTION_RENAME","parentPermissions","dirname","registerSidebarFavoriteAction","registerSidebarAction","starSvg","starOutlineSvg","FolderEyeSvg","FilenameFilter","FileListFilter","subscribe","query","scope","queryParts","displayname","part","chips","store","useSearchStore","registerFilenameFilter","registerFileListFilter","HiddenFilesFilter","key","value","registerHiddenFilesFilter","svgCalendarRangeOutline","startOfToday","startOfLastWeek","timePresets","time","timeValue","props","__props","selectedOption","ref","watch","preset","timeRange","onMounted","f","onReset","onUnmounted","_createElementBlock","_Fragment","_renderList","_createVNode","_unref","NcButton","$event","_createTextVNode","_toDisplayString","_createBlock","NcDateTimePicker","tagName","ModifiedFilter","registerModifiedFilter","WrappedComponent","defineCustomElement","FileListFilterModified","svgFileOutline","svgDocument","svgPDF","svgPresentation","svgSpreadsheet","svgImage","svgMovie","svgAudio","typePresets","colorize","svg","color","selectedOptions","resetFilter","onDeselect","id","event","option","toggleOption","selected","o","_normalizeClass","$style","fileType","NcIconSvgWrapper","TypeFilter","mimeList","previous","current","presets","presetId","filtered","registerTypeFilter","FileListFilterType","FolderPlusSvg","content","newNodeName","fileid","source","createNewFolder","Folder","basename","root","encodedSource","response","TemplatePickerVue","defineAsyncComponent","__vitePreload","TemplatePicker","getTemplatePicker","mountingPoint","createApp","args","h","registerTemplateEntries","templates","provider","addNewFileMenuEntry","templatePicker","PlusSvg","templatesEnabled","templatesPath","initTemplatesFolder","templatePath","join","data","removeNewFileMenuEntry","registerPreviewServiceWorker","getRootUrl","registration","getContents","options","filesContents","getFavoriteNodes","client","getRemoteURL","getRootPath","generateFavoriteFolderView","View","generateIdFromPath","hashCode","registerFavoritesView","Navigation","getNavigation","controller","favoriteFolders","favoriteFoldersViews","addToFavorites","removePathFromFavorites","updateNodeFromFavorites","updateAndSortViews","b","getLanguage","getCanonicalLocale","favoriteFolder","isFolderTreeEnabled","showHiddenFiles","folderTreeView","folderTreeId","FolderMultipleSvg","treeView","tree","getFolderTreeNodes","registerNodeViews","onCreateNode","onDeleteNode","onMoveNode","onUserConfigUpdated","registerFolderTreeView","views","isRegistered","generateNodeView","expanded","getSourceParent","getLoadChildViews","updateTreeChildren","cachedNodes","folders","removeFolderView","viewId","removeFolderViewSource","oldSource","newPath","sourceRoot","oldPath","childViews","isSamePath","AccountIcon","currentUserId","isPersonalFile","sharedMountTypes","mountType","getFiles","VIEW_ID","registerPersonalFilesView","hasPersonalFilesView","defaultView","lastTwoWeeksTimestamp","recentLimit","filterHidden","getRecentSearch","stat","resultToNode","registerRecentView","HistorySvg","deleteAction","downloadAction","editLocallyAction","favoriteAction","moveOrCopyAction","openFolderAction","openInFilesAction","renameAction","sidebarAction","viewInFolderAction","newFolderEntry","newTemplatesFolder","registerFilesView","registerSearchView","registerDavProperty","initLivePhotos","getNewFileMenu","target","prop"],"ignoreList":[0,3,4,7,10,13,14,16,19,23,26,27,28,29,30,31,32,33,36,39,45],"sources":["../node_modules/@mdi/svg/svg/autorenew.svg?raw","../build/frontend/apps/files/src/actions/convertUtils.ts","../build/frontend/apps/files/src/actions/convertAction.ts","../node_modules/@mdi/svg/svg/close.svg?raw","../node_modules/@mdi/svg/svg/network-off.svg?raw","../build/frontend/apps/files/src/actions/deleteUtils.ts","../build/frontend/apps/files/src/actions/deleteAction.ts","../node_modules/@mdi/svg/svg/arrow-down.svg?raw","../build/frontend/apps/files/src/actions/downloadAction.ts","../build/frontend/apps/files/src/actions/favoriteAction.ts","../node_modules/@mdi/svg/svg/folder.svg?raw","../build/frontend/apps/files/src/actions/openFolderAction.ts","../build/frontend/apps/files/src/actions/openInFilesAction.ts","../node_modules/@mdi/svg/svg/laptop.svg?raw","../node_modules/@mdi/svg/svg/web.svg?raw","../build/frontend/apps/files/src/actions/openLocallyAction.ts","../node_modules/@mdi/svg/svg/pencil-outline.svg?raw","../build/frontend/apps/files/src/actions/renameAction.ts","../build/frontend/apps/files/src/actions/sidebarFavoriteAction.ts","../node_modules/@mdi/svg/svg/folder-eye-outline.svg?raw","../build/frontend/apps/files/src/actions/viewInFolderAction.ts","../build/frontend/apps/files/src/filters/FilenameFilter.ts","../build/frontend/apps/files/src/filters/HiddenFilesFilter.ts","../node_modules/@mdi/svg/svg/calendar-range-outline.svg?raw","../build/frontend/apps/files/src/components/FileListFilter/FileListFilterModified.vue","../build/frontend/apps/files/src/filters/ModifiedFilter.ts","../node_modules/@mdi/svg/svg/file-outline.svg?raw","../node_modules/@mdi/svg/svg/file-document.svg?raw","../node_modules/@mdi/svg/svg/file-pdf-box.svg?raw","../node_modules/@mdi/svg/svg/file-presentation-box.svg?raw","../node_modules/@mdi/svg/svg/file-table-box.svg?raw","../node_modules/@mdi/svg/svg/image.svg?raw","../node_modules/@mdi/svg/svg/movie.svg?raw","../node_modules/@mdi/svg/svg/music.svg?raw","../build/frontend/apps/files/src/components/FileListFilter/FileListFilterType.vue","../build/frontend/apps/files/src/filters/TypeFilter.ts","../node_modules/@mdi/svg/svg/folder-plus-outline.svg?raw","../build/frontend/apps/files/src/newMenu/newFolder.ts","../build/frontend/apps/files/src/newMenu/newFromTemplate.ts","../node_modules/@mdi/svg/svg/plus.svg?raw","../build/frontend/apps/files/src/newMenu/newTemplatesFolder.ts","../build/frontend/apps/files/src/services/ServiceWorker.js","../build/frontend/apps/files/src/services/Favorites.ts","../build/frontend/apps/files/src/views/favorites.ts","../build/frontend/apps/files/src/views/folderTree.ts","../node_modules/@mdi/svg/svg/account-outline.svg?raw","../build/frontend/apps/files/src/services/PersonalFiles.ts","../build/frontend/apps/files/src/views/personal-files.ts","../build/frontend/apps/files/src/services/Recent.ts","../build/frontend/apps/files/src/views/recent.ts","../build/frontend/apps/files/src/init.ts"],"sourcesContent":["export default \"<svg xmlns=\\\"http://www.w3.org/2000/svg\\\" id=\\\"mdi-autorenew\\\" viewBox=\\\"0 0 24 24\\\"><path d=\\\"M12,6V9L16,5L12,1V4A8,8 0 0,0 4,12C4,13.57 4.46,15.03 5.24,16.26L6.7,14.8C6.25,13.97 6,13 6,12A6,6 0 0,1 12,6M18.76,7.74L17.3,9.2C17.74,10.04 18,11 18,12A6,6 0 0,1 12,18V15L8,19L12,23V20A8,8 0 0,0 20,12C20,10.43 19.54,8.97 18.76,7.74Z\\\" /></svg>\"","/**\n * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport type { AxiosError, AxiosResponse } from '@nextcloud/axios'\nimport type { OCSResponse } from '@nextcloud/typings/ocs'\n\nimport axios, { isAxiosError } from '@nextcloud/axios'\nimport { showError, showLoading, showSuccess } from '@nextcloud/dialogs'\nimport { emit } from '@nextcloud/event-bus'\nimport { n, t } from '@nextcloud/l10n'\nimport { generateOcsUrl } from '@nextcloud/router'\nimport PQueue from 'p-queue'\nimport { fetchNode } from '../services/WebdavClient.ts'\nimport { logger } from '../utils/logger.ts'\n\ntype ConversionResponse = {\n\tpath: string\n\tfileId: number\n}\n\ninterface PromiseRejectedResult<T> {\n\tstatus: 'rejected'\n\treason: T\n}\n\ntype PromiseSettledResult<T, E> = PromiseFulfilledResult<T> | PromiseRejectedResult<E>\ntype ConversionSuccess = AxiosResponse<OCSResponse<ConversionResponse>>\ntype ConversionError = AxiosError<OCSResponse<ConversionResponse>>\n\nconst queue = new PQueue({ concurrency: 5 })\n/**\n *\n * @param fileId\n * @param targetMimeType\n */\nfunction requestConversion(fileId: number, targetMimeType: string): Promise<AxiosResponse> {\n\treturn axios.post(generateOcsUrl('/apps/files/api/v1/convert'), {\n\t\tfileId,\n\t\ttargetMimeType,\n\t})\n}\n\n/**\n *\n * @param fileIds\n * @param targetMimeType\n */\nexport async function convertFiles(fileIds: number[], targetMimeType: string) {\n\tconst conversions = fileIds.map((fileId) => queue.add(() => requestConversion(fileId, targetMimeType)))\n\n\t// Start conversion\n\tconst toast = showLoading(t('files', 'Converting files …'))\n\n\t// Handle results\n\ttry {\n\t\tconst results = await Promise.allSettled(conversions) as PromiseSettledResult<ConversionSuccess, ConversionError>[]\n\t\tconst failed = results.filter((result) => result.status === 'rejected') as PromiseRejectedResult<ConversionError>[]\n\t\tif (failed.length > 0) {\n\t\t\tconst messages = failed.map((result) => result.reason?.response?.data?.ocs?.meta?.message)\n\t\t\tlogger.error('Failed to convert files', { fileIds, targetMimeType, messages })\n\n\t\t\t// If all failed files have the same error message, show it\n\t\t\tif (new Set(messages).size === 1 && typeof messages[0] === 'string') {\n\t\t\t\tshowError(t('files', 'Failed to convert files: {message}', { message: messages[0] }))\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif (failed.length === fileIds.length) {\n\t\t\t\tshowError(t('files', 'All files failed to be converted'))\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\t// A single file failed and if we have a message for the failed file, show it\n\t\t\tif (failed.length === 1 && messages[0]) {\n\t\t\t\tshowError(t('files', 'One file could not be converted: {message}', { message: messages[0] }))\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\t// We already check above when all files failed\n\t\t\t// if we're here, we have a mix of failed and successful files\n\t\t\tshowError(n('files', '%n file could not be converted', '%n files could not be converted', failed.length))\n\t\t\tshowSuccess(n('files', '%n file converted', '%n files converted', fileIds.length - failed.length))\n\t\t\treturn\n\t\t}\n\n\t\t// All files converted\n\t\tshowSuccess(t('files', 'Files converted'))\n\n\t\t// Extract files that are within the current directory\n\t\t// in batch mode, you might have files from different directories\n\t\t// ⚠️, let's get the actual current dir, as the one from the action\n\t\t// might have changed as the user navigated away\n\t\tconst currentDir = window.OCP.Files.Router.query.dir as string\n\t\tconst newPaths = results\n\t\t\t.filter((result) => result.status === 'fulfilled')\n\t\t\t.map((result) => result.value.data.ocs.data.path)\n\t\t\t.filter((path) => path.startsWith(currentDir))\n\n\t\t// Fetch the new files\n\t\tlogger.debug('Files to fetch', { newPaths })\n\t\tconst newFiles = await Promise.all(newPaths.map((path) => fetchNode(path)))\n\n\t\t// Inform the file list about the new files\n\t\tnewFiles.forEach((file) => emit('files:node:created', file))\n\n\t\t// Switch to the new files\n\t\tconst firstSuccess = results[0] as PromiseFulfilledResult<ConversionSuccess>\n\t\tconst newFileId = firstSuccess.value.data.ocs.data.fileId\n\t\twindow.OCP.Files.Router.goToRoute(null, { ...window.OCP.Files.Router.params, fileid: newFileId.toString() }, window.OCP.Files.Router.query)\n\t} catch (error) {\n\t\t// Should not happen as we use allSettled and handle errors above\n\t\tshowError(t('files', 'Failed to convert files'))\n\t\tlogger.error('Failed to convert files', { fileIds, targetMimeType, error })\n\t} finally {\n\t\t// Hide loading toast\n\t\ttoast.hideToast()\n\t}\n}\n\n/**\n *\n * @param fileId\n * @param targetMimeType\n */\nexport async function convertFile(fileId: number, targetMimeType: string) {\n\tconst toast = showLoading(t('files', 'Converting file …'))\n\n\ttry {\n\t\tconst result = await queue.add(() => requestConversion(fileId, targetMimeType)) as AxiosResponse<OCSResponse<ConversionResponse>>\n\t\tshowSuccess(t('files', 'File successfully converted'))\n\n\t\t// Inform the file list about the new file\n\t\tconst newFile = await fetchNode(result.data.ocs.data.path)\n\t\temit('files:node:created', newFile)\n\n\t\t// Switch to the new file\n\t\tconst newFileId = result.data.ocs.data.fileId\n\t\twindow.OCP.Files.Router.goToRoute(null, { ...window.OCP.Files.Router.params, fileid: newFileId.toString() }, window.OCP.Files.Router.query)\n\t} catch (error) {\n\t\t// If the server returned an error message, show it\n\t\tif (isAxiosError(error) && error.response?.data?.ocs?.meta?.message) {\n\t\t\tshowError(t('files', 'Failed to convert file: {message}', { message: error.response.data.ocs.meta.message }))\n\t\t\treturn\n\t\t}\n\n\t\tlogger.error('Failed to convert file', { fileId, targetMimeType, error })\n\t\tshowError(t('files', 'Failed to convert file'))\n\t} finally {\n\t\t// Hide loading toast\n\t\ttoast.hideToast()\n\t}\n}\n","/*!\n * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport type { IFileAction } from '@nextcloud/files'\n\nimport AutoRenewSvg from '@mdi/svg/svg/autorenew.svg?raw'\nimport { getCapabilities } from '@nextcloud/capabilities'\nimport { Permission, registerFileAction } from '@nextcloud/files'\nimport { t } from '@nextcloud/l10n'\nimport { generateUrl } from '@nextcloud/router'\nimport { isPublicShare } from '@nextcloud/sharing/public'\nimport { convertFile, convertFiles } from './convertUtils.ts'\n\ntype ConversionsProvider = {\n\tfrom: string\n\tto: string\n\tdisplayName: string\n}\n\nexport const ACTION_CONVERT = 'convert'\n\n/**\n * Registers the convert actions based on the capabilities provided by the server.\n */\nexport function registerConvertActions() {\n\t// Generate sub actions\n\tconst convertProviders = getCapabilities()?.files?.file_conversions as ConversionsProvider[] ?? []\n\tconst actions = convertProviders.map(({ to, from, displayName }) => ({\n\t\tid: `convert-${from}-${to}`,\n\t\tdisplayName: () => t('files', 'Save as {displayName}', { displayName }),\n\t\ticonSvgInline: () => generateIconSvg(to),\n\t\tenabled: ({ nodes, folder }) => {\n\t\t\tif (isPublicShare() && !(folder.permissions & Permission.CREATE)) {\n\t\t\t\t// cannot create the converted file in a public share if we don't have create permissions\n\t\t\t\treturn false\n\t\t\t}\n\t\t\t// Conversion reads the source file, so it requires read permission\n\t\t\tif (nodes.some((node) => (node.permissions & Permission.READ) === 0)) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\t// Check that all nodes have the same mime type\n\t\t\treturn nodes.every((node) => from === node.mime)\n\t\t},\n\n\t\tasync exec({ nodes }) {\n\t\t\tif (!nodes[0]) {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\t// If we're here, we know that the node has a fileid\n\t\t\tconvertFile(nodes[0].fileid as number, to)\n\n\t\t\t// Silently terminate, we'll handle the UI in the background\n\t\t\treturn null\n\t\t},\n\n\t\tasync execBatch({ nodes }) {\n\t\t\tconst fileIds = nodes.map((node) => node.fileid).filter(Boolean) as number[]\n\t\t\tconvertFiles(fileIds, to)\n\n\t\t\t// Silently terminate, we'll handle the UI in the background\n\t\t\treturn Array(nodes.length).fill(null)\n\t\t},\n\n\t\tparent: ACTION_CONVERT,\n\t} satisfies IFileAction))\n\n\t// Register main action\n\tregisterFileAction({\n\t\tid: ACTION_CONVERT,\n\t\tdisplayName: () => t('files', 'Save as …'),\n\t\ticonSvgInline: () => AutoRenewSvg,\n\t\tenabled: (context) => {\n\t\t\treturn actions.some((action) => action.enabled!(context))\n\t\t},\n\t\tasync exec() {\n\t\t\treturn null\n\t\t},\n\t\torder: 25,\n\t} satisfies IFileAction)\n\n\t// Register sub actions\n\tactions.forEach(registerFileAction)\n}\n\n/**\n * Generates an SVG icon for a given mime type by using the server's mime icon endpoint.\n *\n * @param mime - The mime type to generate the icon for\n */\nexport function generateIconSvg(mime: string) {\n\t// Generate icon based on mime type\n\tconst url = generateUrl('/core/mimeicon?mime=' + encodeURIComponent(mime))\n\treturn `<svg width=\"32\" height=\"32\" viewBox=\"0 0 32 32\"\n\t\txmlns=\"http://www.w3.org/2000/svg\">\n\t\t<image href=\"${url}\" height=\"32\" width=\"32\" />\n\t</svg>`\n}\n","export default \"<svg xmlns=\\\"http://www.w3.org/2000/svg\\\" id=\\\"mdi-close\\\" viewBox=\\\"0 0 24 24\\\"><path d=\\\"M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41Z\\\" /></svg>\"","export default \"<svg xmlns=\\\"http://www.w3.org/2000/svg\\\" id=\\\"mdi-network-off\\\" viewBox=\\\"0 0 24 24\\\"><path d=\\\"M1,5.27L5,9.27V15A2,2 0 0,0 7,17H11V19H10A1,1 0 0,0 9,20H2V22H9A1,1 0 0,0 10,23H14A1,1 0 0,0 15,22H17.73L19.73,24L21,22.72L2.28,4L1,5.27M15,20A1,1 0 0,0 14,19H13V17.27L15.73,20H15M17.69,16.87L5.13,4.31C5.41,3.55 6.14,3 7,3H17A2,2 0 0,1 19,5V15C19,15.86 18.45,16.59 17.69,16.87M22,20V21.18L20.82,20H22Z\\\" /></svg>\"","/*!\n * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport type { INode, IView } from '@nextcloud/files'\nimport type { Capabilities } from '../types.ts'\n\nimport axios from '@nextcloud/axios'\nimport { getCapabilities } from '@nextcloud/capabilities'\nimport { emit } from '@nextcloud/event-bus'\nimport { FileType } from '@nextcloud/files'\nimport { n, t } from '@nextcloud/l10n'\nimport { pinia } from '../store/index.ts'\nimport { useUserConfigStore } from '../store/userconfig.ts'\n\nexport const isTrashbinEnabled = () => (getCapabilities() as Capabilities)?.files?.undelete === true\n\n/**\n * @param nodes\n */\nexport function canUnshareOnly(nodes: INode[]) {\n\treturn nodes.every((node) => node.attributes['is-mount-root'] === true\n\t\t&& node.attributes['mount-type'] === 'shared')\n}\n\n/**\n *\n * @param nodes\n */\nexport function canDisconnectOnly(nodes: INode[]) {\n\treturn nodes.every((node) => node.attributes['is-mount-root'] === true\n\t\t&& node.attributes['mount-type'] === 'external')\n}\n\n/**\n *\n * @param nodes\n */\nexport function isMixedUnshareAndDelete(nodes: INode[]) {\n\tif (nodes.length === 1) {\n\t\treturn false\n\t}\n\n\tconst hasSharedItems = nodes.some((node) => canUnshareOnly([node]))\n\tconst hasDeleteItems = nodes.some((node) => !canUnshareOnly([node]))\n\treturn hasSharedItems && hasDeleteItems\n}\n\n/**\n *\n * @param nodes\n */\nexport function isAllFiles(nodes: INode[]) {\n\treturn !nodes.some((node) => node.type !== FileType.File)\n}\n\n/**\n *\n * @param nodes\n */\nexport function isAllFolders(nodes: INode[]) {\n\treturn !nodes.some((node) => node.type !== FileType.Folder)\n}\n\n/**\n * Get the display name for the delete action\n *\n * @param context - The context\n * @param context.nodes - The nodes to delete\n * @param context.view - The current view\n */\nexport function displayName({ nodes, view }: { nodes: INode[], view: IView }) {\n\t/**\n\t * If those nodes are all the root node of a\n\t * share, we can only unshare them.\n\t */\n\tif (canUnshareOnly(nodes)) {\n\t\tif (nodes.length === 1) {\n\t\t\treturn t('files', 'Leave this share')\n\t\t}\n\t\treturn t('files', 'Leave these shares')\n\t}\n\n\t/**\n\t * If those nodes are all the root node of an\n\t * external storage, we can only disconnect it.\n\t */\n\tif (canDisconnectOnly(nodes)) {\n\t\tif (nodes.length === 1) {\n\t\t\treturn t('files', 'Disconnect storage')\n\t\t}\n\t\treturn t('files', 'Disconnect storages')\n\t}\n\n\t/**\n\t * If we're in the trashbin, we can only delete permanently\n\t */\n\tif (view.id === 'trashbin' || !isTrashbinEnabled()) {\n\t\treturn t('files', 'Delete permanently')\n\t}\n\n\t/**\n\t * If we're in the sharing view, we can only unshare\n\t */\n\tif (isMixedUnshareAndDelete(nodes)) {\n\t\treturn t('files', 'Delete and unshare')\n\t}\n\n\t/**\n\t * If we're only selecting files, use proper wording\n\t */\n\tif (isAllFiles(nodes)) {\n\t\tif (nodes.length === 1) {\n\t\t\treturn t('files', 'Delete file')\n\t\t}\n\t\treturn t('files', 'Delete files')\n\t}\n\n\t/**\n\t * If we're only selecting folders, use proper wording\n\t */\n\tif (isAllFolders(nodes)) {\n\t\tif (nodes.length === 1) {\n\t\t\treturn t('files', 'Delete folder')\n\t\t}\n\t\treturn t('files', 'Delete folders')\n\t}\n\n\treturn t('files', 'Delete')\n}\n\n/**\n *\n */\nexport function shouldAskForConfirmation() {\n\tconst userConfig = useUserConfigStore(pinia)\n\treturn userConfig.userConfig.show_dialog_deletion !== false\n}\n\n/**\n *\n * @param nodes\n * @param view\n */\nexport async function askConfirmation(nodes: INode[], view: IView) {\n\tconst message = view.id === 'trashbin' || !isTrashbinEnabled()\n\t\t? n('files', 'You are about to permanently delete {count} item', 'You are about to permanently delete {count} items', nodes.length, { count: nodes.length })\n\t\t: n('files', 'You are about to delete {count} item', 'You are about to delete {count} items', nodes.length, { count: nodes.length })\n\n\treturn new Promise<boolean>((resolve) => {\n\t\t// TODO: Use the new dialog API\n\t\twindow.OC.dialogs.confirmDestructive(\n\t\t\tmessage,\n\t\t\tt('files', 'Confirm deletion'),\n\t\t\t{\n\t\t\t\ttype: window.OC.dialogs.YES_NO_BUTTONS,\n\t\t\t\tconfirm: displayName({ nodes, view }),\n\t\t\t\tconfirmClasses: 'error',\n\t\t\t\tcancel: t('files', 'Cancel'),\n\t\t\t},\n\t\t\t(decision: boolean) => {\n\t\t\t\tresolve(decision)\n\t\t\t},\n\t\t)\n\t})\n}\n\n/**\n *\n * @param node\n */\nexport async function deleteNode(node: INode) {\n\tawait axios.delete(node.encodedSource)\n\n\t// Let's delete even if it's moved to the trashbin\n\t// since it has been removed from the current view\n\t// and changing the view will trigger a reload anyway.\n\temit('files:node:deleted', node)\n}\n","/*!\n * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport type { IFileAction } from '@nextcloud/files'\nimport type { TriggeredActionContext } from '../utils/actionUtils.ts'\n\nimport CloseSvg from '@mdi/svg/svg/close.svg?raw'\nimport NetworkOffSvg from '@mdi/svg/svg/network-off.svg?raw'\nimport TrashCanSvg from '@mdi/svg/svg/trash-can-outline.svg?raw'\nimport { Permission } from '@nextcloud/files'\nimport { loadState } from '@nextcloud/initial-state'\nimport { t } from '@nextcloud/l10n'\nimport PQueue from 'p-queue'\nimport { logger } from '../utils/logger.ts'\nimport { askConfirmation, canDisconnectOnly, canUnshareOnly, deleteNode, displayName, shouldAskForConfirmation } from './deleteUtils.ts'\n\n// TODO: once the files app is migrated to the new frontend use the import instead:\n// import { TRASHBIN_VIEW_ID } from '../../../files_trashbin/src/files_views/trashbinView.ts'\nconst TRASHBIN_VIEW_ID = 'trashbin'\n\nconst queue = new PQueue({ concurrency: 5 })\n\nexport const ACTION_DELETE = 'delete'\n\nexport const action: IFileAction = {\n\tid: ACTION_DELETE,\n\tdisplayName,\n\ticonSvgInline: ({ nodes }) => {\n\t\tif (canUnshareOnly(nodes)) {\n\t\t\treturn CloseSvg\n\t\t}\n\n\t\tif (canDisconnectOnly(nodes)) {\n\t\t\treturn NetworkOffSvg\n\t\t}\n\n\t\treturn TrashCanSvg\n\t},\n\n\tenabled({ nodes, view }) {\n\t\tif (view.id === TRASHBIN_VIEW_ID) {\n\t\t\tconst config = loadState('files_trashbin', 'config', { allow_delete: true })\n\t\t\tif (config.allow_delete === false) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\n\t\treturn nodes.length > 0 && nodes\n\t\t\t.map((node) => node.permissions)\n\t\t\t.every((permission) => (permission & Permission.DELETE) !== 0)\n\t},\n\n\tasync exec({ nodes, view, trigger }: TriggeredActionContext) {\n\t\ttry {\n\t\t\tlet confirm = true\n\n\t\t\t// Deleting via the hotkey is easy to trigger by accident, so always confirm it\n\t\t\tif (shouldAskForConfirmation() || trigger === 'hotkey') {\n\t\t\t\tconfirm = await askConfirmation([nodes[0]], view)\n\t\t\t}\n\n\t\t\t// If the user cancels the deletion, we don't want to do anything\n\t\t\tif (confirm === false) {\n\t\t\t\treturn null\n\t\t\t}\n\n\t\t\tawait deleteNode(nodes[0])\n\n\t\t\treturn true\n\t\t} catch (error) {\n\t\t\tlogger.error('Error while deleting a file', { error, source: nodes[0].source, node: nodes[0] })\n\t\t\treturn false\n\t\t}\n\t},\n\n\tasync execBatch({ nodes, view }) {\n\t\tlet confirm = true\n\n\t\tif (shouldAskForConfirmation()) {\n\t\t\tconfirm = await askConfirmation(nodes, view)\n\t\t} else if (nodes.length >= 5 && !canUnshareOnly(nodes) && !canDisconnectOnly(nodes)) {\n\t\t\tconfirm = await askConfirmation(nodes, view)\n\t\t}\n\n\t\t// If the user cancels the deletion, we don't want to do anything\n\t\tif (confirm === false) {\n\t\t\treturn Promise.all(nodes.map(() => null))\n\t\t}\n\n\t\t// Map each node to a promise that resolves with the result of exec(node)\n\t\tconst promises = nodes.map((node) => {\n\t\t\t// Create a promise that resolves with the result of exec(node)\n\t\t\tconst promise = new Promise<boolean>((resolve) => {\n\t\t\t\tqueue.add(async () => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait deleteNode(node)\n\t\t\t\t\t\tresolve(true)\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tlogger.error('Error while deleting a file', { error, source: node.source, node })\n\t\t\t\t\t\tresolve(false)\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t})\n\t\t\treturn promise\n\t\t})\n\n\t\treturn Promise.all(promises)\n\t},\n\n\tdestructive: true,\n\torder: 100,\n\n\thotkey: {\n\t\tdescription: t('files', 'Delete'),\n\t\tkey: 'Delete',\n\t},\n}\n","export default \"<svg xmlns=\\\"http://www.w3.org/2000/svg\\\" id=\\\"mdi-arrow-down\\\" viewBox=\\\"0 0 24 24\\\"><path d=\\\"M11,4H13V16L18.5,10.5L19.92,11.92L12,19.84L4.08,11.92L5.5,10.5L11,16V4Z\\\" /></svg>\"","/*!\n * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport type { IFileAction, INode, IView } from '@nextcloud/files'\n\nimport ArrowDownSvg from '@mdi/svg/svg/arrow-down.svg?raw'\nimport axios from '@nextcloud/axios'\nimport { showError } from '@nextcloud/dialogs'\nimport { emit } from '@nextcloud/event-bus'\nimport { DefaultType, FileType } from '@nextcloud/files'\nimport { t } from '@nextcloud/l10n'\nimport { useFilesStore } from '../store/files.ts'\nimport { pinia } from '../store/index.ts'\nimport { usePathsStore } from '../store/paths.ts'\nimport { logger } from '../utils/logger.ts'\nimport { isDownloadable } from '../utils/permissions.ts'\n\nexport const action: IFileAction = {\n\tid: 'download',\n\tdefault: DefaultType.DEFAULT,\n\n\tdisplayName: () => t('files', 'Download'),\n\ticonSvgInline: () => ArrowDownSvg,\n\n\tenabled({ nodes, view }): boolean {\n\t\tif (nodes.length === 0) {\n\t\t\treturn false\n\t\t}\n\n\t\t// We can only download dav files and folders.\n\t\tif (nodes.some((node) => !node.isDavResource)) {\n\t\t\treturn false\n\t\t}\n\n\t\t// Trashbin does not allow batch download\n\t\tif (nodes.length > 1 && view.id === 'trashbin') {\n\t\t\treturn false\n\t\t}\n\n\t\treturn nodes.every(isDownloadable)\n\t},\n\n\tasync exec({ nodes }) {\n\t\ttry {\n\t\t\tawait downloadNodes(nodes)\n\t\t} catch (error) {\n\t\t\tshowError(t('files', 'The requested file is not available.'))\n\t\t\tlogger.error('The requested file is not available.', { error })\n\t\t\temit('files:node:deleted', nodes[0])\n\t\t}\n\t\treturn null\n\t},\n\n\tasync execBatch({ nodes, view, folder }) {\n\t\ttry {\n\t\t\tawait downloadNodes(nodes)\n\t\t} catch (error) {\n\t\t\tshowError(t('files', 'The requested files are not available.'))\n\t\t\tlogger.error('The requested files are not available.', { error })\n\t\t\t// Try to reload the current directory to update the view\n\t\t\tconst directory = getCurrentDirectory(view, folder.path)!\n\t\t\temit('files:node:updated', directory)\n\t\t}\n\t\treturn new Array(nodes.length).fill(null)\n\t},\n\n\torder: 30,\n}\n\n/**\n * Trigger downloading a file.\n *\n * @param url The url of the asset to download\n * @param name Optionally the recommended name of the download (browsers might ignore it)\n */\nasync function triggerDownload(url: string, name?: string) {\n\t// try to see if the resource is still available\n\tawait axios.head(url)\n\n\tconst hiddenElement = document.createElement('a')\n\thiddenElement.download = name ?? ''\n\thiddenElement.href = url\n\thiddenElement.click()\n}\n\n/**\n * Find the longest common path prefix of both input paths\n *\n * @param first The first path\n * @param second The second path\n */\nfunction longestCommonPath(first: string, second: string): string {\n\tconst firstSegments = first.split('/').filter(Boolean)\n\tconst secondSegments = second.split('/').filter(Boolean)\n\tlet base = ''\n\tfor (const [index, segment] of firstSegments.entries()) {\n\t\tif (index >= second.length) {\n\t\t\tbreak\n\t\t}\n\t\tif (segment !== secondSegments[index]) {\n\t\t\tbreak\n\t\t}\n\t\tconst sep = base === '' ? '' : '/'\n\t\tbase = `${base}${sep}${segment}`\n\t}\n\treturn base\n}\n\n/**\n * Download the given nodes.\n *\n * If only one node is given, it will be downloaded directly.\n * If multiple nodes are given, they will be zipped and downloaded.\n *\n * @param nodes The node(s) to download\n */\nasync function downloadNodes(nodes: INode[]) {\n\tlet url: URL\n\n\tif (!nodes[0]) {\n\t\tthrow new Error('No nodes to download')\n\t}\n\n\tif (nodes.length === 1) {\n\t\tif (nodes[0].type === FileType.File) {\n\t\t\tawait triggerDownload(nodes[0].encodedSource, nodes[0].displayname)\n\t\t\treturn\n\t\t} else {\n\t\t\turl = new URL(nodes[0].encodedSource)\n\t\t\turl.searchParams.append('accept', 'zip')\n\t\t}\n\t} else {\n\t\turl = new URL(nodes[0].encodedSource)\n\t\tlet base = url.pathname\n\t\tfor (const node of nodes.slice(1)) {\n\t\t\tbase = longestCommonPath(base, (new URL(node.encodedSource).pathname))\n\t\t}\n\t\turl.pathname = base\n\n\t\t// The URL contains the path encoded so we need to decode as the query.append will re-encode it\n\t\tconst filenames = nodes.map((node) => decodeURIComponent(node.encodedSource.slice(url.href.length + 1)))\n\t\turl.searchParams.append('accept', 'zip')\n\t\turl.searchParams.append('files', JSON.stringify(filenames))\n\t}\n\n\tif (url.pathname.at(-1) !== '/') {\n\t\turl.pathname = `${url.pathname}/`\n\t}\n\n\tawait triggerDownload(url.href)\n}\n\n/**\n * Get the current directory node for the given view and path.\n * TODO: ideally the folder would directly be passed as exec params\n *\n * @param view The current view\n * @param directory The directory path\n * @return The current directory node or null if not found\n */\nfunction getCurrentDirectory(view: IView, directory: string): INode | null {\n\tconst filesStore = useFilesStore(pinia)\n\tconst pathsStore = usePathsStore(pinia)\n\tif (!view?.id) {\n\t\treturn null\n\t}\n\n\tif (directory === '/') {\n\t\treturn filesStore.getRoot(view.id) || null\n\t}\n\tconst fileId = pathsStore.getPath(view.id, directory)!\n\treturn filesStore.getNode(fileId) || null\n}\n","/*\n * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport type { IFileAction, IFolder, INode, IView } from '@nextcloud/files'\n\nimport StarOutlineSvg from '@mdi/svg/svg/star-outline.svg?raw'\nimport StarSvg from '@mdi/svg/svg/star.svg?raw'\nimport axios from '@nextcloud/axios'\nimport { emit } from '@nextcloud/event-bus'\nimport { Permission } from '@nextcloud/files'\nimport { t } from '@nextcloud/l10n'\nimport { encodePath } from '@nextcloud/paths'\nimport { generateUrl } from '@nextcloud/router'\nimport { isPublicShare } from '@nextcloud/sharing/public'\nimport PQueue from 'p-queue'\nimport { logger } from '../utils/logger.ts'\n\nconst queue = new PQueue({ concurrency: 5 })\n\nexport const ACTION_FAVORITE = 'favorite'\n\nexport const action: IFileAction = {\n\tid: ACTION_FAVORITE,\n\tdisplayName({ nodes }) {\n\t\treturn shouldFavorite(nodes)\n\t\t\t? t('files', 'Add to favorites')\n\t\t\t: t('files', 'Remove from favorites')\n\t},\n\ticonSvgInline: ({ nodes }) => {\n\t\treturn shouldFavorite(nodes)\n\t\t\t? StarOutlineSvg\n\t\t\t: StarSvg\n\t},\n\n\tenabled({ nodes }) {\n\t\t// Not enabled for public shares\n\t\tif (isPublicShare()) {\n\t\t\treturn false\n\t\t}\n\n\t\t// We can only favorite nodes if they are located in files\n\t\treturn nodes.every((node) => node.root?.startsWith?.('/files'))\n\t\t\t// and we have permissions\n\t\t\t&& nodes.every((node) => node.permissions !== Permission.NONE)\n\t},\n\n\tasync exec({ nodes, view, folder }): Promise<boolean> {\n\t\tconst willFavorite = shouldFavorite([nodes[0]])\n\t\treturn await favoriteNode(nodes[0], view, willFavorite, folder)\n\t},\n\tasync execBatch({ nodes, view, folder }): Promise<boolean[]> {\n\t\tconst willFavorite = shouldFavorite(nodes)\n\n\t\t// Map each node to a promise that resolves with the result of exec(node)\n\t\tconst promises = nodes.map((node) => {\n\t\t\t// Create a promise that resolves with the result of exec(node)\n\t\t\tconst promise = new Promise<boolean>((resolve) => {\n\t\t\t\tqueue.add(async () => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait favoriteNode(node, view, willFavorite, folder)\n\t\t\t\t\t\tresolve(true)\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tlogger.error('Error while adding file to favorite', { error, source: node.source, node })\n\t\t\t\t\t\tresolve(false)\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t})\n\t\t\treturn promise\n\t\t})\n\n\t\treturn Promise.all(promises)\n\t},\n\n\torder: -50,\n\n\thotkey: {\n\t\tdescription: t('files', 'Add or remove favorite'),\n\t\tkey: 'S',\n\t},\n}\n\n/**\n * Favorite or unfavorite a node\n *\n * @param node - The node to favorite/unfavorite\n * @param view - The current view\n * @param willFavorite - Whether to favorite or unfavorite the node\n * @param folder - The currently open folder\n */\nexport async function favoriteNode(node: INode, view: IView, willFavorite: boolean, folder?: IFolder): Promise<boolean> {\n\ttry {\n\t\t// TODO: migrate to webdav tags plugin\n\t\tconst url = generateUrl('/apps/files/api/v1/files') + encodePath(node.path)\n\t\tawait axios.post(url, {\n\t\t\ttags: willFavorite\n\t\t\t\t? [window.OC.TAG_FAVORITE]\n\t\t\t\t: [],\n\t\t})\n\n\t\t// Remove from the virtual favorites listing, not when browsing a real folder\n\t\tif (view.id === 'favorites' && !willFavorite && isFavoritesRoot(folder)) {\n\t\t\temit('files:node:deleted', node)\n\t\t}\n\n\t\t// Update the node webdav attribute\n\t\tnode.attributes.favorite = willFavorite ? 1 : 0\n\t\temit('files:node:updated', node)\n\n\t\t// Dispatch event to whoever is interested\n\t\tif (willFavorite) {\n\t\t\temit('files:favorites:added', node)\n\t\t} else {\n\t\t\temit('files:favorites:removed', node)\n\t\t}\n\n\t\treturn true\n\t} catch (error) {\n\t\tconst action = willFavorite ? 'adding a file to favourites' : 'removing a file from favourites'\n\t\tlogger.error('Error while ' + action, { error, source: node.source, node })\n\t\treturn false\n\t}\n}\n\n/**\n * If any of the nodes is not favored, we display the favorite action.\n *\n * @param nodes - The nodes to check\n */\nfunction shouldFavorite(nodes: INode[]): boolean {\n\treturn nodes.some((node) => node.attributes.favorite !== 1)\n}\n\n/**\n * Whether the current folder is the virtual root of the favorites view.\n *\n * @param folder - The currently open folder\n */\nfunction isFavoritesRoot(folder?: IFolder): boolean {\n\treturn !folder?.path || folder.path === '/'\n}\n","export default \"<svg xmlns=\\\"http://www.w3.org/2000/svg\\\" id=\\\"mdi-folder\\\" viewBox=\\\"0 0 24 24\\\"><path d=\\\"M10,4H4C2.89,4 2,4.89 2,6V18A2,2 0 0,0 4,20H20A2,2 0 0,0 22,18V8C22,6.89 21.1,6 20,6H12L10,4Z\\\" /></svg>\"","/*!\n * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport type { IFileAction } from '@nextcloud/files'\n\nimport FolderSvg from '@mdi/svg/svg/folder.svg?raw'\nimport { DefaultType, FileType, Permission } from '@nextcloud/files'\nimport { t } from '@nextcloud/l10n'\n\nexport const action: IFileAction = {\n\tid: 'open-folder',\n\tdisplayName({ nodes }) {\n\t\tif (nodes.length !== 1 || !nodes[0]) {\n\t\t\treturn t('files', 'Open folder')\n\t\t}\n\n\t\t// Only works on single node\n\t\tconst displayName = nodes[0].displayname\n\t\treturn t('files', 'Open folder {displayName}', { displayName })\n\t},\n\ticonSvgInline: () => FolderSvg,\n\n\tenabled({ nodes }) {\n\t\t// Only works on single node\n\t\tif (nodes.length !== 1 || !nodes[0]) {\n\t\t\treturn false\n\t\t}\n\n\t\tconst node = nodes[0]\n\t\tif (!node.isDavResource) {\n\t\t\treturn false\n\t\t}\n\n\t\treturn node.type === FileType.Folder\n\t\t\t&& (node.permissions & Permission.READ) !== 0\n\t},\n\n\tasync exec({ nodes, view }) {\n\t\tconst node = nodes[0]\n\t\tif (!node || node.type !== FileType.Folder) {\n\t\t\treturn false\n\t\t}\n\n\t\twindow.OCP.Files.Router.goToRoute(\n\t\t\tnull,\n\t\t\t{ view: view.id, fileid: String(node.fileid) },\n\t\t\t{ dir: node.path },\n\t\t)\n\t\treturn null\n\t},\n\n\t// Main action if enabled, meaning folders only\n\tdefault: DefaultType.HIDDEN,\n\torder: -100,\n}\n","/*!\n * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport type { IFileAction } from '@nextcloud/files'\n\nimport { DefaultType, FileType } from '@nextcloud/files'\nimport { t } from '@nextcloud/l10n'\nimport { VIEW_ID as SEARCH_VIEW_ID } from '../views/search.ts'\n\nexport const action: IFileAction = {\n\tid: 'open-in-files',\n\tdisplayName: () => t('files', 'Open in Files'),\n\ticonSvgInline: () => '',\n\n\tenabled({ view }) {\n\t\treturn view.id === 'recent' || view.id === SEARCH_VIEW_ID\n\t},\n\n\tasync exec({ nodes }) {\n\t\tif (!nodes[0]) {\n\t\t\treturn false\n\t\t}\n\n\t\tlet dir = nodes[0].dirname\n\t\tif (nodes[0].type === FileType.Folder) {\n\t\t\tdir = dir + '/' + nodes[0].basename\n\t\t}\n\n\t\twindow.OCP.Files.Router.goToRoute(\n\t\t\tnull, // use default route\n\t\t\t{ view: 'files', fileid: String(nodes[0].fileid) },\n\t\t\t{ dir, openfile: 'true' },\n\t\t)\n\t\treturn null\n\t},\n\n\t// Before openFolderAction\n\torder: -1000,\n\tdefault: DefaultType.HIDDEN,\n}\n","export default \"<svg xmlns=\\\"http://www.w3.org/2000/svg\\\" id=\\\"mdi-laptop\\\" viewBox=\\\"0 0 24 24\\\"><path d=\\\"M4,6H20V16H4M20,18A2,2 0 0,0 22,16V6C22,4.89 21.1,4 20,4H4C2.89,4 2,4.89 2,6V16A2,2 0 0,0 4,18H0V20H24V18H20Z\\\" /></svg>\"","export default \"<svg xmlns=\\\"http://www.w3.org/2000/svg\\\" id=\\\"mdi-web\\\" viewBox=\\\"0 0 24 24\\\"><path d=\\\"M16.36,14C16.44,13.34 16.5,12.68 16.5,12C16.5,11.32 16.44,10.66 16.36,10H19.74C19.9,10.64 20,11.31 20,12C20,12.69 19.9,13.36 19.74,14M14.59,19.56C15.19,18.45 15.65,17.25 15.97,16H18.92C17.96,17.65 16.43,18.93 14.59,19.56M14.34,14H9.66C9.56,13.34 9.5,12.68 9.5,12C9.5,11.32 9.56,10.65 9.66,10H14.34C14.43,10.65 14.5,11.32 14.5,12C14.5,12.68 14.43,13.34 14.34,14M12,19.96C11.17,18.76 10.5,17.43 10.09,16H13.91C13.5,17.43 12.83,18.76 12,19.96M8,8H5.08C6.03,6.34 7.57,5.06 9.4,4.44C8.8,5.55 8.35,6.75 8,8M5.08,16H8C8.35,17.25 8.8,18.45 9.4,19.56C7.57,18.93 6.03,17.65 5.08,16M4.26,14C4.1,13.36 4,12.69 4,12C4,11.31 4.1,10.64 4.26,10H7.64C7.56,10.66 7.5,11.32 7.5,12C7.5,12.68 7.56,13.34 7.64,14M12,4.03C12.83,5.23 13.5,6.57 13.91,8H10.09C10.5,6.57 11.17,5.23 12,4.03M18.92,8H15.97C15.65,6.75 15.19,5.55 14.59,4.44C16.43,5.07 17.96,6.34 18.92,8M12,2C6.47,2 2,6.5 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2Z\\\" /></svg>\"","/*!\n * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport type { ActionContextSingle, IFile, IFileAction, INode } from '@nextcloud/files'\n\nimport LaptopSvg from '@mdi/svg/svg/laptop.svg?raw'\nimport IconWeb from '@mdi/svg/svg/web.svg?raw'\nimport { getCurrentUser } from '@nextcloud/auth'\nimport axios from '@nextcloud/axios'\nimport { DialogBuilder, showError } from '@nextcloud/dialogs'\nimport { FileType } from '@nextcloud/files'\nimport { loadState } from '@nextcloud/initial-state'\nimport { translate as t } from '@nextcloud/l10n'\nimport { encodePath } from '@nextcloud/paths'\nimport { generateOcsUrl } from '@nextcloud/router'\nimport { isPublicShare } from '@nextcloud/sharing/public'\nimport { getViewer } from '@nextcloud/viewer'\nimport { logger } from '../utils/logger.ts'\nimport { isSyncable } from '../utils/permissions.ts'\n\nconst localClientEnabled = loadState('files', 'localClientEnabled', true)\n\nexport const action: IFileAction = {\n\tid: 'edit-locally',\n\tdisplayName: () => t('files', 'Open locally'),\n\ticonSvgInline: () => LaptopSvg,\n\n\t// Only works on single files\n\tenabled({ nodes }) {\n\t\t// Only works on single node\n\t\tif (nodes.length !== 1 || !nodes[0]) {\n\t\t\treturn false\n\t\t}\n\n\t\t// does not work with shares\n\t\tif (isPublicShare()) {\n\t\t\treturn false\n\t\t}\n\n\t\tif (!localClientEnabled) {\n\t\t\treturn false\n\t\t}\n\n\t\treturn isSyncable(nodes[0]!)\n\t},\n\n\tasync exec({ nodes, contents }) {\n\t\tawait attemptOpenLocalClient(nodes[0], contents)\n\t\treturn null\n\t},\n\n\torder: 25,\n}\n\n/**\n * Try to open the path in the Nextcloud client.\n *\n * If this fails a dialog is shown with 3 options:\n * 1. Retry: If it fails no further dialog is shown.\n * 2. Open online: The viewer is used to open the file.\n * 3. Close the dialog and nothing happens (abort).\n *\n * @param node - The file to open\n * @param contents - The folder the file is in, so the viewer can navigate\n */\nasync function attemptOpenLocalClient(node: INode, contents: ActionContextSingle['contents']) {\n\tawait openLocalClient(node.path)\n\tconst result = await confirmLocalEditDialog()\n\tif (result === 'local') {\n\t\tawait openLocalClient(node.path)\n\t} else if (result === 'online') {\n\t\t// The listing carries the folders too, and the viewer pages through\n\t\t// files alone\n\t\tconst files = contents.filter((entry): entry is IFile => entry.type === FileType.File)\n\t\tawait getViewer().open(files, node as IFile)\n\t}\n}\n\n/**\n * Try to open a file in the Nextcloud client.\n * There is no way to get notified if this action was successful.\n *\n * @param path - Path to open\n */\nasync function openLocalClient(path: string): Promise<void> {\n\tconst link = generateOcsUrl('apps/files/api/v1') + '/openlocaleditor?format=json'\n\n\ttry {\n\t\tconst result = await axios.post(link, { path })\n\t\tconst uid = getCurrentUser()?.uid\n\t\tlet url = `nc://open/${uid}@` + window.location.host + encodePath(path)\n\t\turl += '?token=' + result.data.ocs.data.token\n\n\t\twindow.open(url, '_self')\n\t} catch (error) {\n\t\tshowError(t('files', 'Failed to redirect to client'))\n\t\tlogger.error('Failed to redirect to client', { error })\n\t}\n}\n\n/**\n * Open the confirmation dialog.\n */\nasync function confirmLocalEditDialog(): Promise<'online' | 'local' | false> {\n\tlet result: 'online' | 'local' | false = false\n\tconst dialog = (new DialogBuilder())\n\t\t.setName(t('files', 'Open file locally'))\n\t\t.setText(t('files', 'The file should now open on your device. If it doesn\\'t, please check that you have the desktop app installed.'))\n\t\t.setButtons([\n\t\t\t{\n\t\t\t\tlabel: t('files', 'Retry and close'),\n\t\t\t\tvariant: 'secondary',\n\t\t\t\tcallback: () => {\n\t\t\t\t\tresult = 'local'\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tlabel: t('files', 'Open online'),\n\t\t\t\ticon: IconWeb,\n\t\t\t\tvariant: 'primary',\n\t\t\t\tcallback: () => {\n\t\t\t\t\tresult = 'online'\n\t\t\t\t},\n\t\t\t},\n\t\t])\n\t\t.build()\n\n\ttry {\n\t\tawait dialog.show()\n\t} catch (error) {\n\t\tlogger.debug('Open locally dialog closed', { error })\n\t}\n\n\treturn result\n}\n","export default \"<svg xmlns=\\\"http://www.w3.org/2000/svg\\\" id=\\\"mdi-pencil-outline\\\" viewBox=\\\"0 0 24 24\\\"><path d=\\\"M14.06,9L15,9.94L5.92,19H5V18.08L14.06,9M17.66,3C17.41,3 17.15,3.1 16.96,3.29L15.13,5.12L18.88,8.87L20.71,7.04C21.1,6.65 21.1,6 20.71,5.63L18.37,3.29C18.17,3.09 17.92,3 17.66,3M14.06,6.19L3,17.25V21H6.75L17.81,9.94L14.06,6.19Z\\\" /></svg>\"","/*!\n * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport type { IFileAction } from '@nextcloud/files'\n\nimport PencilSvg from '@mdi/svg/svg/pencil-outline.svg?raw'\nimport { emit } from '@nextcloud/event-bus'\nimport { Permission } from '@nextcloud/files'\nimport { translate as t } from '@nextcloud/l10n'\nimport { dirname } from 'path'\nimport { useFilesStore } from '../store/files.ts'\nimport { pinia } from '../store/index.ts'\n\nexport const ACTION_RENAME = 'rename'\n\nexport const action: IFileAction = {\n\tid: ACTION_RENAME,\n\tdisplayName: () => t('files', 'Rename'),\n\ticonSvgInline: () => PencilSvg,\n\n\tenabled: ({ nodes, view }) => {\n\t\tif (nodes.length === 0 || !nodes[0]) {\n\t\t\treturn false\n\t\t}\n\n\t\t// Disable for single file shares\n\t\tif (view.id === 'public-file-share') {\n\t\t\treturn false\n\t\t}\n\n\t\tconst node = nodes[0]\n\t\tconst filesStore = useFilesStore(pinia)\n\t\tconst parentNode = node.dirname === '/'\n\t\t\t? filesStore.getRoot(view.id)\n\t\t\t: filesStore.getNode(dirname(node.source))\n\t\tconst parentPermissions = parentNode?.permissions || Permission.NONE\n\n\t\t// Enable if the node has update permissions or the node\n\t\t// has delete permission and the parent folder allows creating files\n\t\treturn (\n\t\t\t(\n\t\t\t\tBoolean(node.permissions & Permission.DELETE)\n\t\t\t\t&& Boolean(parentPermissions & Permission.CREATE)\n\t\t\t)\n\t\t\t|| Boolean(node.permissions & Permission.UPDATE)\n\t\t)\n\t},\n\n\tasync exec({ nodes }) {\n\t\t// Renaming is a built-in feature of the files app\n\t\temit('files:node:rename', nodes[0])\n\t\treturn null\n\t},\n\n\torder: 10,\n\n\thotkey: {\n\t\tdescription: t('files', 'Rename'),\n\t\tkey: 'F2',\n\t},\n}\n","/*\n * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport starOutlineSvg from '@mdi/svg/svg/star-outline.svg?raw'\nimport starSvg from '@mdi/svg/svg/star.svg?raw'\nimport { registerSidebarAction } from '@nextcloud/files'\nimport { t } from '@nextcloud/l10n'\nimport { favoriteNode } from './favoriteAction.ts'\n\n/**\n * Register the favorite/unfavorite action in the sidebar\n */\nexport function registerSidebarFavoriteAction() {\n\tregisterSidebarAction({\n\t\tid: 'files-favorite',\n\t\torder: 0,\n\n\t\tenabled({ node }) {\n\t\t\treturn node.isDavResource && node.root.startsWith('/files/')\n\t\t},\n\n\t\tdisplayName({ node }) {\n\t\t\tif (node.attributes.favorite) {\n\t\t\t\treturn t('files', 'Unfavorite')\n\t\t\t}\n\t\t\treturn t('files', 'Favorite')\n\t\t},\n\n\t\ticonSvgInline({ node }) {\n\t\t\tif (node.attributes.favorite) {\n\t\t\t\treturn starSvg\n\t\t\t}\n\t\t\treturn starOutlineSvg\n\t\t},\n\n\t\tonClick({ node, view, folder }) {\n\t\t\tfavoriteNode(node, view, !node.attributes.favorite, folder)\n\t\t},\n\t})\n}\n","export default \"<svg xmlns=\\\"http://www.w3.org/2000/svg\\\" id=\\\"mdi-folder-eye-outline\\\" viewBox=\\\"0 0 24 24\\\"><path d=\\\"M9.3 20H4C2.9 20 2 19.1 2 18V6C2 4.9 2.9 4 4 4H10L12 6H20C21.1 6 22 6.9 22 8V14.6C21.4 14.2 20.7 13.8 20 13.5V8H4V18H9.3C9.3 18.1 9.2 18.2 9.2 18.3L8.8 19L9.1 19.7C9.2 19.8 9.2 19.9 9.3 20M23 19C22.1 21.3 19.7 23 17 23S11.9 21.3 11 19C11.9 16.7 14.3 15 17 15S22.1 16.7 23 19M19.5 19C19.5 17.6 18.4 16.5 17 16.5S14.5 17.6 14.5 19 15.6 21.5 17 21.5 19.5 20.4 19.5 19M17 18C16.4 18 16 18.4 16 19S16.4 20 17 20 18 19.6 18 19 17.6 18 17 18\\\" /></svg>\"","/*!\n * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport type { IFileAction } from '@nextcloud/files'\n\nimport FolderEyeSvg from '@mdi/svg/svg/folder-eye-outline.svg?raw'\nimport { FileType, Permission } from '@nextcloud/files'\nimport { t } from '@nextcloud/l10n'\nimport { isPublicShare } from '@nextcloud/sharing/public'\n\nexport const action: IFileAction = {\n\tid: 'view-in-folder',\n\tdisplayName() {\n\t\treturn t('files', 'View in folder')\n\t},\n\ticonSvgInline: () => FolderEyeSvg,\n\n\tenabled({ nodes, view }) {\n\t\t// Not enabled for public shares\n\t\tif (isPublicShare()) {\n\t\t\treturn false\n\t\t}\n\n\t\t// Only works outside of the main files view\n\t\tif (view.id === 'files') {\n\t\t\treturn false\n\t\t}\n\n\t\t// Only works on single node\n\t\tif (nodes.length !== 1 || !nodes[0]) {\n\t\t\treturn false\n\t\t}\n\n\t\tconst node = nodes[0]\n\t\tif (!node.isDavResource) {\n\t\t\treturn false\n\t\t}\n\n\t\t// Can only view files that are in the user root folder\n\t\tif (!node.root?.startsWith('/files')) {\n\t\t\treturn false\n\t\t}\n\n\t\tif (node.permissions === Permission.NONE) {\n\t\t\treturn false\n\t\t}\n\n\t\treturn node.type === FileType.File\n\t},\n\n\tasync exec({ nodes }) {\n\t\tif (!nodes[0] || nodes[0].type !== FileType.File) {\n\t\t\treturn false\n\t\t}\n\n\t\twindow.OCP.Files.Router.goToRoute(\n\t\t\tnull,\n\t\t\t{ view: 'files', fileid: String(nodes[0].fileid) },\n\t\t\t{ dir: nodes[0].dirname },\n\t\t)\n\t\treturn null\n\t},\n\n\torder: 10,\n}\n","/*!\n * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport type { IFileListFilterChip, INode } from '@nextcloud/files'\n\nimport { subscribe } from '@nextcloud/event-bus'\nimport { FileListFilter, registerFileListFilter } from '@nextcloud/files'\nimport { pinia } from '../store/index.ts'\nimport { useSearchStore } from '../store/search.ts'\n\n/**\n * Simple file list filter controlled by the Navigation search box\n */\nclass FilenameFilter extends FileListFilter {\n\tprivate searchQuery = ''\n\n\tconstructor() {\n\t\tsuper('files:filename', 5)\n\t\tsubscribe('files:search:updated', ({ query, scope }) => {\n\t\t\tif (scope === 'filter') {\n\t\t\t\tthis.updateQuery(query)\n\t\t\t}\n\t\t})\n\t}\n\n\tpublic filter(nodes: INode[]): INode[] {\n\t\tconst queryParts = this.searchQuery.toLocaleLowerCase().split(' ').filter(Boolean)\n\t\treturn nodes.filter((node) => {\n\t\t\tconst displayname = node.displayname.toLocaleLowerCase()\n\t\t\treturn queryParts.every((part) => displayname.includes(part))\n\t\t})\n\t}\n\n\tpublic reset(): void {\n\t\tthis.updateQuery('')\n\t}\n\n\tpublic updateQuery(query: string) {\n\t\tquery = (query || '').trim()\n\n\t\t// Only if the query is different we update the filter to prevent re-computing all nodes\n\t\tif (query !== this.searchQuery) {\n\t\t\tthis.searchQuery = query\n\t\t\tthis.filterUpdated()\n\n\t\t\tconst chips: IFileListFilterChip[] = []\n\t\t\tif (query !== '') {\n\t\t\t\tchips.push({\n\t\t\t\t\ttext: query,\n\t\t\t\t\tonclick: () => {\n\t\t\t\t\t\tthis.updateQuery('')\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t} else {\n\t\t\t\t// make sure to also reset the search store when pressing the \"X\" on the filter chip\n\t\t\t\tconst store = useSearchStore(pinia)\n\t\t\t\tif (store.scope === 'filter') {\n\t\t\t\t\tstore.query = ''\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.updateChips(chips)\n\t\t}\n\t}\n}\n\n/**\n * Register the filename filter\n */\nexport function registerFilenameFilter() {\n\tregisterFileListFilter(new FilenameFilter())\n}\n","/*!\n * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport type { INode } from '@nextcloud/files'\nimport type { UserConfig } from '../types.ts'\n\nimport { subscribe } from '@nextcloud/event-bus'\nimport { FileListFilter, registerFileListFilter } from '@nextcloud/files'\nimport { loadState } from '@nextcloud/initial-state'\n\nclass HiddenFilesFilter extends FileListFilter {\n\tprivate showHidden?: boolean\n\n\tconstructor() {\n\t\tsuper('files:hidden', 0)\n\t\tthis.showHidden = loadState<Partial<UserConfig>>('files', 'config', { show_hidden: false }).show_hidden\n\n\t\tsubscribe('files:config:updated', ({ key, value }) => {\n\t\t\tif (key === 'show_hidden') {\n\t\t\t\tthis.showHidden = Boolean(value)\n\t\t\t\tthis.filterUpdated()\n\t\t\t}\n\t\t})\n\t}\n\n\tpublic filter(nodes: INode[]): INode[] {\n\t\tif (this.showHidden) {\n\t\t\treturn nodes\n\t\t}\n\t\treturn nodes.filter((node) => (node.attributes.hidden !== true && !node.basename.startsWith('.')))\n\t}\n}\n\n/**\n * Register a file list filter to only show hidden files if enabled by user config\n */\nexport function registerHiddenFilesFilter() {\n\tregisterFileListFilter(new HiddenFilesFilter())\n}\n","export default \"<svg xmlns=\\\"http://www.w3.org/2000/svg\\\" id=\\\"mdi-calendar-range-outline\\\" viewBox=\\\"0 0 24 24\\\"><path d=\\\"M7 11H9V13H7V11M21 5V19C21 20.11 20.11 21 19 21H5C3.89 21 3 20.1 3 19V5C3 3.9 3.9 3 5 3H6V1H8V3H16V1H18V3H19C20.11 3 21 3.9 21 5M5 7H19V5H5V7M19 19V9H5V19H19M15 13H17V11H15V13M11 13H13V11H11V13Z\\\" /></svg>\"","<!--\n - SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n<template>\n\t<div>\n\t\t<NcButton\n\t\t\tv-for=\"preset of timePresets\"\n\t\t\t:key=\"preset.id\"\n\t\t\talignment=\"start\"\n\t\t\t:pressed=\"preset === selectedOption\"\n\t\t\tvariant=\"tertiary\"\n\t\t\twide\n\t\t\t@update:pressed=\"$event ? (selectedOption = preset) : onReset()\">\n\t\t\t{{ preset.label }}\n\t\t</NcButton>\n\t\t<NcDateTimePicker\n\t\t\tv-if=\"selectedOption?.id === 'custom'\"\n\t\t\tv-model=\"timeRange\"\n\t\t\tappendToBody\n\t\t\t:aria-label=\"t('files', 'Custom date range')\"\n\t\t\ttype=\"date-range\" />\n\t</div>\n</template>\n\n<script setup lang=\"ts\">\nimport type { ITimePreset, ModifiedFilter } from '../../filters/ModifiedFilter.ts'\n\nimport { t } from '@nextcloud/l10n'\nimport { NcDateTimePicker } from '@nextcloud/vue'\nimport { onMounted, onUnmounted, ref, watch } from 'vue'\nimport NcButton from '@nextcloud/vue/components/NcButton'\n\nconst props = defineProps<{\n\tfilter: ModifiedFilter\n}>()\n\nconst selectedOption = ref<typeof timePresets[number]>()\nwatch(selectedOption, (preset) => {\n\tif (selectedOption.value) {\n\t\tif (selectedOption.value.id === 'custom' && !timeRange.value) {\n\t\t\ttimeRange.value = [new Date(startOfLastWeek()), new Date(startOfToday())]\n\t\t\tselectedOption.value.timeRange = [...timeRange.value]\n\t\t}\n\t\tprops.filter.setPreset(selectedOption.value)\n\t} else {\n\t\tprops.filter.setPreset()\n\t}\n})\n\nconst timeRange = ref<[Date, Date]>()\nwatch(timeRange, () => {\n\tif (timeRange.value) {\n\t\tselectedOption.value!.timeRange = [...timeRange.value]\n\t\tprops.filter.setPreset(selectedOption.value)\n\t}\n})\n\nonMounted(() => {\n\tselectedOption.value = props.filter.preset && timePresets.find((f) => f.id === props.filter.preset!.id)\n\tprops.filter.addEventListener('reset', onReset)\n})\nonUnmounted(() => {\n\tprops.filter.removeEventListener('reset', onReset)\n})\n\n/**\n * Handler for resetting the filter\n */\nfunction onReset() {\n\tselectedOption.value = undefined\n\ttimeRange.value = undefined\n}\n</script>\n\n<script lang=\"ts\">\nconst startOfToday = () => (new Date()).setHours(0, 0, 0, 0)\nconst startOfLastWeek = () => startOfToday() - (7 * 24 * 60 * 60 * 1000)\n\n/**\n * Available presets\n */\nconst timePresets = [\n\t{\n\t\tid: 'today',\n\t\tlabel: t('files', 'Today'),\n\t\tfilter: (time: number) => time > startOfToday(),\n\t} satisfies ITimePreset,\n\t{\n\t\tid: 'last-7',\n\t\tlabel: t('files', 'Last 7 days'),\n\t\tfilter: (time: number) => time > startOfLastWeek(),\n\t} satisfies ITimePreset,\n\t{\n\t\tid: 'last-30',\n\t\tlabel: t('files', 'Last 30 days'),\n\t\tfilter: (time: number) => time > (startOfToday() - (30 * 24 * 60 * 60 * 1000)),\n\t} satisfies ITimePreset,\n\t{\n\t\tid: 'this-year',\n\t\tlabel: t('files', 'This year ({year})', { year: (new Date()).getFullYear() }),\n\t\tfilter: (time: number) => time > (new Date(startOfToday())).setMonth(0, 1),\n\t} satisfies ITimePreset,\n\t{\n\t\tid: 'last-year',\n\t\tlabel: t('files', 'Last year ({year})', { year: (new Date()).getFullYear() - 1 }),\n\t\tfilter: (time: number) => (time > (new Date(startOfToday())).setFullYear((new Date()).getFullYear() - 1, 0, 1)) && (time < (new Date(startOfToday())).setMonth(0, 1)),\n\t} satisfies ITimePreset,\n\t{\n\t\tid: 'custom',\n\t\tlabel: t('files', 'Custom range'),\n\t\ttimeRange: [new Date(startOfLastWeek()), new Date(startOfToday())],\n\t\tfilter(time: number) {\n\t\t\tif (!this.timeRange) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\tconst timeValue = new Date(time).getTime()\n\t\t\treturn timeValue >= this.timeRange[0].getTime() && timeValue <= this.timeRange[1].getTime()\n\t\t},\n\t} satisfies ITimePreset & Record<string, unknown>,\n]\n</script>\n\n<style scoped lang=\"scss\">\n.files-list-filter-time {\n\t&__clear-button :deep(.action-button__text) {\n\t\tcolor: var(--color-error-text);\n\t}\n}\n</style>\n","/*!\n * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport type { IFileListFilterChip, IFileListFilterWithUi, INode } from '@nextcloud/files'\n\nimport svgCalendarRangeOutline from '@mdi/svg/svg/calendar-range-outline.svg?raw'\nimport { FileListFilter, registerFileListFilter } from '@nextcloud/files'\nimport { t } from '@nextcloud/l10n'\nimport { defineCustomElement } from 'vue'\nimport FileListFilterModified from '../components/FileListFilter/FileListFilterModified.vue'\n\nexport interface ITimePreset {\n\tid: string\n\tlabel: string\n\tfilter: (time: number) => boolean\n}\n\nconst tagName = 'files-file-list-filter-modified'\n\nclass ModifiedFilter extends FileListFilter implements IFileListFilterWithUi {\n\tprivate currentInstance?: InstanceType<typeof FileListFilterModified>\n\tprivate currentPreset?: ITimePreset\n\n\tpublic readonly displayName = t('files', 'Modified')\n\tpublic readonly iconSvgInline = svgCalendarRangeOutline\n\tpublic readonly tagName = tagName\n\n\tconstructor() {\n\t\tsuper('files:modified', 50)\n\t}\n\n\tpublic filter(nodes: INode[]): INode[] {\n\t\tif (!this.currentPreset) {\n\t\t\treturn nodes\n\t\t}\n\n\t\treturn nodes.filter((node) => node.mtime === undefined || this.currentPreset!.filter(node.mtime.getTime()))\n\t}\n\n\tpublic reset(): void {\n\t\tthis.dispatchEvent(new CustomEvent('reset'))\n\t}\n\n\tpublic get preset() {\n\t\treturn this.currentPreset\n\t}\n\n\tpublic setPreset(preset?: ITimePreset) {\n\t\tthis.currentPreset = preset\n\t\tthis.filterUpdated()\n\n\t\tconst chips: IFileListFilterChip[] = []\n\t\tif (preset) {\n\t\t\tchips.push({\n\t\t\t\ticon: svgCalendarRangeOutline,\n\t\t\t\ttext: preset.label,\n\t\t\t\tonclick: () => this.reset(),\n\t\t\t})\n\t\t} else {\n\t\t\t(this.currentInstance as { resetFilter: () => void } | undefined)?.resetFilter()\n\t\t}\n\t\tthis.updateChips(chips)\n\t}\n}\n\nexport type { ModifiedFilter }\n\n/**\n * Register the file list filter by modification date\n */\nexport function registerModifiedFilter() {\n\tconst WrappedComponent = defineCustomElement(FileListFilterModified, { shadowRoot: false })\n\tcustomElements.define(tagName, WrappedComponent)\n\tregisterFileListFilter(new ModifiedFilter())\n}\n","export default \"<svg xmlns=\\\"http://www.w3.org/2000/svg\\\" id=\\\"mdi-file-outline\\\" viewBox=\\\"0 0 24 24\\\"><path d=\\\"M14,2H6A2,2 0 0,0 4,4V20A2,2 0 0,0 6,22H18A2,2 0 0,0 20,20V8L14,2M18,20H6V4H13V9H18V20Z\\\" /></svg>\"","export default \"<svg xmlns=\\\"http://www.w3.org/2000/svg\\\" id=\\\"mdi-file-document\\\" viewBox=\\\"0 0 24 24\\\"><path d=\\\"M13,9H18.5L13,3.5V9M6,2H14L20,8V20A2,2 0 0,1 18,22H6C4.89,22 4,21.1 4,20V4C4,2.89 4.89,2 6,2M15,18V16H6V18H15M18,14V12H6V14H18Z\\\" /></svg>\"","export default \"<svg xmlns=\\\"http://www.w3.org/2000/svg\\\" id=\\\"mdi-file-pdf-box\\\" viewBox=\\\"0 0 24 24\\\"><path d=\\\"M19 3H5C3.9 3 3 3.9 3 5V19C3 20.1 3.9 21 5 21H19C20.1 21 21 20.1 21 19V5C21 3.9 20.1 3 19 3M9.5 11.5C9.5 12.3 8.8 13 8 13H7V15H5.5V9H8C8.8 9 9.5 9.7 9.5 10.5V11.5M14.5 13.5C14.5 14.3 13.8 15 13 15H10.5V9H13C13.8 9 14.5 9.7 14.5 10.5V13.5M18.5 10.5H17V11.5H18.5V13H17V15H15.5V9H18.5V10.5M12 10.5H13V13.5H12V10.5M7 10.5H8V11.5H7V10.5Z\\\" /></svg>\"","export default \"<svg xmlns=\\\"http://www.w3.org/2000/svg\\\" id=\\\"mdi-file-presentation-box\\\" viewBox=\\\"0 0 24 24\\\"><path d=\\\"M19,16H5V8H19M19,3H5C3.89,3 3,3.89 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V5C21,3.89 20.1,3 19,3Z\\\" /></svg>\"","export default \"<svg xmlns=\\\"http://www.w3.org/2000/svg\\\" id=\\\"mdi-file-table-box\\\" viewBox=\\\"0 0 24 24\\\"><path d=\\\"M19 3H5C3.89 3 3 3.89 3 5V19C3 20.1 3.9 21 5 21H19C20.1 21 21 20.1 21 19V5C21 3.89 20.1 3 19 3M9 18H6V16H9V18M9 15H6V13H9V15M9 12H6V10H9V12M13 18H10V16H13V18M13 15H10V13H13V15M13 12H10V10H13V12Z\\\" /></svg>\"","export default \"<svg xmlns=\\\"http://www.w3.org/2000/svg\\\" id=\\\"mdi-image\\\" viewBox=\\\"0 0 24 24\\\"><path d=\\\"M8.5,13.5L11,16.5L14.5,12L19,18H5M21,19V5C21,3.89 20.1,3 19,3H5A2,2 0 0,0 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19Z\\\" /></svg>\"","export default \"<svg xmlns=\\\"http://www.w3.org/2000/svg\\\" id=\\\"mdi-movie\\\" viewBox=\\\"0 0 24 24\\\"><path d=\\\"M18,4L20,8H17L15,4H13L15,8H12L10,4H8L10,8H7L5,4H4A2,2 0 0,0 2,6V18A2,2 0 0,0 4,20H20A2,2 0 0,0 22,18V4H18Z\\\" /></svg>\"","export default \"<svg xmlns=\\\"http://www.w3.org/2000/svg\\\" id=\\\"mdi-music\\\" viewBox=\\\"0 0 24 24\\\"><path d=\\\"M21,3V15.5A3.5,3.5 0 0,1 17.5,19A3.5,3.5 0 0,1 14,15.5A3.5,3.5 0 0,1 17.5,12C18.04,12 18.55,12.12 19,12.34V6.47L9,8.6V17.5A3.5,3.5 0 0,1 5.5,21A3.5,3.5 0 0,1 2,17.5A3.5,3.5 0 0,1 5.5,14C6.04,14 6.55,14.12 7,14.34V6L21,3Z\\\" /></svg>\"","<!--\n - SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n<template>\n\t<div :class=\"$style.fileListFilterType\">\n\t\t<NcButton\n\t\t\tv-for=\"fileType of typePresets\"\n\t\t\t:key=\"fileType.id\"\n\t\t\t:pressed=\"selectedOptions.includes(fileType)\"\n\t\t\tvariant=\"tertiary\"\n\t\t\talignment=\"start\"\n\t\t\twide\n\t\t\t@update:pressed=\"toggleOption(fileType, $event)\">\n\t\t\t<template #icon>\n\t\t\t\t<NcIconSvgWrapper :svg=\"fileType.icon\" />\n\t\t\t</template>\n\t\t\t{{ fileType.label }}\n\t\t</NcButton>\n\t</div>\n</template>\n\n<script setup lang=\"ts\">\nimport type { ITypePreset, TypeFilter } from '../../filters/TypeFilter.ts'\n\nimport svgDocument from '@mdi/svg/svg/file-document.svg?raw'\nimport svgPDF from '@mdi/svg/svg/file-pdf-box.svg?raw'\nimport svgPresentation from '@mdi/svg/svg/file-presentation-box.svg?raw'\nimport svgSpreadsheet from '@mdi/svg/svg/file-table-box.svg?raw'\nimport svgFolder from '@mdi/svg/svg/folder.svg?raw'\nimport svgImage from '@mdi/svg/svg/image.svg?raw'\nimport svgMovie from '@mdi/svg/svg/movie.svg?raw'\nimport svgAudio from '@mdi/svg/svg/music.svg?raw'\nimport { t } from '@nextcloud/l10n'\nimport { onMounted, onUnmounted, ref, watch } from 'vue'\nimport NcButton from '@nextcloud/vue/components/NcButton'\nimport NcIconSvgWrapper from '@nextcloud/vue/components/NcIconSvgWrapper'\n\nconst props = defineProps<{\n\tfilter: TypeFilter\n}>()\n\nconst selectedOptions = ref<ITypePreset[]>([])\nwatch(selectedOptions, () => {\n\tprops.filter.setPresets([...selectedOptions.value])\n})\n\nonMounted(() => {\n\tprops.filter.addEventListener('reset', resetFilter)\n\tprops.filter.addEventListener('deselect', onDeselect)\n\tselectedOptions.value = typePresets.filter(({ id }) => props.filter.presets.some((preset) => preset.id === id))\n})\nonUnmounted(() => {\n\tprops.filter.removeEventListener('reset', resetFilter)\n\tprops.filter.removeEventListener('deselect', onDeselect)\n})\n\n/**\n * Handler for reset event from filter.\n *\n * Assigning a new array unconditionally would re-trigger the watcher above,\n * which calls back into `setPresets` and so dispatches `reset` again.\n */\nfunction resetFilter() {\n\tif (selectedOptions.value.length > 0) {\n\t\tselectedOptions.value = []\n\t}\n}\n\n/**\n * Handle deselect event from filter\n *\n * @param event - The custom event\n */\nfunction onDeselect(event: CustomEvent<string>) {\n\tconst option = typePresets.find((preset) => preset.id === event.detail)\n\tif (option) {\n\t\ttoggleOption(option, false)\n\t}\n}\n\n/**\n * Toggle option from selected option\n *\n * @param option The option to toggle\n * @param selected Whether the option is selected or not\n */\nfunction toggleOption(option: ITypePreset, selected: boolean) {\n\tselectedOptions.value = selectedOptions.value.filter((o) => o.id !== option.id)\n\n\tif (selected) {\n\t\tselectedOptions.value.push(option)\n\t}\n}\n</script>\n\n<script lang=\"ts\">\n/**\n * Available presets\n */\nconst typePresets = [\n\t{\n\t\tid: 'document',\n\t\tlabel: t('files', 'Documents'),\n\t\ticon: colorize(svgDocument, '#49abea'),\n\t\tmime: ['x-office/document'],\n\t},\n\t{\n\t\tid: 'spreadsheet',\n\t\tlabel: t('files', 'Spreadsheets'),\n\t\ticon: colorize(svgSpreadsheet, '#9abd4e'),\n\t\tmime: ['x-office/spreadsheet'],\n\t},\n\t{\n\t\tid: 'presentation',\n\t\tlabel: t('files', 'Presentations'),\n\t\ticon: colorize(svgPresentation, '#f0965f'),\n\t\tmime: ['x-office/presentation'],\n\t},\n\t{\n\t\tid: 'pdf',\n\t\tlabel: t('files', 'PDFs'),\n\t\ticon: colorize(svgPDF, '#dc5047'),\n\t\tmime: ['application/pdf'],\n\t},\n\t{\n\t\tid: 'folder',\n\t\tlabel: t('files', 'Folders'),\n\t\ticon: colorize(svgFolder, window.getComputedStyle(document.body).getPropertyValue('--color-primary-element')),\n\t\tmime: ['httpd/unix-directory'],\n\t},\n\t{\n\t\tid: 'audio',\n\t\tlabel: t('files', 'Audio'),\n\t\ticon: svgAudio,\n\t\tmime: ['audio'],\n\t},\n\t{\n\t\tid: 'image',\n\t\t// TRANSLATORS: This is for filtering files, e.g. PNG or JPEG, so photos, drawings, or images in general\n\t\tlabel: t('files', 'Images'),\n\t\ticon: svgImage,\n\t\tmime: ['image'],\n\t},\n\t{\n\t\tid: 'video',\n\t\tlabel: t('files', 'Videos'),\n\t\ticon: svgMovie,\n\t\tmime: ['video'],\n\t},\n] as ITypePreset[]\n\n/**\n * Helper to colorize an svg icon\n *\n * @param svg - the svg content\n * @param color - the color to apply\n */\nfunction colorize(svg: string, color: string) {\n\treturn svg.replace('<path ', `<path fill=\"${color}\" `)\n}\n</script>\n\n<style module>\n.fileListFilterType {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: var(--default-grid-baseline);\n\twidth: 100%;\n}\n</style>\n","/*!\n * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport type { IFileListFilterChip, IFileListFilterWithUi, INode } from '@nextcloud/files'\n\nimport svgFileOutline from '@mdi/svg/svg/file-outline.svg?raw'\nimport { FileListFilter, registerFileListFilter } from '@nextcloud/files'\nimport { t } from '@nextcloud/l10n'\nimport { defineCustomElement } from 'vue'\nimport FileListFilterType from '../components/FileListFilter/FileListFilterType.vue'\nimport { logger } from '../utils/logger.ts'\n\nexport interface ITypePreset {\n\tid: string\n\tlabel: string\n\ticon: string\n\tmime: string[]\n}\n\nconst tagName = 'files-file-list-filter-type'\n\nclass TypeFilter extends FileListFilter implements IFileListFilterWithUi {\n\tprivate currentPresets: ITypePreset[]\n\n\tpublic readonly displayName = t('files', 'Type')\n\tpublic readonly iconSvgInline = svgFileOutline\n\tpublic readonly tagName = tagName\n\n\tconstructor() {\n\t\tsuper('files:type', 10)\n\t\tthis.currentPresets = []\n\t}\n\n\tpublic filter(nodes: INode[]): INode[] {\n\t\tif (!this.currentPresets || this.currentPresets.length === 0) {\n\t\t\treturn nodes\n\t\t}\n\n\t\tconst mimeList = this.currentPresets.reduce((previous: string[], current) => [...previous, ...current.mime], [] as string[])\n\t\treturn nodes.filter((node) => {\n\t\t\tif (!node.mime) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tconst mime = node.mime.toLowerCase()\n\n\t\t\tif (mimeList.includes(mime)) {\n\t\t\t\treturn true\n\t\t\t} else if (mimeList.includes(window.OC.MimeTypeList.aliases[mime])) {\n\t\t\t\treturn true\n\t\t\t} else if (mimeList.includes(mime.split('/')[0])) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\treturn false\n\t\t})\n\t}\n\n\tpublic reset(): void {\n\t\t// to be listener by the component\n\t\tthis.dispatchEvent(new CustomEvent('reset'))\n\t}\n\n\tpublic get presets(): ITypePreset[] {\n\t\treturn this.currentPresets\n\t}\n\n\tpublic setPresets(presets?: ITypePreset[]) {\n\t\tlogger.debug('TypeFilter: setting presets', { presets })\n\n\t\tthis.currentPresets = presets ?? []\n\t\tthis.filterUpdated()\n\n\t\tconst chips: IFileListFilterChip[] = []\n\t\tif (presets && presets.length > 0) {\n\t\t\tfor (const preset of presets) {\n\t\t\t\tchips.push({\n\t\t\t\t\ticon: preset.icon,\n\t\t\t\t\ttext: preset.label,\n\t\t\t\t\tonclick: () => this.removeFilterPreset(preset.id),\n\t\t\t\t})\n\t\t\t}\n\t\t} else {\n\t\t\tthis.reset()\n\t\t}\n\t\tthis.updateChips(chips)\n\t}\n\n\t/**\n\t * Helper callback that removed a preset from selected.\n\t * This is used when clicking on \"remove\" on a filter-chip.\n\t *\n\t * @param presetId Id of preset to remove\n\t */\n\tprivate removeFilterPreset(presetId: string) {\n\t\tconst filtered = this.currentPresets.filter(({ id }) => id !== presetId)\n\t\tthis.dispatchEvent(new CustomEvent('deselect', { detail: presetId }))\n\t\tthis.setPresets(filtered)\n\t}\n}\n\nexport type { TypeFilter }\n\n/**\n * Register the file list filter by file type\n */\nexport function registerTypeFilter() {\n\tconst WrappedComponent = defineCustomElement(FileListFilterType, { shadowRoot: false })\n\twindow.customElements.define(tagName, WrappedComponent)\n\tregisterFileListFilter(new TypeFilter())\n}\n","export default \"<svg xmlns=\\\"http://www.w3.org/2000/svg\\\" id=\\\"mdi-folder-plus-outline\\\" viewBox=\\\"0 0 24 24\\\"><path d=\\\"M13 19C13 19.34 13.04 19.67 13.09 20H4C2.9 20 2 19.11 2 18V6C2 4.89 2.89 4 4 4H10L12 6H20C21.1 6 22 6.89 22 8V13.81C21.39 13.46 20.72 13.22 20 13.09V8H4V18H13.09C13.04 18.33 13 18.66 13 19M20 18V15H18V18H15V20H18V23H20V20H23V18H20Z\\\" /></svg>\"","/*!\n * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport type { IFolder, INode, NewMenuEntry } from '@nextcloud/files'\n\nimport FolderPlusSvg from '@mdi/svg/svg/folder-plus-outline.svg?raw'\nimport { getCurrentUser } from '@nextcloud/auth'\nimport axios from '@nextcloud/axios'\nimport { showError, showSuccess } from '@nextcloud/dialogs'\nimport { emit } from '@nextcloud/event-bus'\nimport { Folder, Permission } from '@nextcloud/files'\nimport { t } from '@nextcloud/l10n'\nimport { basename } from 'path'\nimport { logger } from '../utils/logger.ts'\nimport { newNodeName } from '../utils/newNodeDialog.ts'\n\nexport const entry: NewMenuEntry = {\n\tid: 'newFolder',\n\torder: 0,\n\tdisplayName: t('files', 'New folder'),\n\t// Make the svg icon color match the primary element color\n\ticonSvgInline: FolderPlusSvg.replace(/viewBox/gi, 'style=\"color: var(--color-primary-element)\" viewBox'),\n\n\tenabled(context) {\n\t\treturn Boolean(context.permissions & Permission.CREATE)\n\t\t\t&& Boolean(context.permissions & Permission.READ)\n\t},\n\n\tasync handler(context: IFolder, content: INode[]) {\n\t\tconst name = await newNodeName(t('files', 'New folder'), content, { isFolder: true })\n\t\tif (name === null) {\n\t\t\treturn\n\t\t}\n\t\ttry {\n\t\t\tconst { fileid, source } = await createNewFolder(context, name.trim())\n\n\t\t\t// Create the folder in the store\n\t\t\tconst folder = new Folder({\n\t\t\t\tsource,\n\t\t\t\tid: fileid,\n\t\t\t\tmtime: new Date(),\n\t\t\t\towner: context.owner,\n\t\t\t\tpermissions: Permission.ALL,\n\t\t\t\troot: context?.root || '/files/' + getCurrentUser()?.uid,\n\t\t\t\t// Include mount-type from parent folder as this is inherited\n\t\t\t\tattributes: {\n\t\t\t\t\t'mount-type': context.attributes?.['mount-type'],\n\t\t\t\t\t'owner-id': context.attributes?.['owner-id'],\n\t\t\t\t\t'owner-display-name': context.attributes?.['owner-display-name'],\n\t\t\t\t\t'hide-download': context.attributes?.['hide-download'],\n\t\t\t\t},\n\t\t\t})\n\n\t\t\t// Show success\n\t\t\temit('files:node:created', folder)\n\t\t\tshowSuccess(t('files', 'Created new folder \"{name}\"', { name: basename(source) }))\n\t\t\tlogger.debug('Created new folder', { folder, source })\n\n\t\t\t// Navigate to the new folder\n\t\t\twindow.OCP.Files.Router.goToRoute(\n\t\t\t\tnull, // use default route\n\t\t\t\t{ view: 'files', fileid: String(fileid) },\n\t\t\t\t{ dir: context.path },\n\t\t\t)\n\t\t} catch (error) {\n\t\t\tlogger.error('Creating new folder failed', { error })\n\t\t\tshowError('Creating new folder failed')\n\t\t}\n\t},\n}\n\ntype createFolderResponse = {\n\tfileid: number\n\tsource: string\n}\n\n/**\n * Create a new folder in the given root with the given name\n *\n * @param root - The folder in which the new folder should be created\n * @param name - The name of the new folder\n */\nasync function createNewFolder(root: IFolder, name: string): Promise<createFolderResponse> {\n\tconst source = root.source + '/' + name\n\tconst encodedSource = root.encodedSource + '/' + encodeURIComponent(name)\n\n\tconst response = await axios({\n\t\tmethod: 'MKCOL',\n\t\turl: encodedSource,\n\t\theaders: {\n\t\t\tOverwrite: 'F',\n\t\t},\n\t})\n\treturn {\n\t\tfileid: parseInt(response.headers['oc-fileid']),\n\t\tsource,\n\t}\n}\n","/**\n * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport type { IFolder, INode, NewMenuEntry } from '@nextcloud/files'\nimport type { ComponentPublicInstance } from 'vue'\nimport type { TemplateFile } from '../types.ts'\n\nimport { addNewFileMenuEntry, Permission } from '@nextcloud/files'\nimport { loadState } from '@nextcloud/initial-state'\nimport { translate as t } from '@nextcloud/l10n'\nimport { isPublicShare } from '@nextcloud/sharing/public'\nimport { createApp, defineAsyncComponent, h } from 'vue'\nimport { newNodeName } from '../utils/newNodeDialog.ts'\n\n// async to reduce bundle size\nconst TemplatePickerVue = defineAsyncComponent(() => import('../views/TemplatePicker.vue'))\nlet TemplatePicker: ComponentPublicInstance & { open: (n: string, t: TemplateFile) => void } | null = null\n\n/**\n *\n * @param context\n */\nasync function getTemplatePicker(context: IFolder) {\n\tif (TemplatePicker === null) {\n\t\t// Create document root\n\t\tconst mountingPoint = document.createElement('div')\n\t\tmountingPoint.id = 'template-picker'\n\t\tdocument.body.appendChild(mountingPoint)\n\n\t\t// Init vue app\n\t\tconst app = createApp({\n\t\t\tmethods: { open(...args) { this.$refs.picker.open(...args) } },\n\t\t\trender: () => h(TemplatePickerVue, {\n\t\t\t\tref: 'picker',\n\t\t\t\tparent: context,\n\t\t\t}),\n\t\t})\n\t\tTemplatePicker = app.mount(mountingPoint) as ComponentPublicInstance & { open: (n: string, t: TemplateFile) => void }\n\t}\n\treturn TemplatePicker\n}\n\n/**\n * Register all new-file-menu entries for all template providers\n */\nexport function registerTemplateEntries() {\n\tlet templates: TemplateFile[]\n\tif (isPublicShare()) {\n\t\ttemplates = loadState<TemplateFile[]>('files_sharing', 'templates', [])\n\t} else {\n\t\ttemplates = loadState<TemplateFile[]>('files', 'templates', [])\n\t}\n\n\t// Init template files menu\n\ttemplates.forEach((provider, index) => {\n\t\taddNewFileMenuEntry({\n\t\t\tid: `template-new-${provider.app}-${index}`,\n\t\t\tdisplayName: provider.label,\n\t\t\ticonSvgInline: provider.iconSvgInline,\n\t\t\tenabled(context: IFolder): boolean {\n\t\t\t\tif (context.attributes['is-encrypted']) {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\n\t\t\t\t// templates are only supported in folders where the user has read and create permissions\n\t\t\t\treturn (context.permissions & Permission.READ) !== 0\n\t\t\t\t\t&& (context.permissions & Permission.CREATE) !== 0\n\t\t\t},\n\t\t\torder: 11,\n\t\t\tasync handler(context: IFolder, content: INode[]) {\n\t\t\t\tconst templatePicker = getTemplatePicker(context)\n\t\t\t\tconst name = await newNodeName(`${provider.label}${provider.extension}`, content, {\n\t\t\t\t\tlabel: t('files', 'Filename'),\n\t\t\t\t\tname: provider.label,\n\t\t\t\t})\n\n\t\t\t\tif (name !== null) {\n\t\t\t\t\t// Create the file\n\t\t\t\t\tconst picker = await templatePicker\n\t\t\t\t\tpicker.open(name.trim(), provider)\n\t\t\t\t}\n\t\t\t},\n\t\t} satisfies NewMenuEntry)\n\t})\n}\n","export default \"<svg xmlns=\\\"http://www.w3.org/2000/svg\\\" id=\\\"mdi-plus\\\" viewBox=\\\"0 0 24 24\\\"><path d=\\\"M19,13H13V19H11V13H5V11H11V5H13V11H19V13Z\\\" /></svg>\"","/**\n * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport type { IFolder, INode, NewMenuEntry } from '@nextcloud/files'\n\nimport PlusSvg from '@mdi/svg/svg/plus.svg?raw'\nimport { getCurrentUser } from '@nextcloud/auth'\nimport axios from '@nextcloud/axios'\nimport { showError } from '@nextcloud/dialogs'\nimport { Permission, removeNewFileMenuEntry } from '@nextcloud/files'\nimport { loadState } from '@nextcloud/initial-state'\nimport { translate as t } from '@nextcloud/l10n'\nimport { generateOcsUrl } from '@nextcloud/router'\nimport { join } from 'path'\nimport { logger } from '../utils/logger.ts'\nimport { newNodeName } from '../utils/newNodeDialog.ts'\n\nconst templatesEnabled = loadState<boolean>('files', 'templates_enabled', true)\nlet templatesPath = loadState<string | false>('files', 'templates_path', false)\nlogger.debug('Templates folder enabled', { templatesEnabled })\nlogger.debug('Initial templates folder', { templatesPath })\n\n/**\n * Init template folder\n *\n * @param directory Folder where to create the templates folder\n * @param name Name to use or the templates folder\n */\nasync function initTemplatesFolder(directory: IFolder, name: string) {\n\tconst templatePath = join(directory.path, name)\n\ttry {\n\t\tlogger.debug('Initializing the templates directory', { templatePath })\n\t\tconst { data } = await axios.post(generateOcsUrl('apps/files/api/v1/templates/path'), {\n\t\t\ttemplatePath,\n\t\t\tcopySystemTemplates: true,\n\t\t})\n\n\t\t// Go to template directory\n\t\twindow.OCP.Files.Router.goToRoute(\n\t\t\tnull, // use default route\n\t\t\t{ view: 'files', fileid: undefined },\n\t\t\t{ dir: templatePath },\n\t\t)\n\n\t\tlogger.info('Created new templates folder', {\n\t\t\t...data.ocs.data,\n\t\t})\n\t\ttemplatesPath = data.ocs.data.templates_path as string\n\t} catch (error) {\n\t\tlogger.error('Unable to initialize the templates directory', { error })\n\t\tshowError(t('files', 'Unable to initialize the templates directory'))\n\t}\n}\n\nexport const entry: NewMenuEntry = {\n\tid: 'template-picker',\n\tdisplayName: t('files', 'Create templates folder'),\n\ticonSvgInline: PlusSvg,\n\torder: 30,\n\tenabled(context: IFolder): boolean {\n\t\t// Templates disabled or templates folder already initialized\n\t\tif (!templatesEnabled || templatesPath) {\n\t\t\treturn false\n\t\t}\n\t\t// Allow creation on your own folders only\n\t\tif (context.owner !== getCurrentUser()?.uid) {\n\t\t\treturn false\n\t\t}\n\t\treturn (context.permissions & Permission.CREATE) !== 0\n\t},\n\tasync handler(context: IFolder, content: INode[]) {\n\t\tconst name = await newNodeName(t('files', 'Templates'), content, { name: t('files', 'New template folder'), isFolder: true })\n\n\t\tif (name !== null) {\n\t\t\t// Create the template folder\n\t\t\tinitTemplatesFolder(context, name)\n\n\t\t\t// Remove the menu entry\n\t\t\tremoveNewFileMenuEntry('template-picker')\n\t\t}\n\t},\n}\n","/**\n * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\nimport { generateUrl, getRootUrl } from '@nextcloud/router'\nimport { logger } from '../utils/logger.ts'\n\nexport default () => {\n\tif ('serviceWorker' in navigator) {\n\t\t// Use the window load event to keep the page load performant\n\t\twindow.addEventListener('load', async () => {\n\t\t\ttry {\n\t\t\t\tconst url = generateUrl('/apps/files/preview-service-worker.js', {}, { noRewrite: true })\n\t\t\t\tlet scope = getRootUrl()\n\t\t\t\t// If the instance is not in a subfolder an empty string will be returned.\n\t\t\t\t// The service worker registration will use the current path if it receives an empty string,\n\t\t\t\t// which will result in a service worker registration for every single path the user visits.\n\t\t\t\tif (scope === '') {\n\t\t\t\t\tscope = '/'\n\t\t\t\t}\n\n\t\t\t\tconst registration = await navigator.serviceWorker.register(url, { scope })\n\t\t\t\tlogger.debug('SW registered: ', { registration })\n\t\t\t} catch (error) {\n\t\t\t\tlogger.error('SW registration failed: ', { error })\n\t\t\t}\n\t\t})\n\t} else {\n\t\tlogger.debug('Service Worker is not enabled on this browser.')\n\t}\n}\n","/*!\n * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport type { ContentsWithRoot } from '@nextcloud/files'\n\nimport { getCurrentUser } from '@nextcloud/auth'\nimport { Folder, Permission } from '@nextcloud/files'\nimport { getFavoriteNodes, getRemoteURL, getRootPath } from '@nextcloud/files/dav'\nimport { logger } from '../utils/logger.ts'\nimport { getContents as filesContents } from './Files.ts'\nimport { client } from './WebdavClient.ts'\n\n/**\n * Get the contents for the favorites view\n *\n * @param path - The path to get the contents for\n * @param options - Additional options\n * @param options.signal - Optional AbortSignal to cancel the request\n * @return A promise resolving to the contents with root folder\n */\nexport async function getContents(path = '/', options: { signal: AbortSignal }): Promise<ContentsWithRoot> {\n\t// We only filter root files for favorites, for subfolders we can simply reuse the files contents\n\tif (path && path !== '/') {\n\t\treturn filesContents(path, options)\n\t}\n\n\ttry {\n\t\tconst contents = await getFavoriteNodes({ client, signal: options.signal })\n\t\treturn {\n\t\t\tcontents,\n\t\t\tfolder: new Folder({\n\t\t\t\tid: 0,\n\t\t\t\tsource: `${getRemoteURL()}${getRootPath()}`,\n\t\t\t\troot: getRootPath(),\n\t\t\t\towner: getCurrentUser()?.uid || null,\n\t\t\t\tpermissions: Permission.READ,\n\t\t\t}),\n\t\t}\n\t} catch (error) {\n\t\tif (options.signal.aborted) {\n\t\t\tlogger.debug('Favorite nodes request was aborted')\n\t\t\tthrow new DOMException('Aborted', 'AbortError')\n\t\t}\n\t\tlogger.error('Failed to load favorite nodes via WebDAV', { error })\n\t\tthrow error\n\t}\n}\n","/*!\n * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport type { Folder, Node } from '@nextcloud/files'\n\nimport FolderSvg from '@mdi/svg/svg/folder-outline.svg?raw'\nimport StarSvg from '@mdi/svg/svg/star-outline.svg?raw'\nimport { subscribe } from '@nextcloud/event-bus'\nimport { FileType, getNavigation, View } from '@nextcloud/files'\nimport { getCanonicalLocale, getLanguage, t } from '@nextcloud/l10n'\nimport { getContents } from '../services/Favorites.ts'\nimport { hashCode } from '../utils/hashUtils.ts'\nimport { logger } from '../utils/logger.ts'\n\n/**\n * Generate a favorite folder view\n *\n * @param folder - The folder to generate the view for\n * @param index - The order index\n */\nfunction generateFavoriteFolderView(folder: Folder, index = 0): View {\n\treturn new View({\n\t\tid: generateIdFromPath(folder.path),\n\t\tname: folder.displayname,\n\n\t\ticon: FolderSvg,\n\t\torder: index,\n\n\t\tparams: {\n\t\t\tdir: folder.path,\n\t\t\tfileid: String(folder.fileid),\n\t\t\tview: 'favorites',\n\t\t},\n\n\t\tparent: 'favorites',\n\n\t\tcolumns: [],\n\n\t\tgetContents,\n\t})\n}\n\n/**\n * Generate a unique id from the folder path\n *\n * @param path - The folder path\n */\nfunction generateIdFromPath(path: string): string {\n\treturn `favorite-${hashCode(path)}`\n}\n\n/**\n * Register the favorites view and setup event listeners to update it\n */\nexport async function registerFavoritesView() {\n\tconst Navigation = getNavigation()\n\tNavigation.register(new View({\n\t\tid: 'favorites',\n\t\tname: t('files', 'Favorites'),\n\t\tcaption: t('files', 'List of favorite files and folders.'),\n\n\t\temptyTitle: t('files', 'No favorites yet'),\n\t\temptyCaption: t('files', 'Files and folders you mark as favorite will show up here'),\n\n\t\ticon: StarSvg,\n\t\torder: 15,\n\n\t\tcolumns: [],\n\n\t\tgetContents,\n\t}))\n\n\tconst controller = new AbortController()\n\tconst favoriteFolders = (await getContents('', { signal: controller.signal })).contents\n\t\t.filter((node) => node.type === FileType.Folder) as Folder[]\n\tconst favoriteFoldersViews = favoriteFolders\n\t\t.map((folder, index) => generateFavoriteFolderView(folder, index)) as View[]\n\tlogger.debug('Generating favorites view', { favoriteFolders })\n\tfavoriteFoldersViews.forEach((view) => Navigation.register(view))\n\n\t/**\n\t * Update favorites navigation when a new folder is added\n\t */\n\tsubscribe('files:favorites:added', (node: Node) => {\n\t\tif (node.type !== FileType.Folder) {\n\t\t\treturn\n\t\t}\n\n\t\t// Sanity check\n\t\tif (node.path === null || !node.root?.startsWith('/files')) {\n\t\t\tlogger.error('Favorite folder is not within user files root', { node })\n\t\t\treturn\n\t\t}\n\n\t\taddToFavorites(node as Folder)\n\t})\n\n\t/**\n\t * Remove favorites navigation when a folder is removed\n\t */\n\tsubscribe('files:favorites:removed', (node: Node) => {\n\t\tif (node.type !== FileType.Folder) {\n\t\t\treturn\n\t\t}\n\n\t\t// Sanity check\n\t\tif (node.path === null || !node.root?.startsWith('/files')) {\n\t\t\tlogger.error('Favorite folder is not within user files root', { node })\n\t\t\treturn\n\t\t}\n\n\t\tremovePathFromFavorites(node.path)\n\t})\n\n\t/**\n\t * Update favorites navigation when a folder is renamed\n\t */\n\tsubscribe('files:node:renamed', (node: Node) => {\n\t\tif (node.type !== FileType.Folder) {\n\t\t\treturn\n\t\t}\n\n\t\tif (node.attributes.favorite !== 1) {\n\t\t\treturn\n\t\t}\n\n\t\tupdateNodeFromFavorites(node as Folder)\n\t})\n\n\t/**\n\t * Sort the favorites paths array and\n\t * update the order property of the existing views\n\t */\n\tconst updateAndSortViews = function() {\n\t\tfavoriteFolders.sort((a, b) => a.basename.localeCompare(b.basename, [getLanguage(), getCanonicalLocale()], { ignorePunctuation: true, numeric: true, usage: 'sort' }))\n\t\tfavoriteFolders.forEach((folder, index) => {\n\t\t\tconst view = favoriteFoldersViews.find((view) => view.id === generateIdFromPath(folder.path))\n\t\t\tif (view) {\n\t\t\t\tview.order = index\n\t\t\t}\n\t\t})\n\t}\n\n\t/**\n\t * Add a folder to the favorites paths array and update the views\n\t *\n\t * @param node - The folder node\n\t */\n\tfunction addToFavorites(node: Folder) {\n\t\tconst view = generateFavoriteFolderView(node)\n\n\t\t// Skip if already exists\n\t\tif (favoriteFolders.find((folder) => folder.path === node.path)) {\n\t\t\treturn\n\t\t}\n\n\t\t// Update arrays\n\t\tfavoriteFolders.push(node)\n\t\tfavoriteFoldersViews.push(view)\n\n\t\t// Update and sort views\n\t\tupdateAndSortViews()\n\t\tNavigation.register(view)\n\t}\n\n\t/**\n\t * Remove a folder from the favorites paths array and update the views\n\t *\n\t * @param path - The folder path\n\t */\n\tfunction removePathFromFavorites(path: string) {\n\t\tconst id = generateIdFromPath(path)\n\t\tconst index = favoriteFolders.findIndex((folder) => folder.path === path)\n\n\t\t// Skip if not exists\n\t\tif (index === -1) {\n\t\t\treturn\n\t\t}\n\n\t\t// Update arrays\n\t\tfavoriteFolders.splice(index, 1)\n\t\tfavoriteFoldersViews.splice(index, 1)\n\n\t\t// Update and sort views\n\t\tNavigation.remove(id)\n\t\tupdateAndSortViews()\n\t}\n\n\t/**\n\t * Update a folder from the favorites paths array and update the views\n\t *\n\t * @param node - The updated folder node\n\t */\n\tfunction updateNodeFromFavorites(node: Folder) {\n\t\tconst favoriteFolder = favoriteFolders.find((folder) => folder.fileid === node.fileid)\n\n\t\t// Skip if it does not exists\n\t\tif (favoriteFolder === undefined) {\n\t\t\treturn\n\t\t}\n\n\t\tremovePathFromFavorites(favoriteFolder.path)\n\t\taddToFavorites(node)\n\t}\n\n\tupdateAndSortViews()\n}\n","/*!\n * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport type { IFolder, INode, IView } from '@nextcloud/files'\nimport type { TreeNode } from '../services/FolderTree.ts'\n\nimport FolderMultipleSvg from '@mdi/svg/svg/folder-multiple-outline.svg?raw'\nimport FolderSvg from '@mdi/svg/svg/folder-outline.svg?raw'\nimport { subscribe } from '@nextcloud/event-bus'\nimport { FileType, getNavigation, View } from '@nextcloud/files'\nimport { loadState } from '@nextcloud/initial-state'\nimport { t } from '@nextcloud/l10n'\nimport { isSamePath } from '@nextcloud/paths'\nimport PQueue from 'p-queue'\nimport {\n\tfolderTreeId,\n\tgetContents,\n\tgetFolderTreeNodes,\n\tgetSourceParent,\n\tsourceRoot,\n} from '../services/FolderTree.ts'\nimport { useFilesStore } from '../store/files.ts'\nimport { pinia } from '../store/index.ts'\n\ninterface IFolderTreeView extends IView {\n\tloading?: boolean\n\tloaded?: boolean\n}\n\nconst Navigation = getNavigation()\nconst queue = new PQueue({ concurrency: 5, intervalCap: 5, interval: 200 })\nconst isFolderTreeEnabled = loadState('files', 'config', { folder_tree: true }).folder_tree\nlet showHiddenFiles = loadState('files', 'config', { show_hidden: false }).show_hidden\n\nconst folderTreeView: IFolderTreeView = new View({\n\tid: folderTreeId,\n\n\tname: t('files', 'Folder tree'),\n\tcaption: t('files', 'List of your files and folders.'),\n\n\ticon: FolderMultipleSvg,\n\torder: 50, // Below all other views\n\n\tgetContents,\n\n\tasync loadChildViews(view) {\n\t\tconst treeView = view as IFolderTreeView\n\t\tif (treeView.loading || treeView.loaded) {\n\t\t\treturn\n\t\t}\n\n\t\ttreeView.loading = true\n\t\ttry {\n\t\t\tconst dir = new URLSearchParams(window.location.search).get('dir') ?? '/'\n\t\t\tconst tree = await getFolderTreeNodes(dir, 1, true)\n\t\t\tregisterNodeViews(tree, dir)\n\t\t\ttreeView.loaded = true\n\n\t\t\tsubscribe('files:node:created', onCreateNode)\n\t\t\tsubscribe('files:node:deleted', onDeleteNode)\n\t\t\tsubscribe('files:node:moved', onMoveNode)\n\t\t\tsubscribe('files:config:updated', onUserConfigUpdated)\n\t\t} finally {\n\t\t\ttreeView.loading = false\n\t\t}\n\t},\n})\n\n/**\n * Register the folder tree feature\n */\nexport async function registerFolderTreeView() {\n\tif (!isFolderTreeEnabled) {\n\t\treturn\n\t}\n\tNavigation.register(folderTreeView)\n}\n\n/**\n * Helper to register node views in the navigation.\n *\n * @param nodes - The nodes to register\n * @param path - The path to expand by default, if any\n */\nasync function registerNodeViews(nodes: (TreeNode | IFolder)[], path?: string) {\n\tconst views: IView[] = []\n\tfor (const node of nodes) {\n\t\tconst isRegistered = Navigation.views.some((view) => view.id === `${folderTreeId}::${node.encodedSource}`)\n\t\t// skip hidden files if the setting is disabled\n\t\tif (!showHiddenFiles && node.basename.startsWith('.')) {\n\t\t\tif (isRegistered) {\n\t\t\t\t// and also remove any existing views for hidden files if the setting was toggled\n\t\t\t\tNavigation.remove(`${folderTreeId}::${node.encodedSource}`)\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\t// skip already registered views to avoid duplicates when loading multiple levels\n\t\tif (isRegistered) {\n\t\t\tcontinue\n\t\t}\n\n\t\tviews.push(generateNodeView(\n\t\t\tnode,\n\t\t\tpath === node.path || path?.startsWith(node.path + '/') ? true : undefined,\n\t\t))\n\t}\n\tNavigation.register(...views)\n}\n\n/**\n * Generates a navigation view for a given folder tree node or folder.\n *\n * @param node - The folder tree node or folder for which to generate the view.\n * @param expanded - Whether the view should be expanded by default.\n */\nfunction generateNodeView(node: TreeNode | IFolder, expanded?: boolean): IView {\n\treturn {\n\t\tid: `${folderTreeId}::${node.encodedSource}`,\n\t\tparent: getSourceParent(node.source),\n\n\t\texpanded,\n\t\tloaded: expanded,\n\n\t\t// @ts-expect-error Casing differences\n\t\tname: node.displayName ?? node.displayname ?? node.basename,\n\n\t\ticon: FolderSvg,\n\n\t\tgetContents,\n\t\tloadChildViews: getLoadChildViews(node),\n\n\t\tparams: {\n\t\t\tview: folderTreeId,\n\t\t\tfileid: String(node.fileid), // Needed for matching exact routes\n\t\t\tdir: node.path,\n\t\t},\n\t}\n}\n\n/**\n * Generates a function to load child views for a given folder tree node or folder.\n * This function is used as the `loadChildViews` callback in the navigation view.\n *\n * @param node - The folder tree node or folder for which to generate the child view loader function.\n */\nfunction getLoadChildViews(node: TreeNode | IFolder) {\n\treturn async (view: IView): Promise<void> => {\n\t\tconst treeView = view as IFolderTreeView\n\t\tif (treeView.loading || treeView.loaded) {\n\t\t\treturn\n\t\t}\n\n\t\ttreeView.loading = true\n\t\ttry {\n\t\t\tawait updateTreeChildren(node.path)\n\t\t\ttreeView.loaded = true\n\t\t} finally {\n\t\t\ttreeView.loading = false\n\t\t}\n\t}\n}\n\n/**\n * Registers child views for the given path. If no path is provided, it registers the root nodes.\n *\n * @param path - The path for which to register child views. Defaults to '/' for root nodes.\n */\nasync function updateTreeChildren(path: string = '/') {\n\tawait queue.add(async () => {\n\t\tconst filesStore = useFilesStore(pinia)\n\t\tconst cachedNodes = filesStore.getNodesByPath(Navigation.active!.id, path)\n\t\tif (cachedNodes.length > 0) {\n\t\t\t// if there are nodes loaded in the path we dont need to fetch from API\n\t\t\tconst folders = cachedNodes.filter((node) => node.type === FileType.Folder) as IFolder[]\n\t\t\tregisterNodeViews(folders, path)\n\t\t} else {\n\t\t\t// otherwise we need to fetch the tree nodes for the path\n\t\t\tconst nodes = await getFolderTreeNodes(path, 2)\n\t\t\tregisterNodeViews(nodes)\n\t\t}\n\t})\n}\n\n/**\n * Remove a folder view from the navigation.\n *\n * @param folder - The folder for which to remove the view\n */\nfunction removeFolderView(folder: IFolder) {\n\tconst viewId = folder.encodedSource\n\tNavigation.remove(viewId)\n}\n\n/**\n * Remove a folder view from the navigation by its source URL.\n *\n * @param source - The source URL of the folder for which to remove the view\n */\nfunction removeFolderViewSource(source: string) {\n\tNavigation.remove(source)\n}\n\n/**\n * Handle node creation events to add new folder tree views to the navigation.\n *\n * @param node - The node that was created\n */\nfunction onCreateNode(node: INode) {\n\tif (node.type !== FileType.Folder) {\n\t\treturn\n\t}\n\tregisterNodeViews([node as IFolder])\n}\n\n/**\n * Handle node deletion events to remove the corresponding folder tree views from the navigation.\n *\n * @param node - The node that was deleted\n */\nfunction onDeleteNode(node: INode) {\n\tif (node.type !== FileType.Folder) {\n\t\treturn\n\t}\n\tremoveFolderView(node as IFolder)\n}\n\n/**\n * Handle node move events to update the folder tree views accordingly.\n *\n * @param context - the event context\n * @param context.node - The node that was moved\n * @param context.oldSource - the old source URL of the moved node\n */\nfunction onMoveNode({ node, oldSource }) {\n\tif (node.type !== FileType.Folder) {\n\t\treturn\n\t}\n\tremoveFolderViewSource(oldSource)\n\tregisterNodeViews([node as IFolder])\n\n\tconst newPath = node.source.replace(sourceRoot, '')\n\tconst oldPath = oldSource.replace(sourceRoot, '')\n\tconst childViews = Navigation.views.filter((view) => {\n\t\tif (!view.params?.dir) {\n\t\t\treturn false\n\t\t}\n\t\tif (isSamePath(view.params.dir, oldPath)) {\n\t\t\treturn false\n\t\t}\n\t\treturn view.params.dir.startsWith(oldPath)\n\t})\n\tfor (const view of childViews) {\n\t\tview.parent = getSourceParent(node.source)\n\t\tview.params!.dir = view.params!.dir!.replace(oldPath, newPath)\n\t}\n}\n\n/**\n * Handle user config updates, specifically for the \"show hidden files\" setting,\n * to show hidden folders in the folder tree when enabled and hide them when disabled.\n *\n * @param context - the event context\n * @param context.key - the key of the updated config\n * @param context.value - the new value of the updated config\n */\nasync function onUserConfigUpdated({ key, value }) {\n\tif (key === 'show_hidden') {\n\t\tshowHiddenFiles = value\n\t\tawait updateTreeChildren()\n\t}\n}\n","export default \"<svg xmlns=\\\"http://www.w3.org/2000/svg\\\" id=\\\"mdi-account-outline\\\" viewBox=\\\"0 0 24 24\\\"><path d=\\\"M12,4A4,4 0 0,1 16,8A4,4 0 0,1 12,12A4,4 0 0,1 8,8A4,4 0 0,1 12,4M12,6A2,2 0 0,0 10,8A2,2 0 0,0 12,10A2,2 0 0,0 14,8A2,2 0 0,0 12,6M12,13C14.67,13 20,14.33 20,17V20H4V17C4,14.33 9.33,13 12,13M12,14.9C9.03,14.9 5.9,16.36 5.9,17V18.1H18.1V17C18.1,16.36 14.97,14.9 12,14.9Z\\\" /></svg>\"","/**\n * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport type { ContentsWithRoot, Node } from '@nextcloud/files'\n\nimport { getCurrentUser } from '@nextcloud/auth'\nimport { getContents as getFiles } from './Files.ts'\n\nconst currentUserId = getCurrentUser()?.uid\n\n/**\n * Filters each file/folder on its shared status\n *\n * A personal file is considered a file that has all of the following properties:\n * 1. the current user owns\n * 2. the file is not shared with anyone\n * 3. the file is not a group folder\n *\n * @todo Move to `@nextcloud/files`\n * @param node The node to check\n */\nexport function isPersonalFile(node: Node): boolean {\n\t// the type of mounts that determine whether the file is shared\n\tconst sharedMountTypes = ['group', 'shared']\n\tconst mountType = node.attributes['mount-type']\n\n\treturn currentUserId === node.owner && !sharedMountTypes.includes(mountType)\n}\n\n/**\n * Get personal files from a given path\n *\n * @param path - The path to get the personal files from\n * @param options - Options\n * @param options.signal - Abort signal to cancel the request\n * @return A promise that resolves to the personal files\n */\nexport function getContents(path: string = '/', options: { signal: AbortSignal }): Promise<ContentsWithRoot> {\n\t// get all the files from the current path as a cancellable promise\n\t// then filter the files that the user does not own, or has shared / is a group folder\n\treturn getFiles(path, options)\n\t\t.then((content) => {\n\t\t\tcontent.contents = content.contents.filter(isPersonalFile)\n\t\t\treturn content\n\t\t})\n}\n","/**\n * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport AccountIcon from '@mdi/svg/svg/account-outline.svg?raw'\nimport { getNavigation, View } from '@nextcloud/files'\nimport { t } from '@nextcloud/l10n'\nimport { getContents } from '../services/PersonalFiles.ts'\nimport { defaultView, hasPersonalFilesView } from '../utils/filesViews.ts'\n\nexport const VIEW_ID = 'personal'\n\n/**\n * Register the personal files view if allowed\n */\nexport function registerPersonalFilesView(): void {\n\tif (!hasPersonalFilesView()) {\n\t\treturn\n\t}\n\n\tconst Navigation = getNavigation()\n\tNavigation.register(new View({\n\t\tid: VIEW_ID,\n\t\tname: t('files', 'Personal files'),\n\t\tcaption: t('files', 'List of your files and folders that are not shared.'),\n\n\t\temptyTitle: t('files', 'No personal files found'),\n\t\temptyCaption: t('files', 'Files that are not shared will show up here.'),\n\n\t\ticon: AccountIcon,\n\t\t// if this is the default view we set it at the top of the list - otherwise default position of fifth\n\t\torder: defaultView() === VIEW_ID ? 0 : 5,\n\n\t\tgetContents,\n\t}))\n}\n","/**\n * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\nimport type { ContentsWithRoot, Node } from '@nextcloud/files'\nimport type { ResponseDataDetailed, SearchResult } from 'webdav'\n\nimport { getCurrentUser } from '@nextcloud/auth'\nimport { Folder, Permission } from '@nextcloud/files'\nimport { getRecentSearch, getRemoteURL, getRootPath, resultToNode } from '@nextcloud/files/dav'\nimport { loadState } from '@nextcloud/initial-state'\nimport { pinia } from '../store/index.ts'\nimport { useUserConfigStore } from '../store/userconfig.ts'\nimport { logger } from '../utils/logger.ts'\nimport { client } from './WebdavClient.ts'\n\nconst lastTwoWeeksTimestamp = Math.round((Date.now() / 1000) - (60 * 60 * 24 * 14))\nconst recentLimit = loadState<number>('files', 'recent_limit', 100)\n\n/**\n * Get recently changed nodes\n *\n * This takes the users preference about hidden files into account.\n * If hidden files are not shown, then also recently changed files *in* hidden directories are filtered.\n *\n * @param path Path to search for recent changes\n * @param options Options including abort signal\n * @param options.signal Abort signal to cancel the request\n */\nexport async function getContents(path = '/', options?: { signal: AbortSignal }): Promise<ContentsWithRoot> {\n\tconst store = useUserConfigStore(pinia)\n\n\t/**\n\t * Filter function that returns only the visible nodes - or hidden if explicitly configured\n\t *\n\t * @param node The node to check\n\t */\n\tconst filterHidden = (node: Node) => path !== '/' // We need to hide files from hidden directories in the root if not configured to show\n\t\t|| store.userConfig.show_hidden // If configured to show hidden files we can early return\n\t\t|| !node.dirname.split('/').some((dir) => dir.startsWith('.')) // otherwise only include the file if non of the parent directories is hidden\n\n\ttry {\n\t\tconst contentsResponse = await client.search('/', {\n\t\t\tsignal: options?.signal,\n\t\t\tdetails: true,\n\t\t\tdata: getRecentSearch(lastTwoWeeksTimestamp, recentLimit),\n\t\t}) as ResponseDataDetailed<SearchResult>\n\n\t\tconst contents = contentsResponse.data.results\n\t\t\t.map((stat) => {\n\t\t\t\t// The search endpoint already includes the dav remote URL so we must not include it in the source\n\t\t\t\tstat.filename = stat.filename.replace('/remote.php/dav', '')\n\t\t\t\treturn resultToNode(stat)\n\t\t\t})\n\t\t\t.filter(filterHidden)\n\n\t\treturn {\n\t\t\tfolder: new Folder({\n\t\t\t\tid: 0,\n\t\t\t\tsource: `${getRemoteURL()}${getRootPath()}`,\n\t\t\t\troot: getRootPath(),\n\t\t\t\towner: getCurrentUser()?.uid || null,\n\t\t\t\tpermissions: Permission.READ,\n\t\t\t}),\n\t\t\tcontents,\n\t\t}\n\t} catch (error) {\n\t\tif (options?.signal.aborted) {\n\t\t\tlogger.info('Fetching recent files aborted')\n\t\t\tthrow new DOMException('Aborted', 'AbortError')\n\t\t}\n\t\tlogger.error('Failed to fetch recent files', { error })\n\t\tthrow error\n\t}\n}\n","/**\n * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport HistorySvg from '@mdi/svg/svg/history.svg?raw'\nimport { getNavigation, View } from '@nextcloud/files'\nimport { t } from '@nextcloud/l10n'\nimport { getContents } from '../services/Recent.ts'\n\nexport default () => {\n\tconst Navigation = getNavigation()\n\tNavigation.register(new View({\n\t\tid: 'recent',\n\t\tname: t('files', 'Recent'),\n\t\tcaption: t('files', 'List of recently modified files and folders.'),\n\n\t\temptyTitle: t('files', 'No recently modified files'),\n\t\temptyCaption: t('files', 'Files and folders you recently modified will show up here.'),\n\n\t\ticon: HistorySvg,\n\t\torder: 10,\n\n\t\tdefaultSortKey: 'mtime',\n\n\t\tgetContents,\n\t}))\n}\n","/**\n * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport { addNewFileMenuEntry, getNewFileMenu, registerFileAction } from '@nextcloud/files'\nimport { registerDavProperty } from '@nextcloud/files/dav'\nimport { isPublicShare } from '@nextcloud/sharing/public'\nimport { registerConvertActions } from './actions/convertAction.ts'\nimport { action as deleteAction } from './actions/deleteAction.ts'\nimport { action as downloadAction } from './actions/downloadAction.ts'\nimport { action as favoriteAction } from './actions/favoriteAction.ts'\nimport { action as moveOrCopyAction } from './actions/moveOrCopyAction.ts'\nimport { action as openFolderAction } from './actions/openFolderAction.ts'\nimport { action as openInFilesAction } from './actions/openInFilesAction.ts'\nimport { action as editLocallyAction } from './actions/openLocallyAction.ts'\nimport { action as renameAction } from './actions/renameAction.ts'\nimport { action as sidebarAction } from './actions/sidebarAction.ts'\nimport { registerSidebarFavoriteAction } from './actions/sidebarFavoriteAction.ts'\nimport { action as viewInFolderAction } from './actions/viewInFolderAction.ts'\nimport { registerFilenameFilter } from './filters/FilenameFilter.ts'\nimport { registerHiddenFilesFilter } from './filters/HiddenFilesFilter.ts'\nimport { registerModifiedFilter } from './filters/ModifiedFilter.ts'\nimport { registerTypeFilter } from './filters/TypeFilter.ts'\nimport { entry as newFolderEntry } from './newMenu/newFolder.ts'\nimport { registerTemplateEntries } from './newMenu/newFromTemplate.ts'\nimport { entry as newTemplatesFolder } from './newMenu/newTemplatesFolder.ts'\nimport { initLivePhotos } from './services/LivePhotos.ts'\nimport registerPreviewServiceWorker from './services/ServiceWorker.js'\nimport { registerFavoritesView } from './views/favorites.ts'\nimport { registerFilesView } from './views/files.ts'\nimport { registerFolderTreeView } from './views/folderTree.ts'\nimport { registerPersonalFilesView } from './views/personal-files.ts'\nimport registerRecentView from './views/recent.ts'\nimport { registerSearchView } from './views/search.ts'\n\n// Register file actions\nregisterConvertActions()\nregisterFileAction(deleteAction)\nregisterFileAction(downloadAction)\nregisterFileAction(editLocallyAction)\nregisterFileAction(favoriteAction)\nregisterFileAction(moveOrCopyAction)\nregisterFileAction(openFolderAction)\nregisterFileAction(openInFilesAction)\nregisterFileAction(renameAction)\nregisterFileAction(sidebarAction)\nregisterFileAction(viewInFolderAction)\n\n// Register new menu entry\naddNewFileMenuEntry(newFolderEntry)\naddNewFileMenuEntry(newTemplatesFolder)\nregisterTemplateEntries()\n\n// Register files views when not on public share\nif (isPublicShare() === false) {\n\tregisterFavoritesView()\n\tregisterFilesView()\n\tregisterPersonalFilesView()\n\tregisterRecentView()\n\tregisterSearchView()\n\tregisterFolderTreeView()\n}\n\n// Register file list filters\nregisterHiddenFilesFilter()\nregisterTypeFilter()\nregisterModifiedFilter()\nregisterFilenameFilter()\n\n// Register sidebar action\nregisterSidebarFavoriteAction()\n\n// Register preview service worker\nregisterPreviewServiceWorker()\n\nregisterDavProperty('nc:hidden', { nc: 'http://nextcloud.org/ns' })\nregisterDavProperty('nc:is-mount-root', { nc: 'http://nextcloud.org/ns' })\nregisterDavProperty('nc:metadata-blurhash', { nc: 'http://nextcloud.org/ns' })\n\ninitLivePhotos()\n\n// TODO: REMOVE THIS ONCE THE UPLOAD LIBRARY IS MIGRATED TO THE NEW FILES LIBRARY\nwindow._nc_newfilemenu = new Proxy(getNewFileMenu(), {\n\tget(target, prop) {\n\t\treturn target[prop as keyof typeof target]\n\t},\n\tset(target, prop, value) {\n\t\ttarget[prop as keyof typeof target] = value\n\t\treturn true\n\t},\n})\n"],"file":"files-init.mjs"} |