Skip to content

Commit

Permalink
✨ Merge release/v5.1 to dev (#1526)
Browse files Browse the repository at this point in the history
* storing default condition payload values in db with conditions (#1309)

* storing default condition payload values in db with conditions

* version bump to v5.1.1

* code clean up review cmt

* removing old condition payload when new are added

* version bump to 5.1.1

---------

Co-authored-by: danoswaltCL <[email protected]>

* Bugfix/1365 assignedcondition null mark issue (#1366)

* proper null coalescing in mark call for assignedcondition

* make assignedCondition an optional value in MarkData object, as we can safely as assume null is the intended condition

* version bump

* 🐛 Hotfix: Fix for Exclusions logic(Simple & Within Subject Exps) and code optimization for mark call (#1324)

* bugfixes for exclusions logic and mark call opt

* removing extra call to fetch experiment

* Storing proper group exclusion and individual exclusion documents (#1343)

* correct group exclusion and individual exclusion docs with code optimization for assign call

* code optimizations for mark and assign call for exclusions

* resolved peer review comments for group exclusions bug

* version bump release branch

---------

Co-authored-by: danoswaltCL <[email protected]>

* Bugfix/1382 experiment type in assign response (#1384)

* add experimentType to IExperimentAssignmentv5 response

* changes to main.java

* remove extra ts lib experimentType logic

* spec update

* spec update dataservice

* version bump

* ✨ Enhancement: Update data CSV export format (#1378)

* bugfixes for exclusions logic and mark call opt

* correct group exclusion and individual exclusion docs with code optimization for assign call

* code optimizations for mark and assign call for exclusions

* updating data csv export format to capture each mark call

* resolve peer review comments to confirm workingGroup is defined

* fix for integration test cases with old DP keys

* use new relic env var for prod and staging (#1438)

* Bugfix/use new relic var (#1442)

* use new relic env var for prod and staging

* version bump 5.1.5

* switch default user role from cretor to reader (#1448)

* experiment list context chip issue is resolved

* send whole url string in email link (#1464)

* send whole url string in email link

* change version to 5.1.7 for pipeline

* snackbar for import and delete experiment (#1468)

* snackbar issue resolved for import and delete operation of experiment

* version bump

---------

Co-authored-by: danoswaltCL <[email protected]>

* Bugfix for consistent metrics statistics view (#1467)

* bugfix for metrics statistics view

* metrics consistent dictionary usage across stepper and details page

* bump to 5.1.9

---------

Co-authored-by: danoswaltCL <[email protected]>

* Merge down release hotfixes 5.0 into 5.1 (#1470)

* cherry-pick ea63855 (#1159)

Co-authored-by: pratik <[email protected]>

* Hotfix/enrollment complete fix (#1161)

* cherry-pick ea63855

* bump version after enrollment complete  hotfix

---------

Co-authored-by: pratik <[email protected]>

* Fix/version root only (#1163)

* revert, change version back to major-minor on root only

* add backend

* Fix/version root only (#1164)

* revert, change version back to major-minor on root only

* add backend

* commit the backend package.json

* no assignedCondition null in java lib (#1441)

* fix missing imports

* version bump 5.1.10

---------

Co-authored-by: pratik <[email protected]>

* peer review comments to improve enrollment code testcases

* Resolved review comment on PR

* Disabled dp and condition table and Allow payload edit (#1473)

* disabled dp and condition table edit and allowed change in condition payload while enrolling

* same changes for factorial experiment

* removed unnecessary the code change

* Grey out the decision points and conditions/factors tables

* Revert "Grey out the decision points and conditions/factors tables"

This reverts commit 91c7494.

* Grey out the decision points and conditions/factors tables (recommit)

---------

Co-authored-by: Zack Lee <[email protected]>

* add prefix to keys for cache lookup (#1477)

* add prefix to keys for cache lookup

* version bump

* ✨ Toggle for within-subjects experiment type support (#1471)

* toggle for within-subjects experiment type support

* version bump

---------

Co-authored-by: danoswaltCL <[email protected]>

* 🐛 Bugfix to overwrite monitored document for unused decision points (#1482)

* bugfix to overwrite monitored document for unused decision points

* unit test cases fixed for multiple monitored document getting stored for unused dp

* version bump

---------

Co-authored-by: danoswaltCL <[email protected]>

* ✨ Detailed Integration Testcases: Exclusion codes (#1433)

* detailed integration test cases for exclusion codes

* peer review comments to improve exclusion code testcases

* added missing mock experiments while resolving conflicts

* review comments fixed for enrollment code and other integration test cases

---------

Co-authored-by: Yagnik Hingrajiya <[email protected]>
Co-authored-by: danoswaltCL <[email protected]>
Co-authored-by: Yagnik <[email protected]>
Co-authored-by: Ben Blanchard <[email protected]>
Co-authored-by: Zack Lee <[email protected]>
  • Loading branch information
6 people authored May 13, 2024
1 parent c8d6004 commit 489a738
Show file tree
Hide file tree
Showing 82 changed files with 3,486 additions and 1,326 deletions.
718 changes: 718 additions & 0 deletions backend/locust/notes.txt

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions backend/packages/Upgrade/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ APP_BANNER=true
APP_DEMO=false
CACHING_ENABLED=false
CACHING_TTL=10
USE_NEW_RELIC=false
#
# LOGGING
#
Expand Down
1 change: 1 addition & 0 deletions backend/packages/Upgrade/.env.test
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ APP_BANNER=true
APP_DEMO=false
CACHING_ENABLED=true
CACHING_TTL=10
USE_NEW_RELIC=false

#
# LOGGING
Expand Down
7 changes: 5 additions & 2 deletions backend/packages/Upgrade/src/api/Algorithms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,12 @@ export function randomCondition(
}
}

const randomAssignData = {
const randomAssignData: IExperimentAssignmentv5 = {
site: assignedData.site,
target: assignedData.target,
assignedCondition: randomConditionArray,
assignedFactor: experiment.type === EXPERIMENT_TYPE.FACTORIAL ? assignedFactorsArray : null,
experimentType: experiment.type,
};

// rotate elements in assigned condition array based on number of monitored decision point
Expand Down Expand Up @@ -103,11 +104,12 @@ export function randomRoundRobinCondition(
}
}

const randomRoundRobinAssignData = {
const randomRoundRobinAssignData: IExperimentAssignmentv5 = {
site: assignedData.site,
target: assignedData.target,
assignedCondition: randomRoundRobinConditionArray,
assignedFactor: experiment.type === EXPERIMENT_TYPE.FACTORIAL ? assignedFactorsArray : null,
experimentType: experiment.type,
};

// rotate elements in assigned condition array based on number of monitored decision point
Expand Down Expand Up @@ -175,6 +177,7 @@ function convertToAssignedCondition(
target: target,
assignedCondition: assignedConditionArray,
assignedFactor: experiment.type === EXPERIMENT_TYPE.FACTORIAL ? assignedFactorsArray : null,
experimentType: experiment.type,
};
}

Expand Down
2 changes: 1 addition & 1 deletion backend/packages/Upgrade/src/api/models/Experiment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -175,5 +175,5 @@ export class Experiment extends BaseModel {
enum: EXPERIMENT_TYPE,
default: EXPERIMENT_TYPE.SIMPLE,
})
public type: string;
public type: EXPERIMENT_TYPE;
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ export class IndividualExclusion extends BaseModel {
@ManyToOne(() => Experiment, { onDelete: 'CASCADE' })
public experiment: Experiment;

@Column({ nullable: true })
public groupId?: string;

@IsNotEmpty()
@Column({ type: 'enum', enum: EXCLUSION_CODE, nullable: true })
public exclusionCode: EXCLUSION_CODE;
Expand Down
2 changes: 1 addition & 1 deletion backend/packages/Upgrade/src/api/models/User.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export class User extends BaseModel {
@Column({
type: 'enum',
enum: UserRole,
default: UserRole.CREATOR,
default: UserRole.READER,
nullable: true,
})
public role: UserRole;
Expand Down
123 changes: 96 additions & 27 deletions backend/packages/Upgrade/src/api/repositories/AnalyticsRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ import { GroupExclusionRepository } from './GroupExclusionRepository';
import { DecisionPoint } from '../models/DecisionPoint';
import { MonitoredDecisionPointLog } from '../models/MonitoredDecisionPointLog';
import { ExperimentCondition } from '../models/ExperimentCondition';
import { ConditionPayload } from '../models/ConditionPayload';
import { StateTimeLog } from '../models/StateTimeLogs';
import { IndividualExclusion } from '../models/IndividualExclusion';
import { UserStratificationFactor } from '../models/UserStratificationFactor';
import { MonitoredDecisionPointRepository } from './MonitoredDecisionPointRepository';
import { IndividualEnrollment } from '../models/IndividualEnrollment';

export interface IEnrollmentByCondition {
conditions_id: string;
Expand Down Expand Up @@ -50,16 +56,29 @@ export interface CSVExportDataRow {
experimentId: string;
experimentName: string;
userId: string;
groupId: string;
partition: string;
conditionName: string;
firstDecisionPointReachedOn: string;
decisionPointReachedCount: number;
markExperimentPointTime: string;
context: string[];
assignmentUnit: string;
group: string;
consistencyRule: string;
designType: string;
algorithmType: string;
stratification: string;
stratificationValue: string;
site: string;
target: string;
excludeIfReached: string;
payload: string;
postRule: string;
revertTo: string;
enrollmentStartDate: string;
enrollmentCompleteDate: string;
enrollmentGroupId: string;
exclusionGroupId: string;
enrollmentCode: string;
exclusionCode: string;
}

@EntityRepository()
Expand Down Expand Up @@ -403,45 +422,95 @@ export class AnalyticsRepository {
skip: number,
take: number
): Promise<CSVExportDataRow[]> {
const individualEnrollmentRepository = getCustomRepository(IndividualEnrollmentRepository, 'export');
return individualEnrollmentRepository
.createQueryBuilder('individualEnrollment')
const monitoredDecisionPointRepository = getCustomRepository(MonitoredDecisionPointRepository, 'export');
return monitoredDecisionPointRepository
.createQueryBuilder('monitoredDecisionPoint')
.select([
'experiment.id as "experimentId"',
'experiment.name as "experimentName"',
'experiment.context as "context"',
'experiment.assignmentUnit as "assignmentUnit"',
'experiment.group as "group"',
'monitored.site as "site"',
'monitored.target as "target"',
'"individualEnrollment"."userId" as "userId"',
'"individualEnrollment"."partitionId" as "decisionPointId"',
'"individualEnrollment"."groupId" as "groupId"',
'experiment.consistencyRule as "consistencyRule"',
'experiment.type as "designType"',
'experiment.assignmentAlgorithm as "algorithmType"',
'experiment.stratificationFactorStratificationFactorName as "stratification"',
'"userStratificationFactor"."stratificationFactorValue" as "stratificationValue"',
'monitoredDecisionPoint.site as "site"',
'monitoredDecisionPoint.target as "target"',
'"decisionPointData"."excludeIfReached" as "excludeIfReached"',
'"monitoredDecisionPoint"."userId" as "userId"',
'"decisionPointData"."id" as "decisionPointId"',
'"individualEnrollment"."groupId" as "enrollmentGroupId"',
'"individualExclusion"."groupId" as "exclusionGroupId"',
'condition."conditionCode" as "conditionName"',
'MIN("monitoredPointLogs"."createdAt") as "firstDecisionPointReachedOn"',
'CAST(COUNT("monitoredPointLogs"."id") as int) as "decisionPointReachedCount"',
'"conditionPayload"."payloadValue" as "payload"',
'experiment.postExperimentRule as "postRule"',
'"experimentCondition"."conditionCode" as "revertTo"',
'"enrollingStateTimeLog"."timeLog" as "enrollmentStartDate"',
'"enrollmentCompleteStateTimeLog"."timeLog" as "enrollmentCompleteDate"',
'"monitoredPointLogs"."createdAt" as "markExperimentPointTime"',
'"individualEnrollment"."enrollmentCode" as "enrollmentCode"',
'"individualExclusion"."exclusionCode" as "exclusionCode"',
])
.leftJoin('individualEnrollment.condition', 'condition')
.innerJoin(Experiment, 'experiment', 'experiment.id = "individualEnrollment"."experimentId"')
.leftJoin('individualEnrollment.partition', 'decisionPoint')
.innerJoin(
MonitoredDecisionPoint,
'monitored',
'monitored.userId = individualEnrollment.userId AND monitored.site = decisionPoint.site AND monitored.target = decisionPoint.target'
.innerJoin(Experiment, 'experiment', 'experiment.id::text = "monitoredDecisionPoint"."experimentId"')
.leftJoin(ExperimentCondition, 'experimentCondition', 'experimentCondition.id = "experiment"."revertTo"')
.leftJoin(
UserStratificationFactor,
'userStratificationFactor',
'userStratificationFactor.userId = monitoredDecisionPoint.userId AND userStratificationFactor.factorName = experiment.stratificationFactorStratificationFactorName'
)
.leftJoin('monitored.monitoredPointLogs', 'monitoredPointLogs')
.leftJoin(
StateTimeLog,
'enrollingStateTimeLog',
`"enrollingStateTimeLog"."experimentId" = "experiment"."id" AND enrollingStateTimeLog.toState = 'enrolling'`
)
.leftJoin(
StateTimeLog,
'enrollmentCompleteStateTimeLog',
`"enrollmentCompleteStateTimeLog"."experimentId" = "experiment"."id" AND enrollmentCompleteStateTimeLog.toState = 'enrollmentComplete'`
)
.leftJoin(
IndividualEnrollment,
'individualEnrollment',
'individualEnrollment.userId = monitoredDecisionPoint.userId'
)
.leftJoin(
IndividualExclusion,
'individualExclusion',
'individualExclusion.userId = monitoredDecisionPoint.userId'
)
.leftJoin(ExperimentCondition, 'condition', '"condition"."conditionCode" = monitoredDecisionPoint.condition')
.leftJoin(ConditionPayload, 'conditionPayload', 'conditionPayload.parentConditionId = condition.id')
.leftJoin(
DecisionPoint,
'decisionPointData',
'decisionPointData.site = monitoredDecisionPoint.site AND decisionPointData.target = monitoredDecisionPoint.target'
)
.leftJoin('monitoredDecisionPoint.monitoredPointLogs', 'monitoredPointLogs')
.groupBy('experiment.id')
.addGroupBy('experiment.name')
.addGroupBy('"monitored"."site"')
.addGroupBy('"monitored"."target"')
.addGroupBy('"individualEnrollment"."userId"')
.addGroupBy('"individualEnrollment"."partitionId"')
.addGroupBy('"experimentCondition"."conditionCode"')
.addGroupBy('"monitoredDecisionPoint"."site"')
.addGroupBy('"monitoredDecisionPoint"."target"')
.addGroupBy('"monitoredDecisionPoint"."userId"')
.addGroupBy('"decisionPointData"."id"')
.addGroupBy('"individualEnrollment"."groupId"')
.addGroupBy('"individualExclusion"."groupId"')
.addGroupBy('condition."conditionCode"')
.orderBy('"individualEnrollment"."userId"', 'ASC')
.addGroupBy('"decisionPointData"."excludeIfReached"')
.addGroupBy('"conditionPayload"."payloadValue"')
.addGroupBy('"enrollingStateTimeLog"."timeLog"')
.addGroupBy('"enrollmentCompleteStateTimeLog"."timeLog"')
.addGroupBy('"monitoredPointLogs"."createdAt"')
.addGroupBy('"individualEnrollment"."enrollmentCode"')
.addGroupBy('"individualExclusion"."exclusionCode"')
.addGroupBy('"userStratificationFactor"."stratificationFactorValue"')
.addGroupBy('"monitoredDecisionPoint"."userId"')
.orderBy('"monitoredDecisionPoint"."userId"', 'ASC')
.offset(skip)
.limit(take)
.where('"individualEnrollment"."experimentId" = :experimentId', { experimentId })
.where('"monitoredDecisionPoint"."experimentId" = :experimentId', { experimentId })
.execute();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,10 +112,11 @@ export class ExperimentRepository extends Repository<Experiment> {

public async getValidExperiments(context: string): Promise<Experiment[]> {
const whereExperimentsClause =
'(experiment.state = :enrolling OR experiment.state = :enrollmentComplete) AND :context ILIKE ANY (ARRAY[experiment.context])';
'(experiment.state = :enrolling OR experiment.state = :enrollmentComplete) AND NOT (experiment.state = :enrollmentComplete AND experiment.postExperimentRule = :assign AND experiment.revertTo IS NULL) AND :context ILIKE ANY (ARRAY[experiment.context])';
const whereClauseParams = {
enrolling: 'enrolling',
enrollmentComplete: 'enrollmentComplete',
assign: 'assign',
context,
};
const experimentConditionLevelPayloadQuery = this.createQueryBuilder('experiment')
Expand Down Expand Up @@ -210,11 +211,12 @@ export class ExperimentRepository extends Repository<Experiment> {

public async getValidExperimentsWithPreview(context: string): Promise<Experiment[]> {
const whereExperimentsClause =
'(experiment.state = :enrolling OR experiment.state = :enrollmentComplete OR experiment.state = :preview) AND :context ILIKE ANY (ARRAY[experiment.context])';
'(experiment.state = :enrolling OR experiment.state = :enrollmentComplete OR experiment.state = :preview) AND NOT (experiment.state = :enrollmentComplete AND experiment.postExperimentRule = :assign AND experiment.revertTo IS NULL) AND :context ILIKE ANY (ARRAY[experiment.context])';
const whereClauseParams = {
enrolling: 'enrolling',
enrollmentComplete: 'enrollmentComplete',
preview: 'preview',
assign: 'assign',
context,
};
const experimentConditionLevelPayloadQuery = this.createQueryBuilder('experiment')
Expand Down
Loading

0 comments on commit 489a738

Please sign in to comment.