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:
parent
895ff09dee
commit
f833cf58eb
@ -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={() => {}} />);
|
||||||
|
|
||||||
|
@ -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>
|
||||||
|
@ -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>
|
||||||
);
|
);
|
||||||
|
@ -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
|
||||||
|
@ -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}
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -249,9 +249,7 @@ beforeAll(async () => {
|
|||||||
db.stores,
|
db.stores,
|
||||||
{
|
{
|
||||||
experimental: {
|
experimental: {
|
||||||
flags: {
|
flags: {},
|
||||||
featuresExportImport: true,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
db.rawDatabase,
|
db.rawDatabase,
|
||||||
|
@ -155,9 +155,7 @@ beforeAll(async () => {
|
|||||||
db.stores,
|
db.stores,
|
||||||
{
|
{
|
||||||
experimental: {
|
experimental: {
|
||||||
flags: {
|
flags: {},
|
||||||
featuresExportImport: true,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
db.rawDatabase,
|
db.rawDatabase,
|
||||||
|
@ -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,
|
||||||
|
Loading…
Reference in New Issue
Block a user