-
Notifications
You must be signed in to change notification settings - Fork 83
feat(OptimizelyConfig): Add new fields to OptimizelyConfig #698
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
||
constructor(configObj: ProjectConfig, datafile: string) { | ||
this.experimentsMap = OptimizelyConfig.getExperimentsMap(configObj); | ||
this.featuresMap = OptimizelyConfig.getFeaturesMap(configObj, this.experimentsMap); | ||
this.sdkKey = configObj.sdkKey ? configObj.sdkKey : ''; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can use configObj.sdkKey ?? '';
if you want.
let cond = ''; | ||
conditions.forEach((item) => { | ||
let subAudience = ''; | ||
// Checks if item is list of conditions means if it is sub audience |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// Checks if item is list of conditions means it is sub audience
Audience, | ||
Experiment, | ||
FeatureVariable, | ||
OptimizelyExperimentsMap, | ||
OptimizelyFeaturesMap, | ||
OptimizelyVariablesMap, | ||
FeatureVariable, | ||
OptimizelyAttribute, | ||
OptimizelyAudience, | ||
OptimizelyEvent, | ||
OptimizelyExperiment, | ||
OptimizelyVariable, | ||
OptimizelyVariation, | ||
Rollout, | ||
VariationVariable, | ||
Variation, | ||
Rollout, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NIT: arrange these in alphabetical order
private datafile: string; | ||
private static audienceConditionalOperators: string[] = ['and', 'or', 'not']; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can probably be moved to ENUMS?
|
||
constructor(configObj: ProjectConfig, datafile: string) { | ||
this.experimentsMap = OptimizelyConfig.getExperimentsMap(configObj); | ||
this.featuresMap = OptimizelyConfig.getFeaturesMap(configObj, this.experimentsMap); | ||
this.sdkKey = configObj.sdkKey ? configObj.sdkKey : ''; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this.sdkKey = configObj.sdkKey ? configObj.sdkKey : ''; | |
this.sdkKey = configObj.sdkKey || ''; |
this.experimentsMap = OptimizelyConfig.getExperimentsMap(configObj); | ||
this.featuresMap = OptimizelyConfig.getFeaturesMap(configObj, this.experimentsMap); | ||
this.sdkKey = configObj.sdkKey ? configObj.sdkKey : ''; | ||
this.environmentKey = configObj.environmentKey ? configObj.environmentKey : ''; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this.environmentKey = configObj.environmentKey ? configObj.environmentKey : ''; | |
this.environmentKey = configObj.environmentKey || ''; |
* @returns {OptimizelyAudience[]} Array of unique audiences | ||
*/ | ||
static getAudiences(configObj: ProjectConfig): OptimizelyAudience[] { | ||
const finalAudiences: OptimizelyAudience[] = []; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why call it finalAudiences
? can you simply call it audiences
if (item instanceof Array) { | ||
subAudience = OptimizelyConfig.GetSerializedAudiences(item, audiencesById); | ||
subAudience = `(${subAudience})`; | ||
} else if (OptimizelyConfig.audienceConditionalOperators.includes(item)) { | ||
cond = item.toUpperCase(); | ||
} else { | ||
// Checks if item is audience id | ||
const audienceName = audiencesById[item] ? audiencesById[item].name : item; | ||
// if audience condition is "NOT" then add "NOT" at start. Otherwise check if there is already audience id in serializedAudience then append condition between serializedAudience and item | ||
if (serializedAudience || cond === 'NOT') { | ||
cond = cond === '' ? 'OR' : cond; | ||
if (serializedAudience === '') { | ||
serializedAudience = `${cond} "${audiencesById[item].name}"`; | ||
} else { | ||
serializedAudience = serializedAudience.concat(` ${cond} "${audienceName}"`); | ||
} | ||
} else { | ||
serializedAudience = `"${audienceName}"`; | ||
} | ||
} | ||
// Checks if sub audience is empty or not | ||
if (subAudience !== '') { | ||
if (serializedAudience !== '' || cond === 'NOT') { | ||
cond = cond === '' ? 'OR' : cond; | ||
if (serializedAudience === '') { | ||
serializedAudience = `${cond} ${subAudience}`; | ||
} else { | ||
serializedAudience = serializedAudience.concat(` ${cond} ${subAudience}`); | ||
} | ||
} else { | ||
serializedAudience = serializedAudience.concat(subAudience); | ||
} | ||
} | ||
}); | ||
} | ||
return serializedAudience; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NOT reviewing this code. will leave it to @msohailhussain and @jaeopt as they have more context about this particular peice
|
||
const variableIdMap = OptimizelyConfig.getVariableIdMap(configObj); | ||
|
||
experiments.forEach((experiment) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you could use map
here and assigned the result directly to deliveryRules
?
}, | ||
{}, | ||
) | ||
experiments.forEach((experiment) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could do reduce here probably?
datafileCopy.environmentKey = datafile.environmentKey; | ||
datafileCopy.sdkKey = datafile.sdkKey; | ||
} | ||
datafileCopy.environmentKey = datafile.environmentKey ? datafile.environmentKey : ''; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
datafileCopy.environmentKey = datafile.environmentKey ? datafile.environmentKey : ''; | |
datafileCopy.environmentKey = datafile.environmentKey || ''; |
datafileCopy.sdkKey = datafile.sdkKey; | ||
} | ||
datafileCopy.environmentKey = datafile.environmentKey ? datafile.environmentKey : ''; | ||
datafileCopy.sdkKey = datafile.sdkKey ? datafile.sdkKey : ''; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
datafileCopy.sdkKey = datafile.sdkKey ? datafile.sdkKey : ''; | |
datafileCopy.sdkKey = datafile.sdkKey || ''; |
export type OptimizelyAudience = { | ||
id: string; | ||
name: string; | ||
conditions: unknown[] | string; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It appears that we expect conditions
type here to just be string
since we JSON.stringify the typedAudience/oldAudience conditions
* @param {string} featureId | ||
* @returns {[key: string]: Variation} Variations mapped by key | ||
*/ | ||
static GetVariationsMap( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why this method is also capitalized?
* @param {[id: string]: Audience} audiencesById | ||
* @returns {string} Serialized audiences condition string | ||
*/ | ||
static GetSerializedAudiences( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are we capitalizing this method?
@@ -248,6 +249,7 @@ export interface OptimizelyOptions { | |||
export interface OptimizelyExperiment { | |||
id: string; | |||
key: string; | |||
audiences: unknown[] | string; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should just be string
configObj: ProjectConfig, | ||
featureVariableIdMap: FeatureVariablesMap, | ||
featureId: string, | ||
experiments: Experiment[] | undefined |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should not be expected undefined as every rollout object should contain experiments
. @msohailhussain please correct if I am wrong.
experiments: Experiment[] | undefined | ||
): OptimizelyExperiment[] { | ||
const deliveryRules: OptimizelyExperiment[] = []; | ||
if (!experiments) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If above is true, this if statement is unnecessary.
isFeatureEnabled: boolean | undefined | ||
): OptimizelyVariablesMap { | ||
let variablesMap: OptimizelyVariablesMap = {}; | ||
if (!featureId) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This statement seems unnecessary as we should expect a valid featureId
, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please address
*/ | ||
static getAudiences(configObj: ProjectConfig): OptimizelyAudience[] { | ||
const finalAudiences: OptimizelyAudience[] = []; | ||
const typedAudienceIds: { [id: string]: boolean } = {}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i agree. there is one more existing code that's using the same kv map, we should use .includes and only use Ids arrays.
@@ -69,150 +332,122 @@ export class OptimizelyConfig { | |||
static getRolloutExperimentIds(rollouts: Rollout[]): { [key: string]: boolean } { | |||
return (rollouts || []).reduce((experimentIds: { [key: string]: boolean }, rollout) => { | |||
rollout.experiments.forEach((e) => { | |||
(experimentIds)[e.id] = true; | |||
experimentIds[e.id] = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same comment, use .includes more cleaner.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good except for couple of minor comments and failing browser stack tests.
featureId: string | ||
): { [key: string]: Variation } { | ||
let variationsMap: { [key: string]: OptimizelyVariation } = {}; | ||
variationsMap = variations.reduce((OptlyVariationsMap: { [key: string]: OptimizelyVariation }, variation) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
optlyVariationsMap
instead of OptlyVariationsMap
isFeatureEnabled: boolean | undefined | ||
): OptimizelyVariablesMap { | ||
const variablesMap = (featureIdVariableMap[featureId] || []).reduce( | ||
(OptlyVariablesMap: OptimizelyVariablesMap, featureVariable) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
optlyVariablesMap
instead of OptlyVariablesMap
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall looks great!
- One comment about using OptimizelyConfig types internally.
- Also I do not see duplicate-key warning about experimentsMap in OptimizelyConfig and deprecation warning about experimentsMap in OptimizelyFeature.
@@ -81,7 +83,7 @@ export interface ProjectConfig { | |||
groupIdMap: { [id: string]: Group }; | |||
groups: Group[]; | |||
events: Event[]; | |||
attributes: Array<{ id: string }>; | |||
attributes: OptimizelyAttribute[]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's not a good idea to use "OptimizelyAttribute" or other "OptimizelyXYZ" types in here.
Even if they look identical for now, we should separate them as public types only.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
makes sense, thanks.
Had already added for Also added for OptimizelyConfig Interface here but forgot about the class which i have added now. Comment on the interface can be seen here: https://github.com/optimizely/javascript-sdk/pull/698/files#diff-2f8a7f1ccf360ce99abd03c811c59f9488fa24db24f8578d808e813e75192acdR347 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
nit - add a period (.) at the end of "This experimentsMap is for experiments of legacy projects only" in multiple places.
Summary
The following new public properties are added to OptimizelyConfig:
Test plan
All FSC tests OPTIMIZELY_CONFIG_V2 tests should pass.
FSC OptimizelyConfig link