diff --git a/frontend/src/component/feature/FeatureToggleList/FeatureToggleListTable.tsx b/frontend/src/component/feature/FeatureToggleList/FeatureToggleListTable.tsx
index 9cdea15fcb..a77ab7a2f2 100644
--- a/frontend/src/component/feature/FeatureToggleList/FeatureToggleListTable.tsx
+++ b/frontend/src/component/feature/FeatureToggleList/FeatureToggleListTable.tsx
@@ -68,6 +68,7 @@ export const FeatureToggleListTable: VFC = () => {
const [showExportDialog, setShowExportDialog] = useState(false);
const { features = [], loading, refetchFeatures } = useFeatures();
const [searchParams, setSearchParams] = useSearchParams();
+ const { uiConfig } = useUiConfig();
const [initialState] = useState(() => ({
sortBy: [
{
@@ -310,16 +311,28 @@ export const FeatureToggleListTable: VFC = () => {
>
View archive
-
- setShowExportDialog(true)}
- sx={theme => ({
- marginRight: theme.spacing(2),
- })}
- >
-
-
-
+
+
+ setShowExportDialog(true)
+ }
+ sx={theme => ({
+ marginRight: theme.spacing(2),
+ })}
+ >
+
+
+
+ }
+ />
{
/>
}
/>
- setShowExportDialog(false)}
- environments={enabledEnvironments}
+ setShowExportDialog(false)}
+ environments={enabledEnvironments}
+ />
+ }
/>
);
diff --git a/frontend/src/component/project/Project/Project.tsx b/frontend/src/component/project/Project/Project.tsx
index ce2ea40bf3..ce02a943d8 100644
--- a/frontend/src/component/project/Project/Project.tsx
+++ b/frontend/src/component/project/Project/Project.tsx
@@ -139,16 +139,23 @@ export const Project = () => {
- setModalOpen(true)}
- tooltipProps={{ title: 'Import' }}
- data-testid={IMPORT_BUTTON}
- data-loading
- >
-
-
+ setModalOpen(true)}
+ tooltipProps={{ title: 'Import' }}
+ data-testid={IMPORT_BUTTON}
+ data-loading
+ >
+
+
+ }
+ />
-
-
- setShowExportDialog(true)
- }
- sx={theme => ({
- marginRight: theme.spacing(2),
- })}
- >
-
-
-
+
+
+ setShowExportDialog(true)
+ }
+ sx={theme => ({
+ marginRight:
+ theme.spacing(2),
+ })}
+ >
+
+
+
+ }
+ />
navigate(getCreateTogglePath(projectId))
@@ -704,7 +712,10 @@ export const ProjectFeatureToggles = ({
}
/>
= ({ selectedIds, data, projectId }) => {
+ const { uiConfig } = useUiConfig();
const [showExportDialog, setShowExportDialog] = useState(false);
const { trackEvent } = usePlausibleTracker();
const selectedData = useMemo(
@@ -54,12 +56,17 @@ export const ProjectFeaturesBatchActions: FC<
- setShowExportDialog(false)}
- environments={environments}
- onConfirm={trackExport}
+ setShowExportDialog(false)}
+ environments={environments}
+ onConfirm={trackExport}
+ />
+ }
/>
>
);
diff --git a/frontend/src/interfaces/uiConfig.ts b/frontend/src/interfaces/uiConfig.ts
index 2815aa40d3..946c87ebb0 100644
--- a/frontend/src/interfaces/uiConfig.ts
+++ b/frontend/src/interfaces/uiConfig.ts
@@ -40,6 +40,7 @@ export interface IFlags {
embedProxyFrontend?: boolean;
maintenanceMode?: boolean;
messageBanner?: boolean;
+ featuresExportImport?: boolean;
newProjectOverview?: boolean;
caseInsensitiveInOperators?: boolean;
crOnVariants?: boolean;
diff --git a/src/lib/__snapshots__/create-config.test.ts.snap b/src/lib/__snapshots__/create-config.test.ts.snap
index 020bb3c737..13a2003714 100644
--- a/src/lib/__snapshots__/create-config.test.ts.snap
+++ b/src/lib/__snapshots__/create-config.test.ts.snap
@@ -75,6 +75,7 @@ exports[`should create default config 1`] = `
"crOnVariants": false,
"embedProxy": true,
"embedProxyFrontend": true,
+ "featuresExportImport": true,
"loginHistory": false,
"maintenanceMode": false,
"messageBanner": false,
@@ -101,6 +102,7 @@ exports[`should create default config 1`] = `
"crOnVariants": false,
"embedProxy": true,
"embedProxyFrontend": true,
+ "featuresExportImport": true,
"loginHistory": false,
"maintenanceMode": false,
"messageBanner": false,
diff --git a/src/lib/features/export-import-toggles/export-import-controller.ts b/src/lib/features/export-import-toggles/export-import-controller.ts
index 1310df1c1d..dab6d3a52d 100644
--- a/src/lib/features/export-import-toggles/export-import-controller.ts
+++ b/src/lib/features/export-import-toggles/export-import-controller.ts
@@ -21,6 +21,7 @@ import {
} from '../../openapi';
import { IAuthRequest } from '../../routes/unleash-types';
import { extractUsername } from '../../util';
+import { InvalidOperationError } from '../../error';
class ExportImportController extends Controller {
private logger: Logger;
@@ -118,6 +119,7 @@ class ExportImportController extends Controller {
req: IAuthRequest,
res: Response,
): Promise {
+ this.verifyExportImportEnabled();
const query = req.body;
const userName = extractUsername(req);
const data = await this.exportImportService.export(query, userName);
@@ -134,6 +136,7 @@ class ExportImportController extends Controller {
req: IAuthRequest,
res: Response,
): Promise {
+ this.verifyExportImportEnabled();
const dto = req.body;
const { user } = req;
const validation = await this.startTransaction(async (tx) =>
@@ -152,6 +155,7 @@ class ExportImportController extends Controller {
req: IAuthRequest,
res: Response,
): Promise {
+ this.verifyExportImportEnabled();
const dto = req.body;
const { user } = req;
await this.startTransaction(async (tx) =>
@@ -160,5 +164,13 @@ class ExportImportController extends Controller {
res.status(200).end();
}
+
+ private verifyExportImportEnabled() {
+ if (!this.config.flagResolver.isEnabled('featuresExportImport')) {
+ throw new InvalidOperationError(
+ 'Feature export/import is not enabled',
+ );
+ }
+ }
}
export default ExportImportController;
diff --git a/src/lib/features/export-import-toggles/export-import-permissions.e2e.test.ts b/src/lib/features/export-import-toggles/export-import-permissions.e2e.test.ts
index 618e3281fb..cbd114f258 100644
--- a/src/lib/features/export-import-toggles/export-import-permissions.e2e.test.ts
+++ b/src/lib/features/export-import-toggles/export-import-permissions.e2e.test.ts
@@ -233,7 +233,9 @@ beforeAll(async () => {
db.stores,
{
experimental: {
- flags: {},
+ flags: {
+ featuresExportImport: true,
+ },
},
},
db.rawDatabase,
diff --git a/src/lib/features/export-import-toggles/export-import.e2e.test.ts b/src/lib/features/export-import-toggles/export-import.e2e.test.ts
index 8b0b2a2e72..924fc8eaa2 100644
--- a/src/lib/features/export-import-toggles/export-import.e2e.test.ts
+++ b/src/lib/features/export-import-toggles/export-import.e2e.test.ts
@@ -138,7 +138,9 @@ beforeAll(async () => {
db.stores,
{
experimental: {
- flags: {},
+ flags: {
+ featuresExportImport: true,
+ },
},
},
db.rawDatabase,
diff --git a/src/lib/types/experimental.ts b/src/lib/types/experimental.ts
index 39c630665a..a92fa1b87a 100644
--- a/src/lib/types/experimental.ts
+++ b/src/lib/types/experimental.ts
@@ -34,6 +34,10 @@ const flags = {
process.env.UNLEASH_EXPERIMENTAL_MESSAGE_BANNER,
false,
),
+ featuresExportImport: parseEnvVarBoolean(
+ process.env.UNLEASH_EXPERIMENTAL_FEATURES_EXPORT_IMPORT,
+ true,
+ ),
caseInsensitiveInOperators: parseEnvVarBoolean(
process.env.UNLEASH_EXPERIMENTAL_CASE_INSENSITIVE_IN_OPERATORS,
false,