feat: add entities on layout

This commit is contained in:
Maël Gangloff
2024-07-27 16:45:20 +02:00
parent 117a19fa47
commit 68392dd8ec
7 changed files with 144 additions and 90 deletions

View File

@@ -4,12 +4,13 @@ import {
Badge,
Card,
Divider,
Empty,
Flex,
Form,
FormProps,
Input,
List,
message,
Segmented,
Space,
Tag,
Timeline,
@@ -19,6 +20,7 @@ import {
BankOutlined,
ClockCircleOutlined,
DeleteOutlined,
IdcardOutlined,
SearchOutlined,
ShareAltOutlined,
SignatureOutlined,
@@ -28,7 +30,7 @@ import {
} from "@ant-design/icons";
import {Domain, getDomain} from "../../utils/api";
import {AxiosError} from "axios"
import vCard from 'vcf'
const {Title} = Typography
@@ -42,10 +44,13 @@ export default function DomainSearchPage() {
const [messageApi, contextHolder] = message.useMessage()
const onFinish: FormProps<FieldType>['onFinish'] = (values) => {
getDomain(values.ldhName).then(setDomain).catch((e: AxiosError) => {
getDomain(values.ldhName).then(d => {
setDomain(d)
messageApi.success('Found !')
}).catch((e: AxiosError) => {
const data = e?.response?.data as { detail: string }
messageApi.error(data.detail ?? 'An error occurred')
setDomain(null)
messageApi.error(data.detail ?? 'An error occurred')
})
}
@@ -78,87 +83,106 @@ export default function DomainSearchPage() {
{
domain &&
<Space direction="vertical" size="middle" style={{width: '100%'}}>
<Badge.Ribbon text={`.${domain.tld.tld.toUpperCase()} (${domain.tld.type})`}
color={
domain.tld.type === 'ccTLD' ? 'purple' :
(domain.tld.type === 'gTLD' && domain.tld.specification13) ? "volcano" :
domain.tld.type === 'gTLD' ? "green"
: "cyan"
}>
<Card title={`${domain.ldhName}${domain.handle ? ' (' + domain.handle + ')' : ''}`}
size="small">
{domain.status.length > 0 &&
<>
<Divider orientation="left">EPP Status Codes</Divider>
<Flex gap="4px 0" wrap>
{
domain.status.map(s =>
<Tag color={s === 'active' ? 'green' : 'blue'}>{s}</Tag>
)
}
</Flex>
</>
}
<Divider orientation="left">Timeline</Divider>
<Timeline
mode="right"
items={domain.events
.sort((e1, e2) => new Date(e2.date).getTime() - new Date(e1.date).getTime())
.map(({action, date}) => {
let color, dot
if (action === 'registration') {
color = 'green'
dot = <SignatureOutlined style={{fontSize: '16px'}}/>
} else if (action === 'expiration') {
color = 'red'
dot = <ClockCircleOutlined style={{fontSize: '16px'}}/>
} else if (action === 'transfer') {
color = 'orange'
dot = <ShareAltOutlined style={{fontSize: '16px'}}/>
} else if (action === 'last changed') {
color = 'blue'
dot = <SyncOutlined style={{fontSize: '16px'}}/>
} else if (action === 'deletion') {
color = 'red'
dot = <DeleteOutlined style={{fontSize: '16px'}}/>
(!domain.deleted ? <Space direction="vertical" size="middle" style={{width: '100%'}}>
<Badge.Ribbon text={`.${domain.tld.tld.toUpperCase()} (${domain.tld.type})`}
color={
domain.tld.type === 'ccTLD' ? 'purple' :
(domain.tld.type === 'gTLD' && domain.tld.specification13) ? "volcano" :
domain.tld.type === 'gTLD' ? "green"
: "cyan"
}>
<Card title={`${domain.ldhName}${domain.handle ? ' (' + domain.handle + ')' : ''}`}
size="small">
{domain.status.length > 0 &&
<>
<Divider orientation="left">EPP Status Codes</Divider>
<Flex gap="4px 0" wrap>
{
domain.status.map(s =>
<Tag color={s === 'active' ? 'green' : 'blue'}>{s}</Tag>
)
}
return {
label: new Date(date).toUTCString(),
children: action,
color,
dot,
pending: new Date(date).getTime() > new Date().getTime()
}
}
)
</Flex>
</>
}
/>
{
domain.entities.length > 0 && <>
<Divider orientation="left">Entities</Divider>
<Segmented
options={domain.entities.map(e => ({
label: (
<div style={{padding: 4}}>
<Avatar style={{backgroundColor: '#87d068'}}
icon={e.roles.includes('registrant') ?
<SignatureOutlined/> : e.roles.includes('registrar') ?
<BankOutlined/> :
e.roles.includes('technical') ? <ToolOutlined/> :
<UserOutlined/>}/>
<div>{e.entity.handle}</div>
</div>
),
value: e.entity.handle
}))}
/>
</>
}
</Card>
</Badge.Ribbon>
</Space>
<Divider orientation="left">Timeline</Divider>
<Timeline
mode="right"
items={domain.events
.sort((e1, e2) => new Date(e2.date).getTime() - new Date(e1.date).getTime())
.map(({action, date}) => {
let color, dot
if (action === 'registration') {
color = 'green'
dot = <SignatureOutlined style={{fontSize: '16px'}}/>
} else if (action === 'expiration') {
color = 'red'
dot = <ClockCircleOutlined style={{fontSize: '16px'}}/>
} else if (action === 'transfer') {
color = 'orange'
dot = <ShareAltOutlined style={{fontSize: '16px'}}/>
} else if (action === 'last changed') {
color = 'blue'
dot = <SyncOutlined style={{fontSize: '16px'}}/>
} else if (action === 'deletion') {
color = 'red'
dot = <DeleteOutlined style={{fontSize: '16px'}}/>
}
return {
label: new Date(date).toUTCString(),
children: action,
color,
dot,
pending: new Date(date).getTime() > new Date().getTime()
}
}
)
}
/>
{
domain.entities.length > 0 &&
<>
<Divider orientation="left">Entities</Divider>
<List
className="demo-loadmore-list"
itemLayout="horizontal"
dataSource={domain.entities}
renderItem={(e) => {
const jCard = vCard.fromJSON(e.entity.jCard)
let name = ''
if (jCard.data.fn !== undefined && !Array.isArray(jCard.data.fn)) name = jCard.data.fn.valueOf()
return <List.Item>
<List.Item.Meta
avatar={<Avatar style={{backgroundColor: '#87d068'}}
icon={e.roles.includes('registrant') ?
<SignatureOutlined/> : e.roles.includes('registrar') ?
<BankOutlined/> :
e.roles.includes('technical') ?
<ToolOutlined/> :
e.roles.includes('administrative') ?
<IdcardOutlined/> :
<UserOutlined/>}/>}
title={e.entity.handle}
description={name}
/>
<div>{e.roles.join(', ')}</div>
</List.Item>
}}
/>
</>
}
</Card>
</Badge.Ribbon>
</Space>
: <Empty
description={
<Typography.Text>
Although the domain exists in my database, it has been deleted from the WHOIS by its
registrar.
</Typography.Text>
}/>)
}
</Card>
</Flex>

View File

@@ -23,8 +23,7 @@ export interface Event {
export interface Entity {
handle: string
events: Event[]
roles: string[]
jCard: any
}
export interface Nameserver {
@@ -55,6 +54,7 @@ export interface Domain {
}[]
nameservers: Nameserver[]
tld: Tld
deleted: boolean
}
export interface User {