diff --git a/plugins/visualizer/src/components/AppVisualizerPage/GraphVisualizer.tsx b/plugins/visualizer/src/components/AppVisualizerPage/GraphVisualizer.tsx index ae78611d2e..de043d71ca 100644 --- a/plugins/visualizer/src/components/AppVisualizerPage/GraphVisualizer.tsx +++ b/plugins/visualizer/src/components/AppVisualizerPage/GraphVisualizer.tsx @@ -14,7 +14,14 @@ * limitations under the License. */ -import { AppNode, AppTree } from '@backstage/frontend-plugin-api'; +import { + AppNode, + AppTree, + ExtensionDataRef, + RouteRef, + coreExtensionData, + useRouteRef, +} from '@backstage/frontend-plugin-api'; import Box from '@material-ui/core/Box'; import Tooltip from '@material-ui/core/Tooltip'; import Typography from '@material-ui/core/Typography'; @@ -23,6 +30,7 @@ import { Theme, makeStyles } from '@material-ui/core/styles'; import InputIcon from '@material-ui/icons/InputSharp'; import DisabledIcon from '@material-ui/icons/NotInterestedSharp'; import React from 'react'; +import { Link } from 'react-router-dom'; function createOutputColorGenerator(availableColors: string[]) { const map = new Map(); @@ -139,17 +147,75 @@ const useStyles = makeStyles(theme => ({ }, })); -function Output(props: { id: string }) { - const { id } = props; +const useOutputStyles = makeStyles(theme => ({ + output: ({ color }: { color: string }) => ({ + padding: `0 10px`, + height: 20, + borderRadius: 10, + color: theme.palette.getContrastText(color), + backgroundColor: color, + }), +})); + +function getFullPath(node?: AppNode): string { + if (!node) { + return ''; + } + const parent = node.edges.attachedTo?.node; + const part = node.instance?.getData(coreExtensionData.routePath); + if (!part) { + return getFullPath(parent); + } + return getFullPath(parent) + part; +} + +function OutputLink(props: { + dataRef: ExtensionDataRef; + node: AppNode; + className: string; +}) { + const routeRef = props.node.instance?.getData(coreExtensionData.routeRef); + + let link: string | undefined = undefined; + try { + link = useRouteRef(routeRef as RouteRef)(); + } catch { + /* ignore */ + } + + return ( + {props.dataRef.id}}> + + {link ? link : null} + + + ); +} + +function Output(props: { dataRef: ExtensionDataRef; node: AppNode }) { + const { dataRef, node } = props; + const { id } = dataRef; + const instance = node.instance!; + + const classes = useOutputStyles({ color: getOutputColor(id) }); + + if (id === coreExtensionData.routePath.id) { + return ( + {getFullPath(node)}}> + + {String(instance.getData(dataRef))} + + + ); + } + + if (id === coreExtensionData.routeRef.id) { + return ; + } return ( {id}}> - + ); } @@ -217,8 +283,7 @@ function Extension(props: { node: AppNode }) { const enabled = Boolean(node.instance); const classes = useStyles({ enabled }); - const dataRefIds = - node.instance && [...node.instance.getDataRefs()].map(r => r.id); + const dataRefs = node.instance && [...node.instance.getDataRefs()]; return ( @@ -229,9 +294,11 @@ function Extension(props: { node: AppNode }) { - {dataRefIds && - dataRefIds.length > 0 && - [...dataRefIds].sort().map(id => )} + {dataRefs && + dataRefs.length > 0 && + dataRefs + .sort((a, b) => a.id.localeCompare(b.id)) + .map(ref => )} {!enabled && }