Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: display beta tag with css #14478

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ describe('Navigation', () => {
});

getFilteredMenuListForOverviewPage().forEach((link) => {
expect(screen.getByRole('link', { name: getLinkName(link) })).toBeInTheDocument();
expect(screen.getByRole('link', { name: textMock(link.key) })).toBeInTheDocument();
});
});

Expand All @@ -32,9 +32,9 @@ describe('Navigation', () => {

getFilteredMenuListForOverviewPage().forEach((link) => {
if (link.featureFlagName) {
expect(screen.queryByRole('link', { name: getLinkName(link) })).not.toBeInTheDocument();
expect(screen.queryByRole('link', { name: textMock(link.key) })).not.toBeInTheDocument();
} else {
expect(screen.getByRole('link', { name: getLinkName(link) })).toBeInTheDocument();
expect(screen.getByRole('link', { name: textMock(link.key) })).toBeInTheDocument();
}
});
});
Expand All @@ -47,11 +47,11 @@ describe('Navigation', () => {
});

getFilteredMenuListForOverviewPage().forEach((link) => {
expect(screen.getByRole('link', { name: getLinkName(link) })).toBeInTheDocument();
expect(screen.getByRole('link', { name: textMock(link.key) })).toBeInTheDocument();
});
});

it('renders "beta" tag for menu items that are tagges as beta', () => {
it('renders menu items that are tagged as beta, with isBeta class', () => {
const betaItems = topBarMenuItem.filter((item) => !!item.isBeta);

// ensure any feature flags are toggled on
Expand All @@ -62,18 +62,25 @@ describe('Navigation', () => {
});

betaItems.forEach((link) => {
expect(screen.getByRole('link', { name: `${textMock(link.key)} Beta` })).toBeInTheDocument();
expect(screen.getByRole('link', { name: textMock(link.key) })).toHaveClass('isBeta');
});
});
});

const getLinkName = (linkItem: HeaderMenuItem): string => {
let name = textMock(linkItem.key);
if (linkItem.isBeta) {
name = `${name} Beta`;
}
return name;
};
it('renders menu items that are not tagged as beta, without isBeta class', () => {
const menuItemsNotBeta = getFilteredMenuListForOverviewPage().filter((item) => !item.isBeta);

// ensure any feature flags are toggled on
typedLocalStorage.setItem('featureFlags', getFeatureFlags(menuItemsNotBeta));

renderWithProviders(<Navigation />, {
startUrl: `${APP_DEVELOPMENT_BASENAME}/my-org/my-app`,
});

menuItemsNotBeta.forEach((link) => {
expect(screen.getByRole('link', { name: textMock(link.key) })).not.toHaveClass('isBeta');
});
});
});

