mirror of
				https://github.com/Unleash/unleash.git
				synced 2025-10-27 11:02:16 +01:00 
			
		
		
		
	feat: improve flag filters on project page (#10705)
This commit is contained in:
		
							parent
							
								
									c12aca72db
								
							
						
					
					
						commit
						9d996f14d9
					
				@ -37,7 +37,6 @@ interface ILifecycleFiltersBaseProps {
 | 
				
			|||||||
const Wrapper = styled(Box)(({ theme }) => ({
 | 
					const Wrapper = styled(Box)(({ theme }) => ({
 | 
				
			||||||
    display: 'flex',
 | 
					    display: 'flex',
 | 
				
			||||||
    justifyContent: 'space-between',
 | 
					    justifyContent: 'space-between',
 | 
				
			||||||
    minHeight: theme.spacing(7),
 | 
					 | 
				
			||||||
    gap: theme.spacing(2),
 | 
					    gap: theme.spacing(2),
 | 
				
			||||||
}));
 | 
					}));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -20,7 +20,7 @@ import {
 | 
				
			|||||||
import { useChangeRequestsEnabled } from 'hooks/useChangeRequestsEnabled';
 | 
					import { useChangeRequestsEnabled } from 'hooks/useChangeRequestsEnabled';
 | 
				
			||||||
import { useFeatureToggleSwitch } from '../ProjectFeatureToggles/FeatureToggleSwitch/useFeatureToggleSwitch.tsx';
 | 
					import { useFeatureToggleSwitch } from '../ProjectFeatureToggles/FeatureToggleSwitch/useFeatureToggleSwitch.tsx';
 | 
				
			||||||
import useLoading from 'hooks/useLoading';
 | 
					import useLoading from 'hooks/useLoading';
 | 
				
			||||||
import { ProjectFeatureTogglesHeader } from './ProjectFeatureTogglesHeader/ProjectFeatureTogglesHeader.tsx';
 | 
					import { ProjectFeatureTogglesHeader as LegacyProjectFeatureTogglesHeader } from './ProjectFeatureTogglesHeader/LegacyProjectFeatureTogglesHeader.tsx';
 | 
				
			||||||
import { createColumnHelper, useReactTable } from '@tanstack/react-table';
 | 
					import { createColumnHelper, useReactTable } from '@tanstack/react-table';
 | 
				
			||||||
import { withTableState } from 'utils/withTableState';
 | 
					import { withTableState } from 'utils/withTableState';
 | 
				
			||||||
import type { FeatureSearchResponseSchema } from 'openapi';
 | 
					import type { FeatureSearchResponseSchema } from 'openapi';
 | 
				
			||||||
@ -41,7 +41,7 @@ import {
 | 
				
			|||||||
    useProjectFeatureSearchActions,
 | 
					    useProjectFeatureSearchActions,
 | 
				
			||||||
} from './useProjectFeatureSearch.ts';
 | 
					} from './useProjectFeatureSearch.ts';
 | 
				
			||||||
import { AvatarCell } from './AvatarCell.tsx';
 | 
					import { AvatarCell } from './AvatarCell.tsx';
 | 
				
			||||||
import { styled } from '@mui/material';
 | 
					import { styled, useMediaQuery, useTheme } from '@mui/material';
 | 
				
			||||||
import useProjectOverview from 'hooks/api/getters/useProjectOverview/useProjectOverview';
 | 
					import useProjectOverview from 'hooks/api/getters/useProjectOverview/useProjectOverview';
 | 
				
			||||||
import { ConnectSdkDialog } from '../../../onboarding/dialog/ConnectSdkDialog.tsx';
 | 
					import { ConnectSdkDialog } from '../../../onboarding/dialog/ConnectSdkDialog.tsx';
 | 
				
			||||||
import { ProjectOnboarding } from '../../../onboarding/flow/ProjectOnboarding.tsx';
 | 
					import { ProjectOnboarding } from '../../../onboarding/flow/ProjectOnboarding.tsx';
 | 
				
			||||||
@ -57,6 +57,9 @@ import { IMPORT_BUTTON } from 'utils/testIds';
 | 
				
			|||||||
import { ProjectCleanupReminder } from './ProjectCleanupReminder/ProjectCleanupReminder.tsx';
 | 
					import { ProjectCleanupReminder } from './ProjectCleanupReminder/ProjectCleanupReminder.tsx';
 | 
				
			||||||
import { formatEnvironmentColumnId } from './formatEnvironmentColumnId.ts';
 | 
					import { formatEnvironmentColumnId } from './formatEnvironmentColumnId.ts';
 | 
				
			||||||
import { ProjectFeaturesColumnsMenu } from './ProjectFeaturesColumnsMenu/ProjectFeaturesColumnsMenu.tsx';
 | 
					import { ProjectFeaturesColumnsMenu } from './ProjectFeaturesColumnsMenu/ProjectFeaturesColumnsMenu.tsx';
 | 
				
			||||||
 | 
					import { useUiFlag } from 'hooks/useUiFlag.ts';
 | 
				
			||||||
 | 
					import { ProjectFeatureTogglesHeader } from './ProjectFeatureTogglesHeader/ProjectFeatureTogglesHeader.tsx';
 | 
				
			||||||
 | 
					import { ProjectFlagsSearch } from './ProjectFlagsSearch/ProjectFlagsSearch.tsx';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type ProjectFeatureTogglesProps = {
 | 
					type ProjectFeatureTogglesProps = {
 | 
				
			||||||
    environments: string[];
 | 
					    environments: string[];
 | 
				
			||||||
@ -71,12 +74,27 @@ const Container = styled('div')(({ theme }) => ({
 | 
				
			|||||||
    gap: theme.spacing(2),
 | 
					    gap: theme.spacing(2),
 | 
				
			||||||
}));
 | 
					}));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const FilterRow = styled('div')(({ theme }) => ({
 | 
					const LegacyFilterRow = styled('div')(({ theme }) => ({
 | 
				
			||||||
    display: 'flex',
 | 
					    display: 'flex',
 | 
				
			||||||
    flexFlow: 'row wrap',
 | 
					    flexFlow: 'row wrap',
 | 
				
			||||||
    justifyContent: 'space-between',
 | 
					    justifyContent: 'space-between',
 | 
				
			||||||
}));
 | 
					}));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const FiltersContainer = styled('div')(({ theme }) => ({
 | 
				
			||||||
 | 
					    display: 'flex',
 | 
				
			||||||
 | 
					    flexDirection: 'column',
 | 
				
			||||||
 | 
					    gap: theme.spacing(1),
 | 
				
			||||||
 | 
					    padding: theme.spacing(2, 3, 2),
 | 
				
			||||||
 | 
					    [theme.breakpoints.down('md')]: {
 | 
				
			||||||
 | 
					        padding: theme.spacing(2, 2),
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					}));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const FilterRow = styled('div')({
 | 
				
			||||||
 | 
					    display: 'flex',
 | 
				
			||||||
 | 
					    alignItems: 'center',
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const ButtonGroup = styled('div')(({ theme }) => ({
 | 
					const ButtonGroup = styled('div')(({ theme }) => ({
 | 
				
			||||||
    display: 'flex',
 | 
					    display: 'flex',
 | 
				
			||||||
    gap: theme.spacing(1),
 | 
					    gap: theme.spacing(1),
 | 
				
			||||||
@ -91,6 +109,9 @@ export const ProjectFeatureToggles = ({
 | 
				
			|||||||
    const { project } = useProjectOverview(projectId);
 | 
					    const { project } = useProjectOverview(projectId);
 | 
				
			||||||
    const [connectSdkOpen, setConnectSdkOpen] = useState(false);
 | 
					    const [connectSdkOpen, setConnectSdkOpen] = useState(false);
 | 
				
			||||||
    const [modalOpen, setModalOpen] = useState(false);
 | 
					    const [modalOpen, setModalOpen] = useState(false);
 | 
				
			||||||
 | 
					    const flagsUiFilterRefactorEnabled = useUiFlag('flagsUiFilterRefactor');
 | 
				
			||||||
 | 
					    const theme = useTheme();
 | 
				
			||||||
 | 
					    const isSmallScreen = useMediaQuery(theme.breakpoints.down('md'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const {
 | 
					    const {
 | 
				
			||||||
        features,
 | 
					        features,
 | 
				
			||||||
@ -500,25 +521,32 @@ export const ProjectFeatureToggles = ({
 | 
				
			|||||||
            ) : null}
 | 
					            ) : null}
 | 
				
			||||||
            <PageContent
 | 
					            <PageContent
 | 
				
			||||||
                disableLoading
 | 
					                disableLoading
 | 
				
			||||||
                disablePadding
 | 
					 | 
				
			||||||
                header={
 | 
					                header={
 | 
				
			||||||
                    <ProjectFeatureTogglesHeader
 | 
					                    flagsUiFilterRefactorEnabled ? (
 | 
				
			||||||
                        isLoading={initialLoad}
 | 
					                        <ProjectFeatureTogglesHeader
 | 
				
			||||||
                        totalItems={total}
 | 
					                            isLoading={initialLoad}
 | 
				
			||||||
                        searchQuery={tableState.query || ''}
 | 
					                            totalItems={total}
 | 
				
			||||||
                        onChangeSearchQuery={(query) => {
 | 
					                            environmentsToExport={environments}
 | 
				
			||||||
                            setTableState({ query });
 | 
					                        />
 | 
				
			||||||
                        }}
 | 
					                    ) : (
 | 
				
			||||||
                        dataToExport={data}
 | 
					                        <LegacyProjectFeatureTogglesHeader
 | 
				
			||||||
                        environmentsToExport={environments}
 | 
					                            isLoading={initialLoad}
 | 
				
			||||||
                        actions={
 | 
					                            totalItems={total}
 | 
				
			||||||
                            <ProjectFeaturesColumnsMenu
 | 
					                            searchQuery={tableState.query || ''}
 | 
				
			||||||
                                columnVisibility={columnVisibility}
 | 
					                            onChangeSearchQuery={(query) => {
 | 
				
			||||||
                                environments={environments}
 | 
					                                setTableState({ query });
 | 
				
			||||||
                                onToggle={onToggleColumnVisibility}
 | 
					                            }}
 | 
				
			||||||
                            />
 | 
					                            dataToExport={data}
 | 
				
			||||||
                        }
 | 
					                            environmentsToExport={environments}
 | 
				
			||||||
                    />
 | 
					                            actions={
 | 
				
			||||||
 | 
					                                <ProjectFeaturesColumnsMenu
 | 
				
			||||||
 | 
					                                    columnVisibility={columnVisibility}
 | 
				
			||||||
 | 
					                                    environments={environments}
 | 
				
			||||||
 | 
					                                    onToggle={onToggleColumnVisibility}
 | 
				
			||||||
 | 
					                                />
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        />
 | 
				
			||||||
 | 
					                    )
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                bodyClass='noop'
 | 
					                bodyClass='noop'
 | 
				
			||||||
                style={{ cursor: 'inherit' }}
 | 
					                style={{ cursor: 'inherit' }}
 | 
				
			||||||
@ -528,31 +556,74 @@ export const ProjectFeatureToggles = ({
 | 
				
			|||||||
                    aria-busy={isPlaceholder}
 | 
					                    aria-busy={isPlaceholder}
 | 
				
			||||||
                    aria-live='polite'
 | 
					                    aria-live='polite'
 | 
				
			||||||
                >
 | 
					                >
 | 
				
			||||||
                    <FilterRow>
 | 
					                    {flagsUiFilterRefactorEnabled ? (
 | 
				
			||||||
                        <ProjectOverviewFilters
 | 
					                        <FiltersContainer>
 | 
				
			||||||
                            project={projectId}
 | 
					                            <FilterRow>
 | 
				
			||||||
                            onChange={setTableState}
 | 
					                                <ProjectLifecycleFilters
 | 
				
			||||||
                            state={filterState}
 | 
					                                    projectId={projectId}
 | 
				
			||||||
                        />
 | 
					                                    state={filterState}
 | 
				
			||||||
                        <ProjectLifecycleFilters
 | 
					                                    onChange={setTableState}
 | 
				
			||||||
                            projectId={projectId}
 | 
					                                    total={loading ? undefined : total}
 | 
				
			||||||
                            state={filterState}
 | 
					                                />
 | 
				
			||||||
                            onChange={setTableState}
 | 
					                                {isSmallScreen ? null : (
 | 
				
			||||||
                            total={loading ? undefined : total}
 | 
					                                    <ProjectFlagsSearch
 | 
				
			||||||
                        />
 | 
					                                        searchQuery={tableState.query || ''}
 | 
				
			||||||
                        <ButtonGroup>
 | 
					                                        onChangeSearchQuery={(query) => {
 | 
				
			||||||
                            <PermissionIconButton
 | 
					                                            setTableState({ query });
 | 
				
			||||||
                                permission={UPDATE_FEATURE}
 | 
					                                        }}
 | 
				
			||||||
 | 
					                                        isLoading={loading}
 | 
				
			||||||
 | 
					                                    />
 | 
				
			||||||
 | 
					                                )}
 | 
				
			||||||
 | 
					                                <ProjectFeaturesColumnsMenu
 | 
				
			||||||
 | 
					                                    columnVisibility={columnVisibility}
 | 
				
			||||||
 | 
					                                    environments={environments}
 | 
				
			||||||
 | 
					                                    onToggle={onToggleColumnVisibility}
 | 
				
			||||||
 | 
					                                />
 | 
				
			||||||
 | 
					                            </FilterRow>
 | 
				
			||||||
 | 
					                            <FilterRow>
 | 
				
			||||||
 | 
					                                <ProjectOverviewFilters
 | 
				
			||||||
 | 
					                                    project={projectId}
 | 
				
			||||||
 | 
					                                    onChange={setTableState}
 | 
				
			||||||
 | 
					                                    state={filterState}
 | 
				
			||||||
 | 
					                                />
 | 
				
			||||||
 | 
					                            </FilterRow>
 | 
				
			||||||
 | 
					                            {isSmallScreen ? (
 | 
				
			||||||
 | 
					                                <ProjectFlagsSearch
 | 
				
			||||||
 | 
					                                    searchQuery={tableState.query || ''}
 | 
				
			||||||
 | 
					                                    onChangeSearchQuery={(query) => {
 | 
				
			||||||
 | 
					                                        setTableState({ query });
 | 
				
			||||||
 | 
					                                    }}
 | 
				
			||||||
 | 
					                                    isLoading={loading}
 | 
				
			||||||
 | 
					                                />
 | 
				
			||||||
 | 
					                            ) : null}
 | 
				
			||||||
 | 
					                        </FiltersContainer>
 | 
				
			||||||
 | 
					                    ) : (
 | 
				
			||||||
 | 
					                        <LegacyFilterRow>
 | 
				
			||||||
 | 
					                            <ProjectOverviewFilters
 | 
				
			||||||
 | 
					                                project={projectId}
 | 
				
			||||||
 | 
					                                onChange={setTableState}
 | 
				
			||||||
 | 
					                                state={filterState}
 | 
				
			||||||
 | 
					                            />
 | 
				
			||||||
 | 
					                            <ProjectLifecycleFilters
 | 
				
			||||||
                                projectId={projectId}
 | 
					                                projectId={projectId}
 | 
				
			||||||
                                onClick={() => setModalOpen(true)}
 | 
					                                state={filterState}
 | 
				
			||||||
                                tooltipProps={{ title: 'Import' }}
 | 
					                                onChange={setTableState}
 | 
				
			||||||
                                data-testid={IMPORT_BUTTON}
 | 
					                                total={loading ? undefined : total}
 | 
				
			||||||
                                data-loading-project
 | 
					                            />
 | 
				
			||||||
                            >
 | 
					                            <ButtonGroup>
 | 
				
			||||||
                                <ImportSvg />
 | 
					                                <PermissionIconButton
 | 
				
			||||||
                            </PermissionIconButton>
 | 
					                                    permission={UPDATE_FEATURE}
 | 
				
			||||||
                        </ButtonGroup>
 | 
					                                    projectId={projectId}
 | 
				
			||||||
                    </FilterRow>
 | 
					                                    onClick={() => setModalOpen(true)}
 | 
				
			||||||
 | 
					                                    tooltipProps={{ title: 'Import' }}
 | 
				
			||||||
 | 
					                                    data-testid={IMPORT_BUTTON}
 | 
				
			||||||
 | 
					                                    data-loading-project
 | 
				
			||||||
 | 
					                                >
 | 
				
			||||||
 | 
					                                    <ImportSvg />
 | 
				
			||||||
 | 
					                                </PermissionIconButton>
 | 
				
			||||||
 | 
					                            </ButtonGroup>
 | 
				
			||||||
 | 
					                        </LegacyFilterRow>
 | 
				
			||||||
 | 
					                    )}
 | 
				
			||||||
                    <SearchHighlightProvider value={tableState.query || ''}>
 | 
					                    <SearchHighlightProvider value={tableState.query || ''}>
 | 
				
			||||||
                        <PaginatedTable
 | 
					                        <PaginatedTable
 | 
				
			||||||
                            tableInstance={table}
 | 
					                            tableInstance={table}
 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,165 @@
 | 
				
			|||||||
 | 
					import { type ReactNode, type FC, useState } from 'react';
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					    Box,
 | 
				
			||||||
 | 
					    Button,
 | 
				
			||||||
 | 
					    IconButton,
 | 
				
			||||||
 | 
					    Tooltip,
 | 
				
			||||||
 | 
					    useMediaQuery,
 | 
				
			||||||
 | 
					    useTheme,
 | 
				
			||||||
 | 
					} from '@mui/material';
 | 
				
			||||||
 | 
					import useLoading from 'hooks/useLoading';
 | 
				
			||||||
 | 
					import { PageHeader } from 'component/common/PageHeader/PageHeader';
 | 
				
			||||||
 | 
					import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
 | 
				
			||||||
 | 
					import { Search } from 'component/common/Search/Search';
 | 
				
			||||||
 | 
					import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
 | 
				
			||||||
 | 
					import { ExportDialog } from 'component/feature/FeatureToggleList/ExportDialog';
 | 
				
			||||||
 | 
					import type { FeatureSchema } from 'openapi';
 | 
				
			||||||
 | 
					import { usePlausibleTracker } from 'hooks/usePlausibleTracker';
 | 
				
			||||||
 | 
					import ReviewsOutlined from '@mui/icons-material/ReviewsOutlined';
 | 
				
			||||||
 | 
					import { useFeedback } from 'component/feedbackNew/useFeedback';
 | 
				
			||||||
 | 
					import IosShare from '@mui/icons-material/IosShare';
 | 
				
			||||||
 | 
					import { FlagCreationButton } from './FlagCreationButton/FlagCreationButton.tsx';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface IProjectFeatureTogglesHeaderProps {
 | 
				
			||||||
 | 
					    isLoading?: boolean;
 | 
				
			||||||
 | 
					    totalItems?: number;
 | 
				
			||||||
 | 
					    searchQuery?: string;
 | 
				
			||||||
 | 
					    onChangeSearchQuery?: (query: string) => void;
 | 
				
			||||||
 | 
					    dataToExport?: Pick<FeatureSchema, 'name'>[];
 | 
				
			||||||
 | 
					    environmentsToExport?: string[];
 | 
				
			||||||
 | 
					    actions?: ReactNode;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @deprecated remove with `flagsUiFilterRefactor` flag
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export const ProjectFeatureTogglesHeader: FC<
 | 
				
			||||||
 | 
					    IProjectFeatureTogglesHeaderProps
 | 
				
			||||||
 | 
					> = ({
 | 
				
			||||||
 | 
					    isLoading,
 | 
				
			||||||
 | 
					    totalItems,
 | 
				
			||||||
 | 
					    searchQuery,
 | 
				
			||||||
 | 
					    onChangeSearchQuery,
 | 
				
			||||||
 | 
					    environmentsToExport,
 | 
				
			||||||
 | 
					    actions,
 | 
				
			||||||
 | 
					}) => {
 | 
				
			||||||
 | 
					    const projectId = useRequiredPathParam('projectId');
 | 
				
			||||||
 | 
					    const headerLoadingRef = useLoading(isLoading || false);
 | 
				
			||||||
 | 
					    const [showTitle, setShowTitle] = useState(true);
 | 
				
			||||||
 | 
					    const theme = useTheme();
 | 
				
			||||||
 | 
					    const isSmallScreen = useMediaQuery(theme.breakpoints.down('md'));
 | 
				
			||||||
 | 
					    const [showExportDialog, setShowExportDialog] = useState(false);
 | 
				
			||||||
 | 
					    const { trackEvent } = usePlausibleTracker();
 | 
				
			||||||
 | 
					    const projectOverviewRefactorFeedback = false;
 | 
				
			||||||
 | 
					    const { openFeedback } = useFeedback('newProjectOverview', 'automatic');
 | 
				
			||||||
 | 
					    const handleSearch = (query: string) => {
 | 
				
			||||||
 | 
					        onChangeSearchQuery?.(query);
 | 
				
			||||||
 | 
					        trackEvent('search-bar', {
 | 
				
			||||||
 | 
					            props: {
 | 
				
			||||||
 | 
					                screen: 'project',
 | 
				
			||||||
 | 
					                length: query.length,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const createFeedbackContext = () => {
 | 
				
			||||||
 | 
					        openFeedback({
 | 
				
			||||||
 | 
					            title: 'How easy was it to work with the project overview in Unleash?',
 | 
				
			||||||
 | 
					            positiveLabel:
 | 
				
			||||||
 | 
					                'What do you like most about the updated project overview?',
 | 
				
			||||||
 | 
					            areasForImprovementsLabel:
 | 
				
			||||||
 | 
					                'What improvements are needed in the project overview?',
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					        <Box ref={headerLoadingRef} aria-busy={isLoading} aria-live='polite'>
 | 
				
			||||||
 | 
					            <PageHeader
 | 
				
			||||||
 | 
					                titleElement={
 | 
				
			||||||
 | 
					                    showTitle
 | 
				
			||||||
 | 
					                        ? `Feature flags ${
 | 
				
			||||||
 | 
					                              totalItems !== undefined ? `(${totalItems})` : ''
 | 
				
			||||||
 | 
					                          }`
 | 
				
			||||||
 | 
					                        : null
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                actions={
 | 
				
			||||||
 | 
					                    <>
 | 
				
			||||||
 | 
					                        <ConditionallyRender
 | 
				
			||||||
 | 
					                            condition={!isSmallScreen}
 | 
				
			||||||
 | 
					                            show={
 | 
				
			||||||
 | 
					                                <Search
 | 
				
			||||||
 | 
					                                    data-loading
 | 
				
			||||||
 | 
					                                    placeholder='Search and Filter'
 | 
				
			||||||
 | 
					                                    expandable
 | 
				
			||||||
 | 
					                                    initialValue={searchQuery || ''}
 | 
				
			||||||
 | 
					                                    onChange={handleSearch}
 | 
				
			||||||
 | 
					                                    onFocus={() => setShowTitle(false)}
 | 
				
			||||||
 | 
					                                    onBlur={() => setShowTitle(true)}
 | 
				
			||||||
 | 
					                                    hasFilters
 | 
				
			||||||
 | 
					                                    id='projectFeatureFlags'
 | 
				
			||||||
 | 
					                                />
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        />
 | 
				
			||||||
 | 
					                        {actions}
 | 
				
			||||||
 | 
					                        <PageHeader.Divider sx={{ marginLeft: 0 }} />
 | 
				
			||||||
 | 
					                        <Tooltip title='Export all project flags' arrow>
 | 
				
			||||||
 | 
					                            <IconButton
 | 
				
			||||||
 | 
					                                data-loading
 | 
				
			||||||
 | 
					                                onClick={() => setShowExportDialog(true)}
 | 
				
			||||||
 | 
					                                sx={(theme) => ({
 | 
				
			||||||
 | 
					                                    marginRight: theme.spacing(2),
 | 
				
			||||||
 | 
					                                })}
 | 
				
			||||||
 | 
					                            >
 | 
				
			||||||
 | 
					                                <IosShare />
 | 
				
			||||||
 | 
					                            </IconButton>
 | 
				
			||||||
 | 
					                        </Tooltip>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        <ConditionallyRender
 | 
				
			||||||
 | 
					                            condition={!isLoading}
 | 
				
			||||||
 | 
					                            show={
 | 
				
			||||||
 | 
					                                <ExportDialog
 | 
				
			||||||
 | 
					                                    showExportDialog={showExportDialog}
 | 
				
			||||||
 | 
					                                    project={projectId}
 | 
				
			||||||
 | 
					                                    data={[]}
 | 
				
			||||||
 | 
					                                    onClose={() => setShowExportDialog(false)}
 | 
				
			||||||
 | 
					                                    environments={environmentsToExport || []}
 | 
				
			||||||
 | 
					                                />
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        {/* FIXME: remove */}
 | 
				
			||||||
 | 
					                        <ConditionallyRender
 | 
				
			||||||
 | 
					                            condition={
 | 
				
			||||||
 | 
					                                projectOverviewRefactorFeedback &&
 | 
				
			||||||
 | 
					                                !isSmallScreen
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                            show={
 | 
				
			||||||
 | 
					                                <Button
 | 
				
			||||||
 | 
					                                    startIcon={<ReviewsOutlined />}
 | 
				
			||||||
 | 
					                                    onClick={createFeedbackContext}
 | 
				
			||||||
 | 
					                                    variant='outlined'
 | 
				
			||||||
 | 
					                                    data-loading
 | 
				
			||||||
 | 
					                                >
 | 
				
			||||||
 | 
					                                    Provide feedback
 | 
				
			||||||
 | 
					                                </Button>
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        />
 | 
				
			||||||
 | 
					                        <FlagCreationButton isLoading={isLoading} />
 | 
				
			||||||
 | 
					                    </>
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					                <ConditionallyRender
 | 
				
			||||||
 | 
					                    condition={isSmallScreen}
 | 
				
			||||||
 | 
					                    show={
 | 
				
			||||||
 | 
					                        <Search
 | 
				
			||||||
 | 
					                            initialValue={searchQuery || ''}
 | 
				
			||||||
 | 
					                            onChange={handleSearch}
 | 
				
			||||||
 | 
					                            hasFilters
 | 
				
			||||||
 | 
					                            id='projectFeatureFlags'
 | 
				
			||||||
 | 
					                        />
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                />
 | 
				
			||||||
 | 
					            </PageHeader>
 | 
				
			||||||
 | 
					        </Box>
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -1,136 +1,59 @@
 | 
				
			|||||||
import { type ReactNode, type FC, useState } from 'react';
 | 
					import { type FC, useState } from 'react';
 | 
				
			||||||
import {
 | 
					import { Box, IconButton, Tooltip } from '@mui/material';
 | 
				
			||||||
    Box,
 | 
					 | 
				
			||||||
    IconButton,
 | 
					 | 
				
			||||||
    Tooltip,
 | 
					 | 
				
			||||||
    useMediaQuery,
 | 
					 | 
				
			||||||
    useTheme,
 | 
					 | 
				
			||||||
} from '@mui/material';
 | 
					 | 
				
			||||||
import useLoading from 'hooks/useLoading';
 | 
					import useLoading from 'hooks/useLoading';
 | 
				
			||||||
import { PageHeader } from 'component/common/PageHeader/PageHeader';
 | 
					import { PageHeader } from 'component/common/PageHeader/PageHeader';
 | 
				
			||||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
 | 
					 | 
				
			||||||
import { Search } from 'component/common/Search/Search';
 | 
					 | 
				
			||||||
import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
 | 
					import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
 | 
				
			||||||
import { ExportDialog } from 'component/feature/FeatureToggleList/ExportDialog';
 | 
					import { ExportDialog } from 'component/feature/FeatureToggleList/ExportDialog';
 | 
				
			||||||
import type { FeatureSchema } from 'openapi';
 | 
					 | 
				
			||||||
import { usePlausibleTracker } from 'hooks/usePlausibleTracker';
 | 
					 | 
				
			||||||
import IosShare from '@mui/icons-material/IosShare';
 | 
					import IosShare from '@mui/icons-material/IosShare';
 | 
				
			||||||
import { FlagCreationButton } from './FlagCreationButton/FlagCreationButton.tsx';
 | 
					import { FlagCreationButton } from './FlagCreationButton/FlagCreationButton.tsx';
 | 
				
			||||||
 | 
					import { ImportButton } from './ImportButton/ImportButton.tsx';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface IProjectFeatureTogglesHeaderProps {
 | 
					type ProjectFeatureTogglesHeaderProps = {
 | 
				
			||||||
    isLoading?: boolean;
 | 
					    isLoading?: boolean;
 | 
				
			||||||
    totalItems?: number;
 | 
					    totalItems?: number;
 | 
				
			||||||
    searchQuery?: string;
 | 
					 | 
				
			||||||
    onChangeSearchQuery?: (query: string) => void;
 | 
					 | 
				
			||||||
    dataToExport?: Pick<FeatureSchema, 'name'>[];
 | 
					 | 
				
			||||||
    environmentsToExport?: string[];
 | 
					    environmentsToExport?: string[];
 | 
				
			||||||
    actions?: ReactNode;
 | 
					};
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const ProjectFeatureTogglesHeader: FC<
 | 
					export const ProjectFeatureTogglesHeader: FC<
 | 
				
			||||||
    IProjectFeatureTogglesHeaderProps
 | 
					    ProjectFeatureTogglesHeaderProps
 | 
				
			||||||
> = ({
 | 
					> = ({ isLoading, totalItems, environmentsToExport }) => {
 | 
				
			||||||
    isLoading,
 | 
					 | 
				
			||||||
    totalItems,
 | 
					 | 
				
			||||||
    searchQuery,
 | 
					 | 
				
			||||||
    onChangeSearchQuery,
 | 
					 | 
				
			||||||
    environmentsToExport,
 | 
					 | 
				
			||||||
    actions,
 | 
					 | 
				
			||||||
}) => {
 | 
					 | 
				
			||||||
    const projectId = useRequiredPathParam('projectId');
 | 
					    const projectId = useRequiredPathParam('projectId');
 | 
				
			||||||
    const headerLoadingRef = useLoading(isLoading || false);
 | 
					    const headerLoadingRef = useLoading(isLoading || false);
 | 
				
			||||||
    const [showTitle, setShowTitle] = useState(true);
 | 
					 | 
				
			||||||
    const theme = useTheme();
 | 
					 | 
				
			||||||
    const isSmallScreen = useMediaQuery(theme.breakpoints.down('md'));
 | 
					 | 
				
			||||||
    const [showExportDialog, setShowExportDialog] = useState(false);
 | 
					    const [showExportDialog, setShowExportDialog] = useState(false);
 | 
				
			||||||
    const { trackEvent } = usePlausibleTracker();
 | 
					 | 
				
			||||||
    const handleSearch = (query: string) => {
 | 
					 | 
				
			||||||
        onChangeSearchQuery?.(query);
 | 
					 | 
				
			||||||
        trackEvent('search-bar', {
 | 
					 | 
				
			||||||
            props: {
 | 
					 | 
				
			||||||
                screen: 'project',
 | 
					 | 
				
			||||||
                length: query.length,
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
        <Box
 | 
					        <Box ref={headerLoadingRef} aria-busy={isLoading} aria-live='polite'>
 | 
				
			||||||
            ref={headerLoadingRef}
 | 
					 | 
				
			||||||
            aria-busy={isLoading}
 | 
					 | 
				
			||||||
            aria-live='polite'
 | 
					 | 
				
			||||||
            sx={(theme) => ({
 | 
					 | 
				
			||||||
                padding: `${theme.spacing(2.5)} ${theme.spacing(3.125)}`,
 | 
					 | 
				
			||||||
            })}
 | 
					 | 
				
			||||||
        >
 | 
					 | 
				
			||||||
            <PageHeader
 | 
					            <PageHeader
 | 
				
			||||||
                titleElement={
 | 
					                titleElement={`Feature flags ${
 | 
				
			||||||
                    showTitle
 | 
					                    totalItems !== undefined ? `(${totalItems})` : ''
 | 
				
			||||||
                        ? `Feature flags ${
 | 
					                }`}
 | 
				
			||||||
                              totalItems !== undefined ? `(${totalItems})` : ''
 | 
					 | 
				
			||||||
                          }`
 | 
					 | 
				
			||||||
                        : null
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                actions={
 | 
					                actions={
 | 
				
			||||||
                    <>
 | 
					                    <>
 | 
				
			||||||
                        <ConditionallyRender
 | 
					 | 
				
			||||||
                            condition={!isSmallScreen}
 | 
					 | 
				
			||||||
                            show={
 | 
					 | 
				
			||||||
                                <Search
 | 
					 | 
				
			||||||
                                    data-loading
 | 
					 | 
				
			||||||
                                    placeholder='Search and Filter'
 | 
					 | 
				
			||||||
                                    expandable
 | 
					 | 
				
			||||||
                                    initialValue={searchQuery || ''}
 | 
					 | 
				
			||||||
                                    onChange={handleSearch}
 | 
					 | 
				
			||||||
                                    onFocus={() => setShowTitle(false)}
 | 
					 | 
				
			||||||
                                    onBlur={() => setShowTitle(true)}
 | 
					 | 
				
			||||||
                                    hasFilters
 | 
					 | 
				
			||||||
                                    id='projectFeatureFlags'
 | 
					 | 
				
			||||||
                                />
 | 
					 | 
				
			||||||
                            }
 | 
					 | 
				
			||||||
                        />
 | 
					 | 
				
			||||||
                        {actions}
 | 
					 | 
				
			||||||
                        <PageHeader.Divider sx={{ marginLeft: 0 }} />
 | 
					 | 
				
			||||||
                        <Tooltip title='Export all project flags' arrow>
 | 
					                        <Tooltip title='Export all project flags' arrow>
 | 
				
			||||||
                            <IconButton
 | 
					                            <IconButton
 | 
				
			||||||
                                data-loading
 | 
					                                data-loading
 | 
				
			||||||
                                onClick={() => setShowExportDialog(true)}
 | 
					                                onClick={() => setShowExportDialog(true)}
 | 
				
			||||||
                                sx={(theme) => ({
 | 
					 | 
				
			||||||
                                    marginRight: theme.spacing(2),
 | 
					 | 
				
			||||||
                                })}
 | 
					 | 
				
			||||||
                            >
 | 
					                            >
 | 
				
			||||||
                                <IosShare />
 | 
					                                <IosShare />
 | 
				
			||||||
                            </IconButton>
 | 
					                            </IconButton>
 | 
				
			||||||
                        </Tooltip>
 | 
					                        </Tooltip>
 | 
				
			||||||
 | 
					                        <ImportButton />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        <ConditionallyRender
 | 
					                        {!isLoading ? (
 | 
				
			||||||
                            condition={!isLoading}
 | 
					                            <ExportDialog
 | 
				
			||||||
                            show={
 | 
					                                showExportDialog={showExportDialog}
 | 
				
			||||||
                                <ExportDialog
 | 
					                                project={projectId}
 | 
				
			||||||
                                    showExportDialog={showExportDialog}
 | 
					                                data={[]}
 | 
				
			||||||
                                    project={projectId}
 | 
					                                onClose={() => setShowExportDialog(false)}
 | 
				
			||||||
                                    data={[]}
 | 
					                                environments={environmentsToExport || []}
 | 
				
			||||||
                                    onClose={() => setShowExportDialog(false)}
 | 
					                            />
 | 
				
			||||||
                                    environments={environmentsToExport || []}
 | 
					                        ) : null}
 | 
				
			||||||
                                />
 | 
					                        <Box>
 | 
				
			||||||
                            }
 | 
					                            <FlagCreationButton isLoading={isLoading} />
 | 
				
			||||||
                        />
 | 
					                        </Box>
 | 
				
			||||||
                        <FlagCreationButton isLoading={isLoading} />
 | 
					 | 
				
			||||||
                    </>
 | 
					                    </>
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            >
 | 
					            />
 | 
				
			||||||
                <ConditionallyRender
 | 
					 | 
				
			||||||
                    condition={isSmallScreen}
 | 
					 | 
				
			||||||
                    show={
 | 
					 | 
				
			||||||
                        <Search
 | 
					 | 
				
			||||||
                            initialValue={searchQuery || ''}
 | 
					 | 
				
			||||||
                            onChange={handleSearch}
 | 
					 | 
				
			||||||
                            hasFilters
 | 
					 | 
				
			||||||
                            id='projectFeatureFlags'
 | 
					 | 
				
			||||||
                        />
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                />
 | 
					 | 
				
			||||||
            </PageHeader>
 | 
					 | 
				
			||||||
        </Box>
 | 
					        </Box>
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +1,5 @@
 | 
				
			|||||||
import type { FC } from 'react';
 | 
					import type { FC } from 'react';
 | 
				
			||||||
 | 
					import { Box } from '@mui/material';
 | 
				
			||||||
import { ColumnsMenu } from '../ColumnsMenu/ColumnsMenu.tsx';
 | 
					import { ColumnsMenu } from '../ColumnsMenu/ColumnsMenu.tsx';
 | 
				
			||||||
import { formatEnvironmentColumnId } from '../formatEnvironmentColumnId.ts';
 | 
					import { formatEnvironmentColumnId } from '../formatEnvironmentColumnId.ts';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -12,47 +13,49 @@ export const ProjectFeaturesColumnsMenu: FC<
 | 
				
			|||||||
    ProjectFeaturesColumnsMenuProps
 | 
					    ProjectFeaturesColumnsMenuProps
 | 
				
			||||||
> = ({ columnVisibility, environments, onToggle }) => {
 | 
					> = ({ columnVisibility, environments, onToggle }) => {
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
        <ColumnsMenu
 | 
					        <Box sx={(theme) => ({ marginLeft: theme.spacing(1) })}>
 | 
				
			||||||
            columns={[
 | 
					            <ColumnsMenu
 | 
				
			||||||
                {
 | 
					                columns={[
 | 
				
			||||||
                    header: 'Name',
 | 
					                    {
 | 
				
			||||||
                    id: 'name',
 | 
					                        header: 'Name',
 | 
				
			||||||
                    isVisible: columnVisibility.name,
 | 
					                        id: 'name',
 | 
				
			||||||
                    isStatic: true,
 | 
					                        isVisible: columnVisibility.name,
 | 
				
			||||||
                },
 | 
					                        isStatic: true,
 | 
				
			||||||
                {
 | 
					                    },
 | 
				
			||||||
                    header: 'Created',
 | 
					                    {
 | 
				
			||||||
                    id: 'createdAt',
 | 
					                        header: 'Created',
 | 
				
			||||||
                    isVisible: columnVisibility.createdAt,
 | 
					                        id: 'createdAt',
 | 
				
			||||||
                },
 | 
					                        isVisible: columnVisibility.createdAt,
 | 
				
			||||||
                {
 | 
					                    },
 | 
				
			||||||
                    header: 'By',
 | 
					                    {
 | 
				
			||||||
                    id: 'createdBy',
 | 
					                        header: 'By',
 | 
				
			||||||
                    isVisible: columnVisibility.createdBy,
 | 
					                        id: 'createdBy',
 | 
				
			||||||
                },
 | 
					                        isVisible: columnVisibility.createdBy,
 | 
				
			||||||
                {
 | 
					                    },
 | 
				
			||||||
                    header: 'Last seen',
 | 
					                    {
 | 
				
			||||||
                    id: 'lastSeenAt',
 | 
					                        header: 'Last seen',
 | 
				
			||||||
                    isVisible: columnVisibility.lastSeenAt,
 | 
					                        id: 'lastSeenAt',
 | 
				
			||||||
                },
 | 
					                        isVisible: columnVisibility.lastSeenAt,
 | 
				
			||||||
                {
 | 
					                    },
 | 
				
			||||||
                    header: 'Lifecycle',
 | 
					                    {
 | 
				
			||||||
                    id: 'lifecycle',
 | 
					                        header: 'Lifecycle',
 | 
				
			||||||
                    isVisible: columnVisibility.lifecycle,
 | 
					                        id: 'lifecycle',
 | 
				
			||||||
                },
 | 
					                        isVisible: columnVisibility.lifecycle,
 | 
				
			||||||
                {
 | 
					                    },
 | 
				
			||||||
                    id: 'divider',
 | 
					                    {
 | 
				
			||||||
                },
 | 
					                        id: 'divider',
 | 
				
			||||||
                ...environments.map((environment) => ({
 | 
					                    },
 | 
				
			||||||
                    header: environment,
 | 
					                    ...environments.map((environment) => ({
 | 
				
			||||||
                    id: formatEnvironmentColumnId(environment),
 | 
					                        header: environment,
 | 
				
			||||||
                    isVisible:
 | 
					                        id: formatEnvironmentColumnId(environment),
 | 
				
			||||||
                        columnVisibility[
 | 
					                        isVisible:
 | 
				
			||||||
                            formatEnvironmentColumnId(environment)
 | 
					                            columnVisibility[
 | 
				
			||||||
                        ],
 | 
					                                formatEnvironmentColumnId(environment)
 | 
				
			||||||
                })),
 | 
					                            ],
 | 
				
			||||||
            ]}
 | 
					                    })),
 | 
				
			||||||
            onToggle={onToggle}
 | 
					                ]}
 | 
				
			||||||
        />
 | 
					                onToggle={onToggle}
 | 
				
			||||||
 | 
					            />
 | 
				
			||||||
 | 
					        </Box>
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -4,6 +4,7 @@ import type { FilterItemParamHolder } from '../../../filter/Filters/Filters.tsx'
 | 
				
			|||||||
import { useProjectStatus } from 'hooks/api/getters/useProjectStatus/useProjectStatus';
 | 
					import { useProjectStatus } from 'hooks/api/getters/useProjectStatus/useProjectStatus';
 | 
				
			||||||
import { LifecycleFilters } from 'component/common/LifecycleFilters/LifecycleFilters.tsx';
 | 
					import { LifecycleFilters } from 'component/common/LifecycleFilters/LifecycleFilters.tsx';
 | 
				
			||||||
import { Box, useMediaQuery, useTheme } from '@mui/material';
 | 
					import { Box, useMediaQuery, useTheme } from '@mui/material';
 | 
				
			||||||
 | 
					import { useUiFlag } from 'hooks/useUiFlag.ts';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type ProjectLifecycleFiltersProps = {
 | 
					type ProjectLifecycleFiltersProps = {
 | 
				
			||||||
    projectId: string;
 | 
					    projectId: string;
 | 
				
			||||||
@ -23,6 +24,7 @@ export const ProjectLifecycleFilters: FC<ProjectLifecycleFiltersProps> = ({
 | 
				
			|||||||
    const { data } = useProjectStatus(projectId);
 | 
					    const { data } = useProjectStatus(projectId);
 | 
				
			||||||
    const theme = useTheme();
 | 
					    const theme = useTheme();
 | 
				
			||||||
    const isSmallScreen = useMediaQuery(theme.breakpoints.down('md'));
 | 
					    const isSmallScreen = useMediaQuery(theme.breakpoints.down('md'));
 | 
				
			||||||
 | 
					    const flagsUiFilterRefactorEnabled = useUiFlag('flagsUiFilterRefactor');
 | 
				
			||||||
    const lifecycleSummary = Object.entries(
 | 
					    const lifecycleSummary = Object.entries(
 | 
				
			||||||
        data?.lifecycleSummary || {},
 | 
					        data?.lifecycleSummary || {},
 | 
				
			||||||
    ).reduce(
 | 
					    ).reduce(
 | 
				
			||||||
@ -48,7 +50,13 @@ export const ProjectLifecycleFilters: FC<ProjectLifecycleFiltersProps> = ({
 | 
				
			|||||||
        <Box
 | 
					        <Box
 | 
				
			||||||
            sx={{
 | 
					            sx={{
 | 
				
			||||||
                marginRight: 'auto',
 | 
					                marginRight: 'auto',
 | 
				
			||||||
                margin: isSmallScreen ? theme.spacing(0, 2) : '0 auto 0 0',
 | 
					                ...(!flagsUiFilterRefactorEnabled
 | 
				
			||||||
 | 
					                    ? {
 | 
				
			||||||
 | 
					                          margin: isSmallScreen
 | 
				
			||||||
 | 
					                              ? theme.spacing(0, 3)
 | 
				
			||||||
 | 
					                              : `${theme.spacing(1.5)} auto 0 0`,
 | 
				
			||||||
 | 
					                      }
 | 
				
			||||||
 | 
					                    : {}),
 | 
				
			||||||
            }}
 | 
					            }}
 | 
				
			||||||
        >
 | 
					        >
 | 
				
			||||||
            <LifecycleFilters
 | 
					            <LifecycleFilters
 | 
				
			||||||
 | 
				
			|||||||
@ -7,6 +7,8 @@ import {
 | 
				
			|||||||
} from 'component/filter/Filters/Filters';
 | 
					} from 'component/filter/Filters/Filters';
 | 
				
			||||||
import { useProjectFlagCreators } from 'hooks/api/getters/useProjectFlagCreators/useProjectFlagCreators';
 | 
					import { useProjectFlagCreators } from 'hooks/api/getters/useProjectFlagCreators/useProjectFlagCreators';
 | 
				
			||||||
import { formatTag } from 'utils/format-tag';
 | 
					import { formatTag } from 'utils/format-tag';
 | 
				
			||||||
 | 
					import { styled } from '@mui/material';
 | 
				
			||||||
 | 
					import { useUiFlag } from 'hooks/useUiFlag';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type ProjectOverviewFiltersProps = {
 | 
					type ProjectOverviewFiltersProps = {
 | 
				
			||||||
    state: FilterItemParamHolder;
 | 
					    state: FilterItemParamHolder;
 | 
				
			||||||
@ -14,6 +16,10 @@ type ProjectOverviewFiltersProps = {
 | 
				
			|||||||
    project: string;
 | 
					    project: string;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const StyledFilters = styled(Filters)({
 | 
				
			||||||
 | 
					    padding: 0,
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const ProjectOverviewFilters: FC<ProjectOverviewFiltersProps> = ({
 | 
					export const ProjectOverviewFilters: FC<ProjectOverviewFiltersProps> = ({
 | 
				
			||||||
    state,
 | 
					    state,
 | 
				
			||||||
    onChange,
 | 
					    onChange,
 | 
				
			||||||
@ -22,6 +28,10 @@ export const ProjectOverviewFilters: FC<ProjectOverviewFiltersProps> = ({
 | 
				
			|||||||
    const { tags } = useAllTags();
 | 
					    const { tags } = useAllTags();
 | 
				
			||||||
    const { flagCreators } = useProjectFlagCreators(project);
 | 
					    const { flagCreators } = useProjectFlagCreators(project);
 | 
				
			||||||
    const [availableFilters, setAvailableFilters] = useState<IFilterItem[]>([]);
 | 
					    const [availableFilters, setAvailableFilters] = useState<IFilterItem[]>([]);
 | 
				
			||||||
 | 
					    const flagsUiFilterRefactorEnabled = useUiFlag('flagsUiFilterRefactor');
 | 
				
			||||||
 | 
					    const FilterComponent = flagsUiFilterRefactorEnabled
 | 
				
			||||||
 | 
					        ? StyledFilters
 | 
				
			||||||
 | 
					        : Filters;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    useEffect(() => {
 | 
					    useEffect(() => {
 | 
				
			||||||
        const tagsOptions = (tags || []).map((tag) => {
 | 
					        const tagsOptions = (tags || []).map((tag) => {
 | 
				
			||||||
@ -124,7 +134,7 @@ export const ProjectOverviewFilters: FC<ProjectOverviewFiltersProps> = ({
 | 
				
			|||||||
    }, [JSON.stringify(tags), JSON.stringify(flagCreators)]);
 | 
					    }, [JSON.stringify(tags), JSON.stringify(flagCreators)]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
        <Filters
 | 
					        <FilterComponent
 | 
				
			||||||
            availableFilters={availableFilters}
 | 
					            availableFilters={availableFilters}
 | 
				
			||||||
            state={state}
 | 
					            state={state}
 | 
				
			||||||
            onChange={onChange}
 | 
					            onChange={onChange}
 | 
				
			||||||
 | 
				
			|||||||
@ -88,6 +88,7 @@ export type UiFlags = {
 | 
				
			|||||||
    lifecycleGraphs?: boolean;
 | 
					    lifecycleGraphs?: boolean;
 | 
				
			||||||
    newStrategyModal?: boolean;
 | 
					    newStrategyModal?: boolean;
 | 
				
			||||||
    globalChangeRequestList?: boolean;
 | 
					    globalChangeRequestList?: boolean;
 | 
				
			||||||
 | 
					    flagsUiFilterRefactor?: boolean;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface IVersionInfo {
 | 
					export interface IVersionInfo {
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user