Skip to content

Commit

Permalink
feat(ui): add the tag filter to the search filter options (#177)
Browse files Browse the repository at this point in the history
  • Loading branch information
bimalgrg519 authored Jan 26, 2023
1 parent bebb0b7 commit 3a918da
Show file tree
Hide file tree
Showing 17 changed files with 368 additions and 34 deletions.
4 changes: 3 additions & 1 deletion ui/web-v2/apps/admin/src/assets/lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,8 @@
"feature.filter.enabled": "Enabled",
"feature.filter.hasExperiment": "Has experiment",
"feature.filter.maintainer": "Maintainer",
"feature.filter.tags": "Tags",
"feature.filter.tags.placeholder": "Select one or more tags",
"feature.flagStatus.inactive": "Inactive",
"feature.flagStatus.new": "New",
"feature.flagStatus.receivingRequests": "Receiving requests",
Expand Down Expand Up @@ -455,4 +457,4 @@
"type": "Type",
"warning": "Warning",
"yes": "Yes"
}
}
2 changes: 2 additions & 0 deletions ui/web-v2/apps/admin/src/assets/lang/ja.json
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,8 @@
"feature.filter.enabled": "有効 / 無効",
"feature.filter.hasExperiment": "エクスペリメントがある",
"feature.filter.maintainer": "管理者",
"feature.filter.tags": "タグ",
"feature.filter.tags.placeholder": "一つ以上タグを選択してください",
"feature.filter": "フィルター",
"feature.flagStatus.inactive": "休止",
"feature.flagStatus.new": "新規作成",
Expand Down
12 changes: 11 additions & 1 deletion ui/web-v2/apps/admin/src/components/CreatableSelect/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,21 @@ export interface CreatableSelectProps {
disabled?: boolean;
isSearchable?: boolean;
defaultValues?: Option[];
closeMenuOnSelect?: boolean;
className?: string;
onChange: (options: Option[]) => void;
}

