mirror of
https://github.com/Unleash/unleash.git
synced 2025-07-12 13:48:35 +02:00
feat: update search placement on flags overview screen (#9854)
- search has a new place, closer to filters - filters are adjusted to wrap properly on small screens
This commit is contained in:
parent
58a01d0c47
commit
6c5fa4c8a7
@ -1,5 +1,5 @@
|
||||
import { Box, Chip, styled } from '@mui/material';
|
||||
import type { FC } from 'react';
|
||||
import type { FC, ReactNode } from 'react';
|
||||
import type { FilterItemParamHolder } from '../../../filter/Filters/Filters';
|
||||
import type { LifecycleStage } from '../../FeatureView/FeatureOverview/FeatureLifecycle/LifecycleStage';
|
||||
import { useLifecycleCount } from 'hooks/api/getters/useLifecycleCount/useLifecycleCount';
|
||||
@ -30,13 +30,22 @@ interface ILifecycleFiltersProps {
|
||||
state: FilterItemParamHolder;
|
||||
onChange: (value: FilterItemParamHolder) => void;
|
||||
total?: number;
|
||||
children?: ReactNode;
|
||||
}
|
||||
|
||||
const Wrapper = styled(Box)(({ theme }) => ({
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
padding: theme.spacing(1.5, 3, 0, 3),
|
||||
minHeight: theme.spacing(7),
|
||||
gap: theme.spacing(2),
|
||||
}));
|
||||
|
||||
const StyledContainer = styled(Box)(({ theme }) => ({
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
flexWrap: 'wrap',
|
||||
gap: theme.spacing(1),
|
||||
padding: theme.spacing(2, 3, 0, 3),
|
||||
}));
|
||||
|
||||
const lifecycleOptions: {
|
||||
@ -74,43 +83,49 @@ export const LifecycleFilters: FC<ILifecycleFiltersProps> = ({
|
||||
state,
|
||||
onChange,
|
||||
total,
|
||||
children,
|
||||
}) => {
|
||||
const { lifecycleCount } = useLifecycleCount();
|
||||
const current = state.lifecycle?.values ?? [];
|
||||
|
||||
return (
|
||||
<Wrapper>
|
||||
{lifecycleOptions.map(({ label, value }) => {
|
||||
const isActive =
|
||||
value === null ? !state.lifecycle : current.includes(value);
|
||||
const count = getStageCount(value, lifecycleCount);
|
||||
const dynamicLabel =
|
||||
isActive && Number.isInteger(total)
|
||||
? `${label} (${total === count ? total : `${total} of ${count}`})`
|
||||
: `${label}${count !== undefined ? ` (${count})` : ''}`;
|
||||
|
||||
const handleClick = () =>
|
||||
onChange(
|
||||
<StyledContainer>
|
||||
{lifecycleOptions.map(({ label, value }) => {
|
||||
const isActive =
|
||||
value === null
|
||||
? { lifecycle: null }
|
||||
: {
|
||||
lifecycle: {
|
||||
operator: 'IS',
|
||||
values: [value],
|
||||
},
|
||||
},
|
||||
);
|
||||
? !state.lifecycle
|
||||
: current.includes(value);
|
||||
const count = getStageCount(value, lifecycleCount);
|
||||
const dynamicLabel =
|
||||
isActive && Number.isInteger(total)
|
||||
? `${label} (${total === count ? total : `${total} of ${count}`})`
|
||||
: `${label}${count !== undefined ? ` (${count})` : ''}`;
|
||||
|
||||
return (
|
||||
<StyledChip
|
||||
key={label}
|
||||
label={dynamicLabel}
|
||||
variant='outlined'
|
||||
isActive={isActive}
|
||||
onClick={handleClick}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
const handleClick = () =>
|
||||
onChange(
|
||||
value === null
|
||||
? { lifecycle: null }
|
||||
: {
|
||||
lifecycle: {
|
||||
operator: 'IS',
|
||||
values: [value],
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
return (
|
||||
<StyledChip
|
||||
key={label}
|
||||
label={dynamicLabel}
|
||||
variant='outlined'
|
||||
isActive={isActive}
|
||||
onClick={handleClick}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</StyledContainer>
|
||||
{children}
|
||||
</Wrapper>
|
||||
);
|
||||
};
|
||||
|
@ -155,7 +155,7 @@ export const FeatureToggleListTable: FC = () => {
|
||||
onTagClick,
|
||||
onFlagTypeClick,
|
||||
),
|
||||
meta: { width: '50%' },
|
||||
meta: { width: '40%' },
|
||||
}),
|
||||
columnHelper.accessor('createdAt', {
|
||||
header: 'Created',
|
||||
@ -181,7 +181,7 @@ export const FeatureToggleListTable: FC = () => {
|
||||
data-loading
|
||||
/>
|
||||
),
|
||||
enableSorting: false, // FIXME: enable sorting by lifecycle
|
||||
enableSorting: false,
|
||||
size: 50,
|
||||
meta: { width: '1%' },
|
||||
}),
|
||||
@ -192,6 +192,7 @@ export const FeatureToggleListTable: FC = () => {
|
||||
<StatusCell {...original} />
|
||||
),
|
||||
enableSorting: false,
|
||||
size: 350,
|
||||
}),
|
||||
columnHelper.accessor('project', {
|
||||
header: 'Project',
|
||||
@ -402,23 +403,19 @@ export const FeatureToggleListTable: FC = () => {
|
||||
}
|
||||
actions={
|
||||
<>
|
||||
<ConditionallyRender
|
||||
condition={!isSmallScreen}
|
||||
show={
|
||||
<>
|
||||
<Search
|
||||
placeholder='Search'
|
||||
expandable
|
||||
initialValue={
|
||||
tableState.query || ''
|
||||
}
|
||||
onChange={setSearchValue}
|
||||
id='globalFeatureFlags'
|
||||
/>
|
||||
<PageHeader.Divider />
|
||||
</>
|
||||
}
|
||||
/>
|
||||
{!flagsReleaseManagementUIEnabled &&
|
||||
!isSmallScreen ? (
|
||||
<>
|
||||
<Search
|
||||
placeholder='Search'
|
||||
expandable
|
||||
initialValue={tableState.query || ''}
|
||||
onChange={setSearchValue}
|
||||
id='globalFeatureFlags'
|
||||
/>
|
||||
<PageHeader.Divider />
|
||||
</>
|
||||
) : null}
|
||||
<Link
|
||||
component={RouterLink}
|
||||
to='/archive'
|
||||
@ -449,7 +446,9 @@ export const FeatureToggleListTable: FC = () => {
|
||||
}
|
||||
>
|
||||
<ConditionallyRender
|
||||
condition={isSmallScreen}
|
||||
condition={
|
||||
isSmallScreen && !flagsReleaseManagementUIEnabled
|
||||
}
|
||||
show={
|
||||
<Search
|
||||
initialValue={tableState.query || ''}
|
||||
@ -466,17 +465,36 @@ export const FeatureToggleListTable: FC = () => {
|
||||
state={filterState}
|
||||
onChange={setTableState}
|
||||
total={loading ? undefined : total}
|
||||
/>
|
||||
>
|
||||
{!isSmallScreen ? (
|
||||
<Search
|
||||
placeholder='Search'
|
||||
initialValue={tableState.query || ''}
|
||||
onChange={setSearchValue}
|
||||
id='globalFeatureFlags'
|
||||
/>
|
||||
) : null}
|
||||
</LifecycleFilters>
|
||||
) : null}
|
||||
<FeatureToggleFilters
|
||||
onChange={setTableState}
|
||||
state={filterState}
|
||||
/>
|
||||
{isSmallScreen ? (
|
||||
<Box sx={(theme) => ({ padding: theme.spacing(0, 3, 3) })}>
|
||||
<Search
|
||||
initialValue={tableState.query || ''}
|
||||
onChange={setSearchValue}
|
||||
id='globalFeatureFlags'
|
||||
/>
|
||||
</Box>
|
||||
) : null}
|
||||
<SearchHighlightProvider value={tableState.query || ''}>
|
||||
<div ref={bodyLoadingRef}>
|
||||
<PaginatedTable tableInstance={table} totalItems={total} />
|
||||
</div>
|
||||
</SearchHighlightProvider>
|
||||
|
||||
<ConditionallyRender
|
||||
condition={rows.length === 0}
|
||||
show={
|
||||
|
Loading…
Reference in New Issue
Block a user