Queues.utils.tsx135 lines · main
1import { Column } from 'react-data-grid'
2import { cn } from 'ui'
3import z from 'zod'
4
5import {
6 QueueCreatedAtCell,
7 QueueNameCell,
8 QueueRLSCell,
9 QueueSizeCell,
10 QueueTypeCell,
11 QueueWithMetrics,
12} from './QueueCells'
13import { PostgresQueue } from '@/data/database-queues/database-queues-query'
14
15export const formatQueueColumns = (): Column<QueueWithMetrics>[] => {
16 return [
17 {
18 key: 'queue_name',
19 name: 'Name',
20 resizable: true,
21 minWidth: 200,
22 headerCellClass: undefined,
23 renderHeaderCell: () => {
24 return (
25 <div className={cn('flex items-center justify-between font-normal text-xs w-full ml-8')}>
26 <p className="text-foreground!">Name</p>
27 </div>
28 )
29 },
30 renderCell: (props) => {
31 return <QueueNameCell queue={props.row} />
32 },
33 },
34 {
35 key: 'type',
36 name: 'Type',
37 resizable: true,
38 minWidth: 120,
39 headerCellClass: undefined,
40 renderHeaderCell: () => {
41 return (
42 <div className={cn('flex items-center justify-between font-normal text-xs w-full')}>
43 <p className="text-foreground!">Type</p>
44 </div>
45 )
46 },
47 renderCell: (props) => {
48 return <QueueTypeCell queue={props.row} />
49 },
50 },
51 {
52 key: 'rls_enabled',
53 name: 'RLS enabled',
54 resizable: true,
55 minWidth: 120,
56 headerCellClass: undefined,
57 renderHeaderCell: () => {
58 return (
59 <div className={cn('flex items-center justify-between font-normal text-xs w-full')}>
60 <p className="text-foreground!">RLS enabled</p>
61 </div>
62 )
63 },
64 renderCell: (props) => {
65 return <QueueRLSCell queue={props.row} />
66 },
67 },
68 {
69 key: 'created_at',
70 name: 'Created at',
71 resizable: true,
72 minWidth: 180,
73 headerCellClass: undefined,
74 renderHeaderCell: () => {
75 return (
76 <div className={cn('flex items-center justify-between font-normal text-xs w-full')}>
77 <p className="text-foreground!">Created at</p>
78 </div>
79 )
80 },
81 renderCell: (props) => {
82 return <QueueCreatedAtCell queue={props.row} />
83 },
84 },
85 {
86 key: 'queue_size',
87 name: 'Size',
88 resizable: true,
89 minWidth: 120,
90 headerCellClass: undefined,
91 renderHeaderCell: () => {
92 return (
93 <div className={cn('flex items-center justify-between font-normal text-xs w-full')}>
94 <p className="text-foreground!">Size</p>
95 </div>
96 )
97 },
98 renderCell: (props) => {
99 return <QueueSizeCell queue={props.row} />
100 },
101 },
102 ]
103}
104
105export const prepareQueuesForDataGrid = (queues: PostgresQueue[]): QueueWithMetrics[] => {
106 return queues.map((queue) => ({
107 ...queue,
108 id: queue.queue_name, // Use queue_name as unique id
109 }))
110}
111
112// pgmq stores queue names as-provided in pgmq.meta and lowercases them only when
113// building the underlying q_/a_ relations, so uppercase queue names are fine —
114// the user-facing name is preserved and table-name lookups go through
115// pgmqQueueTable / pgmqArchiveTable which lowercase to match pgmq's behavior.
116export const QueueNameSchema = z
117 .string()
118 .trim()
119 .min(1, 'Please provide a name for your queue')
120 .max(47, "The name can't be longer than 47 characters")
121 .regex(
122 /^[a-zA-Z0-9_-]+$/,
123 'Name must contain only alphanumeric characters, underscores, and hyphens'
124 )
125
126export const isQueueNameValid = (queueName: string) => {
127 return QueueNameSchema.safeParse(queueName).success
128}
129
130// pgmq.format_table_name() lowercases its input, so the actual relations in the
131// pgmq schema are always q_/a_ followed by the lowercased queue name — even when
132// pgmq.meta stores the original casing. Use these helpers anywhere a queue name
133// is mapped to a relname.
134export const pgmqQueueTable = (queueName: string) => `q_${queueName.toLowerCase()}`
135export const pgmqArchiveTable = (queueName: string) => `a_${queueName.toLowerCase()}`