diff --git a/.changeset/selfish-hats-wait.md b/.changeset/selfish-hats-wait.md new file mode 100644 index 0000000000..d706d42e8e --- /dev/null +++ b/.changeset/selfish-hats-wait.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-org': patch +--- + +Add styling to the `MembersListCard` and `ComponentsGrid` to handle overflow text. diff --git a/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.test.tsx b/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.test.tsx index c98cc3eb32..cc524b60a2 100644 --- a/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.test.tsx +++ b/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.test.tsx @@ -28,6 +28,19 @@ import { import React from 'react'; import { MembersListCard } from './MembersListCard'; +// Mock needed because jsdom doesn't correctly implement box-sizing +// https://github.com/ShinyChang/React-Text-Truncate/issues/70 +// https://stackoverflow.com/questions/71916701/how-to-mock-a-react-function-component-that-takes-a-ref-prop +jest.mock('react-text-truncate', () => { + const { forwardRef } = jest.requireActual('react'); + return { + __esModule: true, + default: forwardRef((props: any, ref: any) => ( +
{props.text}
+ )), + }; +}); + describe('MemberTab Test', () => { const groupEntity: GroupEntity = { apiVersion: 'backstage.io/v1alpha1', @@ -95,7 +108,7 @@ describe('MemberTab Test', () => { expect( rendered.getByText('tara-macgovern@example.com'), ).toBeInTheDocument(); - expect(rendered.getByText('Tara MacGovern')).toHaveAttribute( + expect(rendered.getByText('Tara MacGovern').closest('a')).toHaveAttribute( 'href', '/catalog/foo-bar/user/tara.macgovern', ); diff --git a/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.tsx b/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.tsx index c41a73ab9c..eb61989144 100644 --- a/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.tsx +++ b/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.tsx @@ -44,6 +44,7 @@ import { Progress, ResponseErrorPanel, Link, + OverflowTooltip, } from '@backstage/core-components'; import { useApi } from '@backstage/core-plugin-api'; @@ -59,18 +60,6 @@ const useStyles = makeStyles((theme: Theme) => flex: '1', minWidth: '0px', }, - email: { - overflow: 'hidden', - whiteSpace: 'nowrap', - textOverflow: 'ellipsis', - display: 'inline-block', - verticalAlign: 'middle', - maxWidth: '100%', - '&:hover': { - overflow: 'visible', - whiteSpace: 'normal', - }, - }, }), ); @@ -103,23 +92,23 @@ const MemberComponent = (props: { member: UserEntity }) => { - + - {displayName} + {profile?.email && ( - - {profile.email} + + )} {description && ( diff --git a/plugins/org/src/components/Cards/OwnershipCard/ComponentsGrid.tsx b/plugins/org/src/components/Cards/OwnershipCard/ComponentsGrid.tsx index b130057fe3..dbd569abff 100644 --- a/plugins/org/src/components/Cards/OwnershipCard/ComponentsGrid.tsx +++ b/plugins/org/src/components/Cards/OwnershipCard/ComponentsGrid.tsx @@ -15,7 +15,12 @@ */ import { Entity } from '@backstage/catalog-model'; -import { Link, Progress, ResponseErrorPanel } from '@backstage/core-components'; +import { + Link, + OverflowTooltip, + Progress, + ResponseErrorPanel, +} from '@backstage/core-components'; import { useRouteRef } from '@backstage/core-plugin-api'; import { BackstageTheme } from '@backstage/theme'; import { @@ -47,6 +52,9 @@ const useStyles = makeStyles((theme: BackstageTheme) => bold: { fontWeight: theme.typography.fontWeightBold, }, + smallFont: { + fontSize: theme.typography.body2.fontSize, + }, entityTypeBox: { background: (props: { type: string }) => theme.getPageTheme({ themeId: props.type }).backgroundImage, @@ -68,6 +76,7 @@ const EntityCountTile = ({ const classes = useStyles({ type: type ?? kind }); const rawTitle = type ?? kind; + const isLongText = rawTitle.length > 10; return ( @@ -80,9 +89,16 @@ const EntityCountTile = ({ {counter} - - {pluralize(rawTitle.toLocaleUpperCase('en-US'), counter)} - + + + + + {type && {kind}} diff --git a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx index 84f27fa183..30b7dee2de 100644 --- a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx +++ b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx @@ -120,6 +120,19 @@ const getEntitiesMock = ( } as GetEntitiesResponse); }; +// Mock needed because jsdom doesn't correctly implement box-sizing +// https://github.com/ShinyChang/React-Text-Truncate/issues/70 +// https://stackoverflow.com/questions/71916701/how-to-mock-a-react-function-component-that-takes-a-ref-prop +jest.mock('react-text-truncate', () => { + const { forwardRef } = jest.requireActual('react'); + return { + __esModule: true, + default: forwardRef((props: any, ref: any) => ( +
{props.text}
+ )), + }; +}); + describe('OwnershipCard', () => { const groupEntity: GroupEntity = { apiVersion: 'backstage.io/v1alpha1', @@ -177,19 +190,19 @@ describe('OwnershipCard', () => { expect(getByText('OPENAPI')).toBeInTheDocument(); expect( - queryByText(getByText('OPENAPI').parentElement!, '1'), + queryByText(getByText('OPENAPI').closest('a')!, '1'), ).toBeInTheDocument(); expect(getByText('SERVICE')).toBeInTheDocument(); expect( - queryByText(getByText('SERVICE').parentElement!, '1'), + queryByText(getByText('SERVICE').closest('a')!, '1'), ).toBeInTheDocument(); expect(getByText('LIBRARY')).toBeInTheDocument(); expect( - queryByText(getByText('LIBRARY').parentElement!, '1'), + queryByText(getByText('LIBRARY').closest('a')!, '1'), ).toBeInTheDocument(); expect(getByText('SYSTEM')).toBeInTheDocument(); expect( - queryByText(getByText('SYSTEM').parentElement!, '1'), + queryByText(getByText('SYSTEM').closest('a')!, '1'), ).toBeInTheDocument(); }); @@ -215,17 +228,17 @@ describe('OwnershipCard', () => { expect(getByText('SYSTEM')).toBeInTheDocument(); expect( - queryByText(getByText('SYSTEM').parentElement!, '1'), + queryByText(getByText('SYSTEM').closest('a')!, '1'), ).toBeInTheDocument(); expect( - queryByText(getByText('SYSTEM').parentElement!, 'System'), + queryByText(getByText('SYSTEM').closest('a')!, 'System'), ).not.toBeInTheDocument(); expect(getByText('OPENAPI')).toBeInTheDocument(); expect( - queryByText(getByText('OPENAPI').parentElement!, '1'), + queryByText(getByText('OPENAPI').closest('a')!, '1'), ).toBeInTheDocument(); expect( - queryByText(getByText('OPENAPI').parentElement!, 'API'), + queryByText(getByText('OPENAPI').closest('a')!, 'API'), ).toBeInTheDocument(); expect(() => getByText('LIBRARY')).toThrow(); });