UI : Added lineage for Tables and Pipelines. (#770)

* UI : Added lineage for Tables and Pipelines.

* hide interactive control

* Addressing review comments
This commit is contained in:
Sachin Chaurasiya 2021-10-15 18:48:18 +05:30 committed by GitHub
parent 0d1a42f26a
commit 1cf0c54dde
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 735 additions and 5 deletions

View File

@ -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",

View File

@ -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",

View File

@ -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<AxiosResponse> => {
return APIClient.get(
`/lineage/${type}/name/${fqn}?upstreamDepth=${upstreamDepth}&downstreamDepth=${downstreamDepth}`
);
};

View File

@ -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<LineageEdge & { isMapped: boolean }> =
entityLineage['upstreamEdges']?.map((up) => ({ isMapped: false, ...up })) ||
[];
let downstreamEdges: Array<LineageEdge & { isMapped: boolean }> =
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<EntityReference & { lDepth: number }> => {
let upDepth = 0;
let downDepth = 0;
if (pos === 'to') {
const UPNodes: Array<EntityReference> = [];
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<EntityReference> = [];
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<EntityReference & { lDepth: number }> = []
) => {
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<EntityReference & { lDepth: number }> = []
) => {
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<Elements>(
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 ? (
<ReactFlowProvider>
<ReactFlow
panOnScroll
elements={elements as Elements}
nodesConnectable={false}
onConnect={onConnect}
onElementsRemove={onElementsRemove}
onLoad={onLoad}
onNodeContextMenu={onNodeContextMenu}
onNodeMouseEnter={onNodeMouseEnter}
onNodeMouseLeave={onNodeMouseLeave}
onNodeMouseMove={onNodeMouseMove}>
<Controls showInteractive={false} />
</ReactFlow>
</ReactFlowProvider>
) : (
<div className="tw-flex tw-justify-center tw-font-medium tw-items-center tw-border tw-border-main tw-rounded-md tw-p-8">
No Lineage data available
</div>
)}
</>
);
};
export default DatasetLineage;

View File

@ -17,6 +17,7 @@
export enum EntityType {
DATASET = 'dataset',
TABLE = 'table',
TOPIC = 'topic',
DASHBOARD = 'dashboard',
PIPELINE = 'pipeline',

View File

@ -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<EntityLineage>(
{} 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 && (
<div className="tw-w-full tw-h-96">
<DatasetLineage entityLineage={entityLineage} />
</div>
)}
{activeTab === 3 && (
<ManageTab
currentTier={tier}
currentUser={owner?.id}

View File

@ -25,6 +25,7 @@ import { useParams } from 'react-router-dom';
import AppState from '../../AppState';
import { getDatabase } from '../../axiosAPIs/databaseAPI';
import { postFeed } from '../../axiosAPIs/feedsAPI';
import { getLineageByFQN } from '../../axiosAPIs/lineageAPI';
import { getServiceById } from '../../axiosAPIs/serviceAPI';
import {
addFollower,
@ -37,6 +38,7 @@ import EntityPageInfo from '../../components/common/entityPageInfo/EntityPageInf
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 FrequentlyJoinedTables from '../../components/my-data-details/FrequentlyJoinedTables';
import ManageTab from '../../components/my-data-details/ManageTab';
import ProfilerTable from '../../components/my-data-details/ProfilerTable';
@ -55,6 +57,7 @@ import {
TableJoins,
} from '../../generated/entity/data/table';
import { User } from '../../generated/entity/teams/user';
import { EntityLineage } from '../../generated/type/entityLineage';
import { LabelType, State } from '../../generated/type/tagLabel';
import { useAuth } from '../../hooks/authHooks';
import useToastContext from '../../hooks/useToastContext';
@ -131,9 +134,10 @@ const MyDataDetailsPage = () => {
const [tableDetails, setTableDetails] = useState<Table>({} as Table);
const [activeTab, setActiveTab] = useState<number>(1);
const { datasetFQN: tableFQN } = useParams() as Record<string, string>;
const showToast = useToastContext();
const [entityLineage, setEntityLineage] = useState<EntityLineage>(
{} 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 && (
<div className="tw-w-full tw-h-96">
<DatasetLineage entityLineage={entityLineage} />
</div>
)}
{activeTab === 4 && (
<ManageTab
currentTier={tier}
currentUser={owner?.id}

View File

@ -299,6 +299,23 @@
@apply tw-cursor-not-allowed !important;
}
/* React flow */
.leaf-node {
@apply tw-border-main tw-py-1;
}
.leaf-node .react-flow__handle {
@apply tw-bg-grey-muted;
}
.leaf-node.core {
@apply tw-border-primary tw-text-primary;
}
.leaf-node.core .react-flow__handle {
@apply tw-bg-primary;
}
.react-flow__edge.selected .react-flow__edge-path {
stroke: #7147e8;
}
/* react-slick */
.slick-dots {