mirror of
https://github.com/Unleash/unleash.git
synced 2025-10-27 11:02:16 +01:00
chore: remove legacy flag UI (#10781)
This commit is contained in:
parent
7efd707dee
commit
b5d1f6e075
@ -262,7 +262,6 @@ test('clears lifecycle filter when switching to archived view', async () => {
|
||||
testServerRoute(server, '/api/admin/ui-config', {
|
||||
flags: {
|
||||
flagCreator: true,
|
||||
flagsUiFilterRefactor: true,
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
import { ReactComponent as ImportSvg } from 'assets/icons/import.svg';
|
||||
import { useCallback, useMemo, useState } from 'react';
|
||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||
import { PageContent } from 'component/common/PageContent/PageContent';
|
||||
@ -20,7 +19,6 @@ import {
|
||||
import { useChangeRequestsEnabled } from 'hooks/useChangeRequestsEnabled';
|
||||
import { useFeatureToggleSwitch } from '../ProjectFeatureToggles/FeatureToggleSwitch/useFeatureToggleSwitch.tsx';
|
||||
import useLoading from 'hooks/useLoading';
|
||||
import { ProjectFeatureTogglesHeader as LegacyProjectFeatureTogglesHeader } from './ProjectFeatureTogglesHeader/LegacyProjectFeatureTogglesHeader.tsx';
|
||||
import { createColumnHelper, useReactTable } from '@tanstack/react-table';
|
||||
import { withTableState } from 'utils/withTableState';
|
||||
import type { FeatureSearchResponseSchema } from 'openapi';
|
||||
@ -50,14 +48,10 @@ import { ProjectOnboarded } from 'component/onboarding/flow/ProjectOnboarded';
|
||||
import { usePlausibleTracker } from 'hooks/usePlausibleTracker';
|
||||
import { ArchivedFeatureActionCell } from '../../../archive/ArchiveTable/ArchivedFeatureActionCell/ArchivedFeatureActionCell.tsx';
|
||||
import { ArchiveBatchActions } from '../../../archive/ArchiveTable/ArchiveBatchActions.tsx';
|
||||
import PermissionIconButton from 'component/common/PermissionIconButton/PermissionIconButton';
|
||||
import { UPDATE_FEATURE } from '@server/types/permissions';
|
||||
import { ImportModal } from '../Import/ImportModal.tsx';
|
||||
import { IMPORT_BUTTON } from 'utils/testIds';
|
||||
import { ProjectCleanupReminder } from './ProjectCleanupReminder/ProjectCleanupReminder.tsx';
|
||||
import { formatEnvironmentColumnId } from './formatEnvironmentColumnId.ts';
|
||||
import { ProjectFeaturesColumnsMenu } from './ProjectFeaturesColumnsMenu/ProjectFeaturesColumnsMenu.tsx';
|
||||
import { useUiFlag } from 'hooks/useUiFlag.ts';
|
||||
import { ProjectFeatureTogglesHeader } from './ProjectFeatureTogglesHeader/ProjectFeatureTogglesHeader.tsx';
|
||||
import { ProjectFlagsSearch } from './ProjectFlagsSearch/ProjectFlagsSearch.tsx';
|
||||
|
||||
@ -74,12 +68,6 @@ const Container = styled('div')(({ theme }) => ({
|
||||
gap: theme.spacing(2),
|
||||
}));
|
||||
|
||||
const LegacyFilterRow = styled('div')(({ theme }) => ({
|
||||
display: 'flex',
|
||||
flexFlow: 'row wrap',
|
||||
justifyContent: 'space-between',
|
||||
}));
|
||||
|
||||
const FiltersContainer = styled('div')(({ theme }) => ({
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
@ -95,12 +83,6 @@ const FilterRow = styled('div')({
|
||||
alignItems: 'center',
|
||||
});
|
||||
|
||||
const ButtonGroup = styled('div')(({ theme }) => ({
|
||||
display: 'flex',
|
||||
gap: theme.spacing(1),
|
||||
paddingInline: theme.spacing(1.5),
|
||||
}));
|
||||
|
||||
const LinkToggle = styled('button')(({ theme }) => ({
|
||||
background: 'none',
|
||||
border: 'none',
|
||||
@ -126,7 +108,6 @@ export const ProjectFeatureToggles = ({
|
||||
const { project } = useProjectOverview(projectId);
|
||||
const [connectSdkOpen, setConnectSdkOpen] = useState(false);
|
||||
const [modalOpen, setModalOpen] = useState(false);
|
||||
const flagsUiFilterRefactorEnabled = useUiFlag('flagsUiFilterRefactor');
|
||||
const theme = useTheme();
|
||||
const isSmallScreen = useMediaQuery(theme.breakpoints.down('md'));
|
||||
|
||||
@ -551,48 +532,23 @@ export const ProjectFeatureToggles = ({
|
||||
<PageContent
|
||||
disableLoading
|
||||
header={
|
||||
flagsUiFilterRefactorEnabled ? (
|
||||
<ProjectFeatureTogglesHeader
|
||||
isLoading={initialLoad}
|
||||
totalItems={total}
|
||||
environmentsToExport={environments}
|
||||
actions={
|
||||
flagsUiFilterRefactorEnabled ? (
|
||||
<LinkToggle
|
||||
type='button'
|
||||
onClick={toggleArchived}
|
||||
>
|
||||
{showArchived
|
||||
? 'View active flags'
|
||||
: 'View archived flags'}
|
||||
</LinkToggle>
|
||||
) : null
|
||||
}
|
||||
title={
|
||||
showArchived
|
||||
? 'Archived feature flags'
|
||||
: 'Feature flags'
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
<LegacyProjectFeatureTogglesHeader
|
||||
isLoading={initialLoad}
|
||||
totalItems={total}
|
||||
searchQuery={tableState.query || ''}
|
||||
onChangeSearchQuery={(query) => {
|
||||
setTableState({ query });
|
||||
}}
|
||||
dataToExport={data}
|
||||
environmentsToExport={environments}
|
||||
actions={
|
||||
<ProjectFeaturesColumnsMenu
|
||||
columnVisibility={columnVisibility}
|
||||
environments={environments}
|
||||
onToggle={onToggleColumnVisibility}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
)
|
||||
<ProjectFeatureTogglesHeader
|
||||
isLoading={initialLoad}
|
||||
totalItems={total}
|
||||
environmentsToExport={environments}
|
||||
actions={
|
||||
<LinkToggle type='button' onClick={toggleArchived}>
|
||||
{showArchived
|
||||
? 'View active flags'
|
||||
: 'View archived flags'}
|
||||
</LinkToggle>
|
||||
}
|
||||
title={
|
||||
showArchived
|
||||
? 'Archived feature flags'
|
||||
: 'Feature flags'
|
||||
}
|
||||
/>
|
||||
}
|
||||
bodyClass='noop'
|
||||
style={{ cursor: 'inherit' }}
|
||||
@ -602,50 +558,25 @@ export const ProjectFeatureToggles = ({
|
||||
aria-busy={isPlaceholder}
|
||||
aria-live='polite'
|
||||
>
|
||||
{flagsUiFilterRefactorEnabled ? (
|
||||
<FiltersContainer>
|
||||
<FilterRow>
|
||||
{showArchived ? (
|
||||
<Box sx={{ marginRight: 'auto' }}>
|
||||
<ProjectOverviewFilters
|
||||
project={projectId}
|
||||
onChange={setTableState}
|
||||
state={filterState}
|
||||
/>
|
||||
</Box>
|
||||
) : (
|
||||
<ProjectLifecycleFilters
|
||||
projectId={projectId}
|
||||
state={filterState}
|
||||
onChange={setTableState}
|
||||
total={loading ? undefined : total}
|
||||
/>
|
||||
)}
|
||||
{isSmallScreen ? null : (
|
||||
<ProjectFlagsSearch
|
||||
searchQuery={tableState.query || ''}
|
||||
onChangeSearchQuery={(query) => {
|
||||
setTableState({ query });
|
||||
}}
|
||||
isLoading={loading}
|
||||
/>
|
||||
)}
|
||||
<ProjectFeaturesColumnsMenu
|
||||
columnVisibility={columnVisibility}
|
||||
environments={environments}
|
||||
onToggle={onToggleColumnVisibility}
|
||||
/>
|
||||
</FilterRow>
|
||||
{showArchived ? null : (
|
||||
<FilterRow>
|
||||
<FiltersContainer>
|
||||
<FilterRow>
|
||||
{showArchived ? (
|
||||
<Box sx={{ marginRight: 'auto' }}>
|
||||
<ProjectOverviewFilters
|
||||
project={projectId}
|
||||
onChange={setTableState}
|
||||
state={filterState}
|
||||
/>
|
||||
</FilterRow>
|
||||
</Box>
|
||||
) : (
|
||||
<ProjectLifecycleFilters
|
||||
projectId={projectId}
|
||||
state={filterState}
|
||||
onChange={setTableState}
|
||||
total={loading ? undefined : total}
|
||||
/>
|
||||
)}
|
||||
{isSmallScreen ? (
|
||||
{isSmallScreen ? null : (
|
||||
<ProjectFlagsSearch
|
||||
searchQuery={tableState.query || ''}
|
||||
onChangeSearchQuery={(query) => {
|
||||
@ -653,35 +584,32 @@ export const ProjectFeatureToggles = ({
|
||||
}}
|
||||
isLoading={loading}
|
||||
/>
|
||||
) : null}
|
||||
</FiltersContainer>
|
||||
) : (
|
||||
<LegacyFilterRow>
|
||||
<ProjectOverviewFilters
|
||||
project={projectId}
|
||||
onChange={setTableState}
|
||||
state={filterState}
|
||||
)}
|
||||
<ProjectFeaturesColumnsMenu
|
||||
columnVisibility={columnVisibility}
|
||||
environments={environments}
|
||||
onToggle={onToggleColumnVisibility}
|
||||
/>
|
||||
<ProjectLifecycleFilters
|
||||
projectId={projectId}
|
||||
state={filterState}
|
||||
onChange={setTableState}
|
||||
total={loading ? undefined : total}
|
||||
</FilterRow>
|
||||
{showArchived ? null : (
|
||||
<FilterRow>
|
||||
<ProjectOverviewFilters
|
||||
project={projectId}
|
||||
onChange={setTableState}
|
||||
state={filterState}
|
||||
/>
|
||||
</FilterRow>
|
||||
)}
|
||||
{isSmallScreen ? (
|
||||
<ProjectFlagsSearch
|
||||
searchQuery={tableState.query || ''}
|
||||
onChangeSearchQuery={(query) => {
|
||||
setTableState({ query });
|
||||
}}
|
||||
isLoading={loading}
|
||||
/>
|
||||
<ButtonGroup>
|
||||
<PermissionIconButton
|
||||
permission={UPDATE_FEATURE}
|
||||
projectId={projectId}
|
||||
onClick={() => setModalOpen(true)}
|
||||
tooltipProps={{ title: 'Import' }}
|
||||
data-testid={IMPORT_BUTTON}
|
||||
data-loading-project
|
||||
>
|
||||
<ImportSvg />
|
||||
</PermissionIconButton>
|
||||
</ButtonGroup>
|
||||
</LegacyFilterRow>
|
||||
)}
|
||||
) : null}
|
||||
</FiltersContainer>
|
||||
<SearchHighlightProvider value={tableState.query || ''}>
|
||||
<PaginatedTable
|
||||
tableInstance={table}
|
||||
|
||||
@ -1,165 +0,0 @@
|
||||
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>
|
||||
);
|
||||
};
|
||||
@ -3,8 +3,7 @@ import { useEffect } from 'react';
|
||||
import type { FilterItemParamHolder } from '../../../filter/Filters/Filters.tsx';
|
||||
import { useProjectStatus } from 'hooks/api/getters/useProjectStatus/useProjectStatus';
|
||||
import { LifecycleFilters } from 'component/common/LifecycleFilters/LifecycleFilters.tsx';
|
||||
import { Box, useMediaQuery, useTheme } from '@mui/material';
|
||||
import { useUiFlag } from 'hooks/useUiFlag.ts';
|
||||
import { Box, useTheme } from '@mui/material';
|
||||
|
||||
type ProjectLifecycleFiltersProps = {
|
||||
projectId: string;
|
||||
@ -23,8 +22,6 @@ export const ProjectLifecycleFilters: FC<ProjectLifecycleFiltersProps> = ({
|
||||
}) => {
|
||||
const { data } = useProjectStatus(projectId);
|
||||
const theme = useTheme();
|
||||
const isSmallScreen = useMediaQuery(theme.breakpoints.down('md'));
|
||||
const flagsUiFilterRefactorEnabled = useUiFlag('flagsUiFilterRefactor');
|
||||
const lifecycleSummary = Object.entries(
|
||||
data?.lifecycleSummary || {},
|
||||
).reduce(
|
||||
@ -47,18 +44,7 @@ export const ProjectLifecycleFilters: FC<ProjectLifecycleFiltersProps> = ({
|
||||
}
|
||||
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
marginRight: 'auto',
|
||||
...(flagsUiFilterRefactorEnabled
|
||||
? {}
|
||||
: {
|
||||
margin: isSmallScreen
|
||||
? theme.spacing(0, 3)
|
||||
: `${theme.spacing(1.5)} auto ${theme.spacing(1.5)} ${theme.spacing(3)}`,
|
||||
}),
|
||||
}}
|
||||
>
|
||||
<Box sx={{ marginRight: 'auto' }}>
|
||||
<LifecycleFilters
|
||||
state={state}
|
||||
onChange={onChange}
|
||||
|
||||
@ -8,7 +8,6 @@ import {
|
||||
import { useProjectFlagCreators } from 'hooks/api/getters/useProjectFlagCreators/useProjectFlagCreators';
|
||||
import { formatTag } from 'utils/format-tag';
|
||||
import { styled } from '@mui/material';
|
||||
import { useUiFlag } from 'hooks/useUiFlag';
|
||||
|
||||
type ProjectOverviewFiltersProps = {
|
||||
state: FilterItemParamHolder;
|
||||
@ -28,10 +27,6 @@ export const ProjectOverviewFilters: FC<ProjectOverviewFiltersProps> = ({
|
||||
const { tags } = useAllTags();
|
||||
const { flagCreators } = useProjectFlagCreators(project);
|
||||
const [availableFilters, setAvailableFilters] = useState<IFilterItem[]>([]);
|
||||
const flagsUiFilterRefactorEnabled = useUiFlag('flagsUiFilterRefactor');
|
||||
const FilterComponent = flagsUiFilterRefactorEnabled
|
||||
? StyledFilters
|
||||
: Filters;
|
||||
|
||||
useEffect(() => {
|
||||
const tagsOptions = (tags || []).map((tag) => {
|
||||
@ -120,25 +115,13 @@ export const ProjectOverviewFilters: FC<ProjectOverviewFiltersProps> = ({
|
||||
singularOperators: ['IS', 'IS_NOT'],
|
||||
pluralOperators: ['IS_ANY_OF', 'IS_NONE_OF'],
|
||||
},
|
||||
...(!flagsUiFilterRefactorEnabled
|
||||
? [
|
||||
{
|
||||
label: 'Show only archived',
|
||||
icon: 'inventory',
|
||||
options: [{ label: 'True', value: 'true' }],
|
||||
filterKey: 'archived',
|
||||
singularOperators: ['IS'],
|
||||
pluralOperators: ['IS_ANY_OF'],
|
||||
} satisfies IFilterItem,
|
||||
]
|
||||
: []),
|
||||
];
|
||||
|
||||
setAvailableFilters(availableFilters);
|
||||
}, [JSON.stringify(tags), JSON.stringify(flagCreators)]);
|
||||
|
||||
return (
|
||||
<FilterComponent
|
||||
<StyledFilters
|
||||
availableFilters={availableFilters}
|
||||
state={state}
|
||||
onChange={onChange}
|
||||
|
||||
@ -88,7 +88,6 @@ export type UiFlags = {
|
||||
lifecycleGraphs?: boolean;
|
||||
newStrategyModal?: boolean;
|
||||
globalChangeRequestList?: boolean;
|
||||
flagsUiFilterRefactor?: boolean;
|
||||
trafficBillingDisplay?: boolean;
|
||||
milestoneProgression?: boolean;
|
||||
featureReleasePlans?: boolean;
|
||||
|
||||
@ -60,7 +60,6 @@ export type IFlagKey =
|
||||
| 'newStrategyModal'
|
||||
| 'globalChangeRequestList'
|
||||
| 'newUiConfigService'
|
||||
| 'flagsUiFilterRefactor'
|
||||
| 'trafficBillingDisplay'
|
||||
| 'milestoneProgression'
|
||||
| 'envAddStrategySuggestion'
|
||||
@ -277,10 +276,6 @@ const flags: IFlags = {
|
||||
process.env.UNLEASH_EXPERIMENTAL_NEW_UI_CONFIG_SERVICE,
|
||||
false,
|
||||
),
|
||||
flagsUiFilterRefactor: parseEnvVarBoolean(
|
||||
process.env.UNLEASH_EXPERIMENTAL_FLAGS_UI_FILTER_REFACTOR,
|
||||
false,
|
||||
),
|
||||
trafficBillingDisplay: parseEnvVarBoolean(
|
||||
process.env.UNLEASH_EXPERIMENTAL_TRAFFIC_BILLING_DISPLAY,
|
||||
false,
|
||||
|
||||
@ -56,7 +56,6 @@ process.nextTick(async () => {
|
||||
newStrategyModal: true,
|
||||
globalChangeRequestList: true,
|
||||
newUiConfigService: true,
|
||||
flagsUiFilterRefactor: true,
|
||||
trafficBillingDisplay: true,
|
||||
milestoneProgression: true,
|
||||
featureReleasePlans: true,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user