1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-03-18 00:19:49 +01:00

feat: dependant flag on feature search (#6684)

This commit is contained in:
Jaanus Sellin 2024-03-25 15:45:18 +02:00 committed by GitHub
parent d4f52cdb54
commit 283a8f4d8b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 92 additions and 47 deletions

View File

@ -137,6 +137,11 @@ class FeatureSearchStore implements IFeatureSearchStore {
this.db.raw( this.db.raw(
'EXISTS (SELECT 1 FROM feature_strategies WHERE feature_strategies.feature_name = features.name AND feature_strategies.environment = feature_environments.environment AND (feature_strategies.disabled IS NULL OR feature_strategies.disabled = false)) as has_enabled_strategies', 'EXISTS (SELECT 1 FROM feature_strategies WHERE feature_strategies.feature_name = features.name AND feature_strategies.environment = feature_environments.environment AND (feature_strategies.disabled IS NULL OR feature_strategies.disabled = false)) as has_enabled_strategies',
), ),
this.db.raw(`CASE
WHEN dependent_features.parent = features.name THEN 'parent'
WHEN dependent_features.child = features.name THEN 'child'
ELSE null
END AS dependency`),
]; ];
applyQueryParams(query, queryParams); applyQueryParams(query, queryParams);
@ -197,6 +202,17 @@ class FeatureSearchStore implements IFeatureSearchStore {
'feature_strategy_segment.segment_id', 'feature_strategy_segment.segment_id',
'segments.id', 'segments.id',
) )
.leftJoin('dependent_features', (qb) => {
qb.on(
'dependent_features.parent',
'=',
'features.name',
).orOn(
'dependent_features.child',
'=',
'features.name',
);
})
.leftJoin('client_metrics_env', (qb) => { .leftJoin('client_metrics_env', (qb) => {
qb.on( qb.on(
'client_metrics_env.environment', 'client_metrics_env.environment',
@ -335,6 +351,7 @@ class FeatureSearchStore implements IFeatureSearchStore {
stale: row.stale, stale: row.stale,
impressionData: row.impression_data, impressionData: row.impression_data,
lastSeenAt: row.last_seen_at, lastSeenAt: row.last_seen_at,
dependencyType: row.dependency,
environments: [], environments: [],
segments: row.segment_name ? [row.segment_name] : [], segments: row.segment_name ? [row.segment_name] : [],
}; };

View File

@ -977,3 +977,57 @@ test('should return environment usage metrics', async () => {
], ],
}); });
}); });
test('should return dependencyType', async () => {
await app.createFeature({
name: 'my_feature_a',
createdAt: '2023-01-29T15:21:39.975Z',
});
await app.createFeature({
name: 'my_feature_b',
createdAt: '2023-01-29T15:21:39.975Z',
});
await app.createFeature({
name: 'my_feature_c',
createdAt: '2023-01-29T15:21:39.975Z',
});
await app.createFeature({
name: 'my_feature_d',
createdAt: '2023-01-29T15:21:39.975Z',
});
await stores.dependentFeaturesStore.upsert({
child: 'my_feature_b',
parent: 'my_feature_a',
enabled: true,
});
await stores.dependentFeaturesStore.upsert({
child: 'my_feature_c',
parent: 'my_feature_a',
enabled: true,
});
const { body } = await searchFeatures({
query: 'my_feature',
});
expect(body).toMatchObject({
features: [
{
name: 'my_feature_a',
dependencyType: 'parent',
},
{
name: 'my_feature_b',
dependencyType: 'child',
},
{
name: 'my_feature_c',
dependencyType: 'child',
},
{
name: 'my_feature_d',
dependencyType: null,
},
],
});
});

View File

@ -12,7 +12,18 @@ export const featureSearchResponseSchema = {
$id: '#/components/schemas/featureSearchResponseSchema', $id: '#/components/schemas/featureSearchResponseSchema',
type: 'object', type: 'object',
additionalProperties: false, additionalProperties: false,
required: ['name'], required: [
'name',
'dependencyType',
'type',
'project',
'stale',
'favorite',
'impressionData',
'createdAt',
'environments',
'segments',
],
description: 'A feature toggle definition', description: 'A feature toggle definition',
properties: { properties: {
name: { name: {
@ -33,6 +44,14 @@ export const featureSearchResponseSchema = {
'Controls disabling of the comments section in case of an incident', 'Controls disabling of the comments section in case of an incident',
description: 'Detailed description of the feature', description: 'Detailed description of the feature',
}, },
dependencyType: {
type: 'string',
enum: ['parent', 'child', null],
nullable: true,
example: 'parent',
description:
"The type of dependency. 'parent' means that the feature is a parent feature, 'child' means that the feature is a child feature.",
},
archived: { archived: {
type: 'boolean', type: 'boolean',
example: true, example: true,
@ -43,11 +62,6 @@ export const featureSearchResponseSchema = {
example: 'dx-squad', example: 'dx-squad',
description: 'Name of the project the feature belongs to', description: 'Name of the project the feature belongs to',
}, },
enabled: {
type: 'boolean',
example: true,
description: '`true` if the feature is enabled, otherwise `false`.',
},
stale: { stale: {
type: 'boolean', type: 'boolean',
example: false, example: false,
@ -129,47 +143,6 @@ export const featureSearchResponseSchema = {
nullable: true, nullable: true,
description: 'The list of feature tags', description: 'The list of feature tags',
}, },
children: {
type: 'array',
description:
'The list of child feature names. This is an experimental field and may change.',
items: {
type: 'string',
example: 'some-feature',
},
},
dependencies: {
type: 'array',
items: {
type: 'object',
additionalProperties: false,
required: ['feature'],
properties: {
feature: {
description: 'The name of the parent feature',
type: 'string',
example: 'some-feature',
},
enabled: {
description:
'Whether the parent feature is enabled or not',
type: 'boolean',
example: true,
},
variants: {
description:
'The list of variants the parent feature should resolve to. Only valid when feature is enabled.',
type: 'array',
items: {
example: 'some-feature-blue-variant',
type: 'string',
},
},
},
},
description:
'The list of parent dependencies. This is an experimental field and may change.',
},
}, },
components: { components: {
schemas: { schemas: {

View File

@ -223,6 +223,7 @@ export type IFeatureSearchOverview = Exclude<
IFeatureOverview, IFeatureOverview,
'environments' 'environments'
> & { > & {
dependencyType: 'parent' | 'child' | null;
environments: FeatureSearchEnvironmentSchema[]; environments: FeatureSearchEnvironmentSchema[];
}; };