Skip to content

Commit

Permalink
Merge pull request #4128 from relative-ci/ui-modules-search-module-ch…
Browse files Browse the repository at this point in the history
…unks-when-there-are-more-than-10-rltv-895

UI: Module chunks - dropdown search
  • Loading branch information
vio authored Jan 9, 2024
2 parents 1ff1ee3 + 92f06a4 commit ecda2e0
Show file tree
Hide file tree
Showing 7 changed files with 112 additions and 46 deletions.
3 changes: 3 additions & 0 deletions packages/ui/src/ui/filters/filters.i18n.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
export const CHUNKS_NOT_FOUND = 'No chunks found';
export const CHUNKS_SEARCH = 'Search by chunk name';
export const CHUNKS_SEARCH_CLEAR = 'Clear search';
export const CLEAR = 'Clear all';
export const CHECK = 'Check all';
29 changes: 29 additions & 0 deletions packages/ui/src/ui/filters/filters.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,35 @@
text-transform: lowercase;
}

.filterGroupSearchWrapper {
padding-bottom: var(--space-xxxsmall);
margin-bottom: var(--space-xxxsmall);
border-bottom: 1px solid var(--color-outline);
}

.filterGroupSearchNotFound {
padding: var(--space-xxsmall) 0;
text-align: center;
font-size: var(--size-small);
color: var(--color-text-light);
}

.filterGroupSearchNotFoundClear {
outline: none;
appearance: none;
border: none;
background: none;
cursor: pointer;
white-space: nowrap;
color: var(--color-text-dark);
}

.filterGroupSearchNotFoundClear:hover,
.filterGroupSearchNotFoundClear:active,
.filterGroupSearchNotFoundClear:focus {
color: var(--color-text-dark);
}

.filterGroupItems {
max-height: calc(10 * (var(--space-small) + 2 * var(--space-xxxsmall)));
overflow: auto;
Expand Down
88 changes: 63 additions & 25 deletions packages/ui/src/ui/filters/filters.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import React, { useCallback } from 'react';
import React, { useCallback, useMemo, useState } from 'react';
import cx from 'classnames';

import type { FilterFieldsData, FilterGroupFieldData } from '../../types';
import { FlexStack } from '../../layout/flex-stack';
import { Stack } from '../../layout/stack';
import { Dropdown } from '../dropdown';
import { InputSearch } from '../input-search';
import * as I18N from './filters.i18n';
import { getGroupFiltersLabelSuffix, LABELS } from './filters.utils';
import css from './filters.module.css';
Expand Down Expand Up @@ -75,6 +77,8 @@ const FilterGroup = (props: FilterGroupProps) => {
toggleFilters,
} = props;

const [search, setSearch] = useState('');

const { label: groupLabel, children: groupItems } = data;

const areAllGroupItemsChecked = groupItems
Expand Down Expand Up @@ -108,6 +112,14 @@ const FilterGroup = (props: FilterGroupProps) => {
});
};

const filteredGroupItems = useMemo(() => {
if (!search) {
return groupItems;
}

return groupItems.filter((item) => item.label.match(new RegExp(`${search}`, 'i')));
}, [search, groupItems]);

return (
<Dropdown
className={className}
Expand All @@ -118,8 +130,32 @@ const FilterGroup = (props: FilterGroupProps) => {
{({ MenuItem, menuItemClassName }) => {
return (
<>
{groupItems.length > 10 && (
<div className={css.filterGroupSearchWrapper}>
<InputSearch
defaultValue={search}
onChange={setSearch}
placeholder={I18N.CHUNKS_SEARCH}
debounceWait={0}
/>
</div>
)}
<div className={css.filterGroupItems}>
{groupItems.map(({ key: itemKey, ...itemData }) => {
{filteredGroupItems.length === 0 && (
<Stack className={css.filterGroupSearchNotFound}>
<p>{I18N.CHUNKS_NOT_FOUND}</p>
<div>
<button
type="button"
onClick={() => setSearch('')}
className={css.filterGroupSearchNotFoundClear}
>
{I18N.CHUNKS_SEARCH_CLEAR}
</button>
</div>
</Stack>
)}
{filteredGroupItems.map(({ key: itemKey, ...itemData }) => {
const id = [groupKey, itemKey].join('.');
const getOnOnlyClick = () => getOnGroupCheck(false, { [id]: true });

Expand All @@ -138,29 +174,31 @@ const FilterGroup = (props: FilterGroupProps) => {
);
})}
</div>
<div className={css.filterGroupActions}>
{areAllGroupItemsChecked ? (
<MenuItem
id="clear-all"
as="button"
className={menuItemClassName}
type="button"
onClick={getOnGroupCheck(false)}
>
{I18N.CLEAR}
</MenuItem>
) : (
<MenuItem
id="clear-all"
as="button"
className={menuItemClassName}
type="button"
onClick={getOnGroupCheck(true)}
>
{I18N.CHECK}
</MenuItem>
)}
</div>
{filteredGroupItems.length !== 0 && (
<div className={css.filterGroupActions}>
{areAllGroupItemsChecked ? (
<MenuItem
id="clear-all"
as="button"
className={menuItemClassName}
type="button"
onClick={getOnGroupCheck(false)}
>
{I18N.CLEAR}
</MenuItem>
) : (
<MenuItem
id="clear-all"
as="button"
className={menuItemClassName}
type="button"
onClick={getOnGroupCheck(true)}
>
{I18N.CHECK}
</MenuItem>
)}
</div>
)}
</>
);
}}
Expand Down
File renamed without changes.
20 changes: 0 additions & 20 deletions packages/ui/src/ui/input/input.jsx

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ export default {
};

export const Default = () => <Input placeholder="Search" />;
export const WithSize = () => <Input size="small" placeholder="Search" />;
export const WithSize = () => <Input placeholder="Search" size="small" />;
16 changes: 16 additions & 0 deletions packages/ui/src/ui/input/input.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import React from 'react';
import cx from 'classnames';

import css from './input.module.css';

interface InputProps {
size?: 'small' | 'medium' | 'large';
}

export const Input = (props: InputProps & Omit<React.ComponentProps<'input'>, 'size'>) => {
const { className = '', size = 'medium', ...restProps } = props;

const rootClassName = cx(css.root, className, css[size]);

return <input className={rootClassName} {...restProps} />;
};

0 comments on commit ecda2e0

Please sign in to comment.