mirror of
https://github.com/Unleash/unleash.git
synced 2025-07-17 13:46:47 +02:00
feat: lifecycle filters UI (#9713)
This commit is contained in:
parent
1a85b46acc
commit
b120c97717
@ -0,0 +1,86 @@
|
|||||||
|
import { Box, Chip, styled } from '@mui/material';
|
||||||
|
import type { FC } from 'react';
|
||||||
|
import type { FilterItemParamHolder } from '../../../filter/Filters/Filters';
|
||||||
|
import type { LifecycleStage } from '../../FeatureView/FeatureOverview/FeatureLifecycle/LifecycleStage';
|
||||||
|
|
||||||
|
const StyledChip = styled(Chip, {
|
||||||
|
shouldForwardProp: (prop) => prop !== 'isActive',
|
||||||
|
})<{
|
||||||
|
isActive?: boolean;
|
||||||
|
}>(({ theme, isActive = false }) => ({
|
||||||
|
borderRadius: `${theme.shape.borderRadius}px`,
|
||||||
|
padding: theme.spacing(0.5),
|
||||||
|
fontSize: theme.typography.body2.fontSize,
|
||||||
|
height: 'auto',
|
||||||
|
...(isActive && {
|
||||||
|
backgroundColor: theme.palette.secondary.light,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
borderColor: theme.palette.primary.main,
|
||||||
|
color: theme.palette.primary.main,
|
||||||
|
}),
|
||||||
|
':focus-visible': {
|
||||||
|
outline: `1px solid ${theme.palette.primary.main}`,
|
||||||
|
borderColor: theme.palette.primary.main,
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
interface ILifecycleFiltersProps {
|
||||||
|
state: FilterItemParamHolder;
|
||||||
|
onChange: (value: FilterItemParamHolder) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Wrapper = styled(Box)(({ theme }) => ({
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
gap: theme.spacing(1),
|
||||||
|
padding: theme.spacing(2, 3, 0, 3),
|
||||||
|
}));
|
||||||
|
|
||||||
|
const lifecycleOptions: {
|
||||||
|
label: string;
|
||||||
|
value: LifecycleStage['name'] | null;
|
||||||
|
}[] = [
|
||||||
|
{ label: 'All flags', value: null },
|
||||||
|
{ label: 'Develop', value: 'pre-live' },
|
||||||
|
{ label: 'Rollout production', value: 'live' },
|
||||||
|
{ label: 'Cleanup', value: 'completed' },
|
||||||
|
{ label: 'Archived', value: 'archived' },
|
||||||
|
];
|
||||||
|
|
||||||
|
export const LifecycleFilters: FC<ILifecycleFiltersProps> = ({
|
||||||
|
state,
|
||||||
|
onChange,
|
||||||
|
}) => {
|
||||||
|
const current = state.lifecycle?.values ?? [];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Wrapper>
|
||||||
|
{lifecycleOptions.map(({ label, value }) => {
|
||||||
|
const isActive =
|
||||||
|
value === null ? !state.lifecycle : current.includes(value);
|
||||||
|
|
||||||
|
const handleClick = () =>
|
||||||
|
onChange(
|
||||||
|
value === null
|
||||||
|
? { lifecycle: null }
|
||||||
|
: {
|
||||||
|
lifecycle: {
|
||||||
|
operator: 'IS',
|
||||||
|
values: [value],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<StyledChip
|
||||||
|
key={label}
|
||||||
|
label={label}
|
||||||
|
variant='outlined'
|
||||||
|
isActive={isActive}
|
||||||
|
onClick={handleClick}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Wrapper>
|
||||||
|
);
|
||||||
|
};
|
@ -18,7 +18,6 @@ import { FavoriteIconCell } from 'component/common/Table/cells/FavoriteIconCell/
|
|||||||
import { FavoriteIconHeader } from 'component/common/Table/FavoriteIconHeader/FavoriteIconHeader';
|
import { FavoriteIconHeader } from 'component/common/Table/FavoriteIconHeader/FavoriteIconHeader';
|
||||||
import { useEnvironments } from 'hooks/api/getters/useEnvironments/useEnvironments';
|
import { useEnvironments } from 'hooks/api/getters/useEnvironments/useEnvironments';
|
||||||
import { ExportDialog } from './ExportDialog';
|
import { ExportDialog } from './ExportDialog';
|
||||||
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
|
|
||||||
import { focusable } from 'themes/themeStyles';
|
import { focusable } from 'themes/themeStyles';
|
||||||
import { FeatureEnvironmentSeenCell } from 'component/common/Table/cells/FeatureSeenCell/FeatureEnvironmentSeenCell';
|
import { FeatureEnvironmentSeenCell } from 'component/common/Table/cells/FeatureSeenCell/FeatureEnvironmentSeenCell';
|
||||||
import useToast from 'hooks/useToast';
|
import useToast from 'hooks/useToast';
|
||||||
@ -30,6 +29,8 @@ import { FeatureToggleListActions } from './FeatureToggleListActions/FeatureTogg
|
|||||||
import useLoading from 'hooks/useLoading';
|
import useLoading from 'hooks/useLoading';
|
||||||
import { usePlausibleTracker } from 'hooks/usePlausibleTracker';
|
import { usePlausibleTracker } from 'hooks/usePlausibleTracker';
|
||||||
import { useGlobalFeatureSearch } from './useGlobalFeatureSearch';
|
import { useGlobalFeatureSearch } from './useGlobalFeatureSearch';
|
||||||
|
import { LifecycleFilters } from './FeatureToggleFilters/LifecycleFilters';
|
||||||
|
import { useUiFlag } from 'hooks/useUiFlag';
|
||||||
|
|
||||||
export const featuresPlaceholder = Array(15).fill({
|
export const featuresPlaceholder = Array(15).fill({
|
||||||
name: 'Name of the feature',
|
name: 'Name of the feature',
|
||||||
@ -40,7 +41,6 @@ export const featuresPlaceholder = Array(15).fill({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const columnHelper = createColumnHelper<FeatureSearchResponseSchema>();
|
const columnHelper = createColumnHelper<FeatureSearchResponseSchema>();
|
||||||
const feedbackCategory = 'search';
|
|
||||||
|
|
||||||
export const FeatureToggleListTable: VFC = () => {
|
export const FeatureToggleListTable: VFC = () => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
@ -54,7 +54,9 @@ export const FeatureToggleListTable: VFC = () => {
|
|||||||
const [showExportDialog, setShowExportDialog] = useState(false);
|
const [showExportDialog, setShowExportDialog] = useState(false);
|
||||||
|
|
||||||
const { setToastApiError } = useToast();
|
const { setToastApiError } = useToast();
|
||||||
const { uiConfig } = useUiConfig();
|
const flagsReleaseManagementUIEnabled = useUiFlag(
|
||||||
|
'flagsReleaseManagementUI',
|
||||||
|
);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
features,
|
features,
|
||||||
@ -306,6 +308,12 @@ export const FeatureToggleListTable: VFC = () => {
|
|||||||
</PageHeader>
|
</PageHeader>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
{flagsReleaseManagementUIEnabled ? (
|
||||||
|
<LifecycleFilters
|
||||||
|
state={filterState}
|
||||||
|
onChange={setTableState}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
<FeatureToggleFilters
|
<FeatureToggleFilters
|
||||||
onChange={setTableState}
|
onChange={setTableState}
|
||||||
state={filterState}
|
state={filterState}
|
||||||
|
@ -31,6 +31,7 @@ export const useGlobalFeatureSearch = (pageLimit = DEFAULT_PAGE_LIMIT) => {
|
|||||||
segment: FilterItemParam,
|
segment: FilterItemParam,
|
||||||
createdAt: FilterItemParam,
|
createdAt: FilterItemParam,
|
||||||
type: FilterItemParam,
|
type: FilterItemParam,
|
||||||
|
lifecycle: FilterItemParam,
|
||||||
};
|
};
|
||||||
const [tableState, setTableState] = usePersistentTableState(
|
const [tableState, setTableState] = usePersistentTableState(
|
||||||
`${storageKey}`,
|
`${storageKey}`,
|
||||||
|
Loading…
Reference in New Issue
Block a user