mirror of
https://github.com/maelgangloff/domain-watchdog.git
synced 2025-12-29 16:15:04 +00:00
Merge branch 'develop' into feat/openprovider-provider
This commit is contained in:
@@ -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>
|
||||
</>
|
||||
)
|
||||
|
||||
@@ -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>
|
||||
</>
|
||||
}
|
||||
)}
|
||||
</>
|
||||
|
||||
@@ -42,7 +42,6 @@ export function CreateWatchlistButton({onUpdateWatchlist, connectors}: {
|
||||
paddingBottom: 80
|
||||
}
|
||||
}}
|
||||
extra={<Button onClick={onClose}>{t`Cancel`}</Button>}
|
||||
>
|
||||
<WatchlistForm
|
||||
form={form}
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {Button, Drawer, Form, Typography} from 'antd'
|
||||
import {Drawer, Form, Typography} from 'antd'
|
||||
import {t} from 'ttag'
|
||||
import {WatchlistForm} from './WatchlistForm'
|
||||
import React, {useState} from 'react'
|
||||
@@ -53,7 +53,6 @@ export function UpdateWatchlistButton({watchlist, onUpdateWatchlist, connectors}
|
||||
paddingBottom: 80
|
||||
}
|
||||
}}
|
||||
extra={<Button onClick={onClose}>{t`Cancel`}</Button>}
|
||||
>
|
||||
<WatchlistForm
|
||||
form={form}
|
||||
|
||||
101
assets/components/tracking/watchlist/WatchlistSelectionModal.tsx
Normal file
101
assets/components/tracking/watchlist/WatchlistSelectionModal.tsx
Normal file
@@ -0,0 +1,101 @@
|
||||
import React, {useEffect, useState} from "react"
|
||||
import type {ModalProps} from "antd"
|
||||
import {Tag, Tooltip} from "antd"
|
||||
import {Flex, Modal, Select, Typography} from "antd"
|
||||
import type {Domain, Watchlist} from "../../../utils/api"
|
||||
import {getWatchlists} from "../../../utils/api"
|
||||
import {t} from 'ttag'
|
||||
import {DomainToTag} from "../../../utils/functions/DomainToTag"
|
||||
import {EllipsisOutlined} from '@ant-design/icons'
|
||||
|
||||
const MAX_DOMAIN_TAGS = 25
|
||||
|
||||
function WatchlistOption({watchlist}: {watchlist: Watchlist}) {
|
||||
let domains = watchlist.domains
|
||||
let rest: Domain[]|undefined = undefined
|
||||
|
||||
if (domains.length > MAX_DOMAIN_TAGS) {
|
||||
rest = domains.slice(MAX_DOMAIN_TAGS)
|
||||
domains = domains.slice(0, MAX_DOMAIN_TAGS)
|
||||
}
|
||||
|
||||
return <Flex vertical>
|
||||
<Typography.Text strong>{watchlist.name}</Typography.Text>
|
||||
<Flex wrap gap='4px'>
|
||||
{domains.map(d => <DomainToTag link={false} domain={d} key={d.ldhName} />)}
|
||||
{rest
|
||||
&& <Tooltip title={rest.map(d => <DomainToTag link={false} domain={d} key={d.ldhName} />)}>
|
||||
<Tag icon={<EllipsisOutlined/>} color='processing'>
|
||||
{t`${rest.length} more`}
|
||||
</Tag>
|
||||
</Tooltip>
|
||||
}
|
||||
</Flex>
|
||||
</Flex>
|
||||
}
|
||||
|
||||
interface WatchlistSelectionModalProps {
|
||||
onFinish: (watchlist: Watchlist) => Promise<void>|void
|
||||
description?: string
|
||||
open?: boolean
|
||||
modalProps?: Partial<ModalProps>
|
||||
}
|
||||
|
||||
export default function WatchlistSelectionModal(props: WatchlistSelectionModalProps) {
|
||||
const [watchlists, setWatchlists] = useState<Watchlist[] | undefined>()
|
||||
const [selectedWatchlist, setSelectedWatchlist] = useState<Watchlist | undefined>()
|
||||
const [validationLoading, setValidationLoading] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
if (props.open && !watchlists) {
|
||||
getWatchlists().then(list => setWatchlists(list["hydra:member"]))
|
||||
}
|
||||
}, [props.open])
|
||||
|
||||
const onFinish = () => {
|
||||
const promise = props.onFinish(selectedWatchlist as Watchlist)
|
||||
|
||||
if (promise) {
|
||||
setValidationLoading(true)
|
||||
promise.finally(() => {
|
||||
setSelectedWatchlist(undefined)
|
||||
setValidationLoading(false)
|
||||
})
|
||||
} else {
|
||||
setSelectedWatchlist(undefined)
|
||||
}
|
||||
}
|
||||
|
||||
return <Modal
|
||||
open={props.open}
|
||||
onOk={onFinish}
|
||||
okButtonProps={{
|
||||
disabled: !selectedWatchlist,
|
||||
loading: validationLoading,
|
||||
}}
|
||||
{...props.modalProps ?? {}}
|
||||
>
|
||||
<Flex vertical>
|
||||
<Typography.Paragraph>
|
||||
{
|
||||
props.description
|
||||
|| t`Select one of your available Watchlists`
|
||||
}
|
||||
</Typography.Paragraph>
|
||||
<Select
|
||||
placeholder={t`Watchlist`}
|
||||
style={{width: '100%'}}
|
||||
onChange={(_, option) => setSelectedWatchlist(option as Watchlist)}
|
||||
options={watchlists}
|
||||
value={selectedWatchlist?.token}
|
||||
fieldNames={{
|
||||
label: 'name',
|
||||
value: 'token',
|
||||
}}
|
||||
loading={!watchlists}
|
||||
status={selectedWatchlist ? '' : 'error'}
|
||||
optionRender={(watchlist) => <WatchlistOption watchlist={watchlist.data}/>}
|
||||
/>
|
||||
</Flex>
|
||||
</Modal>
|
||||
}
|
||||
Reference in New Issue
Block a user