1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-05-22 01:16:07 +02:00

fix: prevent project cell overflow on api keys table (#7472)

Preparations for virtualizing API tokens table - projects column for tokens with a list of projects assigned will not overflow the cell.
This commit is contained in:
Tymoteusz Czech 2024-07-02 12:10:02 +02:00 committed by GitHub
parent 8a9535d352
commit e916deda74
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 72 additions and 43 deletions

View File

@ -4,19 +4,14 @@ import { ProjectsList } from 'component/admin/apiToken/ProjectsList/ProjectsList
describe('ProjectsList', () => { describe('ProjectsList', () => {
it('should prioritize new "projects" array over deprecated "project"', async () => { it('should prioritize new "projects" array over deprecated "project"', async () => {
render( const { container } = render(
<ProjectsList <ProjectsList
project='project' project='project'
projects={['project1', 'project2']} projects={['project1', 'project2']}
/>, />,
); );
const links = await screen.findAllByRole('link'); expect(container.textContent).toContain('2 projects');
expect(links).toHaveLength(2);
expect(links[0]).toHaveTextContent('project1');
expect(links[1]).toHaveTextContent('project2');
expect(links[0]).toHaveAttribute('href', '/projects/project1');
expect(links[1]).toHaveAttribute('href', '/projects/project2');
}); });
it('should render correctly with single "project"', async () => { it('should render correctly with single "project"', async () => {
@ -27,12 +22,6 @@ describe('ProjectsList', () => {
expect(links[0]).toHaveTextContent('project'); expect(links[0]).toHaveTextContent('project');
}); });
it('should have comma between project links', async () => {
const { container } = render(<ProjectsList projects={['a', 'b']} />);
expect(container.textContent).toContain(', ');
});
it('should render asterisk if no projects are passed', async () => { it('should render asterisk if no projects are passed', async () => {
const { container } = render(<ProjectsList />); const { container } = render(<ProjectsList />);
@ -44,4 +33,14 @@ describe('ProjectsList', () => {
expect(container.textContent).toEqual('*'); expect(container.textContent).toEqual('*');
}); });
it('should show the number of projects', async () => {
const { container } = render(
<ProjectsList
projects={['project1', 'project2', 'project3', 'project4']}
/>,
);
expect(container.textContent).toContain('4 projects');
});
}); });

View File

@ -1,8 +1,10 @@
import { styled } from '@mui/material'; import { styled } from '@mui/material';
import { Highlighter } from 'component/common/Highlighter/Highlighter'; import { Highlighter } from 'component/common/Highlighter/Highlighter';
import { HtmlTooltip } from 'component/common/HtmlTooltip/HtmlTooltip';
import { LinkCell } from 'component/common/Table/cells/LinkCell/LinkCell';
import { TextCell } from 'component/common/Table/cells/TextCell/TextCell'; import { TextCell } from 'component/common/Table/cells/TextCell/TextCell';
import { useSearchHighlightContext } from 'component/common/Table/SearchHighlightContext/SearchHighlightContext'; import { useSearchHighlightContext } from 'component/common/Table/SearchHighlightContext/SearchHighlightContext';
import { Fragment, type VFC } from 'react'; import { Fragment, type FC } from 'react';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
const StyledLink = styled(Link)(({ theme }) => ({ const StyledLink = styled(Link)(({ theme }) => ({
@ -18,33 +20,25 @@ interface IProjectsListProps {
projects?: string | string[]; projects?: string | string[];
} }
export const ProjectsList: VFC<IProjectsListProps> = ({ export const ProjectsList: FC<IProjectsListProps> = ({ projects, project }) => {
projects,
project,
}) => {
const { searchQuery } = useSearchHighlightContext(); const { searchQuery } = useSearchHighlightContext();
const fields: string[] =
projects && Array.isArray(projects) const projectsList =
projects && Array.isArray(projects) && projects.length > 1
? projects ? projects
: project
? [project]
: []; : [];
if (fields.length === 0) { if (projectsList.length > 0) {
return ( return (
<TextCell> <TextCell>
<Highlighter search={searchQuery}>*</Highlighter> <HtmlTooltip
</TextCell> title={projectsList.map((item, index) => (
);
}
return (
<TextCell>
{fields.map((item, index) => (
<Fragment key={item}> <Fragment key={item}>
{index > 0 && ', '} {index > 0 && ', '}
{!item || item === '*' ? ( {!item || item === '*' ? (
<Highlighter search={searchQuery}>*</Highlighter> <Highlighter search={searchQuery}>
*
</Highlighter>
) : ( ) : (
<StyledLink to={`/projects/${item}`}> <StyledLink to={`/projects/${item}`}>
<Highlighter search={searchQuery}> <Highlighter search={searchQuery}>
@ -54,6 +48,41 @@ export const ProjectsList: VFC<IProjectsListProps> = ({
)} )}
</Fragment> </Fragment>
))} ))}
placement='bottom-start'
arrow
tabIndex={0}
>
<span>{`${projectsList.length}`} projects</span>
</HtmlTooltip>
</TextCell> </TextCell>
); );
}
if (
(projectsList.length === 1 && projectsList[0] === '*') ||
project === '*' ||
(!project && (!projectsList || projectsList.length === 0))
) {
return (
<TextCell>
<HtmlTooltip
title='ALL current and future projects'
placement='bottom'
arrow
>
<span>
<Highlighter search={searchQuery}>*</Highlighter>
</span>
</HtmlTooltip>
</TextCell>
);
}
if (projectsList.length === 1 || project) {
const item = project || projectsList[0];
return <LinkCell to={`/projects/${item}`} title={item} />;
}
return null;
}; };

View File

@ -68,6 +68,7 @@ export interface IHtmlTooltipProps extends TooltipProps {
maxWidth?: SpacingArgument; maxWidth?: SpacingArgument;
maxHeight?: SpacingArgument; maxHeight?: SpacingArgument;
fontSize?: string; fontSize?: string;
tabIndex?: number;
} }
export const HtmlTooltip = (props: IHtmlTooltipProps) => { export const HtmlTooltip = (props: IHtmlTooltipProps) => {