Added new settings to determine how to search on tags during short URL creation, and how many suggestions to display

This commit is contained in:
Alejandro Celaya 2021-08-15 10:55:58 +02:00
parent 590393dcfd
commit 9f02bc6496
4 changed files with 25 additions and 4 deletions

View file

@ -17,8 +17,12 @@ interface RealTimeUpdatesSettings {
interval?: number; interval?: number;
} }
type TagFilteringMode = 'startsWith' | 'includes';
export interface ShortUrlCreationSettings { export interface ShortUrlCreationSettings {
validateUrls: boolean; validateUrls: boolean;
tagFilteringMode?: TagFilteringMode;
maxTagSuggestions?: number;
} }
export interface UiSettings { export interface UiSettings {

View file

@ -1,6 +1,7 @@
import { useEffect } from 'react'; import { useEffect } from 'react';
import ReactTags, { SuggestionComponentProps, TagComponentProps } from 'react-tag-autocomplete'; import ReactTags, { SuggestionComponentProps, TagComponentProps } from 'react-tag-autocomplete';
import ColorGenerator from '../../utils/services/ColorGenerator'; import ColorGenerator from '../../utils/services/ColorGenerator';
import { Settings } from '../../settings/reducers/settings';
import { TagsList } from '../reducers/tagsList'; import { TagsList } from '../reducers/tagsList';
import TagBullet from './TagBullet'; import TagBullet from './TagBullet';
import Tag from './Tag'; import Tag from './Tag';
@ -14,17 +15,20 @@ export interface TagsSelectorProps {
interface TagsSelectorConnectProps extends TagsSelectorProps { interface TagsSelectorConnectProps extends TagsSelectorProps {
listTags: Function; listTags: Function;
tagsList: TagsList; tagsList: TagsList;
settings: Settings;
} }
const toComponentTag = (tag: string) => ({ id: tag, name: tag }); const toComponentTag = (tag: string) => ({ id: tag, name: tag });
const TagsSelector = (colorGenerator: ColorGenerator) => ( const TagsSelector = (colorGenerator: ColorGenerator) => (
{ selectedTags, onChange, listTags, tagsList, placeholder = 'Add tags to the URL' }: TagsSelectorConnectProps, { selectedTags, onChange, placeholder, listTags, tagsList, settings }: TagsSelectorConnectProps,
) => { ) => {
useEffect(() => { useEffect(() => {
listTags(); listTags();
}, []); }, []);
const searchMode = settings.shortUrlCreation?.tagFilteringMode ?? 'startsWith';
const maxSuggestions = settings.shortUrlCreation?.maxTagSuggestions;
const ReactTagsTag = ({ tag, onDelete }: TagComponentProps) => const ReactTagsTag = ({ tag, onDelete }: TagComponentProps) =>
<Tag colorGenerator={colorGenerator} text={tag.name} clearable className="react-tags__tag" onClose={onDelete} />; <Tag colorGenerator={colorGenerator} text={tag.name} clearable className="react-tags__tag" onClose={onDelete} />;
const ReactTagsSuggestion = ({ item }: SuggestionComponentProps) => ( const ReactTagsSuggestion = ({ item }: SuggestionComponentProps) => (
@ -42,9 +46,15 @@ const TagsSelector = (colorGenerator: ColorGenerator) => (
suggestionComponent={ReactTagsSuggestion} suggestionComponent={ReactTagsSuggestion}
allowNew allowNew
addOnBlur addOnBlur
placeholderText={placeholder} placeholderText={placeholder ?? 'Add tags to the URL'}
minQueryLength={1} minQueryLength={1}
maxSuggestionsLength={maxSuggestions}
delimiters={[ 'Enter', 'Tab', ',' ]} delimiters={[ 'Enter', 'Tab', ',' ]}
suggestionsTransform={
searchMode === 'includes'
? (query, suggestions) => suggestions.filter(({ name }) => name.includes(query))
: undefined
}
onDelete={(removedTagIndex) => { onDelete={(removedTagIndex) => {
const tagsCopy = [ ...selectedTags ]; const tagsCopy = [ ...selectedTags ];

View file

@ -12,7 +12,7 @@ import { ConnectDecorator } from '../../container/types';
const provideServices = (bottle: Bottle, connect: ConnectDecorator) => { const provideServices = (bottle: Bottle, connect: ConnectDecorator) => {
// Components // Components
bottle.serviceFactory('TagsSelector', TagsSelector, 'ColorGenerator'); bottle.serviceFactory('TagsSelector', TagsSelector, 'ColorGenerator');
bottle.decorator('TagsSelector', connect([ 'tagsList' ], [ 'listTags' ])); bottle.decorator('TagsSelector', connect([ 'tagsList', 'settings' ], [ 'listTags' ]));
bottle.serviceFactory( bottle.serviceFactory(
'TagCard', 'TagCard',

View file

@ -3,6 +3,7 @@ import { Mock } from 'ts-mockery';
import createTagsSelector from '../../../src/tags/helpers/TagsSelector'; import createTagsSelector from '../../../src/tags/helpers/TagsSelector';
import ColorGenerator from '../../../src/utils/services/ColorGenerator'; import ColorGenerator from '../../../src/utils/services/ColorGenerator';
import { TagsList } from '../../../src/tags/reducers/tagsList'; import { TagsList } from '../../../src/tags/reducers/tagsList';
import { Settings } from '../../../src/settings/reducers/settings';
describe('<TagsSelector />', () => { describe('<TagsSelector />', () => {
const onChange = jest.fn(); const onChange = jest.fn();
@ -14,7 +15,13 @@ describe('<TagsSelector />', () => {
beforeEach(jest.clearAllMocks); beforeEach(jest.clearAllMocks);
beforeEach(() => { beforeEach(() => {
wrapper = shallow( wrapper = shallow(
<TagsSelector selectedTags={tags} tagsList={tagsList} listTags={jest.fn()} onChange={onChange} />, <TagsSelector
selectedTags={tags}
tagsList={tagsList}
settings={Mock.all<Settings>()}
listTags={jest.fn()}
onChange={onChange}
/>,
); );
}); });