diff --git a/.changeset/mean-eggs-knock.md b/.changeset/mean-eggs-knock.md new file mode 100644 index 0000000000..dd9336a0e7 --- /dev/null +++ b/.changeset/mean-eggs-knock.md @@ -0,0 +1,6 @@ +--- +'@backstage/core-components': minor +'@backstage/plugin-catalog-graph': minor +--- + +Add documentation and more type safety around DependencyGraph diff --git a/packages/core-components/api-report.md b/packages/core-components/api-report.md index 4a94135b4a..235e11607f 100644 --- a/packages/core-components/api-report.md +++ b/packages/core-components/api-report.md @@ -17,7 +17,6 @@ import { ComponentProps } from 'react'; import { Context } from 'react'; import { default as CSS_2 } from 'csstype'; import { CSSProperties } from 'react'; -import { default as dagre_2 } from 'dagre'; import { ElementType } from 'react'; import { ErrorInfo } from 'react'; import { IconComponent } from '@backstage/core-plugin-api'; @@ -53,15 +52,11 @@ export function AlertDisplay(_props: {}): JSX.Element | null; // Warning: (ae-missing-release-tag) "Alignment" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // -// @public (undocumented) +// @public enum Alignment { - // (undocumented) DOWN_LEFT = 'DL', - // (undocumented) DOWN_RIGHT = 'DR', - // (undocumented) UP_LEFT = 'UL', - // (undocumented) UP_RIGHT = 'UR', } @@ -264,11 +259,10 @@ export type CustomProviderClassKey = 'form' | 'button'; // @public (undocumented) export function DashboardIcon(props: IconComponentProps): JSX.Element; -// Warning: (ae-forgotten-export) The symbol "CustomType" needs to be exported by the entry point index.d.ts // Warning: (ae-missing-release-tag) "DependencyEdge" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // -// @public (undocumented) -type DependencyEdge = T & { +// @public +type DependencyEdge = T & { from: string; to: string; label?: string; @@ -276,8 +270,10 @@ type DependencyEdge = T & { // Warning: (ae-missing-release-tag) "DependencyGraph" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // -// @public (undocumented) -export function DependencyGraph(props: DependencyGraphProps): JSX.Element; +// @public +export function DependencyGraph( + props: DependencyGraphProps, +): JSX.Element; // Warning: (ae-missing-release-tag) "DependencyGraphDefaultLabelClassKey" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -301,40 +297,42 @@ export type DependencyGraphNodeClassKey = 'node'; // Warning: (ae-missing-release-tag) "DependencyGraphProps" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // -// @public (undocumented) -export type DependencyGraphProps = React_2.SVGProps & { - edges: DependencyEdge[]; - nodes: DependencyNode[]; - direction?: Direction; +// @public +export interface DependencyGraphProps + extends React_2.SVGProps { + acyclicer?: 'greedy'; + // Warning: (ae-unresolved-link) The @link reference could not be resolved: This type of declaration is not supported yet by the resolver align?: Alignment; - nodeMargin?: number; + defs?: SVGDefsElement | SVGDefsElement[]; + // Warning: (ae-unresolved-link) The @link reference could not be resolved: This type of declaration is not supported yet by the resolver + direction?: Direction; edgeMargin?: number; - rankMargin?: number; + edgeRanks?: number; + edges: DependencyEdge[]; + edgeWeight?: number; + labelOffset?: number; + // Warning: (ae-unresolved-link) The @link reference could not be resolved: This type of declaration is not supported yet by the resolver + labelPosition?: LabelPosition; + nodeMargin?: number; + nodes: DependencyNode[]; paddingX?: number; paddingY?: number; - acyclicer?: 'greedy'; + // Warning: (ae-unresolved-link) The @link reference could not be resolved: This type of declaration is not supported yet by the resolver ranker?: Ranker; - labelPosition?: LabelPosition; - labelOffset?: number; - edgeRanks?: number; - edgeWeight?: number; - renderNode?: RenderNodeFunction; - renderLabel?: RenderLabelFunction; - defs?: SVGDefsElement | SVGDefsElement[]; + rankMargin?: number; + renderLabel?: RenderLabelFunction; + renderNode?: RenderNodeFunction; zoom?: 'enabled' | 'disabled' | 'enable-on-click'; -}; +} declare namespace DependencyGraphTypes { export { DependencyEdge, - GraphEdge, RenderLabelProps, RenderLabelFunction, DependencyNode, - GraphNode, RenderNodeProps, RenderNodeFunction, - EdgeProperties, Direction, Alignment, Ranker, @@ -345,22 +343,18 @@ export { DependencyGraphTypes }; // Warning: (ae-missing-release-tag) "DependencyNode" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // -// @public (undocumented) -type DependencyNode = T & { +// @public +type DependencyNode = T & { id: string; }; // Warning: (ae-missing-release-tag) "Direction" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // -// @public (undocumented) +// @public enum Direction { - // (undocumented) BOTTOM_TOP = 'BT', - // (undocumented) LEFT_RIGHT = 'LR', - // (undocumented) RIGHT_LEFT = 'RL', - // (undocumented) TOP_BOTTOM = 'TB', } @@ -387,20 +381,6 @@ export type DismissbleBannerClassKey = // @public (undocumented) export function DocsIcon(props: IconComponentProps): JSX.Element; -// Warning: (ae-missing-release-tag) "EdgeProperties" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -type EdgeProperties = { - label?: string; - width?: number; - height?: number; - labeloffset?: number; - labelpos?: LabelPosition; - minlen?: number; - weight?: number; - [customKey: string]: any; -}; - // Warning: (ae-missing-release-tag) "EmailIcon" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) @@ -520,18 +500,6 @@ export type GaugeClassKey = 'root' | 'overlay' | 'circle' | 'colorUnknown'; // @public (undocumented) export function GitHubIcon(props: IconComponentProps): JSX.Element; -// Warning: (ae-missing-release-tag) "GraphEdge" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -type GraphEdge = DependencyEdge & - dagre_2.GraphEdge & - EdgeProperties; - -// Warning: (ae-missing-release-tag) "GraphNode" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -type GraphNode = dagre_2.Node>; - // Warning: (ae-missing-release-tag) "GroupIcon" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) @@ -738,7 +706,7 @@ export type ItemCardHeaderProps = Partial> & { // Warning: (ae-missing-release-tag) "LabelPosition" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // -// @public (undocumented) +// @public enum LabelPosition { // (undocumented) CENTER = 'c', @@ -888,37 +856,43 @@ export function Progress( // Warning: (ae-missing-release-tag) "Ranker" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // -// @public (undocumented) +// @public enum Ranker { - // (undocumented) LONGEST_PATH = 'longest-path', - // (undocumented) NETWORK_SIMPLEX = 'network-simplex', - // (undocumented) TIGHT_TREE = 'tight-tree', } // Warning: (ae-missing-release-tag) "RenderLabelFunction" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // -// @public (undocumented) -type RenderLabelFunction = (props: RenderLabelProps) => React.ReactNode; +// @public +type RenderLabelFunction = ( + props: RenderLabelProps, +) => React_2.ReactNode; // Warning: (ae-missing-release-tag) "RenderLabelProps" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// Warning: (ae-unresolved-link) The @link reference could not be resolved: This type of declaration is not supported yet by the resolver +// Warning: (ae-unresolved-link) The @link reference could not be resolved: This type of declaration is not supported yet by the resolver // -// @public (undocumented) -type RenderLabelProps = { +// @public +type RenderLabelProps = { edge: DependencyEdge; }; // Warning: (ae-missing-release-tag) "RenderNodeFunction" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// Warning: (ae-unresolved-link) The @link reference could not be resolved: This type of declaration is not supported yet by the resolver // -// @public (undocumented) -type RenderNodeFunction = (props: RenderNodeProps) => React.ReactNode; +// @public +type RenderNodeFunction = ( + props: RenderNodeProps, +) => React_2.ReactNode; // Warning: (ae-missing-release-tag) "RenderNodeProps" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// Warning: (ae-unresolved-link) The @link reference could not be resolved: This type of declaration is not supported yet by the resolver +// Warning: (ae-unresolved-link) The @link reference could not be resolved: This type of declaration is not supported yet by the resolver // -// @public (undocumented) -type RenderNodeProps = { +// @public +type RenderNodeProps = { node: DependencyNode; }; @@ -2498,6 +2472,8 @@ export type WarningPanelClassKey = // Warnings were encountered during analysis: // +// src/components/DependencyGraph/types.d.ts:14:5 - (ae-unresolved-link) The @link reference could not be resolved: The package "@backstage/core-components" does not have an export "DependencyNode" +// src/components/DependencyGraph/types.d.ts:18:5 - (ae-unresolved-link) The @link reference could not be resolved: The package "@backstage/core-components" does not have an export "DependencyNode" // src/components/TabbedLayout/RoutedTabs.d.ts:9:5 - (ae-forgotten-export) The symbol "SubRoute" needs to be exported by the entry point index.d.ts // src/components/Table/Table.d.ts:19:5 - (ae-forgotten-export) The symbol "SelectedFilters" needs to be exported by the entry point index.d.ts // src/layout/ErrorBoundary/ErrorBoundary.d.ts:7:5 - (ae-forgotten-export) The symbol "SlackChannel" needs to be exported by the entry point index.d.ts diff --git a/packages/core-components/package.json b/packages/core-components/package.json index fb3d564061..eaad5e8a95 100644 --- a/packages/core-components/package.json +++ b/packages/core-components/package.json @@ -37,7 +37,6 @@ "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", - "@types/dagre": "^0.7.44", "@types/react": "*", "@types/react-sparklines": "^1.7.0", "@types/react-text-truncate": "^0.14.0", @@ -79,6 +78,7 @@ "@types/d3-selection": "^2.0.0", "@types/d3-shape": "^3.0.1", "@types/d3-zoom": "^2.0.0", + "@types/dagre": "^0.7.44", "@types/google-protobuf": "^3.7.2", "@types/jest": "^26.0.7", "@types/node": "^14.14.32", diff --git a/packages/core-components/src/components/DependencyGraph/DependencyGraph.tsx b/packages/core-components/src/components/DependencyGraph/DependencyGraph.tsx index abc98dd60a..1c3a4fce96 100644 --- a/packages/core-components/src/components/DependencyGraph/DependencyGraph.tsx +++ b/packages/core-components/src/components/DependencyGraph/DependencyGraph.tsx @@ -29,39 +29,148 @@ import { Ranker, RenderNodeFunction, RenderLabelFunction, - GraphEdge, - GraphNode, LabelPosition, } from './types'; import { Node } from './Node'; -import { Edge } from './Edge'; +import { Edge, GraphEdge } from './Edge'; import { ARROW_MARKER_ID } from './constants'; -export type DependencyGraphProps = React.SVGProps & { - edges: DependencyEdge[]; - nodes: DependencyNode[]; +/** + * Properties of {@link DependencyGraph} + * + * @remarks + * and are useful when rendering custom or edge labels + */ +export interface DependencyGraphProps + extends React.SVGProps { + /** + * Edges of graph + */ + edges: DependencyEdge[]; + /** + * Nodes of Graph + */ + nodes: DependencyNode[]; + /** + * Graph {@link DependencyGraphTypes.Direction | direction} + * + * @remarks + * + * Default: `DependencyGraphTypes.Direction.TOP_BOTTOM` + */ direction?: Direction; + /** + * Node {@link DependencyGraphTypes.Alignment | alignment} + */ align?: Alignment; + /** + * Margin between nodes on each rank + * + * @remarks + * + * Default: 50 + */ nodeMargin?: number; + /** + * Margin between edges + * + * @remarks + * + * Default: 10 + */ edgeMargin?: number; + /** + * Margin between each rank + * + * @remarks + * + * Default: 50 + */ rankMargin?: number; + /** + * Margin on left and right of whole graph + * + * @remarks + * + * Default: 0 + */ paddingX?: number; + /** + * Margin on top and bottom of whole graph + * + * @remarks + * + * Default: 0 + */ paddingY?: number; + /** + * Heuristic used to find set of edges that will make graph acyclic + */ acyclicer?: 'greedy'; + /** + * {@link DependencyGraphTypes.Ranker | Algorithm} used to rank nodes + * + * @remarks + * + * Default: `DependencyGraphTypes.Ranker.NETWORK_SIMPLEX` + */ ranker?: Ranker; + /** + * {@link DependencyGraphTypes.LabelPosition | Position} of label in relation to edge + * + * @remarks + * + * Default: `DependencyGraphTypes.LabelPosition.RIGHT` + */ labelPosition?: LabelPosition; + /** + * How much to move label away from edge + * + * @remarks + * + * Applies only when {@link DependencyGraphProps.labelPosition} is `DependencyGraphTypes.LabelPosition.LEFT` or + * `DependencyGraphTypes.LabelPosition.RIGHT` + */ labelOffset?: number; + /** + * Minimum number of ranks to keep between connected nodes + */ edgeRanks?: number; + /** + * Weight applied to edges in graph + */ edgeWeight?: number; - renderNode?: RenderNodeFunction; - renderLabel?: RenderLabelFunction; + /** + * Custom node rendering component + */ + renderNode?: RenderNodeFunction; + /** + * Custom label rendering component + */ + renderLabel?: RenderLabelFunction; + /** + * {@link https://developer.mozilla.org/en-US/docs/Web/SVG/Element/defs | Defs} shared by rendered SVG to be used by + * {@link DependencyGraphProps.renderNode} and/or {@link DependencyGraphProps.renderLabel} + */ defs?: SVGDefsElement | SVGDefsElement[]; + /** + * Controls zoom behavior of graph + * + * @remarks + * + * Default: `enabled` + */ zoom?: 'enabled' | 'disabled' | 'enable-on-click'; -}; +} const WORKSPACE_ID = 'workspace'; -export function DependencyGraph(props: DependencyGraphProps) { +/** + * Graph component used to visualize relations between entities + */ +export function DependencyGraph( + props: DependencyGraphProps, +) { const { edges, nodes, @@ -88,7 +197,7 @@ export function DependencyGraph(props: DependencyGraphProps) { const [containerWidth, setContainerWidth] = React.useState(100); const [containerHeight, setContainerHeight] = React.useState(100); - const graph = React.useRef>( + const graph = React.useRef>>( new dagre.graphlib.Graph(), ); const [graphWidth, setGraphWidth] = React.useState( @@ -256,13 +365,13 @@ export function DependencyGraph(props: DependencyGraphProps) { updateGraph, ]); - function setNode(id: string, node: DependencyNode) { + function setNode(id: string, node: DependencyNode) { graph.current.setNode(id, node); updateGraph(); return graph.current; } - function setEdge(id: dagre.Edge, edge: DependencyEdge) { + function setEdge(id: dagre.Edge, edge: DependencyEdge) { graph.current.setEdge(id, edge); updateGraph(); return graph.current; @@ -303,7 +412,7 @@ export function DependencyGraph(props: DependencyGraphProps) { viewBox={`0 0 ${graphWidth} ${graphHeight}`} > {graphEdges.map(e => { - const edge = graph.current.edge(e) as GraphEdge; + const edge = graph.current.edge(e) as GraphEdge; if (!edge) return null; return ( { - const node = graph.current.node(id) as GraphNode; + const node = graph.current.node(id); if (!node) return null; return ( ( )); const minProps = { - points: [ - { x: 10, y: 20 }, - { x: 20, y: 20 }, - ], id, setEdge, renderElement, diff --git a/packages/core-components/src/components/DependencyGraph/Edge.tsx b/packages/core-components/src/components/DependencyGraph/Edge.tsx index a82c5d4813..fd4d92b834 100644 --- a/packages/core-components/src/components/DependencyGraph/Edge.tsx +++ b/packages/core-components/src/components/DependencyGraph/Edge.tsx @@ -20,13 +20,26 @@ import isFinite from 'lodash/isFinite'; import makeStyles from '@material-ui/core/styles/makeStyles'; import { BackstageTheme } from '@backstage/theme'; import { - GraphEdge, RenderLabelProps, RenderLabelFunction, DependencyEdge, + LabelPosition, } from './types'; import { ARROW_MARKER_ID, EDGE_TEST_ID, LABEL_TEST_ID } from './constants'; import { DefaultLabel } from './DefaultLabel'; +import dagre from 'dagre'; + +/* Based on: https://github.com/dagrejs/dagre/wiki#configuring-the-layout */ +export type EdgeProperties = { + label?: string; + width?: number; + height?: number; + labeloffset?: number; + labelpos?: LabelPosition; + minlen?: number; + weight?: number; +}; +export type GraphEdge = DependencyEdge & dagre.GraphEdge & EdgeProperties; export type DependencyGraphEdgeClassKey = 'path' | 'label'; @@ -47,14 +60,19 @@ const useStyles = makeStyles( type EdgePoint = dagre.GraphEdge['points'][0]; -export type EdgeComponentProps = { +export type EdgeComponentProps = { id: dagre.Edge; edge: GraphEdge; - render?: RenderLabelFunction; - setEdge: (id: dagre.Edge, edge: DependencyEdge) => dagre.graphlib.Graph<{}>; + render?: RenderLabelFunction; + setEdge: ( + id: dagre.Edge, + edge: DependencyEdge, + ) => dagre.graphlib.Graph<{}>; }; -const renderDefault = (props: RenderLabelProps) => ; +const renderDefault = (props: RenderLabelProps) => ( + +); const createPath = d3Shape .line() @@ -62,13 +80,14 @@ const createPath = d3Shape .y(d => d.y) .curve(d3Shape.curveMonotoneX); -export function Edge({ +export function Edge({ render = renderDefault, setEdge, id, edge, -}: EdgeComponentProps) { - const { x = 0, y = 0, width, height, points, ...labelProps } = edge; +}: EdgeComponentProps) { + const { x = 0, y = 0, width, height, points } = edge; + const labelProps: DependencyEdge = edge; const classes = useStyles(); const labelRef = React.useRef(null); diff --git a/packages/core-components/src/components/DependencyGraph/Node.test.tsx b/packages/core-components/src/components/DependencyGraph/Node.test.tsx index ebd6478db9..aaba09c004 100644 --- a/packages/core-components/src/components/DependencyGraph/Node.test.tsx +++ b/packages/core-components/src/components/DependencyGraph/Node.test.tsx @@ -20,21 +20,16 @@ import { render } from '@testing-library/react'; import { Node } from './Node'; import { RenderNodeProps } from './types'; -const node = { id: 'abc' }; +const node = { id: 'abc', x: 0, y: 0, width: 0, height: 0 }; const setNode = jest.fn(() => new dagre.graphlib.Graph()); const renderElement = jest.fn((props: RenderNodeProps) => ( {props.node.id} )); const minProps = { - id: node.id, node, setNode, render: renderElement, - x: 0, - y: 0, - width: 0, - height: 0, }; describe('', () => { @@ -50,7 +45,7 @@ describe('', () => { it('renders the supplied element', () => { const { getByText } = render(); - expect(getByText(minProps.id)).toBeInTheDocument(); + expect(getByText(minProps.node.id)).toBeInTheDocument(); }); it('passes down node properties to the render method', () => { @@ -62,13 +57,13 @@ describe('', () => { it('calls setNode with node ID and actual size after rendering', () => { const { getByText } = render(); - expect(getByText(minProps.id)).toBeInTheDocument(); + expect(getByText(minProps.node.id)).toBeInTheDocument(); // Updates the node in the graph expect(setNode).toHaveBeenCalledWith(node.id, { + ...node, height: 100, width: 100, - ...node, }); // Does not pass down width/height to node diff --git a/packages/core-components/src/components/DependencyGraph/Node.tsx b/packages/core-components/src/components/DependencyGraph/Node.tsx index e37f7a6e37..01d518b554 100644 --- a/packages/core-components/src/components/DependencyGraph/Node.tsx +++ b/packages/core-components/src/components/DependencyGraph/Node.tsx @@ -17,8 +17,9 @@ import React from 'react'; import makeStyles from '@material-ui/core/styles/makeStyles'; import { DefaultNode } from './DefaultNode'; -import { RenderNodeFunction, RenderNodeProps, GraphNode } from './types'; +import { RenderNodeFunction, RenderNodeProps, DependencyNode } from './types'; import { NODE_TEST_ID } from './constants'; +import dagre from 'dagre'; export type DependencyGraphNodeClassKey = 'node'; @@ -31,20 +32,23 @@ const useStyles = makeStyles( { name: 'BackstageDependencyGraphNode' }, ); -export type NodeComponentProps = { +export type GraphNode = dagre.Node>; + +export type NodeComponentProps = { node: GraphNode; - render?: RenderNodeFunction; + render?: RenderNodeFunction; setNode: dagre.graphlib.Graph['setNode']; }; const renderDefault = (props: RenderNodeProps) => ; -export function Node({ +export function Node({ render = renderDefault, setNode, node, -}: NodeComponentProps) { - const { width, height, x = 0, y = 0, ...nodeProps } = node; +}: NodeComponentProps) { + const { width, height, x = 0, y = 0 } = node; + const nodeProps: DependencyNode = node; const classes = useStyles(); const nodeRef = React.useRef(null); diff --git a/packages/core-components/src/components/DependencyGraph/types.ts b/packages/core-components/src/components/DependencyGraph/types.ts index ed22007f9a..eab793685b 100644 --- a/packages/core-components/src/components/DependencyGraph/types.ts +++ b/packages/core-components/src/components/DependencyGraph/types.ts @@ -14,73 +14,132 @@ * limitations under the License. */ -import dagre from 'dagre'; +/** + * Types used to customize and provide data to {@link DependencyGraph} + * + * @packageDocumentation + */ -type CustomType = { [customKey: string]: any }; +import React from 'react'; -/* Edges */ -export type DependencyEdge = T & { +/** + * Edge of {@link DependencyGraph} + */ +export type DependencyEdge = T & { + /** + * ID of {@link DependencyNode} from where the Edge start + */ from: string; + /** + * ID of {@link DependencyNode} to where the Edge goes to + */ to: string; + /** + * Label assigned and rendered with the Edge + */ label?: string; }; -export type GraphEdge = DependencyEdge & - dagre.GraphEdge & - EdgeProperties; +/** + * Properties of {@link DependencyGraphTypes.RenderLabelFunction} for {@link DependencyGraphTypes.DependencyEdge} + */ +export type RenderLabelProps = { edge: DependencyEdge }; -export type RenderLabelProps = { edge: DependencyEdge }; - -export type RenderLabelFunction = ( - props: RenderLabelProps, +/** + * Custom React component for edge labels + */ +export type RenderLabelFunction = ( + props: RenderLabelProps, ) => React.ReactNode; -/* Nodes */ -export type DependencyNode = T & { +/** + * Node of {@link DependencyGraph} + */ +export type DependencyNode = T & { id: string; }; -export type GraphNode = dagre.Node>; +/** + * Properties of {@link DependencyGraphTypes.RenderNodeFunction} for {@link DependencyGraphTypes.DependencyNode} + */ +export type RenderNodeProps = { node: DependencyNode }; -export type RenderNodeProps = { node: DependencyNode }; - -export type RenderNodeFunction = ( - props: RenderNodeProps, +/** + * Custom React component for graph {@link DependencyGraphTypes.DependencyNode} + */ +export type RenderNodeFunction = ( + props: RenderNodeProps, ) => React.ReactNode; -/* Based on: https://github.com/dagrejs/dagre/wiki#configuring-the-layout */ - -export type EdgeProperties = { - label?: string; - width?: number; - height?: number; - labeloffset?: number; - labelpos?: LabelPosition; - minlen?: number; - weight?: number; - [customKey: string]: any; -}; - +/** + * Graph direction + */ export enum Direction { + /** + * Top to Bottom + */ TOP_BOTTOM = 'TB', + /** + * Bottom to Top + */ BOTTOM_TOP = 'BT', + /** + * Left to Right + */ LEFT_RIGHT = 'LR', + /** + * Right to Left + */ RIGHT_LEFT = 'RL', } +/** + * Node alignment + */ export enum Alignment { + /** + * Up Left + */ UP_LEFT = 'UL', + /** + * Up Right + */ UP_RIGHT = 'UR', + /** + * Down Left + */ DOWN_LEFT = 'DL', + /** + * Down Right + */ DOWN_RIGHT = 'DR', } +/** + * Algorithm used to rand nodes in graph + */ export enum Ranker { + /** + * {@link https://en.wikipedia.org/wiki/Network_simplex_algorithm | Network Simplex} algorithm + */ NETWORK_SIMPLEX = 'network-simplex', + /** + * Tight Tree algorithm + */ TIGHT_TREE = 'tight-tree', + /** + * Longest path algorithm + * + * @remarks + * + * Simplest and fastest + */ LONGEST_PATH = 'longest-path', } +/** + * Position of label in relation to the edge + */ export enum LabelPosition { LEFT = 'l', RIGHT = 'r', diff --git a/plugins/catalog-graph/api-report.md b/plugins/catalog-graph/api-report.md index b3694b9fe8..815f3427f2 100644 --- a/plugins/catalog-graph/api-report.md +++ b/plugins/catalog-graph/api-report.md @@ -93,13 +93,23 @@ export const EntityCatalogGraphCard: ({ }) => JSX.Element; // @public -export type EntityEdge = DependencyGraphTypes.DependencyEdge<{ +export type EntityEdge = DependencyGraphTypes.DependencyEdge; + +// Warning: (ae-missing-release-tag) "EntityEdgeData" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public +export type EntityEdgeData = { relations: string[]; label: 'visible'; -}>; +}; // @public -export type EntityNode = DependencyGraphTypes.DependencyNode<{ +export type EntityNode = DependencyGraphTypes.DependencyNode; + +// Warning: (ae-missing-release-tag) "EntityNodeData" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public +export type EntityNodeData = { name: string; kind?: string; title?: string; @@ -107,7 +117,7 @@ export type EntityNode = DependencyGraphTypes.DependencyNode<{ focused?: boolean; color?: 'primary' | 'secondary' | 'default'; onClick?: MouseEventHandler; -}>; +}; // @public export const EntityRelationsGraph: ({ diff --git a/plugins/catalog-graph/src/components/EntityRelationsGraph/CustomLabel.test.tsx b/plugins/catalog-graph/src/components/EntityRelationsGraph/CustomLabel.test.tsx index 2a48600941..5b8f50b983 100644 --- a/plugins/catalog-graph/src/components/EntityRelationsGraph/CustomLabel.test.tsx +++ b/plugins/catalog-graph/src/components/EntityRelationsGraph/CustomLabel.test.tsx @@ -31,12 +31,6 @@ describe('', () => { relations: [RELATION_PARENT_OF], from: 'from-id', to: 'to-id', - id: 'id', - x: 111, - y: 222, - width: 100, - height: 25, - points: [], }} /> , @@ -54,12 +48,6 @@ describe('', () => { relations: [RELATION_PARENT_OF, RELATION_CHILD_OF], from: 'from-id', to: 'to-id', - id: 'id', - x: 111, - y: 222, - width: 100, - height: 25, - points: [], }} /> , diff --git a/plugins/catalog-graph/src/components/EntityRelationsGraph/CustomLabel.tsx b/plugins/catalog-graph/src/components/EntityRelationsGraph/CustomLabel.tsx index 9016891efa..60a858eee6 100644 --- a/plugins/catalog-graph/src/components/EntityRelationsGraph/CustomLabel.tsx +++ b/plugins/catalog-graph/src/components/EntityRelationsGraph/CustomLabel.tsx @@ -17,7 +17,7 @@ import { DependencyGraphTypes } from '@backstage/core-components'; import { BackstageTheme } from '@backstage/theme'; import makeStyles from '@material-ui/core/styles/makeStyles'; import React from 'react'; -import { GraphEdge } from './types'; +import { EntityEdgeData } from './types'; import classNames from 'classnames'; const useStyles = makeStyles((theme: BackstageTheme) => ({ @@ -31,7 +31,7 @@ const useStyles = makeStyles((theme: BackstageTheme) => ({ export function CustomLabel({ edge: { relations }, -}: DependencyGraphTypes.RenderLabelProps) { +}: DependencyGraphTypes.RenderLabelProps) { const classes = useStyles(); return ( diff --git a/plugins/catalog-graph/src/components/EntityRelationsGraph/CustomNode.test.tsx b/plugins/catalog-graph/src/components/EntityRelationsGraph/CustomNode.test.tsx index f411f8255a..48272b8d1e 100644 --- a/plugins/catalog-graph/src/components/EntityRelationsGraph/CustomNode.test.tsx +++ b/plugins/catalog-graph/src/components/EntityRelationsGraph/CustomNode.test.tsx @@ -36,10 +36,6 @@ describe('', () => { name: 'name', namespace: 'namespace', id: 'kind:namespace/name', - x: 111, - y: 222, - width: 100, - height: 25, color: 'primary', }} /> @@ -59,10 +55,6 @@ describe('', () => { name: 'name', namespace: 'default', id: 'kind:default/name', - x: 111, - y: 222, - width: 100, - height: 25, }} /> , @@ -83,10 +75,6 @@ describe('', () => { namespace: 'namespace', onClick, id: 'kind:namespace/name', - x: 111, - y: 222, - width: 100, - height: 25, }} /> , @@ -108,10 +96,6 @@ describe('', () => { namespace: 'namespace', title: 'Custom Title', id: 'kind:namespace/name', - x: 111, - y: 222, - width: 100, - height: 25, }} /> , diff --git a/plugins/catalog-graph/src/components/EntityRelationsGraph/CustomNode.tsx b/plugins/catalog-graph/src/components/EntityRelationsGraph/CustomNode.tsx index 53542cfbd6..9cd752a5d7 100644 --- a/plugins/catalog-graph/src/components/EntityRelationsGraph/CustomNode.tsx +++ b/plugins/catalog-graph/src/components/EntityRelationsGraph/CustomNode.tsx @@ -20,7 +20,7 @@ import { makeStyles } from '@material-ui/core/styles'; import classNames from 'classnames'; import React, { useLayoutEffect, useRef, useState } from 'react'; import { EntityKindIcon } from './EntityKindIcon'; -import { GraphNode } from './types'; +import { EntityNodeData } from './types'; const useStyles = makeStyles((theme: BackstageTheme) => ({ node: { @@ -65,7 +65,7 @@ export function CustomNode({ title, onClick, }, -}: DependencyGraphTypes.RenderNodeProps) { +}: DependencyGraphTypes.RenderNodeProps) { const classes = useStyles(); const [width, setWidth] = useState(0); const [height, setHeight] = useState(0); diff --git a/plugins/catalog-graph/src/components/EntityRelationsGraph/index.ts b/plugins/catalog-graph/src/components/EntityRelationsGraph/index.ts index 63ac9c2eac..b86c8f05ae 100644 --- a/plugins/catalog-graph/src/components/EntityRelationsGraph/index.ts +++ b/plugins/catalog-graph/src/components/EntityRelationsGraph/index.ts @@ -17,4 +17,9 @@ export { EntityRelationsGraph } from './EntityRelationsGraph'; export { ALL_RELATION_PAIRS } from './relations'; export type { RelationPairs } from './relations'; export { Direction } from './types'; -export type { EntityEdge, EntityNode } from './types'; +export type { + EntityEdgeData, + EntityEdge, + EntityNodeData, + EntityNode, +} from './types'; diff --git a/plugins/catalog-graph/src/components/EntityRelationsGraph/types.ts b/plugins/catalog-graph/src/components/EntityRelationsGraph/types.ts index d6bda71a33..830032d527 100644 --- a/plugins/catalog-graph/src/components/EntityRelationsGraph/types.ts +++ b/plugins/catalog-graph/src/components/EntityRelationsGraph/types.ts @@ -17,11 +17,9 @@ import { DependencyGraphTypes } from '@backstage/core-components'; import { MouseEventHandler } from 'react'; /** - * Edge between two entities. - * - * @public + * Additional Data for entities */ -export type EntityEdge = DependencyGraphTypes.DependencyEdge<{ +export type EntityEdgeData = { /** * Up to two relations that are connecting an entity. */ @@ -31,14 +29,19 @@ export type EntityEdge = DependencyGraphTypes.DependencyEdge<{ */ // Not used, but has to be non empty to draw a label at all! label: 'visible'; -}>; +}; /** - * Node representing an entity. + * Edge between two entities. * * @public */ -export type EntityNode = DependencyGraphTypes.DependencyNode<{ +export type EntityEdge = DependencyGraphTypes.DependencyEdge; + +/** + * Additional data for Entity Node + */ +export type EntityNodeData = { /** * Name of the entity. */ @@ -68,11 +71,14 @@ export type EntityNode = DependencyGraphTypes.DependencyNode<{ * Optional click handler. */ onClick?: MouseEventHandler; -}>; +}; -export type GraphEdge = DependencyGraphTypes.GraphEdge; - -export type GraphNode = DependencyGraphTypes.GraphNode; +/** + * Node representing an entity. + * + * @public + */ +export type EntityNode = DependencyGraphTypes.DependencyNode; /** * Render direction of the graph.