diff --git a/catalog-rest-service/src/main/resources/ui/package-lock.json b/catalog-rest-service/src/main/resources/ui/package-lock.json index 8688be66d41..abd03f44ac1 100644 --- a/catalog-rest-service/src/main/resources/ui/package-lock.json +++ b/catalog-rest-service/src/main/resources/ui/package-lock.json @@ -3495,6 +3495,228 @@ "@types/tern": "*" } }, + "@types/d3": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@types/d3/-/d3-7.0.0.tgz", + "integrity": "sha512-7rMMuS5unvbvFCJXAkQXIxWTo2OUlmVXN5q7sfQFesuVICY55PSP6hhbUhWjTTNpfTTB3iLALsIYDFe7KUNABw==", + "requires": { + "@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/d3-array": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.0.1.tgz", + "integrity": "sha512-D/G7oG0czeszALrkdUiV68CDiHDxXf+M2mLVqAyKktGd12VKQQljj1sHJGBKjcK4jRH1biBd6ZPQPHpJ0mNa0w==" + }, + "@types/d3-axis": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-axis/-/d3-axis-3.0.1.tgz", + "integrity": "sha512-zji/iIbdd49g9WN0aIsGcwcTBUkgLsCSwB+uH+LPVDAiKWENMtI3cJEWt+7/YYwelMoZmbBfzA3qCdrZ2XFNnw==", + "requires": { + "@types/d3-selection": "*" + } + }, + "@types/d3-brush": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-brush/-/d3-brush-3.0.1.tgz", + "integrity": "sha512-B532DozsiTuQMHu2YChdZU0qsFJSio3Q6jmBYGYNp3gMDzBmuFFgPt9qKA4VYuLZMp4qc6eX7IUFUEsvHiXZAw==", + "requires": { + "@types/d3-selection": "*" + } + }, + "@types/d3-chord": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-chord/-/d3-chord-3.0.1.tgz", + "integrity": "sha512-eQfcxIHrg7V++W8Qxn6QkqBNBokyhdWSAS73AbkbMzvLQmVVBviknoz2SRS/ZJdIOmhcmmdCRE/NFOm28Z1AMw==" + }, + "@types/d3-color": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.0.2.tgz", + "integrity": "sha512-WVx6zBiz4sWlboCy7TCgjeyHpNjMsoF36yaagny1uXfbadc9f+5BeBf7U+lRmQqY3EHbGQpP8UdW8AC+cywSwQ==" + }, + "@types/d3-contour": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-contour/-/d3-contour-3.0.1.tgz", + "integrity": "sha512-C3zfBrhHZvrpAAK3YXqLWVAGo87A4SvJ83Q/zVJ8rFWJdKejUnDYaWZPkA8K84kb2vDA/g90LTQAz7etXcgoQQ==", + "requires": { + "@types/d3-array": "*", + "@types/geojson": "*" + } + }, + "@types/d3-delaunay": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@types/d3-delaunay/-/d3-delaunay-6.0.0.tgz", + "integrity": "sha512-iGm7ZaGLq11RK3e69VeMM6Oqj2SjKUB9Qhcyd1zIcqn2uE8w9GFB445yCY46NOQO3ByaNyktX1DK+Etz7ZaX+w==" + }, + "@types/d3-dispatch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-dispatch/-/d3-dispatch-3.0.1.tgz", + "integrity": "sha512-NhxMn3bAkqhjoxabVJWKryhnZXXYYVQxaBnbANu0O94+O/nX9qSjrA1P1jbAQJxJf+VC72TxDX/YJcKue5bRqw==" + }, + "@types/d3-drag": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-drag/-/d3-drag-3.0.1.tgz", + "integrity": "sha512-o1Va7bLwwk6h03+nSM8dpaGEYnoIG19P0lKqlic8Un36ymh9NSkNFX1yiXMKNMx8rJ0Kfnn2eovuFaL6Jvj0zA==", + "requires": { + "@types/d3-selection": "*" + } + }, + "@types/d3-dsv": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/d3-dsv/-/d3-dsv-3.0.0.tgz", + "integrity": "sha512-o0/7RlMl9p5n6FQDptuJVMxDf/7EDEv2SYEO/CwdG2tr1hTfUVi0Iavkk2ax+VpaQ/1jVhpnj5rq1nj8vwhn2A==" + }, + "@types/d3-ease": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.0.tgz", + "integrity": "sha512-aMo4eaAOijJjA6uU+GIeW018dvy9+oH5Y2VPPzjjfxevvGQ/oRDs+tfYC9b50Q4BygRR8yE2QCLsrT0WtAVseA==" + }, + "@types/d3-fetch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-fetch/-/d3-fetch-3.0.1.tgz", + "integrity": "sha512-toZJNOwrOIqz7Oh6Q7l2zkaNfXkfR7mFSJvGvlD/Ciq/+SQ39d5gynHJZ/0fjt83ec3WL7+u3ssqIijQtBISsw==", + "requires": { + "@types/d3-dsv": "*" + } + }, + "@types/d3-force": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-force/-/d3-force-3.0.3.tgz", + "integrity": "sha512-z8GteGVfkWJMKsx6hwC3SiTSLspL98VNpmvLpEFJQpZPq6xpA1I8HNBDNSpukfK0Vb0l64zGFhzunLgEAcBWSA==" + }, + "@types/d3-format": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-3.0.1.tgz", + "integrity": "sha512-5KY70ifCCzorkLuIkDe0Z9YTf9RR2CjBX1iaJG+rgM/cPP+sO+q9YdQ9WdhQcgPj1EQiJ2/0+yUkkziTG6Lubg==" + }, + "@types/d3-geo": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-geo/-/d3-geo-3.0.2.tgz", + "integrity": "sha512-DbqK7MLYA8LpyHQfv6Klz0426bQEf7bRTvhMy44sNGVyZoWn//B0c+Qbeg8Osi2Obdc9BLLXYAKpyWege2/7LQ==", + "requires": { + "@types/geojson": "*" + } + }, + "@types/d3-hierarchy": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-hierarchy/-/d3-hierarchy-3.0.2.tgz", + "integrity": "sha512-+krnrWOZ+aQB6v+E+jEkmkAx9HvsNAD+1LCD0vlBY3t+HwjKnsBFbpVLx6WWzDzCIuiTWdAxXMEnGnVXpB09qQ==" + }, + "@types/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-jx5leotSeac3jr0RePOH1KdR9rISG91QIE4Q2PYTu4OymLTZfA3SrnURSLzKH48HmXVUru50b8nje4E79oQSQw==", + "requires": { + "@types/d3-color": "*" + } + }, + "@types/d3-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.0.0.tgz", + "integrity": "sha512-0g/A+mZXgFkQxN3HniRDbXMN79K3CdTpLsevj+PXiTcb2hVyvkZUBg37StmgCQkaD84cUJ4uaDAWq7UJOQy2Tg==" + }, + "@types/d3-polygon": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/d3-polygon/-/d3-polygon-3.0.0.tgz", + "integrity": "sha512-D49z4DyzTKXM0sGKVqiTDTYr+DHg/uxsiWDAkNrwXYuiZVd9o9wXZIo+YsHkifOiyBkmSWlEngHCQme54/hnHw==" + }, + "@types/d3-quadtree": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-quadtree/-/d3-quadtree-3.0.2.tgz", + "integrity": "sha512-QNcK8Jguvc8lU+4OfeNx+qnVy7c0VrDJ+CCVFS9srBo2GL9Y18CnIxBdTF3v38flrGy5s1YggcoAiu6s4fLQIw==" + }, + "@types/d3-random": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-3.0.1.tgz", + "integrity": "sha512-IIE6YTekGczpLYo/HehAy3JGF1ty7+usI97LqraNa8IiDur+L44d0VOjAvFQWJVdZOJHukUJw+ZdZBlgeUsHOQ==" + }, + "@types/d3-scale": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.1.tgz", + "integrity": "sha512-GDuXcRcR6mKcpUVMhPNttpOzHi2dP6YcDqLZYSZHgwTZ+sfCa8e9q0VEBwZomblAPNMYpVqxojnSyIEb4s/Pwg==", + "requires": { + "@types/d3-time": "*" + } + }, + "@types/d3-scale-chromatic": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.0.0.tgz", + "integrity": "sha512-dsoJGEIShosKVRBZB0Vo3C8nqSDqVGujJU6tPznsBJxNJNwMF8utmS83nvCBKQYPpjCzaaHcrf66iTRpZosLPw==" + }, + "@types/d3-selection": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.1.tgz", + "integrity": "sha512-aJ1d1SCUtERHH65bB8NNoLpUOI3z8kVcfg2BGm4rMMUwuZF4x6qnIEKjT60Vt0o7gP/a/xkRVs4D9CpDifbyRA==" + }, + "@types/d3-shape": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.0.2.tgz", + "integrity": "sha512-5+ButCmIfNX8id5seZ7jKj3igdcxx+S9IDBiT35fQGTLZUfkFgTv+oBH34xgeoWDKpWcMITSzBILWQtBoN5Piw==", + "requires": { + "@types/d3-path": "*" + } + }, + "@types/d3-time": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.0.tgz", + "integrity": "sha512-sZLCdHvBUcNby1cB6Fd3ZBrABbjz3v1Vm90nysCQ6Vt7vd6e/h9Lt7SiJUoEX0l4Dzc7P5llKyhqSi1ycSf1Hg==" + }, + "@types/d3-time-format": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-4.0.0.tgz", + "integrity": "sha512-yjfBUe6DJBsDin2BMIulhSHmr5qNR5Pxs17+oW4DoVPyVIXZ+m6bs7j1UVKP08Emv6jRmYrYqxYzO63mQxy1rw==" + }, + "@types/d3-timer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.0.tgz", + "integrity": "sha512-HNB/9GHqu7Fo8AQiugyJbv6ZxYz58wef0esl4Mv828w1ZKpAshw/uFWVDUcIB9KKFeFKoxS3cHY07FFgtTRZ1g==" + }, + "@types/d3-transition": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-3.0.1.tgz", + "integrity": "sha512-Sv4qEI9uq3bnZwlOANvYK853zvpdKEm1yz9rcc8ZTsxvRklcs9Fx4YFuGA3gXoQN/c/1T6QkVNjhaRO/cWj94g==", + "requires": { + "@types/d3-selection": "*" + } + }, + "@types/d3-zoom": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-3.0.1.tgz", + "integrity": "sha512-7s5L9TjfqIYQmQQEUcpMAcBOahem7TRoSO/+Gkz02GbMVuULiZzjF2BOdw291dbO2aNon4m2OdFsRGaCq2caLQ==", + "requires": { + "@types/d3-interpolate": "*", + "@types/d3-selection": "*" + } + }, "@types/eslint": { "version": "7.28.0", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-7.28.0.tgz", @@ -3531,6 +3753,11 @@ "integrity": "sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw==", "dev": true }, + "@types/geojson": { + "version": "7946.0.8", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.8.tgz", + "integrity": "sha512-1rkryxURpr6aWP7R786/UQOkJ3PcpQiWkAXBmdWc7ryFWqN6a4xfK7BtjXvFBKO9LjQ+MWQSWxYeZX1OApnArA==" + }, "@types/glob": { "version": "7.1.4", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.4.tgz", @@ -3564,6 +3791,15 @@ "integrity": "sha512-MUc6zSmU3tEVnkQ78q0peeEjKWPUADMlC/t++2bI8WnAG2tvYRPIgHG8lWkXwqc8MsUF6Z2MOf+Mh5sazOmhiQ==", "dev": true }, + "@types/hoist-non-react-statics": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz", + "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==", + "requires": { + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0" + } + }, "@types/html-minifier-terser": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-5.1.2.tgz", @@ -3783,6 +4019,17 @@ "@types/react": "*" } }, + "@types/react-redux": { + "version": "7.1.19", + "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.19.tgz", + "integrity": "sha512-L37dSCT0aoJnCgpR8Iuginlbxoh7qhWOXiaDqEsxVMrER1CmVhFD+63NxgJeT4pkmEM28oX0NH4S4f+sXHTZjA==", + "requires": { + "@types/hoist-non-react-statics": "^3.3.0", + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0", + "redux": "^4.0.0" + } + }, "@types/react-router": { "version": "5.1.16", "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.16.tgz", @@ -5574,6 +5821,11 @@ } } }, + "classcat": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/classcat/-/classcat-5.0.3.tgz", + "integrity": "sha512-6dK2ke4VEJZOFx2ZfdDAl5OhEL8lvkl6EHF92IfRePfHxQTqir5NlcNVUv+2idjDqCX2NDc8m8YSAI5NI975ZQ==" + }, "classnames": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz", @@ -6444,6 +6696,25 @@ "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-1.4.1.tgz", "integrity": "sha512-p2sTHSLCJI2QKunbGb7ocOh7DgTAn8IrLx21QRc/BSnodXM4sv6aLQlnfpvehFMLZEfBc6g9pH9SWQccFYfJ9Q==" }, + "d3-dispatch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", + "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==" + }, + "d3-drag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", + "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", + "requires": { + "d3-dispatch": "1 - 3", + "d3-selection": "3" + } + }, + "d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==" + }, "d3-format": { "version": "1.4.5", "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-1.4.5.tgz", @@ -6475,6 +6746,11 @@ "d3-time-format": "2" } }, + "d3-selection": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", + "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==" + }, "d3-shape": { "version": "1.3.7", "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz", @@ -6496,6 +6772,35 @@ "d3-time": "1" } }, + "d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==" + }, + "d3-transition": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", + "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", + "requires": { + "d3-color": "1 - 3", + "d3-dispatch": "1 - 3", + "d3-ease": "1 - 3", + "d3-interpolate": "1 - 3", + "d3-timer": "1 - 3" + } + }, + "d3-zoom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", + "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", + "requires": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "2 - 3", + "d3-transition": "2 - 3" + } + }, "damerau-levenshtein": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.7.tgz", @@ -17323,6 +17628,15 @@ "prop-types": "^15.7.2" } }, + "react-draggable": { + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/react-draggable/-/react-draggable-4.4.4.tgz", + "integrity": "sha512-6e0WdcNLwpBx/YIDpoyd2Xb04PB0elrDrulKUgdrIlwuYvxh5Ok9M+F8cljm8kPXXs43PmMzek9RrB1b7mLMqA==", + "requires": { + "clsx": "^1.1.1", + "prop-types": "^15.6.0" + } + }, "react-dropdown": { "version": "1.9.2", "resolved": "https://registry.npmjs.org/react-dropdown/-/react-dropdown-1.9.2.tgz", @@ -17340,6 +17654,33 @@ "@babel/runtime": "^7.12.5" } }, + "react-flow-renderer": { + "version": "9.6.8", + "resolved": "https://registry.npmjs.org/react-flow-renderer/-/react-flow-renderer-9.6.8.tgz", + "integrity": "sha512-dMPOV6XXUZZ8WKZzP5mYBM3fWprq+cCjUJ+DolOQvdiGwB/ak1fRBeb/LZE3xZ20escTeW2n/u+EzlZgzWtsAA==", + "requires": { + "@babel/runtime": "^7.15.4", + "@types/d3": "^7.0.0", + "@types/react-redux": "^7.1.18", + "classcat": "^5.0.3", + "d3-selection": "^3.0.0", + "d3-zoom": "^3.0.0", + "fast-deep-equal": "^3.1.3", + "react-draggable": "^4.4.4", + "react-redux": "^7.2.5", + "redux": "^4.1.1" + }, + "dependencies": { + "@babel/runtime": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.15.4.tgz", + "integrity": "sha512-99catp6bHCaxr4sJ/DbTGgHS4+Rs2RVd2g7iOap6SLGPDknRK9ztKNsE/Fg6QhSeh1FGE5f6gHGQmvvn3I3xhw==", + "requires": { + "regenerator-runtime": "^0.13.4" + } + } + } + }, "react-input-autosize": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/react-input-autosize/-/react-input-autosize-3.0.0.tgz", @@ -17434,6 +17775,19 @@ "resolved": "https://registry.npmjs.org/react-property/-/react-property-1.0.1.tgz", "integrity": "sha512-1tKOwxFn3dXVomH6pM9IkLkq2Y8oh+fh/lYW3MJ/B03URswUTqttgckOlbxY2XHF3vPG6uanSc4dVsLW/wk3wQ==" }, + "react-redux": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.5.tgz", + "integrity": "sha512-Dt29bNyBsbQaysp6s/dN0gUodcq+dVKKER8Qv82UrpeygwYeX1raTtil7O/fftw/rFqzaf6gJhDZRkkZnn6bjg==", + "requires": { + "@babel/runtime": "^7.12.1", + "@types/react-redux": "^7.1.16", + "hoist-non-react-statics": "^3.3.2", + "loose-envify": "^1.4.0", + "prop-types": "^15.7.2", + "react-is": "^16.13.1" + } + }, "react-resize-detector": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/react-resize-detector/-/react-resize-detector-2.3.0.tgz", @@ -17749,6 +18103,14 @@ "balanced-match": "^1.0.0" } }, + "redux": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.1.1.tgz", + "integrity": "sha512-hZQZdDEM25UY2P493kPYuKqviVwZ58lEmGQNeQ+gXa+U0gYPUBf7NKYazbe3m+bs/DzM/ahN12DbF+NG8i0CWw==", + "requires": { + "@babel/runtime": "^7.9.2" + } + }, "refractor": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/refractor/-/refractor-3.4.0.tgz", diff --git a/catalog-rest-service/src/main/resources/ui/package.json b/catalog-rest-service/src/main/resources/ui/package.json index c4f2b990404..e5fd3b20edf 100644 --- a/catalog-rest-service/src/main/resources/ui/package.json +++ b/catalog-rest-service/src/main/resources/ui/package.json @@ -57,6 +57,7 @@ "react-codemirror2": "^7.2.1", "react-dom": "^16.14.0", "react-draft-wysiwyg": "^1.14.7", + "react-flow-renderer": "^9.6.8", "react-js-pagination": "^3.0.3", "react-markdown": "^6.0.3", "react-oidc": "^1.0.3", diff --git a/catalog-rest-service/src/main/resources/ui/src/axiosAPIs/lineageAPI.ts b/catalog-rest-service/src/main/resources/ui/src/axiosAPIs/lineageAPI.ts new file mode 100644 index 00000000000..2a8f82cc075 --- /dev/null +++ b/catalog-rest-service/src/main/resources/ui/src/axiosAPIs/lineageAPI.ts @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + + * http://www.apache.org/licenses/LICENSE-2.0 + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +*/ + +import { AxiosResponse } from 'axios'; +import APIClient from './index'; + +export const getLineageByFQN: Function = ( + fqn: string, + type: string, + upstreamDepth = 3, + downstreamDepth = 3 +): Promise => { + return APIClient.get( + `/lineage/${type}/name/${fqn}?upstreamDepth=${upstreamDepth}&downstreamDepth=${downstreamDepth}` + ); +}; diff --git a/catalog-rest-service/src/main/resources/ui/src/components/dataset-lineage/DatasetLineage.tsx b/catalog-rest-service/src/main/resources/ui/src/components/dataset-lineage/DatasetLineage.tsx new file mode 100644 index 00000000000..11ae6a4fb0f --- /dev/null +++ b/catalog-rest-service/src/main/resources/ui/src/components/dataset-lineage/DatasetLineage.tsx @@ -0,0 +1,272 @@ +import React, { + MouseEvent as ReactMouseEvent, + useEffect, + useState, +} from 'react'; +import ReactFlow, { + addEdge, + ArrowHeadType, + Connection, + Controls, + Edge, + Elements, + Node, + OnLoadParams, + Position, + ReactFlowProvider, + removeElements, +} from 'react-flow-renderer'; +import { + Edge as LineageEdge, + EntityLineage, +} from '../../generated/type/entityLineage'; +import { EntityReference } from '../../generated/type/entityReference'; + +const onLoad = (reactFlowInstance: OnLoadParams) => { + reactFlowInstance.fitView(); +}; +/* eslint-disable-next-line */ +const onNodeMouseEnter = (_event: ReactMouseEvent, _node: Node | Edge) => { + return; +}; +/* eslint-disable-next-line */ +const onNodeMouseMove = (_event: ReactMouseEvent, _node: Node | Edge) => { + return; +}; +/* eslint-disable-next-line */ +const onNodeMouseLeave = (_event: ReactMouseEvent, _node: Node | Edge) => { + return; +}; +/* eslint-disable-next-line */ +const onNodeContextMenu = (_event: ReactMouseEvent, _node: Node | Edge) => { + _event.preventDefault(); +}; + +const getDataLabel = (v = '', separator = '.') => { + const length = v.split(separator).length; + + return v.split(separator)[length - 1]; +}; + +const positionX = 150; +const positionY = 60; + +const getLineageData = (entityLineage: EntityLineage) => { + const [x, y] = [0, 0]; + const nodes = entityLineage['nodes']; + let upstreamEdges: Array = + entityLineage['upstreamEdges']?.map((up) => ({ isMapped: false, ...up })) || + []; + let downstreamEdges: Array = + entityLineage['downstreamEdges']?.map((down) => ({ + isMapped: false, + ...down, + })) || []; + const mainNode = entityLineage['entity']; + + const UPStreamNodes: Elements = []; + const DOWNStreamNodes: Elements = []; + const lineageEdges: Elements = []; + + const getNodes = ( + id: string, + pos: 'from' | 'to', + depth: number + ): Array => { + let upDepth = 0; + let downDepth = 0; + if (pos === 'to') { + const UPNodes: Array = []; + const updatedUpStreamEdge = upstreamEdges.map((up) => { + if (up.toEntity === id) { + const edg = UPStreamNodes.find((up) => up.id.includes(`node-${id}`)); + const node = nodes?.find((nd) => nd.id === up.fromEntity); + if (node) { + UPNodes.push(node); + UPStreamNodes.push({ + id: `node-${node.id}-${depth}`, + sourcePosition: Position.Right, + targetPosition: Position.Left, + type: 'default', + className: 'leaf-node', + data: { label: getDataLabel(node.name as string) }, + position: { + x: -positionX * 2 * depth, + y: y + positionY * upDepth, + }, + }); + lineageEdges.push({ + id: `edge-${up.fromEntity}-${id}-${depth}`, + source: `node-${node.id}-${depth}`, + target: edg ? edg.id : `node-${id}-${depth}`, + type: 'custom', + arrowHeadType: ArrowHeadType.ArrowClosed, + }); + } + upDepth += 1; + + return { + ...up, + isMapped: true, + }; + } else { + return up; + } + }); + + upstreamEdges = updatedUpStreamEdge; + + return UPNodes?.map((upNd) => ({ lDepth: depth, ...upNd })) || []; + } else { + const DOWNNodes: Array = []; + const updatedDownStreamEdge = downstreamEdges.map((down) => { + if (down.fromEntity === id) { + const edg = DOWNStreamNodes.find((down) => + down.id.includes(`node-${id}`) + ); + const node = nodes?.find((nd) => nd.id === down.toEntity); + if (node) { + DOWNNodes.push(node); + DOWNStreamNodes.push({ + id: `node-${node.id}-${depth}`, + sourcePosition: Position.Right, + targetPosition: Position.Left, + type: 'default', + className: 'leaf-node', + data: { label: getDataLabel(node.name as string) }, + position: { + x: positionX * 2 * depth, + y: y + positionY * downDepth, + }, + }); + lineageEdges.push({ + id: `edge-${id}-${down.toEntity}`, + source: edg ? edg.id : `node-${id}-${depth}`, + target: `node-${node.id}-${depth}`, + type: 'custom', + arrowHeadType: ArrowHeadType.ArrowClosed, + }); + } + downDepth += 1; + + return { + ...down, + isMapped: true, + }; + } else { + return down; + } + }); + + downstreamEdges = updatedDownStreamEdge; + + return DOWNNodes?.map((downNd) => ({ lDepth: depth, ...downNd })) || []; + } + }; + + const getUpStreamData = ( + Entity: EntityReference, + depth = 1, + upNodesArr: Array = [] + ) => { + const upNodes = getNodes(Entity.id, 'to', depth); + upNodesArr.push(...upNodes); + upNodes.forEach((up) => { + if ( + upstreamEdges.some((upE) => upE.toEntity === up.id && !upE.isMapped) + ) { + getUpStreamData(up, depth + 1, upNodesArr); + } + }); + + return upNodesArr; + }; + + const getDownStreamData = ( + Entity: EntityReference, + depth = 1, + downNodesArr: Array = [] + ) => { + const downNodes = getNodes(Entity.id, 'from', depth); + downNodesArr.push(...downNodes); + downNodes.forEach((down) => { + if ( + downstreamEdges.some( + (downE) => downE.fromEntity === down.id && !downE.isMapped + ) + ) { + getDownStreamData(down, depth + 1, downNodesArr); + } + }); + + return downNodesArr; + }; + + getUpStreamData(mainNode); + + getDownStreamData(mainNode); + + const lineageData = [ + { + id: `node-${mainNode.id}-1`, + sourcePosition: 'right', + targetPosition: 'left', + type: 'default', + className: 'leaf-node core', + data: { label: getDataLabel(mainNode.name as string) }, + position: { x: x, y: y }, + }, + ...UPStreamNodes, + ...DOWNStreamNodes, + ...lineageEdges, + ]; + + return lineageData; +}; + +const DatasetLineage = ({ + entityLineage, +}: { + entityLineage: EntityLineage; +}) => { + const [elements, setElements] = useState( + getLineageData(entityLineage) as Elements + ); + const onElementsRemove = (elementsToRemove: Elements) => + setElements((els) => removeElements(elementsToRemove, els)); + const onConnect = (params: Edge | Connection) => + setElements((els) => addEdge(params, els)); + + useEffect(() => { + setElements(getLineageData(entityLineage) as Elements); + }, [entityLineage]); + + return ( + <> + {(entityLineage?.downstreamEdges ?? []).length > 0 || + (entityLineage.upstreamEdges ?? []).length ? ( + + + + + + ) : ( +
+ No Lineage data available +
+ )} + + ); +}; + +export default DatasetLineage; diff --git a/catalog-rest-service/src/main/resources/ui/src/enums/entity.enum.ts b/catalog-rest-service/src/main/resources/ui/src/enums/entity.enum.ts index cb783f62f07..395d93c15c7 100644 --- a/catalog-rest-service/src/main/resources/ui/src/enums/entity.enum.ts +++ b/catalog-rest-service/src/main/resources/ui/src/enums/entity.enum.ts @@ -17,6 +17,7 @@ export enum EntityType { DATASET = 'dataset', + TABLE = 'table', TOPIC = 'topic', DASHBOARD = 'dashboard', PIPELINE = 'pipeline', diff --git a/catalog-rest-service/src/main/resources/ui/src/pages/Pipeline-details/index.tsx b/catalog-rest-service/src/main/resources/ui/src/pages/Pipeline-details/index.tsx index e5d0048a04d..84e0ff39cdd 100644 --- a/catalog-rest-service/src/main/resources/ui/src/pages/Pipeline-details/index.tsx +++ b/catalog-rest-service/src/main/resources/ui/src/pages/Pipeline-details/index.tsx @@ -5,6 +5,7 @@ import { ColumnTags, TableDetail } from 'Models'; import React, { useEffect, useState } from 'react'; import { Link, useParams } from 'react-router-dom'; import AppState from '../../AppState'; +import { getLineageByFQN } from '../../axiosAPIs/lineageAPI'; import { addFollower, getPipelineByFqn, @@ -20,6 +21,7 @@ import RichTextEditorPreviewer from '../../components/common/rich-text-editor/Ri import TabsPane from '../../components/common/TabsPane/TabsPane'; import { TitleBreadcrumbProps } from '../../components/common/title-breadcrumb/title-breadcrumb.interface'; import PageContainer from '../../components/containers/PageContainer'; +import DatasetLineage from '../../components/dataset-lineage/DatasetLineage'; import Loader from '../../components/Loader/Loader'; import { ModalWithMarkdownEditor } from '../../components/Modals/ModalWithMarkdownEditor/ModalWithMarkdownEditor'; import ManageTab from '../../components/my-data-details/ManageTab'; @@ -33,6 +35,7 @@ import { EntityType } from '../../enums/entity.enum'; import { Pipeline } from '../../generated/entity/data/pipeline'; import { Task } from '../../generated/entity/data/task'; import { User } from '../../generated/entity/teams/user'; +import { EntityLineage } from '../../generated/type/entityLineage'; import { TagLabel } from '../../generated/type/tagLabel'; import { useAuth } from '../../hooks/authHooks'; import { @@ -90,7 +93,9 @@ const MyPipelinePage = () => { task: Task; index: number; }>(); - + const [entityLineage, setEntityLineage] = useState( + {} as EntityLineage + ); const hasEditAccess = () => { if (owner?.type === 'user') { return owner.id === getCurrentUserId(); @@ -109,6 +114,16 @@ const MyPipelinePage = () => { isProtected: false, position: 1, }, + { + name: 'Lineage', + icon: { + alt: 'lineage', + name: 'icon-lineage', + title: 'Lineage', + }, + isProtected: false, + position: 2, + }, { name: 'Manage', icon: { @@ -118,7 +133,7 @@ const MyPipelinePage = () => { }, isProtected: true, protectedState: !owner || hasEditAccess(), - position: 2, + position: 3, }, ]; @@ -431,6 +446,10 @@ const MyPipelinePage = () => { useEffect(() => { fetchPipelineDetail(pipelineFQN); + setActiveTab(1); + getLineageByFQN(pipelineFQN, EntityType.PIPELINE).then( + (res: AxiosResponse) => setEntityLineage(res.data) + ); }, [pipelineFQN]); useEffect(() => { @@ -599,6 +618,11 @@ const MyPipelinePage = () => { )} {activeTab === 2 && ( +
+ +
+ )} + {activeTab === 3 && ( { const [tableDetails, setTableDetails] = useState({} as Table); const [activeTab, setActiveTab] = useState(1); const { datasetFQN: tableFQN } = useParams() as Record; - const showToast = useToastContext(); - + const [entityLineage, setEntityLineage] = useState( + {} as EntityLineage + ); const hasEditAccess = () => { if (owner?.type === 'user') { return owner.id === getCurrentUserId(); @@ -163,6 +167,16 @@ const MyDataDetailsPage = () => { isProtected: false, position: 2, }, + { + name: 'Lineage', + icon: { + alt: 'lineage', + name: 'icon-lineage', + title: 'Lineage', + }, + isProtected: false, + position: 3, + }, { name: 'Manage', icon: { @@ -172,7 +186,7 @@ const MyDataDetailsPage = () => { }, isProtected: true, protectedState: !owner || hasEditAccess(), - position: 3, + position: 4, }, ]; @@ -468,6 +482,10 @@ const MyDataDetailsPage = () => { setTableJoinData(joins); } }); + setActiveTab(1); + getLineageByFQN(tableFQN, EntityType.TABLE).then((res: AxiosResponse) => + setEntityLineage(res.data) + ); }, [tableFQN]); useEffect(() => { @@ -543,6 +561,11 @@ const MyDataDetailsPage = () => { /> )} {activeTab === 3 && ( +
+ +
+ )} + {activeTab === 4 && (