Files
Gildas Garcia cabe14e5ca chore: remove _Shadcn_ suffix from ui tabs components (#47628)
## Problem

Now that we migrated all usages of the deprecated `Tabs` component, we
don't need the `_Shadcn_` suffix anymore.

## Solution

Remove `_Shadcn_` suffix from `ui` tabs components. That's all this PR
does, no visual nor functional changes

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* Standardized tab components across the app so pages and dialogs now
use the same consistent tab UI.
* Improved tab-based views in design, docs, studio, learn, and website
experiences for a more uniform interface.

* **Chores**
* Updated shared UI exports to expose tab components directly,
simplifying future usage across the product.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-06 15:29:16 +02:00

220 lines
7.7 KiB
TypeScript

import { useEscapeKeydown } from '@radix-ui/react-use-escape-keydown'
import { useParams } from 'common'
import dayjs from 'dayjs'
import { isNil } from 'lodash'
import { Archive, Clock12, Trash2, X } from 'lucide-react'
import { useState } from 'react'
import { Button, ResizablePanel, Separator, Tabs, TabsContent, TabsList, TabsTrigger } from 'ui'
import { RowAction, RowData } from '@/components/interfaces/Auth/Users/UserOverview'
import { CodeEditor } from '@/components/ui/CodeEditor/CodeEditor'
import { useDatabaseQueueMessageArchiveMutation } from '@/data/database-queues/database-queue-messages-archive-mutation'
import { useDatabaseQueueMessageDeleteMutation } from '@/data/database-queues/database-queue-messages-delete-mutation'
import { PostgresQueueMessage } from '@/data/database-queues/database-queue-messages-infinite-query'
import { useDatabaseQueueMessageReadMutation } from '@/data/database-queues/database-queue-messages-read-mutation'
import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject'
import { prettifyJSON } from '@/lib/helpers'
export const DATE_FORMAT = 'DD MMM, YYYY HH:mm'
interface MessageDetailsPanelProps {
selectedMessage: PostgresQueueMessage
setSelectedMessage: (value: number | null) => void
}
const tryFormatInitialValue = (value: string) => {
try {
const jsonValue = JSON.parse(value)
return JSON.stringify(jsonValue)
} catch (err) {
if (typeof value === 'string') {
return value.replaceAll(`\"`, `"`)
} else {
return JSON.stringify(value)
}
}
}
export const MessageDetailsPanel = ({
selectedMessage,
setSelectedMessage,
}: MessageDetailsPanelProps) => {
const { id: _id, childId: queueName } = useParams()
const { data: project } = useSelectedProjectQuery()
useEscapeKeydown(() => setSelectedMessage(null))
const {
mutate: archiveMessage,
isPending: isLoadingArchive,
isSuccess: isSuccessArchive,
} = useDatabaseQueueMessageArchiveMutation()
const {
mutate: readMessage,
isPending: isLoadingRead,
isSuccess: isSuccessRead,
} = useDatabaseQueueMessageReadMutation()
const {
mutate: deleteMessage,
isPending: isLoadingDelete,
isSuccess: isSuccessDelete,
} = useDatabaseQueueMessageDeleteMutation()
const initialValue = JSON.stringify(selectedMessage?.message)
const jsonString = prettifyJSON(!isNil(initialValue) ? tryFormatInitialValue(initialValue) : '')
const [view, setView] = useState<'details' | 'suggestion'>('details')
return (
<ResizablePanel
defaultSize="30"
maxSize="45"
minSize="30"
collapsible
onResize={(panelSize) => {
if (panelSize.asPercentage === 0) {
setSelectedMessage(null)
}
}}
className="bg-studio border-t pointer-events-auto"
>
<Button
variant="text"
className="absolute top-3 right-3 px-1"
icon={<X />}
onClick={() => setSelectedMessage(null)}
/>
<Tabs
value={view}
className="flex flex-col h-full"
onValueChange={(value: any) => {
setView(value)
}}
>
<TabsList className="px-5 flex gap-x-4 min-h-[46px]">
<TabsTrigger
value="details"
className="px-0 pb-0 h-full text-xs data-[state=active]:bg-transparent shadow-none!"
>
Overview
</TabsTrigger>
</TabsList>
<TabsContent value="details" className="w-full mt-0 overflow-y-auto grow">
<div className="flex flex-col px-4 py-4 text-sm">
<RowData property="Message ID" value={`${selectedMessage.msg_id}`} />
<RowData
property="Added at"
value={dayjs(selectedMessage.enqueued_at).format(DATE_FORMAT)}
/>
<RowData
property="Available at"
value={dayjs(selectedMessage.vt).format(DATE_FORMAT)}
/>
<RowData property="Retries" value={`${selectedMessage.read_ct}`} />
<div className="mt-2">
<h4 className="text-foreground-light py-1">Payload</h4>
<CodeEditor
isReadOnly
hideLineNumbers
id={selectedMessage.msg_id.toString()}
value={jsonString || 'NULL'}
language="json"
className="h-[200px]"
/>
</div>
</div>
<Separator />
<div className="flex flex-col px-4 py-4 -space-y-1">
{!selectedMessage.archived_at ? (
<>
<RowAction
title="Postpone message"
description="The message will be postponed and won't show up in reads for 60 seconds."
button={{
icon: <Clock12 />,
text: 'Postpone',
isLoading: isLoadingRead,
onClick: () => {
readMessage({
projectRef: project!.ref,
connectionString: project?.connectionString,
queueName: queueName!,
messageId: selectedMessage.msg_id,
duration: 60,
})
},
}}
success={
isSuccessRead
? {
title: 'Postponed',
description: 'The message was postponed for 60 seconds.',
}
: undefined
}
/>
<RowAction
title="Archive message"
description="The message will be marked as archived and hidden from future reads by consumers. You can still access the message later."
button={{
icon: <Archive />,
text: 'Archive',
isLoading: isLoadingArchive,
variant: 'warning',
onClick: () => {
archiveMessage({
projectRef: project!.ref,
connectionString: project?.connectionString,
queueName: queueName!,
messageId: selectedMessage.msg_id,
})
},
}}
success={
isSuccessArchive
? {
title: 'Archived',
description: 'The message was archived successfully.',
}
: undefined
}
/>
<RowAction
title="Delete message"
description="The message cannot be recovered afterwards."
button={{
icon: <Trash2 />,
text: 'Delete',
variant: 'danger',
isLoading: isLoadingDelete,
onClick: () => {
deleteMessage({
projectRef: project!.ref,
connectionString: project?.connectionString,
queueName: queueName!,
messageId: selectedMessage.msg_id,
})
},
}}
success={
isSuccessDelete
? {
title: 'Deleted',
description: 'The message was deleted successfully.',
}
: undefined
}
/>
</>
) : null}
</div>
</TabsContent>
</Tabs>
</ResizablePanel>
)
}