mirror of
https://github.com/maelgangloff/domain-watchdog.git
synced 2025-12-29 16:15:04 +00:00
feat: add eslint linter
This commit is contained in:
@@ -1,15 +1,14 @@
|
||||
import React, {useEffect} from "react";
|
||||
import {Background, Controls, MiniMap, ReactFlow, useEdgesState, useNodesState} from "@xyflow/react";
|
||||
import {Flex} from "antd";
|
||||
import {Domain} from "../../utils/api";
|
||||
import {getLayoutedElements} from "../tracking/watchlist/diagram/getLayoutedElements";
|
||||
import {domainEntitiesToNode, domainToNode, nsToNode, tldToNode} from "../tracking/watchlist/diagram/watchlistToNodes";
|
||||
import {domainEntitiesToEdges, domainNSToEdges, tldToEdge} from "../tracking/watchlist/diagram/watchlistToEdges";
|
||||
import React, {useEffect} from 'react'
|
||||
import {Background, Controls, Edge, MiniMap, Node, ReactFlow, useEdgesState, useNodesState} from '@xyflow/react'
|
||||
import {Flex} from 'antd'
|
||||
import {Domain} from '../../utils/api'
|
||||
import {getLayoutedElements} from '../tracking/watchlist/diagram/getLayoutedElements'
|
||||
import {domainEntitiesToNode, domainToNode, nsToNode, tldToNode} from '../tracking/watchlist/diagram/watchlistToNodes'
|
||||
import {domainEntitiesToEdges, domainNSToEdges, tldToEdge} from '../tracking/watchlist/diagram/watchlistToEdges'
|
||||
|
||||
export function DomainDiagram({domain}: { domain: Domain }) {
|
||||
const [nodes, setNodes, onNodesChange] = useNodesState([])
|
||||
const [edges, setEdges, onEdgesChange] = useEdgesState([])
|
||||
|
||||
const [nodes, setNodes, onNodesChange] = useNodesState<Node>([])
|
||||
const [edges, setEdges, onEdgesChange] = useEdgesState<Edge>([])
|
||||
|
||||
useEffect(() => {
|
||||
const nodes = [
|
||||
@@ -33,21 +32,23 @@ export function DomainDiagram({domain}: { domain: Domain }) {
|
||||
setEdges(e.edges)
|
||||
}, [])
|
||||
|
||||
return <Flex style={{width: '100%', height: '100vh'}}>
|
||||
<ReactFlow
|
||||
fitView
|
||||
colorMode='system'
|
||||
nodesConnectable={false}
|
||||
edgesReconnectable={false}
|
||||
nodes={nodes}
|
||||
edges={edges}
|
||||
onNodesChange={onNodesChange}
|
||||
onEdgesChange={onEdgesChange}
|
||||
style={{width: '100%', height: '100%'}}
|
||||
>
|
||||
<MiniMap/>
|
||||
<Controls/>
|
||||
<Background/>
|
||||
</ReactFlow>
|
||||
</Flex>
|
||||
}
|
||||
return (
|
||||
<Flex style={{width: '100%', height: '100vh'}}>
|
||||
<ReactFlow
|
||||
fitView
|
||||
colorMode='system'
|
||||
nodesConnectable={false}
|
||||
edgesReconnectable={false}
|
||||
nodes={nodes}
|
||||
edges={edges}
|
||||
onNodesChange={onNodesChange}
|
||||
onEdgesChange={onEdgesChange}
|
||||
style={{width: '100%', height: '100%'}}
|
||||
>
|
||||
<MiniMap/>
|
||||
<Controls/>
|
||||
<Background/>
|
||||
</ReactFlow>
|
||||
</Flex>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,21 +1,19 @@
|
||||
import {StepProps, Steps, Tooltip} from "antd";
|
||||
import React from "react";
|
||||
import {t} from "ttag";
|
||||
import {StepProps, Steps, Tooltip} from 'antd'
|
||||
import React from 'react'
|
||||
import {t} from 'ttag'
|
||||
import {
|
||||
CheckOutlined,
|
||||
DeleteOutlined,
|
||||
ExclamationCircleOutlined,
|
||||
FieldTimeOutlined,
|
||||
SignatureOutlined
|
||||
} from "@ant-design/icons";
|
||||
import {rdapEventDetailTranslation, rdapStatusCodeDetailTranslation} from "../../utils/functions/rdapTranslation";
|
||||
} from '@ant-design/icons'
|
||||
import {rdapEventDetailTranslation, rdapStatusCodeDetailTranslation} from '../../utils/functions/rdapTranslation'
|
||||
|
||||
export function DomainLifecycleSteps({status}: { status: string[] }) {
|
||||
|
||||
const rdapEventDetailTranslated = rdapEventDetailTranslation()
|
||||
const rdapStatusCodeDetailTranslated = rdapStatusCodeDetailTranslation()
|
||||
|
||||
|
||||
const steps: StepProps[] = [
|
||||
{
|
||||
title: <Tooltip title={rdapEventDetailTranslated.registration}>{t`Registration`}</Tooltip>,
|
||||
@@ -26,16 +24,19 @@ export function DomainLifecycleSteps({status}: { status: string[] }) {
|
||||
icon: <CheckOutlined/>
|
||||
},
|
||||
{
|
||||
title: <Tooltip title={rdapStatusCodeDetailTranslated["auto renew period"]}>{t`Auto-Renew Grace Period`}</Tooltip>,
|
||||
title: <Tooltip
|
||||
title={rdapStatusCodeDetailTranslated['auto renew period']}>{t`Auto-Renew Grace Period`}</Tooltip>,
|
||||
icon: <FieldTimeOutlined style={{color: 'palevioletred'}}/>
|
||||
},
|
||||
{
|
||||
title: <Tooltip
|
||||
title={rdapStatusCodeDetailTranslated["redemption period"]}>{t`Redemption Grace Period`}</Tooltip>,
|
||||
title={rdapStatusCodeDetailTranslated['redemption period']}
|
||||
>{t`Redemption Grace Period`}
|
||||
</Tooltip>,
|
||||
icon: <ExclamationCircleOutlined style={{color: 'magenta'}}/>
|
||||
},
|
||||
{
|
||||
title: <Tooltip title={rdapStatusCodeDetailTranslated["pending delete"]}>{t`Pending Delete`}</Tooltip>,
|
||||
title: <Tooltip title={rdapStatusCodeDetailTranslated['pending delete']}>{t`Pending Delete`}</Tooltip>,
|
||||
icon: <DeleteOutlined style={{color: 'orangered'}}/>
|
||||
}
|
||||
]
|
||||
@@ -50,8 +51,10 @@ export function DomainLifecycleSteps({status}: { status: string[] }) {
|
||||
currentStep = 4
|
||||
}
|
||||
|
||||
return <Steps
|
||||
current={currentStep}
|
||||
items={steps}
|
||||
/>
|
||||
}
|
||||
return (
|
||||
<Steps
|
||||
current={currentStep}
|
||||
items={steps}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,107 +1,121 @@
|
||||
import {Badge, Card, Col, Divider, Flex, Row, Space, Tag, Tooltip, Typography} from "antd";
|
||||
import {t} from "ttag";
|
||||
import {EventTimeline} from "./EventTimeline";
|
||||
import {EntitiesList} from "./EntitiesList";
|
||||
import {DomainDiagram} from "./DomainDiagram";
|
||||
import React from "react";
|
||||
import {Domain} from "../../utils/api";
|
||||
import {rdapStatusCodeDetailTranslation} from "../../utils/functions/rdapTranslation";
|
||||
import {regionNames} from "../../i18n";
|
||||
import {Badge, Card, Col, Divider, Flex, Row, Space, Tag, Tooltip, Typography} from 'antd'
|
||||
import {t} from 'ttag'
|
||||
import {EventTimeline} from './EventTimeline'
|
||||
import {EntitiesList} from './EntitiesList'
|
||||
import {DomainDiagram} from './DomainDiagram'
|
||||
import React from 'react'
|
||||
import {Domain} from '../../utils/api'
|
||||
import {regionNames} from '../../i18n'
|
||||
|
||||
import {getCountryCode} from "../../utils/functions/getCountryCode";
|
||||
import {eppStatusCodeToColor} from "../../utils/functions/eppStatusCodeToColor";
|
||||
import {DomainLifecycleSteps} from "./DomainLifecycleSteps";
|
||||
import {getCountryCode} from '../../utils/functions/getCountryCode'
|
||||
import {DomainLifecycleSteps} from './DomainLifecycleSteps'
|
||||
import {BankOutlined, KeyOutlined, SafetyCertificateOutlined} from '@ant-design/icons'
|
||||
import {statusToTag} from '../tracking/StatusToTag'
|
||||
|
||||
export function DomainResult({domain}: { domain: Domain }) {
|
||||
|
||||
const rdapStatusCodeDetailTranslated = rdapStatusCodeDetailTranslation()
|
||||
const {tld, events} = domain
|
||||
const domainEvents = events.sort((e1, e2) => new Date(e2.date).getTime() - new Date(e1.date).getTime())
|
||||
const clientStatus = domain.status.filter(s => s.startsWith('client'))
|
||||
const serverStatus = domain.status.filter(s => !clientStatus.includes(s))
|
||||
|
||||
const isLocked = (type: 'client' | 'server'): boolean =>
|
||||
(domain.status.includes(type + ' update prohibited') && domain.status.includes(type + ' delete prohibited'))
|
||||
|| domain.status.includes(type + ' transfer prohibited')
|
||||
const isDomainLocked = (type: 'client' | 'server'): boolean =>
|
||||
(domain.status.includes(type + ' update prohibited') && domain.status.includes(type + ' delete prohibited')) ||
|
||||
domain.status.includes(type + ' transfer prohibited')
|
||||
|
||||
const statusToTag = (s: string) => <Tooltip
|
||||
placement='bottomLeft'
|
||||
title={rdapStatusCodeDetailTranslated[s as keyof typeof rdapStatusCodeDetailTranslated] || undefined}>
|
||||
<Tag color={eppStatusCodeToColor(s)}>{s}</Tag>
|
||||
</Tooltip>
|
||||
return (
|
||||
<Space direction='vertical' size='middle' style={{width: '100%'}}>
|
||||
|
||||
return <Space direction="vertical" size="middle" style={{width: '100%'}}>
|
||||
|
||||
<Badge.Ribbon text={
|
||||
<Tooltip
|
||||
title={tld.type === 'ccTLD' ? regionNames.of(getCountryCode(tld.tld)) : tld.type === 'gTLD' ? tld?.registryOperator : undefined}>
|
||||
{`${domain.tld.tld.toUpperCase()} (${tld.type})`}
|
||||
</Tooltip>
|
||||
}
|
||||
color={
|
||||
tld.type === 'ccTLD' ? 'purple' :
|
||||
(tld.type === 'gTLD' && tld.specification13) ? "volcano" :
|
||||
tld.type === 'gTLD' ? "green"
|
||||
: "cyan"
|
||||
}>
|
||||
|
||||
<Card title={<Space>
|
||||
{domain.ldhName}{domain.handle && <Typography.Text code>{domain.handle}</Typography.Text>}
|
||||
</Space>}
|
||||
size="small">
|
||||
{
|
||||
domain.events.length > 0 && <DomainLifecycleSteps status={domain.status}/>
|
||||
<Badge.Ribbon
|
||||
text={
|
||||
<Tooltip
|
||||
title={tld.type === 'ccTLD' ? regionNames.of(getCountryCode(tld.tld)) : tld.type === 'gTLD' ? tld?.registryOperator : undefined}
|
||||
>
|
||||
{`${domain.tld.tld.toUpperCase()} (${tld.type})`}
|
||||
</Tooltip>
|
||||
}
|
||||
<Row gutter={8}>
|
||||
<Col span={24} xl={12} xxl={12}>
|
||||
<Flex justify='center' align='center' style={{margin: 10}} wrap gap="4px 0">
|
||||
<Tooltip
|
||||
title={t`Registry-level protection, ensuring the highest level of security by preventing unauthorized, unwanted, or accidental changes to the domain name at the registry level`}>
|
||||
<Tag bordered={false} color={isLocked('server') ? 'green' : 'default'}
|
||||
icon={<SafetyCertificateOutlined
|
||||
style={{fontSize: '16px'}}/>}>{t`Registry Lock`}</Tag>
|
||||
</Tooltip>
|
||||
<Tooltip
|
||||
title={t`Registrar-level protection, safeguarding the domain from unauthorized, unwanted, or accidental changes through registrar controls`}>
|
||||
<Tag bordered={false} color={isLocked('client') ? 'green' : 'default'}
|
||||
icon={<BankOutlined
|
||||
style={{fontSize: '16px'}}/>}>{t`Registrar Lock`}</Tag>
|
||||
</Tooltip>
|
||||
<Tooltip
|
||||
title={t`DNSSEC secures DNS by adding cryptographic signatures to DNS records, ensuring authenticity and integrity of responses`}>
|
||||
<Tag bordered={false} color={domain.delegationSigned ? 'green' : 'default'}
|
||||
icon={<KeyOutlined style={{fontSize: '16px'}}/>}>{t`DNSSEC`}</Tag>
|
||||
</Tooltip>
|
||||
</Flex>
|
||||
{domain.status.length > 0 &&
|
||||
<>
|
||||
<Divider orientation="left">{t`EPP Status Codes`}</Divider>
|
||||
<Flex gap="4px 0" wrap>
|
||||
{serverStatus.map(statusToTag)}
|
||||
{clientStatus.map(statusToTag)}
|
||||
</Flex>
|
||||
</>
|
||||
}
|
||||
{
|
||||
domain.events.length > 0 && <>
|
||||
<Divider orientation="left">{t`Timeline`}</Divider>
|
||||
<EventTimeline events={domainEvents}/>
|
||||
</>
|
||||
}
|
||||
{
|
||||
domain.entities.length > 0 &&
|
||||
<>
|
||||
<Divider orientation="left">{t`Entities`}</Divider>
|
||||
<EntitiesList domain={domain}/>
|
||||
</>
|
||||
}
|
||||
</Col>
|
||||
<Col span={24} xl={12} xxl={12}>
|
||||
<DomainDiagram domain={domain}/>
|
||||
</Col>
|
||||
</Row>
|
||||
</Card>
|
||||
</Badge.Ribbon>
|
||||
</Space>
|
||||
}
|
||||
color={
|
||||
tld.type === 'ccTLD'
|
||||
? 'purple'
|
||||
: (tld.type === 'gTLD' && tld.specification13)
|
||||
? 'volcano'
|
||||
: tld.type === 'gTLD'
|
||||
? 'green'
|
||||
: 'cyan'
|
||||
}
|
||||
>
|
||||
|
||||
<Card
|
||||
title={<Space>
|
||||
{domain.ldhName}{domain.handle && <Typography.Text code>{domain.handle}</Typography.Text>}
|
||||
</Space>}
|
||||
size='small'
|
||||
>
|
||||
{
|
||||
domain.events.length > 0 && <DomainLifecycleSteps status={domain.status}/>
|
||||
}
|
||||
<Row gutter={8}>
|
||||
<Col span={24} xl={12} xxl={12}>
|
||||
<Flex justify='center' align='center' style={{margin: 10}} wrap gap='4px 0'>
|
||||
<Tooltip
|
||||
title={t`Registry-level protection, ensuring the highest level of security by preventing unauthorized, unwanted, or accidental changes to the domain name at the registry level`}
|
||||
>
|
||||
<Tag
|
||||
bordered={false} color={isDomainLocked('server') ? 'green' : 'default'}
|
||||
icon={<SafetyCertificateOutlined
|
||||
style={{fontSize: '16px'}}
|
||||
/>}
|
||||
>{t`Registry Lock`}
|
||||
</Tag>
|
||||
</Tooltip>
|
||||
<Tooltip
|
||||
title={t`Registrar-level protection, safeguarding the domain from unauthorized, unwanted, or accidental changes through registrar controls`}
|
||||
>
|
||||
<Tag
|
||||
bordered={false} color={isDomainLocked('client') ? 'green' : 'default'}
|
||||
icon={<BankOutlined
|
||||
style={{fontSize: '16px'}}
|
||||
/>}
|
||||
>{t`Registrar Lock`}
|
||||
</Tag>
|
||||
</Tooltip>
|
||||
<Tooltip
|
||||
title={t`DNSSEC secures DNS by adding cryptographic signatures to DNS records, ensuring authenticity and integrity of responses`}
|
||||
>
|
||||
<Tag
|
||||
bordered={false} color={domain.delegationSigned ? 'green' : 'default'}
|
||||
icon={<KeyOutlined style={{fontSize: '16px'}}/>}
|
||||
>{t`DNSSEC`}
|
||||
</Tag>
|
||||
</Tooltip>
|
||||
</Flex>
|
||||
{domain.status.length > 0 &&
|
||||
<>
|
||||
<Divider orientation='left'>{t`EPP Status Codes`}</Divider>
|
||||
<Flex gap='4px 0' wrap>
|
||||
{serverStatus.map(statusToTag)}
|
||||
{clientStatus.map(statusToTag)}
|
||||
</Flex>
|
||||
</>}
|
||||
{
|
||||
domain.events.length > 0 && <>
|
||||
<Divider orientation='left'>{t`Timeline`}</Divider>
|
||||
<EventTimeline events={domainEvents}/>
|
||||
</>
|
||||
}
|
||||
{
|
||||
domain.entities.length > 0 &&
|
||||
<>
|
||||
<Divider orientation='left'>{t`Entities`}</Divider>
|
||||
<EntitiesList domain={domain}/>
|
||||
</>
|
||||
}
|
||||
</Col>
|
||||
<Col span={24} xl={12} xxl={12}>
|
||||
<DomainDiagram domain={domain}/>
|
||||
</Col>
|
||||
</Row>
|
||||
</Card>
|
||||
</Badge.Ribbon>
|
||||
</Space>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,38 +1,44 @@
|
||||
import {Form, Input} from "antd";
|
||||
import {t} from "ttag";
|
||||
import {SearchOutlined} from "@ant-design/icons";
|
||||
import React from "react";
|
||||
import {Form, Input} from 'antd'
|
||||
import {t} from 'ttag'
|
||||
import {SearchOutlined} from '@ant-design/icons'
|
||||
import React from 'react'
|
||||
|
||||
export type FieldType = {
|
||||
export interface FieldType {
|
||||
ldhName: string
|
||||
}
|
||||
|
||||
export function DomainSearchBar({onFinish, initialValue}: { onFinish: (values: FieldType) => void, initialValue?: string }) {
|
||||
return <Form
|
||||
onFinish={onFinish}
|
||||
autoComplete="off"
|
||||
style={{width: '100%'}}
|
||||
>
|
||||
<Form.Item<FieldType>
|
||||
name="ldhName"
|
||||
initialValue={initialValue}
|
||||
rules={[{
|
||||
required: true,
|
||||
message: t`Required`
|
||||
}, {
|
||||
pattern: /^(?=.*\.)?\S*[^.\s]$/,
|
||||
message: t`This domain name does not appear to be valid`,
|
||||
max: 63,
|
||||
min: 2
|
||||
}]}
|
||||
export function DomainSearchBar({onFinish, initialValue}: {
|
||||
onFinish: (values: FieldType) => void,
|
||||
initialValue?: string
|
||||
}) {
|
||||
return (
|
||||
<Form
|
||||
onFinish={onFinish}
|
||||
autoComplete='off'
|
||||
style={{width: '100%'}}
|
||||
>
|
||||
<Input style={{textAlign: 'center'}}
|
||||
size="large"
|
||||
prefix={<SearchOutlined/>}
|
||||
placeholder="example.com"
|
||||
autoComplete='off'
|
||||
autoFocus
|
||||
/>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
}
|
||||
<Form.Item<FieldType>
|
||||
name='ldhName'
|
||||
initialValue={initialValue}
|
||||
rules={[{
|
||||
required: true,
|
||||
message: t`Required`
|
||||
}, {
|
||||
pattern: /^(?=.*\.)?\S*[^.\s]$/,
|
||||
message: t`This domain name does not appear to be valid`,
|
||||
max: 63,
|
||||
min: 2
|
||||
}]}
|
||||
>
|
||||
<Input
|
||||
style={{textAlign: 'center'}}
|
||||
size='large'
|
||||
prefix={<SearchOutlined/>}
|
||||
placeholder='example.com'
|
||||
autoComplete='off'
|
||||
autoFocus
|
||||
/>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,41 +1,45 @@
|
||||
import {List, Tag, Tooltip, Typography} from "antd";
|
||||
import React from "react";
|
||||
import {Domain} from "../../utils/api";
|
||||
import {rdapRoleDetailTranslation, rdapRoleTranslation} from "../../utils/functions/rdapTranslation";
|
||||
import {roleToAvatar} from "../../utils/functions/roleToAvatar";
|
||||
import {rolesToColor} from "../../utils/functions/rolesToColor";
|
||||
import {sortDomainEntities} from "../../utils/functions/sortDomainEntities";
|
||||
import {extractDetailsFromJCard} from "../../utils/functions/extractDetailsFromJCard";
|
||||
import {List, Tag, Tooltip, Typography} from 'antd'
|
||||
import React from 'react'
|
||||
import {Domain} from '../../utils/api'
|
||||
import {rdapRoleDetailTranslation, rdapRoleTranslation} from '../../utils/functions/rdapTranslation'
|
||||
import {roleToAvatar} from '../../utils/functions/roleToAvatar'
|
||||
import {rolesToColor} from '../../utils/functions/rolesToColor'
|
||||
import {sortDomainEntities} from '../../utils/functions/sortDomainEntities'
|
||||
import {extractDetailsFromJCard} from '../../utils/functions/extractDetailsFromJCard'
|
||||
|
||||
export function EntitiesList({domain}: { domain: Domain }) {
|
||||
const rdapRoleTranslated = rdapRoleTranslation()
|
||||
const rdapRoleDetailTranslated = rdapRoleDetailTranslation()
|
||||
|
||||
const roleToTag = (r: string) => <Tooltip
|
||||
title={rdapRoleDetailTranslated[r as keyof typeof rdapRoleDetailTranslated] || undefined}>
|
||||
<Tag color={rolesToColor([r])}>{rdapRoleTranslated[r as keyof typeof rdapRoleTranslated] || r
|
||||
}</Tag>
|
||||
title={rdapRoleDetailTranslated[r as keyof typeof rdapRoleDetailTranslated] || undefined}
|
||||
>
|
||||
<Tag color={rolesToColor([r])}>{rdapRoleTranslated[r as keyof typeof rdapRoleTranslated] || r}
|
||||
</Tag>
|
||||
</Tooltip>
|
||||
|
||||
return <List
|
||||
className="demo-loadmore-list"
|
||||
itemLayout="horizontal"
|
||||
dataSource={sortDomainEntities(domain)}
|
||||
renderItem={(e) => {
|
||||
const details = extractDetailsFromJCard(e)
|
||||
return (
|
||||
<List
|
||||
className='demo-loadmore-list'
|
||||
itemLayout='horizontal'
|
||||
dataSource={sortDomainEntities(domain)}
|
||||
renderItem={(e) => {
|
||||
const details = extractDetailsFromJCard(e)
|
||||
|
||||
return <List.Item>
|
||||
<List.Item.Meta
|
||||
avatar={roleToAvatar(e)}
|
||||
title={<Typography.Text code>{e.entity.handle}</Typography.Text>}
|
||||
description={<>
|
||||
{details.fn && <div>👤 {details.fn}</div>}
|
||||
{details.organization && <div>🏢 {details.organization}</div>}
|
||||
</>}
|
||||
/>
|
||||
{e.roles.map(roleToTag)}
|
||||
</List.Item>
|
||||
}
|
||||
}
|
||||
/>
|
||||
}
|
||||
return (
|
||||
<List.Item>
|
||||
<List.Item.Meta
|
||||
avatar={roleToAvatar(e)}
|
||||
title={<Typography.Text code>{e.entity.handle}</Typography.Text>}
|
||||
description={<>
|
||||
{details.fn && <div>👤 {details.fn}</div>}
|
||||
{details.organization && <div>🏢 {details.organization}</div>}
|
||||
</>}
|
||||
/>
|
||||
{e.roles.map(roleToTag)}
|
||||
</List.Item>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import {Timeline, Tooltip, Typography} from "antd";
|
||||
import React from "react";
|
||||
import {Event} from "../../utils/api";
|
||||
import useBreakpoint from "../../hooks/useBreakpoint";
|
||||
import {rdapEventDetailTranslation, rdapEventNameTranslation} from "../../utils/functions/rdapTranslation";
|
||||
import {actionToColor} from "../../utils/functions/actionToColor";
|
||||
import {actionToIcon} from "../../utils/functions/actionToIcon";
|
||||
import {Timeline, Tooltip, Typography} from 'antd'
|
||||
import React from 'react'
|
||||
import {Event} from '../../utils/api'
|
||||
import useBreakpoint from '../../hooks/useBreakpoint'
|
||||
import {rdapEventDetailTranslation, rdapEventNameTranslation} from '../../utils/functions/rdapTranslation'
|
||||
import {actionToColor} from '../../utils/functions/actionToColor'
|
||||
import {actionToIcon} from '../../utils/functions/actionToIcon'
|
||||
|
||||
export function EventTimeline({events}: { events: Event[] }) {
|
||||
const sm = useBreakpoint('sm')
|
||||
@@ -13,38 +13,46 @@ export function EventTimeline({events}: { events: Event[] }) {
|
||||
const rdapEventNameTranslated = rdapEventNameTranslation()
|
||||
const rdapEventDetailTranslated = rdapEventDetailTranslation()
|
||||
|
||||
return <>
|
||||
<Timeline
|
||||
mode={sm ? "left" : "right"}
|
||||
items={events.map(e => {
|
||||
const eventName = <Typography.Text style={{color: e.deleted ? 'grey' : 'default'}}>
|
||||
{rdapEventNameTranslated[e.action as keyof typeof rdapEventNameTranslated] || e.action}
|
||||
</Typography.Text>
|
||||
return (
|
||||
<>
|
||||
<Timeline
|
||||
mode={sm ? 'left' : 'right'}
|
||||
items={events.map(e => {
|
||||
const eventName = (
|
||||
<Typography.Text style={{color: e.deleted ? 'grey' : 'default'}}>
|
||||
{rdapEventNameTranslated[e.action as keyof typeof rdapEventNameTranslated] || e.action}
|
||||
</Typography.Text>
|
||||
)
|
||||
|
||||
const dateStr = <Typography.Text
|
||||
style={{color: e.deleted ? 'grey' : 'default'}}>{new Date(e.date).toLocaleString(locale)}
|
||||
</Typography.Text>
|
||||
const dateStr = (
|
||||
<Typography.Text
|
||||
style={{color: e.deleted ? 'grey' : 'default'}}
|
||||
>{new Date(e.date).toLocaleString(locale)}
|
||||
</Typography.Text>
|
||||
)
|
||||
|
||||
const eventDetail = rdapEventDetailTranslated[e.action as keyof typeof rdapEventDetailTranslated] || undefined
|
||||
const eventDetail = rdapEventDetailTranslated[e.action as keyof typeof rdapEventDetailTranslated] || undefined
|
||||
|
||||
const text = sm ? {
|
||||
children: <Tooltip placement='bottom' title={eventDetail}>
|
||||
{eventName} {dateStr}
|
||||
</Tooltip>
|
||||
} : {
|
||||
label: dateStr,
|
||||
children: <Tooltip placement='left' title={eventDetail}>{eventName}</Tooltip>,
|
||||
const text = sm
|
||||
? {
|
||||
children: <Tooltip placement='bottom' title={eventDetail}>
|
||||
{eventName} {dateStr}
|
||||
</Tooltip>
|
||||
}
|
||||
: {
|
||||
label: dateStr,
|
||||
children: <Tooltip placement='left' title={eventDetail}>{eventName}</Tooltip>
|
||||
}
|
||||
|
||||
return {
|
||||
color: e.deleted ? 'grey' : actionToColor(e.action),
|
||||
dot: actionToIcon(e.action),
|
||||
pending: new Date(e.date).getTime() > new Date().getTime(),
|
||||
...text
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
color: e.deleted ? 'grey' : actionToColor(e.action),
|
||||
dot: actionToIcon(e.action),
|
||||
pending: new Date(e.date).getTime() > new Date().getTime(),
|
||||
...text
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
/>
|
||||
</>
|
||||
}
|
||||
)}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user