mirror of
https://github.com/Unleash/unleash.git
synced 2025-02-09 00:18:00 +01:00
feat: add option to return disabled strategies (#5059)
Adds the option to include disabled strategies (behind the playgroundImprovements flag Closes # [1-1505](https://linear.app/unleash/issue/1-1505/return-disabled-strategies-in-the-playground-features-request) --------- Signed-off-by: andreas-unleash <andreas@getunleash.ai>
This commit is contained in:
parent
04568ebde8
commit
cf42a829f4
@ -70,6 +70,7 @@ export class FeatureToggleRowConverter {
|
||||
constraints: row.constraints || [],
|
||||
parameters: mapValues(row.parameters || {}, ensureStringValue),
|
||||
sortOrder: row.sort_order,
|
||||
disabled: row.strategy_disabled,
|
||||
};
|
||||
strategy.variants = row.strategy_variants || [];
|
||||
return strategy;
|
||||
@ -111,6 +112,7 @@ export class FeatureToggleRowConverter {
|
||||
row: any,
|
||||
feature: PartialDeep<IFeatureToggleClient>,
|
||||
featureQuery?: IFeatureToggleQuery,
|
||||
includeDisabledStrategies?: boolean,
|
||||
) => {
|
||||
feature.impressionData = row.impression_data;
|
||||
feature.enabled = !!row.enabled;
|
||||
@ -123,7 +125,10 @@ export class FeatureToggleRowConverter {
|
||||
feature.variants = row.variants || [];
|
||||
feature.project = row.project;
|
||||
|
||||
if (this.isUnseenStrategyRow(feature, row) && !row.strategy_disabled) {
|
||||
if (
|
||||
this.isUnseenStrategyRow(feature, row) &&
|
||||
(includeDisabledStrategies ? true : !row.strategy_disabled)
|
||||
) {
|
||||
feature.strategies?.push(this.rowToStrategy(row));
|
||||
}
|
||||
if (this.isNewTag(feature, row)) {
|
||||
@ -141,13 +146,19 @@ export class FeatureToggleRowConverter {
|
||||
buildFeatureToggleListFromRows = (
|
||||
rows: any[],
|
||||
featureQuery?: IFeatureToggleQuery,
|
||||
includeDisabledStrategies?: boolean,
|
||||
): FeatureToggle[] => {
|
||||
const result = rows.reduce((acc, r) => {
|
||||
let feature: PartialDeep<IFeatureToggleClient> = acc[r.name] ?? {
|
||||
strategies: [],
|
||||
};
|
||||
|
||||
feature = this.createBaseFeature(r, feature, featureQuery);
|
||||
feature = this.createBaseFeature(
|
||||
r,
|
||||
feature,
|
||||
featureQuery,
|
||||
includeDisabledStrategies,
|
||||
);
|
||||
|
||||
feature.createdAt = r.created_at;
|
||||
feature.favorite = r.favorite;
|
||||
@ -162,6 +173,7 @@ export class FeatureToggleRowConverter {
|
||||
buildPlaygroundFeaturesFromRows = (
|
||||
rows: any[],
|
||||
dependentFeaturesEnabled: boolean,
|
||||
includeDisabledStrategies: boolean,
|
||||
featureQuery?: IFeatureToggleQuery,
|
||||
): FeatureConfigurationClient[] => {
|
||||
const result = rows.reduce((acc, r) => {
|
||||
@ -169,7 +181,12 @@ export class FeatureToggleRowConverter {
|
||||
strategies: [],
|
||||
};
|
||||
|
||||
feature = this.createBaseFeature(r, feature, featureQuery);
|
||||
feature = this.createBaseFeature(
|
||||
r,
|
||||
feature,
|
||||
featureQuery,
|
||||
includeDisabledStrategies,
|
||||
);
|
||||
|
||||
if (r.parent && dependentFeaturesEnabled) {
|
||||
feature.dependencies = feature.dependencies || [];
|
||||
|
@ -165,6 +165,7 @@ export default class FakeFeatureToggleStore implements IFeatureToggleStore {
|
||||
|
||||
async getPlaygroundFeatures(
|
||||
dependentFeaturesEnabled: boolean,
|
||||
includeDisabledStrategies: boolean,
|
||||
query?: IFeatureToggleQuery,
|
||||
): Promise<FeatureConfigurationClient[]> {
|
||||
return this.features.filter(
|
||||
|
@ -1056,6 +1056,7 @@ class FeatureToggleService {
|
||||
await this.clientFeatureToggleStore.getPlayground(query || {}),
|
||||
await this.featureToggleStore.getPlaygroundFeatures(
|
||||
this.flagResolver.isEnabled('dependentFeatures'),
|
||||
this.flagResolver.isEnabled('playgroundImprovements'),
|
||||
query,
|
||||
),
|
||||
]);
|
||||
|
@ -123,6 +123,7 @@ export default class FeatureToggleStore implements IFeatureToggleStore {
|
||||
featureQuery?: IFeatureToggleQuery,
|
||||
userId?: number,
|
||||
archived: boolean = false,
|
||||
includeDisabledStrategies: boolean = false,
|
||||
): Promise<FeatureToggle[]> {
|
||||
const environment = featureQuery?.environment || DEFAULT_ENV;
|
||||
|
||||
@ -150,11 +151,13 @@ export default class FeatureToggleStore implements IFeatureToggleStore {
|
||||
return this.featureToggleRowConverter.buildFeatureToggleListFromRows(
|
||||
rows,
|
||||
featureQuery,
|
||||
includeDisabledStrategies,
|
||||
);
|
||||
}
|
||||
|
||||
async getPlaygroundFeatures(
|
||||
dependentFeaturesEnabled: boolean,
|
||||
includeDisabledStrategies: boolean,
|
||||
featureQuery: IFeatureToggleQuery,
|
||||
): Promise<FeatureConfigurationClient[]> {
|
||||
const environment = featureQuery?.environment || DEFAULT_ENV;
|
||||
@ -177,6 +180,7 @@ export default class FeatureToggleStore implements IFeatureToggleStore {
|
||||
return this.featureToggleRowConverter.buildPlaygroundFeaturesFromRows(
|
||||
rows,
|
||||
dependentFeaturesEnabled,
|
||||
includeDisabledStrategies,
|
||||
featureQuery,
|
||||
);
|
||||
}
|
||||
|
@ -39,6 +39,7 @@ export interface IFeatureToggleStore extends Store<FeatureToggle, string> {
|
||||
): Promise<FeatureToggle[]>;
|
||||
getPlaygroundFeatures(
|
||||
dependentFeaturesEnabled: boolean,
|
||||
includeDisabledStrategies: boolean,
|
||||
featureQuery?: IFeatureToggleQuery,
|
||||
): Promise<FeatureConfigurationClient[]>;
|
||||
countByDate(queryModifiers: {
|
||||
|
@ -11,7 +11,9 @@ let db: ITestDb;
|
||||
|
||||
beforeAll(async () => {
|
||||
db = await dbInit('advanced_playground', getLogger, {
|
||||
experimental: { flags: { dependentFeatures: true } },
|
||||
experimental: {
|
||||
flags: { dependentFeatures: true, playgroundImprovements: true },
|
||||
},
|
||||
});
|
||||
app = await setupAppWithCustomConfig(
|
||||
db.stores,
|
||||
@ -23,6 +25,9 @@ beforeAll(async () => {
|
||||
strategyVariant: true,
|
||||
privateProjects: true,
|
||||
dependentFeatures: true,
|
||||
playgroundImprovements: true,
|
||||
useLastSeenRefactor: true,
|
||||
separateAdminClientApi: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -327,6 +332,7 @@ test('show matching variant from variants selection only for enabled toggles', a
|
||||
variants,
|
||||
},
|
||||
);
|
||||
|
||||
await enableToggle('test-playground-feature-with-variants');
|
||||
|
||||
const { body: result } = await app.request
|
||||
@ -357,3 +363,41 @@ test('show matching variant from variants selection only for enabled toggles', a
|
||||
expect(feature.variants).toMatchObject([]);
|
||||
});
|
||||
});
|
||||
|
||||
test('should return disabled strategies with unevaluated result', async () => {
|
||||
await createFeatureToggleWithStrategy(
|
||||
'test-playground-feature-with-disabled-strategy',
|
||||
{
|
||||
name: 'flexibleRollout',
|
||||
constraints: [],
|
||||
disabled: true,
|
||||
parameters: {
|
||||
rollout: '50',
|
||||
stickiness: 'random',
|
||||
groupId: 'test-playground-feature-with-variants',
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
const { body: result } = await app.request
|
||||
.post('/api/admin/playground/advanced')
|
||||
.send({
|
||||
environments: ['default'],
|
||||
projects: ['default'],
|
||||
context: { appName: 'playground' },
|
||||
})
|
||||
.set('Content-Type', 'application/json')
|
||||
.expect(200);
|
||||
|
||||
const typedResult: AdvancedPlaygroundResponseSchema = result;
|
||||
|
||||
const feature = typedResult.features.find(
|
||||
(feature) =>
|
||||
feature.name === 'test-playground-feature-with-disabled-strategy',
|
||||
);
|
||||
|
||||
expect(
|
||||
feature?.environments.default[0].strategies.data[0].result
|
||||
.evaluationStatus,
|
||||
).toBe('unevaluated');
|
||||
});
|
||||
|
@ -44,7 +44,6 @@ export default class UnleashClient {
|
||||
!strategy ||
|
||||
!strategy.name ||
|
||||
typeof strategy.name !== 'string' ||
|
||||
!strategy.isEnabled ||
|
||||
typeof strategy.isEnabled !== 'function'
|
||||
) {
|
||||
throw new Error('Invalid strategy data / interface');
|
||||
|
@ -145,9 +145,20 @@ export class Strategy {
|
||||
}
|
||||
: undefined;
|
||||
|
||||
if (disabled) {
|
||||
return {
|
||||
result: {
|
||||
enabled: 'unknown',
|
||||
evaluationStatus: 'unevaluated',
|
||||
},
|
||||
constraints: constraintResults.constraints,
|
||||
segments: segmentResults.segments,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
result: {
|
||||
enabled: disabled ? false : overallResult,
|
||||
enabled: overallResult,
|
||||
evaluationStatus: 'complete',
|
||||
variant,
|
||||
variants: variant ? variantDefinitions : undefined,
|
||||
|
@ -8,6 +8,7 @@ import { overrideSchema } from './override-schema';
|
||||
export const playgroundStrategyEvaluation = {
|
||||
evaluationComplete: 'complete',
|
||||
evaluationIncomplete: 'incomplete',
|
||||
unevaluated: 'unevaluated',
|
||||
unknownResult: 'unknown',
|
||||
} as const;
|
||||
|
||||
@ -21,8 +22,11 @@ export const strategyEvaluationResults = {
|
||||
evaluationStatus: {
|
||||
type: 'string',
|
||||
description:
|
||||
"Signals that this strategy could not be evaluated. This is most likely because you're using a custom strategy that Unleash doesn't know about.",
|
||||
enum: [playgroundStrategyEvaluation.evaluationIncomplete],
|
||||
"Signals that this strategy could not be evaluated. This is most likely because you're using a custom strategy that Unleash doesn't know about. The `unevaluated` result is also returned if the strategy is disabled.",
|
||||
enum: [
|
||||
playgroundStrategyEvaluation.evaluationIncomplete,
|
||||
playgroundStrategyEvaluation.unevaluated,
|
||||
],
|
||||
},
|
||||
enabled: {
|
||||
description:
|
||||
|
@ -48,6 +48,7 @@ process.nextTick(async () => {
|
||||
dependentFeatures: true,
|
||||
useLastSeenRefactor: true,
|
||||
separateAdminClientApi: true,
|
||||
playgroundImprovements: true,
|
||||
},
|
||||
},
|
||||
authentication: {
|
||||
|
Loading…
Reference in New Issue
Block a user