1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-04-29 01:15:48 +02:00

fix: projects archive search (#7898)

Filter projects when searching
This commit is contained in:
Tymoteusz Czech 2024-08-15 16:19:29 +02:00 committed by GitHub
parent a3decb543f
commit f2e2952c31
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 88 additions and 13 deletions

View File

@ -1,4 +1,4 @@
import type { VFC } from 'react'; import type { FC } from 'react';
import { safeRegExp } from '@server/util/escape-regex'; import { safeRegExp } from '@server/util/escape-regex';
import { styled } from '@mui/material'; import { styled } from '@mui/material';
@ -14,7 +14,7 @@ export const StyledSpan = styled('span')(({ theme }) => ({
}, },
})); }));
export const Highlighter: VFC<IHighlighterProps> = ({ export const Highlighter: FC<IHighlighterProps> = ({
search, search,
children, children,
caseSensitive, caseSensitive,

View File

@ -28,6 +28,8 @@ import {
import Undo from '@mui/icons-material/Undo'; import Undo from '@mui/icons-material/Undo';
import PermissionIconButton from 'component/common/PermissionIconButton/PermissionIconButton'; import PermissionIconButton from 'component/common/PermissionIconButton/PermissionIconButton';
import Delete from '@mui/icons-material/Delete'; import Delete from '@mui/icons-material/Delete';
import { Highlighter } from 'component/common/Highlighter/Highlighter';
import { useSearchHighlightContext } from 'component/common/Table/SearchHighlightContext/SearchHighlightContext';
export type ProjectArchiveCardProps = { export type ProjectArchiveCardProps = {
id: string; id: string;
@ -51,16 +53,21 @@ export const ProjectArchiveCard: FC<ProjectArchiveCardProps> = ({
owners, owners,
}) => { }) => {
const { locationSettings } = useLocationSettings(); const { locationSettings } = useLocationSettings();
const { searchQuery } = useSearchHighlightContext();
return ( return (
<StyledProjectCard disabled> <StyledProjectCard disabled data-testid={id}>
<StyledProjectCardBody> <StyledProjectCardBody>
<StyledDivHeader> <StyledDivHeader>
<StyledIconBox> <StyledIconBox>
<ProjectIcon color='action' /> <ProjectIcon color='action' />
</StyledIconBox> </StyledIconBox>
<StyledBox data-loading> <StyledBox data-loading>
<StyledCardTitle>{name}</StyledCardTitle> <StyledCardTitle>
<Highlighter search={searchQuery}>
{name}
</Highlighter>
</StyledCardTitle>
</StyledBox> </StyledBox>
<ProjectModeBadge mode={mode} /> <ProjectModeBadge mode={mode} />
</StyledDivHeader> </StyledDivHeader>
@ -89,6 +96,7 @@ export const ProjectArchiveCard: FC<ProjectArchiveCardProps> = ({
date={ date={
new Date(archivedAt as string) new Date(archivedAt as string)
} }
live={false}
/> />
</p> </p>
</Box> </Box>

View File

@ -0,0 +1,52 @@
import { screen, waitFor } from '@testing-library/react';
import { render } from 'utils/testRenderer';
import { testServerRoute, testServerSetup } from 'utils/testServer';
import { ArchiveProjectList } from './ArchiveProjectList';
import userEvent from '@testing-library/user-event';
const server = testServerSetup();
const setupApi = () => {
testServerRoute(server, '/api/admin/projects', {
projects: [
{ id: 'testid-1', name: 'Project One', archived: true },
{ id: 'testid-2', name: 'Project Two', archived: true },
],
});
testServerRoute(server, '/api/admin/ui-config', {
flags: {
archiveFeature: true,
},
versionInfo: {
current: { enterprise: 'version' },
},
});
};
beforeEach(() => {
setupApi();
});
test('displays archived projects correctly', async () => {
render(<ArchiveProjectList />);
await waitFor(() => {
expect(screen.getByText('Project One')).toBeInTheDocument();
expect(screen.getByText('Project Two')).toBeInTheDocument();
});
});
test('search in header works', async () => {
render(<ArchiveProjectList />);
const searchInput = screen.getByPlaceholderText(/^Search/);
expect(searchInput).toBeInTheDocument();
await userEvent.type(searchInput, 'One');
await waitFor(() => {
expect(screen.queryByTestId('testid-1')).toBeInTheDocument();
expect(screen.queryByTestId('testid-2')).not.toBeInTheDocument();
});
});

View File

@ -1,4 +1,4 @@
import { type FC, useEffect, useState } from 'react'; import { type FC, useEffect, useMemo, useState } from 'react';
import { useSearchParams } from 'react-router-dom'; import { useSearchParams } from 'react-router-dom';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { PageContent } from 'component/common/PageContent/PageContent'; import { PageContent } from 'component/common/PageContent/PageContent';
@ -15,6 +15,8 @@ import {
import useProjects from 'hooks/api/getters/useProjects/useProjects'; import useProjects from 'hooks/api/getters/useProjects/useProjects';
import { ReviveProjectDialog } from './ReviveProjectDialog/ReviveProjectDialog'; import { ReviveProjectDialog } from './ReviveProjectDialog/ReviveProjectDialog';
import { DeleteProjectDialogue } from '../Project/DeleteProject/DeleteProjectDialogue'; import { DeleteProjectDialogue } from '../Project/DeleteProject/DeleteProjectDialogue';
import { SearchHighlightProvider } from 'component/common/Table/SearchHighlightContext/SearchHighlightContext';
import { safeRegExp } from '@server/util/escape-regex';
const StyledApiError = styled(ApiError)(({ theme }) => ({ const StyledApiError = styled(ApiError)(({ theme }) => ({
maxWidth: '500px', maxWidth: '500px',
@ -82,6 +84,16 @@ export const ArchiveProjectList: FC = () => {
/> />
); );
const filteredProjects = useMemo(
() =>
searchValue
? projects.filter((project) =>
safeRegExp(searchValue, 'i').test(project.name),
)
: projects,
[projects, searchValue],
);
return ( return (
<PageContent <PageContent
isLoading={loading} isLoading={loading}
@ -123,14 +135,16 @@ export const ArchiveProjectList: FC = () => {
)} )}
/> />
<ProjectGroup <SearchHighlightProvider value={searchValue}>
loading={loading} <ProjectGroup
searchValue={searchValue} loading={loading}
projects={projects} searchValue={searchValue}
placeholder='No archived projects found' projects={filteredProjects}
ProjectCardComponent={ProjectCard} placeholder='No archived projects found'
link={false} ProjectCardComponent={ProjectCard}
/> link={false}
/>
</SearchHighlightProvider>
</StyledContainer> </StyledContainer>
<ReviveProjectDialog <ReviveProjectDialog
id={reviveProject.id || ''} id={reviveProject.id || ''}

View File

@ -112,6 +112,7 @@ export const ProjectGroup = <T extends { id: string }>({
</StyledCardLink> </StyledCardLink>
) : ( ) : (
<ProjectCardComponent <ProjectCardComponent
key={project.id}
onHover={() => {}} onHover={() => {}}
{...project} {...project}
/> />