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 {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 {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() {
|
||||
const [form] = Form.useForm()
|
||||
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 domainsURI = values.domains.map(d => '/api/domains/' + d)
|
||||
|
||||
postWatchlist(domainsURI, values.triggers).then((w) => {
|
||||
form.resetFields()
|
||||
refreshWatchlists()
|
||||
@@ -159,36 +160,61 @@ export default function WatchlistPage() {
|
||||
</>
|
||||
)}
|
||||
</Form.List>
|
||||
<Form.List name="trigers">
|
||||
{(fields, {add, remove}) => (
|
||||
<Form.List
|
||||
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) => (
|
||||
<Card
|
||||
size="small"
|
||||
title={`Trigger ${field.name + 1}`}
|
||||
{fields.map((field, index) => (
|
||||
<Form.Item
|
||||
{...(index === 0 ? formItemLayout : formItemLayoutWithOutLabel)}
|
||||
label={index === 0 ? 'Domain trigger' : ''}
|
||||
required={true}
|
||||
key={field.key}
|
||||
extra={
|
||||
<CloseOutlined
|
||||
onClick={() => {
|
||||
remove(field.name);
|
||||
}}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<Form.Item name={[field.name, 'event']}>
|
||||
<Select
|
||||
status="warning"
|
||||
options={triggerEventItems}
|
||||
|
||||
<Space wrap>
|
||||
<Form.Item {...field}
|
||||
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>
|
||||
<Form.Item name={[field.name, 'action']}>
|
||||
<Select
|
||||
options={trigerActionItems}
|
||||
/>
|
||||
</Form.Item>
|
||||
</Card>
|
||||
) : null}
|
||||
</Form.Item>
|
||||
))}
|
||||
<Divider/>
|
||||
<Form.Item>
|
||||
<Button
|
||||
type="dashed"
|
||||
@@ -196,8 +222,9 @@ export default function WatchlistPage() {
|
||||
style={{width: '60%'}}
|
||||
icon={<ThunderboltFilled/>}
|
||||
>
|
||||
Add a trigger
|
||||
Add a Trigger
|
||||
</Button>
|
||||
<Form.ErrorList errors={errors}/>
|
||||
</Form.Item>
|
||||
</>
|
||||
)}
|
||||
@@ -215,18 +242,32 @@ export default function WatchlistPage() {
|
||||
</Form>
|
||||
</Card>
|
||||
|
||||
<Card title="My Watchlists" style={{width: '100%'}}>
|
||||
<Skeleton loading={watchlists === undefined} active>
|
||||
{watchlists && watchlists.map(watchlist =>
|
||||
|
||||
<Skeleton loading={watchlists === undefined} active>
|
||||
{watchlists && watchlists.length > 0 && <Card title="My Watchlists" style={{width: '100%'}}>
|
||||
{watchlists.map(watchlist =>
|
||||
<>
|
||||
<Divider/>
|
||||
<Card title={"Watchlist " + watchlist.token} extra={<DeleteFilled onClick={() => {
|
||||
deleteWatchlist(watchlist.token).then(refreshWatchlists)
|
||||
}}/>}>
|
||||
<Card title={"Watchlist " + watchlist.token} extra={<Popconfirm
|
||||
title="Delete the Watchlist"
|
||||
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>
|
||||
<Divider/>
|
||||
</>
|
||||
)}
|
||||
</Skeleton>
|
||||
</Card>
|
||||
</Card>
|
||||
}
|
||||
</Skeleton>
|
||||
</Flex>
|
||||
}
|
||||
@@ -47,7 +47,7 @@ class Domain
|
||||
{
|
||||
#[ORM\Id]
|
||||
#[ORM\Column(length: 255)]
|
||||
#[Groups(['domain:item', 'domain:list', 'watchlist:item'])]
|
||||
#[Groups(['domain:item', 'domain:list', 'watchlist:item', 'watchlist:list'])]
|
||||
private ?string $ldhName = null;
|
||||
|
||||
#[ORM\Column(length: 255, nullable: true)]
|
||||
|
||||
@@ -58,14 +58,14 @@ class WatchList
|
||||
#[ORM\JoinTable(name: 'watch_lists_domains',
|
||||
joinColumns: [new ORM\JoinColumn(name: 'watch_list_token', referencedColumnName: 'token')],
|
||||
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;
|
||||
|
||||
/**
|
||||
* @var Collection<int, WatchListTrigger>
|
||||
*/
|
||||
#[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")]
|
||||
private Collection $watchListTriggers;
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ class WatchListTrigger
|
||||
{
|
||||
#[ORM\Id]
|
||||
#[ORM\Column(length: 255)]
|
||||
#[Groups(['watchlist:item', 'watchlist:create', 'watchlist:update'])]
|
||||
#[Groups(['watchlist:list', 'watchlist:item', 'watchlist:create', 'watchlist:update'])]
|
||||
private ?string $event = null;
|
||||
|
||||
#[ORM\Id]
|
||||
@@ -23,7 +23,7 @@ class WatchListTrigger
|
||||
|
||||
#[ORM\Id]
|
||||
#[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;
|
||||
|
||||
public function getEvent(): ?string
|
||||
|
||||
Reference in New Issue
Block a user