refactor: move functions

This commit is contained in:
Maël Gangloff 2024-08-21 02:01:20 +02:00
parent 723ef3e883
commit a3c4a4e196
No known key found for this signature in database
GPG Key ID: 11FDC81C24A7F629
15 changed files with 208 additions and 183 deletions

View File

@ -1,4 +1,4 @@
import {ItemType, MenuItemType} from "antd/lib/menu/interface";
import {ItemType} from "antd/lib/menu/interface";
import {t} from "ttag";
import {
AimOutlined,
@ -22,8 +22,7 @@ import {useNavigate} from "react-router-dom";
export function Sider({isAuthenticated}: { isAuthenticated: boolean }) {
const navigate = useNavigate()
const menuItems: ItemType<MenuItemType>[] = [
const menuItems: ItemType[] = [
{
key: 'home',
label: t`Home`,
@ -64,7 +63,8 @@ export function Sider({isAuthenticated}: { isAuthenticated: boolean }) {
icon: <CloudServerOutlined/>,
label: t`Nameserver`,
title: t`Nameserver Finder`,
disabled: true
disabled: true,
onClick: () => navigate('/search/nameserver')
}
]
},
@ -103,7 +103,6 @@ export function Sider({isAuthenticated}: { isAuthenticated: boolean }) {
key: 'account',
icon: <UserOutlined/>,
label: t`My Account`,
disabled: !isAuthenticated,
onClick: () => navigate('/user')
}, {
key: 'logout',
@ -122,7 +121,6 @@ export function Sider({isAuthenticated}: { isAuthenticated: boolean }) {
}
return <Menu
defaultSelectedKeys={['home']}
defaultOpenKeys={['search', 'info', 'tracking', 'doc']}
mode="inline"
theme="dark"

View File

@ -19,9 +19,9 @@ export function DomainResult({domain}: { domain: Domain }) {
domain.tld.type === 'gTLD' ? "green"
: "cyan"
}>
<Card title={<>
<Card title={<Space>
{domain.ldhName}{domain.handle && <Typography.Text code>{domain.handle}</Typography.Text>}
</>}
</Space>}
size="small">
{domain.status.length > 0 &&
<>

View File

@ -10,7 +10,6 @@ export type FieldType = {
export function DomainSearchBar({onFinish}: { onFinish: (values: FieldType) => void }) {
return <Form
name="basic"
labelCol={{span: 8}}
wrapperCol={{span: 16}}
onFinish={onFinish}

View File

@ -1,49 +1,33 @@
import vCard from "vcf";
import {Avatar, List, Tag, Tooltip} from "antd";
import {BankOutlined, IdcardOutlined, SignatureOutlined, ToolOutlined, UserOutlined} from "@ant-design/icons";
import {List, Tag, Tooltip} from "antd";
import React from "react";
import {Domain} from "../../utils/api";
import {rdapRoleDetailTranslation, rdapRoleTranslation} from "./rdapTranslation";
import {rolesToColor} from "../tracking/watchlist/diagram/watchlistToEdges";
import {entityToName, rolesToColor, roleToAvatar, sortDomainEntities} from "../../utils";
export function EntitiesList({domain}: { domain: Domain }) {
const rdapRoleTranslated = rdapRoleTranslation()
const rdapRoleDetailTranslated = rdapRoleDetailTranslation()
const roleToTag = (r: string) => <Tooltip
title={r in rdapRoleDetailTranslated ? rdapRoleDetailTranslated[r as keyof typeof rdapRoleDetailTranslated] : undefined}>
<Tag
color={rolesToColor([r])}>{rdapRoleTranslated[r as keyof typeof rdapRoleTranslated]}</Tag>
</Tooltip>
return <List
className="demo-loadmore-list"
itemLayout="horizontal"
dataSource={domain.entities.sort((e1, e2) => {
const p = (r: string[]) => r.includes('registrant') ? 4 : r.includes('administrative') ? 3 : r.includes('billing') ? 2 : 1
return p(e2.roles) - p(e1.roles)
})}
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>
dataSource={sortDomainEntities(domain)}
renderItem={(e) =>
<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/>}/>}
avatar={roleToAvatar(e)}
title={e.entity.handle}
description={name}
description={entityToName(e)}
/>
{e.roles.map((r) =>
<Tooltip
title={r in rdapRoleDetailTranslated ? rdapRoleDetailTranslated[r as keyof typeof rdapRoleDetailTranslated] : undefined}>
<Tag
color={rolesToColor([r])}>{rdapRoleTranslated[r as keyof typeof rdapRoleTranslated]}</Tag>
</Tooltip>)}
{e.roles.map(roleToTag)}
</List.Item>
}}
}
/>
}

View File

@ -1,26 +1,9 @@
import {
ClockCircleOutlined,
DeleteOutlined,
ReloadOutlined,
ShareAltOutlined,
SignatureOutlined,
SyncOutlined
} from "@ant-design/icons";
import {Timeline, Tooltip} from "antd";
import {Timeline, Tooltip, Typography} from "antd";
import React from "react";
import {Domain, EventAction} from "../../utils/api";
import {Domain} from "../../utils/api";
import useBreakpoint from "../../hooks/useBreakpoint";
import {rdapEventDetailTranslation, rdapEventNameTranslation} from "./rdapTranslation";
export function actionToColor(a: EventAction) {
return a === 'registration' ? 'green' :
a === 'reregistration' ? 'cyan' :
a === 'expiration' ? 'red' :
a === 'deletion' ? 'magenta' :
a === 'transfer' ? 'orange' :
a === 'last changed' ? 'blue' : 'default'
}
import {actionToColor, actionToIcon} from "../../utils";
export function EventTimeline({domain}: { domain: Domain }) {
const sm = useBreakpoint('sm')
@ -30,29 +13,22 @@ export function EventTimeline({domain}: { domain: Domain }) {
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')
return <Timeline
mode={sm ? "left" : "right"}
items={domainEvents.map(({action, date}) => {
let dot
if (action === 'registration') {
dot = <SignatureOutlined style={{fontSize: '16px'}}/>
} else if (action === 'expiration') {
dot = <ClockCircleOutlined style={{fontSize: '16px'}}/>
} else if (action === 'transfer') {
dot = <ShareAltOutlined style={{fontSize: '16px'}}/>
} else if (action === 'last changed') {
dot = <SyncOutlined style={{fontSize: '16px'}}/>
} else if (action === 'deletion') {
dot = <DeleteOutlined style={{fontSize: '16px'}}/>
} else if (action === 'reregistration') {
dot = <ReloadOutlined style={{fontSize: '16px'}}/>
}
items={domainEvents.map(e => {
const sameEvents = domainEvents.filter(se => se.action === e.action)
const isRelevant = !(sameEvents.length > 1 && sameEvents.indexOf(e) !== 0)
const eventName = action in rdapEventNameTranslated ? 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 eventName = <Typography.Text style={{color: isRelevant ? 'default' : 'grey'}}>
{e.action in rdapEventNameTranslated ? rdapEventNameTranslated[e.action as keyof typeof rdapEventNameTranslated] : e.action}
</Typography.Text>
const dateStr = <Typography.Text
style={{color: isRelevant ? 'default' : 'grey'}}>{new Date(e.date).toLocaleString(locale)}
</Typography.Text>
const eventDetail = e.action in rdapEventDetailTranslated ? rdapEventDetailTranslated[e.action as keyof typeof rdapEventDetailTranslated] : undefined
const text = sm ? {
children: <Tooltip placement='bottom' title={eventDetail}>
@ -64,9 +40,9 @@ export function EventTimeline({domain}: { domain: Domain }) {
}
return {
color: (action === 'expiration' ? (expirationEvents.length > 0 && domainEvents[0].date === date) : true) ? actionToColor(action) : 'grey',
dot,
pending: new Date(date).getTime() > new Date().getTime(),
color: isRelevant ? actionToColor(e.action) : 'grey',
dot: actionToIcon(e.action),
pending: new Date(e.date).getTime() > new Date().getTime(),
...text
}
}

View File

@ -16,7 +16,7 @@ const formItemLayoutWithOutLabel = {
xs: {span: 24, offset: 0},
sm: {span: 20, offset: 4},
},
};
}
export function ConnectorForm({form, onCreate}: { form: FormInstance, onCreate: (values: Connector) => void }) {
const [provider, setProvider] = useState<string>()

View File

@ -5,13 +5,13 @@ import {ViewDiagramWatchlistButton} from "./diagram/ViewDiagramWatchlistButton";
import {UpdateWatchlistButton} from "./UpdateWatchlistButton";
import {DeleteWatchlistButton} from "./DeleteWatchlistButton";
import punycode from "punycode/punycode";
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 {rdapEventDetailTranslation, rdapEventNameTranslation} from "../../search/rdapTranslation";
import {actionToColor, actionToIcon} from "../../../utils";
export function WatchlistCard({watchlist, onUpdateWatchlist, connectors, onDelete}: {
watchlist: Watchlist,
@ -78,7 +78,7 @@ export function WatchlistCard({watchlist, onUpdateWatchlist, connectors, onDelet
events: watchlist.triggers?.filter(t => t.action === 'email')
.map(t => <Tooltip
title={t.event in rdapEventDetailTranslated ? rdapEventDetailTranslated[t.event as keyof typeof rdapEventDetailTranslated] : undefined}>
<Tag color={actionToColor(t.event)}>
<Tag color={actionToColor(t.event)} icon={actionToIcon(t.event)}>
{rdapEventNameTranslated[t.event as keyof typeof rdapEventNameTranslated]}
</Tag>
</Tooltip>

View File

@ -3,8 +3,8 @@ import {t} from "ttag";
import {ApiOutlined, MinusCircleOutlined, PlusOutlined} from "@ant-design/icons";
import React from "react";
import {Connector} from "../../../utils/api/connectors";
import {actionToColor} from "../../search/EventTimeline";
import {rdapEventDetailTranslation, rdapEventNameTranslation} from "../../search/rdapTranslation";
import {actionToColor, actionToIcon} from "../../../utils";
type TagRender = SelectProps['tagRender'];
@ -44,6 +44,7 @@ export function WatchlistForm({form, connectors, onFinish, isCreation}: {
return (<Tooltip
title={value in rdapEventDetailTranslated ? rdapEventDetailTranslated[value as keyof typeof rdapEventDetailTranslated] : undefined}>
<Tag
icon={actionToIcon(value)}
color={actionToColor(value)}
onMouseDown={onPreventMouseDown}
closable={closable}

View File

@ -1,13 +1,7 @@
import {Domain, Watchlist} from "../../../../utils/api";
import {rdapRoleTranslation} from "../../../search/rdapTranslation";
import {t} from "ttag";
export const rolesToColor = (roles: string[]) => roles.includes('registrant') ? 'green' :
roles.includes('administrative') ? 'blue' :
roles.includes('technical') ? 'orange' :
roles.includes('registrar') ? 'magenta' :
roles.includes('sponsor') ? 'purple' :
roles.includes('billing') ? 'cyan' : 'default'
import {rolesToColor} from "../../../../utils";
export function domainEntitiesToEdges(d: Domain, withRegistrar = false) {
const rdapRoleTranslated = rdapRoleTranslation()

View File

@ -1,7 +1,7 @@
import {Domain, Nameserver, Tld, Watchlist} from "../../../../utils/api";
import vCard from "vcf";
import React from "react";
import {t} from 'ttag'
import {entityToName} from "../../../../utils";
export const domainToNode = (d: Domain) => ({
id: d.ldhName,
@ -14,14 +14,10 @@ export const domainToNode = (d: Domain) => ({
export const domainEntitiesToNode = (d: Domain, withRegistrar = false) => d.entities
.filter(e => !withRegistrar ? !e.roles.includes('registrar') : true)
.map(e => {
const jCard = vCard.fromJSON(e.entity.jCard)
let label = e.entity.handle
if (jCard.data.fn !== undefined && !Array.isArray(jCard.data.fn)) label = jCard.data.fn.valueOf()
return {
id: e.entity.handle,
type: e.roles.includes('registrant') || e.roles.includes('registrar') ? 'input' : 'output',
data: {label},
data: {label: entityToName(e)},
style: {
width: 200
}

View File

@ -7,11 +7,6 @@ import {getConfiguration, InstanceConfig} from "../utils/api";
import {RegisterForm} from "../components/RegisterForm";
const gridStyle: React.CSSProperties = {
width: '50%',
textAlign: 'center',
}
export const AuthenticatedContext = createContext<any>(null)
export default function LoginPage() {
@ -28,7 +23,7 @@ export default function LoginPage() {
}, [])
return <Card title={wantRegister ? t`Register` : t`Log in`} style={{width: '100%'}}>
<Card.Grid style={gridStyle} hoverable={false}>
<Card.Grid style={{width: '50%', textAlign: 'center'}} hoverable={false}>
{wantRegister ? <RegisterForm/> : <LoginForm ssoLogin={configuration?.ssoLogin}/>}
{
configuration?.registerEnabled &&

View File

@ -54,11 +54,10 @@ export default function WatchlistPage() {
const [form] = Form.useForm()
const [messageApi, contextHolder] = message.useMessage()
const [watchlists, setWatchlists] = useState<Watchlist[] | null>()
const [connectors, setConnectors] = useState<(Connector & { id: string })[] | null>()
const [watchlists, setWatchlists] = useState<Watchlist[]>()
const [connectors, setConnectors] = useState<(Connector & { id: string })[]>()
const onCreateWatchlist = (values: FormValuesType) => {
postWatchlist(getRequestDataFromForm(values)).then((w) => {
form.resetFields()
refreshWatchlists()
@ -98,9 +97,10 @@ export default function WatchlistPage() {
return <Flex gap="middle" align="center" justify="center" vertical>
{contextHolder}
{
connectors &&
<Card title={t`Create a Watchlist`} style={{width: '100%'}}>
<WatchlistForm form={form} onFinish={onCreateWatchlist} connectors={connectors} isCreation={true}/>
<Card loading={connectors === undefined} title={t`Create a Watchlist`} style={{width: '100%'}}>
{connectors &&
<WatchlistForm form={form} onFinish={onCreateWatchlist} connectors={connectors} isCreation={true}/>
}
</Card>
}
<Divider/>

View File

@ -1,27 +0,0 @@
import {MessageInstance, MessageType} from "antd/lib/message/interface";
import {AxiosError, AxiosResponse} from "axios";
import {t} from "ttag";
export function showErrorAPI(e: AxiosError, messageApi: MessageInstance): MessageType | undefined {
const response = e.response as AxiosResponse
const data = response.data
if ('message' in data) {
return messageApi.error(data.message as string)
}
if (!('detail' in data)) return
const detail = data.detail as string
if (response.status === 429) {
const duration = response.headers['retry-after']
return messageApi.error(t`Please retry after ${duration} seconds`)
}
if (response.status.toString()[0] === '4') {
return messageApi.warning(detail !== '' ? detail : t`An error occurred`)
}
return messageApi.error(detail !== '' ? detail : t`An error occurred`)
}

109
assets/utils/index.tsx Normal file
View File

@ -0,0 +1,109 @@
import {MessageInstance, MessageType} from "antd/lib/message/interface";
import {AxiosError, AxiosResponse} from "axios";
import {t} from "ttag";
import {Avatar} from "antd";
import {
BankOutlined,
ClockCircleOutlined,
DeleteOutlined,
DollarOutlined,
IdcardOutlined,
LockOutlined,
ReloadOutlined,
ShareAltOutlined,
SignatureOutlined,
SyncOutlined,
ToolOutlined,
UnlockOutlined,
UserOutlined
} from "@ant-design/icons";
import {Domain, Entity, EventAction} from "./api";
import vCard from "vcf";
import React from "react";
export const roleToAvatar = (e: { roles: string[] }) => <Avatar style={{backgroundColor: rolesToColor(e.roles)}}
icon={e.roles.includes('registrant') ?
<SignatureOutlined/> : e.roles.includes('registrar') ?
<BankOutlined/> :
e.roles.includes('technical') ?
<ToolOutlined/> :
e.roles.includes('administrative') ?
<IdcardOutlined/> :
e.roles.includes('billing') ?
<DollarOutlined/> :
<UserOutlined/>}/>
export const rolesToColor = (roles: string[]) => roles.includes('registrant') ? 'green' :
roles.includes('administrative') ? 'blue' :
roles.includes('technical') ? 'orange' :
roles.includes('registrar') ? 'purple' :
roles.includes('sponsor') ? 'magenta' :
roles.includes('billing') ? 'cyan' : 'default'
export const actionToColor = (a: EventAction) => a === 'registration' ? 'green' :
a === 'reregistration' ? 'cyan' :
a === 'expiration' ? 'red' :
a === 'deletion' ? 'magenta' :
a === 'transfer' ? 'orange' :
a === 'last changed' ? 'blue' :
a === 'registrar expiration' ? 'red' :
a === 'reinstantiation' ? 'purple' :
a === 'enum validation expiration' ? 'red' : 'default'
export const actionToIcon = (a: EventAction) => a === 'registration' ?
<SignatureOutlined style={{fontSize: '16px'}}/> : a === 'expiration' ?
<ClockCircleOutlined style={{fontSize: '16px'}}/> : a === 'transfer' ?
<ShareAltOutlined style={{fontSize: '16px'}}/> : a === 'last changed' ?
<SyncOutlined style={{fontSize: '16px'}}/> : a === 'deletion' ?
<DeleteOutlined style={{fontSize: '16px'}}/> : a === 'reregistration' ?
<ReloadOutlined style={{fontSize: '16px'}}/> : a === 'locked' ?
<LockOutlined style={{fontSize: '16px'}}/> : a === 'unlocked' ?
<UnlockOutlined style={{fontSize: '16px'}}/> : a === 'registrar expiration' ?
<ClockCircleOutlined
style={{fontSize: '16px'}}/> : a === 'enum validation expiration' ?
<ClockCircleOutlined style={{fontSize: '16px'}}/> : a === 'reinstantiation' ?
<ReloadOutlined style={{fontSize: '16px'}}/> : undefined
export const entityToName = (e: { entity: Entity }): string => {
const jCard = vCard.fromJSON(e.entity.jCard)
let name = e.entity.handle
if (jCard.data.fn && !Array.isArray(jCard.data.fn) && jCard.data.fn.valueOf() !== '') name = jCard.data.fn.valueOf()
return name
}
export const sortDomainEntities = (domain: Domain) => domain.entities.sort((e1, e2) => {
const p = (r: string[]) => r.includes('registrant') ? 5 :
r.includes('administrative') ? 4 :
r.includes('billing') ? 3 :
r.includes('registrar') ? 2 : 1
return p(e2.roles) - p(e1.roles)
})
export function showErrorAPI(e: AxiosError, messageApi: MessageInstance): MessageType | undefined {
const response = e.response as AxiosResponse
const data = response.data
if ('message' in data) {
return messageApi.error(data.message as string)
}
if (!('detail' in data)) return
const detail = data.detail as string
if (response.status === 429) {
const duration = response.headers['retry-after']
return messageApi.error(t`Please retry after ${duration} seconds`)
}
if (response.status.toString()[0] === '4') {
return messageApi.warning(detail !== '' ? detail : t`An error occurred`)
}
return messageApi.error(detail !== '' ? detail : t`An error occurred`)
}

View File

@ -12,7 +12,7 @@ msgstr ""
#: assets/components/LoginForm.tsx:61
#: assets/components/RegisterForm.tsx:40
#: assets/components/RegisterForm.tsx:48
#: assets/components/search/DomainSearchBar.tsx:23
#: assets/components/search/DomainSearchBar.tsx:22
#: assets/components/tracking/connector/ConnectorForm.tsx:43
#: assets/components/tracking/connector/ConnectorForm.tsx:69
#: assets/components/tracking/connector/ConnectorForm.tsx:77
@ -22,8 +22,8 @@ msgstr ""
#: assets/components/tracking/connector/ConnectorForm.tsx:142
#: assets/components/tracking/connector/ConnectorForm.tsx:156
#: assets/components/tracking/connector/ConnectorForm.tsx:165
#: assets/components/tracking/watchlist/WatchlistForm.tsx:113
#: assets/components/tracking/watchlist/WatchlistForm.tsx:210
#: assets/components/tracking/watchlist/WatchlistForm.tsx:114
#: assets/components/tracking/watchlist/WatchlistForm.tsx:211
msgid "Required"
msgstr ""
@ -468,8 +468,8 @@ msgstr ""
msgid "Entities"
msgstr ""
#: assets/components/search/DomainSearchBar.tsx:26
#: assets/components/tracking/watchlist/WatchlistForm.tsx:116
#: assets/components/search/DomainSearchBar.tsx:25
#: assets/components/tracking/watchlist/WatchlistForm.tsx:117
msgid "This domain name does not appear to be valid"
msgstr ""
@ -544,12 +544,12 @@ msgid ""
msgstr ""
#: assets/components/tracking/connector/ConnectorForm.tsx:176
#: assets/components/tracking/watchlist/WatchlistForm.tsx:250
#: assets/components/tracking/watchlist/WatchlistForm.tsx:251
msgid "Create"
msgstr ""
#: assets/components/tracking/connector/ConnectorForm.tsx:179
#: assets/components/tracking/watchlist/WatchlistForm.tsx:253
#: assets/components/tracking/watchlist/WatchlistForm.tsx:254
msgid "Reset"
msgstr ""
@ -582,72 +582,72 @@ msgstr ""
msgid "No"
msgstr ""
#: assets/components/tracking/watchlist/WatchlistForm.tsx:70
#: assets/components/tracking/watchlist/WatchlistForm.tsx:71
msgid "Name"
msgstr ""
#: assets/components/tracking/watchlist/WatchlistForm.tsx:81
#: assets/components/tracking/watchlist/WatchlistForm.tsx:82
msgid "Watchlist Name"
msgstr ""
#: assets/components/tracking/watchlist/WatchlistForm.tsx:82
#: assets/components/tracking/watchlist/WatchlistForm.tsx:83
msgid "Naming the Watchlist makes it easier to find in the list below."
msgstr ""
#: assets/components/tracking/watchlist/WatchlistForm.tsx:93
#: assets/components/tracking/watchlist/WatchlistForm.tsx:94
msgid "At least one domain name"
msgstr ""
#: assets/components/tracking/watchlist/WatchlistCard.tsx:28
#: assets/components/tracking/watchlist/WatchlistForm.tsx:104
#: assets/components/tracking/watchlist/WatchlistForm.tsx:105
msgid "Domain names"
msgstr ""
#: assets/components/tracking/watchlist/WatchlistForm.tsx:122
#: assets/components/tracking/watchlist/WatchlistForm.tsx:123
msgid "Domain name"
msgstr ""
#: assets/components/tracking/watchlist/WatchlistForm.tsx:139
#: assets/components/tracking/watchlist/WatchlistForm.tsx:140
msgid "Add a Domain name"
msgstr ""
#: assets/components/tracking/watchlist/WatchlistCard.tsx:32
#: assets/components/tracking/watchlist/WatchlistForm.tsx:146
#: assets/components/tracking/watchlist/WatchlistForm.tsx:147
msgid "Tracked events"
msgstr ""
#: assets/components/tracking/watchlist/WatchlistForm.tsx:148
#: assets/components/tracking/watchlist/WatchlistForm.tsx:149
msgid "At least one trigger"
msgstr ""
#: assets/components/tracking/watchlist/WatchlistForm.tsx:171
#: assets/components/tracking/watchlist/WatchlistForm.tsx:185
#: assets/components/tracking/watchlist/WatchlistForm.tsx:172
#: assets/components/tracking/watchlist/WatchlistForm.tsx:186
msgid "Connector"
msgstr ""
#: assets/components/tracking/watchlist/WatchlistForm.tsx:181
#: assets/components/tracking/watchlist/WatchlistForm.tsx:182
msgid ""
"Please make sure the connector information is valid to purchase a domain "
"that may be available soon."
msgstr ""
#: assets/components/tracking/watchlist/WatchlistForm.tsx:201
#: assets/components/tracking/watchlist/WatchlistForm.tsx:202
msgid "DSN"
msgstr ""
#: assets/components/tracking/watchlist/WatchlistForm.tsx:213
#: assets/components/tracking/watchlist/WatchlistForm.tsx:214
msgid "This DSN does not appear to be valid"
msgstr ""
#: assets/components/tracking/watchlist/WatchlistForm.tsx:231
#: assets/components/tracking/watchlist/WatchlistForm.tsx:232
msgid "Check out this link to the Symfony documentation to help you build the DSN"
msgstr ""
#: assets/components/tracking/watchlist/WatchlistForm.tsx:240
#: assets/components/tracking/watchlist/WatchlistForm.tsx:241
msgid "Add a Webhook"
msgstr ""
#: assets/components/tracking/watchlist/WatchlistForm.tsx:250
#: assets/components/tracking/watchlist/WatchlistForm.tsx:251
msgid "Update"
msgstr ""
@ -671,11 +671,11 @@ msgstr ""
msgid "Watchlist Entity Diagram"
msgstr ""
#: assets/components/tracking/watchlist/diagram/watchlistToEdges.tsx:42
#: assets/components/tracking/watchlist/diagram/watchlistToEdges.tsx:36
msgid "Registry"
msgstr ""
#: assets/components/tracking/watchlist/diagram/watchlistToNodes.tsx:33
#: assets/components/tracking/watchlist/diagram/watchlistToNodes.tsx:29
#, javascript-format
msgid ".${ tld.tld } Registry"
msgstr ""
@ -705,44 +705,44 @@ msgstr ""
msgid "Watchlist"
msgstr ""
#: assets/components/Sider.tsx:29
#: assets/components/Sider.tsx:28
msgid "Home"
msgstr ""
#: assets/components/Sider.tsx:35
#: assets/components/Sider.tsx:34
msgid "Search"
msgstr ""
#: assets/components/Sider.tsx:41
#: assets/components/Sider.tsx:40
msgid "Domain"
msgstr ""
#: assets/components/Sider.tsx:42
#: assets/components/Sider.tsx:41
msgid "Domain Finder"
msgstr ""
#: assets/components/Sider.tsx:49
#: assets/components/Sider.tsx:48
#: assets/pages/info/TldPage.tsx:79
msgid "TLD"
msgstr ""
#: assets/components/Sider.tsx:50
#: assets/components/Sider.tsx:49
msgid "TLD list"
msgstr ""
#: assets/components/Sider.tsx:57
#: assets/components/Sider.tsx:56
msgid "Entity"
msgstr ""
#: assets/components/Sider.tsx:58
#: assets/components/Sider.tsx:57
msgid "Entity Finder"
msgstr ""
#: assets/components/Sider.tsx:65
#: assets/components/Sider.tsx:64
msgid "Nameserver"
msgstr ""
#: assets/components/Sider.tsx:66
#: assets/components/Sider.tsx:65
msgid "Nameserver Finder"
msgstr ""
@ -767,18 +767,18 @@ msgstr ""
msgid "My Account"
msgstr ""
#: assets/components/Sider.tsx:111
#: assets/components/Sider.tsx:110
msgid "Log out"
msgstr ""
#: assets/components/Sider.tsx:119
#: assets/pages/LoginPage.tsx:30
#: assets/pages/LoginPage.tsx:38
#: assets/components/Sider.tsx:118
#: assets/pages/LoginPage.tsx:25
#: assets/pages/LoginPage.tsx:33
msgid "Log in"
msgstr ""
#: assets/components/RegisterForm.tsx:55
#: assets/pages/LoginPage.tsx:30
#: assets/pages/LoginPage.tsx:25
msgid "Register"
msgstr ""
@ -881,15 +881,15 @@ msgstr ""
msgid "Create a Connector"
msgstr ""
#: assets/pages/tracking/WatchlistPage.tsx:65
#: assets/pages/tracking/WatchlistPage.tsx:64
msgid "Watchlist created !"
msgstr ""
#: assets/pages/tracking/WatchlistPage.tsx:77
#: assets/pages/tracking/WatchlistPage.tsx:76
msgid "Watchlist updated !"
msgstr ""
#: assets/pages/tracking/WatchlistPage.tsx:102
#: assets/pages/tracking/WatchlistPage.tsx:100
msgid "Create a Watchlist"
msgstr ""
@ -897,7 +897,7 @@ msgstr ""
msgid "Sorry, the page you visited does not exist."
msgstr ""
#: assets/pages/LoginPage.tsx:38
#: assets/pages/LoginPage.tsx:33
msgid "Create an account"
msgstr ""