1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-04-29 01:15:48 +02:00

1-3060: remove features export import flag (#8890)

This PR removes all references to the `featuresExportImport` flag.

The flag was introduced in [PR
#3411](https://github.com/Unleash/unleash/pull/3411) on March 29th 2023,
and the flag was archived on April 3rd. The flag has always defaulted to
true.

We've looked at the project that introduced the flag and have spoken to CS about it: we can find no reason to keep the flag around. So well remove it now.
This commit is contained in:
Thomas Heartman 2024-12-02 10:26:06 +01:00 committed by GitHub
parent 895ff09dee
commit f833cf58eb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 50 additions and 112 deletions

View File

@ -6,11 +6,7 @@ import { testServerRoute, testServerSetup } from 'utils/testServer';
const server = testServerSetup(); const server = testServerSetup();
test('all options are drawn', async () => { test('all options are drawn', async () => {
testServerRoute(server, '/api/admin/ui-config', { testServerRoute(server, '/api/admin/ui-config', {});
flags: {
featuresExportImport: true,
},
});
render(<FeatureToggleListActions onExportClick={() => {}} />); render(<FeatureToggleListActions onExportClick={() => {}} />);

View File

@ -13,8 +13,6 @@ import {
import Add from '@mui/icons-material/Add'; import Add from '@mui/icons-material/Add';
import MoreVert from '@mui/icons-material/MoreVert'; import MoreVert from '@mui/icons-material/MoreVert';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { useUiFlag } from 'hooks/useUiFlag';
import { CREATE_FEATURE } from 'component/providers/AccessProvider/permissions'; import { CREATE_FEATURE } from 'component/providers/AccessProvider/permissions';
import { PermissionHOC } from 'component/common/PermissionHOC/PermissionHOC'; import { PermissionHOC } from 'component/common/PermissionHOC/PermissionHOC';
import { useCreateFeaturePath } from 'component/feature/CreateFeatureButton/useCreateFeaturePath'; import { useCreateFeaturePath } from 'component/feature/CreateFeatureButton/useCreateFeaturePath';
@ -40,7 +38,6 @@ export const FeatureToggleListActions: FC<IFeatureFlagListActions> = ({
}: IFeatureFlagListActions) => { }: IFeatureFlagListActions) => {
const { trackEvent } = usePlausibleTracker(); const { trackEvent } = usePlausibleTracker();
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null); const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
const featuresExportImport = useUiFlag('featuresExportImport');
const createFeature = useCreateFeaturePath({ const createFeature = useCreateFeaturePath({
query: '', query: '',
project: 'default', project: 'default',
@ -123,31 +120,24 @@ export const FeatureToggleListActions: FC<IFeatureFlagListActions> = ({
</MenuItem> </MenuItem>
)} )}
</PermissionHOC> </PermissionHOC>
<ConditionallyRender <MenuItem
condition={featuresExportImport} onClick={() => {
show={ onExportClick();
<MenuItem handleClose();
onClick={() => { trackEvent('search-feature-buttons', {
onExportClick(); props: {
handleClose(); action: 'export',
trackEvent('search-feature-buttons', { },
props: { });
action: 'export', }}
}, >
}); <ListItemIcon>
}} <IosShare />
> </ListItemIcon>
<ListItemIcon> <ListItemText>
<IosShare /> <Typography variant='body2'>Export</Typography>
</ListItemIcon> </ListItemText>
<ListItemText> </MenuItem>
<Typography variant='body2'>
Export
</Typography>
</ListItemText>
</MenuItem>
}
/>
</MenuList> </MenuList>
</StyledPopover> </StyledPopover>
</StyledActions> </StyledActions>

View File

@ -339,16 +339,11 @@ export const FeatureToggleListTable: VFC = () => {
</Box> </Box>
} }
/> />
<ConditionallyRender <ExportDialog
condition={Boolean(uiConfig?.flags?.featuresExportImport)} showExportDialog={showExportDialog}
show={ data={data}
<ExportDialog onClose={() => setShowExportDialog(false)}
showExportDialog={showExportDialog} environments={enabledEnvironments}
data={data}
onClose={() => setShowExportDialog(false)}
environments={enabledEnvironments}
/>
}
/> />
</PageContent> </PageContent>
); );

View File

@ -59,11 +59,11 @@ export const FlagCreationButton = ({
skipNavigationOnComplete, skipNavigationOnComplete,
onSuccess, onSuccess,
}: IFlagCreationButtonProps) => { }: IFlagCreationButtonProps) => {
const { loading } = useUiConfig();
const [searchParams] = useSearchParams(); const [searchParams] = useSearchParams();
const projectId = useRequiredPathParam('projectId'); const projectId = useRequiredPathParam('projectId');
const showCreateDialog = Boolean(searchParams.get('create')); const showCreateDialog = Boolean(searchParams.get('create'));
const [openCreateDialog, setOpenCreateDialog] = useState(showCreateDialog); const [openCreateDialog, setOpenCreateDialog] = useState(showCreateDialog);
const { loading } = useUiConfig();
return ( return (
<> <>
@ -104,7 +104,6 @@ export const ProjectFeatureTogglesHeader: FC<
const [showTitle, setShowTitle] = useState(true); const [showTitle, setShowTitle] = useState(true);
const theme = useTheme(); const theme = useTheme();
const isSmallScreen = useMediaQuery(theme.breakpoints.down('md')); const isSmallScreen = useMediaQuery(theme.breakpoints.down('md'));
const featuresExportImportFlag = useUiFlag('featuresExportImport');
const [showExportDialog, setShowExportDialog] = useState(false); const [showExportDialog, setShowExportDialog] = useState(false);
const { trackEvent } = usePlausibleTracker(); const { trackEvent } = usePlausibleTracker();
const projectOverviewRefactorFeedback = useUiFlag( const projectOverviewRefactorFeedback = useUiFlag(
@ -168,46 +167,28 @@ export const ProjectFeatureTogglesHeader: FC<
/> />
{actions} {actions}
<PageHeader.Divider sx={{ marginLeft: 0 }} /> <PageHeader.Divider sx={{ marginLeft: 0 }} />
<ConditionallyRender <Tooltip title='Export all project flags' arrow>
condition={featuresExportImportFlag} <IconButton
show={ data-loading
<> onClick={() => setShowExportDialog(true)}
<Tooltip sx={(theme) => ({
title='Export all project flags' marginRight: theme.spacing(2),
arrow })}
> >
<IconButton <IosShare />
data-loading </IconButton>
onClick={() => </Tooltip>
setShowExportDialog(true)
}
sx={(theme) => ({
marginRight: theme.spacing(2),
})}
>
<IosShare />
</IconButton>
</Tooltip>
<ConditionallyRender <ConditionallyRender
condition={!isLoading} condition={!isLoading}
show={ show={
<ExportDialog <ExportDialog
showExportDialog={ showExportDialog={showExportDialog}
showExportDialog project={projectId}
} data={[]}
project={projectId} onClose={() => setShowExportDialog(false)}
data={[]} environments={environmentsToExport || []}
onClose={() => />
setShowExportDialog(false)
}
environments={
environmentsToExport || []
}
/>
}
/>
</>
} }
/> />
<ConditionallyRender <ConditionallyRender

View File

@ -302,10 +302,7 @@ export const Project = () => {
</StyledDiv> </StyledDiv>
<StyledDiv> <StyledDiv>
<ConditionallyRender <ConditionallyRender
condition={Boolean( condition={Boolean(!simplifyProjectOverview)}
!simplifyProjectOverview &&
uiConfig?.flags?.featuresExportImport,
)}
show={ show={
<PermissionIconButton <PermissionIconButton
permission={UPDATE_FEATURE} permission={UPDATE_FEATURE}

View File

@ -56,7 +56,6 @@ export type UiFlags = {
maintenanceMode?: boolean; maintenanceMode?: boolean;
messageBanner?: Variant; messageBanner?: Variant;
banner?: Variant; banner?: Variant;
featuresExportImport?: boolean;
caseInsensitiveInOperators?: boolean; caseInsensitiveInOperators?: boolean;
notifications?: boolean; notifications?: boolean;
personalAccessTokensKillSwitch?: boolean; personalAccessTokensKillSwitch?: boolean;

View File

@ -22,7 +22,7 @@ import {
} from '../../openapi'; } from '../../openapi';
import type { IAuthRequest } from '../../routes/unleash-types'; import type { IAuthRequest } from '../../routes/unleash-types';
import { extractUsername } from '../../util'; import { extractUsername } from '../../util';
import { BadDataError, InvalidOperationError } from '../../error'; import { BadDataError } from '../../error';
import ApiUser from '../../types/api-user'; import ApiUser from '../../types/api-user';
class ExportImportController extends Controller { class ExportImportController extends Controller {
@ -116,7 +116,6 @@ class ExportImportController extends Controller {
req: IAuthRequest<unknown, unknown, ExportQuerySchema, unknown>, req: IAuthRequest<unknown, unknown, ExportQuerySchema, unknown>,
res: Response, res: Response,
): Promise<void> { ): Promise<void> {
this.verifyExportImportEnabled();
const query = req.body; const query = req.body;
const userName = extractUsername(req); const userName = extractUsername(req);
@ -134,7 +133,6 @@ class ExportImportController extends Controller {
req: IAuthRequest<unknown, unknown, ImportTogglesSchema, unknown>, req: IAuthRequest<unknown, unknown, ImportTogglesSchema, unknown>,
res: Response, res: Response,
): Promise<void> { ): Promise<void> {
this.verifyExportImportEnabled();
const dto = req.body; const dto = req.body;
const { user } = req; const { user } = req;
@ -154,7 +152,6 @@ class ExportImportController extends Controller {
req: IAuthRequest<unknown, unknown, ImportTogglesSchema, unknown>, req: IAuthRequest<unknown, unknown, ImportTogglesSchema, unknown>,
res: Response, res: Response,
): Promise<void> { ): Promise<void> {
this.verifyExportImportEnabled();
const { user, audit } = req; const { user, audit } = req;
if (user instanceof ApiUser && user.type === 'admin') { if (user instanceof ApiUser && user.type === 'admin') {
@ -171,13 +168,5 @@ class ExportImportController extends Controller {
res.status(200).end(); res.status(200).end();
} }
private verifyExportImportEnabled() {
if (!this.config.flagResolver.isEnabled('featuresExportImport')) {
throw new InvalidOperationError(
'Feature export/import is not enabled',
);
}
}
} }
export default ExportImportController; export default ExportImportController;

View File

@ -249,9 +249,7 @@ beforeAll(async () => {
db.stores, db.stores,
{ {
experimental: { experimental: {
flags: { flags: {},
featuresExportImport: true,
},
}, },
}, },
db.rawDatabase, db.rawDatabase,

View File

@ -155,9 +155,7 @@ beforeAll(async () => {
db.stores, db.stores,
{ {
experimental: { experimental: {
flags: { flags: {},
featuresExportImport: true,
},
}, },
}, },
db.rawDatabase, db.rawDatabase,

View File

@ -13,7 +13,6 @@ export type IFlagKey =
| 'responseTimeWithAppNameKillSwitch' | 'responseTimeWithAppNameKillSwitch'
| 'maintenanceMode' | 'maintenanceMode'
| 'messageBanner' | 'messageBanner'
| 'featuresExportImport'
| 'caseInsensitiveInOperators' | 'caseInsensitiveInOperators'
| 'strictSchemaValidation' | 'strictSchemaValidation'
| 'personalAccessTokensKillSwitch' | 'personalAccessTokensKillSwitch'
@ -96,10 +95,6 @@ const flags: IFlags = {
process.env.UNLEASH_EXPERIMENTAL_MESSAGE_BANNER_PAYLOAD ?? '', process.env.UNLEASH_EXPERIMENTAL_MESSAGE_BANNER_PAYLOAD ?? '',
}, },
}, },
featuresExportImport: parseEnvVarBoolean(
process.env.UNLEASH_EXPERIMENTAL_FEATURES_EXPORT_IMPORT,
true,
),
caseInsensitiveInOperators: parseEnvVarBoolean( caseInsensitiveInOperators: parseEnvVarBoolean(
process.env.UNLEASH_EXPERIMENTAL_CASE_INSENSITIVE_IN_OPERATORS, process.env.UNLEASH_EXPERIMENTAL_CASE_INSENSITIVE_IN_OPERATORS,
false, false,