const getFeatureFlags = (menuItems: HeaderMenuItem[]) => {
return menuItems.filter((item) => !!item.featureFlagName).map((item) => item.featureFlagName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import { useTranslation } from 'react-i18next';
import { Heading } from '@digdir/designsystemet-react';
import { getFilteredMenuListForOverviewPage } from 'app-development/utils/headerMenu/headerMenuUtils';
import { Link } from 'react-router-dom';
import { StudioBetaTag } from '@studio/components';
import cn from 'classnames';
import { studioBetaTagClasses } from '@studio/components';

export const Navigation = () => {
const { t } = useTranslation();
Expand All @@ -19,10 +20,13 @@ export const Navigation = () => {
<div className={classes.links}>
{menuItems.map((menuItem) => {
return (
<Link key={menuItem.key} to={`../${menuItem.link}`} className={classes.link}>
<Link
key={menuItem.key}
to={`../${menuItem.link}`}
className={cn(classes.link, menuItem.isBeta && studioBetaTagClasses.isBeta)}
>
<menuItem.icon className={classes.icon} />
<span>{t(menuItem.key)}</span>
{menuItem.isBeta && <StudioBetaTag />}
</Link>
);
})}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,3 @@
.active {
border-bottom: 2px solid var(--fds-semantic-surface-neutral-default);
}

.betaTag {
min-height: min-content;
padding: 0 var(--fds-spacing-1);
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ describe('LargeNavigationMenu', () => {
renderLargeNavigationMenu();

menuItems.forEach((item) => {
expect(screen.getByText(item.name)).toBeInTheDocument();
expect(screen.getByRole('link', { name: item.name })).toBeInTheDocument();
});
});

Expand All @@ -30,26 +30,20 @@ describe('LargeNavigationMenu', () => {
routerInitialEntries: [menuItems[0].link],
});

const activeItem = screen.getByText(menuItems[0].name);
const activeItem = screen.getByRole('link', { name: menuItems[0].name });
expect(activeItem).toHaveClass('active');
});

it('should display the beta tag for items marked as beta', () => {
it('should set "isBeta" className for menu item that is beta', () => {
renderLargeNavigationMenu();

const betaTags = screen.getAllByText('Beta');

expect(betaTags.length).toEqual(menuItems.filter((item) => item.isBeta).length);
const menuItem = screen.getByRole('link', { name: menuItems[0].name });
expect(menuItem).toHaveClass('isBeta');
});

it('should not display the beta tag for items not marked as beta', () => {
it('should not set "isBeta" className for menu item that is not beta', () => {
renderLargeNavigationMenu();

const betaTags = screen.getAllByText('Beta');

expect(menuItems.length - betaTags.length).toEqual(
menuItems.filter((item) => !item.isBeta).length,
);
const menuItem = screen.getByRole('link', { name: menuItems[1].name });
expect(menuItem).not.toHaveClass('isBeta');
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, { type ReactElement } from 'react';
import classes from './LargeNavigationMenu.module.css';
import cn from 'classnames';
import { NavLink, useLocation } from 'react-router-dom';
import { StudioBetaTag, StudioPageHeader } from '@studio/components';
import { StudioPageHeader } from '@studio/components';
import { extractLastRouterParam } from 'app-development/utils/headerMenu/headerMenuUtils';
import { type NavigationMenuItem } from 'app-development/types/HeaderMenu/NavigationMenuItem';
import { usePageHeaderContext } from 'app-development/contexts/PageHeaderContext';
Expand Down Expand Up @@ -36,6 +36,7 @@ const HeaderButtonListItem = ({ menuItem }: HeaderButtonListItemProps): ReactEle
<StudioPageHeader.HeaderLink
color='dark'
variant={variant}
isBeta={menuItem.isBeta}
renderLink={(props) => (
<NavLink to={menuItem.link} {...props}>
<span
Expand All @@ -45,7 +46,6 @@ const HeaderButtonListItem = ({ menuItem }: HeaderButtonListItemProps): ReactEle
>
{menuItem.name}
</span>
{menuItem.isBeta && <StudioBetaTag className={classes.betaTag} />}
</NavLink>
)}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const mockMenuItem: NavigationMenuSmallItem = {
href: menuItemLink,
openInNewTab: false,
},
isBeta: true,
isBeta: false,
};

const mockOnClick = jest.fn();
Expand All @@ -32,7 +32,7 @@ describe('SmallHeaderMenuItem', () => {
renderSmallHeaderMenuItem();

const linkElement = screen.getByRole('menuitem', {
name: `${textMock(menuItemName)} Beta`,
name: textMock(menuItemName),
});
expect(linkElement).toBeInTheDocument();
expect(linkElement).toHaveAttribute('href', menuItemLink);
Expand All @@ -44,17 +44,37 @@ describe('SmallHeaderMenuItem', () => {
});

const linkElement = screen.getByRole('menuitem', {
name: `${textMock(menuItemName)} Beta`,
name: textMock(menuItemName),
});
expect(linkElement).toHaveClass('active');
});

it('should add "isBeta" class when menuItem is beta', () => {
renderSmallHeaderMenuItem({
componentProps: { menuItem: { ...mockMenuItem, isBeta: true } },
});

const linkElement = screen.getByRole('menuitem', {
name: textMock(menuItemName),
});
expect(linkElement).toHaveClass('isBeta');
});

it('should not add "isBeta" class by default', () => {
renderSmallHeaderMenuItem();

const linkElement = screen.getByRole('menuitem', {
name: textMock(menuItemName),
});
expect(linkElement).not.toHaveClass('isBeta');
});

it('should call onClick when the NavLink is clicked', async () => {
const user = userEvent.setup();
renderSmallHeaderMenuItem();

const linkElement = screen.getByRole('menuitem', {
name: `${textMock(menuItemName)} Beta`,
name: textMock(menuItemName),
});
await user.click(linkElement);

Expand All @@ -76,7 +96,7 @@ describe('SmallHeaderMenuItem', () => {
});

const linkElement = screen.getByRole('menuitem', {
name: `${textMock('testMenuItem')} Beta`,
name: textMock('testMenuItem'),
});
expect(linkElement).toHaveAttribute('target', '_blank');
expect(linkElement).toHaveAttribute('rel', 'noopener noreferrer');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { useTranslation } from 'react-i18next';
import { DropdownMenu } from '@digdir/designsystemet-react';
import { extractLastRouterParam } from 'app-development/utils/headerMenu/headerMenuUtils';
import { type NavigationMenuSmallItem } from 'app-development/types/HeaderMenu/NavigationMenuSmallItem';
import { StudioBetaTag } from '@studio/components';
import { studioBetaTagClasses } from '@studio/components';

export type SmallHeaderMenuItemProps = {
menuItem: NavigationMenuSmallItem;
Expand Down Expand Up @@ -35,13 +35,13 @@ export const SmallHeaderMenuItem = ({
return (
<DropdownMenu.Item key={menuItem.name} asChild className={linkItemClassName}>
<NavLink
className={menuItem.isBeta && studioBetaTagClasses.isBeta}
to={menuItem.action.href}
onClick={onClick}
target={menuItem.action.openInNewTab ? '_blank' : ''}
rel={menuItem.action.openInNewTab ? 'noopener noreferrer' : ''}
>
{t(menuItem.name)}
{menuItem.isBeta && <StudioBetaTag />}
</NavLink>
</DropdownMenu.Item>
);
Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,16 @@ describe('StudioPageHeaderHeaderLink', () => {
expect(screen.getByRole('link', { name: linkText })).toBeInTheDocument();
});

it('Renders the link without isBeta className by default', () => {
renderStudioPageHeaderHeaderLink();
expect(screen.getByRole('link', { name: linkText })).not.toHaveClass('isBeta');
});

it('Renders the link with isBeta className when isBeta is true', () => {
renderStudioPageHeaderHeaderLink({ isBeta: true });
expect(screen.getByRole('link', { name: linkText })).toHaveClass('isBeta');
});

it('Passes the colour and variant classes to the link', () => {
renderStudioPageHeaderHeaderLink();
const link = screen.getByRole('link');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,33 @@ import { type StudioPageHeaderColor } from '../types/StudioPageHeaderColor';
import cn from 'classnames';
import { type StudioPageHeaderVariant } from '../types/StudioPageHeaderVariant';
import linkClasses from './StudioPageHeaderHeaderLink.module.css';
import { studioBetaTagClasses } from '@studio/components';

export type StudioPageHeaderHeaderLinkProps = {
color: StudioPageHeaderColor;
variant: StudioPageHeaderVariant;
renderLink: (props: HTMLAttributes<HTMLAnchorElement>) => ReactElement;
isBeta?: boolean;
} & HTMLAttributes<HTMLAnchorElement>;

export function StudioPageHeaderHeaderLink({
color,
variant,
className: givenClass,
renderLink,
isBeta,
}: StudioPageHeaderHeaderLinkProps): ReactElement {
const className = cn(
commonClasses.linkOrButton,
commonClasses[variant],
commonClasses[color],
isBeta && studioBetaTagClasses.isBeta,
givenClass,
linkClasses.link,
);
const props: HTMLAttributes<HTMLAnchorElement> = { className };
const props: HTMLAttributes<HTMLAnchorElement> = {
className,
};
return renderLink(props);
}

Expand Down
1 change: 0 additions & 1 deletion frontend/libs/studio-components/src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ export * from './StudioActionCloseButton';
export * from './StudioAlert';
export * from './StudioAnimateHeight';
export * from './StudioAvatar';
export * from './StudioBetaTag';
export * from './StudioBlobDownloader';
export * from './StudioBooleanToggleGroup';
export * from './StudioBreadcrumbs';
Expand Down
3 changes: 3 additions & 0 deletions frontend/libs/studio-components/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import classes from './style/studioBetaTag.module.css';

export * from './components';
export * from './hooks';
export * from './style/studio-variables.css';
export { classes as studioBetaTagClasses };
Loading
Loading