mirror of
https://github.com/maelgangloff/domain-watchdog.git
synced 2025-12-29 16:15:04 +00:00
feat: update my watchlist page
This commit is contained in:
@@ -1 +0,0 @@
|
|||||||
# Privacy Policy
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
# Terms of Service
|
|
||||||
0
assets/controllers/.gitkeep
Normal file
0
assets/controllers/.gitkeep
Normal file
@@ -1,7 +1,7 @@
|
|||||||
import React, {useEffect, useState} from "react";
|
import React, {useEffect, useState} from "react";
|
||||||
import {Button, Card, Divider, Flex, Form, Input, message, Select, Skeleton, Space} from "antd";
|
import {Button, Card, Divider, Flex, Form, Input, message, Popconfirm, Select, Skeleton, Space, Typography} from "antd";
|
||||||
|
|
||||||
import {CloseOutlined, DeleteFilled, MinusCircleOutlined, PlusOutlined, ThunderboltFilled} from "@ant-design/icons";
|
import {DeleteFilled, MinusCircleOutlined, PlusOutlined, ThunderboltFilled} from "@ant-design/icons";
|
||||||
import {deleteWatchlist, EventAction, getWatchlists, postWatchlist} from "../../utils/api";
|
import {deleteWatchlist, EventAction, getWatchlists, postWatchlist} from "../../utils/api";
|
||||||
import {AxiosError} from "axios";
|
import {AxiosError} from "axios";
|
||||||
|
|
||||||
@@ -66,14 +66,15 @@ const trigerActionItems = [
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
type Watchlist = { token: string, domains: { ldhName: string }[], triggers?: { event: EventAction, action: string }[] }
|
||||||
|
|
||||||
export default function WatchlistPage() {
|
export default function WatchlistPage() {
|
||||||
const [form] = Form.useForm()
|
const [form] = Form.useForm()
|
||||||
const [messageApi, contextHolder] = message.useMessage()
|
const [messageApi, contextHolder] = message.useMessage()
|
||||||
const [watchlists, setWatchlists] = useState<{ token: string }[] | null>()
|
const [watchlists, setWatchlists] = useState<Watchlist[] | null>()
|
||||||
|
|
||||||
const onCreateWatchlist = (values: { domains: string[], triggers: { event: string, action: string }[] }) => {
|
const onCreateWatchlist = (values: { domains: string[], triggers: { event: string, action: string }[] }) => {
|
||||||
const domainsURI = values.domains.map(d => '/api/domains/' + d)
|
const domainsURI = values.domains.map(d => '/api/domains/' + d)
|
||||||
|
|
||||||
postWatchlist(domainsURI, values.triggers).then((w) => {
|
postWatchlist(domainsURI, values.triggers).then((w) => {
|
||||||
form.resetFields()
|
form.resetFields()
|
||||||
refreshWatchlists()
|
refreshWatchlists()
|
||||||
@@ -159,36 +160,61 @@ export default function WatchlistPage() {
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</Form.List>
|
</Form.List>
|
||||||
<Form.List name="trigers">
|
<Form.List
|
||||||
{(fields, {add, remove}) => (
|
name="triggers"
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
validator: async (_, domains) => {
|
||||||
|
if (!domains || domains.length < 1) {
|
||||||
|
return Promise.reject(new Error('At least one domain trigger'));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
{(fields, {add, remove}, {errors}) => (
|
||||||
<>
|
<>
|
||||||
{fields.map((field) => (
|
{fields.map((field, index) => (
|
||||||
<Card
|
<Form.Item
|
||||||
size="small"
|
{...(index === 0 ? formItemLayout : formItemLayoutWithOutLabel)}
|
||||||
title={`Trigger ${field.name + 1}`}
|
label={index === 0 ? 'Domain trigger' : ''}
|
||||||
|
required={true}
|
||||||
key={field.key}
|
key={field.key}
|
||||||
extra={
|
|
||||||
<CloseOutlined
|
|
||||||
onClick={() => {
|
|
||||||
remove(field.name);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
<Form.Item name={[field.name, 'event']}>
|
|
||||||
<Select
|
<Space wrap>
|
||||||
status="warning"
|
<Form.Item {...field}
|
||||||
options={triggerEventItems}
|
validateTrigger={['onChange', 'onBlur']}
|
||||||
|
rules={[{
|
||||||
|
required: true,
|
||||||
|
message: 'Required'
|
||||||
|
}]}
|
||||||
|
noStyle name={[field.name, 'event']}>
|
||||||
|
<Select style={{minWidth: 300}} options={triggerEventItems} showSearch
|
||||||
|
placeholder="If this happens" optionFilterProp="label"/>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item {...field}
|
||||||
|
validateTrigger={['onChange', 'onBlur']}
|
||||||
|
rules={[{
|
||||||
|
required: true,
|
||||||
|
message: 'Required'
|
||||||
|
}]}
|
||||||
|
noStyle name={[field.name, 'action']}>
|
||||||
|
<Select style={{minWidth: 300}} options={trigerActionItems} showSearch
|
||||||
|
placeholder="Then do that"
|
||||||
|
optionFilterProp="label"/>
|
||||||
|
</Form.Item>
|
||||||
|
</Space>
|
||||||
|
|
||||||
|
|
||||||
|
{fields.length > 1 ? (
|
||||||
|
<MinusCircleOutlined
|
||||||
|
className="dynamic-delete-button"
|
||||||
|
onClick={() => remove(field.name)}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
) : null}
|
||||||
<Form.Item name={[field.name, 'action']}>
|
</Form.Item>
|
||||||
<Select
|
|
||||||
options={trigerActionItems}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
</Card>
|
|
||||||
))}
|
))}
|
||||||
<Divider/>
|
|
||||||
<Form.Item>
|
<Form.Item>
|
||||||
<Button
|
<Button
|
||||||
type="dashed"
|
type="dashed"
|
||||||
@@ -196,8 +222,9 @@ export default function WatchlistPage() {
|
|||||||
style={{width: '60%'}}
|
style={{width: '60%'}}
|
||||||
icon={<ThunderboltFilled/>}
|
icon={<ThunderboltFilled/>}
|
||||||
>
|
>
|
||||||
Add a trigger
|
Add a Trigger
|
||||||
</Button>
|
</Button>
|
||||||
|
<Form.ErrorList errors={errors}/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
@@ -215,18 +242,32 @@ export default function WatchlistPage() {
|
|||||||
</Form>
|
</Form>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
<Card title="My Watchlists" style={{width: '100%'}}>
|
|
||||||
<Skeleton loading={watchlists === undefined} active>
|
<Skeleton loading={watchlists === undefined} active>
|
||||||
{watchlists && watchlists.map(watchlist =>
|
{watchlists && watchlists.length > 0 && <Card title="My Watchlists" style={{width: '100%'}}>
|
||||||
|
{watchlists.map(watchlist =>
|
||||||
<>
|
<>
|
||||||
<Divider/>
|
<Card title={"Watchlist " + watchlist.token} extra={<Popconfirm
|
||||||
<Card title={"Watchlist " + watchlist.token} extra={<DeleteFilled onClick={() => {
|
title="Delete the Watchlist"
|
||||||
deleteWatchlist(watchlist.token).then(refreshWatchlists)
|
description="Are you sure to delete this Watchlist ?"
|
||||||
}}/>}>
|
onConfirm={() => deleteWatchlist(watchlist.token).then(refreshWatchlists)}
|
||||||
|
okText="Yes"
|
||||||
|
cancelText="No"
|
||||||
|
><DeleteFilled/> </Popconfirm>}>
|
||||||
|
<Typography.Paragraph>
|
||||||
|
Domains : {watchlist?.domains.map(d => d.ldhName).join(',')}
|
||||||
|
</Typography.Paragraph>
|
||||||
|
{
|
||||||
|
watchlist.triggers && <Typography.Paragraph>
|
||||||
|
Triggers : {watchlist.triggers.map(t => `${t.event} => ${t.action}`).join(',')}
|
||||||
|
</Typography.Paragraph>
|
||||||
|
}
|
||||||
</Card>
|
</Card>
|
||||||
|
<Divider/>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</Skeleton>
|
</Card>
|
||||||
</Card>
|
}
|
||||||
|
</Skeleton>
|
||||||
</Flex>
|
</Flex>
|
||||||
}
|
}
|
||||||
@@ -47,7 +47,7 @@ class Domain
|
|||||||
{
|
{
|
||||||
#[ORM\Id]
|
#[ORM\Id]
|
||||||
#[ORM\Column(length: 255)]
|
#[ORM\Column(length: 255)]
|
||||||
#[Groups(['domain:item', 'domain:list', 'watchlist:item'])]
|
#[Groups(['domain:item', 'domain:list', 'watchlist:item', 'watchlist:list'])]
|
||||||
private ?string $ldhName = null;
|
private ?string $ldhName = null;
|
||||||
|
|
||||||
#[ORM\Column(length: 255, nullable: true)]
|
#[ORM\Column(length: 255, nullable: true)]
|
||||||
|
|||||||
@@ -58,14 +58,14 @@ class WatchList
|
|||||||
#[ORM\JoinTable(name: 'watch_lists_domains',
|
#[ORM\JoinTable(name: 'watch_lists_domains',
|
||||||
joinColumns: [new ORM\JoinColumn(name: 'watch_list_token', referencedColumnName: 'token')],
|
joinColumns: [new ORM\JoinColumn(name: 'watch_list_token', referencedColumnName: 'token')],
|
||||||
inverseJoinColumns: [new ORM\JoinColumn(name: 'domain_ldh_name', referencedColumnName: 'ldh_name')])]
|
inverseJoinColumns: [new ORM\JoinColumn(name: 'domain_ldh_name', referencedColumnName: 'ldh_name')])]
|
||||||
#[Groups(['watchlist:item', 'watchlist:create', 'watchlist:update'])]
|
#[Groups(['watchlist:list', 'watchlist:item', 'watchlist:create', 'watchlist:update'])]
|
||||||
private Collection $domains;
|
private Collection $domains;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var Collection<int, WatchListTrigger>
|
* @var Collection<int, WatchListTrigger>
|
||||||
*/
|
*/
|
||||||
#[ORM\OneToMany(targetEntity: WatchListTrigger::class, mappedBy: 'watchList', cascade: ['persist'], orphanRemoval: true)]
|
#[ORM\OneToMany(targetEntity: WatchListTrigger::class, mappedBy: 'watchList', cascade: ['persist'], orphanRemoval: true)]
|
||||||
#[Groups(['watchlist:item', 'watchlist:create', 'watchlist:update'])]
|
#[Groups(['watchlist:list', 'watchlist:item', 'watchlist:create', 'watchlist:update'])]
|
||||||
#[SerializedName("triggers")]
|
#[SerializedName("triggers")]
|
||||||
private Collection $watchListTriggers;
|
private Collection $watchListTriggers;
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ class WatchListTrigger
|
|||||||
{
|
{
|
||||||
#[ORM\Id]
|
#[ORM\Id]
|
||||||
#[ORM\Column(length: 255)]
|
#[ORM\Column(length: 255)]
|
||||||
#[Groups(['watchlist:item', 'watchlist:create', 'watchlist:update'])]
|
#[Groups(['watchlist:list', 'watchlist:item', 'watchlist:create', 'watchlist:update'])]
|
||||||
private ?string $event = null;
|
private ?string $event = null;
|
||||||
|
|
||||||
#[ORM\Id]
|
#[ORM\Id]
|
||||||
@@ -23,7 +23,7 @@ class WatchListTrigger
|
|||||||
|
|
||||||
#[ORM\Id]
|
#[ORM\Id]
|
||||||
#[ORM\Column(enumType: TriggerAction::class)]
|
#[ORM\Column(enumType: TriggerAction::class)]
|
||||||
#[Groups(['watchlist:item', 'watchlist:create', 'watchlist:update'])]
|
#[Groups(['watchlist:list', 'watchlist:item', 'watchlist:create', 'watchlist:update'])]
|
||||||
private ?TriggerAction $action = null;
|
private ?TriggerAction $action = null;
|
||||||
|
|
||||||
public function getEvent(): ?string
|
public function getEvent(): ?string
|
||||||
|
|||||||
Reference in New Issue
Block a user