mirror of
https://github.com/Unleash/unleash.git
synced 2025-09-19 17:52:45 +02:00
chore: remove dependent feature flags (#5419)
This commit is contained in:
parent
581b238378
commit
de287a75fe
@ -31,9 +31,6 @@ const setupArchiveValidation = (orphanParents: string[]) => {
|
|||||||
versionInfo: {
|
versionInfo: {
|
||||||
current: { oss: 'version', enterprise: 'version' },
|
current: { oss: 'version', enterprise: 'version' },
|
||||||
},
|
},
|
||||||
flags: {
|
|
||||||
dependentFeatures: true,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
testServerRoute(
|
testServerRoute(
|
||||||
server,
|
server,
|
||||||
@ -126,6 +123,7 @@ test('Skip change request', async () => {
|
|||||||
await screen.findByText('Archive feature toggles');
|
await screen.findByText('Archive feature toggles');
|
||||||
const button = await screen.findByText('Archive toggles');
|
const button = await screen.findByText('Archive toggles');
|
||||||
|
|
||||||
|
await waitFor(() => expect(button).toBeEnabled());
|
||||||
button.click();
|
button.click();
|
||||||
|
|
||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
|
@ -302,12 +302,8 @@ export const FeatureArchiveDialog: VFC<IFeatureArchiveDialogProps> = ({
|
|||||||
const { disableArchive, offendingParents, hasDeletedDependencies } =
|
const { disableArchive, offendingParents, hasDeletedDependencies } =
|
||||||
useVerifyArchive(featureIds, projectId, isOpen);
|
useVerifyArchive(featureIds, projectId, isOpen);
|
||||||
|
|
||||||
const dependentFeatures = useUiFlag('dependentFeatures');
|
|
||||||
|
|
||||||
const removeDependenciesWarning =
|
const removeDependenciesWarning =
|
||||||
dependentFeatures &&
|
offendingParents.length === 0 && hasDeletedDependencies;
|
||||||
offendingParents.length === 0 &&
|
|
||||||
hasDeletedDependencies;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialogue
|
<Dialogue
|
||||||
@ -317,7 +313,7 @@ export const FeatureArchiveDialog: VFC<IFeatureArchiveDialogProps> = ({
|
|||||||
primaryButtonText={buttonText}
|
primaryButtonText={buttonText}
|
||||||
secondaryButtonText='Cancel'
|
secondaryButtonText='Cancel'
|
||||||
title={dialogTitle}
|
title={dialogTitle}
|
||||||
disabledPrimaryButton={dependentFeatures && disableArchive}
|
disabledPrimaryButton={disableArchive}
|
||||||
>
|
>
|
||||||
<ConditionallyRender
|
<ConditionallyRender
|
||||||
condition={isBulkArchive}
|
condition={isBulkArchive}
|
||||||
@ -342,9 +338,7 @@ export const FeatureArchiveDialog: VFC<IFeatureArchiveDialogProps> = ({
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<ConditionallyRender
|
<ConditionallyRender
|
||||||
condition={
|
condition={offendingParents.length > 0}
|
||||||
dependentFeatures && offendingParents.length > 0
|
|
||||||
}
|
|
||||||
show={
|
show={
|
||||||
<ArchiveParentError
|
<ArchiveParentError
|
||||||
ids={offendingParents}
|
ids={offendingParents}
|
||||||
@ -378,9 +372,7 @@ export const FeatureArchiveDialog: VFC<IFeatureArchiveDialogProps> = ({
|
|||||||
?
|
?
|
||||||
</p>
|
</p>
|
||||||
<ConditionallyRender
|
<ConditionallyRender
|
||||||
condition={
|
condition={offendingParents.length > 0}
|
||||||
dependentFeatures && offendingParents.length > 0
|
|
||||||
}
|
|
||||||
show={
|
show={
|
||||||
<ArchiveParentError
|
<ArchiveParentError
|
||||||
ids={offendingParents}
|
ids={offendingParents}
|
||||||
|
@ -8,9 +8,6 @@ const server = testServerSetup();
|
|||||||
|
|
||||||
const setupApi = () => {
|
const setupApi = () => {
|
||||||
testServerRoute(server, '/api/admin/ui-config', {
|
testServerRoute(server, '/api/admin/ui-config', {
|
||||||
flags: {
|
|
||||||
dependentFeatures: true,
|
|
||||||
},
|
|
||||||
versionInfo: {
|
versionInfo: {
|
||||||
current: { oss: 'irrelevant', enterprise: 'some value' },
|
current: { oss: 'irrelevant', enterprise: 'some value' },
|
||||||
},
|
},
|
||||||
|
@ -10,9 +10,6 @@ const server = testServerSetup();
|
|||||||
|
|
||||||
const setupApi = () => {
|
const setupApi = () => {
|
||||||
testServerRoute(server, '/api/admin/ui-config', {
|
testServerRoute(server, '/api/admin/ui-config', {
|
||||||
flags: {
|
|
||||||
dependentFeatures: true,
|
|
||||||
},
|
|
||||||
versionInfo: {
|
versionInfo: {
|
||||||
current: { oss: 'irrelevant', enterprise: 'some value' },
|
current: { oss: 'irrelevant', enterprise: 'some value' },
|
||||||
},
|
},
|
||||||
@ -35,9 +32,6 @@ const setupApi = () => {
|
|||||||
|
|
||||||
const setupOssWithExistingDependencies = () => {
|
const setupOssWithExistingDependencies = () => {
|
||||||
testServerRoute(server, '/api/admin/ui-config', {
|
testServerRoute(server, '/api/admin/ui-config', {
|
||||||
flags: {
|
|
||||||
dependentFeatures: true,
|
|
||||||
},
|
|
||||||
versionInfo: {
|
versionInfo: {
|
||||||
current: { oss: 'some value' },
|
current: { oss: 'some value' },
|
||||||
},
|
},
|
||||||
|
@ -1,13 +1,9 @@
|
|||||||
import { useUiFlag } from 'hooks/useUiFlag';
|
|
||||||
import { useCheckDependenciesExist } from 'hooks/api/getters/useCheckDependenciesExist/useCheckDependenciesExist';
|
import { useCheckDependenciesExist } from 'hooks/api/getters/useCheckDependenciesExist/useCheckDependenciesExist';
|
||||||
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
|
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
|
||||||
|
|
||||||
export const useShowDependentFeatures = (project: string) => {
|
export const useShowDependentFeatures = (project: string) => {
|
||||||
const dependentFeatures = useUiFlag('dependentFeatures');
|
|
||||||
const { dependenciesExist } = useCheckDependenciesExist(project);
|
const { dependenciesExist } = useCheckDependenciesExist(project);
|
||||||
const { isOss } = useUiConfig();
|
const { isOss } = useUiConfig();
|
||||||
|
|
||||||
return Boolean(
|
return Boolean(isOss() ? dependenciesExist : true);
|
||||||
isOss() ? dependenciesExist && dependentFeatures : dependentFeatures,
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
@ -10,11 +10,7 @@ import userEvent from '@testing-library/user-event';
|
|||||||
const server = testServerSetup();
|
const server = testServerSetup();
|
||||||
|
|
||||||
const setupApi = () => {
|
const setupApi = () => {
|
||||||
testServerRoute(server, '/api/admin/ui-config', {
|
testServerRoute(server, '/api/admin/ui-config', {});
|
||||||
flags: {
|
|
||||||
dependentFeatures: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
test('Cannot change project for feature with dependencies', async () => {
|
test('Cannot change project for feature with dependencies', async () => {
|
||||||
|
@ -41,7 +41,6 @@ const FeatureSettingsProjectConfirm = ({
|
|||||||
feature,
|
feature,
|
||||||
changeRequests,
|
changeRequests,
|
||||||
}: IFeatureSettingsProjectConfirm) => {
|
}: IFeatureSettingsProjectConfirm) => {
|
||||||
const dependentFeatures = useUiFlag('dependentFeatures');
|
|
||||||
const currentProjectId = useRequiredPathParam('projectId');
|
const currentProjectId = useRequiredPathParam('projectId');
|
||||||
const { project } = useProject(projectId);
|
const { project } = useProject(projectId);
|
||||||
|
|
||||||
@ -61,8 +60,7 @@ const FeatureSettingsProjectConfirm = ({
|
|||||||
: false;
|
: false;
|
||||||
|
|
||||||
const hasDependencies =
|
const hasDependencies =
|
||||||
dependentFeatures &&
|
feature.dependencies.length > 0 || feature.children.length > 0;
|
||||||
(feature.dependencies.length > 0 || feature.children.length > 0);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ConditionallyRender
|
<ConditionallyRender
|
||||||
|
@ -143,7 +143,6 @@ export const FeatureView = () => {
|
|||||||
const { refetch: projectRefetch } = useProject(projectId);
|
const { refetch: projectRefetch } = useProject(projectId);
|
||||||
const { favorite, unfavorite } = useFavoriteFeaturesApi();
|
const { favorite, unfavorite } = useFavoriteFeaturesApi();
|
||||||
const { refetchFeature } = useFeature(projectId, featureId);
|
const { refetchFeature } = useFeature(projectId, featureId);
|
||||||
const dependentFeatures = useUiFlag('dependentFeatures');
|
|
||||||
const { setToastData, setToastApiError } = useToast();
|
const { setToastData, setToastApiError } = useToast();
|
||||||
|
|
||||||
const [openTagDialog, setOpenTagDialog] = useState(false);
|
const [openTagDialog, setOpenTagDialog] = useState(false);
|
||||||
@ -267,10 +266,7 @@ export const FeatureView = () => {
|
|||||||
/>
|
/>
|
||||||
</StyledToggleInfoContainer>
|
</StyledToggleInfoContainer>
|
||||||
<ConditionallyRender
|
<ConditionallyRender
|
||||||
condition={
|
condition={feature.dependencies.length > 0}
|
||||||
dependentFeatures &&
|
|
||||||
feature.dependencies.length > 0
|
|
||||||
}
|
|
||||||
show={
|
show={
|
||||||
<StyledDependency>
|
<StyledDependency>
|
||||||
<b>Has parent: </b>
|
<b>Has parent: </b>
|
||||||
@ -283,10 +279,7 @@ export const FeatureView = () => {
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<ConditionallyRender
|
<ConditionallyRender
|
||||||
condition={
|
condition={feature.children.length > 0}
|
||||||
dependentFeatures &&
|
|
||||||
feature.children.length > 0
|
|
||||||
}
|
|
||||||
show={
|
show={
|
||||||
<StyledDependency>
|
<StyledDependency>
|
||||||
<b>Has children:</b>
|
<b>Has children:</b>
|
||||||
|
@ -75,7 +75,6 @@ exports[`should create default config 1`] = `
|
|||||||
"caseInsensitiveInOperators": false,
|
"caseInsensitiveInOperators": false,
|
||||||
"customRootRolesKillSwitch": false,
|
"customRootRolesKillSwitch": false,
|
||||||
"demo": false,
|
"demo": false,
|
||||||
"dependentFeatures": false,
|
|
||||||
"detectSegmentUsageInChangeRequests": false,
|
"detectSegmentUsageInChangeRequests": false,
|
||||||
"disableBulkToggle": false,
|
"disableBulkToggle": false,
|
||||||
"disableMetrics": false,
|
"disableMetrics": false,
|
||||||
|
@ -67,8 +67,6 @@ export default class FeatureToggleClientStore
|
|||||||
const isPlayground = requestType === 'playground';
|
const isPlayground = requestType === 'playground';
|
||||||
const environment = featureQuery?.environment || DEFAULT_ENV;
|
const environment = featureQuery?.environment || DEFAULT_ENV;
|
||||||
const stopTimer = this.timer('getFeatureAdmin');
|
const stopTimer = this.timer('getFeatureAdmin');
|
||||||
const dependentFeaturesEnabled =
|
|
||||||
this.flagResolver.isEnabled('dependentFeatures');
|
|
||||||
|
|
||||||
let selectColumns = [
|
let selectColumns = [
|
||||||
'features.name as name',
|
'features.name as name',
|
||||||
@ -201,7 +199,7 @@ export default class FeatureToggleClientStore
|
|||||||
) {
|
) {
|
||||||
this.addSegmentIdsToStrategy(feature, r);
|
this.addSegmentIdsToStrategy(feature, r);
|
||||||
}
|
}
|
||||||
if (r.parent && !isAdmin && dependentFeaturesEnabled) {
|
if (r.parent && !isAdmin) {
|
||||||
feature.dependencies = feature.dependencies || [];
|
feature.dependencies = feature.dependencies || [];
|
||||||
feature.dependencies.push({
|
feature.dependencies.push({
|
||||||
feature: r.parent,
|
feature: r.parent,
|
||||||
|
@ -64,7 +64,6 @@ beforeAll(async () => {
|
|||||||
experimental: {
|
experimental: {
|
||||||
flags: {
|
flags: {
|
||||||
strictSchemaValidation: true,
|
strictSchemaValidation: true,
|
||||||
dependentFeatures: true,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -182,25 +182,19 @@ export default class DependentFeaturesController extends Controller {
|
|||||||
const { child, projectId } = req.params;
|
const { child, projectId } = req.params;
|
||||||
const { variants, enabled, feature } = req.body;
|
const { variants, enabled, feature } = req.body;
|
||||||
|
|
||||||
if (this.config.flagResolver.isEnabled('dependentFeatures')) {
|
await this.dependentFeaturesService.transactional((service) =>
|
||||||
await this.dependentFeaturesService.transactional((service) =>
|
service.upsertFeatureDependency(
|
||||||
service.upsertFeatureDependency(
|
{ child, projectId },
|
||||||
{ child, projectId },
|
{
|
||||||
{
|
variants,
|
||||||
variants,
|
enabled,
|
||||||
enabled,
|
feature,
|
||||||
feature,
|
},
|
||||||
},
|
req.user,
|
||||||
req.user,
|
),
|
||||||
),
|
);
|
||||||
);
|
|
||||||
|
|
||||||
res.status(200).end();
|
res.status(200).end();
|
||||||
} else {
|
|
||||||
throw new InvalidOperationError(
|
|
||||||
'Dependent features are not enabled',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteFeatureDependency(
|
async deleteFeatureDependency(
|
||||||
@ -209,23 +203,17 @@ export default class DependentFeaturesController extends Controller {
|
|||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const { child, parent, projectId } = req.params;
|
const { child, parent, projectId } = req.params;
|
||||||
|
|
||||||
if (this.config.flagResolver.isEnabled('dependentFeatures')) {
|
await this.dependentFeaturesService.transactional((service) =>
|
||||||
await this.dependentFeaturesService.transactional((service) =>
|
service.deleteFeatureDependency(
|
||||||
service.deleteFeatureDependency(
|
{
|
||||||
{
|
parent,
|
||||||
parent,
|
child,
|
||||||
child,
|
},
|
||||||
},
|
projectId,
|
||||||
projectId,
|
req.user,
|
||||||
req.user,
|
),
|
||||||
),
|
);
|
||||||
);
|
res.status(200).end();
|
||||||
res.status(200).end();
|
|
||||||
} else {
|
|
||||||
throw new InvalidOperationError(
|
|
||||||
'Dependent features are not enabled',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteFeatureDependencies(
|
async deleteFeatureDependencies(
|
||||||
@ -234,20 +222,10 @@ export default class DependentFeaturesController extends Controller {
|
|||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const { child, projectId } = req.params;
|
const { child, projectId } = req.params;
|
||||||
|
|
||||||
if (this.config.flagResolver.isEnabled('dependentFeatures')) {
|
await this.dependentFeaturesService.transactional((service) =>
|
||||||
await this.dependentFeaturesService.transactional((service) =>
|
service.deleteFeaturesDependencies([child], projectId, req.user),
|
||||||
service.deleteFeaturesDependencies(
|
);
|
||||||
[child],
|
res.status(200).end();
|
||||||
projectId,
|
|
||||||
req.user,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
res.status(200).end();
|
|
||||||
} else {
|
|
||||||
throw new InvalidOperationError(
|
|
||||||
'Dependent features are not enabled',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async getParentOptions(
|
async getParentOptions(
|
||||||
@ -256,15 +234,9 @@ export default class DependentFeaturesController extends Controller {
|
|||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const { child } = req.params;
|
const { child } = req.params;
|
||||||
|
|
||||||
if (this.config.flagResolver.isEnabled('dependentFeatures')) {
|
const parentOptions =
|
||||||
const parentOptions =
|
await this.dependentFeaturesService.getParentOptions(child);
|
||||||
await this.dependentFeaturesService.getParentOptions(child);
|
res.send(parentOptions);
|
||||||
res.send(parentOptions);
|
|
||||||
} else {
|
|
||||||
throw new InvalidOperationError(
|
|
||||||
'Dependent features are not enabled',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async checkDependenciesExist(
|
async checkDependenciesExist(
|
||||||
@ -273,14 +245,8 @@ export default class DependentFeaturesController extends Controller {
|
|||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const { child } = req.params;
|
const { child } = req.params;
|
||||||
|
|
||||||
if (this.config.flagResolver.isEnabled('dependentFeatures')) {
|
const exist =
|
||||||
const exist =
|
await this.dependentFeaturesService.checkDependenciesExist();
|
||||||
await this.dependentFeaturesService.checkDependenciesExist();
|
res.send(exist);
|
||||||
res.send(exist);
|
|
||||||
} else {
|
|
||||||
throw new InvalidOperationError(
|
|
||||||
'Dependent features are not enabled',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,6 @@ beforeAll(async () => {
|
|||||||
experimental: {
|
experimental: {
|
||||||
flags: {
|
flags: {
|
||||||
strictSchemaValidation: true,
|
strictSchemaValidation: true,
|
||||||
dependentFeatures: true,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -159,7 +159,6 @@ beforeAll(async () => {
|
|||||||
experimental: {
|
experimental: {
|
||||||
flags: {
|
flags: {
|
||||||
featuresExportImport: true,
|
featuresExportImport: true,
|
||||||
dependentFeatures: true,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -202,7 +202,6 @@ export class FeatureToggleRowConverter {
|
|||||||
|
|
||||||
buildPlaygroundFeaturesFromRows = (
|
buildPlaygroundFeaturesFromRows = (
|
||||||
rows: any[],
|
rows: any[],
|
||||||
dependentFeaturesEnabled: boolean,
|
|
||||||
featureQuery?: IFeatureToggleQuery,
|
featureQuery?: IFeatureToggleQuery,
|
||||||
): FeatureConfigurationClient[] => {
|
): FeatureConfigurationClient[] => {
|
||||||
const result = rows.reduce((acc, r) => {
|
const result = rows.reduce((acc, r) => {
|
||||||
@ -212,7 +211,7 @@ export class FeatureToggleRowConverter {
|
|||||||
|
|
||||||
feature = this.createBaseFeature(r, feature, featureQuery);
|
feature = this.createBaseFeature(r, feature, featureQuery);
|
||||||
|
|
||||||
if (r.parent && dependentFeaturesEnabled) {
|
if (r.parent) {
|
||||||
feature.dependencies = feature.dependencies || [];
|
feature.dependencies = feature.dependencies || [];
|
||||||
feature.dependencies.push({
|
feature.dependencies.push({
|
||||||
feature: r.parent,
|
feature: r.parent,
|
||||||
|
@ -130,6 +130,7 @@ export type FeatureNameCheckResultWithFeaturePattern =
|
|||||||
const oneOf = (values: string[], match: string) => {
|
const oneOf = (values: string[], match: string) => {
|
||||||
return values.some((value) => value === match);
|
return values.some((value) => value === match);
|
||||||
};
|
};
|
||||||
|
|
||||||
class FeatureToggleService {
|
class FeatureToggleService {
|
||||||
private logger: Logger;
|
private logger: Logger;
|
||||||
|
|
||||||
@ -256,32 +257,27 @@ class FeatureToggleService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async validateNoChildren(featureName: string): Promise<void> {
|
async validateNoChildren(featureName: string): Promise<void> {
|
||||||
if (this.flagResolver.isEnabled('dependentFeatures')) {
|
const children = await this.dependentFeaturesReadModel.getChildren([
|
||||||
const children = await this.dependentFeaturesReadModel.getChildren([
|
featureName,
|
||||||
featureName,
|
]);
|
||||||
]);
|
if (children.length > 0) {
|
||||||
if (children.length > 0) {
|
throw new InvalidOperationError(
|
||||||
throw new InvalidOperationError(
|
'You can not archive/delete this feature since other features depend on it.',
|
||||||
'You can not archive/delete this feature since other features depend on it.',
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async validateNoOrphanParents(featureNames: string[]): Promise<void> {
|
async validateNoOrphanParents(featureNames: string[]): Promise<void> {
|
||||||
if (this.flagResolver.isEnabled('dependentFeatures')) {
|
if (featureNames.length === 0) return;
|
||||||
if (featureNames.length === 0) return;
|
const parents = await this.dependentFeaturesReadModel.getOrphanParents(
|
||||||
const parents =
|
featureNames,
|
||||||
await this.dependentFeaturesReadModel.getOrphanParents(
|
);
|
||||||
featureNames,
|
if (parents.length > 0) {
|
||||||
);
|
throw new InvalidOperationError(
|
||||||
if (parents.length > 0) {
|
featureNames.length > 1
|
||||||
throw new InvalidOperationError(
|
? `You can not archive/delete those features since other features depend on them.`
|
||||||
featureNames.length > 1
|
: `You can not archive/delete this feature since other features depend on it.`,
|
||||||
? `You can not archive/delete those features since other features depend on them.`
|
);
|
||||||
: `You can not archive/delete this feature since other features depend on it.`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -959,12 +955,10 @@ class FeatureToggleService {
|
|||||||
|
|
||||||
let dependencies: IDependency[] = [];
|
let dependencies: IDependency[] = [];
|
||||||
let children: string[] = [];
|
let children: string[] = [];
|
||||||
if (this.flagResolver.isEnabled('dependentFeatures')) {
|
[dependencies, children] = await Promise.all([
|
||||||
[dependencies, children] = await Promise.all([
|
this.dependentFeaturesReadModel.getParents(featureName),
|
||||||
this.dependentFeaturesReadModel.getParents(featureName),
|
this.dependentFeaturesReadModel.getChildren([featureName]),
|
||||||
this.dependentFeaturesReadModel.getChildren([featureName]),
|
]);
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (environmentVariants) {
|
if (environmentVariants) {
|
||||||
const result =
|
const result =
|
||||||
@ -1288,21 +1282,17 @@ class FeatureToggleService {
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (this.flagResolver.isEnabled('dependentFeatures')) {
|
const cloneDependencies =
|
||||||
const cloneDependencies =
|
this.dependentFeaturesService.cloneDependencies(
|
||||||
this.dependentFeaturesService.cloneDependencies(
|
{ featureName, newFeatureName, projectId },
|
||||||
{ featureName, newFeatureName, projectId },
|
userName,
|
||||||
userName,
|
);
|
||||||
);
|
|
||||||
|
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
...strategyTasks,
|
...strategyTasks,
|
||||||
...variantTasks,
|
...variantTasks,
|
||||||
cloneDependencies,
|
cloneDependencies,
|
||||||
]);
|
]);
|
||||||
} else {
|
|
||||||
await Promise.all([...strategyTasks, ...variantTasks]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return created;
|
return created;
|
||||||
}
|
}
|
||||||
|
@ -209,16 +209,11 @@ export default class FeatureToggleStore implements IFeatureToggleStore {
|
|||||||
const archived = false;
|
const archived = false;
|
||||||
const builder = this.getBaseFeatureQuery(archived, environment);
|
const builder = this.getBaseFeatureQuery(archived, environment);
|
||||||
|
|
||||||
const dependentFeaturesEnabled =
|
builder.withDependentFeatureToggles();
|
||||||
this.flagResolver.isEnabled('dependentFeatures');
|
|
||||||
|
|
||||||
if (dependentFeaturesEnabled) {
|
builder.addSelectColumn('df.parent as parent');
|
||||||
builder.withDependentFeatureToggles();
|
builder.addSelectColumn('df.variants as parent_variants');
|
||||||
|
builder.addSelectColumn('df.enabled as parent_enabled');
|
||||||
builder.addSelectColumn('df.parent as parent');
|
|
||||||
builder.addSelectColumn('df.variants as parent_variants');
|
|
||||||
builder.addSelectColumn('df.enabled as parent_enabled');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (featureQuery?.project) {
|
if (featureQuery?.project) {
|
||||||
builder.forProject(featureQuery.project);
|
builder.forProject(featureQuery.project);
|
||||||
@ -230,7 +225,6 @@ export default class FeatureToggleStore implements IFeatureToggleStore {
|
|||||||
|
|
||||||
return this.featureToggleRowConverter.buildPlaygroundFeaturesFromRows(
|
return this.featureToggleRowConverter.buildPlaygroundFeaturesFromRows(
|
||||||
rows,
|
rows,
|
||||||
dependentFeaturesEnabled,
|
|
||||||
featureQuery,
|
featureQuery,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,6 @@ beforeAll(async () => {
|
|||||||
experimental: {
|
experimental: {
|
||||||
flags: {
|
flags: {
|
||||||
strictSchemaValidation: true,
|
strictSchemaValidation: true,
|
||||||
dependentFeatures: true,
|
|
||||||
useLastSeenRefactor: true,
|
useLastSeenRefactor: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -93,7 +93,6 @@ beforeAll(async () => {
|
|||||||
experimental: {
|
experimental: {
|
||||||
flags: {
|
flags: {
|
||||||
strictSchemaValidation: true,
|
strictSchemaValidation: true,
|
||||||
dependentFeatures: true,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -10,11 +10,7 @@ let app: IUnleashTest;
|
|||||||
let db: ITestDb;
|
let db: ITestDb;
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
db = await dbInit('advanced_playground', getLogger, {
|
db = await dbInit('advanced_playground', getLogger);
|
||||||
experimental: {
|
|
||||||
flags: { dependentFeatures: true },
|
|
||||||
},
|
|
||||||
});
|
|
||||||
app = await setupAppWithCustomConfig(
|
app = await setupAppWithCustomConfig(
|
||||||
db.stores,
|
db.stores,
|
||||||
{
|
{
|
||||||
@ -24,7 +20,6 @@ beforeAll(async () => {
|
|||||||
strictSchemaValidation: true,
|
strictSchemaValidation: true,
|
||||||
strategyVariant: true,
|
strategyVariant: true,
|
||||||
privateProjects: true,
|
privateProjects: true,
|
||||||
dependentFeatures: true,
|
|
||||||
useLastSeenRefactor: true,
|
useLastSeenRefactor: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -24,7 +24,6 @@ export type IFlagKey =
|
|||||||
| 'filterInvalidClientMetrics'
|
| 'filterInvalidClientMetrics'
|
||||||
| 'customRootRolesKillSwitch'
|
| 'customRootRolesKillSwitch'
|
||||||
| 'privateProjects'
|
| 'privateProjects'
|
||||||
| 'dependentFeatures'
|
|
||||||
| 'disableMetrics'
|
| 'disableMetrics'
|
||||||
| 'useLastSeenRefactor'
|
| 'useLastSeenRefactor'
|
||||||
| 'banners'
|
| 'banners'
|
||||||
@ -107,10 +106,6 @@ const flags: IFlags = {
|
|||||||
process.env.UNLEASH_EXPERIMENTAL_CUSTOM_ROOT_ROLES_KILL_SWITCH,
|
process.env.UNLEASH_EXPERIMENTAL_CUSTOM_ROOT_ROLES_KILL_SWITCH,
|
||||||
false,
|
false,
|
||||||
),
|
),
|
||||||
dependentFeatures: parseEnvVarBoolean(
|
|
||||||
process.env.UNLEASH_EXPERIMENTAL_DEPENDENT_FEATURES,
|
|
||||||
false,
|
|
||||||
),
|
|
||||||
privateProjects: parseEnvVarBoolean(
|
privateProjects: parseEnvVarBoolean(
|
||||||
process.env.UNLEASH_EXPERIMENTAL_PRIVATE_PROJECTS,
|
process.env.UNLEASH_EXPERIMENTAL_PRIVATE_PROJECTS,
|
||||||
false,
|
false,
|
||||||
|
@ -38,7 +38,6 @@ process.nextTick(async () => {
|
|||||||
anonymiseEventLog: false,
|
anonymiseEventLog: false,
|
||||||
responseTimeWithAppNameKillSwitch: false,
|
responseTimeWithAppNameKillSwitch: false,
|
||||||
privateProjects: true,
|
privateProjects: true,
|
||||||
dependentFeatures: true,
|
|
||||||
useLastSeenRefactor: true,
|
useLastSeenRefactor: true,
|
||||||
featureSearchAPI: true,
|
featureSearchAPI: true,
|
||||||
featureSearchFrontend: false,
|
featureSearchFrontend: false,
|
||||||
|
@ -17,7 +17,6 @@ beforeAll(async () => {
|
|||||||
experimental: {
|
experimental: {
|
||||||
flags: {
|
flags: {
|
||||||
strictSchemaValidation: true,
|
strictSchemaValidation: true,
|
||||||
dependentFeatures: true,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -12,16 +12,13 @@ let db: ITestDb;
|
|||||||
const testUser = { name: 'test' } as User;
|
const testUser = { name: 'test' } as User;
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
db = await dbInit('feature_api_client', getLogger, {
|
db = await dbInit('feature_api_client', getLogger);
|
||||||
experimental: { flags: { dependentFeatures: true } },
|
|
||||||
});
|
|
||||||
app = await setupAppWithCustomConfig(
|
app = await setupAppWithCustomConfig(
|
||||||
db.stores,
|
db.stores,
|
||||||
{
|
{
|
||||||
experimental: {
|
experimental: {
|
||||||
flags: {
|
flags: {
|
||||||
strictSchemaValidation: true,
|
strictSchemaValidation: true,
|
||||||
dependentFeatures: true,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user