Skip to content

Commit

Permalink
feat: more powerful project search (#4542)
Browse files Browse the repository at this point in the history
  • Loading branch information
kwasniew authored Aug 22, 2023
1 parent 3acff3e commit 8a3889d
Show file tree
Hide file tree
Showing 4 changed files with 240 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,11 @@ export const SearchSuggestions: VFC<SearchSuggestionsProps> = ({
return {
name: column.filterName,
header: column.Header ?? column.filterName,
options: [...new Set(filterOptions)].sort((a, b) =>
a.localeCompare(b)
),
options: [...new Set(filterOptions)]
.filter(Boolean)
.flatMap(item => item.split('\n'))
.map(item => (item.includes(' ') ? `"${item}"` : item))
.sort((a, b) => a.localeCompare(b)),
suggestedOption:
filterOptions[randomRow] ?? `example-${column.filterName}`,
values: getFilterValues(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import { createLocalStorage } from 'utils/createLocalStorage';
import EnvironmentStrategyDialog from 'component/common/EnvironmentStrategiesDialog/EnvironmentStrategyDialog';
import { FeatureStaleDialog } from 'component/common/FeatureStaleDialog/FeatureStaleDialog';
import { FeatureArchiveDialog } from 'component/common/FeatureArchiveDialog/FeatureArchiveDialog';
import { useSearch } from 'hooks/useSearch';
import { getColumnValues, includesFilter, useSearch } from 'hooks/useSearch';
import { Search } from 'component/common/Search/Search';
import { useChangeRequestToggle } from 'hooks/useChangeRequestToggle';
import { ChangeRequestDialogue } from 'component/changeRequest/ChangeRequestConfirmDialog/ChangeRequestConfirmDialog';
Expand Down Expand Up @@ -234,6 +234,7 @@ export const ProjectFeatureToggles = ({
accessor: 'type',
Cell: FeatureTypeCell,
align: 'center',
filterName: 'type',
maxWidth: 80,
},
{
Expand Down Expand Up @@ -265,6 +266,16 @@ export const ProjectFeatureToggles = ({
Cell: FeatureTagCell,
width: 80,
searchable: true,
filterName: 'tags',
filterBy(
row: IFeatureToggleListItem,
values: string[]
) {
return includesFilter(
getColumnValues(this, row),
values
);
},
},
]
: []),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,13 @@ import {
getSearchTextGenerator,
searchInFilteredData,
filter,
useSearch,
includesFilter,
getColumnValues,
} from './useSearch';
import { FC } from 'react';
import { render, screen } from '@testing-library/react';
import { IFeatureToggleListItem } from '../interfaces/featureToggle';

const columns = [
{
Expand Down Expand Up @@ -32,6 +38,16 @@ const columns = [
searchBy: (row: any, value: string) =>
(value === 'seen' && row.seen) || (value === 'never' && !row.seen),
},
{
accessor: (row: IFeatureToggleListItem) =>
row.tags?.map(({ type, value }) => `${type}:${value}`).join('\n') ||
'',
searchable: true,
filterName: 'tags',
filterBy(row: IFeatureToggleListItem, values: string[]) {
return includesFilter(getColumnValues(this, row), values);
},
},
];

const data = [
Expand All @@ -41,27 +57,34 @@ const data = [
stale: false,
type: 'release',
seen: true,
tags: [
{ type: 'simple', value: 'tag' },
{ type: 'simple', value: 'some space' },
],
},
{
name: 'my-feature-toggle-2',
project: 'default',
stale: true,
type: 'experiment',
seen: false,
tags: [],
},
{
name: 'my-feature-toggle-3',
project: 'my-project',
stale: false,
type: 'operational',
seen: false,
tags: [],
},
{
name: 'my-feature-toggle-4',
project: 'my-project',
stale: true,
type: 'permission',
seen: true,
tags: [],
},
];

Expand Down Expand Up @@ -143,13 +166,15 @@ describe('searchInFilteredData', () => {
name: 'my-feature-toggle-3',
project: 'my-project',
stale: false,
tags: [],
type: 'operational',
seen: false,
},
{
name: 'my-feature-toggle-4',
project: 'my-project',
stale: true,
tags: [],
type: 'permission',
seen: true,
},
Expand All @@ -162,6 +187,7 @@ describe('searchInFilteredData', () => {
name: 'my-feature-toggle-2',
project: 'default',
stale: true,
tags: [],
type: 'experiment',
seen: false,
},
Expand All @@ -187,6 +213,7 @@ describe('searchInFilteredData', () => {
name: 'my-feature-toggle-2',
project: 'default',
stale: true,
tags: [],
type: 'experiment',
seen: false,
},
Expand All @@ -201,13 +228,15 @@ describe('searchInFilteredData', () => {
name: 'my-feature-toggle-2',
project: 'default',
stale: true,
tags: [],
type: 'experiment',
seen: false,
},
{
name: 'my-feature-toggle-3',
project: 'my-project',
stale: false,
tags: [],
type: 'operational',
seen: false,
},
Expand All @@ -225,13 +254,18 @@ describe('filter', () => {
name: 'my-feature-toggle',
project: 'default',
stale: false,
tags: [
{ type: 'simple', value: 'tag' },
{ type: 'simple', value: 'some space' },
],
type: 'release',
seen: true,
},
{
name: 'my-feature-toggle-2',
project: 'default',
stale: true,
tags: [],
type: 'experiment',
seen: false,
},
Expand All @@ -244,13 +278,18 @@ describe('filter', () => {
name: 'my-feature-toggle',
project: 'default',
stale: false,
tags: [
{ type: 'simple', value: 'tag' },
{ type: 'simple', value: 'some space' },
],
type: 'release',
seen: true,
},
{
name: 'my-feature-toggle-3',
project: 'my-project',
stale: false,
tags: [],
type: 'operational',
seen: false,
},
Expand All @@ -276,13 +315,15 @@ describe('filter', () => {
name: 'my-feature-toggle-3',
project: 'my-project',
stale: false,
tags: [],
type: 'operational',
seen: false,
},
{
name: 'my-feature-toggle-4',
project: 'my-project',
stale: true,
tags: [],
type: 'permission',
seen: true,
},
Expand All @@ -297,16 +338,162 @@ describe('filter', () => {
name: 'my-feature-toggle-2',
project: 'default',
stale: true,
tags: [],
type: 'experiment',
seen: false,
},
{
name: 'my-feature-toggle-4',
project: 'my-project',
stale: true,
tags: [],
type: 'permission',
seen: true,
},
]);
});
});

const SearchData: FC<{ searchValue: string }> = ({ searchValue }) => {
const search = useSearch(columns, searchValue, data);

return <div>{search.data.map(item => item.name).join(',')}</div>;
};

const SearchText: FC<{ searchValue: string }> = ({ searchValue }) => {
const search = useSearch(columns, searchValue, data);

return <div>{search.getSearchText(searchValue)}</div>;
};

describe('Search and filter data', () => {
it('should filter single value', () => {
render(<SearchData searchValue={'project:my-project'} />);

screen.getByText('my-feature-toggle-3,my-feature-toggle-4');
});

it('should filter multiple values', () => {
render(<SearchData searchValue={'project:my-project,another-value'} />);

screen.getByText('my-feature-toggle-3,my-feature-toggle-4');
});

it('should filter multiple values with spaces', () => {
render(
<SearchData searchValue={'project:my-project , another-value'} />
);

screen.getByText('my-feature-toggle-3,my-feature-toggle-4');
});

it('should handle multiple filters', () => {
render(
<SearchData
searchValue={'project:my-project ,another-value state:active'}
/>
);

screen.getByText('my-feature-toggle-3');
});

it('should handle multiple filters with long spaces', () => {
render(
<SearchData
searchValue={
'project:my-project , another-value state:active , stale'
}
/>
);

screen.getByText('my-feature-toggle-3,my-feature-toggle-4');
});

it('should handle multiple filters and search string in between', () => {
render(
<SearchData
searchValue={
'project:my-project , another-value toggle-3 state:active , stale'
}
/>
);

screen.getByText('my-feature-toggle-3');
});

it('should handle multiple filters and search string at the end', () => {
render(
<SearchData
searchValue={
'project:my-project , another-value state:active , stale toggle-3'
}
/>
);

screen.getByText('my-feature-toggle-3');
});

it('should handle multiple filters and search string at the beginning', () => {
render(
<SearchData
searchValue={
'toggle-3 project:my-project , another-value state:active , stale'
}
/>
);

screen.getByText('my-feature-toggle-3');
});

it('should return basic search text', () => {
render(<SearchText searchValue={'toggle-3'} />);

screen.getByText('toggle-3');
});

it('should return advanced search text', () => {
render(
<SearchText
searchValue={
'project:my-project , another-value toggle-3 state:active , stale'
}
/>
);

screen.getByText('toggle-3');
});

it('should support custom filter and accessor', () => {
render(<SearchData searchValue={'tags:simple:tag'} />);

screen.getByText('my-feature-toggle');
});

it('should support search on top of filter', () => {
render(<SearchText searchValue={'tags:simple:tag simple:tag'} />);

screen.getByText('simple:tag');
});

it('should support custom filter with spaces', () => {
render(<SearchData searchValue={'tags:"simple:some space",tag'} />);

screen.getByText('my-feature-toggle');
});

it('should support custom filter with spaces - space in second term', () => {
render(<SearchData searchValue={'tags:tag,"simple:some space"'} />);

screen.getByText('my-feature-toggle');
});

it('should support quotes in filter and search', () => {
render(
<SearchData
searchValue={'tags:tag,"simple:some space" "my-feature-toggle"'}
/>
);

screen.getByText('my-feature-toggle');
});
});
Loading

0 comments on commit 8a3889d

Please sign in to comment.