Skip to content

Commit

Permalink
feat: add domain status detail
Browse files Browse the repository at this point in the history
  • Loading branch information
maelgangloff committed Aug 20, 2024
1 parent 7290e7c commit 98104eb
Show file tree
Hide file tree
Showing 9 changed files with 524 additions and 125 deletions.
55 changes: 55 additions & 0 deletions assets/components/search/DomainResult.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import {Badge, Card, Divider, Flex, 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 "./rdapStatusCodeDetailTranslation";

export function DomainResult({domain}: { domain: Domain }) {

const rdapStatusCodeDetailTranslated = rdapStatusCodeDetailTranslation()

return <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 && <Typography.Text code>{domain.handle}</Typography.Text>}
</>}
size="small">
{domain.status.length > 0 &&
<>
<Divider orientation="left">{t`EPP Status Codes`}</Divider>
<Flex gap="4px 0" wrap>
{
domain.status.map(s =>
<Tooltip
placement='bottomLeft'
title={s in rdapStatusCodeDetailTranslated ? rdapStatusCodeDetailTranslated[s as keyof typeof rdapStatusCodeDetailTranslated] : undefined}>
<Tag color={s === 'active' ? 'green' : 'blue'}>{s}</Tag>
</Tooltip>
)
}
</Flex>
</>
}
<Divider orientation="left">{t`Timeline`}</Divider>
<EventTimeline domain={domain}/>
{
domain.entities.length > 0 &&
<>
<Divider orientation="left">{t`Entities`}</Divider>
<EntitiesList domain={domain}/>
</>
}
</Card>
</Badge.Ribbon>
<DomainDiagram domain={domain}/>
</Space>
}
2 changes: 1 addition & 1 deletion assets/components/search/EntitiesList.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import vCard from "vcf";
import {Avatar, List} from "antd";
import {Avatar, List, Tooltip} from "antd";
import {BankOutlined, IdcardOutlined, SignatureOutlined, ToolOutlined, UserOutlined} from "@ant-design/icons";
import React from "react";
import {Domain} from "../../utils/api";
Expand Down
29 changes: 10 additions & 19 deletions assets/components/search/EventTimeline.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ import {
SignatureOutlined,
SyncOutlined
} from "@ant-design/icons";
import {Timeline} from "antd";
import {Timeline, Tooltip} from "antd";
import React from "react";
import {Domain, EventAction} from "../../utils/api";
import {t} from "ttag";
import useBreakpoint from "../../hooks/useBreakpoint";
import {rdapEventDetailTranslation, rdapEventNameTranslation} from "./rdapEventActionDetailTranslation";

