Merge branch 'bugfix/responsive' into develop

This commit is contained in:
Maël Gangloff
2025-11-01 17:55:13 +01:00
11 changed files with 194 additions and 127 deletions

View File

@@ -1,4 +1,4 @@
import {Button, ConfigProvider, FloatButton, Layout, Space, theme, Tooltip, Typography} from 'antd'
import {Button, ConfigProvider, Drawer, Flex, FloatButton, Layout, theme, Tooltip, Typography} from 'antd'
import {Link, Navigate, Route, Routes, useLocation, useNavigate} from 'react-router-dom'
import TextPage from './pages/TextPage'
import DomainSearchPage from './pages/search/DomainSearchPage'
@@ -7,7 +7,8 @@ import TldPage from './pages/infrastructure/TldPage'
import StatisticsPage from './pages/StatisticsPage'
import WatchlistPage from './pages/tracking/WatchlistPage'
import UserPage from './pages/UserPage'
import React, {useCallback, useEffect, useMemo, useState} from 'react'
import type {PropsWithChildren} from 'react'
import React, { useCallback, useEffect, useMemo, useState} from 'react'
import {getUser} from './utils/api'
import LoginPage, {AuthenticatedContext} from './pages/LoginPage'
import ConnectorPage from './pages/tracking/ConnectorPage'
@@ -15,21 +16,56 @@ import NotFoundPage from './pages/NotFoundPage'
import useBreakpoint from './hooks/useBreakpoint'
import {Sider} from './components/Sider'
import {jt, t} from 'ttag'
import {BugOutlined, InfoCircleOutlined, MergeOutlined} from '@ant-design/icons'
import {BugOutlined, InfoCircleOutlined, MergeOutlined, MenuOutlined} from '@ant-design/icons'
import TrackedDomainPage from './pages/tracking/TrackedDomainPage'
import IcannRegistrarPage from "./pages/infrastructure/IcannRegistrarPage"
const PROJECT_LINK = 'https://github.com/maelgangloff/domain-watchdog'
const LICENSE_LINK = 'https://www.gnu.org/licenses/agpl-3.0.txt'
const ProjectLink = <Typography.Link target='_blank' href={PROJECT_LINK}>Domain Watchdog</Typography.Link>
const LicenseLink = <Typography.Link target='_blank' href={LICENSE_LINK}>AGPL-3.0-or-later</Typography.Link>
const ProjectLink = <Typography.Link key="projectLink" target='_blank' href={PROJECT_LINK}>Domain Watchdog</Typography.Link>
const LicenseLink = <Typography.Link key="licenceLink" target='_blank' href={LICENSE_LINK}>AGPL-3.0-or-later</Typography.Link>
function SiderWrapper(props: PropsWithChildren<{sidebarCollapsed: boolean, setSidebarCollapsed: (collapsed: boolean) => void}>): React.ReactElement {
const {sidebarCollapsed, setSidebarCollapsed, children} = props
const sm = useBreakpoint('sm')
const location = useLocation()
useEffect(() => {
if (sm) {
setSidebarCollapsed(false)
}
}, [location])
if (sm) {
return <Drawer
placement="left"
open={sidebarCollapsed}
onClose={() => setSidebarCollapsed(false)}
closeIcon={null}
styles={{body: {padding: 0, height: '100%', background: '#001529'}}}
width='200px'>
{children}
</Drawer>
} else {
return <Layout.Sider
collapsible
breakpoint='sm'
width={220}
trigger={null}
collapsed={sidebarCollapsed && sm}
{...(sm ? {collapsedWidth: 0} : {})}>
{children}
</Layout.Sider>
}
}
export default function App(): React.ReactElement {
const navigate = useNavigate()
const location = useLocation()
const sm = useBreakpoint('sm')
const [sidebarCollapsed, setSidebarCollapsed] = useState(false)
const [isAuthenticated, setIsAuthenticated] = useState(false)
const authenticated = useCallback((authenticated: boolean) => {
@@ -75,15 +111,20 @@ export default function App(): React.ReactElement {
>
<AuthenticatedContext.Provider value={contextValue}>
<Layout hasSider style={{minHeight: '100vh'}}>
{/* Ant will use a break-off tab to toggle the collapse of the sider when collapseWidth = 0 */}
<Layout.Sider collapsible breakpoint='sm' width={220} {...(sm ? {collapsedWidth: 0} : {})}>
<SiderWrapper sidebarCollapsed={sidebarCollapsed} setSidebarCollapsed={setSidebarCollapsed}>
<Sider isAuthenticated={isAuthenticated}/>
</Layout.Sider>
</SiderWrapper>
<Layout>
<Layout.Header style={{padding: 0}}/>
<Layout.Header style={{padding: 0}}>
{sm &&
<Button type="text" style={{marginLeft: 8}} onClick={() => setSidebarCollapsed(!sidebarCollapsed)}>
<MenuOutlined />
</Button>
}
</Layout.Header>
<Layout.Content style={sm ? {margin: '24px 0'} : {margin: '24px 16px 0'}}>
<div style={{
padding: 24,
padding: sm ? 8 : 24,
minHeight: 360
}}
>
@@ -116,7 +157,7 @@ export default function App(): React.ReactElement {
</div>
</Layout.Content>
<Layout.Footer style={{textAlign: 'center'}}>
<Space size='middle' wrap align='center'>
<Flex gap='middle' wrap justify='center'>
<Link to='/tos'><Button type='text'>{t`TOS`}</Button></Link>
<Link to='/privacy'><Button type='text'>{t`Privacy Policy`}</Button></Link>
<Link to='/faq'><Button type='text'>{t`FAQ`}</Button></Link>
@@ -129,7 +170,7 @@ export default function App(): React.ReactElement {
>{t`Documentation`}
</Button>
</Typography.Link>
</Space>
</Flex>
<Typography.Paragraph style={{marginTop: '1em'}}>
{jt`${ProjectLink} is an open source project distributed under the ${LicenseLink} license.`}
</Typography.Paragraph>

View File

@@ -1,6 +1,6 @@
import {Button, Form, Input, message, Space} from 'antd'
import {Button, Flex, Form, Input, message} from 'antd'
import {t} from 'ttag'
import React, {useContext, useEffect} from 'react'
import React, {useContext, useEffect, useState} from 'react'
import {getUser, login} from '../utils/api'
import {AuthenticatedContext} from '../pages/LoginPage'
import {useNavigate} from 'react-router-dom'
@@ -16,6 +16,7 @@ export function LoginForm({ssoLogin}: { ssoLogin?: boolean }) {
const navigate = useNavigate()
const [messageApi, contextHolder] = message.useMessage()
const {setIsAuthenticated} = useContext(AuthenticatedContext)
const [loading, setLoading] = useState(false)
useEffect(() => {
getUser().then(() => {
@@ -25,12 +26,15 @@ export function LoginForm({ssoLogin}: { ssoLogin?: boolean }) {
}, [])
const onFinish = (data: FieldType) => {
setLoading(true)
login(data.username, data.password).then(() => {
setIsAuthenticated(true)
navigate('/home')
}).catch((e) => {
setIsAuthenticated(false)
showErrorAPI(e, messageApi)
setLoading(false)
})
}
return (
@@ -43,6 +47,7 @@ export function LoginForm({ssoLogin}: { ssoLogin?: boolean }) {
style={{maxWidth: 600}}
onFinish={onFinish}
autoComplete='off'
disabled={loading}
>
<Form.Item
label={t`Email address`}
@@ -60,18 +65,15 @@ export function LoginForm({ssoLogin}: { ssoLogin?: boolean }) {
<Input.Password/>
</Form.Item>
<Space>
<Form.Item wrapperCol={{offset: 8, span: 16}}>
<Flex wrap justify="center" gap="middle">
<Button type='primary' htmlType='submit'>
{t`Submit`}
</Button>
</Form.Item>
{ssoLogin && <Form.Item wrapperCol={{offset: 8, span: 16}}>
{ssoLogin &&
<Button type='dashed' htmlType='button' href='/login/oauth'>
{t`Log in with SSO`}
</Button>
</Form.Item>}
</Space>
</Button>}
</Flex>
</Form>
</>
)

View File

@@ -22,16 +22,16 @@ export function ConnectorsList({connectors, onDelete}: { connectors: ConnectorEl
<>
<Divider/>
{connectors.map(connector => {
const createdAt = <Typography.Text strong>
const createdAt = <Typography.Text strong key={"createdAt"}>
{new Date(connector.createdAt).toLocaleString()}
</Typography.Text>
const {watchlistCount} = connector
const connectorName = Object.keys(ConnectorProvider).find(p => ConnectorProvider[p as keyof typeof ConnectorProvider] === connector.provider)
return <>
{contextHolder}
<Card
hoverable title={<Space>
return <Card
hoverable
key={connector.id}
title={<Space>
{t`Connector ${connectorName}`}<Typography.Text code>{connector.id}</Typography.Text>
</Space>}
size='small'
@@ -45,6 +45,7 @@ export function ConnectorsList({connectors, onDelete}: { connectors: ConnectorEl
><DeleteFilled style={{color: token.colorError}}/>
</Popconfirm>}
>
{contextHolder}
<Typography.Paragraph>{jt`Creation date: ${createdAt}`}</Typography.Paragraph>
<Typography.Paragraph>{t`Used in: ${watchlistCount} Watchlist`}</Typography.Paragraph>
<Card.Meta description={
@@ -58,7 +59,6 @@ The creation date corresponds to the date on which you consented to the creation
</>
}/>
</Card>
</>
}
)}
</>

View File

@@ -22,11 +22,13 @@ import {
} from '@ant-design/icons'
import {DomainToTag} from '../../../utils/functions/DomainToTag'
import {isDomainLocked} from "../../../utils/functions/isDomainLocked"
import useBreakpoint from "../../../hooks/useBreakpoint"
export function TrackedDomainTable() {
const REDEMPTION_NOTICE = (
<Tooltip
title={t`At least one domain name is in redemption period and will potentially be deleted soon`}
key="redeptionNotice"
>
<Tag color={eppStatusCodeToColor('redemption period')}>redemption period</Tag>
</Tooltip>
@@ -35,6 +37,7 @@ export function TrackedDomainTable() {
const PENDING_DELETE_NOTICE = (
<Tooltip
title={t`At least one domain name is pending deletion and will soon become available for registration again`}
key="pendingDeleteNotice"
>
<Tag color={eppStatusCodeToColor('pending delete')}>pending delete</Tag>
</Tooltip>
@@ -53,6 +56,7 @@ export function TrackedDomainTable() {
const [dataTable, setDataTable] = useState<TableRow[]>([])
const [total, setTotal] = useState<number>()
const [specialNotice, setSpecialNotice] = useState<ReactElement[]>([])
const sm = useBreakpoint('sm')
const rdapStatusCodeDetailTranslated = rdapStatusCodeDetailTranslation()
@@ -220,6 +224,7 @@ export function TrackedDomainTable() {
text: <Tooltip
placement='bottomLeft'
title={rdapStatusCodeDetailTranslated[s as keyof typeof rdapStatusCodeDetailTranslated] || undefined}
key={s}
>
<Tag color={eppStatusCodeToColor(s)}>{s}</Tag>
</Tooltip>,
@@ -268,7 +273,8 @@ export function TrackedDomainTable() {
fetchData({page, itemsPerPage})
}
}}
scroll={{y: '50vh'}}
scroll={sm ? {} : {y: '50vh'}}
size={sm ? 'small' : 'large'}
/>
</Skeleton>
}

View File

@@ -10,4 +10,8 @@
body {
margin: 0;
font-family: "Noto Color Emoji", sans-serif;
@media (prefers-color-scheme: dark) {
background: #000000;
}
}

View File

@@ -6,6 +6,7 @@ import {LoginForm} from '../components/LoginForm'
import type { InstanceConfig} from '../utils/api'
import {getConfiguration} from '../utils/api'
import {RegisterForm} from '../components/RegisterForm'
import useBreakpoint from "../hooks/useBreakpoint"
export const AuthenticatedContext = createContext<
{
@@ -22,6 +23,7 @@ export const AuthenticatedContext = createContext<
export default function LoginPage() {
const [wantRegister, setWantRegister] = useState<boolean>(false)
const [configuration, setConfiguration] = useState<InstanceConfig>()
const md = useBreakpoint('md')
const toggleWantRegister = () => {
setWantRegister(!wantRegister)
@@ -31,24 +33,32 @@ export default function LoginPage() {
getConfiguration().then(setConfiguration)
}, [])
const grid = [
<Card.Grid key="form" style={{width: md ? '100%' : '50%', textAlign: 'center'}} hoverable={false}>
{wantRegister ? <RegisterForm/> : <LoginForm ssoLogin={configuration?.ssoLogin}/>}
{
configuration?.registerEnabled &&
<Button
type='link'
block
style={{marginTop: '1em'}}
onClick={toggleWantRegister}
>{wantRegister ? t`Log in` : t`Create an account`}
</Button>
}
</Card.Grid>,
<Card.Grid key="ads" style={{width: md ? '100%' : '50%'}} hoverable={false}>
<TextPage resource='ads.md'/>
</Card.Grid>
]
if (md) {
grid.reverse()
}
return (
<Card title={wantRegister ? t`Register` : t`Log in`} style={{width: '100%'}}>
<Card.Grid style={{width: '50%', textAlign: 'center'}} hoverable={false}>
{wantRegister ? <RegisterForm/> : <LoginForm ssoLogin={configuration?.ssoLogin}/>}
{
configuration?.registerEnabled &&
<Button
type='link'
block
style={{marginTop: '1em'}}
onClick={toggleWantRegister}
>{wantRegister ? t`Log in` : t`Create an account`}
</Button>
}
</Card.Grid>
<Card.Grid style={{width: '50%'}} hoverable={false}>
<TextPage resource='ads.md'/>
</Card.Grid>
{grid}
</Card>
)
}

View File

@@ -1,7 +1,7 @@
import React, {useEffect, useState} from 'react'
import type { Statistics} from '../utils/api'
import {getStatistics} from '../utils/api'
import {Card, Col, Divider, Row, Statistic, Tooltip} from 'antd'
import {Card, Col, Divider, Flex, Row, Statistic, Tooltip} from 'antd'
import {t} from 'ttag'
import {
AimOutlined,
@@ -104,20 +104,19 @@ export default function StatisticsPage() {
</Col>
</Row>
<Divider/>
<Row gutter={16} justify='center' align='middle'>
<Flex gap={16} wrap justify='center' align='middle'>
{stats?.domainCount
.sort((a, b) => b.domain - a.domain)
.map(({domain, tld}) => <Col key={tld} span={4}>
<Card bordered={false}>
.map(({domain, tld}) =>
<Card key={tld} bordered={false}>
<Statistic
loading={stats === undefined}
title={tld ? tld : t`TLD`}
value={domain}
valueStyle={{color: 'darkorange'}}
/>
</Card>
</Col>)}
</Row>
</Card>)}
</Flex>
</>
)
}

View File

@@ -5,6 +5,7 @@ import {t} from 'ttag'
import type {ColumnType} from 'antd/es/table'
import {CheckCircleOutlined, SettingOutlined, CloseCircleOutlined} from "@ant-design/icons"
import {getIcannAccreditations} from "../../utils/api/icann-accreditations"
import useBreakpoint from "../../hooks/useBreakpoint"
const {Text, Paragraph} = Typography
@@ -19,6 +20,7 @@ function RegistrarListTable(filters: FiltersType) {
name: string
}
const sm = useBreakpoint('sm')
const [dataTable, setDataTable] = useState<TableRow[]>([])
const [total, setTotal] = useState(0)
@@ -63,14 +65,15 @@ function RegistrarListTable(filters: FiltersType) {
fetchData({...filters, page, itemsPerPage})
}
}}
scroll={{y: '50vh'}}
scroll={sm ? {} : {y: '50vh'}}
size={sm ? 'small' : 'large'}
/>
)
}
export default function IcannRegistrarPage() {
const [activeTabKey, setActiveTabKey] = useState<string>('Accredited')
const sm = useBreakpoint('sm')
const contentList: Record<string, React.ReactNode> = {
Accredited: <>
@@ -125,6 +128,7 @@ export default function IcannRegistrarPage() {
activeTabKey={activeTabKey}
key={activeTabKey}
onTabChange={(k: string) => setActiveTabKey(k)}
size={sm ? 'small' : 'default'}
>
{contentList[activeTabKey]}

View File

@@ -11,6 +11,7 @@ import {getCountryCode} from '../../utils/functions/getCountryCode'
import {tldToEmoji} from '../../utils/functions/tldToEmoji'
import {BankOutlined, FlagOutlined, GlobalOutlined, TrademarkOutlined} from "@ant-design/icons"
import {Link} from "react-router-dom"
import useBreakpoint from "../../hooks/useBreakpoint"
const {Text, Paragraph} = Typography
@@ -30,6 +31,7 @@ function TldTable(filters: FiltersType) {
Country?: string
}
const sm = useBreakpoint('sm')
const [dataTable, setDataTable] = useState<TableRow[]>([])
const [total, setTotal] = useState(0)
@@ -110,14 +112,15 @@ function TldTable(filters: FiltersType) {
fetchData({...filters, page, itemsPerPage})
}
}}
scroll={{y: '50vh'}}
scroll={sm ? {} : {y: '50vh'}}
size={sm ? 'small' : 'large'}
/>
)
}
export default function TldPage() {
const [activeTabKey, setActiveTabKey] = useState<string>('gTLD')
const sm = useBreakpoint("sm")
const contentList: Record<string, React.ReactNode> = {
sTLD: <>
@@ -185,6 +188,7 @@ export default function TldPage() {
activeTabKey={activeTabKey}
key={activeTabKey}
onTabChange={(k: string) => setActiveTabKey(k)}
size={sm ? 'small' : 'default'}
>
{contentList[activeTabKey]}

View File

@@ -10,6 +10,7 @@ export function statusToTag(s: string) {
<Tooltip
placement='bottomLeft'
title={rdapStatusCodeDetailTranslated[s as keyof typeof rdapStatusCodeDetailTranslated] || undefined}
key={s}
>
<Tag color={eppStatusCodeToColor(s)}>{s}</Tag>
</Tooltip>

View File

@@ -3,44 +3,44 @@ msgstr ""
"Content-Type: text/plain; charset=utf-8\n"
"Plural-Forms: nplurals=2; plural=(n!=1);\n"
#: assets/App.tsx:120
#: assets/App.tsx:161
msgid "TOS"
msgstr ""
#: assets/App.tsx:121
#: assets/App.tsx:162
msgid "Privacy Policy"
msgstr ""
#: assets/App.tsx:122
#: assets/App.tsx:163
msgid "FAQ"
msgstr ""
#: assets/App.tsx:129
#: assets/App.tsx:170
msgid "Documentation"
msgstr ""
#: assets/App.tsx:134
#: assets/App.tsx:175
#, javascript-format
msgid ""
"${ ProjectLink } is an open source project distributed under the ${ "
"LicenseLink } license."
msgstr ""
#: assets/App.tsx:147
#: assets/App.tsx:188
msgid "Official git repository"
msgstr ""
#: assets/App.tsx:150
#: assets/App.tsx:191
msgid "Submit an issue"
msgstr ""
#: assets/components/LoginForm.tsx:48
#: assets/components/LoginForm.tsx:53
#: assets/components/RegisterForm.tsx:37
msgid "Email address"
msgstr ""
#: assets/components/LoginForm.tsx:50
#: assets/components/LoginForm.tsx:58
#: assets/components/LoginForm.tsx:55
#: assets/components/LoginForm.tsx:63
#: assets/components/RegisterForm.tsx:39
#: assets/components/RegisterForm.tsx:47
#: assets/components/search/DomainSearchBar.tsx:28
@@ -72,22 +72,22 @@ msgstr ""
msgid "Required"
msgstr ""
#: assets/components/LoginForm.tsx:56
#: assets/components/LoginForm.tsx:61
#: assets/components/RegisterForm.tsx:45
#: assets/utils/providers/forms/EppConnectorForm.tsx:138
msgid "Password"
msgstr ""
#: assets/components/LoginForm.tsx:66
#: assets/components/LoginForm.tsx:70
msgid "Submit"
msgstr ""
#: assets/components/LoginForm.tsx:71
#: assets/components/LoginForm.tsx:74
msgid "Log in with SSO"
msgstr ""
#: assets/components/RegisterForm.tsx:54
#: assets/pages/LoginPage.tsx:35
#: assets/pages/LoginPage.tsx:60
msgid "Register"
msgstr ""
@@ -97,22 +97,22 @@ msgid "Registration"
msgstr ""
#: assets/components/search/DomainLifecycleSteps.tsx:24
#: assets/components/tracking/watchlist/TrackedDomainTable.tsx:133
#: assets/components/tracking/watchlist/TrackedDomainTable.tsx:137
msgid "Active"
msgstr ""
#: assets/components/search/DomainLifecycleSteps.tsx:29
#: assets/components/tracking/watchlist/TrackedDomainTable.tsx:111
#: assets/components/tracking/watchlist/TrackedDomainTable.tsx:115
msgid "Auto-Renew Grace Period"
msgstr ""
#: assets/components/search/DomainLifecycleSteps.tsx:35
#: assets/components/tracking/watchlist/TrackedDomainTable.tsx:119
#: assets/components/tracking/watchlist/TrackedDomainTable.tsx:123
msgid "Redemption Grace Period"
msgstr ""
#: assets/components/search/DomainLifecycleSteps.tsx:40
#: assets/components/tracking/watchlist/TrackedDomainTable.tsx:127
#: assets/components/tracking/watchlist/TrackedDomainTable.tsx:131
msgid "Pending Delete"
msgstr ""
@@ -124,7 +124,7 @@ msgid ""
msgstr ""
#: assets/components/search/DomainResult.tsx:64
#: assets/components/tracking/watchlist/TrackedDomainTable.tsx:89
#: assets/components/tracking/watchlist/TrackedDomainTable.tsx:93
msgid "Registry Lock"
msgstr ""
@@ -135,7 +135,7 @@ msgid ""
msgstr ""
#: assets/components/search/DomainResult.tsx:75
#: assets/components/tracking/watchlist/TrackedDomainTable.tsx:95
#: assets/components/tracking/watchlist/TrackedDomainTable.tsx:99
msgid "Registrar Lock"
msgstr ""
@@ -146,12 +146,12 @@ msgid ""
msgstr ""
#: assets/components/search/DomainResult.tsx:84
#: assets/components/tracking/watchlist/TrackedDomainTable.tsx:101
#: assets/components/tracking/watchlist/TrackedDomainTable.tsx:105
msgid "DNSSEC"
msgstr ""
#: assets/components/search/DomainResult.tsx:90
#: assets/components/tracking/watchlist/TrackedDomainTable.tsx:215
#: assets/components/tracking/watchlist/TrackedDomainTable.tsx:219
msgid "EPP Status Codes"
msgstr ""
@@ -177,7 +177,7 @@ msgid "Search"
msgstr ""
#: assets/components/Sider.tsx:43
#: assets/components/tracking/watchlist/TrackedDomainTable.tsx:175
#: assets/components/tracking/watchlist/TrackedDomainTable.tsx:179
msgid "Domain"
msgstr ""
@@ -192,7 +192,7 @@ msgstr ""
#: assets/components/Sider.tsx:70
#: assets/pages/StatisticsPage.tsx:114
#: assets/pages/infrastructure/TldPage.tsx:79
#: assets/pages/infrastructure/TldPage.tsx:81
msgid "TLD"
msgstr ""
@@ -250,13 +250,13 @@ msgid "Log out"
msgstr ""
#: assets/components/Sider.tsx:154
#: assets/pages/LoginPage.tsx:35
#: assets/pages/LoginPage.tsx:45
#: assets/pages/LoginPage.tsx:46
#: assets/pages/LoginPage.tsx:60
msgid "Log in"
msgstr ""
#: assets/components/tracking/connector/ConnectorForm.tsx:36
#: assets/pages/infrastructure/IcannRegistrarPage.tsx:49
#: assets/pages/infrastructure/IcannRegistrarPage.tsx:51
#: assets/utils/functions/rdapTranslation.ts:12
msgid "Registrar"
msgstr ""
@@ -328,17 +328,17 @@ msgstr ""
msgid "No"
msgstr ""
#: assets/components/tracking/connector/ConnectorsList.tsx:48
#: assets/components/tracking/connector/ConnectorsList.tsx:49
#, javascript-format
msgid "Creation date: ${ createdAt }"
msgstr ""
#: assets/components/tracking/connector/ConnectorsList.tsx:49
#: assets/components/tracking/connector/ConnectorsList.tsx:50
#, javascript-format
msgid "Used in: ${ watchlistCount } Watchlist"
msgstr ""
#: assets/components/tracking/connector/ConnectorsList.tsx:52
#: assets/components/tracking/connector/ConnectorsList.tsx:53
msgid ""
"You can stop using a connector at any time. To delete a connector, you must "
"remove it from each linked Watchlist.\n"
@@ -348,7 +348,7 @@ msgid ""
"withdrawal and were of the minimum age to consent to these conditions."
msgstr ""
#: assets/components/tracking/connector/ConnectorsList.tsx:56
#: assets/components/tracking/connector/ConnectorsList.tsx:57
msgid "The Providers conditions are accessible by following this hyperlink."
msgstr ""
@@ -404,66 +404,66 @@ msgstr ""
msgid "Enable the Watchlist"
msgstr ""
#: assets/components/tracking/watchlist/TrackedDomainTable.tsx:29
#: assets/components/tracking/watchlist/TrackedDomainTable.tsx:30
msgid ""
"At least one domain name is in redemption period and will potentially be "
"deleted soon"
msgstr ""
#: assets/components/tracking/watchlist/TrackedDomainTable.tsx:37
#: assets/components/tracking/watchlist/TrackedDomainTable.tsx:39
msgid ""
"At least one domain name is pending deletion and will soon become available "
"for registration again"
msgstr ""
#: assets/components/tracking/watchlist/TrackedDomainTable.tsx:143
#: assets/components/tracking/watchlist/TrackedDomainTable.tsx:147
msgid "Estimated number of days until WHOIS removal"
msgstr ""
#: assets/components/tracking/watchlist/TrackedDomainTable.tsx:146
#: assets/components/tracking/watchlist/TrackedDomainTable.tsx:150
#, javascript-format
msgid "J ${ expiresInDays }"
msgstr ""
#: assets/components/tracking/watchlist/TrackedDomainTable.tsx:152
#: assets/components/tracking/watchlist/TrackedDomainTable.tsx:156
msgid "Deletion is imminent"
msgstr ""
#: assets/components/tracking/watchlist/TrackedDomainTable.tsx:181
#: assets/components/tracking/watchlist/TrackedDomainTable.tsx:185
msgid "Status"
msgstr ""
#: assets/components/tracking/watchlist/TrackedDomainTable.tsx:187
#: assets/components/tracking/watchlist/TrackedDomainTable.tsx:191
msgid "Options"
msgstr ""
#: assets/components/tracking/watchlist/TrackedDomainTable.tsx:193
#: assets/components/tracking/watchlist/TrackedDomainTable.tsx:197
msgid "Expiration date"
msgstr ""
#: assets/components/tracking/watchlist/TrackedDomainTable.tsx:207
#: assets/components/tracking/watchlist/TrackedDomainTable.tsx:211
msgid "Updated at"
msgstr ""
#: assets/components/tracking/watchlist/TrackedDomainTable.tsx:235
#: assets/components/tracking/watchlist/TrackedDomainTable.tsx:240
msgid "No tracked domain names were found, please create your first Watchlist"
msgstr ""
#: assets/components/tracking/watchlist/TrackedDomainTable.tsx:238
#: assets/components/tracking/watchlist/TrackedDomainTable.tsx:243
msgid "Create now"
msgstr ""
#: assets/components/tracking/watchlist/TrackedDomainTable.tsx:244
#: assets/components/tracking/watchlist/TrackedDomainTable.tsx:249
msgid ""
"Please note that this table does not include domain names marked as expired "
"or those with an unknown expiration date"
msgstr ""
#: assets/components/tracking/watchlist/TrackedDomainTable.tsx:249
#: assets/components/tracking/watchlist/TrackedDomainTable.tsx:254
msgid "At least one domain name you are tracking requires special attention"
msgstr ""
#: assets/components/tracking/watchlist/TrackedDomainTable.tsx:255
#: assets/components/tracking/watchlist/TrackedDomainTable.tsx:260
msgid "The domain names below are subject to special monitoring"
msgstr ""
@@ -475,10 +475,6 @@ msgstr ""
msgid "Update a Watchlist"
msgstr ""
#: assets/components/tracking/watchlist/UpdateWatchlistButton.tsx:56
msgid "Cancel"
msgstr ""
#: assets/components/tracking/watchlist/WatchlistCard.tsx:54
msgid "This Watchlist is not linked to a Connector."
msgstr ""
@@ -568,31 +564,31 @@ msgstr ""
msgid "Reset"
msgstr ""
#: assets/pages/infrastructure/IcannRegistrarPage.tsx:43
#: assets/pages/infrastructure/IcannRegistrarPage.tsx:45
msgid "ID"
msgstr ""
#: assets/pages/infrastructure/IcannRegistrarPage.tsx:77
#: assets/pages/infrastructure/IcannRegistrarPage.tsx:80
msgid ""
"An accredited number means that ICANN's contract with the registrar is "
"ongoing."
msgstr ""
#: assets/pages/infrastructure/IcannRegistrarPage.tsx:82
#: assets/pages/infrastructure/IcannRegistrarPage.tsx:85
msgid "A reserved number can be used by TLD registries for specific operations."
msgstr ""
#: assets/pages/infrastructure/IcannRegistrarPage.tsx:87
#: assets/pages/infrastructure/IcannRegistrarPage.tsx:90
msgid ""
"A terminated number means that ICANN's contract with the registrar has been "
"terminated."
msgstr ""
#: assets/pages/infrastructure/IcannRegistrarPage.tsx:96
#: assets/pages/infrastructure/IcannRegistrarPage.tsx:99
msgid "This page lists ICANN-accredited registrars."
msgstr ""
#: assets/pages/infrastructure/IcannRegistrarPage.tsx:99
#: assets/pages/infrastructure/IcannRegistrarPage.tsx:102
msgid ""
"The list is officially published and maintained by the Internet Assigned "
"Numbers Authority (IANA), the organization responsible for managing the "
@@ -600,63 +596,63 @@ msgid ""
"name extensions)."
msgstr ""
#: assets/pages/infrastructure/IcannRegistrarPage.tsx:111
#: assets/pages/infrastructure/IcannRegistrarPage.tsx:114
#: assets/utils/functions/rdapTranslation.ts:125
msgid "Accredited"
msgstr ""
#: assets/pages/infrastructure/IcannRegistrarPage.tsx:116
#: assets/pages/infrastructure/IcannRegistrarPage.tsx:119
#: assets/utils/functions/rdapTranslation.ts:126
msgid "Reserved"
msgstr ""
#: assets/pages/infrastructure/IcannRegistrarPage.tsx:121
#: assets/pages/infrastructure/IcannRegistrarPage.tsx:124
#: assets/utils/functions/rdapTranslation.ts:124
msgid "Terminated"
msgstr ""
#: assets/pages/infrastructure/TldPage.tsx:86
#: assets/pages/infrastructure/TldPage.tsx:88
msgid "Flag"
msgstr ""
#: assets/pages/infrastructure/TldPage.tsx:89
#: assets/pages/infrastructure/TldPage.tsx:91
msgid "Country"
msgstr ""
#: assets/pages/infrastructure/TldPage.tsx:96
#: assets/pages/infrastructure/TldPage.tsx:98
msgid "Registry Operator"
msgstr ""
#: assets/pages/infrastructure/TldPage.tsx:124
#: assets/pages/infrastructure/TldPage.tsx:127
msgid ""
"Top-level domains sponsored by specific organizations that set rules for "
"registration and use, often related to particular interest groups or "
"industries."
msgstr ""
#: assets/pages/infrastructure/TldPage.tsx:129
#: assets/pages/infrastructure/TldPage.tsx:132
msgid ""
"Generic top-level domains open to everyone, not restricted by specific "
"criteria, representing various themes or industries."
msgstr ""
#: assets/pages/infrastructure/TldPage.tsx:134
#: assets/pages/infrastructure/TldPage.tsx:137
msgid ""
"Generic top-level domains associated with specific brands, allowing "
"companies to use their own brand names as domains."
msgstr ""
#: assets/pages/infrastructure/TldPage.tsx:139
#: assets/pages/infrastructure/TldPage.tsx:142
msgid ""
"Top-level domains based on country codes, identifying websites according to "
"their country of origin."
msgstr ""
#: assets/pages/infrastructure/TldPage.tsx:148
#: assets/pages/infrastructure/TldPage.tsx:151
msgid "This page presents all active TLDs in the root zone database."
msgstr ""
#: assets/pages/infrastructure/TldPage.tsx:151
#: assets/pages/infrastructure/TldPage.tsx:154
msgid ""
"IANA provides the list of currently active TLDs, regardless of their type, "
"and ICANN provides the list of gTLDs.\n"
@@ -668,23 +664,23 @@ msgid ""
"At the same time, the list of root RDAP servers is updated."
msgstr ""
#: assets/pages/infrastructure/TldPage.tsx:166
#: assets/pages/infrastructure/TldPage.tsx:169
msgid "Generic Top-Level-Domains"
msgstr ""
#: assets/pages/infrastructure/TldPage.tsx:171
#: assets/pages/infrastructure/TldPage.tsx:174
msgid "Country-Code Top-Level-Domains"
msgstr ""
#: assets/pages/infrastructure/TldPage.tsx:176
#: assets/pages/infrastructure/TldPage.tsx:179
msgid "Brand Generic Top-Level-Domains"
msgstr ""
#: assets/pages/infrastructure/TldPage.tsx:181
#: assets/pages/infrastructure/TldPage.tsx:184
msgid "Sponsored Top-Level-Domains"
msgstr ""
#: assets/pages/LoginPage.tsx:45
#: assets/pages/LoginPage.tsx:46
msgid "Create an account"
msgstr ""