| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252 |
- /*
- * Response Code
- *
- * for http response codes
- */
- import dayjs from 'dayjs'
- import { AlertCircle, Info } from 'lucide-react'
- import React from 'react'
- import { cn } from 'ui'
- import { isUnixMicro, unixMicroToIsoTimestamp } from './Logs.utils'
- import CopyButton from '@/components/ui/CopyButton'
- export const RowLayout: React.FC<React.PropsWithChildren> = ({ children }) => (
- <div className="flex h-full w-full items-center gap-4">{children}</div>
- )
- // renders a timestamp (either unix microsecond or iso timestamp)
- export const SelectionDetailedTimestampRow = ({ value }: { value: string | number }) => (
- <SelectionDetailedRow
- label="Timestamp"
- value={isUnixMicro(value) ? unixMicroToIsoTimestamp(value) : String(value)}
- />
- )
- export const SelectionDetailedRow = ({
- label,
- value,
- valueRender,
- }: {
- label: string
- value: string
- valueRender?: React.ReactNode
- }) => {
- return (
- <div className="group flex items-center gap-2 flex-wrap">
- <span className="text-foreground-lighter text-sm col-span-3 whitespace-pre-wrap">
- {label}
- </span>
- <span
- title={value}
- className="truncate font-mono text-foreground text-sm whitespace-pre-wrap break-all"
- >
- {valueRender ?? value}
- </span>
- <CopyButton
- iconOnly
- text={value}
- className="group-hover:opacity-100 opacity-0 p-0 h-6 w-6"
- type="text"
- title="Copy to clipboard"
- />
- </div>
- )
- }
- // used for column renderers
- export const TextFormatter: React.FC<{ className?: string; value: string }> = ({
- value,
- className,
- }) => (
- <span className={cn('font-mono text-xs truncate select-text cursor-text', className)}>
- {value}
- </span>
- )
- export const ResponseCodeFormatter = ({ value }: { value: string }) => {
- if (!value) {
- return (
- <div>
- <label className="text-xs text-border-stronger">No data</label>
- </div>
- )
- }
- const ResponseCodeItem = ({
- children,
- className,
- }: {
- children: React.ReactNode
- className?: string
- }) => (
- <div className="flex h-full items-center">
- <div
- className={cn(
- `relative flex h-6 items-center rounded-md justify-center px-2 py-1 text-center`,
- className
- )}
- >
- <label className="block font-mono text-sm">{children}</label>
- </div>
- </div>
- )
- const split = value.toString().split('')[0]
- switch (split) {
- // 2XX || 1XX responses
- case '1':
- return <ResponseCodeItem>{value}</ResponseCodeItem>
- case '2':
- return <ResponseCodeItem className="bg-surface-100 text-brand">{value}</ResponseCodeItem>
- // 5XX responses
- case '5':
- return <ResponseCodeItem className="bg-red-300 text-red-1100">{value}</ResponseCodeItem>
- // 4XX || 3XX responses
- case '4':
- case '3':
- return <ResponseCodeItem className="bg-warning/10 text-warning">{value}</ResponseCodeItem>
- // All other responses
- default:
- return (
- <ResponseCodeItem className="bg-surface-100 text-foreground-lighter">
- {value}
- </ResponseCodeItem>
- )
- }
- }
- /*
- * Response Code
- *
- * for http response codes
- */
- export const SeverityFormatter = ({
- value,
- uppercase = true,
- }: {
- value: string
- uppercase?: boolean
- }) => {
- if (!value) {
- return (
- <div>
- <label className="text-xs text-border-stronger">No data</label>
- </div>
- )
- }
- const uppercasedValue = value.toUpperCase()
- const text = uppercase ? uppercasedValue : value
- const Layout: React.FC<React.PropsWithChildren<{ className?: string }>> = ({
- className,
- children,
- }) => <div className={`w-24 flex items-center h-full ${className}`}>{children}</div>
- switch (uppercasedValue) {
- case 'UNCAUGHTEXCEPTION':
- case 'PANIC':
- case 'FATAL':
- case 'ERROR':
- return (
- <Layout className="gap-1">
- <div className=" p-0.5 rounded-sm text-red-900!">
- <AlertCircle size={14} strokeWidth={2} />
- </div>
- <span className="text-red-900! block! titlecase">{text}</span>
- </Layout>
- )
- break
- case 'INFO':
- case 'DEBUG':
- return (
- <Layout className="gap-1">
- <div className=" p-0.5 rounded-sm text-blue-900!">
- <AlertCircle size={14} strokeWidth={2} />
- </div>
- <span className="text-blue-900! block! titlecase">{text}</span>
- </Layout>
- )
- break
- case 'LOG':
- return (
- <Layout className="gap-1">
- <div className=" p-0.5 rounded-sm text-blue-900!">
- <Info size={14} strokeWidth={2} />
- </div>
- <span className="text-blue-900! block! titlecase">{text}</span>
- </Layout>
- )
- break
- case 'WARNING':
- return (
- <Layout className="gap-1">
- <div className=" p-0.5 rounded-sm text-amber-900!">
- <AlertCircle size={14} strokeWidth={2} />
- </div>
- <span className="text-amber-900! block! titlecase">{text}</span>
- </Layout>
- )
- break
- // All other responses
- default:
- return (
- <Layout>
- <div className="relative rounded-sm px-2 py-1 text-center h-6 flex justify-center items-center bg-surface-100">
- <label className="block font-mono text-sm text-foreground-lighter">{text}</label>
- </div>
- </Layout>
- )
- break
- }
- }
- export const timestampLocalFormatter = (value: string | number) => {
- const timestamp = isUnixMicro(value) ? unixMicroToIsoTimestamp(value) : value
- return dayjs(timestamp).format('DD MMM HH:mm:ss')
- }
- /*
- * JSON Syntax Highlighter
- *
- * for http response codes
- */
- export function jsonSyntaxHighlight(input: Object) {
- let json: string = JSON.stringify(input, null, 2)
- json = json.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>')
- const newJson = json.replace(
- /("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g,
- function (match) {
- var cls = 'number text-tomato-900'
- if (/^"/.test(match)) {
- if (/:$/.test(match)) {
- cls = 'key text-foreground'
- } else {
- cls = 'string text-brand-600'
- }
- } else if (/true|false/.test(match)) {
- cls = 'boolean text-blue-900'
- } else if (/null/.test(match)) {
- cls = 'null text-amber-1100'
- }
- return '<span class="' + cls + '">' + match + '</span>'
- }
- )
- const jsonWithLineWraps = newJson.split(`\n`).map((x) => {
- return `<span class="line text-xs">${x}</span>`
- })
- return jsonWithLineWraps.join('\n')
- }
|