1
0
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:
Tymoteusz Czech 2025-04-30 09:25:45 +02:00 committed by GitHub
parent 58a01d0c47
commit 6c5fa4c8a7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 85 additions and 52 deletions

View File

@ -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>
);
};

View File

@ -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={