diff --git a/ui/src/components/graph/graph.tsx b/ui/src/components/graph/graph.tsx index 166cf19ae..64e9a7922 100644 --- a/ui/src/components/graph/graph.tsx +++ b/ui/src/components/graph/graph.tsx @@ -150,7 +150,7 @@ const Graph: React.FC = ({ data, nodeId }) => { if (isNode(element)) { resetHighlight(); highlightPath(element, false); - setURLSearchParams({ nodeId: element.data.id }); + setURLSearchParams({ nodeId: element.data.id, featureType: element.data.subtitle }); } } } onNodeDragStop={ onNodeDragStop } diff --git a/ui/src/components/graph/graphNodeDetails.tsx b/ui/src/components/graph/graphNodeDetails.tsx new file mode 100644 index 000000000..56e848fe6 --- /dev/null +++ b/ui/src/components/graph/graphNodeDetails.tsx @@ -0,0 +1,87 @@ +import React, { useEffect, useState } from 'react'; +import { useParams, useSearchParams } from "react-router-dom"; +import { fetchFeature } from '../../api'; +import { Feature } from "../../models/model"; +import { LoadingOutlined } from "@ant-design/icons"; +import { Card, Spin } from "antd"; + +type Params = { + project: string; + featureId: string; +} + +const GraphNodeDetails: React.FC = () => { + const [searchParams] = useSearchParams(); + const { project } = useParams() as Params; + const nodeId = searchParams.get('nodeId') as string; + const featureType = searchParams.get('featureType') as string; + const [feature, setFeature] = useState(); + const [loading, setLoading] = useState(false); + + const isFeature = (featureType:string) => { + return featureType === 'feathr_anchor_feature_v1' || featureType === 'feathr_derived_feature_v1' + } + + useEffect(() => { + const fetchFeatureData = async () => { + setFeature(undefined); + if (nodeId && isFeature(featureType)) { + setLoading(true); + const data = await fetchFeature(project, nodeId); + setFeature(data); + setLoading(false); + } + }; + + fetchFeatureData(); + }, [nodeId]); + + return ( + <> + { + loading + ? ( } />) + : (
+ { feature?.attributes.transformation && + + { feature.attributes.transformation.transform_expr && +

transform_expr: { feature.attributes.transformation.transform_expr }

} + { feature.attributes.transformation.filter && +

filter: { feature.attributes.transformation.filter }

} + { feature.attributes.transformation.agg_func && +

agg_func: { feature.attributes.transformation.agg_func }

} + { feature.attributes.transformation.limit && +

limit: { feature.attributes.transformation.limit }

} + { feature.attributes.transformation.group_by && +

group_by: { feature.attributes.transformation.group_by }

} + { feature.attributes.transformation.window && +

window: { feature.attributes.transformation.window }

} + { feature.attributes.transformation.def_expr && +

def_expr: { feature.attributes.transformation.def_expr }

} +
+ } + { feature?.attributes.key && feature.attributes.key.length > 0 && + +

full_name: { feature.attributes.key[0].full_name }

+

key_column: { feature.attributes.key[0].key_column }

+

description: { feature.attributes.key[0].description }

+

key_column_alias: { feature.attributes.key[0].key_column_alias }

+

key_column_type: { feature.attributes.key[0].key_column_type }

+
+ } + { feature?.attributes.type && + +

dimension_type: { feature.attributes.type.dimension_type }

+

tensor_category: { feature.attributes.type.tensor_category }

+

type: { feature.attributes.type.type }

+

val_type: { feature.attributes.type.val_type }

+
+ } +
) + } + + ) +} + + +export default GraphNodeDetails; diff --git a/ui/src/pages/feature/lineageGraph.tsx b/ui/src/pages/feature/lineageGraph.tsx index 3cfcf5452..5035a7fa9 100644 --- a/ui/src/pages/feature/lineageGraph.tsx +++ b/ui/src/pages/feature/lineageGraph.tsx @@ -1,5 +1,5 @@ import React, { useEffect, useState } from 'react'; -import { Card, Radio, Spin } from 'antd'; +import { Card, Col, Radio, Row, Spin } from 'antd'; import { useParams, useSearchParams } from "react-router-dom"; import { Elements } from 'react-flow-renderer'; import Graph from "../../components/graph/graph"; @@ -7,6 +7,7 @@ import { generateEdge, generateNode } from "../../components/graph/utils"; import { fetchProjectLineages } from "../../api"; import { FeatureLineage } from "../../models/model"; import { LoadingOutlined } from "@ant-design/icons"; +import GraphNodeDetails from "../../components/graph/graphNodeDetails"; type Params = { project: string; @@ -24,6 +25,7 @@ const LineageGraph: React.FC = () => { // Fetch lineage data from server side, invoked immediately after component is mounted useEffect(() => { const fetchLineageData = async () => { + setLoading(true); const data = await fetchProjectLineages(project); setLineageData(data); setLoading(false); @@ -105,9 +107,20 @@ const LineageGraph: React.FC = () => {
- { loading - ? } /> - : } + { + loading + ? ( } />) + : ( + + + + + + + + + ) + }
);