85 lines
2.9 KiB
Vue
85 lines
2.9 KiB
Vue
<script setup lang="ts">
|
|
import { Link } from '@inertiajs/vue3';
|
|
import { ArrowUpRight } from 'lucide-vue-next';
|
|
import TicketMetadata from '@/components/tickets/TicketMetadata.vue';
|
|
import { Badge } from '@/components/ui/badge';
|
|
import { useLocalization } from '@/composables/useLocalization';
|
|
import { show as showTicket } from '@/routes/projects/tickets';
|
|
import type {
|
|
TicketPresentationEmits,
|
|
TicketPresentationProps,
|
|
} from '@/types/ticket-presentation';
|
|
|
|
withDefaults(defineProps<TicketPresentationProps>(), {
|
|
showDescription: true,
|
|
showStatus: true,
|
|
});
|
|
|
|
const emit = defineEmits<TicketPresentationEmits>();
|
|
const { t } = useLocalization();
|
|
</script>
|
|
|
|
<template>
|
|
<article
|
|
:class="[
|
|
'bg-card text-card-foreground min-w-0 rounded-md border shadow-sm',
|
|
ticket.is_blocked ? 'border-warning' : 'border-border',
|
|
]"
|
|
>
|
|
<Link
|
|
:href="showTicket({ project: projectId, ticket: ticket.id })"
|
|
:aria-label="
|
|
t('tickets.open', {
|
|
key: ticket.ticket_key,
|
|
title: ticket.title,
|
|
})
|
|
"
|
|
class="focus-visible:ring-ring/35 gap-card min-h-control hover:bg-accent/35 group flex min-w-0 flex-col rounded-t-md p-4 transition-[background-color,box-shadow] focus-visible:outline-none focus-visible:ring-2"
|
|
@click="emit('open', ticket.id)"
|
|
>
|
|
<div class="flex min-w-0 items-start justify-between gap-3">
|
|
<Badge
|
|
variant="outline"
|
|
class="wrap-anywhere max-w-full whitespace-normal"
|
|
>
|
|
{{ ticket.ticket_key }}
|
|
</Badge>
|
|
<ArrowUpRight
|
|
class="text-muted-foreground group-hover:text-primary size-4 shrink-0"
|
|
aria-hidden="true"
|
|
/>
|
|
</div>
|
|
|
|
<h3
|
|
class="text-body group-hover:text-primary wrap-anywhere min-w-0 font-semibold"
|
|
>
|
|
{{ ticket.title }}
|
|
</h3>
|
|
|
|
<TicketMetadata :ticket="ticket" :show-status="showStatus" />
|
|
|
|
<p
|
|
v-if="showDescription && ticket.description"
|
|
class="text-caption text-muted-foreground wrap-anywhere line-clamp-3"
|
|
>
|
|
{{ ticket.description }}
|
|
</p>
|
|
|
|
<p
|
|
v-if="ticket.is_blocked && ticket.blocked_comment"
|
|
class="text-caption text-warning-foreground bg-warning wrap-anywhere rounded-sm px-3 py-2"
|
|
>
|
|
{{
|
|
t('tickets.blockerComment', {
|
|
comment: ticket.blocked_comment,
|
|
})
|
|
}}
|
|
</p>
|
|
</Link>
|
|
|
|
<div v-if="$slots.actions" class="border-t p-4">
|
|
<slot name="actions" />
|
|
</div>
|
|
</article>
|
|
</template>
|