feat: add eslint linter

This commit is contained in:
Maël Gangloff
2024-12-30 23:50:15 +01:00
parent ebfcc58d16
commit 99d135cc31
64 changed files with 3579 additions and 1846 deletions

View File

@@ -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>
)
}

View File

@@ -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}
/>
)
}

View File

@@ -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>
)
}

View File

@@ -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>
)
}

View File

@@ -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>
)
}}
/>
)
}

View File

@@ -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}&emsp;{dateStr}
</Tooltip>
} : {
label: dateStr,
children: <Tooltip placement='left' title={eventDetail}>{eventName}</Tooltip>,
const text = sm
? {
children: <Tooltip placement='bottom' title={eventDetail}>
{eventName}&emsp;{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
}
}
)
}
/>
</>
}
)}
/>
</>
)
}