implement file move, fix ffplayout#440
This commit is contained in:
parent
1a3db6737d
commit
5fd0c3fcbe
@ -79,6 +79,21 @@ export const stringFormatter = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function parent(path: string) {
|
||||||
|
if (path) {
|
||||||
|
const pathArr = path.split('/')
|
||||||
|
pathArr.pop()
|
||||||
|
|
||||||
|
if (pathArr.length > 0) {
|
||||||
|
return pathArr.join('/')
|
||||||
|
} else {
|
||||||
|
return '/'
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function toMin(sec: number) {
|
function toMin(sec: number) {
|
||||||
if (sec) {
|
if (sec) {
|
||||||
const minutes = Math.floor(sec / 60)
|
const minutes = Math.floor(sec / 60)
|
||||||
@ -154,6 +169,7 @@ export const stringFormatter = () => {
|
|||||||
numberToHex,
|
numberToHex,
|
||||||
hexToNumber,
|
hexToNumber,
|
||||||
filename,
|
filename,
|
||||||
|
parent,
|
||||||
toMin,
|
toMin,
|
||||||
secondsToTime,
|
secondsToTime,
|
||||||
mediaType,
|
mediaType,
|
||||||
|
143
pages/media.vue
143
pages/media.vue
@ -1,18 +1,21 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="h-[calc(100vh-140px)]">
|
<div class="h-[calc(100vh-140px)]">
|
||||||
<nav class="text-sm breadcrumbs px-4">
|
<nav class="text-sm breadcrumbs px-4">
|
||||||
<ul>
|
<ul v-on:dragover.prevent>
|
||||||
<li
|
<li
|
||||||
v-for="(crumb, index) in mediaStore.crumbs"
|
v-for="(crumb, index) in mediaStore.crumbs"
|
||||||
:key="index"
|
:key="index"
|
||||||
:active="index === mediaStore.crumbs.length - 1"
|
:active="index === mediaStore.crumbs.length - 1"
|
||||||
@click="getPath(crumb.path)"
|
@click="getPath(crumb.path)"
|
||||||
|
v-on:drop="handleDrop($event, crumb.path, null)"
|
||||||
|
v-on:dragover="handleDragOver"
|
||||||
|
v-on:dragleave="handleDragLeave"
|
||||||
>
|
>
|
||||||
<a v-if="mediaStore.crumbs.length > 1 && mediaStore.crumbs.length - 1 > index" href="#">
|
<a v-if="mediaStore.crumbs.length > 1 && mediaStore.crumbs.length - 1 > index" href="#">
|
||||||
<i class="bi-folder me-1" />
|
<i class="bi-folder-fill me-1" />
|
||||||
{{ crumb.text }}
|
{{ crumb.text }}
|
||||||
</a>
|
</a>
|
||||||
<span v-else><i class="bi-folder me-1" /> {{ crumb.text }}</span>
|
<span v-else><i class="bi-folder-fill me-1" /> {{ crumb.text }}</span>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
@ -25,12 +28,55 @@
|
|||||||
<span class="loading loading-spinner loading-lg"></span>
|
<span class="loading loading-spinner loading-lg"></span>
|
||||||
</div>
|
</div>
|
||||||
<splitpanes>
|
<splitpanes>
|
||||||
<pane min-size="14" max-size="80" size="24" class="h-full px-2">
|
<pane min-size="14" max-size="80" size="24" class="h-full">
|
||||||
<ul v-if="mediaStore.folderTree.parent" class="overflow-auto h-full m-1">
|
<ul v-if="mediaStore.folderTree.parent" class="overflow-auto h-full m-1" v-on:dragover.prevent>
|
||||||
<li
|
<li
|
||||||
class="grid grid-cols-[auto_18px] gap-1"
|
v-if="mediaStore.folderTree.parent_folders.length > 0"
|
||||||
|
v-for="folder in mediaStore.folderTree.parent_folders"
|
||||||
|
class="grid grid-cols-[auto_18px] gap-1 px-2"
|
||||||
|
:class="filename(mediaStore.folderTree.source) === folder.name && 'bg-base-100'"
|
||||||
|
:key="folder.uid"
|
||||||
|
v-on:drop="handleDrop($event, folder, true)"
|
||||||
|
v-on:dragover="handleDragOver"
|
||||||
|
v-on:dragleave="handleDragLeave"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="truncate text-left"
|
||||||
|
@click="getPath(`/${parent(mediaStore.folderTree.source)}/${folder.name}`)"
|
||||||
|
>
|
||||||
|
<i class="bi-folder-fill" />
|
||||||
|
{{ folder.name }}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="opacity-30 hover:opacity-100"
|
||||||
|
@click="
|
||||||
|
;(showDeleteModal = true),
|
||||||
|
(deleteName = `/${parent(mediaStore.folderTree.source)}/${folder.name}`.replace(
|
||||||
|
/\/[/]+/g,
|
||||||
|
'/'
|
||||||
|
))
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<i class="bi-x-circle-fill" />
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
<li v-else class="px-2">
|
||||||
|
<div class="truncate text-left">
|
||||||
|
<i class="bi-folder-fill" />
|
||||||
|
{{ mediaStore.folderTree.parent }}
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</pane>
|
||||||
|
<pane class="h-full px-2">
|
||||||
|
<ul v-if="mediaStore.folderTree.parent" class="h-full overflow-auto m-1" v-on:dragover.prevent>
|
||||||
|
<li
|
||||||
|
class="grid grid-cols-[auto_49px] gap-1"
|
||||||
v-for="folder in mediaStore.folderTree.folders"
|
v-for="folder in mediaStore.folderTree.folders"
|
||||||
:key="folder.uid"
|
:key="folder.uid"
|
||||||
|
v-on:drop="handleDrop($event, folder, false)"
|
||||||
|
v-on:dragover="handleDragOver"
|
||||||
|
v-on:dragleave="handleDragLeave"
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
class="truncate text-left"
|
class="truncate text-left"
|
||||||
@ -52,17 +98,15 @@
|
|||||||
<i class="bi-x-circle-fill" />
|
<i class="bi-x-circle-fill" />
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
|
||||||
</pane>
|
|
||||||
<pane class="h-full px-2">
|
|
||||||
<ul v-if="mediaStore.folderTree.parent" class="h-full overflow-auto m-1">
|
|
||||||
<li
|
<li
|
||||||
v-for="(element, index) in mediaStore.folderTree.files"
|
v-for="(element, index) in mediaStore.folderTree.files"
|
||||||
:id="`file_${index}`"
|
:id="`file_${index}`"
|
||||||
class="grid grid-cols-[auto_176px]"
|
class="grid grid-cols-[auto_176px]"
|
||||||
:key="element.name"
|
:key="element.name"
|
||||||
|
draggable="true"
|
||||||
|
v-on:dragstart="handleDragStart($event, element)"
|
||||||
>
|
>
|
||||||
<div class="truncate">
|
<div class="truncate cursor-grab">
|
||||||
<i v-if="mediaType(element.name) === 'audio'" class="bi-music-note-beamed" />
|
<i v-if="mediaType(element.name) === 'audio'" class="bi-music-note-beamed" />
|
||||||
<i v-else-if="mediaType(element.name) === 'video'" class="bi-film" />
|
<i v-else-if="mediaType(element.name) === 'video'" class="bi-film" />
|
||||||
<i v-else-if="mediaType(element.name) === 'image'" class="bi-file-earmark-image" />
|
<i v-else-if="mediaType(element.name) === 'image'" class="bi-file-earmark-image" />
|
||||||
@ -197,7 +241,7 @@ const authStore = useAuth()
|
|||||||
const configStore = useConfig()
|
const configStore = useConfig()
|
||||||
const indexStore = useIndex()
|
const indexStore = useIndex()
|
||||||
const mediaStore = useMedia()
|
const mediaStore = useMedia()
|
||||||
const { toMin, mediaType } = stringFormatter()
|
const { toMin, mediaType, filename, parent } = stringFormatter()
|
||||||
const contentType = { 'content-type': 'application/json;charset=UTF-8' }
|
const contentType = { 'content-type': 'application/json;charset=UTF-8' }
|
||||||
|
|
||||||
const { configID } = storeToRefs(useConfig())
|
const { configID } = storeToRefs(useConfig())
|
||||||
@ -230,6 +274,8 @@ const currentProgress = ref(0)
|
|||||||
const lastPath = ref('')
|
const lastPath = ref('')
|
||||||
const xhr = ref(new XMLHttpRequest())
|
const xhr = ref(new XMLHttpRequest())
|
||||||
|
|
||||||
|
const fileRefs = ref([] as any[])
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
let config_extensions = configStore.configPlayout.storage.extensions
|
let config_extensions = configStore.configPlayout.storage.extensions
|
||||||
let extra_extensions = configStore.configGui[configStore.configID].extra_extensions
|
let extra_extensions = configStore.configGui[configStore.configID].extra_extensions
|
||||||
@ -249,7 +295,7 @@ onMounted(async () => {
|
|||||||
extensions.value = exts.join(', ')
|
extensions.value = exts.join(', ')
|
||||||
|
|
||||||
if (!mediaStore.folderTree.parent) {
|
if (!mediaStore.folderTree.parent) {
|
||||||
getPath('')
|
await getPath('')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -257,6 +303,77 @@ watch([configID], () => {
|
|||||||
getPath('')
|
getPath('')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
function handleDragStart(event: any, itemData: any) {
|
||||||
|
event.dataTransfer.setData('application/json', JSON.stringify(itemData))
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDragOver(event: any) {
|
||||||
|
event.target.style.color = 'white'
|
||||||
|
event.target.style.fontWeight = 'bold'
|
||||||
|
|
||||||
|
if (event.target.firstChild && event.target.firstChild.classList.contains('bi-folder-fill')) {
|
||||||
|
event.target.firstChild.classList.remove('bi-folder-fill')
|
||||||
|
event.target.firstChild.classList.add('bi-folder2-open')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDragLeave(event: any) {
|
||||||
|
if (event.target && event.target.style) {
|
||||||
|
event.target.style.color = null
|
||||||
|
event.target.style.fontWeight = null
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.target.firstChild && event.target.firstChild.classList.contains('bi-folder2-open')) {
|
||||||
|
event.target.firstChild.classList.remove('bi-folder2-open')
|
||||||
|
event.target.firstChild.classList.add('bi-folder-fill')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleDrop(event: any, targetFolder: any, isParent: boolean | null) {
|
||||||
|
const itemData = JSON.parse(event.dataTransfer.getData('application/json'))
|
||||||
|
const source = `/${mediaStore.folderTree.source}/${itemData.name}`.replace(
|
||||||
|
/\/[/]+/g,
|
||||||
|
'/'
|
||||||
|
)
|
||||||
|
let target
|
||||||
|
|
||||||
|
if (isParent === null) {
|
||||||
|
target = `${targetFolder}/${itemData.name}`.replace(/\/[/]+/g, '/')
|
||||||
|
} else if (isParent) {
|
||||||
|
target = `/${parent(mediaStore.folderTree.source)}/${targetFolder.name}/${
|
||||||
|
itemData.name
|
||||||
|
}`.replace(/\/[/]+/g, '/')
|
||||||
|
} else {
|
||||||
|
target =
|
||||||
|
`/${mediaStore.folderTree.source}/${targetFolder.name}/${itemData.name}`.replace(
|
||||||
|
/\/[/]+/g,
|
||||||
|
'/'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
event.target.style.color = null
|
||||||
|
event.target.style.fontWeight = null
|
||||||
|
|
||||||
|
if (event.target.firstChild.classList.contains('bi-folder2-open')) {
|
||||||
|
event.target.firstChild.classList.remove('bi-folder2-open')
|
||||||
|
event.target.firstChild.classList.add('bi-folder-fill')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (source !== target) {
|
||||||
|
await fetch(`/api/file/${configStore.configGui[configStore.configID].id}/rename/`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { ...contentType, ...authStore.authHeader },
|
||||||
|
body: JSON.stringify({ source, target }),
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
getPath(mediaStore.folderTree.source)
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
indexStore.msgAlert('alert-error', `Delete error: ${e}`, 3)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function getPath(path: string) {
|
async function getPath(path: string) {
|
||||||
browserIsLoading.value = true
|
browserIsLoading.value = true
|
||||||
await mediaStore.getTree(path)
|
await mediaStore.getTree(path)
|
||||||
|
@ -61,11 +61,13 @@ export const useMedia = defineStore('media', {
|
|||||||
|
|
||||||
if (foldersOnly) {
|
if (foldersOnly) {
|
||||||
this.folderCrumbs = crumbs
|
this.folderCrumbs = crumbs
|
||||||
|
data.parent_folders = data.parent_folders.map((i: any) => ({uid: genUID(), name: i}))
|
||||||
data.folders = data.folders.map((i: any) => ({uid: genUID(), name: i}))
|
data.folders = data.folders.map((i: any) => ({uid: genUID(), name: i}))
|
||||||
this.folderList = data
|
this.folderList = data
|
||||||
} else {
|
} else {
|
||||||
this.currentPath = path
|
this.currentPath = path
|
||||||
this.crumbs = crumbs
|
this.crumbs = crumbs
|
||||||
|
data.parent_folders = data.parent_folders.map((i: any) => ({uid: genUID(), name: i}))
|
||||||
data.folders = data.folders.map((i: any) => ({uid: genUID(), name: i}))
|
data.folders = data.folders.map((i: any) => ({uid: genUID(), name: i}))
|
||||||
this.folderTree = data
|
this.folderTree = data
|
||||||
}
|
}
|
||||||
|
1
types/index.d.ts
vendored
1
types/index.d.ts
vendored
@ -73,6 +73,7 @@ declare global {
|
|||||||
interface FileFolderObject {
|
interface FileFolderObject {
|
||||||
source: string
|
source: string
|
||||||
parent: string
|
parent: string
|
||||||
|
parent_folders: Folder[]
|
||||||
folders: Folder[]
|
folders: Folder[]
|
||||||
files: FileObject[]
|
files: FileObject[]
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user