Files
warren/frontend/pages/warrens/files.vue
2025-08-29 15:32:23 +02:00

153 lines
3.7 KiB
Vue

<script setup lang="ts">
import { useDropZone } from '@vueuse/core';
import { toast } from 'vue-sonner';
import DirectoryListContextMenu from '~/components/DirectoryListContextMenu.vue';
import RenameEntryDialog from '~/components/actions/RenameEntryDialog.vue';
import { fetchFile, getWarrenDirectory } from '~/lib/api/warrens';
import type { DirectoryEntry } from '~/shared/types';
definePageMeta({
middleware: ['authenticated'],
});
const warrenStore = useWarrenStore();
const loadingIndicator = useLoadingIndicator();
const uploadStore = useUploadStore();
const warrenPath = computed(() => useWarrenPath());
const dropZoneRef = ref<HTMLElement>();
const dropZone = useDropZone(dropZoneRef, {
onDrop,
multiple: true,
});
if (warrenStore.current == null) {
await navigateTo({
path: '/warrens',
});
}
const dirData = useAsyncData(
'current-directory',
async () => {
if (warrenStore.current == null) {
return {
files: [],
parent: null,
};
}
loadingIndicator.start();
warrenStore.loading = true;
const { files, parent } = await getWarrenDirectory(
warrenStore.current.warrenId,
warrenStore.current.path
);
warrenStore.loading = false;
loadingIndicator.finish();
return { files, parent };
},
{ watch: [warrenPath] }
).data;
function onDrop(files: File[] | null, e: DragEvent) {
if (files == null) {
return;
}
e.preventDefault();
if (warrenStore.current == null) {
toast.warning('Upload', {
description: 'Enter a warren before attempting to upload files',
});
return;
}
const added = uploadStore.addFiles(
warrenStore.current.warrenId,
warrenStore.current.path,
files
);
if (added) {
uploadStore.dialogOpen = true;
}
}
async function onEntryClicked(entry: DirectoryEntry) {
if (warrenStore.loading || warrenStore.current == null) {
return;
}
if (entry.fileType === 'directory') {
warrenStore.addToCurrentWarrenPath(entry.name);
return;
}
if (entry.mimeType == null) {
return;
}
if (entry.mimeType.startsWith('image/')) {
const result = await fetchFile(
warrenStore.current.warrenId,
warrenStore.current.path,
entry.name
);
if (result.success) {
const url = URL.createObjectURL(result.data);
warrenStore.imageViewer.src = url;
}
}
}
function onEntryDownload(entry: DirectoryEntry) {
if (warrenStore.current == null) {
return;
}
if (entry.fileType !== 'file') {
toast.warning('Download', {
description: 'Directory downloads are not supported yet',
});
return;
}
downloadFile(
entry.name,
getApiUrl(
`warrens/files/cat?warrenId=${warrenStore.current.warrenId}&path=${joinPaths(warrenStore.current.path, entry.name)}`
)
);
}
function onBack() {
warrenStore.backCurrentPath();
}
</script>
<template>
<div ref="dropZoneRef" class="grow">
<DirectoryListContextMenu class="w-full grow">
<DirectoryList
v-if="dirData != null"
:is-over-drop-zone="
dropZone.isOverDropZone.value &&
dropZone.files.value != null
"
:entries="dirData.files"
:parent="dirData.parent"
@entry-click="onEntryClicked"
@entry-download="onEntryDownload"
@back="onBack"
/>
</DirectoryListContextMenu>
<RenameEntryDialog />
</div>
</template>