mirror of
https://github.com/SecurityBrewery/catalyst.git
synced 2026-02-25 14:36:13 +01:00
perf: search (#1091)
This commit is contained in:
@@ -17,9 +17,8 @@ import {
|
||||
import { ScrollArea } from '@/components/ui/scroll-area'
|
||||
import { Separator } from '@/components/ui/separator'
|
||||
import { Tabs, TabsList, TabsTrigger } from '@/components/ui/tabs'
|
||||
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip'
|
||||
|
||||
import { Info, LoaderCircle, Search } from 'lucide-vue-next'
|
||||
import { LoaderCircle, Search } from 'lucide-vue-next'
|
||||
|
||||
import { useQuery } from '@tanstack/vue-query'
|
||||
import debounce from 'lodash.debounce'
|
||||
@@ -28,7 +27,7 @@ import { computed, ref, watch } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
|
||||
import { pb } from '@/lib/pocketbase'
|
||||
import type { Ticket, Type } from '@/lib/types'
|
||||
import type { SearchTicket, Type } from '@/lib/types'
|
||||
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
@@ -48,15 +47,13 @@ const filter = computed(() => {
|
||||
let raws: Array<string> = [
|
||||
'name ~ {:search}',
|
||||
'description ~ {:search}',
|
||||
'owner.name ~ {:search}',
|
||||
'owner.email ~ {:search}',
|
||||
'links_via_ticket.name ~ {:search}',
|
||||
'links_via_ticket.url ~ {:search}',
|
||||
'tasks_via_ticket.name ~ {:search}',
|
||||
'comments_via_ticket.message ~ {:search}',
|
||||
'files_via_ticket.name ~ {:search}',
|
||||
'timeline_via_ticket.message ~ {:search}',
|
||||
'state.severity ~ {:search}'
|
||||
'owner_name ~ {:search}',
|
||||
'comment_messages ~ {:search}',
|
||||
'file_names ~ {:search}',
|
||||
'link_names ~ {:search}',
|
||||
'link_urls ~ {:search}',
|
||||
'task_names ~ {:search}',
|
||||
'timeline_messages ~ {:search}'
|
||||
]
|
||||
|
||||
Object.keys(props.selectedType.schema.properties).forEach((key) => {
|
||||
@@ -96,12 +93,10 @@ const {
|
||||
refetch
|
||||
} = useQuery({
|
||||
queryKey: ['tickets', filter.value],
|
||||
queryFn: (): Promise<ListResult<Ticket>> =>
|
||||
pb.collection('tickets').getList(page.value, perPage.value, {
|
||||
queryFn: (): Promise<ListResult<SearchTicket>> =>
|
||||
pb.collection('ticket_search').getList(page.value, perPage.value, {
|
||||
sort: '-created',
|
||||
filter: filter.value,
|
||||
expand:
|
||||
'type,owner,comments_via_ticket.author,files_via_ticket,timeline_via_ticket,links_via_ticket,tasks_via_ticket.owner'
|
||||
filter: filter.value
|
||||
})
|
||||
})
|
||||
|
||||
@@ -139,9 +134,9 @@ watch([tab, props.selectedType, page, perPage], () => refetch())
|
||||
<Tabs v-model="tab" class="flex flex-1 flex-col overflow-hidden">
|
||||
<div class="flex items-center justify-between px-4 pt-2">
|
||||
<TabsList>
|
||||
<TabsTrigger value="all"> All</TabsTrigger>
|
||||
<TabsTrigger value="open"> Open</TabsTrigger>
|
||||
<TabsTrigger value="closed"> Closed</TabsTrigger>
|
||||
<TabsTrigger value="all">All</TabsTrigger>
|
||||
<TabsTrigger value="open">Open</TabsTrigger>
|
||||
<TabsTrigger value="closed">Closed</TabsTrigger>
|
||||
</TabsList>
|
||||
<!-- Button variant="outline" size="sm" class="h-7 gap-1 rounded-md px-3">
|
||||
<ListFilter class="h-3.5 w-3.5" />
|
||||
@@ -155,23 +150,6 @@ watch([tab, props.selectedType, page, perPage], () => refetch())
|
||||
<span class="absolute inset-y-0 start-0 flex items-center justify-center px-2">
|
||||
<Search class="size-4 text-muted-foreground" />
|
||||
</span>
|
||||
|
||||
<div>
|
||||
<TooltipProvider :delay-duration="0">
|
||||
<Tooltip>
|
||||
<TooltipTrigger as-child>
|
||||
<Info class="ml-2 size-4 text-muted-foreground" />
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<p class="w-64">
|
||||
Search name, description, or owner. Links, tasks, comments, files, and
|
||||
timeline messages are also searched, but cause unreliable results if there are
|
||||
more than 1000 records.
|
||||
</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@@ -222,7 +200,6 @@ watch([tab, props.selectedType, page, perPage], () => refetch())
|
||||
</PaginationListItem>
|
||||
<PaginationEllipsis v-else :key="item.type" :index="index" />
|
||||
</template>
|
||||
|
||||
<PaginationNext />
|
||||
<PaginationLast />
|
||||
</PaginationList>
|
||||
|
||||
@@ -3,12 +3,12 @@ import ResourceListElement from '@/components/common/ResourceListElement.vue'
|
||||
|
||||
import { useRoute } from 'vue-router'
|
||||
|
||||
import type { Ticket } from '@/lib/types'
|
||||
import type { SearchTicket } from '@/lib/types'
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
defineProps<{
|
||||
tickets: Array<Ticket>
|
||||
tickets: Array<SearchTicket>
|
||||
}>()
|
||||
</script>
|
||||
|
||||
@@ -19,10 +19,10 @@ defineProps<{
|
||||
:key="item.id"
|
||||
:title="item.name"
|
||||
:created="item.created"
|
||||
:subtitle="item.expand.owner ? item.expand.owner.name : ''"
|
||||
:subtitle="item.owner_name"
|
||||
:description="item.description ? item.description.substring(0, 300) : ''"
|
||||
:active="route.params.id === item.id"
|
||||
:to="`/tickets/${item.expand.type.id}/${item.id}`"
|
||||
:to="`/tickets/${item.type}/${item.id}`"
|
||||
:open="item.open"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -32,6 +32,16 @@ export interface Ticket {
|
||||
}
|
||||
}
|
||||
|
||||
export interface SearchTicket {
|
||||
id: string
|
||||
name: string
|
||||
created: string
|
||||
description: string
|
||||
open: boolean
|
||||
type: string
|
||||
owner_name: string
|
||||
}
|
||||
|
||||
export interface Task {
|
||||
id: string
|
||||
|
||||
|
||||
Reference in New Issue
Block a user