diff --git a/ui/dashboardApp/index.ts b/ui/dashboardApp/index.ts index 11245a155c..78d8a21188 100755 --- a/ui/dashboardApp/index.ts +++ b/ui/dashboardApp/index.ts @@ -36,6 +36,7 @@ import AppContinuousProfiling from '@lib/apps/ContinuousProfiling/index.meta' import AppQueryEditor from '@lib/apps/QueryEditor/index.meta' import AppConfiguration from '@lib/apps/Configuration/index.meta' import AppDebugAPI from '@lib/apps/DebugAPI/index.meta' +import AppOptimizerTrace from '@lib/apps/OptimizerTrace/index.meta' import { handleSSOCallback, isSSOCallback } from '@lib/utils/authSSO' import { mustLoadAppInfo, reloadWhoAmI, NgmState } from '@lib/utils/store' // import __APP_NAME__ from '@lib/apps/__APP_NAME__/index.meta' @@ -133,6 +134,7 @@ async function webPageStart() { .register(AppQueryEditor) .register(AppConfiguration) .register(AppDebugAPI) + .register(AppOptimizerTrace) // .register(__APP_NAME__) // NOTE: Don't remove above comment line, it is a placeholder for code generator diff --git a/ui/lib/apps/OptimizerTrace/components/LogicalOperatorTree.tsx b/ui/lib/apps/OptimizerTrace/components/LogicalOperatorTree.tsx new file mode 100644 index 0000000000..146b659b0e --- /dev/null +++ b/ui/lib/apps/OptimizerTrace/components/LogicalOperatorTree.tsx @@ -0,0 +1,74 @@ +import React, { useEffect, useRef } from 'react' +import { graphviz } from 'd3-graphviz' + +import styles from './OperatorTree.module.less' + +interface LogicalOperatorTreeProps { + data: LogicalOperatorNode[] + labels?: any + className?: string +} + +export interface LogicalOperatorNode { + id: number + children: number[] // children id + type: string + cost: number + selected: boolean + property: string + info: string +} + +export default function LogicalOperatorTree({ + data, + labels = {}, + className, +}: LogicalOperatorTreeProps) { + const containerRef = useRef(null) + + useEffect(() => { + const containerEl = containerRef.current + if (!containerEl) { + return + } + + const define = data + .map( + (n) => + `${n.id} ${createLabels({ + label: `${n.type}_${n.id}`, + color: labels.color || '', + tooltip: `info: ${n.info}`, + })};\n` + ) + .join('') + const link = data + .map((n) => + (n.children || []) + .map((c) => `${n.id} -> ${c} ${createLabels(labels)};\n`) + .join('') + ) + .join('') + + graphviz(containerEl).renderDot( + `digraph { +node [shape=ellipse fontsize=8 fontname="Verdana"]; +${define}\n${link}\n}` + ) + }, [containerRef, data, labels]) + + return ( +
+ ) +} + +export function createLabels(labels: { [props: string]: string } = {}): string { + const ls = Object.entries(labels).filter(([k, v]) => !!v) + if (!ls.length) { + return '' + } + return `[${ls.map(([k, v]) => `${k}="${v}"`).join(' ')}]` +} diff --git a/ui/lib/apps/OptimizerTrace/components/OperatorTree.module.less b/ui/lib/apps/OptimizerTrace/components/OperatorTree.module.less new file mode 100644 index 0000000000..80de4530c9 --- /dev/null +++ b/ui/lib/apps/OptimizerTrace/components/OperatorTree.module.less @@ -0,0 +1,9 @@ +.operator_tree { + height: 300px; + width: 200px; + + svg { + height: 100%; + width: 100%; + } +} diff --git a/ui/lib/apps/OptimizerTrace/components/PhysicalOperatorTree.tsx b/ui/lib/apps/OptimizerTrace/components/PhysicalOperatorTree.tsx new file mode 100644 index 0000000000..c5c7b433e3 --- /dev/null +++ b/ui/lib/apps/OptimizerTrace/components/PhysicalOperatorTree.tsx @@ -0,0 +1,67 @@ +import React, { useEffect, useRef } from 'react' +import { graphviz } from 'd3-graphviz' + +import styles from './OperatorTree.module.less' +import { LogicalOperatorNode, createLabels } from './LogicalOperatorTree' + +export interface PhysicalOperatorNode extends LogicalOperatorNode { + parentNode: null | PhysicalOperatorNode + childrenNodes: PhysicalOperatorNode[] + mapping: string +} + +interface PhysicalOperatorTreeProps { + data: PhysicalOperatorNode + className?: string +} + +export default function PhysicalOperatorTree({ + data, + className, +}: PhysicalOperatorTreeProps) { + const containerRef = useRef(null) + + useEffect(() => { + const containerEl = containerRef.current + if (!containerEl) { + return + } + + const allDatas = [data, ...(data.childrenNodes || [])] + const define = allDatas + .map( + (n) => + `${n.id} ${createLabels({ + label: `${n.type}_${n.id}\ncost: ${n.cost.toFixed(4)}`, + color: n.selected ? 'blue' : '', + tooltip: `info: ${n.info}`, + })};\n` + ) + .join('') + const link = allDatas + .map((n) => + (n.children || []) + .map( + (c) => + `${n.id} -- ${c} ${createLabels({ + color: n.selected ? 'blue' : '', + })};\n` + ) + .join('') + ) + .join('') + + graphviz(containerEl).renderDot( + `graph { + node [shape=ellipse fontsize=8 fontname="Verdana"]; + ${define}\n${link}\n}` + ) + }, [containerRef, data]) + + return ( +
+ ) +} diff --git a/ui/lib/apps/OptimizerTrace/index.meta.ts b/ui/lib/apps/OptimizerTrace/index.meta.ts new file mode 100644 index 0000000000..6c0ff213d6 --- /dev/null +++ b/ui/lib/apps/OptimizerTrace/index.meta.ts @@ -0,0 +1,8 @@ +import translations from './translations' + +export default { + id: 'optimizer_trace', + routerPrefix: '/optimizer_trace', + translations, + reactRoot: () => import('.'), +} diff --git a/ui/lib/apps/OptimizerTrace/index.module.less b/ui/lib/apps/OptimizerTrace/index.module.less new file mode 100644 index 0000000000..77d6f5fd7f --- /dev/null +++ b/ui/lib/apps/OptimizerTrace/index.module.less @@ -0,0 +1,37 @@ +.container { + overflow: auto; +} +.operator_tree { + flex-shrink: 0; +} + +.logical_optimize { + display: flex; + align-items: center; +} + +.arrow { + margin: 0 10px; +} + +.physical_operator_tree_container { + display: flex; + align-items: center; +} + +.unselected_candidates { + border: dashed 1px #ccc; + margin-left: 10px; + padding: 5px; +} + +.steps { + width: 200px; +} + +.step_info { + max-height: 90px; + width: 200px; + overflow: hidden; + text-overflow: ellipsis; +} diff --git a/ui/lib/apps/OptimizerTrace/index.tsx b/ui/lib/apps/OptimizerTrace/index.tsx new file mode 100644 index 0000000000..8c372bde0f --- /dev/null +++ b/ui/lib/apps/OptimizerTrace/index.tsx @@ -0,0 +1,267 @@ +import React, { useCallback, useState } from 'react' +import { HashRouter as Router, Routes, Route } from 'react-router-dom' +import { Button, Upload, Space, Alert, Tooltip } from 'antd' +import { UploadOutlined, ArrowRightOutlined } from '@ant-design/icons' +import { ErrorBoundary } from 'react-error-boundary' + +import { Card, Toolbar, Root } from '@lib/components' + +import styles from './index.module.less' +import LogicalOperatorTree, { + LogicalOperatorNode, +} from './components/LogicalOperatorTree' +import PhysicalOperatorTree, { + PhysicalOperatorNode, +} from './components/PhysicalOperatorTree' + +export default function OptimizeTraceApp() { + return ( + + + + } /> + + + + ) +} + +interface OptimizerData { + logical: { + final: LogicalOperatorNode[] + steps: LogicalOptimizeActionStep[] + } + physical: { + final: LogicalOperatorNode + selected_candidates: PhysicalOperatorNode[] + discarded_candidates: PhysicalOperatorNode[] + } + final: LogicalOperatorNode[] + isFastPlan: boolean +} + +interface LogicalOptimizeActionStep { + index: number + name: string + before: LogicalOperatorNode[] + steps: { + id: number + index: number + action: string + reason: string + type: string + }[] +} + +function OptimizerTrace() { + const [importedData, setImportedData] = useState(null) + const [errorMsg, setErrorMsg] = useState('') + + const handleBeforeUpload = useCallback(async (file: File) => { + setErrorMsg('') + + const t = await file.text() + setImportedData(JSON.parse(t)) + return false + }, []) + + return ( +
+ + + + + + + + + + + {errorMsg && ( + + + + )} + + { + setImportedData(null) + setErrorMsg(error.message) + resetErrorBoundary() + return null + }} + > + {importedData && ( + <> + + + + + )} + +
+ ) +} + +function LogicalOptimization({ data }: { data: OptimizerData }) { + const logicalData = data.logical + const Steps = () => ( + <> + {logicalData.steps.map((s) => { + const Action = () => ( +
+

{s.name}

+ {s.steps.map((actionStep, index) => { + const content = `action ${actionStep.index}: ${actionStep.action} + ${actionStep.reason && `, reason: ${actionStep.reason}`}` + return ( + +

+ {content} +

+
+ ) + })} +
+ ) + return ( + + + + + + + ) + })} + + ) + + return ( + + <> +

Logical Optimization

+
+ + +
+ +
+ ) +} + +function PhysicalOptimization({ data }: { data: OptimizerData }) { + const physicalData = data.physical + const selectedCandidates = physicalData.selected_candidates + const discardedCandidates = physicalData.discarded_candidates + const allCandidates = [...selectedCandidates, ...discardedCandidates] + const allCandidatesMap = allCandidates.reduce((acc, c) => { + acc[c.id] = c + return acc + }, {} as { [props: string]: PhysicalOperatorNode }) + const operatorCandidates = allCandidates.reduce((acc, c) => { + if (!acc[c.mapping]) { + acc[c.mapping] = [] + } + if (!!c.children?.length) { + if (!c.childrenNodes) { + c.childrenNodes = [] + } + c.childrenNodes.push( + ...c.children.map((cid) => { + const cnode = allCandidatesMap[cid] + cnode.parentNode = c + return cnode + }) + ) + } + acc[c.mapping].push(c) + return acc + }, {} as { [props: string]: PhysicalOperatorNode[] }) + const rootOperatorCandidates = Object.entries(operatorCandidates).map( + ([mapping, candidates]) => + [mapping, candidates.filter((c) => !c.parentNode)] as [ + string, + PhysicalOperatorNode[] + ] + ) + + const OperatorCandidates = () => ( + <> + {rootOperatorCandidates.map((m, index) => { + const selectedCandidates = m[1].filter((c) => c.selected) + const unselectedCandidates = m[1].filter((c) => !c.selected) + return ( +
+ {m[0]} + + <> + {selectedCandidates.map((c) => ( + + ))} + + {!!unselectedCandidates.length && ( +
+

unselected candidates

+ {unselectedCandidates.map((c) => ( + + ))} +
+ )} +
+ ) + })} + + ) + + return ( + +

Physical Optimization

+
+ +
+
+ ) +} + +function Final({ data }: { data: OptimizerData }) { + const finalData = data.final + + return ( + +

Final

+ +
+ ) +} diff --git a/ui/lib/apps/OptimizerTrace/translations/en.yaml b/ui/lib/apps/OptimizerTrace/translations/en.yaml new file mode 100755 index 0000000000..bf4187da44 --- /dev/null +++ b/ui/lib/apps/OptimizerTrace/translations/en.yaml @@ -0,0 +1 @@ +optimizer_trace: diff --git a/ui/lib/apps/OptimizerTrace/translations/index.ts b/ui/lib/apps/OptimizerTrace/translations/index.ts new file mode 100644 index 0000000000..a8c57746f6 --- /dev/null +++ b/ui/lib/apps/OptimizerTrace/translations/index.ts @@ -0,0 +1,4 @@ +import zh from './zh.yaml' +import en from './en.yaml' + +export default { zh, en } diff --git a/ui/lib/apps/OptimizerTrace/translations/zh.yaml b/ui/lib/apps/OptimizerTrace/translations/zh.yaml new file mode 100755 index 0000000000..bf4187da44 --- /dev/null +++ b/ui/lib/apps/OptimizerTrace/translations/zh.yaml @@ -0,0 +1 @@ +optimizer_trace: diff --git a/ui/package.json b/ui/package.json index 3fc73f2134..a9317b06be 100755 --- a/ui/package.json +++ b/ui/package.json @@ -27,6 +27,7 @@ "classnames": "^2.2.6", "cypress-real-events": "^1.7.0", "d3": "^5.16.0", + "d3-graphviz": "^4.1.0", "dayjs": "^1.10.7", "echarts": "^4.8.0", "echarts-for-react": "^2.0.16", @@ -45,6 +46,7 @@ "react-ace": "^9.1.1", "react-copy-to-clipboard": "^5.0.2", "react-dom": "^16.13.1", + "react-error-boundary": "^3.1.4", "react-highlight-words": "^0.16.0", "react-i18next": "^11.7.0", "react-markdown": "^7.1.0", @@ -92,6 +94,7 @@ "@cypress/code-coverage": "^3.9.12", "@openapitools/openapi-generator-cli": "^1.0.15-4.3.1", "@types/d3": "^5.7.2", + "@types/d3-graphviz": "^2.6.7", "@types/live-server": "^1.2.1", "@types/lodash": "^4.14.158", "@types/node": "^14.0.27", diff --git a/ui/public/graphvizlib.wasm b/ui/public/graphvizlib.wasm new file mode 100644 index 0000000000..374f5a2517 Binary files /dev/null and b/ui/public/graphvizlib.wasm differ diff --git a/ui/yarn.lock b/ui/yarn.lock index 9e9b6574e7..c36eb14d4a 100644 --- a/ui/yarn.lock +++ b/ui/yarn.lock @@ -2000,6 +2000,13 @@ "@types/react" "^16.0.34" "@types/react-dom" "^16.0.3" +"@hpcc-js/wasm@1.12.8": + version "1.12.8" + resolved "https://registry.npmmirror.com/@hpcc-js/wasm/-/wasm-1.12.8.tgz#c165251ec473ad9bb4d1c8c35ffcda9502b15f9f" + integrity sha512-n4q9ARKco2hpCLsuVaW6Az3cDVaua7B3DSONHkc49WtEzgY/btvcDG5Zr1P6PZDv0sQ7oPnAi9Y+W2DI++MgcQ== + dependencies: + yargs "^17.3.1" + "@humanwhocodes/config-array@^0.9.2": version "0.9.2" resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.9.2.tgz#68be55c737023009dfc5fe245d51181bb6476914" @@ -2190,6 +2197,11 @@ resolved "https://registry.yarnpkg.com/@types/d3-color/-/d3-color-1.2.2.tgz#80cf7cfff7401587b8f89307ba36fe4a576bc7cf" integrity sha512-6pBxzJ8ZP3dYEQ4YjQ+NVbQaOflfgXq/JbDiS99oLobM2o72uAST4q6yPxHv6FOTCRC/n35ktuo8pvw/S4M7sw== +"@types/d3-color@^1": + version "1.4.2" + resolved "https://registry.npmmirror.com/@types/d3-color/-/d3-color-1.4.2.tgz#944f281d04a0f06e134ea96adbb68303515b2784" + integrity sha512-fYtiVLBYy7VQX+Kx7wU/uOIkGQn8aAEY8oWMoyja3N4dLd8Yf6XgSIR/4yWvMuveNOH5VShnqCgRqqh/UNanBA== + "@types/d3-contour@*": version "1.3.0" resolved "https://registry.yarnpkg.com/@types/d3-contour/-/d3-contour-1.3.0.tgz#1a408b121fa5e341f715e3055303ef3079fc7eb0" @@ -2244,6 +2256,15 @@ dependencies: "@types/geojson" "*" +"@types/d3-graphviz@^2.6.7": + version "2.6.7" + resolved "https://registry.npmmirror.com/@types/d3-graphviz/-/d3-graphviz-2.6.7.tgz#48fbec73fe0d5a2a0e2c48b66c9dfe0cd2633ea9" + integrity sha512-dKJjD5HiFvAmC0FL/c70VB1diie8FCpyiCZfxMlf6TwYBqUyFvS4XJt6MoxjIuQTJhKDBGzrIvDOgM8gYMLSVA== + dependencies: + "@types/d3-selection" "^1" + "@types/d3-transition" "^1" + "@types/d3-zoom" "^1" + "@types/d3-hierarchy@*": version "1.1.6" resolved "https://registry.yarnpkg.com/@types/d3-hierarchy/-/d3-hierarchy-1.1.6.tgz#4c017521900813ea524c9ecb8d7985ec26a9ad9a" @@ -2256,6 +2277,13 @@ dependencies: "@types/d3-color" "*" +"@types/d3-interpolate@^1": + version "1.4.2" + resolved "https://registry.npmmirror.com/@types/d3-interpolate/-/d3-interpolate-1.4.2.tgz#88902a205f682773a517612299a44699285eed7b" + integrity sha512-ylycts6llFf8yAEs1tXzx2loxxzDZHseuhPokrqKprTQSTcD3JbJI1omZP1rphsELZO3Q+of3ff0ZS7+O6yVzg== + dependencies: + "@types/d3-color" "^1" + "@types/d3-path@*": version "1.0.8" resolved "https://registry.yarnpkg.com/@types/d3-path/-/d3-path-1.0.8.tgz#48e6945a8ff43ee0a1ce85c8cfa2337de85c7c79" @@ -2293,6 +2321,11 @@ resolved "https://registry.yarnpkg.com/@types/d3-selection/-/d3-selection-1.4.1.tgz#fa1f8710a6b5d7cfe5c6caa61d161be7cae4a022" integrity sha512-bv8IfFYo/xG6dxri9OwDnK3yCagYPeRIjTlrcdYJSx+FDWlCeBDepIHUpqROmhPtZ53jyna0aUajZRk0I3rXNA== +"@types/d3-selection@^1": + version "1.4.3" + resolved "https://registry.npmmirror.com/@types/d3-selection/-/d3-selection-1.4.3.tgz#36928bbe64eb8e0bbcbaa01fb05c21ff6c71fa93" + integrity sha512-GjKQWVZO6Sa96HiKO6R93VBE8DUW+DDkFpIMf9vpY5S78qZTlRRSNUsHr/afDpF7TvLDV7VxrUFOWW7vdIlYkA== + "@types/d3-shape@*": version "1.3.2" resolved "https://registry.yarnpkg.com/@types/d3-shape/-/d3-shape-1.3.2.tgz#a41d9d6b10d02e221696b240caf0b5d0f5a588ec" @@ -2322,6 +2355,13 @@ dependencies: "@types/d3-selection" "*" +"@types/d3-transition@^1": + version "1.3.2" + resolved "https://registry.npmmirror.com/@types/d3-transition/-/d3-transition-1.3.2.tgz#ed59beca7b4d679cfa52f88a6a50e5bbeb7e0a3c" + integrity sha512-J+a3SuF/E7wXbOSN19p8ZieQSFIm5hU2Egqtndbc54LXaAEOpLfDx4sBu/PKAKzHOdgKK1wkMhINKqNh4aoZAg== + dependencies: + "@types/d3-selection" "^1" + "@types/d3-voronoi@*": version "1.1.9" resolved "https://registry.yarnpkg.com/@types/d3-voronoi/-/d3-voronoi-1.1.9.tgz#7bbc210818a3a5c5e0bafb051420df206617c9e5" @@ -2335,6 +2375,14 @@ "@types/d3-interpolate" "*" "@types/d3-selection" "*" +"@types/d3-zoom@^1": + version "1.8.3" + resolved "https://registry.npmmirror.com/@types/d3-zoom/-/d3-zoom-1.8.3.tgz#00237900c6fdc2bb4fe82679ee4d74eb8fbe7b3c" + integrity sha512-3kHkL6sPiDdbfGhzlp5gIHyu3kULhtnHTTAl3UBZVtWB1PzcLL8vdmz5mTx7plLiUqOA2Y+yT2GKjt/TdA2p7Q== + dependencies: + "@types/d3-interpolate" "^1" + "@types/d3-selection" "^1" + "@types/d3@^5.7.2": version "5.7.2" resolved "https://registry.yarnpkg.com/@types/d3/-/d3-5.7.2.tgz#52235eb71a1d3ca171d6dca52a58f5ccbe0254cc" @@ -4009,6 +4057,15 @@ cliui@^6.0.0: strip-ansi "^6.0.0" wrap-ansi "^6.2.0" +cliui@^7.0.2: + version "7.0.4" + resolved "https://registry.npmmirror.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" + integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^7.0.0" + clone-buffer@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/clone-buffer/-/clone-buffer-1.0.0.tgz#e3e25b207ac4e701af721e2cb5a16792cac3dc58" @@ -4554,6 +4611,11 @@ d3-color@1, d3-color@^1.4.0: resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-1.4.1.tgz#c52002bf8846ada4424d55d97982fef26eb3bc8a" integrity sha512-p2sTHSLCJI2QKunbGb7ocOh7DgTAn8IrLx21QRc/BSnodXM4sv6aLQlnfpvehFMLZEfBc6g9pH9SWQccFYfJ9Q== +"d3-color@1 - 2": + version "2.0.0" + resolved "https://registry.npmmirror.com/d3-color/-/d3-color-2.0.0.tgz#8d625cab42ed9b8f601a1760a389f7ea9189d62e" + integrity sha512-SPXi0TSKPD4g9tw0NMZFnR95XVgUZiBH+uUTqQuDu1OsE2zomHU7ho0FISciaPvosimixwHFl3WHLGabv6dDgQ== + d3-contour@1: version "1.3.2" resolved "https://registry.yarnpkg.com/d3-contour/-/d3-contour-1.3.2.tgz#652aacd500d2264cb3423cee10db69f6f59bead3" @@ -4566,6 +4628,11 @@ d3-dispatch@1: resolved "https://registry.yarnpkg.com/d3-dispatch/-/d3-dispatch-1.0.6.tgz#00d37bcee4dd8cd97729dd893a0ac29caaba5d58" integrity sha512-fVjoElzjhCEy+Hbn8KygnmMS7Or0a9sI2UzGwoB7cCtvI1XpVN9GpoYlnb3xt2YV66oXYb1fLJ8GMvP4hdU1RA== +"d3-dispatch@1 - 2", d3-dispatch@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/d3-dispatch/-/d3-dispatch-2.0.0.tgz#8a18e16f76dd3fcaef42163c97b926aa9b55e7cf" + integrity sha512-S/m2VsXI7gAti2pBoLClFFTMOO1HTtT0j99AuXLoGFKO6deHDdnv6ZGTxSTTUTgO1zVcv82fCOtDjYK4EECmWA== + d3-drag@1: version "1.2.5" resolved "https://registry.yarnpkg.com/d3-drag/-/d3-drag-1.2.5.tgz#2537f451acd39d31406677b7dc77c82f7d988f70" @@ -4574,6 +4641,14 @@ d3-drag@1: d3-dispatch "1" d3-selection "1" +d3-drag@2: + version "2.0.0" + resolved "https://registry.npmmirror.com/d3-drag/-/d3-drag-2.0.0.tgz#9eaf046ce9ed1c25c88661911c1d5a4d8eb7ea6d" + integrity sha512-g9y9WbMnF5uqB9qKqwIIa/921RYWzlUDv9Jl1/yONQwxbOfszAWTCm8u7HOTgJgRDXiRZN56cHT9pd24dmXs8w== + dependencies: + d3-dispatch "1 - 2" + d3-selection "2" + d3-dsv@1: version "1.2.0" resolved "https://registry.yarnpkg.com/d3-dsv/-/d3-dsv-1.2.0.tgz#9d5f75c3a5f8abd611f74d3f5847b0d4338b885c" @@ -4588,6 +4663,11 @@ d3-ease@1: resolved "https://registry.yarnpkg.com/d3-ease/-/d3-ease-1.0.6.tgz#ebdb6da22dfac0a22222f2d4da06f66c416a0ec0" integrity sha512-SZ/lVU7LRXafqp7XtIcBdxnWl8yyLpgOmzAk0mWBI9gXNzLDx5ybZgnRbH9dN/yY5tzVBqCQ9avltSnqVwessQ== +"d3-ease@1 - 2": + version "2.0.0" + resolved "https://registry.npmmirror.com/d3-ease/-/d3-ease-2.0.0.tgz#fd1762bfca00dae4bacea504b1d628ff290ac563" + integrity sha512-68/n9JWarxXkOWMshcT5IcjbB+agblQUaIsbnXmrzejn2O82n3p2A9R2zEB9HIEFWKFwPAEDDN8gR0VdSAyyAQ== + d3-fetch@1: version "1.1.2" resolved "https://registry.yarnpkg.com/d3-fetch/-/d3-fetch-1.1.2.tgz#957c8fbc6d4480599ba191b1b2518bf86b3e1be2" @@ -4610,6 +4690,11 @@ d3-format@1: resolved "https://registry.yarnpkg.com/d3-format/-/d3-format-1.4.4.tgz#356925f28d0fd7c7983bfad593726fce46844030" integrity sha512-TWks25e7t8/cqctxCmxpUuzZN11QxIA7YrMbram94zMQ0PXjE4LVIMe/f6a4+xxL8HQ3OsAFULOINQi1pE62Aw== +d3-format@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/d3-format/-/d3-format-2.0.0.tgz#a10bcc0f986c372b729ba447382413aabf5b0767" + integrity sha512-Ab3S6XuE/Q+flY96HXT0jOXcM4EAClYFnRGY5zsjRGNy6qCYrQsMffs7cV5Q9xejb35zxW5hf/guKw34kvIKsA== + d3-geo@1: version "1.12.0" resolved "https://registry.yarnpkg.com/d3-geo/-/d3-geo-1.12.0.tgz#58ddbdf4d9db5f199db69d1b7c93dca6454a6f24" @@ -4617,6 +4702,20 @@ d3-geo@1: dependencies: d3-array "1" +d3-graphviz@^4.1.0: + version "4.1.0" + resolved "https://registry.npmmirror.com/d3-graphviz/-/d3-graphviz-4.1.0.tgz#1ee7ce550bdb95ba399df1a40498fbbb65c85f74" + integrity sha512-RtCGnEROcte5npTfjhiNR3kSbwhBl8LA6NNq0oFRXEIFB9N4xHQgGjZWfAHVsN9NQVctEEkRQ4H0GGdqfStlZQ== + dependencies: + "@hpcc-js/wasm" "1.12.8" + d3-dispatch "^2.0.0" + d3-format "^2.0.0" + d3-interpolate "^2.0.1" + d3-path "^2.0.0" + d3-timer "^2.0.0" + d3-transition "^2.0.0" + d3-zoom "^2.0.0" + d3-hierarchy@1: version "1.1.9" resolved "https://registry.yarnpkg.com/d3-hierarchy/-/d3-hierarchy-1.1.9.tgz#2f6bee24caaea43f8dc37545fa01628559647a83" @@ -4629,11 +4728,23 @@ d3-interpolate@1: dependencies: d3-color "1" +"d3-interpolate@1 - 2", d3-interpolate@^2.0.1: + version "2.0.1" + resolved "https://registry.npmmirror.com/d3-interpolate/-/d3-interpolate-2.0.1.tgz#98be499cfb8a3b94d4ff616900501a64abc91163" + integrity sha512-c5UhwwTs/yybcmTpAVqwSFl6vrQ8JZJoT5F7xNFK9pymv5C0Ymcc9/LIJHtYIggg/yS9YHw8i8O8tgb9pupjeQ== + dependencies: + d3-color "1 - 2" + 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@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/d3-path/-/d3-path-2.0.0.tgz#55d86ac131a0548adae241eebfb56b4582dd09d8" + integrity sha512-ZwZQxKhBnv9yHaiWd6ZU4x5BtCQ7pXszEV9CU6kRgwIQVQGLMv1oiL4M+MK/n79sYzsj+gcgpPQSctJUsLN7fA== + d3-polygon@1: version "1.0.6" resolved "https://registry.yarnpkg.com/d3-polygon/-/d3-polygon-1.0.6.tgz#0bf8cb8180a6dc107f518ddf7975e12abbfbd38e" @@ -4687,6 +4798,11 @@ d3-selection@1, d3-selection@^1.1.0: resolved "https://registry.yarnpkg.com/d3-selection/-/d3-selection-1.4.1.tgz#98eedbbe085fbda5bafa2f9e3f3a2f4d7d622a98" integrity sha512-BTIbRjv/m5rcVTfBs4AMBLKs4x8XaaLkwm28KWu9S2vKNqXkXt2AH2Qf0sdPZHjFxcWg/YL53zcqAz+3g4/7PA== +d3-selection@2: + version "2.0.0" + resolved "https://registry.npmmirror.com/d3-selection/-/d3-selection-2.0.0.tgz#94a11638ea2141b7565f883780dabc7ef6a61066" + integrity sha512-XoGGqhLUN/W14NmaqcO/bb1nqjDAw5WtSYb2X8wiuQWvSZUsUVYsOSkOybUrNvcBjaywBdYPy03eXHMXjk9nZA== + d3-shape@1, d3-shape@^1.3.4: version "1.3.7" resolved "https://registry.yarnpkg.com/d3-shape/-/d3-shape-1.3.7.tgz#df63801be07bc986bc54f63789b4fe502992b5d7" @@ -4711,6 +4827,11 @@ d3-timer@1: resolved "https://registry.yarnpkg.com/d3-timer/-/d3-timer-1.0.10.tgz#dfe76b8a91748831b13b6d9c793ffbd508dd9de5" integrity sha512-B1JDm0XDaQC+uvo4DT79H0XmBskgS3l6Ve+1SBCfxgmtIb1AVrPIoqd+nPSv+loMX8szQ0sVUhGngL7D5QPiXw== +"d3-timer@1 - 2", d3-timer@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/d3-timer/-/d3-timer-2.0.0.tgz#055edb1d170cfe31ab2da8968deee940b56623e6" + integrity sha512-TO4VLh0/420Y/9dO3+f9abDEFYeCUr2WZRlxJvbp4HPTQcSylXNiL6yZa9FIUvV1yRiFufl1bszTCLDqv9PWNA== + d3-transition@1: version "1.3.2" resolved "https://registry.yarnpkg.com/d3-transition/-/d3-transition-1.3.2.tgz#a98ef2151be8d8600543434c1ca80140ae23b398" @@ -4723,6 +4844,17 @@ d3-transition@1: d3-selection "^1.1.0" d3-timer "1" +d3-transition@2, d3-transition@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/d3-transition/-/d3-transition-2.0.0.tgz#366ef70c22ef88d1e34105f507516991a291c94c" + integrity sha512-42ltAGgJesfQE3u9LuuBHNbGrI/AJjNL2OAUdclE70UE6Vy239GCBEYD38uBPoLeNsOhFStGpPI0BAOV+HMxog== + dependencies: + d3-color "1 - 2" + d3-dispatch "1 - 2" + d3-ease "1 - 2" + d3-interpolate "1 - 2" + d3-timer "1 - 2" + d3-voronoi@1: version "1.1.4" resolved "https://registry.yarnpkg.com/d3-voronoi/-/d3-voronoi-1.1.4.tgz#dd3c78d7653d2bb359284ae478645d95944c8297" @@ -4739,6 +4871,17 @@ d3-zoom@1: d3-selection "1" d3-transition "1" +d3-zoom@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/d3-zoom/-/d3-zoom-2.0.0.tgz#f04d0afd05518becce879d04709c47ecd93fba54" + integrity sha512-fFg7aoaEm9/jf+qfstak0IYpnesZLiMX6GZvXtUSdv8RH2o4E2qeelgdU09eKS6wGuiGMfcnMI0nTIqWzRHGpw== + dependencies: + d3-dispatch "1 - 2" + d3-drag "2" + d3-interpolate "1 - 2" + d3-selection "2" + d3-transition "2" + d3@^5.16.0: version "5.16.0" resolved "https://registry.yarnpkg.com/d3/-/d3-5.16.0.tgz#9c5e8d3b56403c79d4ed42fbd62f6113f199c877" @@ -6323,7 +6466,7 @@ get-caller-file@^1.0.1: resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w== -get-caller-file@^2.0.1: +get-caller-file@^2.0.1, get-caller-file@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== @@ -10185,6 +10328,13 @@ react-dom@^16.13.1: prop-types "^15.6.2" scheduler "^0.19.1" +react-error-boundary@^3.1.4: + version "3.1.4" + resolved "https://registry.npmmirror.com/react-error-boundary/-/react-error-boundary-3.1.4.tgz#255db92b23197108757a888b01e5b729919abde0" + integrity sha512-uM9uPzZJTF6wRQORmSrvOIgt4lJ9MC1sNgEOj2XGsDTRE4kmpWxg7ENK9EWNKJRMAOY9z0MuF4yIfl6gp4sotA== + dependencies: + "@babel/runtime" "^7.12.5" + react-highlight-words@^0.16.0: version "0.16.0" resolved "https://registry.yarnpkg.com/react-highlight-words/-/react-highlight-words-0.16.0.tgz#4b4b9824e3d2b98789d3e3b3aedb5e961ae1b7cf" @@ -11394,6 +11544,15 @@ string-width@^4.1.0, string-width@^4.2.0: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.0" +string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.npmmirror.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + string.prototype.matchall@^4.0.6: version "4.0.6" resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.6.tgz#5abb5dabc94c7b0ea2380f65ba610b3a544b15fa" @@ -12494,6 +12653,11 @@ y18n@^4.0.0: resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w== +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.npmmirror.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + yallist@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" @@ -12530,6 +12694,11 @@ yargs-parser@^18.1.2: camelcase "^5.0.0" decamelize "^1.2.0" +yargs-parser@^21.0.0: + version "21.0.1" + resolved "https://registry.npmmirror.com/yargs-parser/-/yargs-parser-21.0.1.tgz#0267f286c877a4f0f728fceb6f8a3e4cb95c6e35" + integrity sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg== + yargs@^15.0.2: version "15.4.1" resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8" @@ -12547,6 +12716,19 @@ yargs@^15.0.2: y18n "^4.0.0" yargs-parser "^18.1.2" +yargs@^17.3.1: + version "17.3.1" + resolved "https://registry.npmmirror.com/yargs/-/yargs-17.3.1.tgz#da56b28f32e2fd45aefb402ed9c26f42be4c07b9" + integrity sha512-WUANQeVgjLbNsEmGk20f+nlHgOqzRFpiGWVaBrYGYIGANIIu3lWjoyi0fNlFmJkvfhCZ6BXINe7/W2O2bV4iaA== + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.3" + y18n "^5.0.5" + yargs-parser "^21.0.0" + yargs@^7.1.0: version "7.1.1" resolved "https://registry.yarnpkg.com/yargs/-/yargs-7.1.1.tgz#67f0ef52e228d4ee0d6311acede8850f53464df6"