mirror of
https://github.com/maelgangloff/domain-watchdog.git
synced 2025-12-29 16:15:04 +00:00
Merge pull request #14 from vinceh121/master
fix: various fixes for responsivity
This commit is contained in:
@@ -32,6 +32,7 @@ import ConnectorsPage from "./pages/tracking/ConnectorsPage";
|
|||||||
import NotFoundPage from "./pages/NotFoundPage";
|
import NotFoundPage from "./pages/NotFoundPage";
|
||||||
import {ItemType, MenuItemType} from "antd/lib/menu/interface";
|
import {ItemType, MenuItemType} from "antd/lib/menu/interface";
|
||||||
import {t} from 'ttag'
|
import {t} from 'ttag'
|
||||||
|
import useBreakpoint from "./hooks/useBreakpoint";
|
||||||
|
|
||||||
export default function App() {
|
export default function App() {
|
||||||
const {
|
const {
|
||||||
@@ -40,6 +41,7 @@ export default function App() {
|
|||||||
|
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
|
const sm = useBreakpoint('sm')
|
||||||
|
|
||||||
|
|
||||||
const [isAuthenticated, setIsAuthenticated] = useState(false)
|
const [isAuthenticated, setIsAuthenticated] = useState(false)
|
||||||
@@ -184,7 +186,8 @@ export default function App() {
|
|||||||
|
|
||||||
return <AuthenticatedContext.Provider value={contextValue}>
|
return <AuthenticatedContext.Provider value={contextValue}>
|
||||||
<Layout hasSider style={{minHeight: '100vh'}}>
|
<Layout hasSider style={{minHeight: '100vh'}}>
|
||||||
<Layout.Sider collapsible>
|
{/* Ant will use a break-off tab to toggle the collapse of the sider when collapseWidth = 0*/}
|
||||||
|
<Layout.Sider collapsible breakpoint="sm" {...(sm ? {collapsedWidth: 0} : {})}>
|
||||||
<Menu
|
<Menu
|
||||||
defaultSelectedKeys={['home']}
|
defaultSelectedKeys={['home']}
|
||||||
defaultOpenKeys={['search', 'info', 'tracking', 'watchdog']}
|
defaultOpenKeys={['search', 'info', 'tracking', 'watchdog']}
|
||||||
@@ -203,11 +206,10 @@ export default function App() {
|
|||||||
onClick: () => navigate('/login')
|
onClick: () => navigate('/login')
|
||||||
}]}
|
}]}
|
||||||
/>
|
/>
|
||||||
<div className="demo-logo-vertical"></div>
|
|
||||||
</Layout.Sider>
|
</Layout.Sider>
|
||||||
<Layout>
|
<Layout>
|
||||||
<Layout.Header style={{padding: 0, background: colorBgContainer}}/>
|
<Layout.Header style={{padding: 0, background: colorBgContainer}}/>
|
||||||
<Layout.Content style={{margin: '24px 16px 0'}}>
|
<Layout.Content style={sm ? {margin: '24px 0'} : {margin: '24px 16px 0'}}>
|
||||||
<div style={{
|
<div style={{
|
||||||
padding: 24,
|
padding: 24,
|
||||||
minHeight: 360,
|
minHeight: 360,
|
||||||
@@ -243,7 +245,7 @@ export default function App() {
|
|||||||
</Layout.Content>
|
</Layout.Content>
|
||||||
<Layout.Footer style={{textAlign: 'center'}}>
|
<Layout.Footer style={{textAlign: 'center'}}>
|
||||||
<Link to='https://github.com/maelgangloff/domain-watchdog'>Domain
|
<Link to='https://github.com/maelgangloff/domain-watchdog'>Domain
|
||||||
Watchdog</Link> ©{new Date().getFullYear()} Created by Maël Gangloff
|
Watchdog</Link> © {new Date().getFullYear()} Created by Maël Gangloff
|
||||||
</Layout.Footer>
|
</Layout.Footer>
|
||||||
</Layout>
|
</Layout>
|
||||||
</Layout>
|
</Layout>
|
||||||
|
|||||||
@@ -10,8 +10,10 @@ import {Timeline} from "antd";
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import {Domain} from "../../utils/api";
|
import {Domain} from "../../utils/api";
|
||||||
import {t} from "ttag";
|
import {t} from "ttag";
|
||||||
|
import useBreakpoint from "../../hooks/useBreakpoint";
|
||||||
|
|
||||||
export function EventTimeline({domain}: { domain: Domain }) {
|
export function EventTimeline({domain}: { domain: Domain }) {
|
||||||
|
const sm = useBreakpoint('sm')
|
||||||
|
|
||||||
const domainEvent = {
|
const domainEvent = {
|
||||||
registration: t`Registration`,
|
registration: t`Registration`,
|
||||||
@@ -30,7 +32,7 @@ export function EventTimeline({domain}: { domain: Domain }) {
|
|||||||
const locale = navigator.language.split('-')[0]
|
const locale = navigator.language.split('-')[0]
|
||||||
|
|
||||||
return <Timeline
|
return <Timeline
|
||||||
mode="right"
|
mode={sm ? "left" : "right"}
|
||||||
items={domain.events
|
items={domain.events
|
||||||
.sort((e1, e2) => new Date(e2.date).getTime() - new Date(e1.date).getTime())
|
.sort((e1, e2) => new Date(e2.date).getTime() - new Date(e1.date).getTime())
|
||||||
.map(({action, date}) => {
|
.map(({action, date}) => {
|
||||||
@@ -56,12 +58,21 @@ export function EventTimeline({domain}: { domain: Domain }) {
|
|||||||
dot = <ReloadOutlined style={{fontSize: '16px'}}/>
|
dot = <ReloadOutlined style={{fontSize: '16px'}}/>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const eventName = Object.keys(domainEvent).includes(action) ? domainEvent[action as keyof typeof domainEvent] : action
|
||||||
|
const dateStr = new Date(date).toLocaleString(locale)
|
||||||
|
|
||||||
|
const text = sm ? {
|
||||||
|
children: <>{eventName} {dateStr}</>
|
||||||
|
} : {
|
||||||
|
label: dateStr,
|
||||||
|
children: eventName,
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
label: new Date(date).toLocaleString(locale),
|
|
||||||
children: Object.keys(domainEvent).includes(action) ? domainEvent[action as keyof typeof domainEvent] : action,
|
|
||||||
color,
|
color,
|
||||||
dot,
|
dot,
|
||||||
pending: new Date(date).getTime() > new Date().getTime()
|
pending: new Date(date).getTime() > new Date().getTime(),
|
||||||
|
...text
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -209,10 +209,17 @@ export function WatchlistForm({form, connectors, onCreateWatchlist}: {
|
|||||||
</Form.List>
|
</Form.List>
|
||||||
<Form.Item label={t`Connector`}
|
<Form.Item label={t`Connector`}
|
||||||
name='connector'
|
name='connector'
|
||||||
|
labelCol={{
|
||||||
|
xs: {span: 24},
|
||||||
|
sm: {span: 4},
|
||||||
|
}}
|
||||||
|
wrapperCol={{
|
||||||
|
md: {span: 12},
|
||||||
|
sm: {span: 20},
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<Select showSearch
|
<Select showSearch
|
||||||
allowClear
|
allowClear
|
||||||
style={{width: '60%'}}
|
|
||||||
placeholder={t`Connector`}
|
placeholder={t`Connector`}
|
||||||
suffixIcon={<ApiOutlined/>}
|
suffixIcon={<ApiOutlined/>}
|
||||||
optionFilterProp="label"
|
optionFilterProp="label"
|
||||||
|
|||||||
@@ -1,23 +1,29 @@
|
|||||||
import {Card, Divider, Popconfirm, Typography} from "antd";
|
import {Card, Divider, Popconfirm, Typography, theme} from "antd";
|
||||||
import {t} from "ttag";
|
import {t} from "ttag";
|
||||||
import {deleteWatchlist, EventAction} from "../../utils/api";
|
import {deleteWatchlist, EventAction} from "../../utils/api";
|
||||||
import {DeleteFilled} from "@ant-design/icons";
|
import {DeleteFilled} from "@ant-design/icons";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
|
const { useToken } = theme;
|
||||||
|
|
||||||
type Watchlist = { token: string, domains: { ldhName: string }[], triggers?: { event: EventAction, action: string }[] }
|
type Watchlist = { token: string, domains: { ldhName: string }[], triggers?: { event: EventAction, action: string }[] }
|
||||||
|
|
||||||
|
|
||||||
export function WatchlistsList({watchlists, onDelete}: { watchlists: Watchlist[], onDelete: () => void }) {
|
export function WatchlistsList({watchlists, onDelete}: { watchlists: Watchlist[], onDelete: () => void }) {
|
||||||
|
const { token } = useToken()
|
||||||
|
|
||||||
return <>
|
return <>
|
||||||
{watchlists.map(watchlist =>
|
{watchlists.map(watchlist =>
|
||||||
<>
|
<>
|
||||||
<Card title={t`Watchlist ${watchlist.token}`} extra={<Popconfirm
|
<Card title={t`Watchlist`} type="inner" extra={<Popconfirm
|
||||||
title={t`Delete the Watchlist`}
|
title={t`Delete the Watchlist`}
|
||||||
description={t`Are you sure to delete this Watchlist?`}
|
description={t`Are you sure to delete this Watchlist?`}
|
||||||
onConfirm={() => deleteWatchlist(watchlist.token).then(onDelete)}
|
onConfirm={() => deleteWatchlist(watchlist.token).then(onDelete)}
|
||||||
okText={t`Yes`}
|
okText={t`Yes`}
|
||||||
cancelText={t`No`}
|
cancelText={t`No`}
|
||||||
><DeleteFilled/></Popconfirm>}>
|
okButtonProps={{danger: true}}
|
||||||
|
><DeleteFilled style={{color: token.colorError}} /></Popconfirm>}>
|
||||||
|
<Card.Meta description={watchlist.token} style={{marginBottom: '1em'}} />
|
||||||
<Typography.Paragraph>
|
<Typography.Paragraph>
|
||||||
{t`Domain name`} : {watchlist?.domains.map(d => d.ldhName).join(',')}
|
{t`Domain name`} : {watchlist?.domains.map(d => d.ldhName).join(',')}
|
||||||
</Typography.Paragraph>
|
</Typography.Paragraph>
|
||||||
|
|||||||
19
assets/hooks/useBreakpoint.tsx
Normal file
19
assets/hooks/useBreakpoint.tsx
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import { Breakpoint, theme } from 'antd';
|
||||||
|
import { useMediaQuery } from 'react-responsive';
|
||||||
|
|
||||||
|
const { useToken } = theme;
|
||||||
|
|
||||||
|
type ScreenProperty = 'screenXXL' | 'screenXL' | 'screenLG' | 'screenMD' | 'screenSM' | 'screenXS';
|
||||||
|
|
||||||
|
const propertyName = (breakpoint: Breakpoint): ScreenProperty => {
|
||||||
|
return 'screen' + breakpoint.toUpperCase() as ScreenProperty
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function useBreakpoint(
|
||||||
|
breakpoint: Breakpoint
|
||||||
|
) {
|
||||||
|
const { token } = useToken()
|
||||||
|
const width: number = token[propertyName(breakpoint)]
|
||||||
|
|
||||||
|
return useMediaQuery({maxWidth: width})
|
||||||
|
}
|
||||||
@@ -1,3 +1,15 @@
|
|||||||
|
@font-face {
|
||||||
|
font-family: "Noto Color Emoji";
|
||||||
|
font-style: normal;
|
||||||
|
font-display: swap;
|
||||||
|
font-weight: 400;
|
||||||
|
src: url(@fontsource/noto-color-emoji/files/noto-color-emoji-emoji-400-normal.woff2)
|
||||||
|
format("woff2"),
|
||||||
|
url(@fontsource/noto-color-emoji/files/noto-color-emoji-emoji-400-normal.woff)
|
||||||
|
format("woff");
|
||||||
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
font-family: "Noto Color Emoji", sans-serif;
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ import {HashRouter} from "react-router-dom";
|
|||||||
import 'antd/dist/reset.css';
|
import 'antd/dist/reset.css';
|
||||||
import './i18n'
|
import './i18n'
|
||||||
|
|
||||||
|
import './index.css'
|
||||||
|
|
||||||
|
|
||||||
const root = ReactDOM.createRoot(document.getElementById("root") as HTMLElement)
|
const root = ReactDOM.createRoot(document.getElementById("root") as HTMLElement)
|
||||||
|
|
||||||
|
|||||||
@@ -3,49 +3,65 @@ import {Collapse, Divider, Table, Typography} from "antd";
|
|||||||
import {getTldList, Tld} from "../../utils/api";
|
import {getTldList, Tld} from "../../utils/api";
|
||||||
import {t} from 'ttag'
|
import {t} from 'ttag'
|
||||||
import {regionNames} from "../../i18n";
|
import {regionNames} from "../../i18n";
|
||||||
|
import useBreakpoint from "../../hooks/useBreakpoint";
|
||||||
|
import { ColumnType } from "antd/es/table";
|
||||||
|
|
||||||
const {Text, Paragraph} = Typography
|
const {Text, Paragraph} = Typography
|
||||||
|
|
||||||
type TldType = 'iTLD' | 'sTLD' | 'gTLD' | 'ccTLD'
|
type TldType = 'iTLD' | 'sTLD' | 'gTLD' | 'ccTLD'
|
||||||
type FiltersType = { type: TldType, contractTerminated?: boolean, specification13?: boolean }
|
type FiltersType = { type: TldType, contractTerminated?: boolean, specification13?: boolean }
|
||||||
|
|
||||||
|
const toEmoji = (tld: string) => {
|
||||||
|
if (tld.startsWith('xn--')) return '-'
|
||||||
|
|
||||||
const toEmoji = (tld: string) => String.fromCodePoint(
|
return String.fromCodePoint(
|
||||||
...getCountryCode(tld)
|
...getCountryCode(tld)
|
||||||
.toUpperCase()
|
.toUpperCase()
|
||||||
.split('')
|
.split('')
|
||||||
.map((char) => 127397 + char.charCodeAt(0)
|
.map((char) => 127397 + char.charCodeAt(0))
|
||||||
)
|
)
|
||||||
)
|
}
|
||||||
|
|
||||||
const getCountryCode = (tld: string): string => {
|
const getCountryCode = (tld: string): string => {
|
||||||
const exceptions = {uk: 'gb', su: 'ru', tp: 'tl'}
|
const exceptions = {uk: 'gb', su: 'ru', tp: 'tl'}
|
||||||
if (tld in exceptions) return exceptions[tld as keyof typeof exceptions]
|
if (tld in exceptions) return exceptions[tld as keyof typeof exceptions]
|
||||||
return tld
|
return tld.toUpperCase()
|
||||||
}
|
}
|
||||||
|
|
||||||
function TldTable(filters: FiltersType) {
|
function TldTable(filters: FiltersType) {
|
||||||
|
const sm = useBreakpoint('sm')
|
||||||
const [dataTable, setDataTable] = useState<Tld[]>([])
|
const [dataTable, setDataTable] = useState<Tld[]>([])
|
||||||
const [total, setTotal] = useState(0)
|
const [total, setTotal] = useState(0)
|
||||||
|
|
||||||
const fetchData = (params: FiltersType & { page: number }) => {
|
const fetchData = (params: FiltersType & { page: number, itemsPerPage: number }) => {
|
||||||
getTldList(params).then((data) => {
|
getTldList(params).then((data) => {
|
||||||
setTotal(data['hydra:totalItems'])
|
setTotal(data['hydra:totalItems'])
|
||||||
setDataTable(data['hydra:member'].map((tld: Tld) => {
|
setDataTable(data['hydra:member'].map((tld: Tld) => {
|
||||||
switch (filters.type) {
|
switch (filters.type) {
|
||||||
case 'ccTLD':
|
case 'ccTLD':
|
||||||
|
let countryName
|
||||||
|
|
||||||
|
try {
|
||||||
|
countryName = regionNames.of(getCountryCode(tld.tld))
|
||||||
|
} catch(e) {
|
||||||
|
countryName = '-'
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
key: tld.tld,
|
||||||
TLD: tld.tld,
|
TLD: tld.tld,
|
||||||
Flag: toEmoji(tld.tld),
|
Flag: toEmoji(tld.tld),
|
||||||
Country: regionNames.of(getCountryCode(tld.tld)) ?? '-'
|
Country: countryName
|
||||||
}
|
}
|
||||||
case 'gTLD':
|
case 'gTLD':
|
||||||
return {
|
return {
|
||||||
|
key: tld.tld,
|
||||||
TLD: tld.tld,
|
TLD: tld.tld,
|
||||||
Operator: tld.registryOperator
|
Operator: tld.registryOperator
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return {
|
return {
|
||||||
|
key: tld.tld,
|
||||||
TLD: tld.tld
|
TLD: tld.tld
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -54,31 +70,27 @@ function TldTable(filters: FiltersType) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchData({...filters, page: 1})
|
fetchData({...filters, page: 1, itemsPerPage: 30})
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
let columns = [
|
let columns: ColumnType<any>[] = [
|
||||||
{
|
{
|
||||||
title: t`TLD`,
|
title: t`TLD`,
|
||||||
dataIndex: "TLD",
|
dataIndex: "TLD"
|
||||||
width: 20
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
if (filters.type === 'ccTLD') columns = [...columns, {
|
if (filters.type === 'ccTLD') columns = [...columns, {
|
||||||
title: t`Flag`,
|
title: t`Flag`,
|
||||||
dataIndex: "Flag",
|
dataIndex: "Flag",
|
||||||
width: 20
|
|
||||||
}, {
|
}, {
|
||||||
title: t`Country`,
|
title: t`Country`,
|
||||||
dataIndex: "Country",
|
dataIndex: "Country"
|
||||||
width: 200
|
|
||||||
}]
|
}]
|
||||||
|
|
||||||
if (filters.type === 'gTLD') columns = [...columns, {
|
if (filters.type === 'gTLD') columns = [...columns, {
|
||||||
title: t`Registry Operator`,
|
title: t`Registry Operator`,
|
||||||
dataIndex: "Operator",
|
dataIndex: "Operator"
|
||||||
width: 50
|
|
||||||
}]
|
}]
|
||||||
|
|
||||||
|
|
||||||
@@ -87,18 +99,21 @@ function TldTable(filters: FiltersType) {
|
|||||||
dataSource={dataTable}
|
dataSource={dataTable}
|
||||||
pagination={{
|
pagination={{
|
||||||
total,
|
total,
|
||||||
pageSize: 30,
|
|
||||||
hideOnSinglePage: true,
|
hideOnSinglePage: true,
|
||||||
onChange: (page, pageSize) => {
|
defaultPageSize: 30,
|
||||||
fetchData({...filters, page})
|
onChange: (page, itemsPerPage) => {
|
||||||
|
fetchData({...filters, page, itemsPerPage})
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
scroll={{y: 240}}
|
|
||||||
|
{...(sm ? {scroll: {y: 'max-content'}} : {scroll: {y: 240}})}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export default function TldPage() {
|
export default function TldPage() {
|
||||||
|
const sm = useBreakpoint('sm')
|
||||||
|
|
||||||
return <>
|
return <>
|
||||||
<Paragraph>
|
<Paragraph>
|
||||||
{t`This page presents all active TLDs in the root zone database.`}
|
{t`This page presents all active TLDs in the root zone database.`}
|
||||||
@@ -111,7 +126,7 @@ export default function TldPage() {
|
|||||||
</Paragraph>
|
</Paragraph>
|
||||||
<Divider/>
|
<Divider/>
|
||||||
<Collapse
|
<Collapse
|
||||||
size="large"
|
size={sm ? 'small' : 'large'}
|
||||||
items={[
|
items={[
|
||||||
{
|
{
|
||||||
key: 'sTLD',
|
key: 'sTLD',
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React, {useState} from "react";
|
import React, {useState} from "react";
|
||||||
import {Badge, Card, Divider, Empty, Flex, FormProps, message, Skeleton, Space, Tag} from "antd";
|
import {Badge, Card, Divider, Empty, Flex, FormProps, message, Skeleton, Space, Tag, Typography} from "antd";
|
||||||
import {Domain, getDomain} from "../../utils/api";
|
import {Domain, getDomain} from "../../utils/api";
|
||||||
import {AxiosError} from "axios"
|
import {AxiosError} from "axios"
|
||||||
import {t} from 'ttag'
|
import {t} from 'ttag'
|
||||||
@@ -7,6 +7,7 @@ import {DomainSearchBar, FieldType} from "../../components/search/DomainSearchBa
|
|||||||
import {EventTimeline} from "../../components/search/EventTimeline";
|
import {EventTimeline} from "../../components/search/EventTimeline";
|
||||||
import {EntitiesList} from "../../components/search/EntitiesList";
|
import {EntitiesList} from "../../components/search/EntitiesList";
|
||||||
|
|
||||||
|
const { Text } = Typography;
|
||||||
|
|
||||||
export default function DomainSearchPage() {
|
export default function DomainSearchPage() {
|
||||||
const [domain, setDomain] = useState<Domain | null>()
|
const [domain, setDomain] = useState<Domain | null>()
|
||||||
@@ -40,7 +41,7 @@ export default function DomainSearchPage() {
|
|||||||
domain.tld.type === 'gTLD' ? "green"
|
domain.tld.type === 'gTLD' ? "green"
|
||||||
: "cyan"
|
: "cyan"
|
||||||
}>
|
}>
|
||||||
<Card title={`${domain.ldhName}${domain.handle ? ' (' + domain.handle + ')' : ''}`}
|
<Card title={<>{domain.ldhName}{domain.handle ? <> (<Text code>{domain.handle}</Text>)</>: undefined}</>}
|
||||||
size="small">
|
size="small">
|
||||||
{domain.status.length > 0 &&
|
{domain.status.length > 0 &&
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React, {useEffect, useState} from "react";
|
import React, {useEffect, useState} from "react";
|
||||||
import {Card, Flex, Form, message, Skeleton} from "antd";
|
import {Card, Divider, Flex, Form, message, Skeleton} from "antd";
|
||||||
import {EventAction, getWatchlists, postWatchlist} from "../../utils/api";
|
import {EventAction, getWatchlists, postWatchlist} from "../../utils/api";
|
||||||
import {AxiosError} from "axios";
|
import {AxiosError} from "axios";
|
||||||
import {t} from 'ttag'
|
import {t} from 'ttag'
|
||||||
@@ -33,7 +33,7 @@ export default function WatchlistPage() {
|
|||||||
messageApi.success(t`Watchlist created !`)
|
messageApi.success(t`Watchlist created !`)
|
||||||
}).catch((e: AxiosError) => {
|
}).catch((e: AxiosError) => {
|
||||||
const data = e?.response?.data as { detail: string }
|
const data = e?.response?.data as { detail: string }
|
||||||
messageApi.error(data.detail ?? t`An error occurred`)
|
messageApi.error(data?.detail ?? t`An error occurred`)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,13 +41,18 @@ export default function WatchlistPage() {
|
|||||||
setWatchlists(w['hydra:member'])
|
setWatchlists(w['hydra:member'])
|
||||||
}).catch((e: AxiosError) => {
|
}).catch((e: AxiosError) => {
|
||||||
const data = e?.response?.data as { detail: string }
|
const data = e?.response?.data as { detail: string }
|
||||||
messageApi.error(data.detail ?? t`An error occurred`)
|
messageApi.error(data?.detail ?? t`An error occurred`)
|
||||||
setWatchlists(undefined)
|
setWatchlists(undefined)
|
||||||
})
|
})
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
refreshWatchlists()
|
refreshWatchlists()
|
||||||
getConnectors().then(c => setConnectors(c['hydra:member']))
|
getConnectors()
|
||||||
|
.then(c => setConnectors(c['hydra:member']))
|
||||||
|
.catch((e: AxiosError) => {
|
||||||
|
const data = e?.response?.data as { detail: string }
|
||||||
|
messageApi.error(data?.detail ?? t`An error occurred`)
|
||||||
|
})
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
return <Flex gap="middle" align="center" justify="center" vertical>
|
return <Flex gap="middle" align="center" justify="center" vertical>
|
||||||
@@ -59,12 +64,10 @@ export default function WatchlistPage() {
|
|||||||
}
|
}
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
|
<Divider />
|
||||||
|
|
||||||
<Skeleton loading={watchlists === undefined} active>
|
<Card size="small" loading={!watchlists} title={t`My Watchlists`} style={{width: '100%'}}>
|
||||||
{watchlists && watchlists.length > 0 && <Card title={t`My Watchlists`} style={{width: '100%'}}>
|
{watchlists && watchlists.length > 0 && <WatchlistsList watchlists={watchlists} onDelete={refreshWatchlists}/>}
|
||||||
<WatchlistsList watchlists={watchlists} onDelete={refreshWatchlists}/>
|
</Card>
|
||||||
</Card>
|
|
||||||
}
|
|
||||||
</Skeleton>
|
|
||||||
</Flex>
|
</Flex>
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
api_platform:
|
api_platform:
|
||||||
title: Domain Watchdog API
|
title: Domain Watchdog API
|
||||||
version: 1.0.0
|
version: 1.0.0
|
||||||
|
|
||||||
formats:
|
formats:
|
||||||
jsonld: [ 'application/ld+json' ]
|
jsonld: [ 'application/ld+json' ]
|
||||||
xml: [ 'application/xml' ]
|
xml: [ 'application/xml' ]
|
||||||
@@ -13,6 +14,7 @@ api_platform:
|
|||||||
stateless: true
|
stateless: true
|
||||||
cache_headers:
|
cache_headers:
|
||||||
vary: [ 'Content-Type', 'Authorization', 'Origin' ]
|
vary: [ 'Content-Type', 'Authorization', 'Origin' ]
|
||||||
|
pagination_client_items_per_page: true
|
||||||
extra_properties:
|
extra_properties:
|
||||||
standard_put: true
|
standard_put: true
|
||||||
rfc_7807_compliant_errors: true
|
rfc_7807_compliant_errors: true
|
||||||
|
|||||||
@@ -18,12 +18,14 @@
|
|||||||
"@babel/core": "^7.17.0",
|
"@babel/core": "^7.17.0",
|
||||||
"@babel/preset-env": "^7.16.0",
|
"@babel/preset-env": "^7.16.0",
|
||||||
"@babel/preset-react": "^7.24.7",
|
"@babel/preset-react": "^7.24.7",
|
||||||
|
"@fontsource/noto-color-emoji": "^5.0.27",
|
||||||
"@symfony/webpack-encore": "^4.0.0",
|
"@symfony/webpack-encore": "^4.0.0",
|
||||||
"@types/axios": "^0.14.0",
|
"@types/axios": "^0.14.0",
|
||||||
"@types/jsonld": "^1.5.15",
|
"@types/jsonld": "^1.5.15",
|
||||||
"@types/punycode": "^2.1.4",
|
"@types/punycode": "^2.1.4",
|
||||||
"@types/react": "^18.3.3",
|
"@types/react": "^18.3.3",
|
||||||
"@types/react-dom": "^18.3.0",
|
"@types/react-dom": "^18.3.0",
|
||||||
|
"@types/react-responsive": "^8.0.8",
|
||||||
"@types/vcf": "^2.0.7",
|
"@types/vcf": "^2.0.7",
|
||||||
"antd": "^5.19.3",
|
"antd": "^5.19.3",
|
||||||
"axios": "^1.7.2",
|
"axios": "^1.7.2",
|
||||||
@@ -33,6 +35,7 @@
|
|||||||
"punycode": "^2.3.1",
|
"punycode": "^2.3.1",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
|
"react-responsive": "^10.0.0",
|
||||||
"react-router-dom": "^6.25.1",
|
"react-router-dom": "^6.25.1",
|
||||||
"regenerator-runtime": "^0.13.9",
|
"regenerator-runtime": "^0.13.9",
|
||||||
"snarkdown": "^2.0.0",
|
"snarkdown": "^2.0.0",
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
"name": "Domain Watchdog",
|
"name": "Domain Watchdog",
|
||||||
"short_name": "Domain Watch",
|
"short_name": "Domain Watch",
|
||||||
"start_url": ".",
|
"start_url": ".",
|
||||||
"orientation": "landscape",
|
|
||||||
"display": "standalone",
|
"display": "standalone",
|
||||||
"background_color": "#fff",
|
"background_color": "#fff",
|
||||||
"description": "A standalone app that collects open access information about domain names, helping users track the history and changes associated with domain names. "
|
"description": "A standalone app that collects open access information about domain names, helping users track the history and changes associated with domain names. "
|
||||||
|
|||||||
62
yarn.lock
62
yarn.lock
@@ -1499,6 +1499,11 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@fastify/busboy/-/busboy-2.1.1.tgz#b9da6a878a371829a0502c9b6c1c143ef6663f4d"
|
resolved "https://registry.yarnpkg.com/@fastify/busboy/-/busboy-2.1.1.tgz#b9da6a878a371829a0502c9b6c1c143ef6663f4d"
|
||||||
integrity sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==
|
integrity sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==
|
||||||
|
|
||||||
|
"@fontsource/noto-color-emoji@^5.0.27":
|
||||||
|
version "5.0.27"
|
||||||
|
resolved "https://registry.yarnpkg.com/@fontsource/noto-color-emoji/-/noto-color-emoji-5.0.27.tgz#61e40657bea980553bde8fd2d566104bd2859ad6"
|
||||||
|
integrity sha512-gsIMN5o8qoRLrA+XyDNKKnMNpTbwpNbINisJqirLOLXl83arOV2sHRnNOkVht2gzUcImUxEUBGektp56G3Vj9w==
|
||||||
|
|
||||||
"@jest/schemas@^29.6.3":
|
"@jest/schemas@^29.6.3":
|
||||||
version "29.6.3"
|
version "29.6.3"
|
||||||
resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.6.3.tgz#430b5ce8a4e0044a7e3819663305a7b3091c8e03"
|
resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.6.3.tgz#430b5ce8a4e0044a7e3819663305a7b3091c8e03"
|
||||||
@@ -1886,6 +1891,13 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@types/react" "*"
|
"@types/react" "*"
|
||||||
|
|
||||||
|
"@types/react-responsive@^8.0.8":
|
||||||
|
version "8.0.8"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/react-responsive/-/react-responsive-8.0.8.tgz#e351be7cc4d03bc476075839922bb5f9a3094e76"
|
||||||
|
integrity sha512-HDUZtoeFRHrShCGaND23HmXAB9evOOTjkghd2wAasLkuorYYitm5A1XLeKkhXKZppcMBxqB/8V4Snl6hRUTA8g==
|
||||||
|
dependencies:
|
||||||
|
"@types/react" "*"
|
||||||
|
|
||||||
"@types/react@*", "@types/react@^18.3.3":
|
"@types/react@*", "@types/react@^18.3.3":
|
||||||
version "18.3.3"
|
version "18.3.3"
|
||||||
resolved "https://registry.yarnpkg.com/@types/react/-/react-18.3.3.tgz#9679020895318b0915d7a3ab004d92d33375c45f"
|
resolved "https://registry.yarnpkg.com/@types/react/-/react-18.3.3.tgz#9679020895318b0915d7a3ab004d92d33375c45f"
|
||||||
@@ -2932,6 +2944,11 @@ css-loader@^6.7.0:
|
|||||||
postcss-value-parser "^4.2.0"
|
postcss-value-parser "^4.2.0"
|
||||||
semver "^7.5.4"
|
semver "^7.5.4"
|
||||||
|
|
||||||
|
css-mediaquery@^0.1.2:
|
||||||
|
version "0.1.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/css-mediaquery/-/css-mediaquery-0.1.2.tgz#6a2c37344928618631c54bd33cedd301da18bea0"
|
||||||
|
integrity sha512-COtn4EROW5dBGlE/4PiKnh6rZpAPxDeFLaEEwt4i10jpDMFt2EhQGS79QmmrO+iKCHv0PU/HrOWEhijFd1x99Q==
|
||||||
|
|
||||||
css-minimizer-webpack-plugin@^5.0.0:
|
css-minimizer-webpack-plugin@^5.0.0:
|
||||||
version "5.0.1"
|
version "5.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-5.0.1.tgz#33effe662edb1a0bf08ad633c32fa75d0f7ec565"
|
resolved "https://registry.yarnpkg.com/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-5.0.1.tgz#33effe662edb1a0bf08ad633c32fa75d0f7ec565"
|
||||||
@@ -4058,6 +4075,11 @@ hunspell-spellchecker@^1.0.2:
|
|||||||
resolved "https://registry.yarnpkg.com/hunspell-spellchecker/-/hunspell-spellchecker-1.0.2.tgz#a10b0bd2fa00a65ab62a4c6b734ce496d318910e"
|
resolved "https://registry.yarnpkg.com/hunspell-spellchecker/-/hunspell-spellchecker-1.0.2.tgz#a10b0bd2fa00a65ab62a4c6b734ce496d318910e"
|
||||||
integrity sha512-4DwmFAvlz+ChsqLDsZT2cwBsYNXh+oWboemxXtafwKIyItq52xfR4e4kr017sLAoPaSYVofSOvPUfmOAhXyYvw==
|
integrity sha512-4DwmFAvlz+ChsqLDsZT2cwBsYNXh+oWboemxXtafwKIyItq52xfR4e4kr017sLAoPaSYVofSOvPUfmOAhXyYvw==
|
||||||
|
|
||||||
|
hyphenate-style-name@^1.0.0:
|
||||||
|
version "1.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/hyphenate-style-name/-/hyphenate-style-name-1.1.0.tgz#1797bf50369588b47b72ca6d5e65374607cf4436"
|
||||||
|
integrity sha512-WDC/ui2VVRrz3jOVi+XtjqkDjiVjTtFaAGiW37k6b+ohyQ5wYDOGkvCZa8+H0nx3gyvv0+BST9xuOgIyGQ00gw==
|
||||||
|
|
||||||
iconv-lite@0.4.24:
|
iconv-lite@0.4.24:
|
||||||
version "0.4.24"
|
version "0.4.24"
|
||||||
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
|
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
|
||||||
@@ -4624,7 +4646,7 @@ log-symbols@^1.0.2:
|
|||||||
dependencies:
|
dependencies:
|
||||||
chalk "^1.0.0"
|
chalk "^1.0.0"
|
||||||
|
|
||||||
loose-envify@^1.1.0:
|
loose-envify@^1.1.0, loose-envify@^1.4.0:
|
||||||
version "1.4.0"
|
version "1.4.0"
|
||||||
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
|
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
|
||||||
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
|
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
|
||||||
@@ -4660,6 +4682,13 @@ lru-cache@^6.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
yallist "^4.0.0"
|
yallist "^4.0.0"
|
||||||
|
|
||||||
|
matchmediaquery@^0.4.2:
|
||||||
|
version "0.4.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/matchmediaquery/-/matchmediaquery-0.4.2.tgz#22582bd4ae63ad9f54c53001bba80cbed0f7eafa"
|
||||||
|
integrity sha512-wrZpoT50ehYOudhDjt/YvUJc6eUzcdFPdmbizfgvswCKNHD1/OBOHYJpHie+HXpu6bSkEGieFMYk6VuutaiRfA==
|
||||||
|
dependencies:
|
||||||
|
css-mediaquery "^0.1.2"
|
||||||
|
|
||||||
mdn-data@2.0.28:
|
mdn-data@2.0.28:
|
||||||
version "2.0.28"
|
version "2.0.28"
|
||||||
resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.28.tgz#5ec48e7bef120654539069e1ae4ddc81ca490eba"
|
resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.28.tgz#5ec48e7bef120654539069e1ae4ddc81ca490eba"
|
||||||
@@ -4882,7 +4911,7 @@ nth-check@^2.0.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
boolbase "^1.0.0"
|
boolbase "^1.0.0"
|
||||||
|
|
||||||
object-assign@^4.0.1:
|
object-assign@^4.0.1, object-assign@^4.1.1:
|
||||||
version "4.1.1"
|
version "4.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
|
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
|
||||||
integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==
|
integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==
|
||||||
@@ -5461,6 +5490,15 @@ process@^0.11.10:
|
|||||||
resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182"
|
resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182"
|
||||||
integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==
|
integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==
|
||||||
|
|
||||||
|
prop-types@^15.6.1:
|
||||||
|
version "15.8.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
|
||||||
|
integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
|
||||||
|
dependencies:
|
||||||
|
loose-envify "^1.4.0"
|
||||||
|
object-assign "^4.1.1"
|
||||||
|
react-is "^16.13.1"
|
||||||
|
|
||||||
proxy-addr@~2.0.7:
|
proxy-addr@~2.0.7:
|
||||||
version "2.0.7"
|
version "2.0.7"
|
||||||
resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025"
|
resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025"
|
||||||
@@ -5886,11 +5924,26 @@ react-dom@^18.3.1:
|
|||||||
loose-envify "^1.1.0"
|
loose-envify "^1.1.0"
|
||||||
scheduler "^0.23.2"
|
scheduler "^0.23.2"
|
||||||
|
|
||||||
|
react-is@^16.13.1:
|
||||||
|
version "16.13.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
|
||||||
|
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
|
||||||
|
|
||||||
react-is@^18.2.0:
|
react-is@^18.2.0:
|
||||||
version "18.3.1"
|
version "18.3.1"
|
||||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e"
|
resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e"
|
||||||
integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==
|
integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==
|
||||||
|
|
||||||
|
react-responsive@^10.0.0:
|
||||||
|
version "10.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-responsive/-/react-responsive-10.0.0.tgz#657c7a90823cd565f43aa5918bd8eb0cd2c91c91"
|
||||||
|
integrity sha512-N6/UiRLGQyGUqrarhBZmrSmHi2FXSD++N5VbSKsBBvWfG0ZV7asvUBluSv5lSzdMyEVjzZ6Y8DL4OHABiztDOg==
|
||||||
|
dependencies:
|
||||||
|
hyphenate-style-name "^1.0.0"
|
||||||
|
matchmediaquery "^0.4.2"
|
||||||
|
prop-types "^15.6.1"
|
||||||
|
shallow-equal "^3.1.0"
|
||||||
|
|
||||||
react-router-dom@^6.25.1:
|
react-router-dom@^6.25.1:
|
||||||
version "6.25.1"
|
version "6.25.1"
|
||||||
resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-6.25.1.tgz#b89f8d63fc8383ea4e89c44bf31c5843e1f7afa0"
|
resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-6.25.1.tgz#b89f8d63fc8383ea4e89c44bf31c5843e1f7afa0"
|
||||||
@@ -6343,6 +6396,11 @@ shallow-clone@^3.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
kind-of "^6.0.2"
|
kind-of "^6.0.2"
|
||||||
|
|
||||||
|
shallow-equal@^3.1.0:
|
||||||
|
version "3.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/shallow-equal/-/shallow-equal-3.1.0.tgz#e7a54bac629c7f248eff6c2f5b63122ba4320bec"
|
||||||
|
integrity sha512-pfVOw8QZIXpMbhBWvzBISicvToTiM5WBF1EeAUZDDSb5Dt29yl4AYbyywbJFSEsRUMr7gJaxqCdr4L3tQf9wVg==
|
||||||
|
|
||||||
shebang-command@^1.2.0:
|
shebang-command@^1.2.0:
|
||||||
version "1.2.0"
|
version "1.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"
|
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"
|
||||||
|
|||||||
Reference in New Issue
Block a user