chore: remove ticket tabs (#1177)

This commit is contained in:
Jonas Plum
2026-01-11 10:04:01 +01:00
committed by GitHub
parent f067a4289a
commit 1b67d5e6cd
14 changed files with 289 additions and 154 deletions

View File

@@ -8,17 +8,21 @@ import StatusIcon from '@/components/ticket/StatusIcon.vue'
import TicketActionBar from '@/components/ticket/TicketActionBar.vue'
import TicketCloseBar from '@/components/ticket/TicketCloseBar.vue'
import TicketHeader from '@/components/ticket/TicketHeader.vue'
import TicketTab from '@/components/ticket/TicketTab.vue'
import TicketComments from '@/components/ticket/comment/TicketComments.vue'
import TicketFiles from '@/components/ticket/file/TicketFiles.vue'
import TicketLinks from '@/components/ticket/link/TicketLinks.vue'
import TicketTasks from '@/components/ticket/task/TicketTasks.vue'
import TicketTimeline from '@/components/ticket/timeline/TicketTimeline.vue'
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger
} from '@/components/ui/accordion'
import { Badge } from '@/components/ui/badge'
import { Button } from '@/components/ui/button'
import { Card } from '@/components/ui/card'
import { Separator } from '@/components/ui/separator'
import { Tabs, TabsList, TabsTrigger } from '@/components/ui/tabs'
import { useToast } from '@/components/ui/toast/use-toast'
import { Edit } from 'lucide-vue-next'
@@ -166,51 +170,64 @@ const updateDescription = (value: string | undefined) => (message.value = value
class="min-h-14"
/>
</Card>
<Separator />
<Tabs default-value="timeline" class="flex flex-1 flex-col">
<TabsList>
<TabsTrigger value="timeline">
Timeline
<Badge
v-if="timeline && timeline.length > 0"
variant="outline"
class="ml-2 hidden sm:inline-flex"
>
{{ timeline.length }}
</Badge>
</TabsTrigger>
<TabsTrigger value="tasks">
Tasks
<Badge
v-if="tasks && tasks.length > 0"
variant="outline"
class="ml-2 hidden sm:inline-flex"
>
{{ tasks.length }}
<StatusIcon :status="taskStatus" class="size-6" />
</Badge>
</TabsTrigger>
<TabsTrigger value="comments">
Comments
<Badge
v-if="comments && comments.length > 0"
variant="outline"
class="ml-2 hidden sm:inline-flex"
>
{{ comments.length }}
</Badge>
</TabsTrigger>
</TabsList>
<TicketTab value="timeline">
<TicketTimeline :ticket="ticket" :timeline="timeline" />
</TicketTab>
<TicketTab value="tasks">
<TicketTasks :ticket="ticket" :tasks="tasks" />
</TicketTab>
<TicketTab value="comments">
<TicketComments :ticket="ticket" :comments="comments" />
</TicketTab>
</Tabs>
<Accordion
type="multiple"
:default-value="['tasks', 'comments', 'timeline']"
class="w-full divide-y rounded-md border"
>
<AccordionItem value="tasks" class="border-0">
<AccordionTrigger class="px-3 py-2 hover:no-underline">
<div class="flex items-center gap-2">
<span class="text-sm font-medium">Tasks</span>
<Badge
v-if="tasks && tasks.length > 0"
variant="outline"
class="hidden sm:inline-flex"
>
{{ tasks.length }}
<StatusIcon :status="taskStatus" class="size-6" />
</Badge>
</div>
</AccordionTrigger>
<AccordionContent class="px-3 pt-2">
<TicketTasks :ticket="ticket" :tasks="tasks" />
</AccordionContent>
</AccordionItem>
<AccordionItem value="comments" class="border-0">
<AccordionTrigger class="px-3 py-2 hover:no-underline">
<div class="flex items-center gap-2">
<span class="text-sm font-medium">Comments</span>
<Badge
v-if="comments && comments.length > 0"
variant="outline"
class="hidden sm:inline-flex"
>
{{ comments.length }}
</Badge>
</div>
</AccordionTrigger>
<AccordionContent class="px-3 pt-2">
<TicketComments :ticket="ticket" :comments="comments" />
</AccordionContent>
</AccordionItem>
<AccordionItem value="timeline" class="border-0">
<AccordionTrigger class="px-3 py-2 hover:no-underline">
<div class="flex items-center gap-2">
<span class="text-sm font-medium">Timeline</span>
<Badge
v-if="timeline && timeline.length > 0"
variant="outline"
class="hidden sm:inline-flex"
>
{{ timeline.length }}
</Badge>
</div>
</AccordionTrigger>
<AccordionContent class="px-3 pt-2">
<TicketTimeline :ticket="ticket" :timeline="timeline" />
</AccordionContent>
</AccordionItem>
</Accordion>
<Separator class="xl:hidden" />
</div>
<div class="flex flex-col gap-4 xl:w-96 xl:flex-initial">

View File

@@ -0,0 +1,15 @@
<script setup lang="ts">
import type { AccordionRootEmits, AccordionRootProps } from 'reka-ui'
import { AccordionRoot, useForwardPropsEmits } from 'reka-ui'
const props = defineProps<AccordionRootProps>()
const emits = defineEmits<AccordionRootEmits>()
const forwarded = useForwardPropsEmits(props, emits)
</script>
<template>
<AccordionRoot v-bind="forwarded">
<slot />
</AccordionRoot>
</template>

View File

@@ -0,0 +1,23 @@
<script setup lang="ts">
import { reactiveOmit } from '@vueuse/core'
import type { AccordionContentProps } from 'reka-ui'
import { AccordionContent } from 'reka-ui'
import type { HTMLAttributes } from 'vue'
import { cn } from '@/lib/utils'
const props = defineProps<AccordionContentProps & { class?: HTMLAttributes['class'] }>()
const delegatedProps = reactiveOmit(props, 'class')
</script>
<template>
<AccordionContent
v-bind="delegatedProps"
class="overflow-hidden text-sm transition-all data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down"
>
<div :class="cn('pb-4 pt-0', props.class)">
<slot />
</div>
</AccordionContent>
</template>

View File

@@ -0,0 +1,20 @@
<script setup lang="ts">
import { reactiveOmit } from '@vueuse/core'
import type { AccordionItemProps } from 'reka-ui'
import { AccordionItem, useForwardProps } from 'reka-ui'
import type { HTMLAttributes } from 'vue'
import { cn } from '@/lib/utils'
const props = defineProps<AccordionItemProps & { class?: HTMLAttributes['class'] }>()
const delegatedProps = reactiveOmit(props, 'class')
const forwardedProps = useForwardProps(delegatedProps)
</script>
<template>
<AccordionItem v-bind="forwardedProps" :class="cn('border-b', props.class)">
<slot />
</AccordionItem>
</template>

View File

@@ -0,0 +1,33 @@
<script setup lang="ts">
import { ChevronDown } from 'lucide-vue-next'
import { reactiveOmit } from '@vueuse/core'
import type { AccordionTriggerProps } from 'reka-ui'
import { AccordionHeader, AccordionTrigger } from 'reka-ui'
import type { HTMLAttributes } from 'vue'
import { cn } from '@/lib/utils'
const props = defineProps<AccordionTriggerProps & { class?: HTMLAttributes['class'] }>()
const delegatedProps = reactiveOmit(props, 'class')
</script>
<template>
<AccordionHeader class="flex">
<AccordionTrigger
v-bind="delegatedProps"
:class="
cn(
'flex flex-1 items-center justify-between py-4 font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180',
props.class
)
"
>
<slot />
<slot name="icon">
<ChevronDown class="h-4 w-4 shrink-0 transition-transform duration-200" />
</slot>
</AccordionTrigger>
</AccordionHeader>
</template>

View File

@@ -0,0 +1,4 @@
export { default as Accordion } from './Accordion.vue'
export { default as AccordionContent } from './AccordionContent.vue'
export { default as AccordionItem } from './AccordionItem.vue'
export { default as AccordionTrigger } from './AccordionTrigger.vue'