export const CreatableSelect: FC<CreatableSelectProps> = memo(
({ disabled, isSearchable, className, onChange, options, defaultValues }) => {
({
disabled,
isSearchable,
className,
onChange,
options,
defaultValues,
closeMenuOnSelect,
}) => {
const textColor = '#3F3F46';
const textColorDisabled = '#6B7280';
const backgroundColor = 'white';
Expand Down Expand Up @@ -82,6 +91,7 @@ export const CreatableSelect: FC<CreatableSelectProps> = memo(
isSearchable={isSearchable}
defaultValue={defaultValues}
onChange={onChange}
closeMenuOnSelect={closeMenuOnSelect}
/>
);
}
Expand Down
13 changes: 13 additions & 0 deletions ui/web-v2/apps/admin/src/components/FeatureAddForm/index.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import { AppState } from '@/modules';
import { Tag } from '@/proto/feature/feature_pb';
import { Dialog } from '@headlessui/react';
import { FC, memo } from 'react';
import { Controller, useFormContext } from 'react-hook-form';
import { useIntl } from 'react-intl';
import { shallowEqual, useSelector } from 'react-redux';

import { messages } from '../../lang/messages';
import { selectAll as selectAllTags } from '../../modules/tags';
import { CreatableSelect, Option } from '../CreatableSelect';
import { Select } from '../Select';
import { VariationInput } from '../VariationInput';
Expand All @@ -25,6 +29,10 @@ export const FeatureAddForm: FC<FeatureAddFormProps> = memo(
setValue,
watch,
} = methods;
const tagsList = useSelector<AppState, Tag.AsObject[]>(
(state) => selectAllTags(state.tags),
shallowEqual
);

const variationsOptions = getValues('variations').map((variation, idx) => {
return {
Expand Down Expand Up @@ -137,9 +145,14 @@ export const FeatureAddForm: FC<FeatureAddFormProps> = memo(
render={({ field }) => {
return (
<CreatableSelect
options={tagsList.map((tag) => ({
label: tag.id,
value: tag.id,
}))}
onChange={(options: Option[]) => {
field.onChange(options.map((o) => o.value));
}}
closeMenuOnSelect={false}
/>
);
}}
Expand Down
75 changes: 62 additions & 13 deletions ui/web-v2/apps/admin/src/components/FeatureList/index.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,9 @@
import { Menu, Transition } from '@headlessui/react';
import {
ArchiveIcon,
DuplicateIcon,
MenuIcon,
PlusIcon,
} from '@heroicons/react/solid';
import { PlusIcon } from '@heroicons/react/solid';
import MUArchiveIcon from '@material-ui/icons/Archive';
import MUFileCopyIcon from '@material-ui/icons/FileCopy';
import MUUnarchiveIcon from '@material-ui/icons/Unarchive';
import dayjs from 'dayjs';
import React, { FC, Fragment, useState, memo, useCallback } from 'react';
import React, { FC, useState, memo, useCallback, useEffect } from 'react';
import { useIntl } from 'react-intl';
import { shallowEqual, useSelector } from 'react-redux';
import { Link } from 'react-router-dom';
Expand All @@ -26,8 +20,9 @@ import { AppState } from '../../modules';
import { selectAll as selectAllAccounts } from '../../modules/accounts';
import { selectAll as selectAllFeatures } from '../../modules/features';
import { useCurrentEnvironment, useIsEditable } from '../../modules/me';
import { selectAll as selectAllTags } from '../../modules/tags';
import { Account } from '../../proto/account/account_pb';
import { Feature } from '../../proto/feature/feature_pb';
import { Feature, Tag } from '../../proto/feature/feature_pb';
import { FeatureSearchOptions } from '../../types/feature';
import {
SORT_OPTIONS_CREATED_AT_ASC,
Expand Down Expand Up @@ -142,9 +137,14 @@ export enum FilterTypes {
HAS_EXPERIMENT = 'has_experiment',
ENABLED = 'enabled',
ARCHIVED = 'archived',
TAGS = 'tags',
}

const filterOptions: Option[] = [
{
value: FilterTypes.TAGS,
label: intl.formatMessage(messages.tags),
},
{
value: FilterTypes.MAINTAINER,
label: intl.formatMessage(messages.feature.filter.maintainer),
Expand Down Expand Up @@ -283,7 +283,8 @@ export const FeatureList: FC<FeatureListProps> = memo(
searchOptions.enabled ||
searchOptions.archived ||
searchOptions.hasExperiment ||
searchOptions.maintainerId ? (
searchOptions.maintainerId ||
searchOptions.tagIds?.length > 0 ? (
<div className="my-10 flex justify-center">
<div className="text-gray-700">
<h1 className="text-lg">
Expand Down Expand Up @@ -439,7 +440,12 @@ const FeatureSearch: FC<FeatureSearchProps> = memo(
(state) => selectAllAccounts(state.accounts),
shallowEqual
);
const tagsList = useSelector<AppState, Tag.AsObject[]>(
(state) => selectAllTags(state.tags),
shallowEqual
);
const [filterValues, setFilterValues] = useState<Option[]>([]);

const handleFilterKeyChange = useCallback(
(key: string): void => {
switch (key) {
Expand All @@ -462,9 +468,17 @@ const FeatureSearch: FC<FeatureSearchProps> = memo(
})
);
return;
case FilterTypes.TAGS:
setFilterValues(
tagsList.map((tag) => ({
value: tag.id,
label: tag.id,
}))
);
return;
}
},
[setFilterValues, accounts]
[setFilterValues, accounts, tagsList]
);

const handleUpdateOption = (
Expand Down Expand Up @@ -497,6 +511,16 @@ const FeatureSearch: FC<FeatureSearchProps> = memo(
return;
}
};
const handleMultiFilterAdd = (key: string, value: string[]): void => {
if (key === FilterTypes.TAGS) {
handleUpdateOption({
tagIds: value,
});
}
};

useEffect(() => {}, []);

return (
<div
className={classNames(
Expand All @@ -522,6 +546,7 @@ const FeatureSearch: FC<FeatureSearchProps> = memo(
values={filterValues}
onChangeKey={handleFilterKeyChange}
onAdd={handleFilterAdd}
onAddMulti={handleMultiFilterAdd}
/>
</div>
<div className="flex-grow" />
Expand Down Expand Up @@ -553,7 +578,8 @@ const FeatureSearch: FC<FeatureSearchProps> = memo(
{(options.enabled ||
options.archived ||
options.hasExperiment ||
options.maintainerId) && (
options.maintainerId ||
options.tagIds?.length > 0) && (
<div className="flex space-x-2 mt-2">
{options.enabled && (
<FilterChip
Expand Down Expand Up @@ -609,10 +635,33 @@ const FeatureSearch: FC<FeatureSearchProps> = memo(
}
/>
)}
{typeof options.tagIds === 'string' && (
<FilterChip
label={`${f(messages.feature.filter.tags)}: ${options.tagIds}`}
onRemove={() =>
handleUpdateOption({
tagIds: null,
})
}
/>
)}
{Array.isArray(options.tagIds) &&
options.tagIds.map((tagId) => (
<FilterChip
key={tagId}
label={`${f(messages.feature.filter.tags)}: ${tagId}`}
onRemove={() =>
handleUpdateOption({
tagIds: options.tagIds.filter((tId) => tId !== tagId),
})
}
/>
))}
{(options.enabled ||
options.archived ||
options.hasExperiment ||
options.maintainerId) && (
options.maintainerId ||
options.tagIds) && (
<FilterRemoveAllButtonProps onClick={onClear} />
)}
</div>
Expand Down
14 changes: 14 additions & 0 deletions ui/web-v2/apps/admin/src/components/FeatureSettingsForm/index.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import { AppState } from '@/modules';
import { Tag } from '@/proto/feature/feature_pb';
import { FC, memo } from 'react';
import { useFormContext, Controller } from 'react-hook-form';
import { useIntl } from 'react-intl';
import { shallowEqual, useSelector } from 'react-redux';

import { messages } from '../../lang/messages';
import { useIsEditable } from '../../modules/me';
import { selectAll as selectAllTags } from '../../modules/tags';
import { classNames } from '../../utils/css';
import { CreatableSelect, Option } from '../CreatableSelect';

Expand All @@ -23,6 +27,11 @@ export const FeatureSettingsForm: FC<FeatureSettingsFormProps> = memo(
} = methods;
const isValid = Object.keys(errors).length == 0;

const tagsList = useSelector<AppState, Tag.AsObject[]>(
(state) => selectAllTags(state.tags),
shallowEqual
);

return (
<div className="p-10 bg-gray-100">
<form className="w-[600px]">
Expand Down Expand Up @@ -82,6 +91,10 @@ export const FeatureSettingsForm: FC<FeatureSettingsFormProps> = memo(
render={({ field }) => {
return (
<CreatableSelect
options={tagsList.map((tag) => ({
label: tag.id,
value: tag.id,
}))}
disabled={!editable}
defaultValues={field.value.map((tag) => {
return {
Expand All @@ -92,6 +105,7 @@ export const FeatureSettingsForm: FC<FeatureSettingsFormProps> = memo(
onChange={(options: Option[]) => {
field.onChange(options.map((o) => o.value));
}}
closeMenuOnSelect={false}
/>
);
}}
Expand Down
Loading

0 comments on commit 3a918da

Please sign in to comment.