mirror of
https://github.com/nextcloud/server.git
synced 2026-06-06 23:34:22 -04:00
Merge pull request #45836 from nextcloud/backport/45251/stable28
[stable28] fix(files): do not rely on unique fileid
This commit is contained in:
commit
683ae3c2fd
18 changed files with 143 additions and 89 deletions
|
|
@ -71,6 +71,7 @@ import { useSelectionStore } from '../store/selection.ts'
|
|||
import { useUploaderStore } from '../store/uploader.ts'
|
||||
import filesListWidthMixin from '../mixins/filesListWidth.ts'
|
||||
import logger from '../logger'
|
||||
import type { FileSource } from '../types.ts'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'BreadCrumbs',
|
||||
|
|
@ -123,8 +124,9 @@ export default defineComponent({
|
|||
|
||||
sections() {
|
||||
return this.dirs.map((dir: string, index: number) => {
|
||||
const fileid = this.getFileIdFromPath(dir)
|
||||
const to = { ...this.$route, params: { fileid }, query: { dir } }
|
||||
const source = this.getFileSourceFromPath(dir)
|
||||
const node: Node | undefined = source ? this.getNodeFromSource(source) : undefined
|
||||
const to = { ...this.$route, params: { node: node?.fileid }, query: { dir } }
|
||||
return {
|
||||
dir,
|
||||
exact: true,
|
||||
|
|
@ -153,19 +155,19 @@ export default defineComponent({
|
|||
},
|
||||
|
||||
selectedFiles() {
|
||||
return this.selectionStore.selected
|
||||
return this.selectionStore.selected as FileSource[]
|
||||
},
|
||||
|
||||
draggingFiles() {
|
||||
return this.draggingStore.dragging
|
||||
return this.draggingStore.dragging as FileSource[]
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
getNodeFromId(id: number): Node | undefined {
|
||||
return this.filesStore.getNode(id)
|
||||
getNodeFromSource(source: FileSource): Node | undefined {
|
||||
return this.filesStore.getNode(source)
|
||||
},
|
||||
getFileIdFromPath(path: string): number | undefined {
|
||||
getFileSourceFromPath(path: string): FileSource | undefined {
|
||||
return this.pathsStore.getPath(this.currentView!.id, path)
|
||||
},
|
||||
getDirDisplayName(path: string): string {
|
||||
|
|
@ -173,8 +175,8 @@ export default defineComponent({
|
|||
return this.$navigation?.active?.name || t('files', 'Home')
|
||||
}
|
||||
|
||||
const fileId: number | undefined = this.getFileIdFromPath(path)
|
||||
const node: Node | undefined = (fileId) ? this.getNodeFromId(fileId) : undefined
|
||||
const source: FileSource | undefined = this.getFileSourceFromPath(path)
|
||||
const node: Node | undefined = source ? this.getNodeFromSource(source) : undefined
|
||||
return node?.attributes?.displayName || basename(path)
|
||||
},
|
||||
|
||||
|
|
@ -244,12 +246,12 @@ export default defineComponent({
|
|||
}
|
||||
|
||||
// Else we're moving/copying files
|
||||
const nodes = selection.map(fileid => this.filesStore.getNode(fileid)) as Node[]
|
||||
const nodes = selection.map(source => this.filesStore.getNode(source)) as Node[]
|
||||
await onDropInternalFiles(nodes, folder, contents.contents, isCopy)
|
||||
|
||||
// Reset selection after we dropped the files
|
||||
// if the dropped files are within the selection
|
||||
if (selection.some(fileid => this.selectedFiles.includes(fileid))) {
|
||||
if (selection.some(source => this.selectedFiles.includes(source))) {
|
||||
logger.debug('Dropped selection, resetting select store...')
|
||||
this.selectionStore.reset()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ import NcLoadingIcon from '@nextcloud/vue/dist/Components/NcLoadingIcon.js'
|
|||
import { useKeyboardStore } from '../../store/keyboard.ts'
|
||||
import { useSelectionStore } from '../../store/selection.ts'
|
||||
import logger from '../../logger.js'
|
||||
import type { FileSource } from '../../types.ts'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'FileEntryCheckbox',
|
||||
|
|
@ -83,10 +84,10 @@ export default defineComponent({
|
|||
return this.selectionStore.selected
|
||||
},
|
||||
isSelected() {
|
||||
return this.selectedFiles.includes(this.fileid)
|
||||
return this.selectedFiles.includes(this.source.source)
|
||||
},
|
||||
index() {
|
||||
return this.nodes.findIndex((node: Node) => node.fileid === this.fileid)
|
||||
return this.nodes.findIndex((node: Node) => node.source === this.source.source)
|
||||
},
|
||||
isFile() {
|
||||
return this.source.type === FileType.File
|
||||
|
|
@ -105,20 +106,20 @@ export default defineComponent({
|
|||
|
||||
// Get the last selected and select all files in between
|
||||
if (this.keyboardStore?.shiftKey && lastSelectedIndex !== null) {
|
||||
const isAlreadySelected = this.selectedFiles.includes(this.fileid)
|
||||
const isAlreadySelected = this.selectedFiles.includes(this.source.source)
|
||||
|
||||
const start = Math.min(newSelectedIndex, lastSelectedIndex)
|
||||
const end = Math.max(lastSelectedIndex, newSelectedIndex)
|
||||
|
||||
const lastSelection = this.selectionStore.lastSelection
|
||||
const filesToSelect = this.nodes
|
||||
.map(file => file.fileid)
|
||||
.map(file => file.source)
|
||||
.slice(start, end + 1)
|
||||
.filter(Boolean) as number[]
|
||||
.filter(Boolean) as FileSource[]
|
||||
|
||||
// If already selected, update the new selection _without_ the current file
|
||||
const selection = [...lastSelection, ...filesToSelect]
|
||||
.filter(fileid => !isAlreadySelected || fileid !== this.fileid)
|
||||
.filter(source => !isAlreadySelected || source !== this.source.source)
|
||||
|
||||
logger.debug('Shift key pressed, selecting all files in between', { start, end, filesToSelect, isAlreadySelected })
|
||||
// Keep previous lastSelectedIndex to be use for further shift selections
|
||||
|
|
@ -127,8 +128,8 @@ export default defineComponent({
|
|||
}
|
||||
|
||||
const selection = selected
|
||||
? [...this.selectedFiles, this.fileid]
|
||||
: this.selectedFiles.filter(fileid => fileid !== this.fileid)
|
||||
? [...this.selectedFiles, this.source.source]
|
||||
: this.selectedFiles.filter(source => source !== this.source.source)
|
||||
|
||||
logger.debug('Updating selection', { selection })
|
||||
this.selectionStore.set(selection)
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
*/
|
||||
|
||||
import type { ComponentPublicInstance, PropType } from 'vue'
|
||||
import type { FileSource } from '../types.ts'
|
||||
|
||||
import { showError } from '@nextcloud/dialogs'
|
||||
import { FileType, Permission, Folder, File as NcFile, NodeStatus, Node, View } from '@nextcloud/files'
|
||||
|
|
@ -102,13 +103,13 @@ export default defineComponent({
|
|||
},
|
||||
|
||||
draggingFiles() {
|
||||
return this.draggingStore.dragging
|
||||
return this.draggingStore.dragging as FileSource[]
|
||||
},
|
||||
selectedFiles() {
|
||||
return this.selectionStore.selected
|
||||
return this.selectionStore.selected as FileSource[]
|
||||
},
|
||||
isSelected() {
|
||||
return this.fileid && this.selectedFiles.includes(this.fileid)
|
||||
return this.selectedFiles.includes(this.source.source)
|
||||
},
|
||||
|
||||
isRenaming() {
|
||||
|
|
@ -133,7 +134,7 @@ export default defineComponent({
|
|||
|
||||
// If we're dragging a selection, we need to check all files
|
||||
if (this.selectedFiles.length > 0) {
|
||||
const nodes = this.selectedFiles.map(fileid => this.filesStore.getNode(fileid)) as Node[]
|
||||
const nodes = this.selectedFiles.map(source => this.filesStore.getNode(source)) as Node[]
|
||||
return nodes.every(canDrag)
|
||||
}
|
||||
return canDrag(this.source)
|
||||
|
|
@ -145,7 +146,7 @@ export default defineComponent({
|
|||
}
|
||||
|
||||
// If the current folder is also being dragged, we can't drop it on itself
|
||||
if (this.fileid && this.draggingFiles.includes(this.fileid)) {
|
||||
if (this.draggingFiles.includes(this.source.source)) {
|
||||
return false
|
||||
}
|
||||
|
||||
|
|
@ -286,14 +287,14 @@ export default defineComponent({
|
|||
|
||||
// Dragging set of files, if we're dragging a file
|
||||
// that is already selected, we use the entire selection
|
||||
if (this.selectedFiles.includes(this.fileid)) {
|
||||
if (this.selectedFiles.includes(this.source.source)) {
|
||||
this.draggingStore.set(this.selectedFiles)
|
||||
} else {
|
||||
this.draggingStore.set([this.fileid])
|
||||
this.draggingStore.set([this.source.source])
|
||||
}
|
||||
|
||||
const nodes = this.draggingStore.dragging
|
||||
.map(fileid => this.filesStore.getNode(fileid)) as Node[]
|
||||
.map(source => this.filesStore.getNode(source)) as Node[]
|
||||
|
||||
const image = await getDragAndDropPreview(nodes)
|
||||
event.dataTransfer?.setDragImage(image, -10, -10)
|
||||
|
|
@ -347,12 +348,12 @@ export default defineComponent({
|
|||
}
|
||||
|
||||
// Else we're moving/copying files
|
||||
const nodes = selection.map(fileid => this.filesStore.getNode(fileid)) as Node[]
|
||||
const nodes = selection.map(source => this.filesStore.getNode(source)) as Node[]
|
||||
await onDropInternalFiles(nodes, folder, contents.contents, isCopy)
|
||||
|
||||
// Reset selection after we dropped the files
|
||||
// if the dropped files are within the selection
|
||||
if (selection.some(fileid => this.selectedFiles.includes(fileid))) {
|
||||
if (selection.some(source => this.selectedFiles.includes(source))) {
|
||||
logger.debug('Dropped selection, resetting select store...')
|
||||
this.selectionStore.reset()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,6 +81,7 @@ import FilesListTableHeaderButton from './FilesListTableHeaderButton.vue'
|
|||
import filesSortingMixin from '../mixins/filesSorting.ts'
|
||||
import logger from '../logger.js'
|
||||
import type { Node } from '@nextcloud/files'
|
||||
import type { FileSource } from '../types.ts'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'FilesListTableHeader',
|
||||
|
|
@ -186,7 +187,7 @@ export default defineComponent({
|
|||
|
||||
onToggleAll(selected) {
|
||||
if (selected) {
|
||||
const selection = this.nodes.map(node => node.fileid).filter(Boolean) as number[]
|
||||
const selection = this.nodes.map(node => node.source).filter(Boolean) as FileSource[]
|
||||
logger.debug('Added all nodes to selection', { selection })
|
||||
this.selectionStore.setLastIndex(null)
|
||||
this.selectionStore.set(selection)
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ import { useFilesStore } from '../store/files.ts'
|
|||
import { useSelectionStore } from '../store/selection.ts'
|
||||
import filesListWidthMixin from '../mixins/filesListWidth.ts'
|
||||
import logger from '../logger.js'
|
||||
import type { FileId } from '../types'
|
||||
import type { FileSource } from '../types'
|
||||
|
||||
// The registered actions list
|
||||
const actions = getFileActions()
|
||||
|
|
@ -81,7 +81,7 @@ export default defineComponent({
|
|||
required: true,
|
||||
},
|
||||
selectedNodes: {
|
||||
type: Array as PropType<FileId[]>,
|
||||
type: Array as PropType<FileSource[]>,
|
||||
default: () => ([]),
|
||||
},
|
||||
},
|
||||
|
|
@ -117,7 +117,7 @@ export default defineComponent({
|
|||
|
||||
nodes() {
|
||||
return this.selectedNodes
|
||||
.map(fileid => this.getNode(fileid))
|
||||
.map(source => this.getNode(source))
|
||||
.filter(Boolean) as Node[]
|
||||
},
|
||||
|
||||
|
|
@ -161,7 +161,7 @@ export default defineComponent({
|
|||
|
||||
async onActionClick(action) {
|
||||
const displayName = action.displayName(this.nodes, this.currentView)
|
||||
const selectionIds = this.selectedNodes
|
||||
const selectionSources = this.selectedNodes
|
||||
try {
|
||||
// Set loading markers
|
||||
this.loading = action.id
|
||||
|
|
@ -182,9 +182,9 @@ export default defineComponent({
|
|||
// Handle potential failures
|
||||
if (results.some(result => result === false)) {
|
||||
// Remove the failed ids from the selection
|
||||
const failedIds = selectionIds
|
||||
.filter((fileid, index) => results[index] === false)
|
||||
this.selectionStore.set(failedIds)
|
||||
const failedSources = selectionSources
|
||||
.filter((source, index) => results[index] === false)
|
||||
this.selectionStore.set(failedSources)
|
||||
|
||||
if (results.some(result => result === null)) {
|
||||
// If some actions returned null, we assume that the dev
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@
|
|||
*/
|
||||
import { defineStore } from 'pinia'
|
||||
import Vue from 'vue'
|
||||
import type { FileId, DragAndDropStore } from '../types'
|
||||
import type { DragAndDropStore, FileSource } from '../types'
|
||||
|
||||
export const useDragAndDropStore = defineStore('dragging', {
|
||||
state: () => ({
|
||||
|
|
@ -32,7 +32,7 @@ export const useDragAndDropStore = defineStore('dragging', {
|
|||
/**
|
||||
* Set the selection of fileIds
|
||||
*/
|
||||
set(selection = [] as FileId[]) {
|
||||
set(selection = [] as FileSource[]) {
|
||||
Vue.set(this, 'dragging', selection)
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -19,14 +19,28 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
import type { Folder, Node } from '@nextcloud/files'
|
||||
import type { FilesStore, RootsStore, RootOptions, Service, FilesState, FileId } from '../types'
|
||||
|
||||
import type { FilesStore, RootsStore, RootOptions, Service, FilesState, FileSource } from '../types'
|
||||
import type { FileStat, ResponseDataDetailed } from 'webdav'
|
||||
import type { Folder, Node } from '@nextcloud/files'
|
||||
|
||||
import { davGetDefaultPropfind, davResultToNode, davRootPath } from '@nextcloud/files'
|
||||
import { defineStore } from 'pinia'
|
||||
import { subscribe } from '@nextcloud/event-bus'
|
||||
import logger from '../logger'
|
||||
import Vue from 'vue'
|
||||
|
||||
import { client } from '../services/WebdavClient.ts'
|
||||
|
||||
const fetchNode = async (node: Node): Promise<Node> => {
|
||||
const propfindPayload = davGetDefaultPropfind()
|
||||
const result = await client.stat(`${davRootPath}${node.path}`, {
|
||||
details: true,
|
||||
data: propfindPayload,
|
||||
}) as ResponseDataDetailed<FileStat>
|
||||
return davResultToNode(result.data)
|
||||
}
|
||||
|
||||
export const useFilesStore = function(...args) {
|
||||
const store = defineStore('files', {
|
||||
state: (): FilesState => ({
|
||||
|
|
@ -36,19 +50,27 @@ export const useFilesStore = function(...args) {
|
|||
|
||||
getters: {
|
||||
/**
|
||||
* Get a file or folder by id
|
||||
* Get a file or folder by its source
|
||||
*/
|
||||
getNode: (state) => (id: FileId): Node|undefined => state.files[id],
|
||||
getNode: (state) => (source: FileSource): Node|undefined => state.files[source],
|
||||
|
||||
/**
|
||||
* Get a list of files or folders by their IDs
|
||||
* Does not return undefined values
|
||||
* Note: does not return undefined values
|
||||
*/
|
||||
getNodes: (state) => (ids: FileId[]): Node[] => ids
|
||||
.map(id => state.files[id])
|
||||
getNodes: (state) => (sources: FileSource[]): Node[] => sources
|
||||
.map(source => state.files[source])
|
||||
.filter(Boolean),
|
||||
|
||||
/**
|
||||
* Get a file or folder by id
|
||||
* Get files or folders by their file ID
|
||||
* Multiple nodes can have the same file ID but different sources
|
||||
* (e.g. in a shared context)
|
||||
*/
|
||||
getNodesById: (state) => (fileId: number): Node[] => Object.values(state.files).filter(node => node.fileid === fileId),
|
||||
|
||||
/**
|
||||
* Get the root folder of a service
|
||||
*/
|
||||
getRoot: (state) => (service: Service): Folder|undefined => state.roots[service],
|
||||
},
|
||||
|
|
@ -58,10 +80,11 @@ export const useFilesStore = function(...args) {
|
|||
// Update the store all at once
|
||||
const files = nodes.reduce((acc, node) => {
|
||||
if (!node.fileid) {
|
||||
logger.error('Trying to update/set a node without fileid', node)
|
||||
logger.error('Trying to update/set a node without fileid', { node })
|
||||
return acc
|
||||
}
|
||||
acc[node.fileid] = node
|
||||
|
||||
acc[node.source] = node
|
||||
return acc
|
||||
}, {} as FilesStore)
|
||||
|
||||
|
|
@ -70,8 +93,8 @@ export const useFilesStore = function(...args) {
|
|||
|
||||
deleteNodes(nodes: Node[]) {
|
||||
nodes.forEach(node => {
|
||||
if (node.fileid) {
|
||||
Vue.delete(this.files, node.fileid)
|
||||
if (node.source) {
|
||||
Vue.delete(this.files, node.source)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
|
@ -88,8 +111,28 @@ export const useFilesStore = function(...args) {
|
|||
this.updateNodes([node])
|
||||
},
|
||||
|
||||
onUpdatedNode(node: Node) {
|
||||
this.updateNodes([node])
|
||||
async onUpdatedNode(node: Node) {
|
||||
if (!node.fileid) {
|
||||
logger.error('Trying to update/set a node without fileid', { node })
|
||||
return
|
||||
}
|
||||
|
||||
// If we have multiple nodes with the same file ID, we need to update all of them
|
||||
const nodes = this.getNodesById(node.fileid)
|
||||
if (nodes.length > 1) {
|
||||
await Promise.all(nodes.map(fetchNode)).then(this.updateNodes)
|
||||
logger.debug(nodes.length + ' nodes updated in store', { fileid: node.fileid })
|
||||
return
|
||||
}
|
||||
|
||||
// If we have only one node with the file ID, we can update it directly
|
||||
if (node.source === nodes[0].source) {
|
||||
this.updateNodes([node])
|
||||
return
|
||||
}
|
||||
|
||||
// Otherwise, it means we receive an event for a node that is not in the store
|
||||
fetchNode(node).then(n => this.updateNodes([n]))
|
||||
},
|
||||
},
|
||||
})
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
import type { FileId, PathsStore, PathOptions, ServicesState } from '../types'
|
||||
import type { FileSource, PathsStore, PathOptions, ServicesState } from '../types'
|
||||
import { defineStore } from 'pinia'
|
||||
import { FileType, Folder, Node, getNavigation } from '@nextcloud/files'
|
||||
import { subscribe } from '@nextcloud/event-bus'
|
||||
|
|
@ -38,7 +38,7 @@ export const usePathsStore = function(...args) {
|
|||
|
||||
getters: {
|
||||
getPath: (state) => {
|
||||
return (service: string, path: string): FileId|undefined => {
|
||||
return (service: string, path: string): FileSource|undefined => {
|
||||
if (!state.paths[service]) {
|
||||
return undefined
|
||||
}
|
||||
|
|
@ -55,7 +55,7 @@ export const usePathsStore = function(...args) {
|
|||
}
|
||||
|
||||
// Now we can set the provided path
|
||||
Vue.set(this.paths[payload.service], payload.path, payload.fileid)
|
||||
Vue.set(this.paths[payload.service], payload.path, payload.source)
|
||||
},
|
||||
|
||||
onCreatedNode(node: Node) {
|
||||
|
|
@ -70,7 +70,7 @@ export const usePathsStore = function(...args) {
|
|||
this.addPath({
|
||||
service,
|
||||
path: node.path,
|
||||
fileid: node.fileid,
|
||||
source: node.source,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -81,26 +81,26 @@ export const usePathsStore = function(...args) {
|
|||
if (!root._children) {
|
||||
Vue.set(root, '_children', [])
|
||||
}
|
||||
root._children.push(node.fileid)
|
||||
root._children.push(node.source)
|
||||
return
|
||||
}
|
||||
|
||||
// If the folder doesn't exists yet, it will be
|
||||
// fetched later and its children updated anyway.
|
||||
if (this.paths[service][node.dirname]) {
|
||||
const parentId = this.paths[service][node.dirname]
|
||||
const parentFolder = files.getNode(parentId) as Folder
|
||||
const parentSource = this.paths[service][node.dirname]
|
||||
const parentFolder = files.getNode(parentSource) as Folder
|
||||
logger.debug('Path already exists, updating children', { parentFolder, node })
|
||||
|
||||
if (!parentFolder) {
|
||||
logger.error('Parent folder not found', { parentId })
|
||||
logger.error('Parent folder not found', { parentSource })
|
||||
return
|
||||
}
|
||||
|
||||
if (!parentFolder._children) {
|
||||
Vue.set(parentFolder, '_children', [])
|
||||
}
|
||||
parentFolder._children.push(node.fileid)
|
||||
parentFolder._children.push(node.source)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@
|
|||
*/
|
||||
import { defineStore } from 'pinia'
|
||||
import Vue from 'vue'
|
||||
import { FileId, SelectionStore } from '../types'
|
||||
import { FileSource, SelectionStore } from '../types'
|
||||
|
||||
export const useSelectionStore = defineStore('selection', {
|
||||
state: () => ({
|
||||
|
|
@ -34,14 +34,14 @@ export const useSelectionStore = defineStore('selection', {
|
|||
/**
|
||||
* Set the selection of fileIds
|
||||
*/
|
||||
set(selection = [] as FileId[]) {
|
||||
set(selection = [] as FileSource[]) {
|
||||
Vue.set(this, 'selected', [...new Set(selection)])
|
||||
},
|
||||
|
||||
/**
|
||||
* Set the last selected index
|
||||
*/
|
||||
setLastIndex(lastSelectedIndex = null as FileId | null) {
|
||||
setLastIndex(lastSelectedIndex = null as number | null) {
|
||||
// Update the last selection if we provided a new selection starting point
|
||||
Vue.set(this, 'lastSelection', lastSelectedIndex ? this.selected : [])
|
||||
Vue.set(this, 'lastSelectedIndex', lastSelectedIndex)
|
||||
|
|
|
|||
|
|
@ -24,12 +24,12 @@ import type { Upload } from '@nextcloud/upload'
|
|||
|
||||
// Global definitions
|
||||
export type Service = string
|
||||
export type FileId = number
|
||||
export type FileSource = string
|
||||
export type ViewId = string
|
||||
|
||||
// Files store
|
||||
export type FilesStore = {
|
||||
[fileid: FileId]: Node
|
||||
[source: FileSource]: Node
|
||||
}
|
||||
|
||||
export type RootsStore = {
|
||||
|
|
@ -48,7 +48,7 @@ export interface RootOptions {
|
|||
|
||||
// Paths store
|
||||
export type PathConfig = {
|
||||
[path: string]: number
|
||||
[path: string]: FileSource
|
||||
}
|
||||
|
||||
export type ServicesState = {
|
||||
|
|
@ -62,7 +62,7 @@ export type PathsStore = {
|
|||
export interface PathOptions {
|
||||
service: Service
|
||||
path: string
|
||||
fileid: FileId
|
||||
source: FileSource
|
||||
}
|
||||
|
||||
// User config store
|
||||
|
|
@ -74,8 +74,8 @@ export interface UserConfigStore {
|
|||
}
|
||||
|
||||
export interface SelectionStore {
|
||||
selected: FileId[]
|
||||
lastSelection: FileId[]
|
||||
selected: FileSource[]
|
||||
lastSelection: FileSource[]
|
||||
lastSelectedIndex: number | null
|
||||
}
|
||||
|
||||
|
|
@ -109,7 +109,7 @@ export interface UploaderStore {
|
|||
|
||||
// Drag and drop store
|
||||
export interface DragAndDropStore {
|
||||
dragging: FileId[]
|
||||
dragging: FileSource[]
|
||||
}
|
||||
|
||||
export interface TemplateFile {
|
||||
|
|
|
|||
|
|
@ -21,8 +21,9 @@
|
|||
*/
|
||||
|
||||
export const hashCode = function(str: string): number {
|
||||
return str.split('').reduce(function(a, b) {
|
||||
a = ((a << 5) - a) + b.charCodeAt(0)
|
||||
return a & a
|
||||
}, 0)
|
||||
let hash = 0
|
||||
for (let i = 0; i < str.length; i++) {
|
||||
hash = ((hash << 5) - hash + str.charCodeAt(i)) | 0
|
||||
}
|
||||
return (hash >>> 0)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -259,8 +259,13 @@ export default defineComponent({
|
|||
if (this.dir === '/') {
|
||||
return this.filesStore.getRoot(this.currentView.id)
|
||||
}
|
||||
const fileId = this.pathsStore.getPath(this.currentView.id, this.dir)
|
||||
return this.filesStore.getNode(fileId)
|
||||
|
||||
const source = this.pathsStore.getPath(this.currentView.id, this.dir)
|
||||
if (source === undefined) {
|
||||
return
|
||||
}
|
||||
|
||||
return this.filesStore.getNode(source) as Folder
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
@ -507,7 +512,7 @@ export default defineComponent({
|
|||
|
||||
// Define current directory children
|
||||
// TODO: make it more official
|
||||
this.$set(folder, '_children', contents.map(node => node.fileid))
|
||||
this.$set(folder, '_children', contents.map(node => node.source))
|
||||
|
||||
// If we're in the root dir, define the root
|
||||
if (dir === '/') {
|
||||
|
|
@ -516,7 +521,7 @@ export default defineComponent({
|
|||
// Otherwise, add the folder to the store
|
||||
if (folder.fileid) {
|
||||
this.filesStore.updateNodes([folder])
|
||||
this.pathsStore.addPath({ service: currentView.id, fileid: folder.fileid, path: dir })
|
||||
this.pathsStore.addPath({ service: currentView.id, source: folder.source, path: dir })
|
||||
} else {
|
||||
// If we're here, the view API messed up
|
||||
logger.error('Invalid root folder returned', { dir, folder, currentView })
|
||||
|
|
|
|||
4
dist/files-init.js
vendored
4
dist/files-init.js
vendored
File diff suppressed because one or more lines are too long
2
dist/files-init.js.map
vendored
2
dist/files-init.js.map
vendored
File diff suppressed because one or more lines are too long
4
dist/files-main.js
vendored
4
dist/files-main.js
vendored
File diff suppressed because one or more lines are too long
2
dist/files-main.js.map
vendored
2
dist/files-main.js.map
vendored
File diff suppressed because one or more lines are too long
4
dist/systemtags-init.js
vendored
4
dist/systemtags-init.js
vendored
File diff suppressed because one or more lines are too long
2
dist/systemtags-init.js.map
vendored
2
dist/systemtags-init.js.map
vendored
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue