refactor: split components Watchlist Page

This commit is contained in:
Maël Gangloff 2024-07-29 18:54:28 +02:00
parent dd4b6c8869
commit f9c003fffb
No known key found for this signature in database
GPG Key ID: 11FDC81C24A7F629
6 changed files with 381 additions and 354 deletions

View File

@ -7,7 +7,7 @@ export type FieldType = {
ldhName: string
}
export function DomainSearchBar({onFinish}: { onFinish: any }) {
export function DomainSearchBar({onFinish}: { onFinish: (values: FieldType) => void }) {
return <Form
name="basic"

View File

@ -0,0 +1,221 @@
import {Button, Form, FormInstance, Input, Select, Space} from "antd";
import {t} from "ttag";
import {MinusCircleOutlined, PlusOutlined, ThunderboltFilled} from "@ant-design/icons";
import React from "react";
import {EventAction} from "../../utils/api";
const formItemLayout = {
labelCol: {
xs: {span: 24},
sm: {span: 4},
},
wrapperCol: {
xs: {span: 24},
sm: {span: 20},
},
};
const formItemLayoutWithOutLabel = {
wrapperCol: {
xs: {span: 24, offset: 0},
sm: {span: 20, offset: 4},
},
};
export function WatchlistForm({form, onCreateWatchlist}: {
form: FormInstance,
onCreateWatchlist: (values: { domains: string[], triggers: { event: string, action: string }[] }) => void
}) {
const triggerEventItems: { label: string, value: EventAction }[] = [
{
label: t`When a domain is expired`,
value: 'expiration'
},
{
label: t`When a domain is deleted`,
value: 'deletion'
},
{
label: t`When a domain is updated`,
value: 'last changed'
},
{
label: t`When a domain is transferred`,
value: 'transfer'
},
{
label: t`When a domain is locked`,
value: 'locked'
},
{
label: t`When a domain is unlocked`,
value: 'unlocked'
},
{
label: t`When a domain is reregistered`,
value: 'reregistration'
},
{
label: t`When a domain is reinstantiated`,
value: 'reinstantiation'
},
{
label: t`When a domain is registered`,
value: 'registration'
}
]
const trigerActionItems = [
{
label: t`Send me an email`,
value: 'email'
}
]
return <Form
{...formItemLayoutWithOutLabel}
form={form}
onFinish={onCreateWatchlist}
>
<Form.List
name="domains"
rules={[
{
validator: async (_, domains) => {
if (!domains || domains.length < 1) {
return Promise.reject(new Error(t`At least one domain name`));
}
},
},
]}
>
{(fields, {add, remove}, {errors}) => (
<>
{fields.map((field, index) => (
<Form.Item
{...(index === 0 ? formItemLayout : formItemLayoutWithOutLabel)}
label={index === 0 ? t`Domain names` : ''}
required={true}
key={field.key}
>
<Form.Item
{...field}
validateTrigger={['onChange', 'onBlur']}
rules={[{
required: true,
message: t`Required`
}, {
pattern: /^(?=.*\.)\S*[^.\s]$/,
message: t`This domain name does not appear to be valid`,
max: 63,
min: 2
}]}
noStyle
>
<Input placeholder={t`Domain name`} style={{width: '60%'}} autoComplete='off'/>
</Form.Item>
{fields.length > 1 ? (
<MinusCircleOutlined
className="dynamic-delete-button"
onClick={() => remove(field.name)}
/>
) : null}
</Form.Item>
))}
<Form.Item>
<Button
type="dashed"
onClick={() => add()}
style={{width: '60%'}}
icon={<PlusOutlined/>}
>
{t`Add a Domain name`}
</Button>
<Form.ErrorList errors={errors}/>
</Form.Item>
</>
)}
</Form.List>
<Form.List
name="triggers"
rules={[
{
validator: async (_, domains) => {
if (!domains || domains.length < 1) {
return Promise.reject(new Error(t`At least one domain trigger`));
}
},
},
]}
>
{(fields, {add, remove}, {errors}) => (
<>
{fields.map((field, index) => (
<Form.Item
{...(index === 0 ? formItemLayout : formItemLayoutWithOutLabel)}
label={index === 0 ? t`Domain trigger` : ''}
required={true}
key={field.key}
>
<Space wrap>
<Form.Item {...field}
validateTrigger={['onChange', 'onBlur']}
rules={[{
required: true,
message: t`Required`
}]}
noStyle name={[field.name, 'event']}>
<Select style={{minWidth: 300}} options={triggerEventItems} showSearch
placeholder={t`If this happens`} optionFilterProp="label"/>
</Form.Item>
<Form.Item {...field}
validateTrigger={['onChange', 'onBlur']}
rules={[{
required: true,
message: t`Required`
}]}
noStyle name={[field.name, 'action']}>
<Select style={{minWidth: 300}} options={trigerActionItems} showSearch
placeholder={t`Then do that`}
optionFilterProp="label"/>
</Form.Item>
</Space>
{fields.length > 1 ? (
<MinusCircleOutlined
className="dynamic-delete-button"
onClick={() => remove(field.name)}
/>
) : null}
</Form.Item>
))}
<Form.Item>
<Button
type="dashed"
onClick={() => add()}
style={{width: '60%'}}
icon={<ThunderboltFilled/>}
>
{t`Add a Trigger`}
</Button>
<Form.ErrorList errors={errors}/>
</Form.Item>
</>
)}
</Form.List>
<Form.Item>
<Space>
<Button type="primary" htmlType="submit">
{t`Create`}
</Button>
<Button type="default" htmlType="reset">
{t`Reset`}
</Button>
</Space>
</Form.Item>
</Form>
}

View File

@ -0,0 +1,34 @@
import {Card, Divider, Popconfirm, Typography} from "antd";
import {t} from "ttag";
import {deleteWatchlist, EventAction} from "../../utils/api";
import {DeleteFilled} from "@ant-design/icons";
import React from "react";
type Watchlist = { token: string, domains: { ldhName: string }[], triggers?: { event: EventAction, action: string }[] }
export function WatchlistsList({watchlists, onDelete}: { watchlists: Watchlist[], onDelete: () => void }) {
return <>
{watchlists.map(watchlist =>
<>
<Card title={t`Watchlist ${watchlist.token}`} extra={<Popconfirm
title={t`Delete the Watchlist`}
description={t`Are you sure to delete this Watchlist?`}
onConfirm={() => deleteWatchlist(watchlist.token).then()}
okText={t`Yes`}
cancelText={t`No`}
><DeleteFilled/> </Popconfirm>}>
<Typography.Paragraph>
{t`Domain name`} : {watchlist?.domains.map(d => d.ldhName).join(',')}
</Typography.Paragraph>
{
watchlist.triggers && <Typography.Paragraph>
{t`Domain triggers`} : {watchlist.triggers.map(t => `${t.event} => ${t.action}`).join(',')}
</Typography.Paragraph>
}
</Card>
<Divider/>
</>
)}
</>
}

View File

@ -1,6 +1,6 @@
import {Result} from "antd";
import React from "react";
import { t } from 'ttag'
import {t} from 'ttag'
export default function NotFoundPage() {

View File

@ -1,81 +1,16 @@
import React, {useEffect, useState} from "react";
import {Button, Card, Divider, Flex, Form, Input, message, Popconfirm, Select, Skeleton, Space, Typography} from "antd";
import {DeleteFilled, MinusCircleOutlined, PlusOutlined, ThunderboltFilled} from "@ant-design/icons";
import {deleteWatchlist, EventAction, getWatchlists, postWatchlist} from "../../utils/api";
import {Card, Flex, Form, message, Skeleton} from "antd";
import {EventAction, getWatchlists, postWatchlist} from "../../utils/api";
import {AxiosError} from "axios";
import {t} from 'ttag'
import {WatchlistForm} from "../../components/tracking/WatchlistForm";
import {WatchlistsList} from "../../components/tracking/WatchlistsList";
const formItemLayout = {
labelCol: {
xs: {span: 24},
sm: {span: 4},
},
wrapperCol: {
xs: {span: 24},
sm: {span: 20},
},
};
const formItemLayoutWithOutLabel = {
wrapperCol: {
xs: {span: 24, offset: 0},
sm: {span: 20, offset: 4},
},
};
type Watchlist = { token: string, domains: { ldhName: string }[], triggers?: { event: EventAction, action: string }[] }
export default function WatchlistPage() {
const triggerEventItems: { label: string, value: EventAction }[] = [
{
label: t`When a domain is expired`,
value: 'expiration'
},
{
label: t`When a domain is deleted`,
value: 'deletion'
},
{
label: t`When a domain is updated`,
value: 'last changed'
},
{
label: t`When a domain is transferred`,
value: 'transfer'
},
{
label: t`When a domain is locked`,
value: 'locked'
},
{
label: t`When a domain is unlocked`,
value: 'unlocked'
},
{
label: t`When a domain is reregistered`,
value: 'reregistration'
},
{
label: t`When a domain is reinstantiated`,
value: 'reinstantiation'
},
{
label: t`When a domain is registered`,
value: 'registration'
}
]
const trigerActionItems = [
{
label: t`Send me an email`,
value: 'email'
}
]
const [form] = Form.useForm()
const [messageApi, contextHolder] = message.useMessage()
const [watchlists, setWatchlists] = useState<Watchlist[] | null>()
@ -103,176 +38,13 @@ export default function WatchlistPage() {
return <Flex gap="middle" align="center" justify="center" vertical>
<Card title={t`Create a watchlist`} style={{width: '100%'}}>
{contextHolder}
<Form
{...formItemLayoutWithOutLabel}
form={form}
onFinish={onCreateWatchlist}
>
<Form.List
name="domains"
rules={[
{
validator: async (_, domains) => {
if (!domains || domains.length < 1) {
return Promise.reject(new Error(t`At least one domain name`));
}
},
},
]}
>
{(fields, {add, remove}, {errors}) => (
<>
{fields.map((field, index) => (
<Form.Item
{...(index === 0 ? formItemLayout : formItemLayoutWithOutLabel)}
label={index === 0 ? t`Domain names` : ''}
required={true}
key={field.key}
>
<Form.Item
{...field}
validateTrigger={['onChange', 'onBlur']}
rules={[{
required: true,
message: t`Required`
}, {
pattern: /^(?=.*\.)\S*[^.\s]$/,
message: t`This domain name does not appear to be valid`,
max: 63,
min: 2
}]}
noStyle
>
<Input placeholder={t`Domain name`} style={{width: '60%'}} autoComplete='off'/>
</Form.Item>
{fields.length > 1 ? (
<MinusCircleOutlined
className="dynamic-delete-button"
onClick={() => remove(field.name)}
/>
) : null}
</Form.Item>
))}
<Form.Item>
<Button
type="dashed"
onClick={() => add()}
style={{width: '60%'}}
icon={<PlusOutlined/>}
>
{t`Add a Domain name`}
</Button>
<Form.ErrorList errors={errors}/>
</Form.Item>
</>
)}
</Form.List>
<Form.List
name="triggers"
rules={[
{
validator: async (_, domains) => {
if (!domains || domains.length < 1) {
return Promise.reject(new Error(t`At least one domain trigger`));
}
},
},
]}
>
{(fields, {add, remove}, {errors}) => (
<>
{fields.map((field, index) => (
<Form.Item
{...(index === 0 ? formItemLayout : formItemLayoutWithOutLabel)}
label={index === 0 ? t`Domain trigger` : ''}
required={true}
key={field.key}
>
<Space wrap>
<Form.Item {...field}
validateTrigger={['onChange', 'onBlur']}
rules={[{
required: true,
message: t`Required`
}]}
noStyle name={[field.name, 'event']}>
<Select style={{minWidth: 300}} options={triggerEventItems} showSearch
placeholder={t`If this happens`} optionFilterProp="label"/>
</Form.Item>
<Form.Item {...field}
validateTrigger={['onChange', 'onBlur']}
rules={[{
required: true,
message: t`Required`
}]}
noStyle name={[field.name, 'action']}>
<Select style={{minWidth: 300}} options={trigerActionItems} showSearch
placeholder={t`Then do that`}
optionFilterProp="label"/>
</Form.Item>
</Space>
{fields.length > 1 ? (
<MinusCircleOutlined
className="dynamic-delete-button"
onClick={() => remove(field.name)}
/>
) : null}
</Form.Item>
))}
<Form.Item>
<Button
type="dashed"
onClick={() => add()}
style={{width: '60%'}}
icon={<ThunderboltFilled/>}
>
{t`Add a Trigger`}
</Button>
<Form.ErrorList errors={errors}/>
</Form.Item>
</>
)}
</Form.List>
<Form.Item>
<Space>
<Button type="primary" htmlType="submit">
{t`Create`}
</Button>
<Button type="default" htmlType="reset">
{t`Reset`}
</Button>
</Space>
</Form.Item>
</Form>
<WatchlistForm form={form} onCreateWatchlist={onCreateWatchlist}/>
</Card>
<Skeleton loading={watchlists === undefined} active>
{watchlists && watchlists.length > 0 && <Card title={t`My Watchlists`} style={{width: '100%'}}>
{watchlists.map(watchlist =>
<>
<Card title={t`Watchlist ${watchlist.token}`} extra={<Popconfirm
title={t`Delete the Watchlist`}
description={t`Are you sure to delete this Watchlist?`}
onConfirm={() => deleteWatchlist(watchlist.token).then(refreshWatchlists)}
okText={t`Yes`}
cancelText={t`No`}
><DeleteFilled/> </Popconfirm>}>
<Typography.Paragraph>
{t`Domain name`} : {watchlist?.domains.map(d => d.ldhName).join(',')}
</Typography.Paragraph>
{
watchlist.triggers && <Typography.Paragraph>
{t`Domain triggers`} : {watchlist.triggers.map(t => `${t.event} => ${t.action}`).join(',')}
</Typography.Paragraph>
}
</Card>
<Divider/>
</>
)}
<WatchlistsList watchlists={watchlists} onDelete={refreshWatchlists}/>
</Card>
}
</Skeleton>

View File

@ -48,16 +48,16 @@ msgid "ENUM validation expiration"
msgstr ""
#: assets/components/search/DomainSearchBar.tsx:23
#: assets/components/tracking/WatchlistForm.tsx:108
#: assets/components/tracking/WatchlistForm.tsx:168
#: assets/components/tracking/WatchlistForm.tsx:178
#: assets/pages/LoginPage.tsx:53
#: assets/pages/LoginPage.tsx:61
#: assets/pages/tracking/WatchlistPage.tsx:137
#: assets/pages/tracking/WatchlistPage.tsx:197
#: assets/pages/tracking/WatchlistPage.tsx:207
msgid "Required"
msgstr ""
#: assets/components/search/DomainSearchBar.tsx:26
#: assets/pages/tracking/WatchlistPage.tsx:140
#: assets/components/tracking/WatchlistForm.tsx:111
msgid "This domain name does not appear to be valid"
msgstr ""
@ -105,12 +105,122 @@ msgstr ""
msgid "Noc"
msgstr ""
#: assets/components/tracking/WatchlistForm.tsx:33
msgid "When a domain is expired"
msgstr ""
#: assets/components/tracking/WatchlistForm.tsx:37
msgid "When a domain is deleted"
msgstr ""
#: assets/components/tracking/WatchlistForm.tsx:41
msgid "When a domain is updated"
msgstr ""
#: assets/components/tracking/WatchlistForm.tsx:45
msgid "When a domain is transferred"
msgstr ""
#: assets/components/tracking/WatchlistForm.tsx:49
msgid "When a domain is locked"
msgstr ""
#: assets/components/tracking/WatchlistForm.tsx:53
msgid "When a domain is unlocked"
msgstr ""
#: assets/components/tracking/WatchlistForm.tsx:57
msgid "When a domain is reregistered"
msgstr ""
#: assets/components/tracking/WatchlistForm.tsx:61
msgid "When a domain is reinstantiated"
msgstr ""
#: assets/components/tracking/WatchlistForm.tsx:65
msgid "When a domain is registered"
msgstr ""
#: assets/components/tracking/WatchlistForm.tsx:72
msgid "Send me an email"
msgstr ""
#: assets/components/tracking/WatchlistForm.tsx:88
msgid "At least one domain name"
msgstr ""
#: assets/components/tracking/WatchlistForm.tsx:99
msgid "Domain names"
msgstr ""
#: assets/components/tracking/WatchlistForm.tsx:117
#: assets/components/tracking/WatchlistsList.tsx:22
msgid "Domain name"
msgstr ""
#: assets/components/tracking/WatchlistForm.tsx:134
msgid "Add a Domain name"
msgstr ""
#: assets/components/tracking/WatchlistForm.tsx:147
msgid "At least one domain trigger"
msgstr ""
#: assets/components/tracking/WatchlistForm.tsx:158
msgid "Domain trigger"
msgstr ""
#: assets/components/tracking/WatchlistForm.tsx:172
msgid "If this happens"
msgstr ""
#: assets/components/tracking/WatchlistForm.tsx:182
msgid "Then do that"
msgstr ""
#: assets/components/tracking/WatchlistForm.tsx:203
msgid "Add a Trigger"
msgstr ""
#: assets/components/tracking/WatchlistForm.tsx:213
msgid "Create"
msgstr ""
#: assets/components/tracking/WatchlistForm.tsx:216
msgid "Reset"
msgstr ""
#: assets/components/tracking/WatchlistsList.tsx:14
#, javascript-format
msgid "Watchlist ${ watchlist.token }"
msgstr ""
#: assets/components/tracking/WatchlistsList.tsx:15
msgid "Delete the Watchlist"
msgstr ""
#: assets/components/tracking/WatchlistsList.tsx:16
msgid "Are you sure to delete this Watchlist?"
msgstr ""
#: assets/components/tracking/WatchlistsList.tsx:18
msgid "Yes"
msgstr ""
#: assets/components/tracking/WatchlistsList.tsx:19
msgid "No"
msgstr ""
#: assets/components/tracking/WatchlistsList.tsx:26
msgid "Domain triggers"
msgstr ""
#: assets/pages/search/DomainSearchPage.tsx:19
msgid "Found !"
msgstr ""
#: assets/pages/search/DomainSearchPage.tsx:23
#: assets/pages/tracking/WatchlistPage.tsx:91
#: assets/pages/tracking/WatchlistPage.tsx:26
msgid "An error occurred"
msgstr ""
@ -224,129 +334,19 @@ msgstr ""
msgid "Roles"
msgstr ""
#: assets/pages/tracking/WatchlistPage.tsx:34
msgid "When a domain is expired"
msgstr ""
#: assets/pages/tracking/WatchlistPage.tsx:38
msgid "When a domain is deleted"
msgstr ""
#: assets/pages/tracking/WatchlistPage.tsx:42
msgid "When a domain is updated"
msgstr ""
#: assets/pages/tracking/WatchlistPage.tsx:46
msgid "When a domain is transferred"
msgstr ""
#: assets/pages/tracking/WatchlistPage.tsx:50
msgid "When a domain is locked"
msgstr ""
#: assets/pages/tracking/WatchlistPage.tsx:54
msgid "When a domain is unlocked"
msgstr ""
#: assets/pages/tracking/WatchlistPage.tsx:58
msgid "When a domain is reregistered"
msgstr ""
#: assets/pages/tracking/WatchlistPage.tsx:62
msgid "When a domain is reinstantiated"
msgstr ""
#: assets/pages/tracking/WatchlistPage.tsx:66
msgid "When a domain is registered"
msgstr ""
#: assets/pages/tracking/WatchlistPage.tsx:73
msgid "Send me an email"
msgstr ""
#: assets/pages/tracking/WatchlistPage.tsx:88
#: assets/pages/tracking/WatchlistPage.tsx:23
msgid "Watchlist created !"
msgstr ""
#: assets/pages/tracking/WatchlistPage.tsx:104
#: assets/pages/tracking/WatchlistPage.tsx:39
msgid "Create a watchlist"
msgstr ""
#: assets/pages/tracking/WatchlistPage.tsx:117
msgid "At least one domain name"
msgstr ""
#: assets/pages/tracking/WatchlistPage.tsx:128
msgid "Domain names"
msgstr ""
#: assets/pages/tracking/WatchlistPage.tsx:146
#: assets/pages/tracking/WatchlistPage.tsx:265
msgid "Domain name"
msgstr ""
#: assets/pages/tracking/WatchlistPage.tsx:163
msgid "Add a Domain name"
msgstr ""
#: assets/pages/tracking/WatchlistPage.tsx:176
msgid "At least one domain trigger"
msgstr ""
#: assets/pages/tracking/WatchlistPage.tsx:187
msgid "Domain trigger"
msgstr ""
#: assets/pages/tracking/WatchlistPage.tsx:201
msgid "If this happens"
msgstr ""
#: assets/pages/tracking/WatchlistPage.tsx:211
msgid "Then do that"
msgstr ""
#: assets/pages/tracking/WatchlistPage.tsx:232
msgid "Add a Trigger"
msgstr ""
#: assets/pages/tracking/WatchlistPage.tsx:242
msgid "Create"
msgstr ""
#: assets/pages/tracking/WatchlistPage.tsx:245
msgid "Reset"
msgstr ""
#: assets/App.tsx:136
#: assets/pages/tracking/WatchlistPage.tsx:254
#: assets/pages/tracking/WatchlistPage.tsx:46
msgid "My Watchlists"
msgstr ""
#: assets/pages/tracking/WatchlistPage.tsx:257
#, javascript-format
msgid "Watchlist ${ watchlist.token }"
msgstr ""
#: assets/pages/tracking/WatchlistPage.tsx:258
msgid "Delete the Watchlist"
msgstr ""
#: assets/pages/tracking/WatchlistPage.tsx:259
msgid "Are you sure to delete this Watchlist?"
msgstr ""
#: assets/pages/tracking/WatchlistPage.tsx:261
msgid "Yes"
msgstr ""
#: assets/pages/tracking/WatchlistPage.tsx:262
msgid "No"
msgstr ""
#: assets/pages/tracking/WatchlistPage.tsx:269
msgid "Domain triggers"
msgstr ""
#: assets/pages/NotFoundPage.tsx:10
msgid "Sorry, the page you visited does not exist."
msgstr ""