copy files
This commit is contained in:
@@ -14,6 +14,7 @@ import {
|
||||
import type { DirectoryEntry } from '#shared/types';
|
||||
|
||||
const warrenStore = useWarrenStore();
|
||||
const copyStore = useCopyStore();
|
||||
const renameDialog = useRenameDirectoryDialog();
|
||||
|
||||
const { entry, disabled } = defineProps<{
|
||||
@@ -22,6 +23,14 @@ const { entry, disabled } = defineProps<{
|
||||
}>();
|
||||
|
||||
const deleting = ref(false);
|
||||
const isCopied = computed(
|
||||
() =>
|
||||
warrenStore.current != null &&
|
||||
copyStore.file != null &&
|
||||
warrenStore.current.warrenId === copyStore.file.warrenId &&
|
||||
warrenStore.current.path === copyStore.file.path &&
|
||||
entry.name === copyStore.file.name
|
||||
);
|
||||
|
||||
async function submitDelete(force: boolean = false) {
|
||||
if (warrenStore.current == null) {
|
||||
@@ -89,6 +98,18 @@ function onDragStart(e: DragEvent) {
|
||||
}
|
||||
|
||||
const onDrop = onDirectoryEntryDrop(entry);
|
||||
|
||||
function onCopy() {
|
||||
if (warrenStore.current == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
copyStore.copyFile(
|
||||
warrenStore.current.warrenId,
|
||||
warrenStore.current.path,
|
||||
entry.name
|
||||
);
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -96,7 +117,10 @@ const onDrop = onDirectoryEntryDrop(entry);
|
||||
<ContextMenuTrigger>
|
||||
<button
|
||||
:disabled="warrenStore.loading || disabled"
|
||||
class="bg-accent/30 border-border flex w-52 translate-0 flex-row gap-4 overflow-hidden rounded-md border-1 px-4 py-2 select-none"
|
||||
:class="[
|
||||
'bg-accent/30 border-border flex w-52 translate-0 flex-row gap-4 overflow-hidden rounded-md border-1 px-4 py-2 select-none',
|
||||
isCopied && 'border-primary/50 border',
|
||||
]"
|
||||
draggable="true"
|
||||
@dragstart="onDragStart"
|
||||
@drop="onDrop"
|
||||
@@ -124,6 +148,10 @@ const onDrop = onDirectoryEntryDrop(entry);
|
||||
<Icon name="lucide:pencil" />
|
||||
Rename
|
||||
</ContextMenuItem>
|
||||
<ContextMenuItem @select="onCopy">
|
||||
<Icon name="lucide:copy" />
|
||||
Copy
|
||||
</ContextMenuItem>
|
||||
|
||||
<ContextMenuSeparator />
|
||||
|
||||
|
||||
@@ -6,11 +6,35 @@ import {
|
||||
ContextMenuItem,
|
||||
} from '@/components/ui/context-menu';
|
||||
|
||||
const dialog = useCreateDirectoryDialog();
|
||||
const warrenStore = useWarrenStore();
|
||||
const copyStore = useCopyStore();
|
||||
const createDirectoryDialog = useCreateDirectoryDialog();
|
||||
|
||||
const pasting = ref<boolean>(false);
|
||||
const validPaste = computed(
|
||||
() =>
|
||||
!pasting.value && copyStore.file != null && warrenStore.current != null
|
||||
);
|
||||
|
||||
const props = defineProps<{
|
||||
class?: string;
|
||||
}>();
|
||||
|
||||
async function onPaste() {
|
||||
if (!validPaste.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
pasting.value = true;
|
||||
|
||||
await pasteFile(copyStore.file!, {
|
||||
warrenId: warrenStore.current!.warrenId,
|
||||
name: copyStore.file!.name,
|
||||
path: warrenStore.current!.path,
|
||||
});
|
||||
|
||||
pasting.value = false;
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -19,7 +43,11 @@ const props = defineProps<{
|
||||
<slot />
|
||||
</ContextMenuTrigger>
|
||||
<ContextMenuContent>
|
||||
<ContextMenuItem @select="dialog.openDialog">
|
||||
<ContextMenuItem @disabled="!validPaste" @select="onPaste">
|
||||
<Icon name="lucide:clipboard-paste" />
|
||||
Paste
|
||||
</ContextMenuItem>
|
||||
<ContextMenuItem @select="createDirectoryDialog.openDialog">
|
||||
<Icon name="lucide:folder-plus" />
|
||||
Create directory
|
||||
</ContextMenuItem>
|
||||
|
||||
@@ -335,3 +335,38 @@ export async function moveFile(
|
||||
success: true,
|
||||
};
|
||||
}
|
||||
|
||||
export async function copyFile(
|
||||
warrenId: string,
|
||||
currentPath: string,
|
||||
targetPath: string
|
||||
): Promise<{ success: boolean }> {
|
||||
const { status } = await useFetch(getApiUrl(`warrens/files/cp`), {
|
||||
method: 'POST',
|
||||
headers: getApiHeaders(),
|
||||
body: JSON.stringify({
|
||||
warrenId,
|
||||
path: currentPath,
|
||||
targetPath: targetPath,
|
||||
}),
|
||||
});
|
||||
|
||||
if (status.value !== 'success') {
|
||||
toast.error('Copy', {
|
||||
id: 'COPY_FILE_TOAST',
|
||||
description: `Failed to copy file`,
|
||||
});
|
||||
return { success: false };
|
||||
}
|
||||
|
||||
await refreshNuxtData('current-directory');
|
||||
|
||||
toast.success('Copy', {
|
||||
id: 'COPY_FILE_TOAST',
|
||||
description: `Successfully copied file`,
|
||||
});
|
||||
|
||||
return {
|
||||
success: true,
|
||||
};
|
||||
}
|
||||
|
||||
18
frontend/stores/copy.ts
Normal file
18
frontend/stores/copy.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
export const useCopyStore = defineStore('file-copy', {
|
||||
state: () => ({
|
||||
file: null as { warrenId: string; path: string; name: string } | null,
|
||||
}),
|
||||
actions: {
|
||||
copyFile(warrenId: string, filePath: string, fileName: string) {
|
||||
this.file = {
|
||||
warrenId,
|
||||
path: filePath,
|
||||
name: fileName,
|
||||
};
|
||||
},
|
||||
/** Removes the current file from the "clipboard" */
|
||||
clearFile() {
|
||||
this.file = null;
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -1,4 +1,4 @@
|
||||
import { moveFile } from '~/lib/api/warrens';
|
||||
import { copyFile, moveFile } from '~/lib/api/warrens';
|
||||
import type { DirectoryEntry } from '~/shared/types';
|
||||
|
||||
export function joinPaths(path: string, ...other: string[]): string {
|
||||
@@ -58,3 +58,20 @@ export function onDirectoryEntryDrop(
|
||||
await moveFile(warrenStore.current.warrenId, currentPath, targetPath);
|
||||
};
|
||||
}
|
||||
|
||||
export async function pasteFile(
|
||||
current: { warrenId: string; path: string; name: string },
|
||||
target: { warrenId: string; path: string; name: string }
|
||||
): Promise<boolean> {
|
||||
if (current.warrenId !== target.warrenId) {
|
||||
throw new Error('Cross-warren copies are not supported yet');
|
||||
}
|
||||
|
||||
const { success } = await copyFile(
|
||||
current.warrenId,
|
||||
joinPaths(current.path, current.name),
|
||||
joinPaths(target.path, target.name)
|
||||
);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user