mirror of
https://github.com/Unleash/unleash.git
synced 2025-02-04 00:18:01 +01:00
feat: search features from command bar (#7378)
Now searching works in command bar 1. Currently piggybacking on the search hook, but I think it is not fast enough, and also it is using the query params as the global search. This causes some weird behaviour in UI. This probably means we will create separate endpoint for this. ![image](https://github.com/Unleash/unleash/assets/964450/a24f41ae-93d7-4ebe-a92b-c20dfe7cb666)
This commit is contained in:
parent
702ee8cb12
commit
21088b745d
@ -16,6 +16,11 @@ import { useOnClickOutside } from 'hooks/useOnClickOutside';
|
|||||||
import { useOnBlur } from 'hooks/useOnBlur';
|
import { useOnBlur } from 'hooks/useOnBlur';
|
||||||
import { RecentlyVisited } from './RecentlyVisited/RecentlyVisited';
|
import { RecentlyVisited } from './RecentlyVisited/RecentlyVisited';
|
||||||
import { useRecentlyVisited } from 'hooks/useRecentlyVisited';
|
import { useRecentlyVisited } from 'hooks/useRecentlyVisited';
|
||||||
|
import { useGlobalFeatureSearch } from '../feature/FeatureToggleList/useGlobalFeatureSearch';
|
||||||
|
import {
|
||||||
|
CommandResultGroup,
|
||||||
|
type CommandResultGroupItem,
|
||||||
|
} from './RecentlyVisited/CommandResultGroup';
|
||||||
|
|
||||||
export const CommandResultsPaper = styled(Paper)(({ theme }) => ({
|
export const CommandResultsPaper = styled(Paper)(({ theme }) => ({
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
@ -86,6 +91,7 @@ export const CommandBar = () => {
|
|||||||
const [value, setValue] = useState<string>('');
|
const [value, setValue] = useState<string>('');
|
||||||
|
|
||||||
const onSearchChange = (value: string) => {
|
const onSearchChange = (value: string) => {
|
||||||
|
setTableState({ query: value });
|
||||||
setValue(value);
|
setValue(value);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -113,6 +119,13 @@ export const CommandBar = () => {
|
|||||||
useOnClickOutside([searchContainerRef], hideSuggestions);
|
useOnClickOutside([searchContainerRef], hideSuggestions);
|
||||||
useOnBlur(searchContainerRef, hideSuggestions);
|
useOnBlur(searchContainerRef, hideSuggestions);
|
||||||
|
|
||||||
|
const { features, setTableState } = useGlobalFeatureSearch(3);
|
||||||
|
|
||||||
|
const flags: CommandResultGroupItem[] = features.map((feature) => ({
|
||||||
|
name: feature.name,
|
||||||
|
link: `/projects/${feature.project}/features/${feature.name}`,
|
||||||
|
}));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledContainer ref={searchContainerRef} active={showSuggestions}>
|
<StyledContainer ref={searchContainerRef} active={showSuggestions}>
|
||||||
<StyledSearch>
|
<StyledSearch>
|
||||||
@ -160,10 +173,14 @@ export const CommandBar = () => {
|
|||||||
</StyledSearch>
|
</StyledSearch>
|
||||||
|
|
||||||
<ConditionallyRender
|
<ConditionallyRender
|
||||||
condition={Boolean(value)}
|
condition={Boolean(value) && showSuggestions}
|
||||||
show={
|
show={
|
||||||
<CommandResultsPaper className='dropdown-outline'>
|
<CommandResultsPaper className='dropdown-outline'>
|
||||||
<div>search result</div>
|
<CommandResultGroup
|
||||||
|
groupName={'Flags'}
|
||||||
|
icon={'flag'}
|
||||||
|
items={flags}
|
||||||
|
/>
|
||||||
</CommandResultsPaper>
|
</CommandResultsPaper>
|
||||||
}
|
}
|
||||||
elseShow={
|
elseShow={
|
||||||
|
@ -0,0 +1,77 @@
|
|||||||
|
import {
|
||||||
|
Icon,
|
||||||
|
List,
|
||||||
|
ListItemButton,
|
||||||
|
ListItemIcon,
|
||||||
|
ListItemText,
|
||||||
|
styled,
|
||||||
|
Typography,
|
||||||
|
} from '@mui/material';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import type { Theme } from '@mui/material/styles/createTheme';
|
||||||
|
|
||||||
|
const listItemButtonStyle = (theme: Theme) => ({
|
||||||
|
borderRadius: theme.spacing(0.5),
|
||||||
|
borderLeft: `${theme.spacing(0.5)} solid transparent`,
|
||||||
|
'&.Mui-selected': {
|
||||||
|
borderLeft: `${theme.spacing(0.5)} solid ${theme.palette.primary.main}`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const StyledTypography = styled(Typography)(({ theme }) => ({
|
||||||
|
fontSize: theme.fontSizes.bodySize,
|
||||||
|
padding: theme.spacing(0, 3),
|
||||||
|
}));
|
||||||
|
|
||||||
|
const StyledListItemIcon = styled(ListItemIcon)(({ theme }) => ({
|
||||||
|
minWidth: theme.spacing(4),
|
||||||
|
margin: theme.spacing(0.25, 0),
|
||||||
|
}));
|
||||||
|
|
||||||
|
const StyledListItemText = styled(ListItemText)(({ theme }) => ({
|
||||||
|
margin: 0,
|
||||||
|
}));
|
||||||
|
|
||||||
|
export interface CommandResultGroupItem {
|
||||||
|
name: string;
|
||||||
|
link: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CommandResultGroupProps {
|
||||||
|
icon: string;
|
||||||
|
groupName: string;
|
||||||
|
items: CommandResultGroupItem[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export const CommandResultGroup = ({
|
||||||
|
icon,
|
||||||
|
groupName,
|
||||||
|
items,
|
||||||
|
}: CommandResultGroupProps) => {
|
||||||
|
const slicedItems = items.slice(0, 3);
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<StyledTypography color='textSecondary'>
|
||||||
|
{groupName}
|
||||||
|
</StyledTypography>
|
||||||
|
<List>
|
||||||
|
{slicedItems.map((item, index) => (
|
||||||
|
<ListItemButton
|
||||||
|
key={`command-result-group-${groupName}-${index}`}
|
||||||
|
dense={true}
|
||||||
|
component={Link}
|
||||||
|
to={item.link}
|
||||||
|
sx={listItemButtonStyle}
|
||||||
|
>
|
||||||
|
<StyledListItemIcon>
|
||||||
|
<Icon>{icon}</Icon>
|
||||||
|
</StyledListItemIcon>
|
||||||
|
<StyledListItemText>
|
||||||
|
<Typography>{item.name}</Typography>
|
||||||
|
</StyledListItemText>
|
||||||
|
</ListItemButton>
|
||||||
|
))}
|
||||||
|
</List>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
@ -15,10 +15,11 @@ import {
|
|||||||
import { usePersistentTableState } from 'hooks/usePersistentTableState';
|
import { usePersistentTableState } from 'hooks/usePersistentTableState';
|
||||||
import mapValues from 'lodash.mapvalues';
|
import mapValues from 'lodash.mapvalues';
|
||||||
|
|
||||||
export const useGlobalFeatureSearch = (storageKey = 'features-list-table') => {
|
export const useGlobalFeatureSearch = (pageLimit = DEFAULT_PAGE_LIMIT) => {
|
||||||
|
const storageKey = 'features-list-table';
|
||||||
const stateConfig = {
|
const stateConfig = {
|
||||||
offset: withDefault(NumberParam, 0),
|
offset: withDefault(NumberParam, 0),
|
||||||
limit: withDefault(NumberParam, DEFAULT_PAGE_LIMIT),
|
limit: withDefault(NumberParam, pageLimit),
|
||||||
query: StringParam,
|
query: StringParam,
|
||||||
favoritesFirst: withDefault(BooleansStringParam, true),
|
favoritesFirst: withDefault(BooleansStringParam, true),
|
||||||
sortBy: withDefault(StringParam, 'createdAt'),
|
sortBy: withDefault(StringParam, 'createdAt'),
|
||||||
|
Loading…
Reference in New Issue
Block a user