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