From 776d386395123ce0d9ba66331063ac4101fe362f Mon Sep 17 00:00:00 2001 From: Aviv Turgeman Date: Thu, 8 Aug 2024 16:08:44 +0300 Subject: [PATCH] [WIP] NNS topology Signed-off-by: Aviv Turgeman --- .../en/plugin__nmstate-console-plugin.json | 10 + package.json | 2 + src/console-models/NodeNetworkStateModel.ts | 4 +- .../components/DetailItem/DetailItem.scss | 17 + .../components/DetailItem/DetailItem.tsx | 116 +++ .../DetailItem/DetailItemHeader.tsx | 74 ++ .../DetailItem/EditButtonWithTooltip.tsx | 51 ++ .../components/DetailItem/OwnerDetailItem.tsx | 60 ++ .../MetadataLabels/MetadataLabels.scss | 8 + .../MetadataLabels/MetadataLabels.tsx | 38 + .../OwnerReferences/OwnerReferences.tsx | 36 + src/views/states/details/StateDetailsPage.tsx | 77 ++ src/views/states/list/StatesList.tsx | 37 +- .../InterfaceDrawer/InterfaceDrawer.tsx | 18 +- src/views/states/list/constants.ts | 3 +- src/views/states/manifest.ts | 24 +- src/views/states/topology/Topology.tsx | 134 ++++ .../topology/components/CustomGroup.tsx | 17 + .../states/topology/components/CustomNode.tsx | 42 ++ src/views/states/topology/utils/constants.ts | 4 + src/views/states/topology/utils/factory.ts | 80 ++ src/views/states/topology/utils/utils.ts | 66 ++ tsconfig.json | 3 +- yarn.lock | 683 +++++++++++++++++- 24 files changed, 1559 insertions(+), 45 deletions(-) create mode 100644 src/utils/components/DetailItem/DetailItem.scss create mode 100644 src/utils/components/DetailItem/DetailItem.tsx create mode 100644 src/utils/components/DetailItem/DetailItemHeader.tsx create mode 100644 src/utils/components/DetailItem/EditButtonWithTooltip.tsx create mode 100644 src/utils/components/DetailItem/OwnerDetailItem.tsx create mode 100644 src/utils/components/MetadataLabels/MetadataLabels.scss create mode 100644 src/utils/components/MetadataLabels/MetadataLabels.tsx create mode 100644 src/utils/components/OwnerReferences/OwnerReferences.tsx create mode 100644 src/views/states/details/StateDetailsPage.tsx create mode 100644 src/views/states/topology/Topology.tsx create mode 100644 src/views/states/topology/components/CustomGroup.tsx create mode 100644 src/views/states/topology/components/CustomNode.tsx create mode 100644 src/views/states/topology/utils/constants.ts create mode 100644 src/views/states/topology/utils/factory.ts create mode 100644 src/views/states/topology/utils/utils.ts diff --git a/locales/en/plugin__nmstate-console-plugin.json b/locales/en/plugin__nmstate-console-plugin.json index d906f2d5..8c106ad0 100644 --- a/locales/en/plugin__nmstate-console-plugin.json +++ b/locales/en/plugin__nmstate-console-plugin.json @@ -1,7 +1,9 @@ { + "{{annotationsCount}} Annotations": "{{annotationsCount}} Annotations", "{{matchingNodeText}} matching": "{{matchingNodeText}} matching", "{{modelName}} details": "{{modelName}} details", "{{qualifiedNodesCount}} matching Nodes found": "{{qualifiedNodesCount}} matching Nodes found", + "<0>List of objects depended by this object. If ALL objects in the list have been deleted, this object will be garbage collected. If this object is managed by a controller, then an entry in this list will point to this controller, with the controller field set to true. There cannot be more than one managing controller.<1><0>{{kind}}<1>metadata<2>ownerReferences": "<0>List of objects depended by this object. If ALL objects in the list have been deleted, this object will be garbage collected. If this object is managed by a controller, then an entry in this list will point to this controller, with the controller field set to true. There cannot be more than one managing controller.<1><0>{{kind}}<1>metadata<2>ownerReferences", "Aborted": "Aborted", "Actions": "Actions", "Add another interface to the policy": "Add another interface to the policy", @@ -10,6 +12,7 @@ "Add Option": "Add Option", "Aggregation mode": "Aggregation mode", "An error occurred": "An error occurred", + "Annotations": "Annotations", "Apply this NodeNetworkConfigurationPolicy only to specific subsets of nodes using the node selector": "Apply this NodeNetworkConfigurationPolicy only to specific subsets of nodes using the node selector", "Are you sure you want to remove {{interfaceType}} interface <5>{{name}}?": "Are you sure you want to remove {{interfaceType}} interface <5>{{name}}?", "Auto-DNS": "Auto-DNS", @@ -30,6 +33,7 @@ "Create": "Create", "Create NodeNetworkConfigurationPolicy": "Create NodeNetworkConfigurationPolicy", "Create NodeNetworkConfigurationPolicy error": "Create NodeNetworkConfigurationPolicy error", + "Created at": "Created at", "Created interfaces cannot be removed": "Created interfaces cannot be removed", "Delete": "Delete", "Delete NodeNetworkConfigurationPolicy?": "Delete NodeNetworkConfigurationPolicy?", @@ -73,6 +77,7 @@ "IPV4 address": "IPV4 address", "IPv6": "IPv6", "Key": "Key", + "Labels": "Labels", "Learn more": "Learn more", "List of network interfaces that should be created, modified, or removed, as a part of this policy.": "List of network interfaces that should be created, modified, or removed, as a part of this policy.", "LLDP": "LLDP", @@ -82,6 +87,7 @@ "MAC Address": "MAC Address", "Matched nodes": "Matched nodes", "Matched nodes summary": "Matched nodes summary", + "More info: ": "More info: ", "MTU": "MTU", "Name": "Name", "Neighbors": "Neighbors", @@ -92,6 +98,8 @@ "No node network configuration policies defined yet": "No node network configuration policies defined yet", "No NodeNetworkStates found": "No NodeNetworkStates found", "Node network is configured and managed by NM state. Create a node network configuration policy to describe the requested network configuration on your nodes in the cluster. The node network configuration enactment reports the netwrok policies enacted upon each node.": "Node network is configured and managed by NM state. Create a node netowrk configuration policy to describe the requested network configuration on your nodes in the cluster. The node network configuration enactment reports the netwrok policies enacted upon each node.", + "No owner": "No owner", + "Node network is configured and managed by NM state. Create a node netowrk configuration policy to describe the requested network configuration on your nodes in the cluster. The node network configuration enactment reports the netwrok policies enacted upon each node.": "Node network is configured and managed by NM state. Create a node netowrk configuration policy to describe the requested network configuration on your nodes in the cluster. The node network configuration enactment reports the netwrok policies enacted upon each node.", "Node Selector": "Node Selector", "NodeNetworkConfigurationPolicy": "NodeNetworkConfigurationPolicy", "NodeNetworkState": "NodeNetworkState", @@ -100,6 +108,8 @@ "Open vSwitch bridge mapping": "Open vSwitch bridge mapping", "OVN localnet name": "OVN localnet name", "OVS bridge name": "OVS bridge name", + "Not available": "Not available", + "Owner": "Owner", "Pending": "Pending", "Please <2>try again.": "Please <2>try again.", "Policy details": "Policy details", diff --git a/package.json b/package.json index dab3e42f..2acdb437 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,8 @@ "@patternfly/react-icons": "^5.1.1", "@patternfly/react-core": "5.1.1", "@patternfly/react-table": "^5.1.1", + "@patternfly/react-icons": "5.2.1", + "@patternfly/react-topology": "5.2.0", "@testing-library/jest-dom": "^5.16.5", "@testing-library/react": "^12.0.0", "@testing-library/react-hooks": "^8.0.1", diff --git a/src/console-models/NodeNetworkStateModel.ts b/src/console-models/NodeNetworkStateModel.ts index da362d14..a68c1042 100644 --- a/src/console-models/NodeNetworkStateModel.ts +++ b/src/console-models/NodeNetworkStateModel.ts @@ -2,7 +2,7 @@ import { K8sModel } from '@openshift-console/dynamic-plugin-sdk/lib/api/common-t import { modelToGroupVersionKind, modelToRef } from './modelUtils'; -const NodeNetworkStateModel: K8sModel = { +export const NodeNetworkStateModel: K8sModel = { label: 'NodeNetworkState', labelPlural: 'NodeNetworkStates', apiVersion: 'v1beta1', @@ -17,5 +17,3 @@ const NodeNetworkStateModel: K8sModel = { export const NodeNetworkStateModelGroupVersionKind = modelToGroupVersionKind(NodeNetworkStateModel); export const NodeNetworkStateModelRef = modelToRef(NodeNetworkStateModel); - -export default NodeNetworkStateModel; diff --git a/src/utils/components/DetailItem/DetailItem.scss b/src/utils/components/DetailItem/DetailItem.scss new file mode 100644 index 00000000..5bb3d0bd --- /dev/null +++ b/src/utils/components/DetailItem/DetailItem.scss @@ -0,0 +1,17 @@ +.description-item__title { + justify-content: space-between; + flex: 1; +} + +.margin-top { + margin-top: var(--pf-v5-global--spacer--md); +} + +.DescriptionItemHeader { + &--list-term { + .pf-c-description-list__text { + align-items: center; + display: inline-flex; + } + } +} diff --git a/src/utils/components/DetailItem/DetailItem.tsx b/src/utils/components/DetailItem/DetailItem.tsx new file mode 100644 index 00000000..131029d3 --- /dev/null +++ b/src/utils/components/DetailItem/DetailItem.tsx @@ -0,0 +1,116 @@ +import React, { FC, ReactNode } from 'react'; + +import { + Button, + DescriptionListDescription, + DescriptionListGroup, + DescriptionListTermHelpText, + Flex, + FlexItem, +} from '@patternfly/react-core'; +import { PencilAltIcon } from '@patternfly/react-icons'; +import { useNMStateTranslation } from '@utils/hooks/useNMStateTranslation'; + +import { DetailItemHeader } from './DetailItemHeader'; +import EditButtonWithTooltip from './EditButtonWithTooltip'; + +import './DetailItem.scss'; + +type DetailItemProps = { + bodyContent?: ReactNode; + breadcrumb?: string; + className?: string; + 'data-test-id'?: string; + descriptionData: any; + descriptionHeader?: ReactNode; + editOnTitleJustify?: boolean; + isDisabled?: boolean; + isEdit?: boolean; + isPopover?: boolean; + label?: ReactNode; + messageOnDisabled?: string; + moreInfoURL?: string; + onEditClick?: () => void; + showEditOnTitle?: boolean; +}; + +const DetailItem: FC = ({ + bodyContent, + breadcrumb, + className, + 'data-test-id': testId, + descriptionData, + descriptionHeader, + editOnTitleJustify = false, + isDisabled, + isEdit, + isPopover, + label, + messageOnDisabled, + moreInfoURL, + onEditClick, + showEditOnTitle, +}) => { + const { t } = useNMStateTranslation(); + const NotAvailable = {t('Not available')}; + + const description = ( + + {descriptionData ?? NotAvailable} + + ); + + return ( + + + + {(bodyContent || breadcrumb || descriptionHeader || label || moreInfoURL) && ( + + + + )} + {isEdit && showEditOnTitle && ( + + + + )} + + + + + {isEdit && !showEditOnTitle ? description : descriptionData} + + + ); +}; + +export default DetailItem; diff --git a/src/utils/components/DetailItem/DetailItemHeader.tsx b/src/utils/components/DetailItem/DetailItemHeader.tsx new file mode 100644 index 00000000..6ad253d4 --- /dev/null +++ b/src/utils/components/DetailItem/DetailItemHeader.tsx @@ -0,0 +1,74 @@ +import React, { FC, ReactNode } from 'react'; + +import { + Breadcrumb, + BreadcrumbItem, + DescriptionListTerm, + DescriptionListTermHelpTextButton, + Popover, +} from '@patternfly/react-core'; +import { useNMStateTranslation } from '@utils/hooks/useNMStateTranslation'; + +import './DetailItem.scss'; + +type DetailItemHeaderProps = { + bodyContent: ReactNode; + breadcrumb?: string; + descriptionHeader: ReactNode; + isPopover: boolean; + label?: ReactNode; + maxWidth?: string; + moreInfoURL?: string; +}; + +export const DetailItemHeader: FC = ({ + bodyContent, + breadcrumb, + descriptionHeader, + isPopover, + label, + maxWidth, + moreInfoURL, +}) => { + const { t } = useNMStateTranslation(); + + if (isPopover && bodyContent) { + return ( + + {bodyContent} + {moreInfoURL && ( + <> + {t('More info: ')} + {moreInfoURL} + + )} + {breadcrumb && ( +
+ + {breadcrumb.split('.').map((item) => ( + {item} + ))} + +
+ )} + + } + hasAutoWidth + headerContent={descriptionHeader} + maxWidth={maxWidth || '30rem'} + > + + {descriptionHeader} + +
+ ); + } + + return ( + + {descriptionHeader} {label} + + ); +}; diff --git a/src/utils/components/DetailItem/EditButtonWithTooltip.tsx b/src/utils/components/DetailItem/EditButtonWithTooltip.tsx new file mode 100644 index 00000000..9433c112 --- /dev/null +++ b/src/utils/components/DetailItem/EditButtonWithTooltip.tsx @@ -0,0 +1,51 @@ +import React, { FC, PropsWithChildren, ReactNode, SyntheticEvent } from 'react'; + +import { Button, Flex, Tooltip } from '@patternfly/react-core'; +import { PencilAltIcon } from '@patternfly/react-icons'; + +type EditButtonWithTooltipProps = PropsWithChildren<{ + isEditable: boolean; + onEditClick: () => void; + testId: string; + tooltipContent?: ReactNode; +}>; + +const EditButtonWithTooltip: FC = ({ + children, + isEditable, + onEditClick, + testId, + tooltipContent, +}) => { + const EditButton = () => ( + + ); + + if (!isEditable && tooltipContent) { + return ( + + + + + + ); + } + + return ; +}; + +export default EditButtonWithTooltip; diff --git a/src/utils/components/DetailItem/OwnerDetailItem.tsx b/src/utils/components/DetailItem/OwnerDetailItem.tsx new file mode 100644 index 00000000..1a248795 --- /dev/null +++ b/src/utils/components/DetailItem/OwnerDetailItem.tsx @@ -0,0 +1,60 @@ +import React, { FC } from 'react'; +import { Trans } from 'react-i18next'; + +import { K8sResourceCommon } from '@openshift-console/dynamic-plugin-sdk'; +import { + Breadcrumb, + BreadcrumbItem, + DescriptionListDescription, + DescriptionListGroup, + DescriptionListTermHelpText, + DescriptionListTermHelpTextButton, + Popover, +} from '@patternfly/react-core'; +import { useNMStateTranslation } from '@utils/hooks/useNMStateTranslation'; + +import OwnerReferences from '../OwnerReferences/OwnerReferences'; + +type OwnerDetailsItemProps = { + obj: K8sResourceCommon; +}; + +const OwnerDetailsItem: FC = ({ obj }) => { + const { t } = useNMStateTranslation(); + + return ( + + + +
+ List of objects depended by this object. If ALL objects in the list have been + deleted, this object will be garbage collected. If this object is managed by a + controller, then an entry in this list will point to this controller, with the + controller field set to true. There cannot be more than one managing controller. +
+ + {{ kind: obj?.kind }} + metadata + ownerReferences + + + } + hasAutoWidth + headerContent={t('Owner')} + maxWidth="30rem" + > + + {t('Owner')} + +
+
+ + + +
+ ); +}; + +export default OwnerDetailsItem; diff --git a/src/utils/components/MetadataLabels/MetadataLabels.scss b/src/utils/components/MetadataLabels/MetadataLabels.scss new file mode 100644 index 00000000..f7289556 --- /dev/null +++ b/src/utils/components/MetadataLabels/MetadataLabels.scss @@ -0,0 +1,8 @@ +.metadata-labels-group { + padding-top: var(--pf-c-label-group--m-category--PaddingTop); + padding-right: var(--pf-c-label-group--m-category--PaddingRight); + padding-bottom: var(--pf-c-label-group--m-category--PaddingBottom); + padding-left: var(--pf-c-label-group--m-category--PaddingLeft); + border: var(--pf-c-label-group--m-category--BorderWidth) solid + var(--pf-c-label-group--m-category--BorderColor); +} diff --git a/src/utils/components/MetadataLabels/MetadataLabels.tsx b/src/utils/components/MetadataLabels/MetadataLabels.tsx new file mode 100644 index 00000000..c5e1f244 --- /dev/null +++ b/src/utils/components/MetadataLabels/MetadataLabels.tsx @@ -0,0 +1,38 @@ +import React, { FC } from 'react'; +import { Link } from 'react-router-dom-v5-compat'; +import { modelToRef } from 'src/console-models/modelUtils'; + +import { K8sModel } from '@openshift-console/dynamic-plugin-sdk'; +import { Label, LabelGroup } from '@patternfly/react-core'; + +import './MetadataLabels.scss'; + +type MetadataLabelsProps = { + labels?: { [key: string]: string }; + model: K8sModel; +}; + +const MetadataLabels: FC = ({ labels, model }) => { + const modelRef = modelToRef(model); + + return ( + + {Object.keys(labels || {})?.map((key) => { + const labelText = labels?.[key] ? `${key}=${labels?.[key]}` : key; + + return ( + + ); + })} + + ); +}; + +export default MetadataLabels; diff --git a/src/utils/components/OwnerReferences/OwnerReferences.tsx b/src/utils/components/OwnerReferences/OwnerReferences.tsx new file mode 100644 index 00000000..56a14683 --- /dev/null +++ b/src/utils/components/OwnerReferences/OwnerReferences.tsx @@ -0,0 +1,36 @@ +import React, { FC } from 'react'; + +import { + getGroupVersionKindForResource, + K8sResourceCommon, + OwnerReference, + ResourceLink, +} from '@openshift-console/dynamic-plugin-sdk'; +import { isEmpty } from '@utils/helpers'; +import { useNMStateTranslation } from '@utils/hooks/useNMStateTranslation'; + +type OwnerReferencesProps = { + obj: K8sResourceCommon; +}; + +const OwnerReferences: FC = ({ obj }) => { + const { t } = useNMStateTranslation(); + const ownerReferences = (obj?.metadata?.ownerReferences || [])?.map( + (ownerRef: OwnerReference) => ( + + ), + ); + + return !isEmpty(ownerReferences) ? ( +
{ownerReferences}
+ ) : ( + {t('No owner')} + ); +}; + +export default OwnerReferences; diff --git a/src/views/states/details/StateDetailsPage.tsx b/src/views/states/details/StateDetailsPage.tsx new file mode 100644 index 00000000..605da01e --- /dev/null +++ b/src/views/states/details/StateDetailsPage.tsx @@ -0,0 +1,77 @@ +import React, { FC } from 'react'; + +import { NodeNetworkStateModel, NodeNetworkStateModelGroupVersionKind } from '@models'; +import { + ResourceIcon, + Timestamp, + useAnnotationsModal, + useLabelsModal, +} from '@openshift-console/dynamic-plugin-sdk'; +import { + DescriptionList, + Divider, + PageSection, + PageSectionVariants, + Title, +} from '@patternfly/react-core'; +import { V1beta1NodeNetworkState } from '@types'; +import DetailItem from '@utils/components/DetailItem/DetailItem'; +import OwnerDetailsItem from '@utils/components/DetailItem/OwnerDetailItem'; +import MetadataLabels from '@utils/components/MetadataLabels/MetadataLabels'; +import { useNMStateTranslation } from '@utils/hooks/useNMStateTranslation'; + +type StateDetailsPageProps = { + nns: V1beta1NodeNetworkState; +}; + +const StateDetailsPage: FC = ({ nns }) => { + const { t } = useNMStateTranslation(); + const launchLabelsModal = useLabelsModal(nns); + const launchAnnotationsModal = useAnnotationsModal(nns); + + if (!nns) return null; + + const annotationsCount = Object.keys(nns?.metadata?.annotations || {}).length; + const annotationsText = t('{{annotationsCount}} Annotations', { + annotationsCount, + }); + + return ( + <> + + <span className="co-resource-item__resource-name"> + <ResourceIcon groupVersionKind={NodeNetworkStateModelGroupVersionKind} /> + <span className="co-resource-item__resource-name">{nns?.metadata?.name} </span> + </span> + + + + + + + } + descriptionHeader={t('Labels')} + isEdit + onEditClick={launchLabelsModal} + showEditOnTitle + /> + + } + descriptionHeader={t('Created at')} + /> + + + + + ); +}; + +export default StateDetailsPage; diff --git a/src/views/states/list/StatesList.tsx b/src/views/states/list/StatesList.tsx index 7f1ba26f..a92e9288 100644 --- a/src/views/states/list/StatesList.tsx +++ b/src/views/states/list/StatesList.tsx @@ -1,11 +1,12 @@ -import React, { FC, useState } from 'react'; +import React, { FC, useCallback, useState } from 'react'; +import { useNavigate } from 'react-router-dom-v5-compat'; +import { useNMStateTranslation } from 'src/utils/hooks/useNMStateTranslation'; + import { + NodeNetworkStateModel, NodeNetworkStateModelGroupVersionKind, NodeNetworkStateModelRef, -} from 'src/console-models'; -import NodeNetworkStateModel from 'src/console-models/NodeNetworkStateModel'; -import { useNMStateTranslation } from 'src/utils/hooks/useNMStateTranslation'; - +} from '@models'; import { ListPageBody, ListPageFilter, @@ -13,7 +14,8 @@ import { useK8sWatchResource, useListPageFilter, } from '@openshift-console/dynamic-plugin-sdk'; -import { Button, Flex, Pagination } from '@patternfly/react-core'; +import { Button, Flex, Icon, Pagination } from '@patternfly/react-core'; +import { TopologyIcon } from '@patternfly/react-icons'; import { Table, TableGridBreakpoint, Th, Thead, Tr } from '@patternfly/react-table'; import { V1beta1NodeNetworkState } from '@types'; import usePagination from '@utils/hooks/usePagination/usePagination'; @@ -33,7 +35,17 @@ import './states-list.scss'; const StatesList: FC = () => { const { t } = useNMStateTranslation(); - const { selectedInterfaceName, selectedStateName, selectedInterfaceType } = useDrawerInterface(); + const navigate = useNavigate(); + const { + selectedInterfaceName, + selectedStateName, + selectedInterfaceType, + setSelectedInterfaceName, + } = useDrawerInterface(); + + const onClose = useCallback(() => { + setSelectedInterfaceName(); + }, []); const [expandAll, setExpandAll] = useState(false); @@ -62,10 +74,15 @@ const StatesList: FC = () => { const { sortedStates, nameSortParams } = useSortStates(filteredData); const paginatedData = sortedStates.slice(pagination?.startIndex, pagination?.endIndex + 1); - return ( <> - + + +
@@ -144,7 +161,7 @@ const StatesList: FC = () => { )} - + ); }; diff --git a/src/views/states/list/components/InterfaceDrawer/InterfaceDrawer.tsx b/src/views/states/list/components/InterfaceDrawer/InterfaceDrawer.tsx index fcc56901..706a0830 100644 --- a/src/views/states/list/components/InterfaceDrawer/InterfaceDrawer.tsx +++ b/src/views/states/list/components/InterfaceDrawer/InterfaceDrawer.tsx @@ -1,25 +1,21 @@ -import React, { FC, useCallback } from 'react'; +import React, { FC } from 'react'; import { Modal, Title } from '@patternfly/react-core'; import { NodeNetworkConfigurationInterface } from '@types'; import { useNMStateTranslation } from '@utils/hooks/useNMStateTranslation'; -import useDrawerInterface from '../../hooks/useDrawerInterface'; - import { InterfaceDrawerTabId, InterfaceDrawerTabProps } from './constants'; import InterfaceDrawerDetailsTab from './InterfaceDrawerDetailsTab'; import InterfaceDrawerYAMLFooter from './InterfaceDrawerFooter'; import InterfaceDrawerYAMLTab from './InterfaceDrawerYAMLTab'; -const InterfaceDrawer: FC<{ selectedInterface: NodeNetworkConfigurationInterface }> = ({ - selectedInterface, -}) => { - const { t } = useNMStateTranslation(); - const { setSelectedInterfaceName } = useDrawerInterface(); +type InterfaceDrawerProps = { + selectedInterface: NodeNetworkConfigurationInterface; + onClose: () => void; +}; - const onClose = useCallback(() => { - setSelectedInterfaceName(); - }, []); +const InterfaceDrawer: FC = ({ selectedInterface, onClose }) => { + const { t } = useNMStateTranslation(); const Tabs: InterfaceDrawerTabProps[] = [ { diff --git a/src/views/states/list/constants.ts b/src/views/states/list/constants.ts index 6733a216..a494f377 100644 --- a/src/views/states/list/constants.ts +++ b/src/views/states/list/constants.ts @@ -1,5 +1,4 @@ -import NodeNetworkStateModel from 'src/console-models/NodeNetworkStateModel'; - +import { NodeNetworkStateModel } from '@models'; import { getResourceUrl } from '@utils/helpers'; export const baseListUrl = getResourceUrl({ model: NodeNetworkStateModel }); diff --git a/src/views/states/manifest.ts b/src/views/states/manifest.ts index 8d6a2f43..3507c66e 100644 --- a/src/views/states/manifest.ts +++ b/src/views/states/manifest.ts @@ -1,20 +1,15 @@ import type { EncodedExtension } from '@openshift/dynamic-plugin-sdk'; import type { - ExtensionK8sModel, ResourceClusterNavItem, ResourceListPage, + RoutePage, } from '@openshift-console/dynamic-plugin-sdk'; -import NodeNetworkStateModel from '../../console-models/NodeNetworkStateModel'; - -const StateExtensionModel: ExtensionK8sModel = { - group: NodeNetworkStateModel.apiGroup as string, - kind: NodeNetworkStateModel.kind, - version: NodeNetworkStateModel.apiVersion, -}; +import { NodeNetworkStateModelGroupVersionKind } from '../../console-models'; export const StateExposedModules = { StatesList: './views/states/list/StatesList', + Topology: './views/states/topology/Topology', }; export const StateExtensions: EncodedExtension[] = [ @@ -25,7 +20,7 @@ export const StateExtensions: EncodedExtension[] = [ perspective: 'admin', name: '%plugin__nmstate-console-plugin~NodeNetworkState%', section: 'networking', - model: StateExtensionModel, + model: NodeNetworkStateModelGroupVersionKind, dataAttributes: { 'data-quickstart-id': 'qs-nav-state-list', 'data-test-id': 'state-nav-list', @@ -36,8 +31,17 @@ export const StateExtensions: EncodedExtension[] = [ type: 'console.page/resource/list', properties: { perspective: 'admin', - model: StateExtensionModel, + model: NodeNetworkStateModelGroupVersionKind, component: { $codeRef: 'StatesList' }, }, } as EncodedExtension, + { + type: 'console.page/route', + properties: { + path: ['nmstate-topology'], + component: { + $codeRef: 'Topology', + }, + }, + } as EncodedExtension, ]; diff --git a/src/views/states/topology/Topology.tsx b/src/views/states/topology/Topology.tsx new file mode 100644 index 00000000..b46ce6db --- /dev/null +++ b/src/views/states/topology/Topology.tsx @@ -0,0 +1,134 @@ +import React, { FC, useEffect, useMemo, useState } from 'react'; +import { useNavigate } from 'react-router-dom-v5-compat'; + +import { NodeNetworkStateModelGroupVersionKind, NodeNetworkStateModelRef } from '@models'; +import { useK8sWatchResource } from '@openshift-console/dynamic-plugin-sdk'; +import { Button, Divider, Icon, Title, ToolbarItem } from '@patternfly/react-core'; +import { ListIcon } from '@patternfly/react-icons'; +import { + action, + createTopologyControlButtons, + defaultControlButtonsOptions, + SELECTION_EVENT, + TopologyControlBar, + TopologySideBar, + TopologyView, + Visualization, + VisualizationProvider, + VisualizationSurface, +} from '@patternfly/react-topology'; +import { V1beta1NodeNetworkState } from '@types'; + +import StateDetailsPage from '../details/StateDetailsPage'; +import InterfaceDrawerDetailsTab from '../list/components/InterfaceDrawer/InterfaceDrawerDetailsTab'; + +import { componentFactory, layoutFactory } from './utils/factory'; +import { transformDataToTopologyModel } from './utils/utils'; + +const Topology: FC = () => { + const navigate = useNavigate(); + const [selectedIds, setSelectedIds] = useState([]); + const [visualization, setVisualization] = useState(null); + + const [data, loaded, error] = useK8sWatchResource({ + groupVersionKind: NodeNetworkStateModelGroupVersionKind, + isList: true, + namespaced: false, + }); + + const { selectedState, selectedInterface } = useMemo(() => { + if (selectedIds.length === 0) return { selectedState: null, selectedInterface: null }; + + const [selectedNNSName, selectedInterfaceName] = selectedIds[0].split('~'); + const selectedState = data?.find((state) => state.metadata.name === selectedNNSName); + const selectedInterface = selectedState?.status?.currentState?.interfaces?.find( + (iface) => iface.name === selectedInterfaceName, + ); + + return { selectedState, selectedInterface }; + }, [selectedIds, data]); + + useEffect(() => { + if (loaded && !error) { + const topologyModel = transformDataToTopologyModel(data); + + if (!visualization) { + const newVisualization = new Visualization(); + newVisualization.registerLayoutFactory(layoutFactory); + newVisualization.registerComponentFactory(componentFactory); + newVisualization.addEventListener(SELECTION_EVENT, setSelectedIds); + newVisualization.fromModel(topologyModel); + setVisualization(newVisualization); + } else { + visualization.fromModel(topologyModel); + } + } + }, [data, loaded, error]); + + const topologySideBar = ( + 0} onClose={() => setSelectedIds([])}> +
+ {!selectedInterface ? ( + + ) : ( + <> + {selectedInterface?.name} + + + + )} +
+
+ ); + + const topologyToolBar = ( + <> + node filter + + + + + ); + + return ( + { + visualization.getGraph().scaleBy(4 / 3); + }), + zoomOutCallback: action(() => { + visualization.getGraph().scaleBy(0.75); + }), + fitToScreenCallback: action(() => { + visualization.getGraph().fit(80); + }), + resetViewCallback: action(() => { + visualization.getGraph().reset(); + visualization.getGraph().layout(); + }), + legend: false, + })} + /> + } + > + + + + + ); +}; + +export default Topology; diff --git a/src/views/states/topology/components/CustomGroup.tsx b/src/views/states/topology/components/CustomGroup.tsx new file mode 100644 index 00000000..d010245d --- /dev/null +++ b/src/views/states/topology/components/CustomGroup.tsx @@ -0,0 +1,17 @@ +import React, { FC } from 'react'; + +import { DefaultGroup, Node } from '@patternfly/react-topology'; + +type CustomGroupProps = { + element: Node; +} & any; + +const CustomGroup: FC = ({ element, ...rest }) => { + const data = element.getData(); + + return ( + + ); +}; + +export default CustomGroup; diff --git a/src/views/states/topology/components/CustomNode.tsx b/src/views/states/topology/components/CustomNode.tsx new file mode 100644 index 00000000..13b23142 --- /dev/null +++ b/src/views/states/topology/components/CustomNode.tsx @@ -0,0 +1,42 @@ +import React, { FC } from 'react'; + +import { + DefaultNode, + Node, + WithDndDropProps, + WithDragNodeProps, + WithSelectionProps, +} from '@patternfly/react-topology'; + +import { ICON_SIZE } from '../utils/constants'; + +type CustomNodeProps = { + element: Node; +} & WithSelectionProps & + WithDragNodeProps & + WithDndDropProps; + +const CustomNode: FC = ({ element, onSelect, selected }) => { + const data = element.getData(); + const Icon = data.icon; + const { width, height } = element.getBounds(); + + const xCenter = (width - ICON_SIZE) / 2; + const yCenter = (height - ICON_SIZE) / 2; + + return ( + + + + + + ); +}; + +export default CustomNode; diff --git a/src/views/states/topology/utils/constants.ts b/src/views/states/topology/utils/constants.ts new file mode 100644 index 00000000..b3175e2c --- /dev/null +++ b/src/views/states/topology/utils/constants.ts @@ -0,0 +1,4 @@ +export const NODE_DIAMETER = 35; +export const CONNECTOR_TARGET_DROP = 'connector-target-drop'; +export const GROUP = 'group'; +export const ICON_SIZE = 15; diff --git a/src/views/states/topology/utils/factory.ts b/src/views/states/topology/utils/factory.ts new file mode 100644 index 00000000..e49f9669 --- /dev/null +++ b/src/views/states/topology/utils/factory.ts @@ -0,0 +1,80 @@ +import { + ColaLayout, + ComponentFactory, + DefaultEdge, + DragObjectWithType, + Edge, + Graph, + GraphComponent, + graphDropTargetSpec, + GraphElement, + groupDropTargetSpec, + Layout, + LayoutFactory, + ModelKind, + Node, + nodeDragSourceSpec, + nodeDropTargetSpec, + withDndDrop, + withDragNode, + withPanZoom, + withSelection, + withTargetDrag, +} from '@patternfly/react-topology'; + +import CustomGroup from '../components/CustomGroup'; +import CustomNode from '../components/CustomNode'; + +import { CONNECTOR_TARGET_DROP, GROUP } from './constants'; + +export const layoutFactory: LayoutFactory = (type: string, graph: Graph): Layout | undefined => + new ColaLayout(graph); + +export const componentFactory: ComponentFactory = (kind: ModelKind, type: string): any => { + switch (type) { + case GROUP: + return withDndDrop(groupDropTargetSpec)( + withDragNode(nodeDragSourceSpec(GROUP))(withSelection()(CustomGroup)), + ); + default: + switch (kind) { + case ModelKind.graph: + return withDndDrop(graphDropTargetSpec())(withPanZoom()(GraphComponent)); + case ModelKind.node: + return withDndDrop(nodeDropTargetSpec([CONNECTOR_TARGET_DROP]))( + withDragNode(nodeDragSourceSpec(ModelKind.node, true, true))( + withSelection()(CustomNode), + ), + ); + case ModelKind.edge: + return withTargetDrag< + DragObjectWithType, + Node, + { dragging?: boolean }, + { + element: GraphElement; + } + >({ + item: { type: CONNECTOR_TARGET_DROP }, + begin: (monitor, props) => { + props.element.raise(); + return props.element; + }, + drag: (event, monitor, props) => { + (props.element as Edge).setEndPoint(event.x, event.y); + }, + end: (dropResult, monitor, props) => { + if (monitor.didDrop() && dropResult && props) { + (props.element as Edge).setTarget(dropResult); + } + (props.element as Edge).setEndPoint(); + }, + collect: (monitor) => ({ + dragging: monitor.isDragging(), + }), + })(DefaultEdge); + default: + return undefined; + } + } +}; diff --git a/src/views/states/topology/utils/utils.ts b/src/views/states/topology/utils/utils.ts new file mode 100644 index 00000000..37a34e62 --- /dev/null +++ b/src/views/states/topology/utils/utils.ts @@ -0,0 +1,66 @@ +import { NetworkIcon } from '@patternfly/react-icons'; +import { Model, ModelKind, NodeModel, NodeShape, NodeStatus } from '@patternfly/react-topology'; +import { NodeNetworkConfigurationInterface, V1beta1NodeNetworkState } from '@types'; + +import { GROUP, NODE_DIAMETER } from './constants'; + +export const getStatus = (iface: NodeNetworkConfigurationInterface) => { + const status = iface.state.toLowerCase(); + if (status === 'up') return NodeStatus.success; + if (status === 'down') return NodeStatus.danger; + if (status === 'absent') return NodeStatus.warning; + return NodeStatus.default; +}; + +export const transformDataToTopologyModel = (data: V1beta1NodeNetworkState[]): Model => { + const nodes = data + .map((nodeState) => { + const nnsName = nodeState.metadata.name; + + const childNodes: NodeModel[] = nodeState.status.currentState.interfaces.map( + (iface: NodeNetworkConfigurationInterface) => ({ + id: `${nnsName}~${iface.name}`, + type: ModelKind.node, + label: iface.name, + width: NODE_DIAMETER, + height: NODE_DIAMETER, + shape: NodeShape.ellipse, + status: getStatus(iface), + data: { + badge: 'I', // Which kind should be each one? + icon: NetworkIcon, + }, + parent: nnsName, + }), + ); + + const groupNode: NodeModel = { + id: nnsName, + type: GROUP, + label: nnsName, + group: true, + children: childNodes.map((child) => child.id), + style: { + padding: 40, + }, + data: { + badge: 'NNS', + }, + }; + + return [groupNode, ...childNodes]; + }) + .flat(); + + const edges: any[] = []; + + return { + nodes, + edges, + graph: { + id: 'nns-topology', + type: ModelKind.graph, + layout: 'Cola', + }, + }; +}; diff --git a/tsconfig.json b/tsconfig.json index 2d0f1312..62ce955d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -17,7 +17,8 @@ "paths": { "@images/*": ["images/*"], "@types": ["src/nmstate-types/index.ts"], - "@utils/*": ["src/utils/*"] + "@utils/*": ["src/utils/*"], + "@models": ["src/console-models/index.ts"] } }, "include": ["src", "pkg", "src/custom.d.ts"], diff --git a/yarn.lock b/yarn.lock index 41fa3fd8..010301fe 100644 --- a/yarn.lock +++ b/yarn.lock @@ -269,6 +269,13 @@ dependencies: regenerator-runtime "^0.14.0" +"@babel/runtime@^7.2.0": + version "7.25.0" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.25.0.tgz#3af9a91c1b739c569d5d80cc917280919c544ecb" + integrity sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw== + dependencies: + regenerator-runtime "^0.14.0" + "@babel/template@^7.22.15", "@babel/template@^7.24.0", "@babel/template@^7.3.3": version "7.24.0" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.24.0.tgz#c6a524aa93a4a05d66aaf31654258fae69d87d50" @@ -798,6 +805,18 @@ react-dropzone "^14.2.3" tslib "^2.5.0" +"@patternfly/react-core@^5.1.1": + version "5.3.4" + resolved "https://registry.yarnpkg.com/@patternfly/react-core/-/react-core-5.3.4.tgz#84f85d3528655134cf0bcdb096f82777f0dd69b6" + integrity sha512-zr2yeilIoFp8MFOo0vNgI8XuM+P2466zHvy4smyRNRH2/but2WObqx7Wu4ftd/eBMYdNqmTeuXe6JeqqRqnPMQ== + dependencies: + "@patternfly/react-icons" "^5.3.2" + "@patternfly/react-styles" "^5.3.1" + "@patternfly/react-tokens" "^5.3.1" + focus-trap "7.5.2" + react-dropzone "^14.2.3" + tslib "^2.5.0" + "@patternfly/react-core@^5.2.3": version "5.2.3" resolved "https://registry.yarnpkg.com/@patternfly/react-core/-/react-core-5.2.3.tgz#21d8168f1cccc2315162b7b1aca14a436cfa0101" @@ -810,16 +829,26 @@ react-dropzone "^14.2.3" tslib "^2.5.0" -"@patternfly/react-icons@^5.1.1", "@patternfly/react-icons@^5.2.1": +"@patternfly/react-icons@5.2.1", "@patternfly/react-icons@^5.1.1", "@patternfly/react-icons@^5.2.1": version "5.2.1" resolved "https://registry.yarnpkg.com/@patternfly/react-icons/-/react-icons-5.2.1.tgz#c29e9fbecd13c33e772abe6089e31bb86b1ab2a8" integrity sha512-aeJ0X+U2NDe8UmI5eQiT0iuR/wmUq97UkDtx3HoZcpRb9T6eUBfysllxjRqHS8rOOspdU8OWq+CUhQ/E2ZDibg== +"@patternfly/react-icons@^5.3.2": + version "5.3.2" + resolved "https://registry.yarnpkg.com/@patternfly/react-icons/-/react-icons-5.3.2.tgz#f594ed67b0d39f486ea0f0367de058d4bd056605" + integrity sha512-GEygYbl0H4zD8nZuTQy2dayKIrV2bMMeWKSOEZ16Y3EYNgYVUOUnN+J0naAEuEGH39Xb1DE9n+XUbE1PC4CxPA== + "@patternfly/react-styles@^5.1.1", "@patternfly/react-styles@^5.2.1": version "5.2.1" resolved "https://registry.yarnpkg.com/@patternfly/react-styles/-/react-styles-5.2.1.tgz#a6f8c750bd65572702ea94c0a6b58f6c0d4361fb" integrity sha512-GT96hzI1QenBhq6Pfc51kxnj9aVLjL1zSLukKZXcYVe0HPOy0BFm90bT1Fo4e/z7V9cDYw4SqSX1XLc3O4jsTw== +"@patternfly/react-styles@^5.3.1": + version "5.3.1" + resolved "https://registry.yarnpkg.com/@patternfly/react-styles/-/react-styles-5.3.1.tgz#4bc42f98c48e117df5d956ee3f551d0f57ef1b35" + integrity sha512-H6uBoFH3bJjD6PP75qZ4k+2TtF59vxf9sIVerPpwrGJcRgBZbvbMZCniSC3+S2LQ8DgXLnDvieq78jJzHz0hiA== + "@patternfly/react-table@^5.1.1": version "5.2.4" resolved "https://registry.yarnpkg.com/@patternfly/react-table/-/react-table-5.2.4.tgz#39d7435d40bfe8b2b2d3ee33c94d4137cea0da9c" @@ -837,6 +866,34 @@ resolved "https://registry.yarnpkg.com/@patternfly/react-tokens/-/react-tokens-5.2.1.tgz#fca7decaa7039dcd93fd215f3f533eff9d070b22" integrity sha512-8GYz/jnJTGAWUJt5eRAW5dtyiHPKETeFJBPGHaUQnvi/t1ZAkoy8i4Kd/RlHsDC7ktiu813SKCmlzwBwldAHKg== +"@patternfly/react-tokens@^5.3.1": + version "5.3.1" + resolved "https://registry.yarnpkg.com/@patternfly/react-tokens/-/react-tokens-5.3.1.tgz#b0f840ee3ee3bcf72b5fbf35dc3fd5559666744d" + integrity sha512-VYK0uVP2/2RJ7ZshJCCLeq0Boih5I1bv+9Z/Bg6h12dCkLs85XsxAX9Ve+BGIo5DF54/mzcRHE1RKYap4ISXuw== + +"@patternfly/react-topology@5.2.0": + version "5.2.0" + resolved "https://registry.yarnpkg.com/@patternfly/react-topology/-/react-topology-5.2.0.tgz#09df2807af75af172ef5291513f1f27235c7d41e" + integrity sha512-+kZJSbD6Pb1bTriNzLRiddfSbEBxyiNGSreiV6zOyPwfRizqbFPsOYyRuEocduzLqj0/wT3PM5Ml6JSp8Rw2TQ== + dependencies: + "@patternfly/react-core" "^5.1.1" + "@patternfly/react-icons" "^5.1.1" + "@patternfly/react-styles" "^5.1.1" + "@types/d3" "^7.4.0" + "@types/d3-force" "^1.2.1" + "@types/dagre" "0.7.42" + "@types/react-measure" "^2.0.6" + d3 "^7.8.0" + dagre "0.8.2" + lodash "^4.17.19" + mobx "^6.9.0" + mobx-react "^7.6.0" + point-in-svg-path "^1.0.1" + popper.js "^1.16.1" + react-measure "^2.3.0" + tslib "^2.0.0" + webcola "3.4.0" + "@remix-run/router@1.15.3": version "1.15.3" resolved "https://registry.yarnpkg.com/@remix-run/router/-/router-1.15.3.tgz#d2509048d69dbb72d5389a14945339f1430b2d3c" @@ -1010,6 +1067,226 @@ dependencies: "@types/node" "*" +"@types/d3-array@*": + version "3.2.1" + resolved "https://registry.yarnpkg.com/@types/d3-array/-/d3-array-3.2.1.tgz#1f6658e3d2006c4fceac53fde464166859f8b8c5" + integrity sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg== + +"@types/d3-axis@*": + version "3.0.6" + resolved "https://registry.yarnpkg.com/@types/d3-axis/-/d3-axis-3.0.6.tgz#e760e5765b8188b1defa32bc8bb6062f81e4c795" + integrity sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw== + dependencies: + "@types/d3-selection" "*" + +"@types/d3-brush@*": + version "3.0.6" + resolved "https://registry.yarnpkg.com/@types/d3-brush/-/d3-brush-3.0.6.tgz#c2f4362b045d472e1b186cdbec329ba52bdaee6c" + integrity sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A== + dependencies: + "@types/d3-selection" "*" + +"@types/d3-chord@*": + version "3.0.6" + resolved "https://registry.yarnpkg.com/@types/d3-chord/-/d3-chord-3.0.6.tgz#1706ca40cf7ea59a0add8f4456efff8f8775793d" + integrity sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg== + +"@types/d3-color@*": + version "3.1.3" + resolved "https://registry.yarnpkg.com/@types/d3-color/-/d3-color-3.1.3.tgz#368c961a18de721da8200e80bf3943fb53136af2" + integrity sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A== + +"@types/d3-contour@*": + version "3.0.6" + resolved "https://registry.yarnpkg.com/@types/d3-contour/-/d3-contour-3.0.6.tgz#9ada3fa9c4d00e3a5093fed0356c7ab929604231" + integrity sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg== + dependencies: + "@types/d3-array" "*" + "@types/geojson" "*" + +"@types/d3-delaunay@*": + version "6.0.4" + resolved "https://registry.yarnpkg.com/@types/d3-delaunay/-/d3-delaunay-6.0.4.tgz#185c1a80cc807fdda2a3fe960f7c11c4a27952e1" + integrity sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw== + +"@types/d3-dispatch@*": + version "3.0.6" + resolved "https://registry.yarnpkg.com/@types/d3-dispatch/-/d3-dispatch-3.0.6.tgz#096efdf55eb97480e3f5621ff9a8da552f0961e7" + integrity sha512-4fvZhzMeeuBJYZXRXrRIQnvUYfyXwYmLsdiN7XXmVNQKKw1cM8a5WdID0g1hVFZDqT9ZqZEY5pD44p24VS7iZQ== + +"@types/d3-drag@*": + version "3.0.7" + resolved "https://registry.yarnpkg.com/@types/d3-drag/-/d3-drag-3.0.7.tgz#b13aba8b2442b4068c9a9e6d1d82f8bcea77fc02" + integrity sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ== + dependencies: + "@types/d3-selection" "*" + +"@types/d3-dsv@*": + version "3.0.7" + resolved "https://registry.yarnpkg.com/@types/d3-dsv/-/d3-dsv-3.0.7.tgz#0a351f996dc99b37f4fa58b492c2d1c04e3dac17" + integrity sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g== + +"@types/d3-ease@*": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@types/d3-ease/-/d3-ease-3.0.2.tgz#e28db1bfbfa617076f7770dd1d9a48eaa3b6c51b" + integrity sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA== + +"@types/d3-fetch@*": + version "3.0.7" + resolved "https://registry.yarnpkg.com/@types/d3-fetch/-/d3-fetch-3.0.7.tgz#c04a2b4f23181aa376f30af0283dbc7b3b569980" + integrity sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA== + dependencies: + "@types/d3-dsv" "*" + +"@types/d3-force@*": + version "3.0.10" + resolved "https://registry.yarnpkg.com/@types/d3-force/-/d3-force-3.0.10.tgz#6dc8fc6e1f35704f3b057090beeeb7ac674bff1a" + integrity sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw== + +"@types/d3-force@^1.2.1": + version "1.2.7" + resolved "https://registry.yarnpkg.com/@types/d3-force/-/d3-force-1.2.7.tgz#b066d91ac3b8f19c35a60b49e89e99f60187460a" + integrity sha512-zySqZfnxn67RVEGWzpD9dQA0AbNIp4Rj0qGvAuUdUNfGLrwuGCbEGAGze5hEdNaHJKQT2gTqr6j+qAzncm11ew== + +"@types/d3-format@*": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@types/d3-format/-/d3-format-3.0.4.tgz#b1e4465644ddb3fdf3a263febb240a6cd616de90" + integrity sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g== + +"@types/d3-geo@*": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@types/d3-geo/-/d3-geo-3.1.0.tgz#b9e56a079449174f0a2c8684a9a4df3f60522440" + integrity sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ== + dependencies: + "@types/geojson" "*" + +"@types/d3-hierarchy@*": + version "3.1.7" + resolved "https://registry.yarnpkg.com/@types/d3-hierarchy/-/d3-hierarchy-3.1.7.tgz#6023fb3b2d463229f2d680f9ac4b47466f71f17b" + integrity sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg== + +"@types/d3-interpolate@*": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz#412b90e84870285f2ff8a846c6eb60344f12a41c" + integrity sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA== + dependencies: + "@types/d3-color" "*" + +"@types/d3-path@*": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@types/d3-path/-/d3-path-3.1.0.tgz#2b907adce762a78e98828f0b438eaca339ae410a" + integrity sha512-P2dlU/q51fkOc/Gfl3Ul9kicV7l+ra934qBFXCFhrZMOL6du1TM0pm1ThYvENukyOn5h9v+yMJ9Fn5JK4QozrQ== + +"@types/d3-polygon@*": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@types/d3-polygon/-/d3-polygon-3.0.2.tgz#dfae54a6d35d19e76ac9565bcb32a8e54693189c" + integrity sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA== + +"@types/d3-quadtree@*": + version "3.0.6" + resolved "https://registry.yarnpkg.com/@types/d3-quadtree/-/d3-quadtree-3.0.6.tgz#d4740b0fe35b1c58b66e1488f4e7ed02952f570f" + integrity sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg== + +"@types/d3-random@*": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@types/d3-random/-/d3-random-3.0.3.tgz#ed995c71ecb15e0cd31e22d9d5d23942e3300cfb" + integrity sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ== + +"@types/d3-scale-chromatic@*": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.0.3.tgz#fc0db9c10e789c351f4c42d96f31f2e4df8f5644" + integrity sha512-laXM4+1o5ImZv3RpFAsTRn3TEkzqkytiOY0Dz0sq5cnd1dtNlk6sHLon4OvqaiJb28T0S/TdsBI3Sjsy+keJrw== + +"@types/d3-scale@*": + version "4.0.8" + resolved "https://registry.yarnpkg.com/@types/d3-scale/-/d3-scale-4.0.8.tgz#d409b5f9dcf63074464bf8ddfb8ee5a1f95945bb" + integrity sha512-gkK1VVTr5iNiYJ7vWDI+yUFFlszhNMtVeneJ6lUTKPjprsvLLI9/tgEGiXJOnlINJA8FyA88gfnQsHbybVZrYQ== + dependencies: + "@types/d3-time" "*" + +"@types/d3-selection@*": + version "3.0.10" + resolved "https://registry.yarnpkg.com/@types/d3-selection/-/d3-selection-3.0.10.tgz#98cdcf986d0986de6912b5892e7c015a95ca27fe" + integrity sha512-cuHoUgS/V3hLdjJOLTT691+G2QoqAjCVLmr4kJXR4ha56w1Zdu8UUQ5TxLRqudgNjwXeQxKMq4j+lyf9sWuslg== + +"@types/d3-shape@*": + version "3.1.6" + resolved "https://registry.yarnpkg.com/@types/d3-shape/-/d3-shape-3.1.6.tgz#65d40d5a548f0a023821773e39012805e6e31a72" + integrity sha512-5KKk5aKGu2I+O6SONMYSNflgiP0WfZIQvVUMan50wHsLG1G94JlxEVnCpQARfTtzytuY0p/9PXXZb3I7giofIA== + dependencies: + "@types/d3-path" "*" + +"@types/d3-time-format@*": + version "4.0.3" + resolved "https://registry.yarnpkg.com/@types/d3-time-format/-/d3-time-format-4.0.3.tgz#d6bc1e6b6a7db69cccfbbdd4c34b70632d9e9db2" + integrity sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg== + +"@types/d3-time@*": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@types/d3-time/-/d3-time-3.0.3.tgz#3c186bbd9d12b9d84253b6be6487ca56b54f88be" + integrity sha512-2p6olUZ4w3s+07q3Tm2dbiMZy5pCDfYwtLXXHUnVzXgQlZ/OyPtUz6OL382BkOuGlLXqfT+wqv8Fw2v8/0geBw== + +"@types/d3-timer@*": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@types/d3-timer/-/d3-timer-3.0.2.tgz#70bbda77dc23aa727413e22e214afa3f0e852f70" + integrity sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw== + +"@types/d3-transition@*": + version "3.0.8" + resolved "https://registry.yarnpkg.com/@types/d3-transition/-/d3-transition-3.0.8.tgz#677707f5eed5b24c66a1918cde05963021351a8f" + integrity sha512-ew63aJfQ/ms7QQ4X7pk5NxQ9fZH/z+i24ZfJ6tJSfqxJMrYLiK01EAs2/Rtw/JreGUsS3pLPNV644qXFGnoZNQ== + dependencies: + "@types/d3-selection" "*" + +"@types/d3-zoom@*": + version "3.0.8" + resolved "https://registry.yarnpkg.com/@types/d3-zoom/-/d3-zoom-3.0.8.tgz#dccb32d1c56b1e1c6e0f1180d994896f038bc40b" + integrity sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw== + dependencies: + "@types/d3-interpolate" "*" + "@types/d3-selection" "*" + +"@types/d3@^7.4.0": + version "7.4.3" + resolved "https://registry.yarnpkg.com/@types/d3/-/d3-7.4.3.tgz#d4550a85d08f4978faf0a4c36b848c61eaac07e2" + integrity sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww== + dependencies: + "@types/d3-array" "*" + "@types/d3-axis" "*" + "@types/d3-brush" "*" + "@types/d3-chord" "*" + "@types/d3-color" "*" + "@types/d3-contour" "*" + "@types/d3-delaunay" "*" + "@types/d3-dispatch" "*" + "@types/d3-drag" "*" + "@types/d3-dsv" "*" + "@types/d3-ease" "*" + "@types/d3-fetch" "*" + "@types/d3-force" "*" + "@types/d3-format" "*" + "@types/d3-geo" "*" + "@types/d3-hierarchy" "*" + "@types/d3-interpolate" "*" + "@types/d3-path" "*" + "@types/d3-polygon" "*" + "@types/d3-quadtree" "*" + "@types/d3-random" "*" + "@types/d3-scale" "*" + "@types/d3-scale-chromatic" "*" + "@types/d3-selection" "*" + "@types/d3-shape" "*" + "@types/d3-time" "*" + "@types/d3-time-format" "*" + "@types/d3-timer" "*" + "@types/d3-transition" "*" + "@types/d3-zoom" "*" + +"@types/dagre@0.7.42": + version "0.7.42" + resolved "https://registry.yarnpkg.com/@types/dagre/-/dagre-0.7.42.tgz#2b0cd7678d5fc273df7816a88b8b34016e3a5d85" + integrity sha512-knVdi1Ul8xYgJ0wdhQ+/2YGJFKJFa/5srcPII9zvOs4KhsHfpnFrSTQXATYmjslglxRMif3Lg+wEZ0beag+94A== + "@types/eslint-scope@^3.7.3": version "3.7.7" resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.7.tgz#3108bd5f18b0cdb277c867b3dd449c9ed7079ac5" @@ -1051,6 +1328,11 @@ "@types/qs" "*" "@types/serve-static" "*" +"@types/geojson@*": + version "7946.0.14" + resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-7946.0.14.tgz#319b63ad6df705ee2a65a73ef042c8271e696613" + integrity sha512-WCfD5Ht3ZesJUsONdhvm84dmzWOiOzOAqOncN0++w0lBw1o8OuDNJF2McvvCef/yBqb/HYRahp1BYtODFQ8bRg== + "@types/graceful-fs@^4.1.3": version "4.1.9" resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.9.tgz#2a06bc0f68a20ab37b3e36aa238be6abdf49e8b4" @@ -1212,6 +1494,13 @@ dependencies: "@types/react" "^17" +"@types/react-measure@^2.0.6": + version "2.0.12" + resolved "https://registry.yarnpkg.com/@types/react-measure/-/react-measure-2.0.12.tgz#e8ba05057357b9529aa4115064fe7ea77549f54c" + integrity sha512-Y6V11CH6bU7RhqrIdENPwEUZlPXhfXNGylMNnGwq5TAEs2wDoBA3kSVVM/EQ8u72sz5r9ja+7W8M8PIVcS841Q== + dependencies: + "@types/react" "*" + "@types/react-router-dom@^5.3.2": version "5.3.3" resolved "https://registry.yarnpkg.com/@types/react-router-dom/-/react-router-dom-5.3.3.tgz#e9d6b4a66fcdbd651a5f106c2656a30088cc1e83" @@ -2454,6 +2743,11 @@ combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6: dependencies: delayed-stream "~1.0.0" +commander@7, commander@^7.0.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" + integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== + commander@^2.20.0: version "2.20.3" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" @@ -2464,11 +2758,6 @@ commander@^5.1.0: resolved "https://registry.yarnpkg.com/commander/-/commander-5.1.0.tgz#46abbd1652f8e059bddaef99bbdcb2ad9cf179ae" integrity sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg== -commander@^7.0.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" - integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== - commander@~9.4.1: version "9.4.1" resolved "https://registry.yarnpkg.com/commander/-/commander-9.4.1.tgz#d1dd8f2ce6faf93147295c0df13c7c21141cfbdd" @@ -2713,6 +3002,293 @@ cypress@11: untildify "^4.0.0" yauzl "^2.10.0" +"d3-array@2 - 3", "d3-array@2.10.0 - 3", "d3-array@2.5.0 - 3", d3-array@3, d3-array@^3.2.0: + version "3.2.4" + resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-3.2.4.tgz#15fec33b237f97ac5d7c986dc77da273a8ed0bb5" + integrity sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg== + dependencies: + internmap "1 - 2" + +d3-axis@3: + version "3.0.0" + resolved "https://registry.yarnpkg.com/d3-axis/-/d3-axis-3.0.0.tgz#c42a4a13e8131d637b745fc2973824cfeaf93322" + integrity sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw== + +d3-brush@3: + version "3.0.0" + resolved "https://registry.yarnpkg.com/d3-brush/-/d3-brush-3.0.0.tgz#6f767c4ed8dcb79de7ede3e1c0f89e63ef64d31c" + integrity sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ== + dependencies: + d3-dispatch "1 - 3" + d3-drag "2 - 3" + d3-interpolate "1 - 3" + d3-selection "3" + d3-transition "3" + +d3-chord@3: + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-chord/-/d3-chord-3.0.1.tgz#d156d61f485fce8327e6abf339cb41d8cbba6966" + integrity sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g== + dependencies: + d3-path "1 - 3" + +"d3-color@1 - 3", d3-color@3: + version "3.1.0" + resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-3.1.0.tgz#395b2833dfac71507f12ac2f7af23bf819de24e2" + integrity sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA== + +d3-contour@4: + version "4.0.2" + resolved "https://registry.yarnpkg.com/d3-contour/-/d3-contour-4.0.2.tgz#bb92063bc8c5663acb2422f99c73cbb6c6ae3bcc" + integrity sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA== + dependencies: + d3-array "^3.2.0" + +d3-delaunay@6: + version "6.0.4" + resolved "https://registry.yarnpkg.com/d3-delaunay/-/d3-delaunay-6.0.4.tgz#98169038733a0a5babbeda55054f795bb9e4a58b" + integrity sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A== + dependencies: + delaunator "5" + +d3-dispatch@1, d3-dispatch@^1.0.3: + version "1.0.6" + resolved "https://registry.yarnpkg.com/d3-dispatch/-/d3-dispatch-1.0.6.tgz#00d37bcee4dd8cd97729dd893a0ac29caaba5d58" + integrity sha512-fVjoElzjhCEy+Hbn8KygnmMS7Or0a9sI2UzGwoB7cCtvI1XpVN9GpoYlnb3xt2YV66oXYb1fLJ8GMvP4hdU1RA== + +"d3-dispatch@1 - 3", d3-dispatch@3: + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-dispatch/-/d3-dispatch-3.0.1.tgz#5fc75284e9c2375c36c839411a0cf550cbfc4d5e" + integrity sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg== + +"d3-drag@2 - 3", d3-drag@3: + version "3.0.0" + resolved "https://registry.yarnpkg.com/d3-drag/-/d3-drag-3.0.0.tgz#994aae9cd23c719f53b5e10e3a0a6108c69607ba" + integrity sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg== + dependencies: + d3-dispatch "1 - 3" + d3-selection "3" + +d3-drag@^1.0.4: + version "1.2.5" + resolved "https://registry.yarnpkg.com/d3-drag/-/d3-drag-1.2.5.tgz#2537f451acd39d31406677b7dc77c82f7d988f70" + integrity sha512-rD1ohlkKQwMZYkQlYVCrSFxsWPzI97+W+PaEIBNTMxRuxz9RF0Hi5nJWHGVJ3Om9d2fRTe1yOBINJyy/ahV95w== + dependencies: + d3-dispatch "1" + d3-selection "1" + +"d3-dsv@1 - 3", d3-dsv@3: + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-dsv/-/d3-dsv-3.0.1.tgz#c63af978f4d6a0d084a52a673922be2160789b73" + integrity sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q== + dependencies: + commander "7" + iconv-lite "0.6" + rw "1" + +"d3-ease@1 - 3", d3-ease@3: + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-ease/-/d3-ease-3.0.1.tgz#9658ac38a2140d59d346160f1f6c30fda0bd12f4" + integrity sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w== + +d3-fetch@3: + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-fetch/-/d3-fetch-3.0.1.tgz#83141bff9856a0edb5e38de89cdcfe63d0a60a22" + integrity sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw== + dependencies: + d3-dsv "1 - 3" + +d3-force@3: + version "3.0.0" + resolved "https://registry.yarnpkg.com/d3-force/-/d3-force-3.0.0.tgz#3e2ba1a61e70888fe3d9194e30d6d14eece155c4" + integrity sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg== + dependencies: + d3-dispatch "1 - 3" + d3-quadtree "1 - 3" + d3-timer "1 - 3" + +"d3-format@1 - 3", d3-format@3: + version "3.1.0" + resolved "https://registry.yarnpkg.com/d3-format/-/d3-format-3.1.0.tgz#9260e23a28ea5cb109e93b21a06e24e2ebd55641" + integrity sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA== + +d3-geo@3: + version "3.1.1" + resolved "https://registry.yarnpkg.com/d3-geo/-/d3-geo-3.1.1.tgz#6027cf51246f9b2ebd64f99e01dc7c3364033a4d" + integrity sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q== + dependencies: + d3-array "2.5.0 - 3" + +d3-hierarchy@3: + version "3.1.2" + resolved "https://registry.yarnpkg.com/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz#b01cd42c1eed3d46db77a5966cf726f8c09160c6" + integrity sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA== + +"d3-interpolate@1 - 3", "d3-interpolate@1.2.0 - 3", d3-interpolate@3: + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-interpolate/-/d3-interpolate-3.0.1.tgz#3c47aa5b32c5b3dfb56ef3fd4342078a632b400d" + integrity sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g== + dependencies: + d3-color "1 - 3" + +d3-path@1: + version "1.0.9" + resolved "https://registry.yarnpkg.com/d3-path/-/d3-path-1.0.9.tgz#48c050bb1fe8c262493a8caf5524e3e9591701cf" + integrity sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg== + +"d3-path@1 - 3", d3-path@3, d3-path@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/d3-path/-/d3-path-3.1.0.tgz#22df939032fb5a71ae8b1800d61ddb7851c42526" + integrity sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ== + +d3-polygon@3: + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-polygon/-/d3-polygon-3.0.1.tgz#0b45d3dd1c48a29c8e057e6135693ec80bf16398" + integrity sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg== + +"d3-quadtree@1 - 3", d3-quadtree@3: + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-quadtree/-/d3-quadtree-3.0.1.tgz#6dca3e8be2b393c9a9d514dabbd80a92deef1a4f" + integrity sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw== + +d3-random@3: + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-random/-/d3-random-3.0.1.tgz#d4926378d333d9c0bfd1e6fa0194d30aebaa20f4" + integrity sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ== + +d3-scale-chromatic@3: + version "3.1.0" + resolved "https://registry.yarnpkg.com/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz#34c39da298b23c20e02f1a4b239bd0f22e7f1314" + integrity sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ== + dependencies: + d3-color "1 - 3" + d3-interpolate "1 - 3" + +d3-scale@4: + version "4.0.2" + resolved "https://registry.yarnpkg.com/d3-scale/-/d3-scale-4.0.2.tgz#82b38e8e8ff7080764f8dcec77bd4be393689396" + integrity sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ== + dependencies: + d3-array "2.10.0 - 3" + d3-format "1 - 3" + d3-interpolate "1.2.0 - 3" + d3-time "2.1.1 - 3" + d3-time-format "2 - 4" + +d3-selection@1: + version "1.4.2" + resolved "https://registry.yarnpkg.com/d3-selection/-/d3-selection-1.4.2.tgz#dcaa49522c0dbf32d6c1858afc26b6094555bc5c" + integrity sha512-SJ0BqYihzOjDnnlfyeHT0e30k0K1+5sR3d5fNueCNeuhZTnGw4M4o8mqJchSwgKMXCNFo+e2VTChiSJ0vYtXkg== + +"d3-selection@2 - 3", d3-selection@3: + version "3.0.0" + resolved "https://registry.yarnpkg.com/d3-selection/-/d3-selection-3.0.0.tgz#c25338207efa72cc5b9bd1458a1a41901f1e1b31" + integrity sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ== + +d3-shape@3: + version "3.2.0" + resolved "https://registry.yarnpkg.com/d3-shape/-/d3-shape-3.2.0.tgz#a1a839cbd9ba45f28674c69d7f855bcf91dfc6a5" + integrity sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA== + dependencies: + d3-path "^3.1.0" + +d3-shape@^1.3.5: + version "1.3.7" + resolved "https://registry.yarnpkg.com/d3-shape/-/d3-shape-1.3.7.tgz#df63801be07bc986bc54f63789b4fe502992b5d7" + integrity sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw== + dependencies: + d3-path "1" + +"d3-time-format@2 - 4", d3-time-format@4: + version "4.1.0" + resolved "https://registry.yarnpkg.com/d3-time-format/-/d3-time-format-4.1.0.tgz#7ab5257a5041d11ecb4fe70a5c7d16a195bb408a" + integrity sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg== + dependencies: + d3-time "1 - 3" + +"d3-time@1 - 3", "d3-time@2.1.1 - 3", d3-time@3: + version "3.1.0" + resolved "https://registry.yarnpkg.com/d3-time/-/d3-time-3.1.0.tgz#9310db56e992e3c0175e1ef385e545e48a9bb5c7" + integrity sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q== + dependencies: + d3-array "2 - 3" + +"d3-timer@1 - 3", d3-timer@3: + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-timer/-/d3-timer-3.0.1.tgz#6284d2a2708285b1abb7e201eda4380af35e63b0" + integrity sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA== + +d3-timer@^1.0.5: + version "1.0.10" + resolved "https://registry.yarnpkg.com/d3-timer/-/d3-timer-1.0.10.tgz#dfe76b8a91748831b13b6d9c793ffbd508dd9de5" + integrity sha512-B1JDm0XDaQC+uvo4DT79H0XmBskgS3l6Ve+1SBCfxgmtIb1AVrPIoqd+nPSv+loMX8szQ0sVUhGngL7D5QPiXw== + +"d3-transition@2 - 3", d3-transition@3: + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-transition/-/d3-transition-3.0.1.tgz#6869fdde1448868077fdd5989200cb61b2a1645f" + integrity sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w== + dependencies: + d3-color "1 - 3" + d3-dispatch "1 - 3" + d3-ease "1 - 3" + d3-interpolate "1 - 3" + d3-timer "1 - 3" + +d3-zoom@3: + version "3.0.0" + resolved "https://registry.yarnpkg.com/d3-zoom/-/d3-zoom-3.0.0.tgz#d13f4165c73217ffeaa54295cd6969b3e7aee8f3" + integrity sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw== + dependencies: + d3-dispatch "1 - 3" + d3-drag "2 - 3" + d3-interpolate "1 - 3" + d3-selection "2 - 3" + d3-transition "2 - 3" + +d3@^7.8.0: + version "7.9.0" + resolved "https://registry.yarnpkg.com/d3/-/d3-7.9.0.tgz#579e7acb3d749caf8860bd1741ae8d371070cd5d" + integrity sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA== + dependencies: + d3-array "3" + d3-axis "3" + d3-brush "3" + d3-chord "3" + d3-color "3" + d3-contour "4" + d3-delaunay "6" + d3-dispatch "3" + d3-drag "3" + d3-dsv "3" + d3-ease "3" + d3-fetch "3" + d3-force "3" + d3-format "3" + d3-geo "3" + d3-hierarchy "3" + d3-interpolate "3" + d3-path "3" + d3-polygon "3" + d3-quadtree "3" + d3-random "3" + d3-scale "4" + d3-scale-chromatic "3" + d3-selection "3" + d3-shape "3" + d3-time "3" + d3-time-format "4" + d3-timer "3" + d3-transition "3" + d3-zoom "3" + +dagre@0.8.2: + version "0.8.2" + resolved "https://registry.yarnpkg.com/dagre/-/dagre-0.8.2.tgz#755b79f4d5499d63cf74c3368fb08add93eceafe" + integrity sha512-TEOOGZOkCOgCG7AoUIq64sJ3d21SMv8tyoqteLpX+UsUsS9Qw8iap4hhogXY4oB3r0bbZuAjO0atAilgCmsE0Q== + dependencies: + graphlib "^2.1.5" + lodash "^4.17.4" + dashdash@^1.12.0: version "1.14.1" resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" @@ -2861,6 +3437,13 @@ define-properties@^1.1.3, define-properties@^1.2.0, define-properties@^1.2.1: has-property-descriptors "^1.0.0" object-keys "^1.1.1" +delaunator@5: + version "5.0.1" + resolved "https://registry.yarnpkg.com/delaunator/-/delaunator-5.0.1.tgz#39032b08053923e924d6094fe2cde1a99cc51278" + integrity sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw== + dependencies: + robust-predicates "^3.0.2" + delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" @@ -3920,6 +4503,11 @@ get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.2, get-intrinsic@ has-symbols "^1.0.3" hasown "^2.0.0" +get-node-dimensions@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/get-node-dimensions/-/get-node-dimensions-1.2.1.tgz#fb7b4bb57060fb4247dd51c9d690dfbec56b0823" + integrity sha512-2MSPMu7S1iOTL+BOa6K1S62hB2zUAYNF/lV0gSVlOaacd087lc6nR1H1r0e3B1CerTo+RceOmi1iJW+vp21xcQ== + get-package-type@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" @@ -4081,6 +4669,13 @@ graphemer@^1.4.0: resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== +graphlib@^2.1.5: + version "2.1.8" + resolved "https://registry.yarnpkg.com/graphlib/-/graphlib-2.1.8.tgz#5761d414737870084c92ec7b5dbcb0592c9d35da" + integrity sha512-jcLLfkpoVGmH7/InMC/1hIvOPSUh38oJtGhvrOFGzioE1DZ+0YW16RgmOJhHiuWTvGiJQ9Z1Ik43JvkRPRvE+A== + dependencies: + lodash "^4.17.15" + gulp-sort@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/gulp-sort/-/gulp-sort-2.0.0.tgz#c6762a2f1f0de0a3fc595a21599d3fac8dba1aca" @@ -4383,7 +4978,7 @@ iconv-lite@0.4.24: dependencies: safer-buffer ">= 2.1.2 < 3" -iconv-lite@0.6.3: +iconv-lite@0.6, iconv-lite@0.6.3: version "0.6.3" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== @@ -4478,6 +5073,11 @@ internal-slot@^1.0.4, internal-slot@^1.0.7: hasown "^2.0.0" side-channel "^1.0.4" +"internmap@1 - 2": + version "2.0.3" + resolved "https://registry.yarnpkg.com/internmap/-/internmap-2.0.3.tgz#6685f23755e43c524e251d29cbc97248e3061009" + integrity sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg== + interpret@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/interpret/-/interpret-2.2.0.tgz#1a78a0b5965c40a5416d007ad6f50ad27c417df9" @@ -5581,7 +6181,7 @@ lodash.once@^4.1.1: resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" integrity sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg== -lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.21: +lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.21, lodash@^4.17.4: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -5758,6 +6358,23 @@ mktemp@~0.4.0: resolved "https://registry.yarnpkg.com/mktemp/-/mktemp-0.4.0.tgz#6d0515611c8a8c84e484aa2000129b98e981ff0b" integrity sha512-IXnMcJ6ZyTuhRmJSjzvHSRhlVPiN9Jwc6e59V0bEJ0ba6OBeX2L0E+mRN1QseeOF4mM+F1Rit6Nh7o+rl2Yn/A== +mobx-react-lite@^3.4.0: + version "3.4.3" + resolved "https://registry.yarnpkg.com/mobx-react-lite/-/mobx-react-lite-3.4.3.tgz#3a4c22c30bfaa8b1b2aa48d12b2ba811c0947ab7" + integrity sha512-NkJREyFTSUXR772Qaai51BnE1voWx56LOL80xG7qkZr6vo8vEaLF3sz1JNUVh+rxmUzxYaqOhfuxTfqUh0FXUg== + +mobx-react@^7.6.0: + version "7.6.0" + resolved "https://registry.yarnpkg.com/mobx-react/-/mobx-react-7.6.0.tgz#ebf0456728a9bd2e5c24fdcf9b36e285a222a7d6" + integrity sha512-+HQUNuh7AoQ9ZnU6c4rvbiVVl+wEkb9WqYsVDzGLng+Dqj1XntHu79PvEWKtSMoMj67vFp/ZPXcElosuJO8ckA== + dependencies: + mobx-react-lite "^3.4.0" + +mobx@^6.9.0: + version "6.13.1" + resolved "https://registry.yarnpkg.com/mobx/-/mobx-6.13.1.tgz#76c41aa675199f75b84a257e4bec8ff839e33259" + integrity sha512-ekLRxgjWJr8hVxj9ZKuClPwM/iHckx3euIJ3Np7zLVNtqJvfbbq7l370W/98C8EabdQ1pB5Jd3BbDWxJPNnaOg== + ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" @@ -6186,6 +6803,16 @@ pkg-dir@^4.2.0: dependencies: find-up "^4.0.0" +point-in-svg-path@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/point-in-svg-path/-/point-in-svg-path-1.0.2.tgz#e7b25370e96f58a858c34882ffb57d41b7a574bf" + integrity sha512-+Smsf7B9e7eRFHIwpN+4rE8inF2APbFWeywPfUgbeh02xdJSkbTz6Pqdt7A36wVCR+CnLbaNkRnBjgOpF5RMVQ== + +popper.js@^1.16.1: + version "1.16.1" + resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.16.1.tgz#2a223cb3dc7b6213d740e40372be40de43e65b1b" + integrity sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ== + portfinder@^1.0.28: version "1.0.32" resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.32.tgz#2fe1b9e58389712429dc2bea5beb2146146c7f81" @@ -6495,6 +7122,16 @@ react-is@^18.0.0: resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== +react-measure@^2.3.0: + version "2.5.2" + resolved "https://registry.yarnpkg.com/react-measure/-/react-measure-2.5.2.tgz#4ffc410e8b9cb836d9455a9ff18fc1f0fca67f89" + integrity sha512-M+rpbTLWJ3FD6FXvYV6YEGvQ5tMayQ3fGrZhRPHrE9bVlBYfDCLuDcgNttYfk8IqfOI03jz6cbpqMRTUclQnaA== + dependencies: + "@babel/runtime" "^7.2.0" + get-node-dimensions "^1.2.1" + prop-types "^15.6.2" + resize-observer-polyfill "^1.5.0" + react-redux@7.2.2: version "7.2.2" resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.2.2.tgz#03862e803a30b6b9ef8582dadcc810947f74b736" @@ -6716,6 +7353,11 @@ reselect@4.x: resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.1.8.tgz#3f5dc671ea168dccdeb3e141236f69f02eaec524" integrity sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ== +resize-observer-polyfill@^1.5.0: + version "1.5.1" + resolved "https://registry.yarnpkg.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz#0e9020dd3d21024458d4ebd27e23e40269810464" + integrity sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg== + resolve-cwd@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" @@ -6805,6 +7447,11 @@ rimraf@^3.0.0, rimraf@^3.0.2: dependencies: glob "^7.1.3" +robust-predicates@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/robust-predicates/-/robust-predicates-3.0.2.tgz#d5b28528c4824d20fc48df1928d41d9efa1ad771" + integrity sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg== + rsvp@^4.8.2: version "4.8.5" resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734" @@ -6822,6 +7469,11 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" +rw@1: + version "1.3.3" + resolved "https://registry.yarnpkg.com/rw/-/rw-1.3.3.tgz#3f862dfa91ab766b14885ef4d01124bfda074fb4" + integrity sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ== + rxjs@^7.5.1: version "7.8.1" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.1.tgz#6f6f3d99ea8044291efd92e7c7fcf562c4057543" @@ -7665,6 +8317,11 @@ tslib@^1.8.1: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== +tslib@^2.0.0: + version "2.6.3" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.3.tgz#0438f810ad7a9edcde7a241c3d80db693c8cbfe0" + integrity sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ== + tslib@^2.1.0, tslib@^2.4.0, tslib@^2.5.0: version "2.6.2" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" @@ -8063,6 +8720,16 @@ wbuf@^1.1.0, wbuf@^1.7.3: dependencies: minimalistic-assert "^1.0.0" +webcola@3.4.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/webcola/-/webcola-3.4.0.tgz#490d26ae98e5b5109478b94a846a62ff6831a99d" + integrity sha512-4BiLXjXw3SJHo3Xd+rF+7fyClT6n7I+AR6TkBqyQ4kTsePSAMDLRCXY1f3B/kXJeP9tYn4G1TblxTO+jAt0gaw== + dependencies: + d3-dispatch "^1.0.3" + d3-drag "^1.0.4" + d3-shape "^1.3.5" + d3-timer "^1.0.5" + webidl-conversions@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-7.0.0.tgz#256b4e1882be7debbf01d05f0aa2039778ea080a"