QueuesRows.tsx115 lines · main
1import dayjs from 'dayjs'
2import { includes, sortBy } from 'lodash'
3import { Check, ChevronRight, Loader2, X } from 'lucide-react'
4import { useRouter } from 'next/router'
5
6import { pgmqQueueTable } from './Queues.utils'
7import Table from '@/components/to-be-cleaned/Table'
8import { useQueuesMetricsQuery } from '@/data/database-queues/database-queues-metrics-query'
9import { PostgresQueue } from '@/data/database-queues/database-queues-query'
10import { useTablesQuery } from '@/data/tables/tables-query'
11import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject'
12import { DATETIME_FORMAT } from '@/lib/constants'
13
14interface QueuesRowsProps {
15 queues: PostgresQueue[]
16 filterString: string
17}
18
19const QueueRow = ({ queue }: { queue: PostgresQueue }) => {
20 const router = useRouter()
21 const { data: selectedProject } = useSelectedProjectQuery()
22
23 const { data: queueTables } = useTablesQuery({
24 projectRef: selectedProject?.ref,
25 connectionString: selectedProject?.connectionString,
26 schema: 'pgmq',
27 })
28 const queueTable = queueTables?.find((x) => x.name === pgmqQueueTable(queue.queue_name))
29 const isRlsEnabled = !!queueTable?.rls_enabled
30
31 const { data: metrics, isPending: isLoading } = useQueuesMetricsQuery(
32 {
33 queueName: queue.queue_name,
34 projectRef: selectedProject?.ref,
35 connectionString: selectedProject?.connectionString,
36 },
37 {
38 staleTime: 30 * 1000, // 30 seconds, talk with Oli whether this is ok to call every minute
39 }
40 )
41
42 const type = queue.is_partitioned ? 'Partitioned' : queue.is_unlogged ? 'Unlogged' : 'Basic'
43
44 return (
45 <Table.tr
46 key={queue.queue_name}
47 onClick={() => {
48 router.push(
49 `/project/${selectedProject?.ref}/integrations/queues/queues/${queue.queue_name}`
50 )
51 }}
52 >
53 <Table.td className="truncate">
54 <p title={queue.queue_name}>{queue.queue_name}</p>
55 </Table.td>
56 <Table.td className="table-cell overflow-auto">
57 <p title={type.toLocaleLowerCase()} className="truncate">
58 {type}
59 </p>
60 </Table.td>
61 <Table.td className="table-cell">
62 <div className="flex justify-center">
63 {isRlsEnabled ? <Check size={14} className="text-brand" /> : <X size={14} />}
64 </div>
65 </Table.td>
66 <Table.td className="table-cell">
67 <p title={queue.created_at}>{dayjs(queue.created_at).format(DATETIME_FORMAT)}</p>
68 </Table.td>
69 <Table.td className="table-cell">
70 <div className="flex justify-center">
71 {isLoading ? (
72 <Loader2 className="animate-spin" size={16} />
73 ) : (
74 <p>
75 {metrics?.queue_length} {metrics?.method === 'estimated' ? '(Approximate)' : null}
76 </p>
77 )}
78 </div>
79 </Table.td>
80 <Table.td>
81 <div className="flex items-center justify-end">
82 <ChevronRight size="18" />
83 </div>
84 </Table.td>
85 </Table.tr>
86 )
87}
88
89export const QueuesRows = ({ queues: fetchedQueues, filterString }: QueuesRowsProps) => {
90 const filteredQueues = fetchedQueues.filter((x) =>
91 includes(x.queue_name.toLowerCase(), filterString.toLowerCase())
92 )
93 const queues = sortBy(filteredQueues, (func) => func.queue_name.toLocaleLowerCase())
94
95 if (queues.length === 0 && filterString.length > 0) {
96 return (
97 <Table.tr>
98 <Table.td colSpan={5}>
99 <p className="text-sm text-foreground">No results found</p>
100 <p className="text-sm text-foreground-light">
101 Your search for "{filterString}" did not return any results
102 </p>
103 </Table.td>
104 </Table.tr>
105 )
106 }
107
108 return (
109 <>
110 {queues.map((q) => (
111 <QueueRow key={q.queue_name} queue={q} />
112 ))}
113 </>
114 )
115}