mirror of
				https://github.com/Unleash/unleash.git
				synced 2025-10-27 11:02:16 +01:00 
			
		
		
		
	feat: dependant flag on feature search (#6684)
This commit is contained in:
		
							parent
							
								
									d4f52cdb54
								
							
						
					
					
						commit
						283a8f4d8b
					
				@ -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] : [],
 | 
				
			||||||
                };
 | 
					                };
 | 
				
			||||||
 | 
				
			|||||||
@ -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,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
				
			|||||||
@ -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: {
 | 
				
			||||||
 | 
				
			|||||||
@ -223,6 +223,7 @@ export type IFeatureSearchOverview = Exclude<
 | 
				
			|||||||
    IFeatureOverview,
 | 
					    IFeatureOverview,
 | 
				
			||||||
    'environments'
 | 
					    'environments'
 | 
				
			||||||
> & {
 | 
					> & {
 | 
				
			||||||
 | 
					    dependencyType: 'parent' | 'child' | null;
 | 
				
			||||||
    environments: FeatureSearchEnvironmentSchema[];
 | 
					    environments: FeatureSearchEnvironmentSchema[];
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user