mirror of
https://github.com/SecurityBrewery/catalyst.git
synced 2025-12-08 16:22:46 +01:00
refactor: improve setup and maintainability (#1067)
This commit is contained in:
147
ui/src/components/ticket/timeline/TicketTimelineItem.vue
Normal file
147
ui/src/components/ticket/timeline/TicketTimelineItem.vue
Normal file
@@ -0,0 +1,147 @@
|
||||
<script setup lang="ts">
|
||||
import PanelListElement from '@/components/common/PanelListElement.vue'
|
||||
import DynamicInput from '@/components/input/DynamicInput.vue'
|
||||
import DynamicMDEditor from '@/components/input/DynamicMDEditor.vue'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import {
|
||||
Dialog,
|
||||
DialogClose,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger
|
||||
} from '@/components/ui/dialog'
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger
|
||||
} from '@/components/ui/dropdown-menu'
|
||||
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'
|
||||
import { toast } from '@/components/ui/toast'
|
||||
import { Calendar } from '@/components/ui/v-calendar'
|
||||
|
||||
import { Calendar as CalendarIcon, Edit, MoreVertical, Trash } from 'lucide-vue-next'
|
||||
|
||||
import { useMutation, useQueryClient } from '@tanstack/vue-query'
|
||||
import format from 'date-fns/format'
|
||||
import { ref, watch } from 'vue'
|
||||
|
||||
import { pb } from '@/lib/pocketbase'
|
||||
import type { TimelineItem } from '@/lib/types'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
const props = defineProps<{
|
||||
timelineItem: TimelineItem
|
||||
}>()
|
||||
|
||||
const isOpen = ref(false)
|
||||
const time = ref(props.timelineItem.time)
|
||||
const editMode = ref(false)
|
||||
const message = ref(props.timelineItem.message)
|
||||
|
||||
const updateTimelineMutation = useMutation({
|
||||
mutationFn: (update: { time?: string; message?: string }): Promise<TimelineItem> =>
|
||||
pb.collection('timeline').update(props.timelineItem.id, update),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['tickets', props.timelineItem.ticket] })
|
||||
editMode.value = false
|
||||
},
|
||||
onError: (error) =>
|
||||
toast({
|
||||
title: error.name,
|
||||
description: error.message,
|
||||
variant: 'destructive'
|
||||
})
|
||||
})
|
||||
|
||||
watch(time, () => {
|
||||
if (time.value) {
|
||||
updateTimelineMutation.mutate({ time: time.value })
|
||||
}
|
||||
})
|
||||
|
||||
const deleteTimelineItemMutation = useMutation({
|
||||
mutationFn: () => pb.collection('timeline').delete(props.timelineItem.id),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['tickets', props.timelineItem.ticket] })
|
||||
isOpen.value = false
|
||||
},
|
||||
onError: (error) =>
|
||||
toast({
|
||||
title: error.name,
|
||||
description: error.message,
|
||||
variant: 'destructive'
|
||||
})
|
||||
})
|
||||
|
||||
const edit = () => (editMode.value = true)
|
||||
const save = () =>
|
||||
updateTimelineMutation.mutate({
|
||||
time: time.value,
|
||||
message: message.value
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<PanelListElement class="flex h-auto flex-row items-start gap-2 p-1 align-top">
|
||||
<Popover>
|
||||
<PopoverTrigger as-child>
|
||||
<Button
|
||||
variant="ghost"
|
||||
:class="cn('w-20 justify-center text-left font-normal', !time && 'text-muted-foreground')"
|
||||
>
|
||||
{{ time ? format(time, 'HH:mm:ss') : 'Pick a date' }}
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent class="w-auto p-0">
|
||||
<Calendar v-model="time" mode="datetime" />
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
<div class="my-0.5 flex-1">
|
||||
<DynamicMDEditor v-model="message" v-model:edit="editMode" @save="save" autofocus />
|
||||
</div>
|
||||
<Dialog v-model:open="isOpen">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger as-child>
|
||||
<Button size="icon" variant="outline" class="ml-auto mr-1 mt-1 h-8 w-8">
|
||||
<MoreVertical class="h-3.5 w-3.5" />
|
||||
<span class="sr-only">More</span>
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end">
|
||||
<DropdownMenuItem class="cursor-pointer" @click="edit">
|
||||
<Edit class="mr-2 h-4 w-4" />
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem class="cursor-pointer" as-child>
|
||||
<DialogTrigger class="w-full">
|
||||
<Trash class="mr-2 h-4 w-4" />
|
||||
Delete
|
||||
</DialogTrigger>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Delete timeline item</DialogTitle>
|
||||
<DialogDescription>
|
||||
Are you sure you want to delete this timeline item?</DialogDescription
|
||||
>
|
||||
</DialogHeader>
|
||||
<DialogFooter>
|
||||
<DialogClose as-child>
|
||||
<Button type="button" variant="secondary"> Cancel</Button>
|
||||
</DialogClose>
|
||||
<Button @click="deleteTimelineItemMutation.mutate" variant="destructive">
|
||||
Delete
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</DropdownMenu>
|
||||
</Dialog>
|
||||
</PanelListElement>
|
||||
</template>
|
||||
Reference in New Issue
Block a user