mirror of
https://github.com/Litlyx/litlyx
synced 2025-12-10 07:48:37 +01:00
implementing snapshots
This commit is contained in:
@@ -17,7 +17,7 @@ const { showDialog, closeDialog, dialogComponent, dialogParams, dialogStyle, dia
|
|||||||
|
|
||||||
<div class="fixed top-4 right-8 z-[999] flex flex-col gap-2" v-if="alerts.length > 0">
|
<div class="fixed top-4 right-8 z-[999] flex flex-col gap-2" v-if="alerts.length > 0">
|
||||||
<div v-for="alert of alerts"
|
<div v-for="alert of alerts"
|
||||||
class="w-[30vw] min-w-[20rem] relative bg-[#151515] border-solid border-[2px] border-[#262626] rounded-lg p-6 drop-shadow-lg">
|
class="w-[30vw] min-w-[20rem] relative bg-[#151515] overflow-hidden border-solid border-[2px] border-[#262626] rounded-lg p-6 drop-shadow-lg">
|
||||||
<div class="flex items-start gap-4">
|
<div class="flex items-start gap-4">
|
||||||
<div> <i :class="alert.icon"></i> </div>
|
<div> <i :class="alert.icon"></i> </div>
|
||||||
<div class="grow">
|
<div class="grow">
|
||||||
@@ -30,7 +30,8 @@ const { showDialog, closeDialog, dialogComponent, dialogParams, dialogStyle, dia
|
|||||||
<i @click="closeAlert(alert.id)" class="fas fa-close hover:text-[#CCCCCC] cursor-pointer"></i>
|
<i @click="closeAlert(alert.id)" class="fas fa-close hover:text-[#CCCCCC] cursor-pointer"></i>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div :style="`width: ${Math.floor(100 / alert.ms * alert.remaining)}%; ${alert.transitionStyle}`"
|
||||||
|
class="absolute bottom-0 left-0 h-1 bg-lyx-primary z-100 alert-bar"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -62,3 +63,4 @@ const { showDialog, closeDialog, dialogComponent, dialogParams, dialogStyle, dia
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
|
||||||
import CreateSnapshot from './dialog/CreateSnapshot.vue';
|
import CreateSnapshot from './dialog/CreateSnapshot.vue';
|
||||||
|
|
||||||
export type Entry = {
|
export type Entry = {
|
||||||
@@ -29,7 +30,7 @@ const debugMode = process.dev;
|
|||||||
|
|
||||||
const { isOpen, close } = useMenu();
|
const { isOpen, close } = useMenu();
|
||||||
|
|
||||||
const { snapshots, snapshot } = useSnapshot();
|
const { snapshots, snapshot, updateSnapshots } = useSnapshot();
|
||||||
|
|
||||||
const snapshotsItems = computed(() => {
|
const snapshotsItems = computed(() => {
|
||||||
if (!snapshots.value) return []
|
if (!snapshots.value) return []
|
||||||
@@ -41,12 +42,28 @@ const { openDialogEx } = useCustomDialog();
|
|||||||
|
|
||||||
function openSnapshotDialog() {
|
function openSnapshotDialog() {
|
||||||
openDialogEx(CreateSnapshot, {
|
openDialogEx(CreateSnapshot, {
|
||||||
width: "20rem",
|
width: "24rem",
|
||||||
height: "16rem",
|
height: "16rem",
|
||||||
closable: false
|
closable: false
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const { createAlert } = useAlert()
|
||||||
|
|
||||||
|
async function deleteSnapshot(close: () => any) {
|
||||||
|
await $fetch("/api/snapshot/delete", {
|
||||||
|
method: 'DELETE',
|
||||||
|
...signHeaders({ 'Content-Type': 'application/json' }),
|
||||||
|
body: JSON.stringify({
|
||||||
|
id: snapshot.value._id.toString(),
|
||||||
|
})
|
||||||
|
});
|
||||||
|
await updateSnapshots();
|
||||||
|
snapshot.value = snapshots.value[1];
|
||||||
|
createAlert('Snapshot deleted','Snapshot deleted successfully', 'far fa-circle-check', 5000);
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -102,11 +119,31 @@ function openSnapshotDialog() {
|
|||||||
<div v-if="snapshot" class="flex flex-col text-[.8rem] mt-2 px-2">
|
<div v-if="snapshot" class="flex flex-col text-[.8rem] mt-2 px-2">
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<div class="grow poppins"> From:</div>
|
<div class="grow poppins"> From:</div>
|
||||||
<div class="poppins"> {{ new Date(snapshot.from).toLocaleString('it-IT') }} </div>
|
<div class="poppins"> {{ new Date(snapshot.from).toLocaleString('it-IT').split(',')[0].trim() }} </div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<div class="grow poppins"> To:</div>
|
<div class="grow poppins"> To:</div>
|
||||||
<div class="poppins"> {{ new Date(snapshot.to).toLocaleString('it-IT') }}</div>
|
<div class="poppins"> {{ new Date(snapshot.to).toLocaleString('it-IT').split(',')[0].trim() }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="mt-4" v-if="snapshot._id.toString().startsWith('default') === false">
|
||||||
|
<UPopover placement="bottom">
|
||||||
|
<LyxUiButton type="danger" class="w-full">
|
||||||
|
Delete current snapshot
|
||||||
|
</LyxUiButton>
|
||||||
|
|
||||||
|
<template #panel="{ close }">
|
||||||
|
<div class="p-4 bg-lyx-widget">
|
||||||
|
<div class="poppins text-center font-medium">
|
||||||
|
Are you sure?
|
||||||
|
</div>
|
||||||
|
<div class="flex gap-2 mt-4">
|
||||||
|
<LyxUiButton @click="close()" type="secondary"> Cancel </LyxUiButton>
|
||||||
|
<LyxUiButton type="danger" @click="deleteSnapshot(close)"> Delete </LyxUiButton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</UPopover>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ const ranges = [
|
|||||||
{ label: 'Last 6 months', duration: { months: 6 } },
|
{ label: 'Last 6 months', duration: { months: 6 } },
|
||||||
{ label: 'Last year', duration: { years: 1 } }
|
{ label: 'Last year', duration: { years: 1 } }
|
||||||
]
|
]
|
||||||
const selected = ref({ start: sub(new Date(), { days: 14 }), end: new Date() })
|
const selected = ref<{ start: Date, end: Date }>({ start: sub(new Date(), { days: 14 }), end: new Date() })
|
||||||
|
|
||||||
function isRangeSelected(duration: Duration) {
|
function isRangeSelected(duration: Duration) {
|
||||||
return isSameDay(selected.value.start, sub(new Date(), duration)) && isSameDay(selected.value.end, new Date())
|
return isSameDay(selected.value.start, sub(new Date(), duration)) && isSameDay(selected.value.end, new Date())
|
||||||
@@ -22,7 +22,7 @@ function selectRange(duration: Duration) {
|
|||||||
selected.value = { start: sub(new Date(), duration), end: new Date() }
|
selected.value = { start: sub(new Date(), duration), end: new Date() }
|
||||||
}
|
}
|
||||||
|
|
||||||
const currentColor = ref<string>("");
|
const currentColor = ref<string>("#5680F8");
|
||||||
|
|
||||||
const colorpicker = ref<HTMLInputElement | null>(null);
|
const colorpicker = ref<HTMLInputElement | null>(null);
|
||||||
|
|
||||||
@@ -34,29 +34,55 @@ function onColorChange() {
|
|||||||
currentColor.value = colorpicker.value?.value || '#000000';
|
currentColor.value = colorpicker.value?.value || '#000000';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const snapshotName = ref<string>("");
|
||||||
|
|
||||||
|
const { updateSnapshots } = useSnapshot();
|
||||||
|
const { createAlert } = useAlert()
|
||||||
|
|
||||||
|
async function confirmSnapshot() {
|
||||||
|
await $fetch("/api/snapshot/create", {
|
||||||
|
method: 'POST',
|
||||||
|
...signHeaders({ 'Content-Type': 'application/json' }),
|
||||||
|
body: JSON.stringify({
|
||||||
|
name: snapshotName.value,
|
||||||
|
color: currentColor.value,
|
||||||
|
from: selected.value.start.toISOString(),
|
||||||
|
to: selected.value.end.toISOString()
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
await updateSnapshots();
|
||||||
|
closeDialog();
|
||||||
|
createAlert('Snapshot created','Snapshot created successfully', 'far fa-circle-check', 5000);
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="w-full h-full flex flex-col">
|
<div class="w-full h-full flex flex-col">
|
||||||
|
|
||||||
<div class="poppins text-center">
|
<div class="poppins text-center">
|
||||||
Create a snapshot
|
Create a snapshot
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mt-10 flex items-center gap-2">
|
<div class="mt-10 flex items-center gap-2">
|
||||||
<div :style="`background-color: ${currentColor};`" @click="showColorPicker" class="w-6 h-6 rounded-full aspect-[1/1] relative">
|
<div :style="`background-color: ${currentColor};`" @click="showColorPicker"
|
||||||
|
class="w-6 h-6 rounded-full aspect-[1/1] relative cursor-pointer">
|
||||||
<input @input="onColorChange" ref="colorpicker" class="relative w-0 h-0 z-[-100]" type="color">
|
<input @input="onColorChange" ref="colorpicker" class="relative w-0 h-0 z-[-100]" type="color">
|
||||||
</div>
|
</div>
|
||||||
<div class="grow">
|
<div class="grow">
|
||||||
<input placeholder="Snapshot name" class="px-4 py-2 w-full rounded-lg bg-lyx-widget-light" type="text">
|
<LyxUiInput placeholder="Snapshot name" v-model="snapshotName" class="px-4 py-1 w-full"></LyxUiInput>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mt-4 justify-center flex w-full">
|
<div class="mt-4 justify-center flex w-full">
|
||||||
|
|
||||||
<UPopover :popper="{ placement: 'bottom' }">
|
<UPopover class="w-full" :popper="{ placement: 'bottom' }">
|
||||||
<UButton icon="i-heroicons-calendar-days-20-solid">
|
<UButton class="w-full" color="primary" variant="solid">
|
||||||
{{ selected.start.toLocaleDateString() }} - {{ selected.end.toLocaleDateString() }}
|
<div class="flex items-center justify-center w-full gap-2">
|
||||||
|
<i class="i-heroicons-calendar-days-20-solid"></i>
|
||||||
|
{{ selected.start.toLocaleDateString() }} - {{ selected.end.toLocaleDateString() }}
|
||||||
|
</div>
|
||||||
</UButton>
|
</UButton>
|
||||||
<template #panel="{ close }">
|
<template #panel="{ close }">
|
||||||
<div class="flex items-center sm:divide-x divide-gray-200 dark:divide-gray-800">
|
<div class="flex items-center sm:divide-x divide-gray-200 dark:divide-gray-800">
|
||||||
@@ -76,13 +102,14 @@ function onColorChange() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="grow"></div>
|
<div class="grow"></div>
|
||||||
<div class="flex items-center justify-around">
|
<div class="flex items-center justify-around gap-4">
|
||||||
<div @click="closeDialog()">
|
<LyxUiButton @click="closeDialog()" type="secondary" class="w-full text-center">
|
||||||
Cancel
|
Cancel
|
||||||
</div>
|
</LyxUiButton>
|
||||||
<div @click="closeDialog()">
|
<LyxUiButton @click="confirmSnapshot()" type="primary" class="w-full text-center"
|
||||||
|
:disabled="snapshotName.length == 0">
|
||||||
Confirm
|
Confirm
|
||||||
</div>
|
</LyxUiButton>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
export type ButtonType = 'primary' | 'secondary' | 'outline' | 'danger';
|
export type ButtonType = 'primary' | 'secondary' | 'outline' | 'danger';
|
||||||
|
|
||||||
const props = defineProps<{ type: ButtonType, }>();
|
const props = defineProps<{ type: ButtonType, disabled?: boolean }>();
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -12,6 +12,7 @@ const props = defineProps<{ type: ButtonType, }>();
|
|||||||
'bg-lyx-widget-lighter outline-lyx-widget-lighter hover:bg-lyx-widget-light': type === 'secondary',
|
'bg-lyx-widget-lighter outline-lyx-widget-lighter hover:bg-lyx-widget-light': type === 'secondary',
|
||||||
'bg-lyx-transparent outline-lyx-widget-lighter hover:bg-lyx-widget-light': type === 'outline',
|
'bg-lyx-transparent outline-lyx-widget-lighter hover:bg-lyx-widget-light': type === 'outline',
|
||||||
'bg-lyx-danger-dark outline-lyx-danger hover:bg-lyx-danger': type === 'danger',
|
'bg-lyx-danger-dark outline-lyx-danger hover:bg-lyx-danger': type === 'danger',
|
||||||
|
'bg-lyx-widget-lighter outline-lyx-widget-lighter hover:bg-lyx-widget-lighter !cursor-not-allowed !text-lyx-text-darker': disabled === true
|
||||||
}">
|
}">
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -5,7 +5,9 @@ export type Alert = {
|
|||||||
text: string,
|
text: string,
|
||||||
icon: string,
|
icon: string,
|
||||||
ms: number,
|
ms: number,
|
||||||
id: number
|
id: number,
|
||||||
|
remaining: number,
|
||||||
|
transitionStyle: string
|
||||||
}
|
}
|
||||||
|
|
||||||
const alerts = ref<Alert[]>([]);
|
const alerts = ref<Alert[]>([]);
|
||||||
@@ -18,11 +20,18 @@ const idPool = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function createAlert(title: string, text: string, icon: string, ms: number) {
|
function createAlert(title: string, text: string, icon: string, ms: number) {
|
||||||
const alert: Alert = { title, text, icon, ms, id: idPool.getId() }
|
const alert = reactive<Alert>({
|
||||||
|
title, text, icon, ms, id: idPool.getId(), remaining: ms,
|
||||||
|
transitionStyle: 'transition: all 250ms linear;'
|
||||||
|
});
|
||||||
alerts.value.push(alert);
|
alerts.value.push(alert);
|
||||||
setTimeout(() => {
|
const timeout = setInterval(() => {
|
||||||
closeAlert(alert.id);
|
alert.remaining -= 250;
|
||||||
}, ms)
|
if (alert.remaining <= 0) {
|
||||||
|
closeAlert(alert.id);
|
||||||
|
clearInterval(timeout);
|
||||||
|
}
|
||||||
|
}, 250)
|
||||||
}
|
}
|
||||||
|
|
||||||
function closeAlert(id: number) {
|
function closeAlert(id: number) {
|
||||||
|
|||||||
@@ -5,6 +5,10 @@ const remoteSnapshots = useFetch<TProjectSnapshot[]>('/api/project/snapshots', {
|
|||||||
immediate: false
|
immediate: false
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const activeProject = useActiveProject();
|
||||||
|
watch(activeProject, () => {
|
||||||
|
remoteSnapshots.refresh();
|
||||||
|
});
|
||||||
|
|
||||||
const snapshots = computed(() => {
|
const snapshots = computed(() => {
|
||||||
|
|
||||||
@@ -13,7 +17,7 @@ const snapshots = computed(() => {
|
|||||||
const getDefaultSnapshots: () => TProjectSnapshot[] = () => [
|
const getDefaultSnapshots: () => TProjectSnapshot[] = () => [
|
||||||
{
|
{
|
||||||
project_id: activeProject.value?._id as any,
|
project_id: activeProject.value?._id as any,
|
||||||
_id: 'deafult0' as any,
|
_id: 'default0' as any,
|
||||||
name: 'All',
|
name: 'All',
|
||||||
from: new Date(activeProject.value?.created_at || 0),
|
from: new Date(activeProject.value?.created_at || 0),
|
||||||
to: new Date(Date.now()),
|
to: new Date(Date.now()),
|
||||||
@@ -21,7 +25,7 @@ const snapshots = computed(() => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
project_id: activeProject.value?._id as any,
|
project_id: activeProject.value?._id as any,
|
||||||
_id: 'deafult1' as any,
|
_id: 'default1' as any,
|
||||||
name: 'Last month',
|
name: 'Last month',
|
||||||
from: new Date(Date.now() - 1000 * 60 * 60 * 24 * 30),
|
from: new Date(Date.now() - 1000 * 60 * 60 * 24 * 30),
|
||||||
to: new Date(Date.now()),
|
to: new Date(Date.now()),
|
||||||
@@ -29,7 +33,7 @@ const snapshots = computed(() => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
project_id: activeProject.value?._id as any,
|
project_id: activeProject.value?._id as any,
|
||||||
_id: 'deafult2' as any,
|
_id: 'default2' as any,
|
||||||
name: 'Last week',
|
name: 'Last week',
|
||||||
from: new Date(Date.now() - 1000 * 60 * 60 * 24 * 7),
|
from: new Date(Date.now() - 1000 * 60 * 60 * 24 * 7),
|
||||||
to: new Date(Date.now()),
|
to: new Date(Date.now()),
|
||||||
@@ -37,7 +41,7 @@ const snapshots = computed(() => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
project_id: activeProject.value?._id as any,
|
project_id: activeProject.value?._id as any,
|
||||||
_id: 'deafult3' as any,
|
_id: 'default3' as any,
|
||||||
name: 'Last day',
|
name: 'Last day',
|
||||||
from: new Date(Date.now() - 1000 * 60 * 60 * 24),
|
from: new Date(Date.now() - 1000 * 60 * 60 * 24),
|
||||||
to: new Date(Date.now()),
|
to: new Date(Date.now()),
|
||||||
@@ -51,7 +55,7 @@ const snapshots = computed(() => {
|
|||||||
];
|
];
|
||||||
})
|
})
|
||||||
|
|
||||||
const snapshot = ref<TProjectSnapshot>(snapshots.value[0]);
|
const snapshot = ref<TProjectSnapshot>(snapshots.value[1]);
|
||||||
|
|
||||||
// watch(remoteSnapshots.data, () => {
|
// watch(remoteSnapshots.data, () => {
|
||||||
// if (!remoteSnapshots.data.value) return;
|
// if (!remoteSnapshots.data.value) return;
|
||||||
@@ -64,9 +68,13 @@ const safeSnapshotDates = computed(() => {
|
|||||||
return { from, to }
|
return { from, to }
|
||||||
})
|
})
|
||||||
|
|
||||||
|
function updateSnapshots() {
|
||||||
|
remoteSnapshots.refresh();
|
||||||
|
}
|
||||||
|
|
||||||
export function useSnapshot() {
|
export function useSnapshot() {
|
||||||
if (remoteSnapshots.status.value === 'idle') {
|
if (remoteSnapshots.status.value === 'idle') {
|
||||||
remoteSnapshots.execute();
|
remoteSnapshots.execute();
|
||||||
}
|
}
|
||||||
return { snapshot, snapshots, safeSnapshotDates }
|
return { snapshot, snapshots, safeSnapshotDates, updateSnapshots }
|
||||||
}
|
}
|
||||||
@@ -70,6 +70,9 @@ const selectLabels = [
|
|||||||
// { label: 'Month', value: 'month' },
|
// { label: 'Month', value: 'month' },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
function testAlert() {
|
||||||
|
createAlert('test', 'test', 'fas fa-home', 40000);
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
43
dashboard/server/api/snapshot/create.post.ts
Normal file
43
dashboard/server/api/snapshot/create.post.ts
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
import { ProjectModel } from "@schema/ProjectSchema";
|
||||||
|
import { ProjectSnapshotModel } from "@schema/ProjectSnapshot";
|
||||||
|
import { UserSettingsModel } from "@schema/UserSettings";
|
||||||
|
|
||||||
|
|
||||||
|
export default defineEventHandler(async event => {
|
||||||
|
|
||||||
|
const body = await readBody(event);
|
||||||
|
|
||||||
|
const { name: newSnapshotName, from, to, color: snapshotColor } = body;
|
||||||
|
|
||||||
|
if (!newSnapshotName) return setResponseStatus(event, 400, 'SnapshotName too short');
|
||||||
|
if (newSnapshotName.length == 0) return setResponseStatus(event, 400, 'SnapshotName too short');
|
||||||
|
|
||||||
|
if (!from) return setResponseStatus(event, 400, 'from is required');
|
||||||
|
if (!to) return setResponseStatus(event, 400, 'to is required');
|
||||||
|
if (!snapshotColor) return setResponseStatus(event, 400, 'color is required');
|
||||||
|
|
||||||
|
const userData = getRequestUser(event);
|
||||||
|
if (!userData?.logged) return setResponseStatus(event, 400, 'NotLogged');
|
||||||
|
|
||||||
|
const userSettings = await UserSettingsModel.findOne({ user_id: userData.id }, { active_project_id: 1 });
|
||||||
|
|
||||||
|
if (!userSettings) return setResponseStatus(event, 500, 'Unkwnown error');
|
||||||
|
|
||||||
|
const currentProjectId = userSettings.active_project_id;
|
||||||
|
|
||||||
|
const project = await ProjectModel.findById(currentProjectId);
|
||||||
|
if (!project) return setResponseStatus(event, 400, 'Project not found');
|
||||||
|
|
||||||
|
|
||||||
|
const newSnapshot = await ProjectSnapshotModel.create({
|
||||||
|
name: newSnapshotName,
|
||||||
|
from: new Date(from),
|
||||||
|
to: new Date(to),
|
||||||
|
color: snapshotColor,
|
||||||
|
project_id: currentProjectId
|
||||||
|
});
|
||||||
|
|
||||||
|
return newSnapshot.id;
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
35
dashboard/server/api/snapshot/delete.delete.ts
Normal file
35
dashboard/server/api/snapshot/delete.delete.ts
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import { ProjectModel } from "@schema/ProjectSchema";
|
||||||
|
import { ProjectSnapshotModel } from "@schema/ProjectSnapshot";
|
||||||
|
import { UserSettingsModel } from "@schema/UserSettings";
|
||||||
|
|
||||||
|
|
||||||
|
export default defineEventHandler(async event => {
|
||||||
|
|
||||||
|
const body = await readBody(event);
|
||||||
|
|
||||||
|
const { id: snapshotId } = body;
|
||||||
|
|
||||||
|
if (!snapshotId) return setResponseStatus(event, 400, 'id is required');
|
||||||
|
|
||||||
|
const userData = getRequestUser(event);
|
||||||
|
if (!userData?.logged) return setResponseStatus(event, 400, 'NotLogged');
|
||||||
|
|
||||||
|
const userSettings = await UserSettingsModel.findOne({ user_id: userData.id }, { active_project_id: 1 });
|
||||||
|
|
||||||
|
if (!userSettings) return setResponseStatus(event, 500, 'Unkwnown error');
|
||||||
|
|
||||||
|
const currentProjectId = userSettings.active_project_id;
|
||||||
|
|
||||||
|
const project = await ProjectModel.findById(currentProjectId);
|
||||||
|
if (!project) return setResponseStatus(event, 400, 'Project not found');
|
||||||
|
|
||||||
|
|
||||||
|
const deletation = await ProjectSnapshotModel.deleteOne({
|
||||||
|
project_id: currentProjectId,
|
||||||
|
_id: snapshotId
|
||||||
|
});
|
||||||
|
|
||||||
|
return { ok: deletation.acknowledged };
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user