directory list context menu
This commit is contained in:
@@ -18,11 +18,11 @@ const { entry, disabled } = defineProps<{
|
|||||||
|
|
||||||
const deleting = ref(false);
|
const deleting = ref(false);
|
||||||
|
|
||||||
async function submitDelete() {
|
async function submitDelete(force: boolean = false) {
|
||||||
deleting.value = true;
|
deleting.value = true;
|
||||||
|
|
||||||
if (entry.fileType === 'directory') {
|
if (entry.fileType === 'directory') {
|
||||||
await deleteWarrenDirectory(warrenRoute.value, entry.name);
|
await deleteWarrenDirectory(warrenRoute.value, entry.name, force);
|
||||||
} else {
|
} else {
|
||||||
await deleteWarrenFile(warrenRoute.value, entry.name);
|
await deleteWarrenFile(warrenRoute.value, entry.name);
|
||||||
}
|
}
|
||||||
@@ -56,10 +56,20 @@ async function submitDelete() {
|
|||||||
</NuxtLink>
|
</NuxtLink>
|
||||||
</ContextMenuTrigger>
|
</ContextMenuTrigger>
|
||||||
<ContextMenuContent>
|
<ContextMenuContent>
|
||||||
<ContextMenuItem @select="submitDelete">
|
<ContextMenuItem @select="() => submitDelete(false)">
|
||||||
<Icon name="lucide:trash-2" />
|
<Icon name="lucide:trash-2" />
|
||||||
Delete
|
Delete
|
||||||
</ContextMenuItem>
|
</ContextMenuItem>
|
||||||
|
<ContextMenuItem
|
||||||
|
v-if="entry.fileType === 'directory'"
|
||||||
|
@select="() => submitDelete(true)"
|
||||||
|
>
|
||||||
|
<Icon
|
||||||
|
class="text-destructive-foreground"
|
||||||
|
name="lucide:trash-2"
|
||||||
|
/>
|
||||||
|
Force delete
|
||||||
|
</ContextMenuItem>
|
||||||
</ContextMenuContent>
|
</ContextMenuContent>
|
||||||
</ContextMenu>
|
</ContextMenu>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
28
frontend/components/DirectoryListContextMenu.vue
Normal file
28
frontend/components/DirectoryListContextMenu.vue
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import {
|
||||||
|
ContextMenu,
|
||||||
|
ContextMenuTrigger,
|
||||||
|
ContextMenuContent,
|
||||||
|
ContextMenuItem,
|
||||||
|
} from '@/components/ui/context-menu';
|
||||||
|
|
||||||
|
const dialog = useCreateDirectoryDialog();
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
class?: string;
|
||||||
|
}>();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<ContextMenu>
|
||||||
|
<ContextMenuTrigger :class="props.class">
|
||||||
|
<slot />
|
||||||
|
</ContextMenuTrigger>
|
||||||
|
<ContextMenuContent>
|
||||||
|
<ContextMenuItem @select="dialog.openDialog">
|
||||||
|
<Icon name="lucide:folder-plus" />
|
||||||
|
Create directory
|
||||||
|
</ContextMenuItem>
|
||||||
|
</ContextMenuContent>
|
||||||
|
</ContextMenu>
|
||||||
|
</template>
|
||||||
@@ -11,9 +11,9 @@ import {
|
|||||||
import { createDirectory } from '~/lib/api/warrens';
|
import { createDirectory } from '~/lib/api/warrens';
|
||||||
|
|
||||||
const warrenRoute = useWarrenRoute();
|
const warrenRoute = useWarrenRoute();
|
||||||
|
const dialog = useCreateDirectoryDialog();
|
||||||
|
|
||||||
const creating = ref(false);
|
const creating = ref(false);
|
||||||
const open = ref(false);
|
|
||||||
const directoryName = ref('');
|
const directoryName = ref('');
|
||||||
|
|
||||||
async function submit() {
|
async function submit() {
|
||||||
@@ -28,13 +28,13 @@ async function submit() {
|
|||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
directoryName.value = '';
|
directoryName.value = '';
|
||||||
open.value = false;
|
dialog.open = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Dialog v-model:open="open">
|
<Dialog v-model:open="dialog.open">
|
||||||
<DialogTrigger as-child>
|
<DialogTrigger as-child>
|
||||||
<slot />
|
<slot />
|
||||||
</DialogTrigger>
|
</DialogTrigger>
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ const breadcrumbs = computed(() => getBreadcrumbs(route.path));
|
|||||||
<template>
|
<template>
|
||||||
<SidebarProvider>
|
<SidebarProvider>
|
||||||
<AppSidebar />
|
<AppSidebar />
|
||||||
<main class="w-full grow">
|
<main class="w-full grow overflow-hidden flex flex-col">
|
||||||
<header
|
<header
|
||||||
class="h-16 flex items-center gap-2 transition-[width,height] ease-linear group-has-[[data-collapsible=icon]]/sidebar-wrapper:h-12"
|
class="h-16 flex items-center gap-2 transition-[width,height] ease-linear group-has-[[data-collapsible=icon]]/sidebar-wrapper:h-12"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { toast } from 'vue-sonner';
|
import { toast } from 'vue-sonner';
|
||||||
import type { DirectoryEntry, FileType } from '~/types';
|
import type { DirectoryEntry } from '~/types';
|
||||||
import type { ApiResponse } from '~/types/api';
|
import type { ApiResponse } from '~/types/api';
|
||||||
import type { Warren } from '~/types/warrens';
|
import type { Warren } from '~/types/warrens';
|
||||||
|
|
||||||
@@ -104,7 +104,8 @@ export async function createDirectory(
|
|||||||
|
|
||||||
export async function deleteWarrenDirectory(
|
export async function deleteWarrenDirectory(
|
||||||
path: string,
|
path: string,
|
||||||
directoryName: string
|
directoryName: string,
|
||||||
|
force: boolean
|
||||||
): Promise<{ success: boolean }> {
|
): Promise<{ success: boolean }> {
|
||||||
// eslint-disable-next-line prefer-const
|
// eslint-disable-next-line prefer-const
|
||||||
let [warrenId, rest] = splitOnce(path, '/');
|
let [warrenId, rest] = splitOnce(path, '/');
|
||||||
@@ -125,7 +126,7 @@ export async function deleteWarrenDirectory(
|
|||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
warrenId,
|
warrenId,
|
||||||
path: rest,
|
path: rest,
|
||||||
force: false,
|
force,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import DirectoryListContextMenu from '~/components/DirectoryListContextMenu.vue';
|
||||||
import { getWarrenDirectory } from '~/lib/api/warrens';
|
import { getWarrenDirectory } from '~/lib/api/warrens';
|
||||||
|
|
||||||
const entries = useAsyncData('current-directory', () =>
|
const entries = useAsyncData('current-directory', () =>
|
||||||
getWarrenDirectory(useWarrenRoute().value)
|
getWarrenDirectory(useWarrenRoute().value)
|
||||||
).data;
|
).data;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<DirectoryListContextMenu class="w-full grow">
|
||||||
<DirectoryList v-if="entries != null" :entries="entries" />
|
<DirectoryList v-if="entries != null" :entries="entries" />
|
||||||
</div>
|
</DirectoryListContextMenu>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -15,3 +15,14 @@ export const useWarrenStore = defineStore<
|
|||||||
|
|
||||||
export const useWarrenRoute = () =>
|
export const useWarrenRoute = () =>
|
||||||
computed(() => useRoute().path.split('/warrens/')[1]);
|
computed(() => useRoute().path.split('/warrens/')[1]);
|
||||||
|
|
||||||
|
export const useCreateDirectoryDialog = defineStore('create_directory_dialog', {
|
||||||
|
state: () => ({
|
||||||
|
open: false,
|
||||||
|
}),
|
||||||
|
actions: {
|
||||||
|
openDialog() {
|
||||||
|
this.open = true;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user