From 34b6e101ff573b98cb9b6392c4ab04babc48f91f Mon Sep 17 00:00:00 2001 From: pratik Date: Mon, 14 Aug 2023 14:25:23 +0530 Subject: [PATCH 01/12] working archive feature frontend changes --- .../experiment-list.component.html | 43 ++++++++--- .../experiment-list.component.ts | 76 +++++++++++++------ .../experiment-status.component.html | 13 +++- .../experiment-status.component.ts | 17 ++++- .../view-experiment.component.html | 23 ++++-- .../pipes/experiment-state.pipe.spec.ts | 8 ++ .../app/shared/pipes/experiment-state.pipe.ts | 2 + .../projects/upgrade/src/assets/i18n/en.json | 3 + types/src/Experiment/enums.ts | 1 + 9 files changed, 143 insertions(+), 43 deletions(-) diff --git a/frontend/projects/upgrade/src/app/features/dashboard/home/components/experiment-list/experiment-list.component.html b/frontend/projects/upgrade/src/app/features/dashboard/home/components/experiment-list/experiment-list.component.html index 2ff389401a..30b0e7fa1f 100644 --- a/frontend/projects/upgrade/src/app/features/dashboard/home/components/experiment-list/experiment-list.component.html +++ b/frontend/projects/upgrade/src/app/features/dashboard/home/components/experiment-list/experiment-list.component.html @@ -13,14 +13,37 @@ - +
+ +
+
+ + + + {{ filterOption | titlecase }} + + +
search
@@ -32,7 +55,7 @@ (click)="openExportAllExperimentsDialog()" > download - {{ 'segments.export-all-segments.text' | translate }} + {{ 'home.experiment.export-all-experiments.text' | translate }} @@ -105,7 +109,9 @@ @@ -131,7 +137,9 @@
@@ -204,10 +212,7 @@
- + {{ 'home-global.consistency-rule.text' | translate | uppercase }} @@ -215,7 +220,9 @@ {{ 'home-global.condition-order.text' | translate | uppercase }} - {{ experiment.consistencyRule || experiment.conditionOrder | titlecase }} + {{ + experiment.consistencyRule || experiment.conditionOrder | titlecase + }}
diff --git a/frontend/projects/upgrade/src/app/shared/pipes/experiment-state.pipe.spec.ts b/frontend/projects/upgrade/src/app/shared/pipes/experiment-state.pipe.spec.ts index af62ab103b..d3ba91f6b7 100644 --- a/frontend/projects/upgrade/src/app/shared/pipes/experiment-state.pipe.spec.ts +++ b/frontend/projects/upgrade/src/app/shared/pipes/experiment-state.pipe.spec.ts @@ -28,6 +28,10 @@ describe('ExperimentStatePipe', () => { expect(experimentStatePipe.transform(EXPERIMENT_STATE.INACTIVE)).toBe('Inactive'); }); + it('should return Archived State', () => { + expect(experimentStatePipe.transform(EXPERIMENT_STATE.ARCHIVED)).toBe('Archived'); + }); + it('should return #000 color for Preview State', () => { expect(experimentStatePipe.transform(EXPERIMENT_STATE.PREVIEW, ExperimentStatePipeType.COLOR)).toBe('#000'); }); @@ -53,4 +57,8 @@ describe('ExperimentStatePipe', () => { it('should return #d8d8d8 color for Inactive State', () => { expect(experimentStatePipe.transform(EXPERIMENT_STATE.INACTIVE, ExperimentStatePipeType.COLOR)).toBe('#d8d8d8'); }); + + it('should return #fd9099 color for Archived State', () => { + expect(experimentStatePipe.transform(EXPERIMENT_STATE.ARCHIVED, ExperimentStatePipeType.COLOR)).toBe('#fd9099'); + }); }); diff --git a/frontend/projects/upgrade/src/app/shared/pipes/experiment-state.pipe.ts b/frontend/projects/upgrade/src/app/shared/pipes/experiment-state.pipe.ts index ae0afb8dc0..7fe5d486f4 100644 --- a/frontend/projects/upgrade/src/app/shared/pipes/experiment-state.pipe.ts +++ b/frontend/projects/upgrade/src/app/shared/pipes/experiment-state.pipe.ts @@ -24,6 +24,8 @@ export class ExperimentStatePipe implements PipeTransform { return type === ExperimentStatePipeType.TEXT ? 'Enrolling' : '#7b9cff'; case EXPERIMENT_STATE.CANCELLED: return type === ExperimentStatePipeType.TEXT ? 'Cancelled' : '#ff0000'; + case EXPERIMENT_STATE.ARCHIVED: + return type === ExperimentStatePipeType.TEXT ? 'Archived' : '#fd9099'; } } } diff --git a/frontend/projects/upgrade/src/assets/i18n/en.json b/frontend/projects/upgrade/src/assets/i18n/en.json index 0ca3539ebb..afed452db2 100644 --- a/frontend/projects/upgrade/src/assets/i18n/en.json +++ b/frontend/projects/upgrade/src/assets/i18n/en.json @@ -71,6 +71,7 @@ "home-global.assignment-weight.text": "WEIGHT (%)", "home.experiment.text.subtitle": "Create and analyze experiments", "home.no-experiment.text": "Welcome!
Let's start by creating a new experiment!", + "home.experiment.export-all-experiments.text": "EXPORT ALL", "home.experiment.add-experiment.text": "ADD EXPERIMENT", "home.experiment.import-experiment.text": "IMPORT EXPERIMENT", "home.experiment-query-result.title.text": "Metrics Data", @@ -267,6 +268,8 @@ "home.change-experiment-status.enrolling-info.text": "*Once the experiment is started you won’t be allowed to update Experiment’s Condition and Sites", "home.change-experiment-status.enrolling-error.text": "*Experiment start date should not be greater than experiment end date {{ endDate }}", "home.change-experiment-status.condition-count-error.text": "*Please have at least 2 conditions to move forward", + "home.change-experiment-status.archiving-confirmation.text": "Please acknowledge that you agree to permanently transition this experiment to archive status", + "home.change-experiment-status.archiving-info.text": "*Archiving the experiment will cancel the post rule. The archived experiments are hidden from the experiment list and can be found by explicitly searching for 'Archived' experiments.", "home.change-post-experiment-rule.title.text": "Change Post Experiment Condition", "logs-global.log-zero-state.text": "No Logs", "logs-global.log-view-diff.text": "view", diff --git a/types/src/Experiment/enums.ts b/types/src/Experiment/enums.ts index 95eb419e6d..8b1ca9912b 100644 --- a/types/src/Experiment/enums.ts +++ b/types/src/Experiment/enums.ts @@ -30,6 +30,7 @@ export enum EXPERIMENT_STATE { ENROLLING = 'enrolling', ENROLLMENT_COMPLETE = 'enrollmentComplete', CANCELLED = 'cancelled', + ARCHIVED = 'archived', } export enum SERVER_ERROR { From 38caaeb6af7e9c3be5d7ada8639b5bf3e2f9cae2 Mon Sep 17 00:00:00 2001 From: pratik Date: Mon, 21 Aug 2023 14:02:53 +0530 Subject: [PATCH 02/12] ignoring storing logs for archived experiments --- .../packages/Upgrade/src/api/repositories/MetricRepository.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/backend/packages/Upgrade/src/api/repositories/MetricRepository.ts b/backend/packages/Upgrade/src/api/repositories/MetricRepository.ts index 98705b851f..16492277bf 100644 --- a/backend/packages/Upgrade/src/api/repositories/MetricRepository.ts +++ b/backend/packages/Upgrade/src/api/repositories/MetricRepository.ts @@ -1,6 +1,7 @@ import { Metric } from '../models/Metric'; import { EntityRepository, Repository } from 'typeorm'; import repositoryError from './utils/repositoryError'; +import { EXPERIMENT_STATE } from '../../../../../../types/src'; @EntityRepository(Metric) export class MetricRepository extends Repository { @@ -32,7 +33,9 @@ export class MetricRepository extends Repository { public async findMetricsWithQueries(ids: string[]): Promise { return this.createQueryBuilder('metrics') .innerJoin('metrics.queries', 'queries') + .innerJoin('queries.experiment', 'experiment') .where('key IN (:...ids)', { ids }) + .andWhere('experiment.state NOT IN (:...archivedAndInactive)', { archivedAndInactive : [EXPERIMENT_STATE.ARCHIVED, EXPERIMENT_STATE.INACTIVE ]}) .getMany() .catch((errorMsg: any) => { const errorMsgString = repositoryError(this.constructor.name, 'findMetricsWithQueries', { ids }, errorMsg); From b056ac97d18589c36cebdaad5ff3cfc8f0d4be56 Mon Sep 17 00:00:00 2001 From: pratik Date: Thu, 24 Aug 2023 16:48:20 +0530 Subject: [PATCH 03/12] add few more missing readonly properties for archive state --- .../pages/view-experiment/view-experiment.component.html | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/frontend/projects/upgrade/src/app/features/dashboard/home/pages/view-experiment/view-experiment.component.html b/frontend/projects/upgrade/src/app/features/dashboard/home/pages/view-experiment/view-experiment.component.html index cb80e012b2..6b36265e25 100644 --- a/frontend/projects/upgrade/src/app/features/dashboard/home/pages/view-experiment/view-experiment.component.html +++ b/frontend/projects/upgrade/src/app/features/dashboard/home/pages/view-experiment/view-experiment.component.html @@ -239,7 +239,7 @@ ( ) - + create
@@ -297,7 +297,7 @@ {{ experiment.endOn | formatDate: 'medium date' }} @@ -394,6 +394,7 @@ class="ft-16-600" color="primary" (change)="toggleVerboseLogging($event)" + [disabled]="experiment.state === ExperimentState.CANCELLED || experiment.state === ExperimentState.ARCHIVED" > {{ 'home.view-experiment.logging.text' | translate | uppercase }} From e2954e18915bfdf87763e711d81256835ac421e7 Mon Sep 17 00:00:00 2001 From: pratik Date: Thu, 24 Aug 2023 23:13:49 +0530 Subject: [PATCH 04/12] missed readonly for archive state --- .../home/pages/view-experiment/view-experiment.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/projects/upgrade/src/app/features/dashboard/home/pages/view-experiment/view-experiment.component.html b/frontend/projects/upgrade/src/app/features/dashboard/home/pages/view-experiment/view-experiment.component.html index 6b36265e25..9a190935e5 100644 --- a/frontend/projects/upgrade/src/app/features/dashboard/home/pages/view-experiment/view-experiment.component.html +++ b/frontend/projects/upgrade/src/app/features/dashboard/home/pages/view-experiment/view-experiment.component.html @@ -316,7 +316,7 @@ From 62ea73c69422972eb196507e7c70dbbcb01e8354 Mon Sep 17 00:00:00 2001 From: RidhamShah Date: Sat, 26 Aug 2023 23:38:16 +0530 Subject: [PATCH 05/12] Create API and database for archive --- .../src/api/controllers/QueryController.ts | 36 +++++++++ .../Upgrade/src/api/models/ArchivedStats.ts | 18 +++++ .../packages/Upgrade/src/api/models/Query.ts | 8 +- .../repositories/ArchivedStatsRepository.ts | 24 ++++++ .../src/api/services/ExperimentService.ts | 27 ++++++- .../Upgrade/src/api/services/QueryService.ts | 14 ++++ .../migrations/1692936809279-archivedState.ts | 79 +++++++++++++++++++ .../test/unit/services/QueryService.test.ts | 32 ++++++++ .../core/analysis/analysis.data.service.ts | 5 ++ .../src/app/core/analysis/analysis.service.ts | 5 +- .../core/analysis/store/analysis.actions.ts | 6 +- .../core/analysis/store/analysis.effects.ts | 17 ++-- .../experiments/store/experiments.effects.ts | 5 +- .../experiment-query-result.component.ts | 6 +- .../src/environments/environment-types.ts | 1 + .../src/environments/environment.bsnl.ts | 1 + .../src/environments/environment.demo.prod.ts | 1 + .../src/environments/environment.prod.ts | 1 + .../src/environments/environment.staging.ts | 1 + .../upgrade/src/environments/environment.ts | 1 + 20 files changed, 273 insertions(+), 15 deletions(-) create mode 100644 backend/packages/Upgrade/src/api/models/ArchivedStats.ts create mode 100644 backend/packages/Upgrade/src/api/repositories/ArchivedStatsRepository.ts create mode 100644 backend/packages/Upgrade/src/database/migrations/1692936809279-archivedState.ts diff --git a/backend/packages/Upgrade/src/api/controllers/QueryController.ts b/backend/packages/Upgrade/src/api/controllers/QueryController.ts index 02801d7671..09ea6c685b 100644 --- a/backend/packages/Upgrade/src/api/controllers/QueryController.ts +++ b/backend/packages/Upgrade/src/api/controllers/QueryController.ts @@ -50,4 +50,40 @@ export class QueryController { ): Promise { return this.queryService.analyze(dataLogParams.queryIds, request.logger); } + + /** + * @swagger + * /query/archive: + * post: + * description: Data log analysis + * consumes: + * - application/json + * parameters: + * - in: body + * name: params + * required: true + * schema: + * type: object + * properties: + * queryIds: + * type: array + * items: + * type: string + * description: Data analysis + * tags: + * - Query + * produces: + * - application/json + * responses: + * '200': + * description: Get data analysis + */ + @Post('/archive') + public archive( + @Body() + dataLogParams: DataLogAnalysisValidator, + @Req() request: AppRequest + ): Promise { + return this.queryService.getArchivedStats(dataLogParams.queryIds, request.logger); + } } diff --git a/backend/packages/Upgrade/src/api/models/ArchivedStats.ts b/backend/packages/Upgrade/src/api/models/ArchivedStats.ts new file mode 100644 index 0000000000..9b4205ce4d --- /dev/null +++ b/backend/packages/Upgrade/src/api/models/ArchivedStats.ts @@ -0,0 +1,18 @@ +import { Entity, PrimaryColumn, Column, OneToOne, JoinColumn } from 'typeorm'; +import { IsNotEmpty } from 'class-validator'; +import { BaseModel } from './base/BaseModel'; +import { Query } from './Query'; + +@Entity() +export class ArchivedStats extends BaseModel { + @PrimaryColumn('uuid') + public id: string; + + @IsNotEmpty() + @Column('jsonb') + public result: any; + + @OneToOne(() => Query, (query) => query.archivedStats, { onDelete: 'CASCADE' }) + @JoinColumn() + public query: Query; +} diff --git a/backend/packages/Upgrade/src/api/models/Query.ts b/backend/packages/Upgrade/src/api/models/Query.ts index 1c584826e8..ef639b1975 100644 --- a/backend/packages/Upgrade/src/api/models/Query.ts +++ b/backend/packages/Upgrade/src/api/models/Query.ts @@ -1,9 +1,11 @@ -import { Entity, ManyToOne, Column, PrimaryColumn } from 'typeorm'; +import { Entity, ManyToOne, Column, PrimaryColumn, OneToOne } from 'typeorm'; import { BaseModel } from './base/BaseModel'; import { Metric } from './Metric'; import { Experiment } from './Experiment'; import { IsDefined } from 'class-validator'; import { REPEATED_MEASURE } from 'upgrade_types'; +import { ArchivedStats } from './ArchivedStats'; +import { Type } from 'class-transformer'; @Entity() export class Query extends BaseModel { @@ -23,6 +25,10 @@ export class Query extends BaseModel { @ManyToOne(() => Experiment, (experiment) => experiment.queries, { onDelete: 'CASCADE' }) public experiment: Experiment; + @OneToOne(() => ArchivedStats, (archivedStats) => archivedStats.query, { onDelete: 'CASCADE' }) + @Type(() => ArchivedStats) + public archivedStats: ArchivedStats; + @Column({ type: 'enum', enum: REPEATED_MEASURE, diff --git a/backend/packages/Upgrade/src/api/repositories/ArchivedStatsRepository.ts b/backend/packages/Upgrade/src/api/repositories/ArchivedStatsRepository.ts new file mode 100644 index 0000000000..4f78267a0a --- /dev/null +++ b/backend/packages/Upgrade/src/api/repositories/ArchivedStatsRepository.ts @@ -0,0 +1,24 @@ +import { EntityRepository, Repository } from 'typeorm'; +import { ArchivedStats } from '../models/ArchivedStats'; +import repositoryError from './utils/repositoryError'; + +@EntityRepository(ArchivedStats) +export class ArchivedStatsRepository extends Repository { + public async saveRawJson( + rawDataArray: Array> + ): Promise { + const result = await this.createQueryBuilder('ArchivedStats') + .insert() + .into(ArchivedStats) + .values(rawDataArray) + .onConflict(`DO NOTHING`) + .returning('*') + .execute() + .catch((errorMsg: any) => { + const errorMsgString = repositoryError(this.constructor.name, 'saveRawJson', { rawDataArray }, errorMsg); + throw errorMsgString; + }); + + return result.raw; + } +} \ No newline at end of file diff --git a/backend/packages/Upgrade/src/api/services/ExperimentService.ts b/backend/packages/Upgrade/src/api/services/ExperimentService.ts index 735d7ba9b3..6a62ffb3cf 100644 --- a/backend/packages/Upgrade/src/api/services/ExperimentService.ts +++ b/backend/packages/Upgrade/src/api/services/ExperimentService.ts @@ -66,6 +66,9 @@ import { ExperimentDTO } from '../DTO/ExperimentDTO'; import { ConditionPayloadDTO } from '../DTO/ConditionPayloadDTO'; import { FactorDTO } from '../DTO/FactorDTO'; import { LevelDTO } from '../DTO/LevelDTO'; +import { QueryService } from './QueryService'; +import { ArchivedStats } from '../models/ArchivedStats'; +import { ArchivedStatsRepository } from '../repositories/ArchivedStatsRepository'; @Service() export class ExperimentService { @@ -87,10 +90,12 @@ export class ExperimentService { @OrmRepository() private factorRepository: FactorRepository, @OrmRepository() private levelRepository: LevelRepository, @OrmRepository() private levelCombinationElementsRepository: LevelCombinationElementRepository, + @OrmRepository() private archivedStatsRepository: ArchivedStatsRepository, public previewUserService: PreviewUserService, public segmentService: SegmentService, public scheduledJobService: ScheduledJobService, - public errorService: ErrorService + public errorService: ErrorService, + public queryService: QueryService ) {} public async find(logger?: UpgradeLogger): Promise { @@ -378,7 +383,7 @@ export class ExperimentService { ): Promise { const oldExperiment = await this.experimentRepository.findOne( { id: experimentId }, - { relations: ['stateTimeLogs'] } + { relations: ['stateTimeLogs', 'queries', 'queries.metric'] } ); if ( @@ -388,6 +393,24 @@ export class ExperimentService { await this.populateExclusionTable(experimentId, state, logger); } + if (state === EXPERIMENT_STATE.ARCHIVED) { + const queryIds = oldExperiment.queries.map((query) => query.id); + const results = await this.queryService.analyze(queryIds, logger); + const archivedStatsData: Array> = results.map( + (result) => { + const queryId = result.id; + delete result.id; + const archivedStats: Partial = { + id: uuid(), + result: result, + query: queryId, + }; + return archivedStats; + } + ); + await this.archivedStatsRepository.saveRawJson(archivedStatsData); + } + let data: AuditLogData = { experimentId, experimentName: oldExperiment.name, diff --git a/backend/packages/Upgrade/src/api/services/QueryService.ts b/backend/packages/Upgrade/src/api/services/QueryService.ts index 7ed2cd4e75..fec047f992 100644 --- a/backend/packages/Upgrade/src/api/services/QueryService.ts +++ b/backend/packages/Upgrade/src/api/services/QueryService.ts @@ -8,6 +8,8 @@ import { ErrorService } from './ErrorService'; import { ExperimentError } from '../models/ExperimentError'; import { UpgradeLogger } from '../../lib/logger/UpgradeLogger'; import { Experiment } from '../models/Experiment'; +import { ArchivedStatsRepository } from '../repositories/ArchivedStatsRepository'; +import { In } from 'typeorm'; interface queryResult { conditionId?: string; @@ -21,6 +23,7 @@ export class QueryService { constructor( @OrmRepository() private queryRepository: QueryRepository, @OrmRepository() private logRepository: LogRepository, + @OrmRepository() private archivedStatsRepository: ArchivedStatsRepository, public errorService: ErrorService ) {} @@ -35,6 +38,17 @@ export class QueryService { }); } + public async getArchivedStats(queryIds: string[], logger: UpgradeLogger): Promise { + logger.info({ message: `Get archivedStats of query with queryIds ${queryIds}` }); + const archiveData = await this.archivedStatsRepository.find({ + relations: ['query'], + where: { query: In(queryIds) }, + }); + return archiveData.map((data) => { + return { ...data.result, id: data.query.id }; + }); + } + public async analyze(queryIds: string[], logger: UpgradeLogger): Promise { logger.info({ message: `Get analysis of query with queryIds ${queryIds}` }); const promiseArray = queryIds.map((queryId) => diff --git a/backend/packages/Upgrade/src/database/migrations/1692936809279-archivedState.ts b/backend/packages/Upgrade/src/database/migrations/1692936809279-archivedState.ts new file mode 100644 index 0000000000..b32bfd8075 --- /dev/null +++ b/backend/packages/Upgrade/src/database/migrations/1692936809279-archivedState.ts @@ -0,0 +1,79 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class archivedState1692936809279 implements MigrationInterface { + name = 'archivedState1692936809279'; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `CREATE TABLE "archived_stats" ("createdAt" TIMESTAMP NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP NOT NULL DEFAULT now(), "versionNumber" integer NOT NULL, "id" uuid NOT NULL, "result" jsonb NOT NULL, "queryId" uuid, CONSTRAINT "REL_df18fe5ea7298a1dc7bfb33b06" UNIQUE ("queryId"), CONSTRAINT "PK_afc8a335c8d9d48cefaf1aa2c09" PRIMARY KEY ("id"))` + ); + await queryRunner.query( + `ALTER TYPE "public"."state_time_log_fromstate_enum" RENAME TO "state_time_log_fromstate_enum_old"` + ); + await queryRunner.query( + `CREATE TYPE "public"."state_time_log_fromstate_enum" AS ENUM('inactive', 'preview', 'scheduled', 'enrolling', 'enrollmentComplete', 'cancelled', 'archived')` + ); + await queryRunner.query( + `ALTER TABLE "public"."state_time_log" ALTER COLUMN "fromState" TYPE "public"."state_time_log_fromstate_enum" USING "fromState"::"text"::"public"."state_time_log_fromstate_enum"` + ); + await queryRunner.query(`DROP TYPE "public"."state_time_log_fromstate_enum_old"`); + await queryRunner.query( + `ALTER TYPE "public"."state_time_log_tostate_enum" RENAME TO "state_time_log_tostate_enum_old"` + ); + await queryRunner.query( + `CREATE TYPE "public"."state_time_log_tostate_enum" AS ENUM('inactive', 'preview', 'scheduled', 'enrolling', 'enrollmentComplete', 'cancelled', 'archived')` + ); + await queryRunner.query( + `ALTER TABLE "public"."state_time_log" ALTER COLUMN "toState" TYPE "public"."state_time_log_tostate_enum" USING "toState"::"text"::"public"."state_time_log_tostate_enum"` + ); + await queryRunner.query(`DROP TYPE "public"."state_time_log_tostate_enum_old"`); + await queryRunner.query(`ALTER TYPE "public"."experiment_state_enum" RENAME TO "experiment_state_enum_old"`); + await queryRunner.query( + `CREATE TYPE "public"."experiment_state_enum" AS ENUM('inactive', 'preview', 'scheduled', 'enrolling', 'enrollmentComplete', 'cancelled', 'archived')` + ); + await queryRunner.query(`ALTER TABLE "public"."experiment" ALTER COLUMN "state" DROP DEFAULT`); + await queryRunner.query( + `ALTER TABLE "public"."experiment" ALTER COLUMN "state" TYPE "public"."experiment_state_enum" USING "state"::"text"::"public"."experiment_state_enum"` + ); + await queryRunner.query(`ALTER TABLE "public"."experiment" ALTER COLUMN "state" SET DEFAULT 'inactive'`); + await queryRunner.query(`DROP TYPE "public"."experiment_state_enum_old"`); + await queryRunner.query( + `ALTER TABLE "archived_stats" ADD CONSTRAINT "FK_df18fe5ea7298a1dc7bfb33b06f" FOREIGN KEY ("queryId") REFERENCES "query"("id") ON DELETE CASCADE ON UPDATE NO ACTION` + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "archived_stats" DROP CONSTRAINT "FK_df18fe5ea7298a1dc7bfb33b06f"`); + await queryRunner.query( + `CREATE TYPE "public"."experiment_state_enum_old" AS ENUM('cancelled', 'enrolling', 'enrollmentComplete', 'inactive', 'preview', 'scheduled')` + ); + await queryRunner.query(`ALTER TABLE "public"."experiment" ALTER COLUMN "state" DROP DEFAULT`); + await queryRunner.query( + `ALTER TABLE "public"."experiment" ALTER COLUMN "state" TYPE "public"."experiment_state_enum_old" USING "state"::"text"::"public"."experiment_state_enum_old"` + ); + await queryRunner.query(`ALTER TABLE "public"."experiment" ALTER COLUMN "state" SET DEFAULT 'inactive'`); + await queryRunner.query(`DROP TYPE "public"."experiment_state_enum"`); + await queryRunner.query(`ALTER TYPE "public"."experiment_state_enum_old" RENAME TO "experiment_state_enum"`); + await queryRunner.query( + `CREATE TYPE "public"."state_time_log_tostate_enum_old" AS ENUM('cancelled', 'enrolling', 'enrollmentComplete', 'inactive', 'preview', 'scheduled')` + ); + await queryRunner.query( + `ALTER TABLE "public"."state_time_log" ALTER COLUMN "toState" TYPE "public"."state_time_log_tostate_enum_old" USING "toState"::"text"::"public"."state_time_log_tostate_enum_old"` + ); + await queryRunner.query(`DROP TYPE "public"."state_time_log_tostate_enum"`); + await queryRunner.query( + `ALTER TYPE "public"."state_time_log_tostate_enum_old" RENAME TO "state_time_log_tostate_enum"` + ); + await queryRunner.query( + `CREATE TYPE "public"."state_time_log_fromstate_enum_old" AS ENUM('cancelled', 'enrolling', 'enrollmentComplete', 'inactive', 'preview', 'scheduled')` + ); + await queryRunner.query( + `ALTER TABLE "public"."state_time_log" ALTER COLUMN "fromState" TYPE "public"."state_time_log_fromstate_enum_old" USING "fromState"::"text"::"public"."state_time_log_fromstate_enum_old"` + ); + await queryRunner.query(`DROP TYPE "public"."state_time_log_fromstate_enum"`); + await queryRunner.query( + `ALTER TYPE "public"."state_time_log_fromstate_enum_old" RENAME TO "state_time_log_fromstate_enum"` + ); + await queryRunner.query(`DROP TABLE "archived_stats"`); + } +} diff --git a/backend/packages/Upgrade/test/unit/services/QueryService.test.ts b/backend/packages/Upgrade/test/unit/services/QueryService.test.ts index b0a675d586..595bfb4a93 100644 --- a/backend/packages/Upgrade/test/unit/services/QueryService.test.ts +++ b/backend/packages/Upgrade/test/unit/services/QueryService.test.ts @@ -9,12 +9,15 @@ import { Query } from '../../../src/api/models/Query'; import { Experiment } from '../../../src/api/models/Experiment'; import { ErrorService } from '../../../src/api/services/ErrorService'; import { ErrorRepository } from '../../../src/api/repositories/ErrorRepository'; +import { ArchivedStatsRepository } from '../../../src/api/repositories/ArchivedStatsRepository'; +import { ArchivedStats } from '../../../src/api/models/ArchivedStats'; const logger = new UpgradeLogger(); describe('Query Service Testing', () => { let service: QueryService; let queryRepo: Repository; + let archivedStatsRepo: Repository; let module: TestingModule; const exp1 = new Experiment(); @@ -43,12 +46,19 @@ describe('Query Service Testing', () => { result: 0, participantsLogged: 0, }; + + const mockArchiveData = new ArchivedStats(); + mockArchiveData.id = 'id1'; + mockArchiveData.query = mockquery1; + mockArchiveData.result = { mainEffect: logResult, interactionEffect: null }; + beforeEach(async () => { module = await Test.createTestingModule({ providers: [ QueryService, QueryRepository, LogRepository, + ArchivedStatsRepository, ErrorService, ErrorRepository, { @@ -69,6 +79,12 @@ describe('Query Service Testing', () => { }), }, }, + { + provide: getRepositoryToken(ArchivedStatsRepository), + useValue: { + find: jest.fn().mockResolvedValue([mockArchiveData]), + }, + }, { provide: ErrorService, useValue: { @@ -80,6 +96,7 @@ describe('Query Service Testing', () => { service = module.get(QueryService); queryRepo = module.get>(getRepositoryToken(QueryRepository)); + archivedStatsRepo = module.get>(getRepositoryToken(ArchivedStatsRepository)); }); it('should be defined', async () => { @@ -90,6 +107,10 @@ describe('Query Service Testing', () => { expect(await queryRepo.find()).toEqual(queryArr); }); + it('should have the repo mocked', async () => { + expect(await archivedStatsRepo.find()).toEqual([mockArchiveData]); + }); + it('should find and map queries to experiments', async () => { const response = await service.find(logger); expect(response).toEqual([ @@ -134,4 +155,15 @@ describe('Query Service Testing', () => { }, ]); }); + + it('should find and map archivedStats to queries', async () => { + const response = await service.getArchivedStats(['id1'], logger); + expect(response).toEqual([ + { + id: mockquery1.id, + interactionEffect: null, + mainEffect: logResult, + }, + ]); + }); }); diff --git a/frontend/projects/upgrade/src/app/core/analysis/analysis.data.service.ts b/frontend/projects/upgrade/src/app/core/analysis/analysis.data.service.ts index 8439059777..cbb67d8214 100644 --- a/frontend/projects/upgrade/src/app/core/analysis/analysis.data.service.ts +++ b/frontend/projects/upgrade/src/app/core/analysis/analysis.data.service.ts @@ -26,4 +26,9 @@ export class AnalysisDataService { const url = this.environment.api.queryResult; return this.http.post(url, { queryIds }); } + + archiveQuery(queryIds: string[]) { + const url = this.environment.api.archiveResult; + return this.http.post(url, { queryIds }); + } } diff --git a/frontend/projects/upgrade/src/app/core/analysis/analysis.service.ts b/frontend/projects/upgrade/src/app/core/analysis/analysis.service.ts index c6a9f7c342..407fb2282a 100644 --- a/frontend/projects/upgrade/src/app/core/analysis/analysis.service.ts +++ b/frontend/projects/upgrade/src/app/core/analysis/analysis.service.ts @@ -10,6 +10,7 @@ import { } from './store/analysis.selectors'; import * as AnalysisActions from './store/analysis.actions'; import { UpsertMetrics } from './store/analysis.models'; +import { EXPERIMENT_STATE } from '../experiments/store/experiments.model'; @Injectable() export class AnalysisService { @@ -33,8 +34,8 @@ export class AnalysisService { this.store$.dispatch(AnalysisActions.actionDeleteMetric({ key })); } - executeQuery(queryIds: string[]) { - this.store$.dispatch(AnalysisActions.actionExecuteQuery({ queryIds })); + executeQuery(queryIds: string[], state?: EXPERIMENT_STATE) { + this.store$.dispatch(AnalysisActions.actionExecuteQuery({ queryIds, state })); } setQueryResult(queryResult: any) { diff --git a/frontend/projects/upgrade/src/app/core/analysis/store/analysis.actions.ts b/frontend/projects/upgrade/src/app/core/analysis/store/analysis.actions.ts index d6594344e4..834293d399 100644 --- a/frontend/projects/upgrade/src/app/core/analysis/store/analysis.actions.ts +++ b/frontend/projects/upgrade/src/app/core/analysis/store/analysis.actions.ts @@ -1,5 +1,6 @@ import { createAction, props } from '@ngrx/store'; import { MetricUnit, UpsertMetrics } from './analysis.models'; +import { EXPERIMENT_STATE } from '../../experiments/store/experiments.model'; export const actionFetchMetrics = createAction('[Analysis] Fetch Metrics'); @@ -33,7 +34,10 @@ export const actionUpsertMetricsSuccess = createAction( export const actionUpsertMetricsFailure = createAction('[Analysis] Upsert Metrics Failure'); -export const actionExecuteQuery = createAction('[Analysis] Execute Query', props<{ queryIds: string[] }>()); +export const actionExecuteQuery = createAction( + '[Analysis] Execute Query', + props<{ queryIds: string[]; state?: EXPERIMENT_STATE }>() +); export const actionExecuteQuerySuccess = createAction( '[Analysis] Execute Query Success', diff --git a/frontend/projects/upgrade/src/app/core/analysis/store/analysis.effects.ts b/frontend/projects/upgrade/src/app/core/analysis/store/analysis.effects.ts index e90b684501..af3511370d 100644 --- a/frontend/projects/upgrade/src/app/core/analysis/store/analysis.effects.ts +++ b/frontend/projects/upgrade/src/app/core/analysis/store/analysis.effects.ts @@ -6,6 +6,7 @@ import { AnalysisDataService } from '../analysis.data.service'; import { Store, select } from '@ngrx/store'; import { AppState } from '../../core.state'; import { selectQueryResult } from './analysis.selectors'; +import { EXPERIMENT_STATE } from '../../experiments/store/experiments.model'; @Injectable() export class AnalysisEffects { @@ -66,11 +67,15 @@ export class AnalysisEffects { executeQuery$ = createEffect(() => this.actions$.pipe( ofType(AnalysisActions.actionExecuteQuery), - map((action) => action.queryIds), - filter((queryIds) => !!queryIds.length), + map((action) => ({ queryIds: action.queryIds, state: action.state })), + filter(({ queryIds }) => !!queryIds.length), withLatestFrom(this.store$.pipe(select(selectQueryResult))), - switchMap(([queryIds, queryResult]) => - this.analysisDataService.executeQuery(queryIds).pipe( + switchMap(([{ queryIds, state }, queryResult]) => { + const analysisData = + (state && state === EXPERIMENT_STATE.ARCHIVED) + ? this.analysisDataService.archiveQuery(queryIds) + : this.analysisDataService.executeQuery(queryIds); + return analysisData.pipe( map((data: any) => { let newResults = queryResult && queryResult.length ? queryResult : []; if (data.length) { @@ -86,8 +91,8 @@ export class AnalysisEffects { return AnalysisActions.actionExecuteQuerySuccess({ queryResult: newResults }); }), catchError(() => [AnalysisActions.actionExecuteQueryFailure()]) - ) - ) + ); + }) ) ); } diff --git a/frontend/projects/upgrade/src/app/core/experiments/store/experiments.effects.ts b/frontend/projects/upgrade/src/app/core/experiments/store/experiments.effects.ts index c380917f55..ad3aa623da 100644 --- a/frontend/projects/upgrade/src/app/core/experiments/store/experiments.effects.ts +++ b/frontend/projects/upgrade/src/app/core/experiments/store/experiments.effects.ts @@ -163,7 +163,10 @@ export class ExperimentEffects { experimentAction.actionFetchExperimentStatsSuccess({ stats }), experimentAction.actionUpsertExperimentSuccess({ experiment: data }), experimentAction.actionFetchAllDecisionPoints(), - analysisAction.actionExecuteQuery({ queryIds }), + analysisAction.actionExecuteQuery({ + queryIds, + state: data.state, + }), ]; }) ) diff --git a/frontend/projects/upgrade/src/app/features/dashboard/home/components/experiment-query-result/experiment-query-result.component.ts b/frontend/projects/upgrade/src/app/features/dashboard/home/components/experiment-query-result/experiment-query-result.component.ts index 38c49e68c0..41d4c264d6 100644 --- a/frontend/projects/upgrade/src/app/features/dashboard/home/components/experiment-query-result/experiment-query-result.component.ts +++ b/frontend/projects/upgrade/src/app/features/dashboard/home/components/experiment-query-result/experiment-query-result.component.ts @@ -13,7 +13,7 @@ import { import { AnalysisService } from '../../../../../core/analysis/analysis.service'; import { Subscription } from 'rxjs'; import { filter } from 'rxjs/operators'; -import { EXPERIMENT_TYPE } from 'upgrade_types'; +import { EXPERIMENT_STATE, EXPERIMENT_TYPE } from 'upgrade_types'; import { ExperimentFactorData } from '../../../../../core/experiment-design-stepper/store/experiment-design-stepper.model'; interface FactorColumnDef { @@ -53,6 +53,7 @@ export class ExperimentQueryResultComponent implements OnInit, OnDestroy { displayedColumns: string[] = []; factorialData = {}; experimentType: string = null; + experimentState: EXPERIMENT_STATE; data: { name: string; series: { name: string; value: number }[]; dot: boolean }[]; meanData2: { name: string; value: number }[]; meanData1: { name: string; value: number }[]; @@ -76,6 +77,7 @@ export class ExperimentQueryResultComponent implements OnInit, OnDestroy { ngOnInit() { const queryIds = []; this.experimentType = this.experiment.type; + this.experimentState = this.experiment.state if (this.experimentType === EXPERIMENT_TYPE.FACTORIAL) { this.setMaxLevelsCount(); @@ -99,7 +101,7 @@ export class ExperimentQueryResultComponent implements OnInit, OnDestroy { [query.id]: [], }; }); - this.analysisService.executeQuery(queryIds); + this.analysisService.executeQuery(queryIds, this.experimentState); this.queryResultsSub = this.analysisService.queryResult$.pipe(filter((result) => !!result)).subscribe((result) => { // main effect graph data this.populateMainEffectGraphData(result); diff --git a/frontend/projects/upgrade/src/environments/environment-types.ts b/frontend/projects/upgrade/src/environments/environment-types.ts index 4ee5f58f29..9a8f34bb98 100644 --- a/frontend/projects/upgrade/src/environments/environment-types.ts +++ b/frontend/projects/upgrade/src/environments/environment-types.ts @@ -33,6 +33,7 @@ export interface APIEndpoints { metrics: string; metricsSave: string; queryResult: string; + archiveResult: string; getVersion: string; contextMetaData: string; segments: string; diff --git a/frontend/projects/upgrade/src/environments/environment.bsnl.ts b/frontend/projects/upgrade/src/environments/environment.bsnl.ts index 5275644957..f7bc065972 100644 --- a/frontend/projects/upgrade/src/environments/environment.bsnl.ts +++ b/frontend/projects/upgrade/src/environments/environment.bsnl.ts @@ -42,6 +42,7 @@ export const environment = { metrics: '/metric', metricsSave: '/metric/save', queryResult: '/query/analyse', + archiveResult: '/query/archive', getVersion: '/version', contextMetaData: '/experiments/contextMetaData', segments: '/segments', diff --git a/frontend/projects/upgrade/src/environments/environment.demo.prod.ts b/frontend/projects/upgrade/src/environments/environment.demo.prod.ts index 0025d9ba13..09e1ec19fe 100755 --- a/frontend/projects/upgrade/src/environments/environment.demo.prod.ts +++ b/frontend/projects/upgrade/src/environments/environment.demo.prod.ts @@ -42,6 +42,7 @@ export const environment = { metrics: '/metric', metricsSave: '/metric/save', queryResult: '/query/analyse', + archiveResult: '/query/archive', getVersion: '/version', contextMetaData: '/experiments/contextMetaData', segments: '/segments', diff --git a/frontend/projects/upgrade/src/environments/environment.prod.ts b/frontend/projects/upgrade/src/environments/environment.prod.ts index f8a2b2d7b3..ef8e0d2fb1 100755 --- a/frontend/projects/upgrade/src/environments/environment.prod.ts +++ b/frontend/projects/upgrade/src/environments/environment.prod.ts @@ -42,6 +42,7 @@ export const environment = { metrics: '/metric', metricsSave: '/metric/save', queryResult: '/query/analyse', + archiveResult: '/query/archive', getVersion: '/version', contextMetaData: '/experiments/contextMetaData', segments: '/segments', diff --git a/frontend/projects/upgrade/src/environments/environment.staging.ts b/frontend/projects/upgrade/src/environments/environment.staging.ts index f92d2f8cdb..eb8a9facfd 100644 --- a/frontend/projects/upgrade/src/environments/environment.staging.ts +++ b/frontend/projects/upgrade/src/environments/environment.staging.ts @@ -42,6 +42,7 @@ export const environment = { metrics: '/metric', metricsSave: '/metric/save', queryResult: '/query/analyse', + archiveResult: '/query/archive', getVersion: '/version', contextMetaData: '/experiments/contextMetaData', segments: '/segments', diff --git a/frontend/projects/upgrade/src/environments/environment.ts b/frontend/projects/upgrade/src/environments/environment.ts index b859c1b323..e736c7e82f 100755 --- a/frontend/projects/upgrade/src/environments/environment.ts +++ b/frontend/projects/upgrade/src/environments/environment.ts @@ -46,6 +46,7 @@ export const environment = { metrics: '/metric', metricsSave: '/metric/save', queryResult: '/query/analyse', + archiveResult: '/query/archive', getVersion: '/version', contextMetaData: '/experiments/contextMetaData', segments: '/segments', From bd8b669f7ef6029d3a11b860465e2a1c844e7601 Mon Sep 17 00:00:00 2001 From: pratik Date: Mon, 28 Aug 2023 17:55:23 +0530 Subject: [PATCH 06/12] resolved failing test cases for archive state --- .../Upgrade/src/api/repositories/MetricRepository.ts | 2 +- .../test/unit/repositories/MetricRepository.test.ts | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/backend/packages/Upgrade/src/api/repositories/MetricRepository.ts b/backend/packages/Upgrade/src/api/repositories/MetricRepository.ts index 16492277bf..84882e8291 100644 --- a/backend/packages/Upgrade/src/api/repositories/MetricRepository.ts +++ b/backend/packages/Upgrade/src/api/repositories/MetricRepository.ts @@ -35,7 +35,7 @@ export class MetricRepository extends Repository { .innerJoin('metrics.queries', 'queries') .innerJoin('queries.experiment', 'experiment') .where('key IN (:...ids)', { ids }) - .andWhere('experiment.state NOT IN (:...archivedAndInactive)', { archivedAndInactive : [EXPERIMENT_STATE.ARCHIVED, EXPERIMENT_STATE.INACTIVE ]}) + .andWhere('experiment.state NOT IN (:...archived)', { archived: [EXPERIMENT_STATE.ARCHIVED] }) .getMany() .catch((errorMsg: any) => { const errorMsgString = repositoryError(this.constructor.name, 'findMetricsWithQueries', { ids }, errorMsg); diff --git a/backend/packages/Upgrade/test/unit/repositories/MetricRepository.test.ts b/backend/packages/Upgrade/test/unit/repositories/MetricRepository.test.ts index d6ab581d98..e3929d06cf 100644 --- a/backend/packages/Upgrade/test/unit/repositories/MetricRepository.test.ts +++ b/backend/packages/Upgrade/test/unit/repositories/MetricRepository.test.ts @@ -26,7 +26,7 @@ afterEach(() => { }); describe('MetricRepository Testing', () => { - it('should delete a metric', async () => { + it('should delete a metric', async () => { createQueryBuilderStub = sandbox.stub(MetricRepository.prototype, 'createQueryBuilder').returns(deleteQueryBuilder); const result = { identifiers: [{ id: metric.key }], @@ -106,8 +106,9 @@ describe('MetricRepository Testing', () => { raw: [metric], }; - selectMock.expects('innerJoin').once().returns(selectQueryBuilder); + selectMock.expects('innerJoin').twice().returns(selectQueryBuilder); selectMock.expects('where').once().returns(selectQueryBuilder); + selectMock.expects('andWhere').once().returns(selectQueryBuilder); selectMock.expects('getMany').once().returns(Promise.resolve(result)); const res = await repo.findMetricsWithQueries([metric.key]); @@ -121,8 +122,9 @@ describe('MetricRepository Testing', () => { it('should throw an error when get monitored experiment metric by date range fails', async () => { createQueryBuilderStub = sandbox.stub(MetricRepository.prototype, 'createQueryBuilder').returns(selectQueryBuilder); - selectMock.expects('innerJoin').once().returns(selectQueryBuilder); + selectMock.expects('innerJoin').twice().returns(selectQueryBuilder); selectMock.expects('where').once().returns(selectQueryBuilder); + selectMock.expects('andWhere').once().returns(selectQueryBuilder); selectMock.expects('getMany').once().returns(Promise.reject(err)); expect(async () => { From f72c420cf7bb15282cc54747aec0bb2ea085ec84 Mon Sep 17 00:00:00 2001 From: pratik Date: Mon, 28 Aug 2023 19:31:03 +0530 Subject: [PATCH 07/12] import change --- .../packages/Upgrade/src/api/repositories/MetricRepository.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/packages/Upgrade/src/api/repositories/MetricRepository.ts b/backend/packages/Upgrade/src/api/repositories/MetricRepository.ts index 84882e8291..794963e74f 100644 --- a/backend/packages/Upgrade/src/api/repositories/MetricRepository.ts +++ b/backend/packages/Upgrade/src/api/repositories/MetricRepository.ts @@ -1,7 +1,7 @@ import { Metric } from '../models/Metric'; import { EntityRepository, Repository } from 'typeorm'; import repositoryError from './utils/repositoryError'; -import { EXPERIMENT_STATE } from '../../../../../../types/src'; +import { EXPERIMENT_STATE } from 'upgrade_types'; @EntityRepository(Metric) export class MetricRepository extends Repository { From d0a7763919a413ee36063e8f07b02031b322742e Mon Sep 17 00:00:00 2001 From: pratik Date: Thu, 31 Aug 2023 15:17:26 +0530 Subject: [PATCH 08/12] not allowing archived state change from enrolling state --- .../modal/experiment-status/experiment-status.component.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/frontend/projects/upgrade/src/app/features/dashboard/home/components/modal/experiment-status/experiment-status.component.ts b/frontend/projects/upgrade/src/app/features/dashboard/home/components/modal/experiment-status/experiment-status.component.ts index 55ba1610dd..8803dc5183 100644 --- a/frontend/projects/upgrade/src/app/features/dashboard/home/components/modal/experiment-status/experiment-status.component.ts +++ b/frontend/projects/upgrade/src/app/features/dashboard/home/components/modal/experiment-status/experiment-status.component.ts @@ -67,10 +67,14 @@ export class ExperimentStatusComponent implements OnInit { ); switch (this.experimentInfo.state) { case EXPERIMENT_STATE.ENROLLING: + this.experimentStatus = [ + { value: EXPERIMENT_STATE.ENROLLMENT_COMPLETE }, + { value: EXPERIMENT_STATE.CANCELLED }, + ]; + break; case EXPERIMENT_STATE.ENROLLMENT_COMPLETE: this.experimentStatus = [ { value: EXPERIMENT_STATE.ENROLLING }, - { value: EXPERIMENT_STATE.ENROLLMENT_COMPLETE }, { value: EXPERIMENT_STATE.CANCELLED }, { value: EXPERIMENT_STATE.ARCHIVED }, ]; From 3be74d616bfd6c94b9e637d04997174e9c190ea7 Mon Sep 17 00:00:00 2001 From: RidhamShah Date: Mon, 11 Sep 2023 10:30:57 +0530 Subject: [PATCH 09/12] merge analysis and archieve api --- .../src/api/controllers/QueryController.ts | 36 ------------------- .../Upgrade/src/api/models/ArchivedStats.ts | 2 +- .../Upgrade/src/api/services/QueryService.ts | 8 ++++- .../core/analysis/analysis.data.service.ts | 5 --- .../src/app/core/analysis/analysis.service.ts | 4 +-- .../core/analysis/store/analysis.actions.ts | 5 +-- .../core/analysis/store/analysis.effects.ts | 17 ++++----- .../core/analysis/store/analysis.selectors.ts | 2 +- .../experiments/store/experiments.effects.ts | 5 +-- .../experiment-query-result.component.ts | 3 +- .../src/environments/environment.bsnl.ts | 1 - .../src/environments/environment.demo.prod.ts | 1 - .../src/environments/environment.prod.ts | 1 - .../src/environments/environment.staging.ts | 1 - .../upgrade/src/environments/environment.ts | 1 - 15 files changed, 20 insertions(+), 72 deletions(-) diff --git a/backend/packages/Upgrade/src/api/controllers/QueryController.ts b/backend/packages/Upgrade/src/api/controllers/QueryController.ts index 872b7a7887..047dca8d11 100644 --- a/backend/packages/Upgrade/src/api/controllers/QueryController.ts +++ b/backend/packages/Upgrade/src/api/controllers/QueryController.ts @@ -50,40 +50,4 @@ export class QueryController { ): Promise { return this.queryService.analyze(dataLogParams.queryIds, request.logger); } - - /** - * @swagger - * /query/archive: - * post: - * description: Data log analysis - * consumes: - * - application/json - * parameters: - * - in: body - * name: params - * required: true - * schema: - * type: object - * properties: - * queryIds: - * type: array - * items: - * type: string - * description: Data analysis - * tags: - * - Query - * produces: - * - application/json - * responses: - * '200': - * description: Get data analysis - */ - @Post('/archive') - public archive( - @Body() - dataLogParams: DataLogAnalysisValidator, - @Req() request: AppRequest - ): Promise { - return this.queryService.getArchivedStats(dataLogParams.queryIds, request.logger); - } } diff --git a/backend/packages/Upgrade/src/api/models/ArchivedStats.ts b/backend/packages/Upgrade/src/api/models/ArchivedStats.ts index 9b4205ce4d..91702fccd4 100644 --- a/backend/packages/Upgrade/src/api/models/ArchivedStats.ts +++ b/backend/packages/Upgrade/src/api/models/ArchivedStats.ts @@ -10,7 +10,7 @@ export class ArchivedStats extends BaseModel { @IsNotEmpty() @Column('jsonb') - public result: any; + public result: object; @OneToOne(() => Query, (query) => query.archivedStats, { onDelete: 'CASCADE' }) @JoinColumn() diff --git a/backend/packages/Upgrade/src/api/services/QueryService.ts b/backend/packages/Upgrade/src/api/services/QueryService.ts index fec047f992..84d65982a1 100644 --- a/backend/packages/Upgrade/src/api/services/QueryService.ts +++ b/backend/packages/Upgrade/src/api/services/QueryService.ts @@ -3,7 +3,7 @@ import { OrmRepository } from 'typeorm-typedi-extensions'; import { QueryRepository } from '../repositories/QueryRepository'; import { Query } from '../models/Query'; import { LogRepository } from '../repositories/LogRepository'; -import { EXPERIMENT_TYPE, SERVER_ERROR } from 'upgrade_types'; +import { EXPERIMENT_STATE, EXPERIMENT_TYPE, SERVER_ERROR } from 'upgrade_types'; import { ErrorService } from './ErrorService'; import { ExperimentError } from '../models/ExperimentError'; import { UpgradeLogger } from '../../lib/logger/UpgradeLogger'; @@ -66,6 +66,12 @@ export class QueryService { const promiseResult = await Promise.all(promiseArray); const experiments: Experiment[] = []; + + // checks for archieve state experiment + if (promiseResult[0].experiment?.state === EXPERIMENT_STATE.ARCHIVED) { + return await this.getArchivedStats(queryIds, logger); + } + const analyzePromise = promiseResult.map((query) => { experiments.push(query.experiment); if (query.experiment?.type === EXPERIMENT_TYPE.FACTORIAL) { diff --git a/frontend/projects/upgrade/src/app/core/analysis/analysis.data.service.ts b/frontend/projects/upgrade/src/app/core/analysis/analysis.data.service.ts index cbb67d8214..8439059777 100644 --- a/frontend/projects/upgrade/src/app/core/analysis/analysis.data.service.ts +++ b/frontend/projects/upgrade/src/app/core/analysis/analysis.data.service.ts @@ -26,9 +26,4 @@ export class AnalysisDataService { const url = this.environment.api.queryResult; return this.http.post(url, { queryIds }); } - - archiveQuery(queryIds: string[]) { - const url = this.environment.api.archiveResult; - return this.http.post(url, { queryIds }); - } } diff --git a/frontend/projects/upgrade/src/app/core/analysis/analysis.service.ts b/frontend/projects/upgrade/src/app/core/analysis/analysis.service.ts index 407fb2282a..5903d37869 100644 --- a/frontend/projects/upgrade/src/app/core/analysis/analysis.service.ts +++ b/frontend/projects/upgrade/src/app/core/analysis/analysis.service.ts @@ -34,8 +34,8 @@ export class AnalysisService { this.store$.dispatch(AnalysisActions.actionDeleteMetric({ key })); } - executeQuery(queryIds: string[], state?: EXPERIMENT_STATE) { - this.store$.dispatch(AnalysisActions.actionExecuteQuery({ queryIds, state })); + executeQuery(queryIds: string[]) { + this.store$.dispatch(AnalysisActions.actionExecuteQuery({ queryIds })); } setQueryResult(queryResult: any) { diff --git a/frontend/projects/upgrade/src/app/core/analysis/store/analysis.actions.ts b/frontend/projects/upgrade/src/app/core/analysis/store/analysis.actions.ts index 834293d399..64b06f667f 100644 --- a/frontend/projects/upgrade/src/app/core/analysis/store/analysis.actions.ts +++ b/frontend/projects/upgrade/src/app/core/analysis/store/analysis.actions.ts @@ -34,10 +34,7 @@ export const actionUpsertMetricsSuccess = createAction( export const actionUpsertMetricsFailure = createAction('[Analysis] Upsert Metrics Failure'); -export const actionExecuteQuery = createAction( - '[Analysis] Execute Query', - props<{ queryIds: string[]; state?: EXPERIMENT_STATE }>() -); +export const actionExecuteQuery = createAction('[Analysis] Execute Query', props<{ queryIds: string[] }>()); export const actionExecuteQuerySuccess = createAction( '[Analysis] Execute Query Success', diff --git a/frontend/projects/upgrade/src/app/core/analysis/store/analysis.effects.ts b/frontend/projects/upgrade/src/app/core/analysis/store/analysis.effects.ts index af3511370d..e90b684501 100644 --- a/frontend/projects/upgrade/src/app/core/analysis/store/analysis.effects.ts +++ b/frontend/projects/upgrade/src/app/core/analysis/store/analysis.effects.ts @@ -6,7 +6,6 @@ import { AnalysisDataService } from '../analysis.data.service'; import { Store, select } from '@ngrx/store'; import { AppState } from '../../core.state'; import { selectQueryResult } from './analysis.selectors'; -import { EXPERIMENT_STATE } from '../../experiments/store/experiments.model'; @Injectable() export class AnalysisEffects { @@ -67,15 +66,11 @@ export class AnalysisEffects { executeQuery$ = createEffect(() => this.actions$.pipe( ofType(AnalysisActions.actionExecuteQuery), - map((action) => ({ queryIds: action.queryIds, state: action.state })), - filter(({ queryIds }) => !!queryIds.length), + map((action) => action.queryIds), + filter((queryIds) => !!queryIds.length), withLatestFrom(this.store$.pipe(select(selectQueryResult))), - switchMap(([{ queryIds, state }, queryResult]) => { - const analysisData = - (state && state === EXPERIMENT_STATE.ARCHIVED) - ? this.analysisDataService.archiveQuery(queryIds) - : this.analysisDataService.executeQuery(queryIds); - return analysisData.pipe( + switchMap(([queryIds, queryResult]) => + this.analysisDataService.executeQuery(queryIds).pipe( map((data: any) => { let newResults = queryResult && queryResult.length ? queryResult : []; if (data.length) { @@ -91,8 +86,8 @@ export class AnalysisEffects { return AnalysisActions.actionExecuteQuerySuccess({ queryResult: newResults }); }), catchError(() => [AnalysisActions.actionExecuteQueryFailure()]) - ); - }) + ) + ) ) ); } diff --git a/frontend/projects/upgrade/src/app/core/analysis/store/analysis.selectors.ts b/frontend/projects/upgrade/src/app/core/analysis/store/analysis.selectors.ts index ce1368c164..a6d06d29da 100644 --- a/frontend/projects/upgrade/src/app/core/analysis/store/analysis.selectors.ts +++ b/frontend/projects/upgrade/src/app/core/analysis/store/analysis.selectors.ts @@ -1,5 +1,5 @@ import { createSelector, createFeatureSelector } from '@ngrx/store'; -import { AnalysisState, State } from './analysis.models'; +import { AnalysisState } from './analysis.models'; export const selectAnalysisState = createFeatureSelector('analysis'); diff --git a/frontend/projects/upgrade/src/app/core/experiments/store/experiments.effects.ts b/frontend/projects/upgrade/src/app/core/experiments/store/experiments.effects.ts index ad3aa623da..c380917f55 100644 --- a/frontend/projects/upgrade/src/app/core/experiments/store/experiments.effects.ts +++ b/frontend/projects/upgrade/src/app/core/experiments/store/experiments.effects.ts @@ -163,10 +163,7 @@ export class ExperimentEffects { experimentAction.actionFetchExperimentStatsSuccess({ stats }), experimentAction.actionUpsertExperimentSuccess({ experiment: data }), experimentAction.actionFetchAllDecisionPoints(), - analysisAction.actionExecuteQuery({ - queryIds, - state: data.state, - }), + analysisAction.actionExecuteQuery({ queryIds }), ]; }) ) diff --git a/frontend/projects/upgrade/src/app/features/dashboard/home/components/experiment-query-result/experiment-query-result.component.ts b/frontend/projects/upgrade/src/app/features/dashboard/home/components/experiment-query-result/experiment-query-result.component.ts index 41d4c264d6..3f606b10c9 100644 --- a/frontend/projects/upgrade/src/app/features/dashboard/home/components/experiment-query-result/experiment-query-result.component.ts +++ b/frontend/projects/upgrade/src/app/features/dashboard/home/components/experiment-query-result/experiment-query-result.component.ts @@ -77,7 +77,6 @@ export class ExperimentQueryResultComponent implements OnInit, OnDestroy { ngOnInit() { const queryIds = []; this.experimentType = this.experiment.type; - this.experimentState = this.experiment.state if (this.experimentType === EXPERIMENT_TYPE.FACTORIAL) { this.setMaxLevelsCount(); @@ -101,7 +100,7 @@ export class ExperimentQueryResultComponent implements OnInit, OnDestroy { [query.id]: [], }; }); - this.analysisService.executeQuery(queryIds, this.experimentState); + this.analysisService.executeQuery(queryIds); this.queryResultsSub = this.analysisService.queryResult$.pipe(filter((result) => !!result)).subscribe((result) => { // main effect graph data this.populateMainEffectGraphData(result); diff --git a/frontend/projects/upgrade/src/environments/environment.bsnl.ts b/frontend/projects/upgrade/src/environments/environment.bsnl.ts index fc2d747dcb..5f68b645e3 100644 --- a/frontend/projects/upgrade/src/environments/environment.bsnl.ts +++ b/frontend/projects/upgrade/src/environments/environment.bsnl.ts @@ -42,7 +42,6 @@ export const environment = { metrics: '/metric', metricsSave: '/metric/save', queryResult: '/query/analyse', - archiveResult: '/query/archive', getVersion: '/version', contextMetaData: '/experiments/contextMetaData', segments: '/segments', diff --git a/frontend/projects/upgrade/src/environments/environment.demo.prod.ts b/frontend/projects/upgrade/src/environments/environment.demo.prod.ts index 313b67898b..083bd4c595 100755 --- a/frontend/projects/upgrade/src/environments/environment.demo.prod.ts +++ b/frontend/projects/upgrade/src/environments/environment.demo.prod.ts @@ -42,7 +42,6 @@ export const environment = { metrics: '/metric', metricsSave: '/metric/save', queryResult: '/query/analyse', - archiveResult: '/query/archive', getVersion: '/version', contextMetaData: '/experiments/contextMetaData', segments: '/segments', diff --git a/frontend/projects/upgrade/src/environments/environment.prod.ts b/frontend/projects/upgrade/src/environments/environment.prod.ts index d02432162a..4d70f6e83f 100755 --- a/frontend/projects/upgrade/src/environments/environment.prod.ts +++ b/frontend/projects/upgrade/src/environments/environment.prod.ts @@ -42,7 +42,6 @@ export const environment = { metrics: '/metric', metricsSave: '/metric/save', queryResult: '/query/analyse', - archiveResult: '/query/archive', getVersion: '/version', contextMetaData: '/experiments/contextMetaData', segments: '/segments', diff --git a/frontend/projects/upgrade/src/environments/environment.staging.ts b/frontend/projects/upgrade/src/environments/environment.staging.ts index 9e58bf0203..cffbfce277 100644 --- a/frontend/projects/upgrade/src/environments/environment.staging.ts +++ b/frontend/projects/upgrade/src/environments/environment.staging.ts @@ -42,7 +42,6 @@ export const environment = { metrics: '/metric', metricsSave: '/metric/save', queryResult: '/query/analyse', - archiveResult: '/query/archive', getVersion: '/version', contextMetaData: '/experiments/contextMetaData', segments: '/segments', diff --git a/frontend/projects/upgrade/src/environments/environment.ts b/frontend/projects/upgrade/src/environments/environment.ts index c69ce6591b..3126c73d9c 100755 --- a/frontend/projects/upgrade/src/environments/environment.ts +++ b/frontend/projects/upgrade/src/environments/environment.ts @@ -46,7 +46,6 @@ export const environment = { metrics: '/metric', metricsSave: '/metric/save', queryResult: '/query/analyse', - archiveResult: '/query/archive', getVersion: '/version', contextMetaData: '/experiments/contextMetaData', segments: '/segments', From 06fcd6c090fb05f27457b0ccf0257c9fc6b71d2d Mon Sep 17 00:00:00 2001 From: RidhamShah Date: Mon, 11 Sep 2023 10:33:11 +0530 Subject: [PATCH 10/12] added remaining file --- frontend/projects/upgrade/src/environments/environment-types.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/frontend/projects/upgrade/src/environments/environment-types.ts b/frontend/projects/upgrade/src/environments/environment-types.ts index 6c28584080..5f194ff24b 100644 --- a/frontend/projects/upgrade/src/environments/environment-types.ts +++ b/frontend/projects/upgrade/src/environments/environment-types.ts @@ -33,7 +33,6 @@ export interface APIEndpoints { metrics: string; metricsSave: string; queryResult: string; - archiveResult: string; getVersion: string; contextMetaData: string; segments: string; From 8bce72960c15211d1ce9ee3f3c59128a78482a91 Mon Sep 17 00:00:00 2001 From: pratik Date: Tue, 12 Sep 2023 13:01:40 +0530 Subject: [PATCH 11/12] fix peer review comments for archive state --- .../components/experiment-list/experiment-list.component.ts | 4 ++-- frontend/projects/upgrade/src/assets/i18n/en.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/projects/upgrade/src/app/features/dashboard/home/components/experiment-list/experiment-list.component.ts b/frontend/projects/upgrade/src/app/features/dashboard/home/components/experiment-list/experiment-list.component.ts index 952e27abf9..3abe657590 100644 --- a/frontend/projects/upgrade/src/app/features/dashboard/home/components/experiment-list/experiment-list.component.ts +++ b/frontend/projects/upgrade/src/app/features/dashboard/home/components/experiment-list/experiment-list.component.ts @@ -56,7 +56,7 @@ export class ExperimentListComponent implements OnInit, OnDestroy, AfterViewInit searchControl = new FormControl(); get filteredStatusOptions(): string[] { - if (this.searchValue !== undefined) { + if (typeof this.searchValue === 'string') { const filterValue = this.searchValue.toLowerCase(); return this.statusFilterOptions.filter((option) => option.toLowerCase().includes(filterValue)); } else { @@ -144,7 +144,7 @@ export class ExperimentListComponent implements OnInit, OnDestroy, AfterViewInit applyFilter(filterValue: string) { this.filterExperimentPredicate(this.selectedExperimentFilterOption); - if (filterValue !== undefined) { + if (typeof filterValue === 'string') { if (this.selectedExperimentFilterOption === EXPERIMENT_SEARCH_KEY.STATUS) { this.allExperiments.filter = filterValue.trim().toLowerCase(); } else { diff --git a/frontend/projects/upgrade/src/assets/i18n/en.json b/frontend/projects/upgrade/src/assets/i18n/en.json index afed452db2..d5eb8783c6 100644 --- a/frontend/projects/upgrade/src/assets/i18n/en.json +++ b/frontend/projects/upgrade/src/assets/i18n/en.json @@ -268,7 +268,7 @@ "home.change-experiment-status.enrolling-info.text": "*Once the experiment is started you won’t be allowed to update Experiment’s Condition and Sites", "home.change-experiment-status.enrolling-error.text": "*Experiment start date should not be greater than experiment end date {{ endDate }}", "home.change-experiment-status.condition-count-error.text": "*Please have at least 2 conditions to move forward", - "home.change-experiment-status.archiving-confirmation.text": "Please acknowledge that you agree to permanently transition this experiment to archive status", + "home.change-experiment-status.archiving-confirmation.text": "Please acknowledge that you agree to permanently transition this experiment to archive status.", "home.change-experiment-status.archiving-info.text": "*Archiving the experiment will cancel the post rule. The archived experiments are hidden from the experiment list and can be found by explicitly searching for 'Archived' experiments.", "home.change-post-experiment-rule.title.text": "Change Post Experiment Condition", "logs-global.log-zero-state.text": "No Logs", From d1a2d825a7220ee40bd2cc6d0e09ea6fede8e124 Mon Sep 17 00:00:00 2001 From: RidhamShah Date: Fri, 22 Sep 2023 12:23:35 +0530 Subject: [PATCH 12/12] Solve review comments --- backend/packages/Upgrade/src/api/services/QueryService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/packages/Upgrade/src/api/services/QueryService.ts b/backend/packages/Upgrade/src/api/services/QueryService.ts index 84d65982a1..e349d1eecb 100644 --- a/backend/packages/Upgrade/src/api/services/QueryService.ts +++ b/backend/packages/Upgrade/src/api/services/QueryService.ts @@ -69,7 +69,7 @@ export class QueryService { // checks for archieve state experiment if (promiseResult[0].experiment?.state === EXPERIMENT_STATE.ARCHIVED) { - return await this.getArchivedStats(queryIds, logger); + return this.getArchivedStats(queryIds, logger); } const analyzePromise = promiseResult.map((query) => {