This commit is contained in:
@@ -151,6 +151,8 @@ const fileNames = computed(() => {
|
|||||||
:disabled="uploadInProgress || selectedFiles.length === 0"
|
:disabled="uploadInProgress || selectedFiles.length === 0"
|
||||||
>Hochladen</UButton>
|
>Hochladen</UButton>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
{{props.fileData}}
|
||||||
</UCard>
|
</UCard>
|
||||||
</div>
|
</div>
|
||||||
</UModal>
|
</UModal>
|
||||||
|
|||||||
@@ -28,7 +28,9 @@ const displayModes = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
const createFolderModalOpen = ref(false)
|
const createFolderModalOpen = ref(false)
|
||||||
const createFolderData = ref({name: '', standardFiletype: null, standardFiletypeIsOptional: true})
|
const initialCreateFolderData = { name: '', standardFiletype: null, standardFiletypeIsOptional: true }
|
||||||
|
const createFolderData = ref({ ...initialCreateFolderData })
|
||||||
|
|
||||||
const renameModalOpen = ref(false)
|
const renameModalOpen = ref(false)
|
||||||
const renameData = ref({id: null, name: '', type: ''})
|
const renameData = ref({id: null, name: '', type: ''})
|
||||||
|
|
||||||
@@ -77,16 +79,14 @@ let dragCounter = 0
|
|||||||
|
|
||||||
const handleGlobalDragEnter = (e) => {
|
const handleGlobalDragEnter = (e) => {
|
||||||
dragCounter++
|
dragCounter++
|
||||||
|
|
||||||
// 1. Abbrechen, wenn wir gerade intern Ordner/Dateien verschieben
|
|
||||||
if (draggedItem.value) return
|
if (draggedItem.value) return
|
||||||
|
|
||||||
// 2. Prüfen ob Files von außen kommen
|
|
||||||
if (e.dataTransfer && e.dataTransfer.types && e.dataTransfer.types.includes('Files')) {
|
if (e.dataTransfer && e.dataTransfer.types && e.dataTransfer.types.includes('Files')) {
|
||||||
// Modal öffnen, falls noch nicht offen (optionaler Check, useModal handhabt das meist selbst)
|
|
||||||
// Wir übergeben den aktuellen Ordner
|
|
||||||
modal.open(DocumentUploadModal, {
|
modal.open(DocumentUploadModal, {
|
||||||
fileData: {folder: currentFolder.value?.id, typeEnabled: true},
|
fileData: {
|
||||||
|
folder: currentFolder.value?.id,
|
||||||
|
type: currentFolder?.value?.standardFiletype,
|
||||||
|
typeEnabled: currentFolder?.value?.standardFiletype ? currentFolder?.value?.standardFiletypeIsOptional : true
|
||||||
|
},
|
||||||
onUploadFinished: () => {
|
onUploadFinished: () => {
|
||||||
setupPage()
|
setupPage()
|
||||||
dragCounter = 0
|
dragCounter = 0
|
||||||
@@ -101,7 +101,6 @@ const handleGlobalDragLeave = (e) => {
|
|||||||
|
|
||||||
const handleGlobalDrop = (e) => {
|
const handleGlobalDrop = (e) => {
|
||||||
dragCounter = 0
|
dragCounter = 0
|
||||||
// Verhindert, dass der Browser die Datei öffnet, falls man neben das Modal droppt
|
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,8 +110,6 @@ const handleGlobalDragOver = (e) => {
|
|||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
setupPage()
|
setupPage()
|
||||||
|
|
||||||
// Globale Listener registrieren
|
|
||||||
window.addEventListener('dragenter', handleGlobalDragEnter)
|
window.addEventListener('dragenter', handleGlobalDragEnter)
|
||||||
window.addEventListener('dragleave', handleGlobalDragLeave)
|
window.addEventListener('dragleave', handleGlobalDragLeave)
|
||||||
window.addEventListener('dragover', handleGlobalDragOver)
|
window.addEventListener('dragover', handleGlobalDragOver)
|
||||||
@@ -120,7 +117,6 @@ onMounted(() => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
// Aufräumen
|
|
||||||
window.removeEventListener('dragenter', handleGlobalDragEnter)
|
window.removeEventListener('dragenter', handleGlobalDragEnter)
|
||||||
window.removeEventListener('dragleave', handleGlobalDragLeave)
|
window.removeEventListener('dragleave', handleGlobalDragLeave)
|
||||||
window.removeEventListener('dragover', handleGlobalDragOver)
|
window.removeEventListener('dragover', handleGlobalDragOver)
|
||||||
@@ -146,7 +142,6 @@ const handleDragStart = (entry) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const handleDrop = async (targetFolderId) => {
|
const handleDrop = async (targetFolderId) => {
|
||||||
// targetFolderId kann null sein (Root)
|
|
||||||
if (!draggedItem.value) return
|
if (!draggedItem.value) return
|
||||||
if (draggedItem.value.id === targetFolderId) return
|
if (draggedItem.value.id === targetFolderId) return
|
||||||
|
|
||||||
@@ -189,13 +184,11 @@ const breadcrumbLinks = computed(() => {
|
|||||||
|
|
||||||
// --- Data Mapping ---
|
// --- Data Mapping ---
|
||||||
const renderedFileList = computed(() => {
|
const renderedFileList = computed(() => {
|
||||||
// 1. Aktuelle Ordner filtern
|
|
||||||
const folderList = folders.value
|
const folderList = folders.value
|
||||||
.filter(i => currentFolder.value ? i.parent === currentFolder.value.id : !i.parent)
|
.filter(i => currentFolder.value ? i.parent === currentFolder.value.id : !i.parent)
|
||||||
.map(i => ({...i, label: i.name, type: "folder"}))
|
.map(i => ({...i, label: i.name, type: "folder"}))
|
||||||
.sort((a, b) => a.label.localeCompare(b.label))
|
.sort((a, b) => a.label.localeCompare(b.label))
|
||||||
|
|
||||||
// 2. Aktuelle Dateien filtern
|
|
||||||
const fileList = documents.value
|
const fileList = documents.value
|
||||||
.filter(i => currentFolder.value ? i.folder === currentFolder.value.id : !i.folder)
|
.filter(i => currentFolder.value ? i.folder === currentFolder.value.id : !i.folder)
|
||||||
.map(i => ({...i, label: i.path.split("/").pop(), type: "file"}))
|
.map(i => ({...i, label: i.path.split("/").pop(), type: "file"}))
|
||||||
@@ -206,7 +199,6 @@ const renderedFileList = computed(() => {
|
|||||||
combined = useSearch(debouncedSearch.value, combined)
|
combined = useSearch(debouncedSearch.value, combined)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. "Nach oben" (..) einfügen, wenn wir nicht im Root sind und nicht suchen
|
|
||||||
if (currentFolder.value && !debouncedSearch.value) {
|
if (currentFolder.value && !debouncedSearch.value) {
|
||||||
combined.unshift({
|
combined.unshift({
|
||||||
id: 'go-up',
|
id: 'go-up',
|
||||||
@@ -215,18 +207,46 @@ const renderedFileList = computed(() => {
|
|||||||
parentId: currentFolder.value.parent || null
|
parentId: currentFolder.value.parent || null
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return combined
|
return combined
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// --- Logic: Mandatory File Types ---
|
||||||
|
// Prüft, ob der aktuelle Ordner strikte Vorgaben macht
|
||||||
|
const isParentTypeMandatory = computed(() => {
|
||||||
|
return currentFolder.value
|
||||||
|
&& currentFolder.value.standardFiletype
|
||||||
|
&& !currentFolder.value.standardFiletypeIsOptional
|
||||||
|
})
|
||||||
|
|
||||||
|
// Überwacht das Öffnen des "Ordner erstellen" Modals, um Vorgaben zu setzen
|
||||||
|
watch(createFolderModalOpen, (isOpen) => {
|
||||||
|
if (isOpen) {
|
||||||
|
if (isParentTypeMandatory.value) {
|
||||||
|
// Wenn Elternordner strikt ist: Werte übernehmen und erzwingen
|
||||||
|
createFolderData.value = {
|
||||||
|
name: '',
|
||||||
|
standardFiletype: currentFolder.value.standardFiletype,
|
||||||
|
standardFiletypeIsOptional: false // Muss auch false sein, damit Kette weitergeht
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Reset auf Standardwerte
|
||||||
|
createFolderData.value = { ...initialCreateFolderData }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
// --- Actions ---
|
// --- Actions ---
|
||||||
const createFolder = async () => {
|
const createFolder = async () => {
|
||||||
await useEntities("folders").create({
|
await useEntities("folders").create({
|
||||||
parent: currentFolder.value?.id,
|
parent: currentFolder.value?.id,
|
||||||
name: createFolderData.value.name
|
name: createFolderData.value.name,
|
||||||
|
standardFiletype: createFolderData.value.standardFiletype,
|
||||||
|
standardFiletypeIsOptional: createFolderData.value.standardFiletypeIsOptional
|
||||||
})
|
})
|
||||||
createFolderModalOpen.value = false
|
createFolderModalOpen.value = false
|
||||||
createFolderData.value = {name: ''}
|
// Reset passiert beim nächsten Öffnen durch den Watcher, aber sicherheitshalber hier clean
|
||||||
|
createFolderData.value = { ...initialCreateFolderData }
|
||||||
setupPage()
|
setupPage()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -288,15 +308,12 @@ const syncdokubox = async () => {
|
|||||||
isSyncing.value = true
|
isSyncing.value = true
|
||||||
try {
|
try {
|
||||||
await $api('/api/functions/services/syncdokubox', {method: 'POST'})
|
await $api('/api/functions/services/syncdokubox', {method: 'POST'})
|
||||||
|
|
||||||
toast.add({
|
toast.add({
|
||||||
title: 'Erfolg',
|
title: 'Erfolg',
|
||||||
description: 'Dokubox wurde synchronisiert.',
|
description: 'Dokubox wurde synchronisiert.',
|
||||||
icon: 'i-heroicons-check-circle',
|
icon: 'i-heroicons-check-circle',
|
||||||
color: 'green'
|
color: 'green'
|
||||||
})
|
})
|
||||||
|
|
||||||
// Liste neu laden
|
|
||||||
await setupPage()
|
await setupPage()
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error)
|
console.error(error)
|
||||||
@@ -310,7 +327,6 @@ const syncdokubox = async () => {
|
|||||||
isSyncing.value = false
|
isSyncing.value = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -325,8 +341,7 @@ const syncdokubox = async () => {
|
|||||||
@click="syncdokubox"
|
@click="syncdokubox"
|
||||||
class="mr-2"
|
class="mr-2"
|
||||||
/>
|
/>
|
||||||
<UInput id="searchinput" v-model="searchString" icon="i-heroicons-magnifying-glass" placeholder="Suche..."
|
<UInput id="searchinput" v-model="searchString" icon="i-heroicons-magnifying-glass" placeholder="Suche..." class="w-64"/>
|
||||||
class="w-64"/>
|
|
||||||
</template>
|
</template>
|
||||||
</UDashboardNavbar>
|
</UDashboardNavbar>
|
||||||
|
|
||||||
@@ -335,8 +350,7 @@ const syncdokubox = async () => {
|
|||||||
<UBreadcrumb :links="breadcrumbLinks"/>
|
<UBreadcrumb :links="breadcrumbLinks"/>
|
||||||
</template>
|
</template>
|
||||||
<template #right>
|
<template #right>
|
||||||
<USelectMenu v-model="displayMode" :options="displayModes" value-attribute="key" class="w-32"
|
<USelectMenu v-model="displayMode" :options="displayModes" value-attribute="key" class="w-32" :ui-menu="{ zIndex: 'z-50' }">
|
||||||
:ui-menu="{ zIndex: 'z-50' }">
|
|
||||||
<template #label>
|
<template #label>
|
||||||
<UIcon :name="displayModes.find(i => i.key === displayMode).icon" class="w-4 h-4"/>
|
<UIcon :name="displayModes.find(i => i.key === displayMode).icon" class="w-4 h-4"/>
|
||||||
<span>{{ displayModes.find(i => i.key === displayMode).label }}</span>
|
<span>{{ displayModes.find(i => i.key === displayMode).label }}</span>
|
||||||
@@ -344,7 +358,7 @@ const syncdokubox = async () => {
|
|||||||
</USelectMenu>
|
</USelectMenu>
|
||||||
<UButtonGroup size="sm">
|
<UButtonGroup size="sm">
|
||||||
<UButton icon="i-heroicons-document-plus" color="primary"
|
<UButton icon="i-heroicons-document-plus" color="primary"
|
||||||
@click="modal.open(DocumentUploadModal, { fileData: { folder: currentFolder?.id }, onUploadFinished: setupPage })">
|
@click="modal.open(DocumentUploadModal, { fileData: { folder: currentFolder?.id,type: currentFolder?.standardFiletype, typeEnabled: currentFolder?.standardFiletype ? currentFolder?.standardFiletypeIsOptional : true }, onUploadFinished: setupPage })">
|
||||||
Datei
|
Datei
|
||||||
</UButton>
|
</UButton>
|
||||||
<UButton icon="i-heroicons-folder-plus" color="white" @click="createFolderModalOpen = true">Ordner</UButton>
|
<UButton icon="i-heroicons-folder-plus" color="white" @click="createFolderModalOpen = true">Ordner</UButton>
|
||||||
@@ -431,9 +445,35 @@ const syncdokubox = async () => {
|
|||||||
<UModal v-model="createFolderModalOpen">
|
<UModal v-model="createFolderModalOpen">
|
||||||
<UCard>
|
<UCard>
|
||||||
<template #header><h3 class="font-bold">Ordner erstellen</h3></template>
|
<template #header><h3 class="font-bold">Ordner erstellen</h3></template>
|
||||||
<UFormGroup label="Name" required>
|
|
||||||
<UInput v-model="createFolderData.name" autofocus @keyup.enter="createFolder"/>
|
<div class="space-y-4">
|
||||||
</UFormGroup>
|
<UFormGroup label="Name" required>
|
||||||
|
<UInput v-model="createFolderData.name" autofocus @keyup.enter="createFolder"/>
|
||||||
|
</UFormGroup>
|
||||||
|
|
||||||
|
<UFormGroup
|
||||||
|
label="Standard Dateityp (Tag)"
|
||||||
|
:help="isParentTypeMandatory ? 'Vom übergeordneten Ordner vorgegeben' : ''"
|
||||||
|
>
|
||||||
|
<USelectMenu
|
||||||
|
v-model="createFolderData.standardFiletype"
|
||||||
|
:options="filetags"
|
||||||
|
value-attribute="id"
|
||||||
|
option-attribute="name"
|
||||||
|
placeholder="Kein Standardtyp"
|
||||||
|
searchable
|
||||||
|
clear-search-on-close
|
||||||
|
:disabled="isParentTypeMandatory"
|
||||||
|
/>
|
||||||
|
</UFormGroup>
|
||||||
|
|
||||||
|
<UCheckbox
|
||||||
|
v-model="createFolderData.standardFiletypeIsOptional"
|
||||||
|
label="Dateityp ist optional"
|
||||||
|
:disabled="isParentTypeMandatory"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<div class="flex justify-end gap-2">
|
<div class="flex justify-end gap-2">
|
||||||
<UButton color="gray" @click="createFolderModalOpen = false">Abbrechen</UButton>
|
<UButton color="gray" @click="createFolderModalOpen = false">Abbrechen</UButton>
|
||||||
|
|||||||
Reference in New Issue
Block a user