feat: udpate watchlist entity diagram

This commit is contained in:
Maël Gangloff 2024-08-16 13:56:52 +02:00
parent e21df5a137
commit d82aac451c
No known key found for this signature in database
GPG Key ID: 11FDC81C24A7F629
14 changed files with 223 additions and 203 deletions

View File

@ -5,8 +5,8 @@ import React from "react";
import {Domain} from "../../utils/api";
import {t} from "ttag";
export function EntitiesList({domain}: { domain: Domain }) {
const domainRole = {
export function translateRoles() {
return {
registrant: t`Registrant`,
technical: t`Technical`,
administrative: t`Administrative`,
@ -19,6 +19,10 @@ export function EntitiesList({domain}: { domain: Domain }) {
notifications: t`Notifications`,
noc: t`Noc`
}
}
export function EntitiesList({domain}: { domain: Domain }) {
const domainRole = translateRoles()
return <List
className="demo-loadmore-list"

View File

@ -1,6 +1,6 @@
import {Button, Checkbox, Form, FormInstance, Input, Popconfirm, Select, Space, Typography} from "antd";
import React, {useState} from "react";
import {Connector, ConnectorProvider} from "../../utils/api/connectors";
import {Connector, ConnectorProvider} from "../../../utils/api/connectors";
import {t} from "ttag";
import {BankOutlined} from "@ant-design/icons";
import {
@ -8,8 +8,8 @@ import {
ovhFields as ovhFieldsFunction,
ovhPricingMode as ovhPricingModeFunction,
ovhSubsidiaryList as ovhSubsidiaryListFunction
} from "../../utils/providers/ovh";
import {helpGetTokenLink, tosHyperlink} from "../../utils/providers";
} from "../../../utils/providers/ovh";
import {helpGetTokenLink, tosHyperlink} from "../../../utils/providers";
const formItemLayoutWithOutLabel = {
wrapperCol: {

View File

@ -2,7 +2,7 @@ import {Card, Divider, Popconfirm, theme, Typography} from "antd";
import {t} from "ttag";
import {DeleteFilled} from "@ant-design/icons";
import React from "react";
import {Connector, deleteConnector} from "../../utils/api/connectors";
import {Connector, deleteConnector} from "../../../utils/api/connectors";
const {useToken} = theme;

View File

@ -2,50 +2,13 @@ import {Button, Flex, Modal, Space, Typography} from "antd"
import {t} from "ttag"
import React, {useEffect, useState} from "react"
import {ApartmentOutlined} from "@ant-design/icons"
import vCard from "vcf";
import '@xyflow/react/dist/style.css'
import {Background, Controls, MiniMap, ReactFlow, useEdgesState, useNodesState} from "@xyflow/react";
import {getWatchlist, Watchlist} from "../../utils/api";
import dagre from 'dagre'
import vCard from "vcf";
const dagreGraph = new dagre.graphlib.Graph();
dagreGraph.setDefaultEdgeLabel(() => ({}));
const nodeWidth = 172;
const nodeHeight = 200;
const getLayoutedElements = (nodes: any, edges: any, direction = 'TB') => {
const isHorizontal = direction === 'LR';
dagreGraph.setGraph({rankdir: direction});
nodes.forEach((node: any) => {
dagreGraph.setNode(node.id, {width: nodeWidth, height: nodeHeight});
});
edges.forEach((edge: any) => {
dagreGraph.setEdge(edge.source, edge.target);
});
dagre.layout(dagreGraph);
const newNodes = nodes.map((node: any) => {
const nodeWithPosition = dagreGraph.node(node.id)
return {
...node,
targetPosition: isHorizontal ? 'left' : 'top',
sourcePosition: isHorizontal ? 'right' : 'bottom',
position: {
x: nodeWithPosition.x - nodeWidth / 2,
y: nodeWithPosition.y - nodeHeight / 2
},
};
});
return {nodes: newNodes, edges};
}
import {getWatchlist, Watchlist} from "../../../utils/api";
import {translateRoles} from "../../search/EntitiesList";
import {getLayoutedElements} from "./getLayoutedElements";
function watchlistToNodes(watchlist: Watchlist) {
@ -79,9 +42,12 @@ function watchlistToNodes(watchlist: Watchlist) {
}
const rolesToColor = (roles: string[]) => roles.includes('registrant') ? 'green' :
roles.includes('technical') ? 'orange' : 'black'
roles.includes('administrative') ? 'blue' :
roles.includes('technical') ? 'orange' : 'violet'
function watchlistToEdges(watchlist: Watchlist) {
const domainRole = translateRoles()
return watchlist.domains
.map(d => d.entities
.filter(e => !e.roles.includes('registrar'))
@ -90,6 +56,7 @@ function watchlistToEdges(watchlist: Watchlist) {
source: e.roles.includes('technical') ? d.ldhName : e.entity.handle,
target: e.roles.includes('technical') ? e.entity.handle : d.ldhName,
style: {stroke: rolesToColor(e.roles), strokeWidth: 3},
label: e.roles.map(r => Object.keys(domainRole).includes(r) ? domainRole[r as keyof typeof domainRole] : r).join(', '),
animated: e.roles.includes('registrant'),
}))
).flat(2)
@ -138,6 +105,10 @@ export function ViewDiagramWatchlistButton({token}: { token: string }) {
>
{nodes && edges && <Flex style={{width: '75vw', height: '80vh'}}>
<ReactFlow
fitView
colorMode='system'
nodesConnectable={false}
edgesReconnectable={false}
nodes={nodes}
edges={edges}
onNodesChange={onNodesChange}

View File

@ -0,0 +1,39 @@
import dagre from "dagre";
const dagreGraph = new dagre.graphlib.Graph();
dagreGraph.setDefaultEdgeLabel(() => ({}));
const nodeWidth = 172;
const nodeHeight = 200;
export const getLayoutedElements = (nodes: any, edges: any, direction = 'TB') => {
const isHorizontal = direction === 'LR';
dagreGraph.setGraph({rankdir: direction});
nodes.forEach((node: any) => {
dagreGraph.setNode(node.id, {width: nodeWidth, height: nodeHeight});
});
edges.forEach((edge: any) => {
dagreGraph.setEdge(edge.source, edge.target);
});
dagre.layout(dagreGraph);
const newNodes = nodes.map((node: any) => {
const nodeWithPosition = dagreGraph.node(node.id)
return {
...node,
targetPosition: isHorizontal ? 'left' : 'top',
sourcePosition: isHorizontal ? 'right' : 'bottom',
position: {
x: nodeWithPosition.x - nodeWidth / 2,
y: nodeWithPosition.y - nodeHeight / 2
},
};
});
return {nodes: newNodes, edges};
}

View File

@ -1,9 +1,9 @@
import {Popconfirm, theme, Typography} from "antd";
import {t} from "ttag";
import {deleteWatchlist} from "../../utils/api";
import {deleteWatchlist} from "../../../utils/api";
import {DeleteFilled} from "@ant-design/icons";
import React from "react";
import {Watchlist} from "../../pages/tracking/WatchlistPage";
import {Watchlist} from "../../../pages/tracking/WatchlistPage";
export function DeleteWatchlistButton({watchlist, onDelete}: { watchlist: Watchlist, onDelete: () => void }) {
const {token} = theme.useToken()

View File

@ -2,9 +2,9 @@ import {Button, Drawer, Form, Typography} from "antd";
import {t} from "ttag";
import {WatchlistForm} from "./WatchlistForm";
import React, {useState} from "react";
import {Watchlist} from "../../pages/tracking/WatchlistPage";
import {Watchlist} from "../../../pages/tracking/WatchlistPage";
import {EditOutlined} from "@ant-design/icons";
import {Connector} from "../../utils/api/connectors";
import {Connector} from "../../../utils/api/connectors";
export function UpdateWatchlistButton({watchlist, onUpdateWatchlist, connectors}: {
watchlist: Watchlist,

View File

@ -2,8 +2,8 @@ import {Button, Form, FormInstance, Input, Select, SelectProps, Space, Tag} from
import {t} from "ttag";
import {ApiOutlined, MinusCircleOutlined, PlusOutlined} from "@ant-design/icons";
import React from "react";
import {Connector} from "../../utils/api/connectors";
import {actionToColor, domainEvent} from "../search/EventTimeline";
import {Connector} from "../../../utils/api/connectors";
import {actionToColor, domainEvent} from "../../search/EventTimeline";
type TagRender = SelectProps['tagRender'];

View File

@ -2,14 +2,14 @@ import {Card, Divider, Space, Table, Tag, Typography} from "antd";
import {t} from "ttag";
import {CalendarFilled, DisconnectOutlined, LinkOutlined} from "@ant-design/icons";
import React from "react";
import useBreakpoint from "../../hooks/useBreakpoint";
import {actionToColor, domainEvent} from "../search/EventTimeline";
import {Watchlist} from "../../pages/tracking/WatchlistPage";
import useBreakpoint from "../../../hooks/useBreakpoint";
import {actionToColor, domainEvent} from "../../search/EventTimeline";
import {Watchlist} from "../../../pages/tracking/WatchlistPage";
import punycode from "punycode/punycode";
import {Connector} from "../../utils/api/connectors";
import {Connector} from "../../../utils/api/connectors";
import {UpdateWatchlistButton} from "./UpdateWatchlistButton";
import {DeleteWatchlistButton} from "./DeleteWatchlistButton";
import {ViewDiagramWatchlistButton} from "./ViewDiagramWatchlistButton";
import {ViewDiagramWatchlistButton} from "../diagram/ViewDiagramWatchlistButton";
export function WatchlistsList({watchlists, onDelete, onUpdateWatchlist, connectors}: {
watchlists: Watchlist[],

View File

@ -2,9 +2,9 @@ import React, {useEffect, useState} from "react";
import {Card, Flex, Form, message, Skeleton} from "antd";
import {t} from "ttag";
import {Connector, getConnectors, postConnector} from "../../utils/api/connectors";
import {ConnectorForm} from "../../components/tracking/ConnectorForm";
import {ConnectorForm} from "../../components/tracking/connector/ConnectorForm";
import {AxiosError} from "axios";
import {ConnectorElement, ConnectorsList} from "../../components/tracking/ConnectorsList";
import {ConnectorElement, ConnectorsList} from "../../components/tracking/connector/ConnectorsList";
import {showErrorAPI} from "../../utils";
export default function ConnectorsPage() {

View File

@ -3,8 +3,8 @@ import {Card, Divider, Flex, Form, message} from "antd";
import {EventAction, getWatchlists, putWatchlist, postWatchlist} from "../../utils/api";
import {AxiosError} from "axios";
import {t} from 'ttag'
import {WatchlistForm} from "../../components/tracking/WatchlistForm";
import {WatchlistsList} from "../../components/tracking/WatchlistsList";
import {WatchlistForm} from "../../components/tracking/watchlist/WatchlistForm";
import {WatchlistsList} from "../../components/tracking/watchlist/WatchlistsList";
import {Connector, getConnectors} from "../../utils/api/connectors";
import {showErrorAPI} from "../../utils";

View File

@ -34,6 +34,7 @@
"core-js": "^3.23.0",
"dagre": "^0.8.5",
"html-loader": "^5.1.0",
"html-to-image": "^1.11.11",
"jsonld": "^8.3.2",
"punycode": "^2.3.1",
"react": "^18.3.1",

View File

@ -13,16 +13,16 @@ msgstr ""
#: assets/components/RegisterForm.tsx:40
#: assets/components/RegisterForm.tsx:48
#: assets/components/search/DomainSearchBar.tsx:23
#: assets/components/tracking/ConnectorForm.tsx:43
#: assets/components/tracking/ConnectorForm.tsx:69
#: assets/components/tracking/ConnectorForm.tsx:77
#: assets/components/tracking/ConnectorForm.tsx:84
#: assets/components/tracking/ConnectorForm.tsx:92
#: assets/components/tracking/ConnectorForm.tsx:122
#: assets/components/tracking/ConnectorForm.tsx:142
#: assets/components/tracking/ConnectorForm.tsx:156
#: assets/components/tracking/ConnectorForm.tsx:165
#: assets/components/tracking/WatchlistForm.tsx:109
#: assets/components/tracking/connector/ConnectorForm.tsx:43
#: assets/components/tracking/connector/ConnectorForm.tsx:69
#: assets/components/tracking/connector/ConnectorForm.tsx:77
#: assets/components/tracking/connector/ConnectorForm.tsx:84
#: assets/components/tracking/connector/ConnectorForm.tsx:92
#: assets/components/tracking/connector/ConnectorForm.tsx:122
#: assets/components/tracking/connector/ConnectorForm.tsx:142
#: assets/components/tracking/connector/ConnectorForm.tsx:156
#: assets/components/tracking/connector/ConnectorForm.tsx:165
#: assets/components/tracking/watchlist/WatchlistForm.tsx:109
msgid "Required"
msgstr ""
@ -84,7 +84,7 @@ msgid "ENUM validation expiration"
msgstr ""
#: assets/components/search/DomainSearchBar.tsx:26
#: assets/components/tracking/WatchlistForm.tsx:112
#: assets/components/tracking/watchlist/WatchlistForm.tsx:112
msgid "This domain name does not appear to be valid"
msgstr ""
@ -132,203 +132,203 @@ msgstr ""
msgid "Noc"
msgstr ""
#: assets/components/tracking/WatchlistForm.tsx:66
msgid "Name"
msgstr ""
#: assets/components/tracking/WatchlistForm.tsx:77
msgid "Watchlist Name"
msgstr ""
#: assets/components/tracking/WatchlistForm.tsx:78
msgid "Naming the Watchlist makes it easier to find in the list below."
msgstr ""
#: assets/components/tracking/WatchlistForm.tsx:89
msgid "At least one domain name"
msgstr ""
#: assets/components/tracking/WatchlistForm.tsx:100
#: assets/components/tracking/WatchlistsList.tsx:26
msgid "Domain names"
msgstr ""
#: assets/components/tracking/WatchlistForm.tsx:118
msgid "Domain name"
msgstr ""
#: assets/components/tracking/WatchlistForm.tsx:135
msgid "Add a Domain name"
msgstr ""
#: assets/components/tracking/WatchlistForm.tsx:142
#: assets/components/tracking/WatchlistsList.tsx:30
msgid "Tracked events"
msgstr ""
#: assets/components/tracking/WatchlistForm.tsx:144
msgid "At least one trigger"
msgstr ""
#: assets/components/tracking/WatchlistForm.tsx:166
#: assets/components/tracking/WatchlistForm.tsx:180
msgid "Connector"
msgstr ""
#: assets/components/tracking/WatchlistForm.tsx:176
msgid ""
"Please make sure the connector information is valid to purchase a domain "
"that may be available soon."
msgstr ""
#: assets/components/tracking/ConnectorForm.tsx:176
#: assets/components/tracking/WatchlistForm.tsx:192
msgid "Create"
msgstr ""
#: assets/components/tracking/WatchlistForm.tsx:192
msgid "Update"
msgstr ""
#: assets/components/tracking/ConnectorForm.tsx:179
#: assets/components/tracking/WatchlistForm.tsx:195
msgid "Reset"
msgstr ""
#: assets/components/tracking/ViewDiagramWatchlistButton.tsx:119
msgid "View the Watchlist Entity Diagram"
msgstr ""
#: assets/components/tracking/ViewDiagramWatchlistButton.tsx:124
msgid "Watchlist Entity Diagram"
msgstr ""
#: assets/components/tracking/ConnectorForm.tsx:40
#: assets/components/tracking/connector/ConnectorForm.tsx:40
msgid "Provider"
msgstr ""
#: assets/components/tracking/ConnectorForm.tsx:47
#: assets/components/tracking/connector/ConnectorForm.tsx:47
msgid "Please select a Provider"
msgstr ""
#: assets/components/tracking/ConnectorForm.tsx:75
#: assets/components/tracking/connector/ConnectorForm.tsx:75
msgid "OVH Endpoint"
msgstr ""
#: assets/components/tracking/ConnectorForm.tsx:82
#: assets/components/tracking/connector/ConnectorForm.tsx:82
msgid "OVH subsidiary"
msgstr ""
#: assets/components/tracking/ConnectorForm.tsx:90
#: assets/components/tracking/connector/ConnectorForm.tsx:90
msgid "OVH pricing mode"
msgstr ""
#: assets/components/tracking/ConnectorForm.tsx:95
#: assets/components/tracking/connector/ConnectorForm.tsx:95
msgid "Confirm pricing mode"
msgstr ""
#: assets/components/tracking/ConnectorForm.tsx:96
#: assets/components/tracking/connector/ConnectorForm.tsx:96
msgid ""
"Are you sure about this setting? This may result in additional charges from "
"the API Provider"
msgstr ""
#: assets/components/tracking/ConnectorForm.tsx:120
#: assets/components/tracking/connector/ConnectorForm.tsx:120
msgid "Personal Access Token (PAT)"
msgstr ""
#: assets/components/tracking/ConnectorForm.tsx:126
#: assets/components/tracking/connector/ConnectorForm.tsx:126
msgid "Organization sharing ID"
msgstr ""
#: assets/components/tracking/ConnectorForm.tsx:129
#: assets/components/tracking/connector/ConnectorForm.tsx:129
msgid "It indicates the organization that will pay for the ordered product"
msgstr ""
#: assets/components/tracking/ConnectorForm.tsx:140
#: assets/components/tracking/connector/ConnectorForm.tsx:140
msgid "API Terms of Service"
msgstr ""
#: assets/components/tracking/ConnectorForm.tsx:148
#: assets/components/tracking/connector/ConnectorForm.tsx:148
msgid ""
"I have read and accepted the conditions of use of the Provider API, "
"accessible from this hyperlink"
msgstr ""
#: assets/components/tracking/ConnectorForm.tsx:154
#: assets/components/tracking/connector/ConnectorForm.tsx:154
msgid "Legal age"
msgstr ""
#: assets/components/tracking/ConnectorForm.tsx:159
#: assets/components/tracking/connector/ConnectorForm.tsx:159
msgid "I am of the minimum age required to consent to these conditions"
msgstr ""
#: assets/components/tracking/ConnectorForm.tsx:163
#: assets/components/tracking/connector/ConnectorForm.tsx:163
msgid "Withdrawal period"
msgstr ""
#: assets/components/tracking/ConnectorForm.tsx:168
#: assets/components/tracking/connector/ConnectorForm.tsx:168
msgid ""
"I waive my right of withdrawal regarding the purchase of domain names via "
"the Provider's API"
msgstr ""
#: assets/components/tracking/UpdateWatchlistButton.tsx:31
msgid "Edit the Watchlist"
#: assets/components/tracking/connector/ConnectorForm.tsx:176
#: assets/components/tracking/watchlist/WatchlistForm.tsx:192
msgid "Create"
msgstr ""
#: assets/components/tracking/UpdateWatchlistButton.tsx:43
msgid "Update a Watchlist"
#: assets/components/tracking/connector/ConnectorForm.tsx:179
#: assets/components/tracking/watchlist/WatchlistForm.tsx:195
msgid "Reset"
msgstr ""
#: assets/components/tracking/UpdateWatchlistButton.tsx:53
msgid "Cancel"
msgstr ""
#: assets/components/tracking/DeleteWatchlistButton.tsx:12
#: assets/components/tracking/DeleteWatchlistButton.tsx:19
msgid "Delete the Watchlist"
msgstr ""
#: assets/components/tracking/DeleteWatchlistButton.tsx:13
msgid "Are you sure to delete this Watchlist?"
msgstr ""
#: assets/components/tracking/ConnectorsList.tsx:25
#: assets/components/tracking/DeleteWatchlistButton.tsx:15
msgid "Yes"
msgstr ""
#: assets/components/tracking/ConnectorsList.tsx:26
#: assets/components/tracking/DeleteWatchlistButton.tsx:16
msgid "No"
msgstr ""
#: assets/components/tracking/WatchlistsList.tsx:46
msgid "This Watchlist is not linked to a Connector."
msgstr ""
#: assets/components/tracking/WatchlistsList.tsx:49
msgid "Watchlist"
msgstr ""
#: assets/components/tracking/WatchlistsList.tsx:60
msgid "Export events to iCalendar format"
msgstr ""
#: assets/components/tracking/ConnectorsList.tsx:19
#: assets/components/tracking/connector/ConnectorsList.tsx:19
#, javascript-format
msgid "Connector ${ connector.provider }"
msgstr ""
#: assets/components/tracking/ConnectorsList.tsx:22
#: assets/components/tracking/connector/ConnectorsList.tsx:22
msgid "Delete the Connector"
msgstr ""
#: assets/components/tracking/ConnectorsList.tsx:23
#: assets/components/tracking/connector/ConnectorsList.tsx:23
msgid "Are you sure to delete this Connector?"
msgstr ""
#: assets/components/tracking/connector/ConnectorsList.tsx:25
#: assets/components/tracking/watchlist/DeleteWatchlistButton.tsx:15
msgid "Yes"
msgstr ""
#: assets/components/tracking/connector/ConnectorsList.tsx:26
#: assets/components/tracking/watchlist/DeleteWatchlistButton.tsx:16
msgid "No"
msgstr ""
#: assets/components/tracking/diagram/ViewDiagramWatchlistButton.tsx:86
msgid "View the Watchlist Entity Diagram"
msgstr ""
#: assets/components/tracking/diagram/ViewDiagramWatchlistButton.tsx:91
msgid "Watchlist Entity Diagram"
msgstr ""
#: assets/components/tracking/watchlist/WatchlistForm.tsx:66
msgid "Name"
msgstr ""
#: assets/components/tracking/watchlist/WatchlistForm.tsx:77
msgid "Watchlist Name"
msgstr ""
#: assets/components/tracking/watchlist/WatchlistForm.tsx:78
msgid "Naming the Watchlist makes it easier to find in the list below."
msgstr ""
#: assets/components/tracking/watchlist/WatchlistForm.tsx:89
msgid "At least one domain name"
msgstr ""
#: assets/components/tracking/watchlist/WatchlistForm.tsx:100
#: assets/components/tracking/watchlist/WatchlistsList.tsx:26
msgid "Domain names"
msgstr ""
#: assets/components/tracking/watchlist/WatchlistForm.tsx:118
msgid "Domain name"
msgstr ""
#: assets/components/tracking/watchlist/WatchlistForm.tsx:135
msgid "Add a Domain name"
msgstr ""
#: assets/components/tracking/watchlist/WatchlistForm.tsx:142
#: assets/components/tracking/watchlist/WatchlistsList.tsx:30
msgid "Tracked events"
msgstr ""
#: assets/components/tracking/watchlist/WatchlistForm.tsx:144
msgid "At least one trigger"
msgstr ""
#: assets/components/tracking/watchlist/WatchlistForm.tsx:166
#: assets/components/tracking/watchlist/WatchlistForm.tsx:180
msgid "Connector"
msgstr ""
#: assets/components/tracking/watchlist/WatchlistForm.tsx:176
msgid ""
"Please make sure the connector information is valid to purchase a domain "
"that may be available soon."
msgstr ""
#: assets/components/tracking/watchlist/WatchlistForm.tsx:192
msgid "Update"
msgstr ""
#: assets/components/tracking/watchlist/UpdateWatchlistButton.tsx:31
msgid "Edit the Watchlist"
msgstr ""
#: assets/components/tracking/watchlist/UpdateWatchlistButton.tsx:43
msgid "Update a Watchlist"
msgstr ""
#: assets/components/tracking/watchlist/UpdateWatchlistButton.tsx:53
msgid "Cancel"
msgstr ""
#: assets/components/tracking/watchlist/DeleteWatchlistButton.tsx:12
#: assets/components/tracking/watchlist/DeleteWatchlistButton.tsx:19
msgid "Delete the Watchlist"
msgstr ""
#: assets/components/tracking/watchlist/DeleteWatchlistButton.tsx:13
msgid "Are you sure to delete this Watchlist?"
msgstr ""
#: assets/components/tracking/watchlist/WatchlistsList.tsx:46
msgid "This Watchlist is not linked to a Connector."
msgstr ""
#: assets/components/tracking/watchlist/WatchlistsList.tsx:49
msgid "Watchlist"
msgstr ""
#: assets/components/tracking/watchlist/WatchlistsList.tsx:60
msgid "Export events to iCalendar format"
msgstr ""
#: assets/components/Sider.tsx:29
msgid "Home"
msgstr ""

View File

@ -3933,6 +3933,11 @@ html-minifier-terser@^7.2.0:
relateurl "^0.2.7"
terser "^5.15.1"
html-to-image@^1.11.11:
version "1.11.11"
resolved "https://registry.yarnpkg.com/html-to-image/-/html-to-image-1.11.11.tgz#c0f8a34dc9e4b97b93ff7ea286eb8562642ebbea"
integrity sha512-9gux8QhvjRO/erSnDPv28noDZcPZmYE7e1vFsBLKLlRlKDSqNJYebj6Qz1TGd5lsRV+X+xYyjCKjuZdABinWjA==
htmlparser2@^6.1.0:
version "6.1.0"
resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-6.1.0.tgz#c4d762b6c3371a05dbe65e94ae43a9f845fb8fb7"