export function actionToColor(a: EventAction) {
return a === 'registration' ? 'green' :
Expand All @@ -21,25 +21,13 @@ export function actionToColor(a: EventAction) {
a === 'last changed' ? 'blue' : 'default'
}

export const domainEvent = () => ({
registration: t`Registration`,
reregistration: t`Reregistration`,
'last changed': t`Changed`,
expiration: t`Expiration`,
deletion: t`Deletion`,
reinstantiation: t`Reinstantiation`,
transfer: t`Transfer`,
locked: t`Locked`,
unlocked: t`Unlocked`,
'registrar expiration': t`Registrar expiration`,
'enum validation expiration': t`ENUM validation expiration`
})

export function EventTimeline({domain}: { domain: Domain }) {
const sm = useBreakpoint('sm')

const locale = navigator.language.split('-')[0]
const domainEventTranslated = domainEvent()
const rdapEventNameTranslated = rdapEventNameTranslation()
const rdapEventDetailTranslated = rdapEventDetailTranslation()

const domainEvents = domain.events.sort((e1, e2) => new Date(e2.date).getTime() - new Date(e1.date).getTime())
const expirationEvents = domainEvents.filter(e => e.action === 'expiration')
Expand All @@ -62,14 +50,17 @@ export function EventTimeline({domain}: { domain: Domain }) {
dot = <ReloadOutlined style={{fontSize: '16px'}}/>
}

const eventName = Object.keys(domainEventTranslated).includes(action) ? domainEventTranslated[action as keyof typeof domainEventTranslated] : action
const eventName = Object.keys(rdapEventNameTranslated).includes(action) ? rdapEventNameTranslated[action as keyof typeof rdapEventNameTranslated] : action
const dateStr = new Date(date).toLocaleString(locale)
const eventDetail = action in rdapEventDetailTranslated ? rdapEventDetailTranslated[action as keyof typeof rdapEventDetailTranslated] : undefined

const text = sm ? {
children: <>{eventName}&emsp;{dateStr}</>
children: <Tooltip placement='bottom' title={eventDetail}>
{eventName}&emsp;{dateStr}
</Tooltip>
} : {
label: dateStr,
children: eventName,
children: <Tooltip placement='left' title={eventDetail}>{eventName}</Tooltip>,
}

return {
Expand Down
35 changes: 35 additions & 0 deletions assets/components/search/rdapEventActionDetailTranslation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import {t} from "ttag";

/**
* @see https://www.iana.org/assignments/rdap-json-values/rdap-json-values.xhtml
*/
export const rdapEventNameTranslation = () => ({
registration: t`Registration`,
reregistration: t`Reregistration`,
'last changed': t`Changed`,
expiration: t`Expiration`,
deletion: t`Deletion`,
reinstantiation: t`Reinstantiation`,
transfer: t`Transfer`,
locked: t`Locked`,
unlocked: t`Unlocked`,
'registrar expiration': t`Registrar expiration`,
'enum validation expiration': t`ENUM validation expiration`
})

/**
* @see https://www.iana.org/assignments/rdap-json-values/rdap-json-values.xhtml
*/
export const rdapEventDetailTranslation = () => ({
registration: t`The object instance was initially registered.`,
reregistration: t`The object instance was registered subsequently to initial registration.`,
'last changed': t`An action noting when the information in the object instance was last changed.`,
expiration: t`The object instance has been removed or will be removed at a predetermined date and time from the registry.`,
deletion: t`The object instance was removed from the registry at a point in time that was not predetermined.`,
reinstantiation: t`The object instance was reregistered after having been removed from the registry.`,
transfer: t`The object instance was transferred from one registrar to another.`,
locked: t`The object instance was locked.`,
unlocked: t`The object instance was unlocked.`,
'registrar expiration': t`An action noting the expiration date of the object in the registrar system.`,
'enum validation expiration': t`Association of phone number represented by this ENUM domain to registrant has expired or will expire at a predetermined date and time.`
})
43 changes: 43 additions & 0 deletions assets/components/search/rdapStatusCodeDetailTranslation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import {t} from "ttag";

/**
* @see https://www.iana.org/assignments/rdap-json-values/rdap-json-values.xhtml
*/
export const rdapStatusCodeDetailTranslation = () => ({
validated: t`Signifies that the data of the object instance has been found to be accurate. This type of status is usually found on entity object instances to note the validity of identifying contact information.`,
'renew prohibited': t`Renewal or reregistration of the object instance is forbidden.`,
'update prohibited': t`Updates to the object instance are forbidden.`,
'transfer prohibited': t`Transfers of the registration from one registrar to another are forbidden. This type of status normally applies to DNR domain names.`,
'delete prohibited': t`Deletion of the registration of the object instance is forbidden. This type of status normally applies to DNR domain names.`,
'proxy': t`The registration of the object instance has been performed by a third party. This is most commonly applied to entities.`,
'private': t`The information of the object instance is not designated for public consumption. This is most commonly applied to entities.`,
'removed': t`Some of the information of the object instance has not been made available and has been removed. This is most commonly applied to entities.`,
'obscured': t`Some of the information of the object instance has been altered for the purposes of not readily revealing the actual information of the object instance. This is most commonly applied to entities.`,
'associated': t`The object instance is associated with other object instances in the registry. This is most commonly used to signify that a nameserver is associated with a domain or that an entity is associated with a network resource or domain.`,
'active': t`The object instance is in use. For domain names, it signifies that the domain name is published in DNS. For network and autnum registrations, it signifies that they are allocated or assigned for use in operational networks. This maps to the "OK" status of the Extensible Provisioning Protocol (EPP) [RFC5730].`,
'inactive': t`The object instance is not in use.`,
'locked': t`Changes to the object instance cannot be made, including the association of other object instances.`,
'pending create': t`A request has been received for the creation of the object instance, but this action is not yet complete.`,
'pending renew': t`A request has been received for the renewal of the object instance, but this action is not yet complete.`,
'pending transfer': t`A request has been received for the transfer of the object instance, but this action is not yet complete.`,
'pending update': t`A request has been received for the update or modification of the object instance, but this action is not yet complete.`,
'pending delete': t`A request has been received for the deletion or removal of the object instance, but this action is not yet complete. For domains, this might mean that the name is no longer published in DNS but has not yet been purged from the registry database.`,
'add period': t`This grace period is provided after the initial registration of the object. If the object is deleted by the client during this period, the server provides a credit to the client for the cost of the registration. This maps to the Domain Registry Grace Period Mapping for the Extensible Provisioning Protocol (EPP) [RFC3915] 'addPeriod' status.`,
'auto renew period': t`This grace period is provided after an object registration period expires and is extended (renewed) automatically by the server. If the object is deleted by the client during this period, the server provides a credit to the client for the cost of the auto renewal. This maps to the Domain Registry Grace Period Mapping for the Extensible Provisioning Protocol (EPP) [RFC3915] 'autoRenewPeriod' status.`,
'client delete prohibited': t`The client requested that requests to delete the object MUST be rejected. This maps to the Extensible Provisioning Protocol (EPP) Domain Name Mapping [RFC5731], Extensible Provisioning Protocol (EPP) Host Mapping [RFC5732], and Extensible Provisioning Protocol (EPP) Contact Mapping [RFC5733] 'clientDeleteProhibited' status.`,
'client hold': t`The client requested that the DNS delegation information MUST NOT be published for the object. This maps to the Extensible Provisioning Protocol (EPP) Domain Name Mapping [RFC5731] 'clientHold' status.`,
'client renew prohibited': t`The client requested that requests to renew the object MUST be rejected. This maps to the Extensible Provisioning Protocol (EPP) Domain Name Mapping [RFC5731] 'clientRenewProhibited' status.`,
'client transfer prohibited': t`The client requested that requests to transfer the object MUST be rejected. This maps to the Extensible Provisioning Protocol (EPP) Domain Name Mapping [RFC5731] and Extensible Provisioning Protocol (EPP) Contact Mapping [RFC5733] 'clientTransferProhibited' status.`,
'client update prohibited': t`The client requested that requests to update the object (other than to remove this status) MUST be rejected. This maps to the Extensible Provisioning Protocol (EPP) Domain Name Mapping [RFC5731], Extensible Provisioning Protocol (EPP) Host Mapping [RFC5732], and Extensible Provisioning Protocol (EPP) Contact Mapping [RFC5733] 'clientUpdateProhibited' status.`,
'pending restore': t`An object is in the process of being restored after being in the redemption period state. This maps to the Domain Registry Grace Period Mapping for the Extensible Provisioning Protocol (EPP) [RFC3915] 'pendingRestore' status.`,
'redemption period': t`A delete has been received, but the object has not yet been purged because an opportunity exists to restore the object and abort the deletion process. This maps to the Domain Registry Grace Period Mapping for the Extensible Provisioning Protocol (EPP) [RFC3915] 'redemptionPeriod' status.`,
'renew period': t`This grace period is provided after an object registration period is explicitly extended (renewed) by the client. If the object is deleted by the client during this period, the server provides a credit to the client for the cost of the renewal. This maps to the Domain Registry Grace Period Mapping for the Extensible Provisioning Protocol (EPP) [RFC3915] 'renewPeriod' status.`,
'server delete prohibited': t`The server set the status so that requests to delete the object MUST be rejected. This maps to the Extensible Provisioning Protocol (EPP) Domain Name Mapping [RFC5731], Extensible Provisioning Protocol (EPP) Host Mapping [RFC5732], and Extensible Provisioning Protocol (EPP) Contact Mapping [RFC5733] 'serverDeleteProhibited' status.`,
'server renew prohibited': t`The server set the status so that requests to renew the object MUST be rejected. This maps to the Extensible Provisioning Protocol (EPP) Domain Name Mapping [RFC5731] 'serverRenewProhibited' status.`,
'server transfer prohibited': t`The server set the status so that requests to transfer the object MUST be rejected. This maps to the Extensible Provisioning Protocol (EPP) Domain Name Mapping [RFC5731] and Extensible Provisioning Protocol (EPP) Contact Mapping [RFC5733] 'serverTransferProhibited' status.`,
'server update prohibited': t`The server set the status so that requests to update the object (other than to remove this status) MUST be rejected. This maps to the Extensible Provisioning Protocol (EPP) Domain Name Mapping [RFC5731], Extensible Provisioning Protocol (EPP) Host Mapping [RFC5732], and Extensible Provisioning Protocol (EPP) Contact Mapping [RFC5733] 'serverUpdateProhibited' status.`,
'server hold': t`The server set the status so that DNS delegation information MUST NOT be published for the object. This maps to the Extensible Provisioning Protocol (EPP) Domain Name Mapping [RFC5731] 'serverHold' status.`,
'transfer period': t`This grace period is provided after the successful transfer of object registration sponsorship from one client to another client. If the object is deleted by the client during this period, the server provides a credit to the client for the cost of the transfer. This maps to the Domain Registry Grace Period Mapping for the Extensible Provisioning Protocol (EPP) [RFC3915] 'transferPeriod' status.`,
'administrative': t`The object instance has been allocated administratively (i.e., not for use by the recipient in their own right in operational networks).`,
'reserved': t`The object instance has been allocated to an IANA special-purpose address registry.`,
})
11 changes: 6 additions & 5 deletions assets/components/tracking/watchlist/WatchlistCard.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
import {Card, Divider, Flex, Space, Table, Tag, Typography} from "antd";
import {Card, Divider, Space, Table, Tag, Typography} from "antd";
import {DisconnectOutlined, LinkOutlined} from "@ant-design/icons";
import {t} from "ttag";
import {ViewDiagramWatchlistButton} from "./diagram/ViewDiagramWatchlistButton";
import {UpdateWatchlistButton} from "./UpdateWatchlistButton";
import {DeleteWatchlistButton} from "./DeleteWatchlistButton";
import punycode from "punycode/punycode";
import {actionToColor, domainEvent} from "../../search/EventTimeline";
import React, {useState} from "react";
import {actionToColor} from "../../search/EventTimeline";
import React from "react";
import {Watchlist} from "../../../pages/tracking/WatchlistPage";
import {Connector} from "../../../utils/api/connectors";
import useBreakpoint from "../../../hooks/useBreakpoint";
import {CalendarWatchlistButton} from "./CalendarWatchlistButton";
import {rdapEventNameTranslation} from "../../search/rdapEventActionDetailTranslation";

export function WatchlistCard({watchlist, onUpdateWatchlist, connectors, onDelete}: {
watchlist: Watchlist,
Expand All @@ -19,7 +20,7 @@ export function WatchlistCard({watchlist, onUpdateWatchlist, connectors, onDelet
onDelete: () => void
}) {
const sm = useBreakpoint('sm')
const domainEventTranslated = domainEvent()
const rdapEventNameTranslated = rdapEventNameTranslation()

const columns = [
{
Expand Down Expand Up @@ -75,7 +76,7 @@ export function WatchlistCard({watchlist, onUpdateWatchlist, connectors, onDelet
domains: watchlist.domains.map(d => <Tag>{punycode.toUnicode(d.ldhName)}</Tag>),
events: watchlist.triggers?.filter(t => t.action === 'email')
.map(t => <Tag color={actionToColor(t.event)}>
{domainEventTranslated[t.event as keyof typeof domainEventTranslated]}
{rdapEventNameTranslated[t.event as keyof typeof rdapEventNameTranslated]}
</Tag>
)
}]}
Expand Down
Loading

0 comments on commit 98104eb

Please sign in to comment.