mirror of
https://github.com/traefik/traefik.git
synced 2025-10-26 14:01:41 +01:00
283 lines
9.0 KiB
TypeScript
283 lines
9.0 KiB
TypeScript
import { Box, Flex, H1, Skeleton, styled, Text } from '@traefiklabs/faency'
|
|
import { useMemo } from 'react'
|
|
import { FiGlobe, FiInfo, FiShield } from 'react-icons/fi'
|
|
import { useParams } from 'react-router-dom'
|
|
|
|
import ProviderIcon from 'components/icons/providers'
|
|
import {
|
|
DetailSection,
|
|
DetailSectionSkeleton,
|
|
ItemBlock,
|
|
ItemTitle,
|
|
LayoutTwoCols,
|
|
ProviderName,
|
|
} from 'components/resources/DetailSections'
|
|
import { ResourceStatus } from 'components/resources/ResourceStatus'
|
|
import { UsedByRoutersSection, UsedByRoutersSkeleton } from 'components/resources/UsedByRoutersSection'
|
|
import Tooltip from 'components/Tooltip'
|
|
import { ResourceDetailDataType, ServiceDetailType, useResourceDetail } from 'hooks/use-resource-detail'
|
|
import Page from 'layout/Page'
|
|
import { NotFound } from 'pages/NotFound'
|
|
|
|
type TcpDetailProps = {
|
|
data: ServiceDetailType
|
|
}
|
|
|
|
const SpacedColumns = styled(Flex, {
|
|
display: 'grid',
|
|
gridTemplateColumns: 'repeat(auto-fill, minmax(360px, 1fr))',
|
|
gridGap: '16px',
|
|
})
|
|
|
|
const ServicesGrid = styled(Box, {
|
|
display: 'grid',
|
|
gridTemplateColumns: '2fr 1fr 1fr',
|
|
alignItems: 'center',
|
|
padding: '$3 $5',
|
|
borderBottom: '1px solid $tableRowBorder',
|
|
})
|
|
|
|
const ServersGrid = styled(Box, {
|
|
display: 'grid',
|
|
alignItems: 'center',
|
|
padding: '$3 $5',
|
|
borderBottom: '1px solid $tableRowBorder',
|
|
})
|
|
|
|
const GridTitle = styled(Text, {
|
|
fontSize: '14px',
|
|
fontWeight: 700,
|
|
color: 'hsl(0, 0%, 56%)',
|
|
})
|
|
|
|
type TcpServer = {
|
|
address: string
|
|
}
|
|
|
|
type ServerStatus = {
|
|
[server: string]: string
|
|
}
|
|
|
|
type TcpHealthCheck = {
|
|
port?: number
|
|
send?: string
|
|
expect?: string
|
|
interval?: string
|
|
unhealthyInterval?: string
|
|
timeout?: string
|
|
}
|
|
|
|
function getTcpServerStatusList(data: ServiceDetailType): ServerStatus {
|
|
const serversList: ServerStatus = {}
|
|
|
|
data.loadBalancer?.servers?.forEach((server: any) => {
|
|
// TCP servers should have address, but handle both url and address for compatibility
|
|
const serverKey = (server as TcpServer).address || (server as any).url
|
|
if (serverKey) {
|
|
serversList[serverKey] = 'DOWN'
|
|
}
|
|
})
|
|
|
|
if (data.serverStatus) {
|
|
Object.entries(data.serverStatus).forEach(([server, status]) => {
|
|
serversList[server] = status
|
|
})
|
|
}
|
|
|
|
return serversList
|
|
}
|
|
|
|
export const TcpServicePanels = ({ data }: TcpDetailProps) => {
|
|
const serversList = getTcpServerStatusList(data)
|
|
const getProviderFromName = (serviceName: string): string => {
|
|
const [, provider] = serviceName.split('@')
|
|
return provider || data.provider
|
|
}
|
|
const providerName = useMemo(() => {
|
|
return data.provider
|
|
}, [data.provider])
|
|
|
|
return (
|
|
<SpacedColumns css={{ mb: '$5', pb: '$5' }} data-testid="tcp-service-details">
|
|
<DetailSection narrow icon={<FiInfo size={20} />} title="Service Details">
|
|
<LayoutTwoCols>
|
|
{data.type && (
|
|
<ItemBlock title="Type">
|
|
<Text css={{ lineHeight: '32px' }}>{data.type}</Text>
|
|
</ItemBlock>
|
|
)}
|
|
{data.provider && (
|
|
<ItemBlock title="Provider">
|
|
<ProviderIcon name={data.provider} />
|
|
<ProviderName css={{ ml: '$2' }}>{providerName}</ProviderName>
|
|
</ItemBlock>
|
|
)}
|
|
</LayoutTwoCols>
|
|
{data.status && (
|
|
<ItemBlock title="Status">
|
|
<ResourceStatus status={data.status} withLabel />
|
|
</ItemBlock>
|
|
)}
|
|
{data.loadBalancer && (
|
|
<>
|
|
{data.loadBalancer.terminationDelay && (
|
|
<ItemBlock title="Termination Delay">
|
|
<Text>{`${data.loadBalancer.terminationDelay} ms`}</Text>
|
|
</ItemBlock>
|
|
)}
|
|
</>
|
|
)}
|
|
</DetailSection>
|
|
{data.loadBalancer?.healthCheck && (
|
|
<DetailSection narrow icon={<FiShield size={20} />} title="Health Check">
|
|
<Box data-testid="tcp-health-check">
|
|
{(() => {
|
|
const tcpHealthCheck = data.loadBalancer.healthCheck as unknown as TcpHealthCheck
|
|
return (
|
|
<>
|
|
<LayoutTwoCols>
|
|
{tcpHealthCheck.interval && (
|
|
<ItemBlock title="Interval">
|
|
<Text>{tcpHealthCheck.interval}</Text>
|
|
</ItemBlock>
|
|
)}
|
|
{tcpHealthCheck.timeout && (
|
|
<ItemBlock title="Timeout">
|
|
<Text>{tcpHealthCheck.timeout}</Text>
|
|
</ItemBlock>
|
|
)}
|
|
</LayoutTwoCols>
|
|
<LayoutTwoCols>
|
|
{tcpHealthCheck.port && (
|
|
<ItemBlock title="Port">
|
|
<Text>{tcpHealthCheck.port}</Text>
|
|
</ItemBlock>
|
|
)}
|
|
{tcpHealthCheck.unhealthyInterval && (
|
|
<ItemBlock title="Unhealthy Interval">
|
|
<Text>{tcpHealthCheck.unhealthyInterval}</Text>
|
|
</ItemBlock>
|
|
)}
|
|
</LayoutTwoCols>
|
|
<LayoutTwoCols>
|
|
{tcpHealthCheck.send && (
|
|
<ItemBlock title="Send">
|
|
<Tooltip label={tcpHealthCheck.send} action="copy">
|
|
<Text>{tcpHealthCheck.send}</Text>
|
|
</Tooltip>
|
|
</ItemBlock>
|
|
)}
|
|
{tcpHealthCheck.expect && (
|
|
<ItemBlock title="Expect">
|
|
<Tooltip label={tcpHealthCheck.expect} action="copy">
|
|
<Text>{tcpHealthCheck.expect}</Text>
|
|
</Tooltip>
|
|
</ItemBlock>
|
|
)}
|
|
</LayoutTwoCols>
|
|
</>
|
|
)
|
|
})()}
|
|
</Box>
|
|
</DetailSection>
|
|
)}
|
|
{!!data?.weighted?.services?.length && (
|
|
<DetailSection narrow icon={<FiGlobe size={20} />} title="Services" noPadding>
|
|
<>
|
|
<ServicesGrid css={{ mt: '$2' }}>
|
|
<GridTitle>Name</GridTitle>
|
|
<GridTitle css={{ textAlign: 'center' }}>Weight</GridTitle>
|
|
<GridTitle css={{ textAlign: 'center' }}>Provider</GridTitle>
|
|
</ServicesGrid>
|
|
<Box data-testid="tcp-weighted-services">
|
|
{data.weighted.services.map((service) => (
|
|
<ServicesGrid key={service.name}>
|
|
<Text>{service.name}</Text>
|
|
<Text css={{ textAlign: 'center' }}>{service.weight}</Text>
|
|
<Flex css={{ justifyContent: 'center' }}>
|
|
<ProviderIcon name={getProviderFromName(service.name)} />
|
|
</Flex>
|
|
</ServicesGrid>
|
|
))}
|
|
</Box>
|
|
</>
|
|
</DetailSection>
|
|
)}
|
|
{Object.keys(serversList).length > 0 && (
|
|
<DetailSection narrow icon={<FiGlobe size={20} />} title="Servers" noPadding>
|
|
<>
|
|
<ServersGrid css={{ gridTemplateColumns: '25% auto', mt: '$2' }}>
|
|
<ItemTitle css={{ mb: 0 }}>Status</ItemTitle>
|
|
<ItemTitle css={{ mb: 0 }}>Address</ItemTitle>
|
|
</ServersGrid>
|
|
<Box data-testid="tcp-servers-list">
|
|
{Object.entries(serversList).map(([server, status]) => (
|
|
<ServersGrid key={server} css={{ gridTemplateColumns: '25% auto' }}>
|
|
<ResourceStatus status={status === 'UP' ? 'enabled' : 'disabled'} />
|
|
<Box>
|
|
<Tooltip label={server} action="copy">
|
|
<Text>{server}</Text>
|
|
</Tooltip>
|
|
</Box>
|
|
</ServersGrid>
|
|
))}
|
|
</Box>
|
|
</>
|
|
</DetailSection>
|
|
)}
|
|
</SpacedColumns>
|
|
)
|
|
}
|
|
|
|
type TcpServiceRenderProps = {
|
|
data?: ResourceDetailDataType
|
|
error?: Error
|
|
name: string
|
|
}
|
|
|
|
export const TcpServiceRender = ({ data, error, name }: TcpServiceRenderProps) => {
|
|
if (error) {
|
|
return (
|
|
<Page title={name}>
|
|
<Text data-testid="error-text">
|
|
Sorry, we could not fetch detail information for this Service right now. Please, try again later.
|
|
</Text>
|
|
</Page>
|
|
)
|
|
}
|
|
|
|
if (!data) {
|
|
return (
|
|
<Page title={name}>
|
|
<Skeleton css={{ height: '$7', width: '320px', mb: '$8' }} data-testid="skeleton" />
|
|
<SpacedColumns>
|
|
<DetailSectionSkeleton narrow />
|
|
<DetailSectionSkeleton narrow />
|
|
<DetailSectionSkeleton narrow />
|
|
</SpacedColumns>
|
|
<UsedByRoutersSkeleton />
|
|
</Page>
|
|
)
|
|
}
|
|
|
|
if (!data.name) {
|
|
return <NotFound />
|
|
}
|
|
|
|
return (
|
|
<Page title={name}>
|
|
<H1 css={{ mb: '$7' }}>{data.name}</H1>
|
|
<TcpServicePanels data={data} />
|
|
<UsedByRoutersSection data={data} protocol="tcp" />
|
|
</Page>
|
|
)
|
|
}
|
|
|
|
export const TcpService = () => {
|
|
const { name } = useParams<{ name: string }>()
|
|
const { data, error } = useResourceDetail(name!, 'services', 'tcp')
|
|
return <TcpServiceRender data={data} error={error} name={name!} />
|
|
}
|
|
|
|
export default TcpService
|