diff --git a/.changeset/lemon-fishes-build.md b/.changeset/lemon-fishes-build.md index 965fba2bb6..0b1ba4090c 100644 --- a/.changeset/lemon-fishes-build.md +++ b/.changeset/lemon-fishes-build.md @@ -1,5 +1,4 @@ --- -'@backstage/catalog-model': patch '@backstage/plugin-explore': patch --- diff --git a/packages/catalog-model/examples/acme/org.yaml b/packages/catalog-model/examples/acme/org.yaml index b98647aec5..9a0d690b57 100644 --- a/packages/catalog-model/examples/acme/org.yaml +++ b/packages/catalog-model/examples/acme/org.yaml @@ -30,4 +30,3 @@ spec: - ./team-b-group.yaml - ./team-c-group.yaml - ./team-d-group.yaml - - ./team-e-big-name-group.yaml diff --git a/packages/catalog-model/examples/acme/team-e-big-name-group.yaml b/packages/catalog-model/examples/acme/team-e-big-name-group.yaml deleted file mode 100644 index 3242e5a715..0000000000 --- a/packages/catalog-model/examples/acme/team-e-big-name-group.yaml +++ /dev/null @@ -1,13 +0,0 @@ -apiVersion: backstage.io/v1alpha1 -kind: Group -metadata: - name: team-e - description: Team E With A Very Very Very Very Big Name Size -spec: - type: team - profile: - displayName: Team E With A Very Very Very Very Big Name Size - email: team-e@example.com - picture: https://avatars.dicebear.com/api/identicon/team-e@example.com.svg?background=%23fff&margin=25 - parent: boxoffice - children: [] diff --git a/plugins/explore/src/components/GroupsExplorerContent/GroupsDiagram.test.tsx b/plugins/explore/src/components/GroupsExplorerContent/GroupsDiagram.test.tsx index bce7e88191..66f54900c9 100644 --- a/plugins/explore/src/components/GroupsExplorerContent/GroupsDiagram.test.tsx +++ b/plugins/explore/src/components/GroupsExplorerContent/GroupsDiagram.test.tsx @@ -66,184 +66,6 @@ describe('', () => { }, }, ); - expect(getByText('Group A', { selector: 'tspan' })).toBeInTheDocument(); - }); - - it('show multiple groups', async () => { - const catalogApi: Partial = { - getEntities: () => - Promise.resolve({ - items: [ - { - apiVersion: 'backstage.io/v1alpha1', - kind: 'Group', - metadata: { - name: 'group-a', - namespace: 'my-namespace', - }, - spec: { - profile: { - displayName: 'Group A', - }, - type: 'organization', - }, - }, - { - apiVersion: 'backstage.io/v1alpha1', - kind: 'Group', - metadata: { - name: 'group-b', - namespace: 'my-namespace', - }, - spec: { - profile: { - displayName: 'Group B', - }, - type: 'organization', - }, - }, - ] as Entity[], - }), - }; - - const { getByText } = await renderInTestApp( - - - , - { - mountedRoutes: { - '/catalog/:namespace/:kind/:name': entityRouteRef, - }, - }, - ); - expect(getByText('Group A', { selector: 'tspan' })).toBeInTheDocument(); - expect(getByText('Group B', { selector: 'tspan' })).toBeInTheDocument(); - }); - - it('show single group with big name/displayName', async () => { - const catalogApi: Partial = { - getEntities: () => - Promise.resolve({ - items: [ - { - apiVersion: 'backstage.io/v1alpha1', - kind: 'Group', - metadata: { - name: 'group-a', - namespace: 'my-namespace', - }, - spec: { - profile: { - displayName: - 'Group A Big Name1 Name2 Name3 Name4 Name5 Name6', - }, - type: 'organization', - }, - }, - ] as Entity[], - }), - }; - - const { getByText } = await renderInTestApp( - - - , - { - mountedRoutes: { - '/catalog/:namespace/:kind/:name': entityRouteRef, - }, - }, - ); - - expect( - getByText('Group A Big Name1 Name2 Name3 Name4 Name5 Name6', { - selector: 'title', - }), - ).toBeInTheDocument(); - expect(getByText('Group A Big', { selector: 'tspan' })).toBeInTheDocument(); - expect( - getByText('Name1 Name2 Name3', { selector: 'tspan' }), - ).toBeInTheDocument(); - expect( - getByText('Name4 Name5 Name6...', { selector: 'tspan' }), - ).toBeInTheDocument(); - }); - - it('show multiple groups and one with big name', async () => { - const catalogApi: Partial = { - getEntities: () => - Promise.resolve({ - items: [ - { - apiVersion: 'backstage.io/v1alpha1', - kind: 'Group', - metadata: { - name: 'group-a', - namespace: 'my-namespace', - }, - spec: { - profile: { - displayName: 'Group A', - }, - type: 'organization', - }, - }, - { - apiVersion: 'backstage.io/v1alpha1', - kind: 'Group', - metadata: { - name: 'group-b', - namespace: 'my-namespace', - }, - spec: { - profile: { - displayName: 'Group B', - }, - type: 'organization', - }, - }, - { - apiVersion: 'backstage.io/v1alpha1', - kind: 'Group', - metadata: { - name: 'group-c', - namespace: 'my-namespace', - }, - spec: { - profile: { - displayName: - 'Group C Big Name1 Name2 Name3 Name4 Name5 Name6', - }, - type: 'organization', - }, - }, - ] as Entity[], - }), - }; - - const { getByText } = await renderInTestApp( - - - , - { - mountedRoutes: { - '/catalog/:namespace/:kind/:name': entityRouteRef, - }, - }, - ); - expect(getByText('Group A', { selector: 'tspan' })).toBeInTheDocument(); - expect(getByText('Group B', { selector: 'tspan' })).toBeInTheDocument(); - expect( - getByText('Group C Big Name1 Name2 Name3 Name4 Name5 Name6', { - selector: 'title', - }), - ).toBeInTheDocument(); - expect(getByText('Group C Big', { selector: 'tspan' })).toBeInTheDocument(); - expect( - getByText('Name1 Name2 Name3', { selector: 'tspan' }), - ).toBeInTheDocument(); - expect( - getByText('Name4 Name5 Name6...', { selector: 'tspan' }), - ).toBeInTheDocument(); + expect(getByText('Group A', { selector: 'div' })).toBeInTheDocument(); }); }); diff --git a/plugins/explore/src/components/GroupsExplorerContent/GroupsDiagram.tsx b/plugins/explore/src/components/GroupsExplorerContent/GroupsDiagram.tsx index 53a16f1114..19570a8802 100644 --- a/plugins/explore/src/components/GroupsExplorerContent/GroupsDiagram.tsx +++ b/plugins/explore/src/components/GroupsExplorerContent/GroupsDiagram.tsx @@ -50,15 +50,32 @@ const useStyles = makeStyles((theme: BackstageTheme) => ({ fill: 'yellowgreen', stroke: theme.palette.border, }, + centeredContent: { + padding: '10px', + height: '100%', + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + color: 'black', + }, + textWrapper: { + display: '-webkit-box', + WebkitBoxOrient: 'vertical', + WebkitLineClamp: 2, + overflow: 'hidden', + textOverflow: 'ellipsis', + textAlign: 'center', + fontWeight: 'bold', + fontSize: '20px', + }, })); -const TEXT_FONT_SIZE: number = 15; -const NODE_WIDTH: number = 180; -const NODE_HEIGHT: number = 90; -const NODE_CORNER_RADIUS: number = 20; -const NODE_MIDDLE_ALIGNMENT_SHIFT: number = 5; -const NODE_MAX_WORDS_PER_ROW: number = 3; -const NODE_MAX_LINES: number = 3; +const dimensions = { + nodeWidth: 180, + nodeHeight: 90, + nodeCornerRadius: 20, + nodeAligmentShift: 5, +}; function RenderNode(props: DependencyGraphTypes.RenderNodeProps) { const classes = useStyles(); @@ -68,127 +85,57 @@ function RenderNode(props: DependencyGraphTypes.RenderNodeProps) { return ( {props.node.name} - - {props.node.name} - +
+
{props.node.name}
+
+
); } const ref = parseEntityRef(props.node.id); - const nameChunks = splitNameInChunks(props.node.name); - const objs = prepareForDisplay(nameChunks); return ( {props.node.name} - - {objs.map(function (object: any, i: number) { - return ( - - {object.text} - - ); - })} - +
+
{props.node.name}
+
+
); } -/** - * Join chunks based on max words per line and add dy position shifting - * @param chunkedArray - * @returns - */ -function prepareForDisplay(chunkedArray: any): any { - return chunkedArray.map((val: Array, pos: number) => { - const text = val.join(' '); - // If array length == 1, dy should be 0 since there is no need to divide the node into blocks, we just need to centralize it - const dy = chunkedArray.length === 1 ? 0 : getDy(pos) - 30; - return { dy: dy, text: text }; - }); -} - -/** - * text svg dy shifting based on array pos and in the blocks inside the node - * @param i text position on the array - */ -function getDy(i: number) { - const blocksSize = NODE_HEIGHT / NODE_MAX_LINES; - const position = blocksSize * i; - return position; -} - -/** - * Create Chunked name based on NODE_MAX_LINES and NODE_MAX_WORDS_PER_ROW - * @param name from props.node.name - * @returns - */ -function splitNameInChunks(name: string) { - const array = name.split(' '); - const formated = array - .slice(0, NODE_MAX_LINES * NODE_MAX_WORDS_PER_ROW) - .map((it, pos) => - pos + 1 === NODE_MAX_LINES * NODE_MAX_WORDS_PER_ROW ? `${it}...` : it, - ); - const chunked = chunkArray(formated, NODE_MAX_WORDS_PER_ROW); - return chunked; -} - -/** - * Returns an array with arrays of the given size. - * - * @param arr {Array} Array to split - * @param size {Integer} Size of each group - */ -function chunkArray(arr: Array, size: number) { - const results = []; - - while (arr.length) { - results.push(arr.splice(0, size)); - } - return results; -} - /** * Dynamically generates a diagram of groups registered in the catalog. */