mirror of
				https://github.com/Unleash/unleash.git
				synced 2025-10-27 11:02:16 +01:00 
			
		
		
		
	feat: draft branch playground evaluation (#3967)
This commit is contained in:
		
							parent
							
								
									7d69750f3b
								
							
						
					
					
						commit
						555f77463d
					
				| @ -137,6 +137,7 @@ | ||||
|     "json2csv": "^5.0.7", | ||||
|     "knex": "^2.4.2", | ||||
|     "lodash.get": "^4.4.2", | ||||
|     "lodash.groupby": "^4.6.0", | ||||
|     "log4js": "^6.0.0", | ||||
|     "make-fetch-happen": "^11.0.0", | ||||
|     "memoizee": "^0.4.15", | ||||
| @ -175,6 +176,7 @@ | ||||
|     "@types/hash-sum": "^1.0.0", | ||||
|     "@types/jest": "29.5.2", | ||||
|     "@types/js-yaml": "4.0.5", | ||||
|     "@types/lodash.groupby": "4.6.7", | ||||
|     "@types/make-fetch-happen": "10.0.1", | ||||
|     "@types/memoizee": "0.4.8", | ||||
|     "@types/mime": "3.0.1", | ||||
|  | ||||
| @ -11,12 +11,20 @@ import { FeatureStrategiesEvaluationResult } from 'lib/features/playground/featu | ||||
| import { ISegmentService } from 'lib/segments/segment-service-interface'; | ||||
| import { FeatureConfigurationClient } from '../../types/stores/feature-strategies-store'; | ||||
| import { generateObjectCombinations } from './generateObjectCombinations'; | ||||
| import groupBy from 'lodash.groupby'; | ||||
| import { omitKeys } from '../../util'; | ||||
| 
 | ||||
| type EvaluationInput = { | ||||
|     features: FeatureConfigurationClient[]; | ||||
|     segments: ISegment[]; | ||||
|     featureProject: Record<string, string>; | ||||
|     context: SdkContextSchema; | ||||
|     environment: string; | ||||
| }; | ||||
| 
 | ||||
| type AdvancedPlaygroundFeatureSchema = PlaygroundFeatureSchema & { | ||||
|     context: SdkContextSchema; | ||||
|     environment: string; | ||||
| }; | ||||
| 
 | ||||
| export class PlaygroundService { | ||||
| @ -42,7 +50,7 @@ export class PlaygroundService { | ||||
|         projects: typeof ALL | string[], | ||||
|         environments: string[], | ||||
|         context: SdkContextSchema, | ||||
|     ): Promise<PlaygroundFeatureSchema[]> { | ||||
|     ): Promise<any> { | ||||
|         const segments = await this.segmentService.getActive(); | ||||
|         const environmentFeatures = await Promise.all( | ||||
|             environments.map((env) => this.resolveFeatures(projects, env)), | ||||
| @ -50,18 +58,32 @@ export class PlaygroundService { | ||||
|         const contexts = generateObjectCombinations(context); | ||||
| 
 | ||||
|         const results = await Promise.all( | ||||
|             environmentFeatures.flatMap(({ features, featureProject }) => | ||||
|                 contexts.map((singleContext) => | ||||
|                     this.evaluate({ | ||||
|                         features, | ||||
|                         featureProject, | ||||
|                         context: singleContext, | ||||
|                         segments, | ||||
|                     }), | ||||
|                 ), | ||||
|             environmentFeatures.flatMap( | ||||
|                 ({ features, featureProject, environment }) => | ||||
|                     contexts.map((singleContext) => | ||||
|                         this.evaluate({ | ||||
|                             features, | ||||
|                             featureProject, | ||||
|                             context: singleContext, | ||||
|                             segments, | ||||
|                             environment, | ||||
|                         }), | ||||
|                     ), | ||||
|             ), | ||||
|         ); | ||||
|         return results.flat(); | ||||
|         const items = results.flat(); | ||||
|         const itemsByName = groupBy(items, (item) => item.name); | ||||
|         return Object.entries(itemsByName).map(([name, entries]) => { | ||||
|             const groupedEnvironments = groupBy( | ||||
|                 entries, | ||||
|                 (entry) => entry.environment, | ||||
|             ); | ||||
|             return { | ||||
|                 name, | ||||
|                 projectId: entries[0]?.projectId, | ||||
|                 environments: groupedEnvironments, | ||||
|             }; | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     private async evaluate({ | ||||
| @ -69,7 +91,8 @@ export class PlaygroundService { | ||||
|         features, | ||||
|         segments, | ||||
|         context, | ||||
|     }: EvaluationInput): Promise<PlaygroundFeatureSchema[]> { | ||||
|         environment, | ||||
|     }: EvaluationInput): Promise<AdvancedPlaygroundFeatureSchema[]> { | ||||
|         const [head, ...rest] = features; | ||||
|         if (!head) { | ||||
|             return []; | ||||
| @ -92,7 +115,7 @@ export class PlaygroundService { | ||||
|                     ? new Date(context.currentTime) | ||||
|                     : undefined, | ||||
|             }; | ||||
|             const output: PlaygroundFeatureSchema[] = client | ||||
|             return client | ||||
|                 .getFeatureToggleDefinitions() | ||||
|                 .map((feature: FeatureInterface) => { | ||||
|                     const strategyEvaluationResult: FeatureStrategiesEvaluationResult = | ||||
| @ -112,18 +135,22 @@ export class PlaygroundService { | ||||
|                         projectId: featureProject[feature.name], | ||||
|                         variant: client.getVariant(feature.name, clientContext), | ||||
|                         name: feature.name, | ||||
|                         environment, | ||||
|                         context, | ||||
|                         variants: variantsMap[feature.name] || [], | ||||
|                     }; | ||||
|                 }); | ||||
| 
 | ||||
|             return output; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private async resolveFeatures( | ||||
|         projects: typeof ALL | string[], | ||||
|         environment: string, | ||||
|     ): Promise<Pick<EvaluationInput, 'features' | 'featureProject'>> { | ||||
|     ): Promise< | ||||
|         Pick<EvaluationInput, 'features' | 'featureProject'> & { | ||||
|             environment: string; | ||||
|         } | ||||
|     > { | ||||
|         const features = await this.featureToggleService.getClientFeatures( | ||||
|             { | ||||
|                 project: projects === ALL ? undefined : projects, | ||||
| @ -139,7 +166,7 @@ export class PlaygroundService { | ||||
|             }, | ||||
|             {}, | ||||
|         ); | ||||
|         return { features, featureProject }; | ||||
|         return { features, featureProject, environment }; | ||||
|     } | ||||
| 
 | ||||
|     async evaluateQuery( | ||||
| @ -152,6 +179,13 @@ export class PlaygroundService { | ||||
|             this.segmentService.getActive(), | ||||
|         ]); | ||||
| 
 | ||||
|         return this.evaluate({ features, featureProject, segments, context }); | ||||
|         const result = await this.evaluate({ | ||||
|             features, | ||||
|             featureProject, | ||||
|             segments, | ||||
|             context, | ||||
|             environment, | ||||
|         }); | ||||
|         return result.map((item) => omitKeys(item, 'environment', 'context')); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -14,7 +14,6 @@ import { | ||||
| } from '../../openapi/spec/playground-response-schema'; | ||||
| import { PlaygroundRequestSchema } from '../../openapi/spec/playground-request-schema'; | ||||
| import { PlaygroundService } from './playground-service'; | ||||
| import { fixedAdvancedPlaygroundResponse } from './hardcodedReponse'; | ||||
| import { IFlagResolver } from '../../types'; | ||||
| 
 | ||||
| export default class PlaygroundController extends Controller { | ||||
| @ -90,7 +89,14 @@ export default class PlaygroundController extends Controller { | ||||
|         res: Response<any>, | ||||
|     ): Promise<void> { | ||||
|         if (this.flagResolver.isEnabled('advancedPlayground')) { | ||||
|             res.json(fixedAdvancedPlaygroundResponse); | ||||
|             res.json({ | ||||
|                 input: req.body, | ||||
|                 features: await this.playgroundService.evaluateAdvancedQuery( | ||||
|                     req.body.projects || '*', | ||||
|                     req.body.environments, | ||||
|                     req.body.context, | ||||
|                 ), | ||||
|             }); | ||||
|         } else { | ||||
|             res.status(409).end(); | ||||
|         } | ||||
|  | ||||
							
								
								
									
										17
									
								
								yarn.lock
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								yarn.lock
									
									
									
									
									
								
							| @ -1316,6 +1316,18 @@ | ||||
|   resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" | ||||
|   integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== | ||||
| 
 | ||||
| "@types/lodash.groupby@4.6.7": | ||||
|   version "4.6.7" | ||||
|   resolved "https://registry.yarnpkg.com/@types/lodash.groupby/-/lodash.groupby-4.6.7.tgz#35fdb9647f100450d1004f65f74cbd964cdb567a" | ||||
|   integrity sha512-dFUR1pqdMgjIBbgPJ/8axJX6M1C7zsL+HF4qdYMQeJ7XOp0Qbf37I3zh9gpXr/ks6tgEYPDRqyZRAnFYvewYHQ== | ||||
|   dependencies: | ||||
|     "@types/lodash" "*" | ||||
| 
 | ||||
| "@types/lodash@*": | ||||
|   version "4.14.195" | ||||
|   resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.195.tgz#bafc975b252eb6cea78882ce8a7b6bf22a6de632" | ||||
|   integrity sha512-Hwx9EUgdwf2GLarOjQp5ZH8ZmblzcbTBC2wtQWNKARBSxM9ezRIAUpeDTgoQRAFB0+8CNWXVA9+MaSOzOF3nPg== | ||||
| 
 | ||||
| "@types/make-fetch-happen@10.0.1": | ||||
|   version "10.0.1" | ||||
|   resolved "https://registry.yarnpkg.com/@types/make-fetch-happen/-/make-fetch-happen-10.0.1.tgz#9e718d8f5f6ed388e2020bb9b4fbd2dc23009b38" | ||||
| @ -5040,6 +5052,11 @@ lodash.get@^4.4.2: | ||||
|   resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" | ||||
|   integrity sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ== | ||||
| 
 | ||||
| lodash.groupby@^4.6.0: | ||||
|   version "4.6.0" | ||||
|   resolved "https://registry.yarnpkg.com/lodash.groupby/-/lodash.groupby-4.6.0.tgz#0b08a1dcf68397c397855c3239783832df7403d1" | ||||
|   integrity sha512-5dcWxm23+VAoz+awKmBaiBvzox8+RqMgFhi7UvX9DHZr2HdxHXM/Wrf8cfKpsW37RNrvtPn6hSwNqurSILbmJw== | ||||
| 
 | ||||
| lodash.isequal@^4.5.0: | ||||
|   version "4.5.0" | ||||
|   resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user