diff --git a/src/lib/features/feature-lifecycle/createFeatureLifecycle.ts b/src/lib/features/feature-lifecycle/createFeatureLifecycle.ts index a97e8d37d4..2114215b06 100644 --- a/src/lib/features/feature-lifecycle/createFeatureLifecycle.ts +++ b/src/lib/features/feature-lifecycle/createFeatureLifecycle.ts @@ -7,6 +7,10 @@ import EventStore from '../../db/event-store'; import type { Db } from '../../db/db'; import { FeatureLifecycleStore } from './feature-lifecycle-store'; import EnvironmentStore from '../project-environments/environment-store'; +import EventService from '../events/event-service'; +import FakeFeatureTagStore from '../../../test/fixtures/fake-feature-tag-store'; +import { EventEmitter } from 'stream'; +import FeatureTagStore from '../../db/feature-tag-store'; export const createFeatureLifecycleService = ( db: Db, @@ -16,12 +20,24 @@ export const createFeatureLifecycleService = ( const eventStore = new EventStore(db, getLogger); const featureLifecycleStore = new FeatureLifecycleStore(db); const environmentStore = new EnvironmentStore(db, eventBus, getLogger); + const featureTagStore = new FeatureTagStore( + db, + config.eventBus, + config.getLogger, + ); + const eventService = new EventService( + { eventStore, featureTagStore }, + { getLogger, eventBus: new EventEmitter() }, + ); const featureLifecycleService = new FeatureLifecycleService( { eventStore, featureLifecycleStore, environmentStore, }, + { + eventService, + }, config, ); @@ -37,12 +53,19 @@ export const createFakeFeatureLifecycleService = (config: IUnleashConfig) => { const eventStore = new FakeEventStore(); const featureLifecycleStore = new FakeFeatureLifecycleStore(); const environmentStore = new FakeEnvironmentStore(); + const eventService = new EventService( + { eventStore, featureTagStore: new FakeFeatureTagStore() }, + config, + ); const featureLifecycleService = new FeatureLifecycleService( { eventStore, featureLifecycleStore, environmentStore, }, + { + eventService, + }, config, ); diff --git a/src/lib/features/feature-lifecycle/fake-feature-lifecycle-store.ts b/src/lib/features/feature-lifecycle/fake-feature-lifecycle-store.ts index 3c821285b0..ff686bffe2 100644 --- a/src/lib/features/feature-lifecycle/fake-feature-lifecycle-store.ts +++ b/src/lib/features/feature-lifecycle/fake-feature-lifecycle-store.ts @@ -43,4 +43,14 @@ export class FakeFeatureLifecycleStore implements IFeatureLifecycleStore { const lifecycle = await this.get(stage.feature); return Boolean(lifecycle.find((s) => s.stage === stage.stage)); } + + async deleteStage(stage: FeatureLifecycleStage): Promise { + if (!this.lifecycles[stage.feature]) { + return; + } + const updatedStages = this.lifecycles[stage.feature].filter( + (s) => s.stage !== stage.stage, + ); + this.lifecycles[stage.feature] = updatedStages; + } } diff --git a/src/lib/features/feature-lifecycle/feature-lifecycle-controller.ts b/src/lib/features/feature-lifecycle/feature-lifecycle-controller.ts index c90e932daa..d91b8b74cf 100644 --- a/src/lib/features/feature-lifecycle/feature-lifecycle-controller.ts +++ b/src/lib/features/feature-lifecycle/feature-lifecycle-controller.ts @@ -5,10 +5,12 @@ import { type IUnleashServices, NONE, serializeDates, + UPDATE_FEATURE, } from '../../types'; import type { OpenApiService } from '../../services'; import { createResponseSchema, + emptyResponse, featureLifecycleSchema, type FeatureLifecycleSchema, getStandardResponses, @@ -16,6 +18,7 @@ import { import Controller from '../../routes/controller'; import type { Request, Response } from 'express'; import { NotFoundError } from '../../error'; +import type { IAuthRequest } from '../../routes/unleash-types'; interface FeatureLifecycleParams { projectId: string; @@ -62,6 +65,46 @@ export default class FeatureLifecycleController extends Controller { }), ], }); + + this.route({ + method: 'post', + path: `${PATH}/complete`, + handler: this.complete, + permission: UPDATE_FEATURE, + acceptAnyContentType: true, + middleware: [ + openApiService.validPath({ + tags: ['Unstable'], + summary: 'Set feature completed', + description: 'This will set the feature as completed.', + operationId: 'complete', + responses: { + 200: emptyResponse, + ...getStandardResponses(401, 403, 404), + }, + }), + ], + }); + + this.route({ + method: 'post', + path: `${PATH}/uncomplete`, + handler: this.uncomplete, + permission: UPDATE_FEATURE, + acceptAnyContentType: true, + middleware: [ + openApiService.validPath({ + tags: ['Unstable'], + summary: 'Set feature uncompleted', + description: 'This will set the feature as uncompleted.', + operationId: 'uncomplete', + responses: { + 200: emptyResponse, + ...getStandardResponses(401, 403, 404), + }, + }), + ], + }); } async getFeatureLifecycle( @@ -83,4 +126,38 @@ export default class FeatureLifecycleController extends Controller { serializeDates(result), ); } + + async complete( + req: IAuthRequest, + res: Response, + ): Promise { + if (!this.flagResolver.isEnabled('featureLifecycle')) { + throw new NotFoundError('Feature lifecycle is disabled.'); + } + const { featureName } = req.params; + + await this.featureLifecycleService.featureCompleted( + featureName, + req.audit, + ); + + res.status(200).end(); + } + + async uncomplete( + req: IAuthRequest, + res: Response, + ): Promise { + if (!this.flagResolver.isEnabled('featureLifecycle')) { + throw new NotFoundError('Feature lifecycle is disabled.'); + } + const { featureName } = req.params; + + await this.featureLifecycleService.featureUnCompleted( + featureName, + req.audit, + ); + + res.status(200).end(); + } } diff --git a/src/lib/features/feature-lifecycle/feature-lifecycle-service.test.ts b/src/lib/features/feature-lifecycle/feature-lifecycle-service.test.ts index 6f0adf6d35..3f2fbb2e5c 100644 --- a/src/lib/features/feature-lifecycle/feature-lifecycle-service.test.ts +++ b/src/lib/features/feature-lifecycle/feature-lifecycle-service.test.ts @@ -68,8 +68,6 @@ test('can insert and read lifecycle stages', async () => { emitMetricsEvent('my-prod-environment'); emitMetricsEvent('my-another-prod-environment'); - eventStore.emit(FEATURE_COMPLETED, { featureName }); - await reachedStage('completed'); eventStore.emit(FEATURE_ARCHIVED, { featureName }); await reachedStage('archived'); @@ -80,7 +78,6 @@ test('can insert and read lifecycle stages', async () => { { stage: 'initial', enteredStageAt: expect.any(Date) }, { stage: 'pre-live', enteredStageAt: expect.any(Date) }, { stage: 'live', enteredStageAt: expect.any(Date) }, - { stage: 'completed', enteredStageAt: expect.any(Date) }, { stage: 'archived', enteredStageAt: expect.any(Date) }, ]); diff --git a/src/lib/features/feature-lifecycle/feature-lifecycle-service.ts b/src/lib/features/feature-lifecycle/feature-lifecycle-service.ts index 9dc79825bd..a4d6d8b056 100644 --- a/src/lib/features/feature-lifecycle/feature-lifecycle-service.ts +++ b/src/lib/features/feature-lifecycle/feature-lifecycle-service.ts @@ -1,9 +1,11 @@ import { CLIENT_METRICS, FEATURE_ARCHIVED, - FEATURE_COMPLETED, FEATURE_CREATED, FEATURE_REVIVED, + FeatureCompletedEvent, + FeatureUncompletedEvent, + type IAuditUser, type IEnvironmentStore, type IEventStore, type IFlagResolver, @@ -15,6 +17,7 @@ import type { } from './feature-lifecycle-store-type'; import EventEmitter from 'events'; import type { Logger } from '../../logger'; +import type EventService from '../events/event-service'; import type { ValidatedClientMetrics } from '../metrics/shared/schema'; export const STAGE_ENTERED = 'STAGE_ENTERED'; @@ -30,6 +33,8 @@ export class FeatureLifecycleService extends EventEmitter { private eventBus: EventEmitter; + private eventService: EventService; + private logger: Logger; constructor( @@ -42,6 +47,11 @@ export class FeatureLifecycleService extends EventEmitter { environmentStore: IEnvironmentStore; featureLifecycleStore: IFeatureLifecycleStore; }, + { + eventService, + }: { + eventService: EventService; + }, { flagResolver, eventBus, @@ -54,6 +64,7 @@ export class FeatureLifecycleService extends EventEmitter { this.environmentStore = environmentStore; this.flagResolver = flagResolver; this.eventBus = eventBus; + this.eventService = eventService; this.logger = getLogger( 'feature-lifecycle/feature-lifecycle-service.ts', ); @@ -84,11 +95,6 @@ export class FeatureLifecycleService extends EventEmitter { } }, ); - this.eventStore.on(FEATURE_COMPLETED, async (event) => { - await this.checkEnabled(() => - this.featureCompleted(event.featureName), - ); - }); this.eventStore.on(FEATURE_ARCHIVED, async (event) => { await this.checkEnabled(() => this.featureArchived(event.featureName), @@ -145,14 +151,32 @@ export class FeatureLifecycleService extends EventEmitter { } } - private async featureCompleted(feature: string) { + public async featureCompleted(feature: string, auditUser: IAuditUser) { await this.featureLifecycleStore.insert([ { feature, stage: 'completed', }, ]); - this.emit(STAGE_ENTERED, { stage: 'completed' }); + await this.eventService.storeEvent( + new FeatureCompletedEvent({ + featureName: feature, + auditUser, + }), + ); + } + + public async featureUnCompleted(feature: string, auditUser: IAuditUser) { + await this.featureLifecycleStore.deleteStage({ + feature, + stage: 'completed', + }); + await this.eventService.storeEvent( + new FeatureUncompletedEvent({ + featureName: feature, + auditUser, + }), + ); } private async featureArchived(feature: string) { diff --git a/src/lib/features/feature-lifecycle/feature-lifecycle-store-type.ts b/src/lib/features/feature-lifecycle/feature-lifecycle-store-type.ts index 48447ba4b3..52e44fc107 100644 --- a/src/lib/features/feature-lifecycle/feature-lifecycle-store-type.ts +++ b/src/lib/features/feature-lifecycle/feature-lifecycle-store-type.ts @@ -12,4 +12,5 @@ export interface IFeatureLifecycleStore { get(feature: string): Promise; stageExists(stage: FeatureLifecycleStage): Promise; delete(feature: string): Promise; + deleteStage(stage: FeatureLifecycleStage): Promise; } diff --git a/src/lib/features/feature-lifecycle/feature-lifecycle-store.ts b/src/lib/features/feature-lifecycle/feature-lifecycle-store.ts index 1a8cc13ca0..071dca5ddb 100644 --- a/src/lib/features/feature-lifecycle/feature-lifecycle-store.ts +++ b/src/lib/features/feature-lifecycle/feature-lifecycle-store.ts @@ -62,6 +62,15 @@ export class FeatureLifecycleStore implements IFeatureLifecycleStore { await this.db('feature_lifecycles').where({ feature }).del(); } + async deleteStage(stage: FeatureLifecycleStage): Promise { + await this.db('feature_lifecycles') + .where({ + stage: stage.stage, + feature: stage.feature, + }) + .del(); + } + async stageExists(stage: FeatureLifecycleStage): Promise { const result = await this.db.raw( `SELECT EXISTS(SELECT 1 FROM feature_lifecycles WHERE stage = ? and feature = ?) AS present`, diff --git a/src/lib/features/feature-lifecycle/feature-lifecycle.e2e.test.ts b/src/lib/features/feature-lifecycle/feature-lifecycle.e2e.test.ts index 5f2e25a52c..d4e12ce56b 100644 --- a/src/lib/features/feature-lifecycle/feature-lifecycle.e2e.test.ts +++ b/src/lib/features/feature-lifecycle/feature-lifecycle.e2e.test.ts @@ -61,6 +61,21 @@ const getFeatureLifecycle = async (featureName: string, expectedCode = 200) => { .get(`/api/admin/projects/default/features/${featureName}/lifecycle`) .expect(expectedCode); }; +const completeFeature = async (featureName: string, expectedCode = 200) => { + return app.request + .post( + `/api/admin/projects/default/features/${featureName}/lifecycle/complete`, + ) + .expect(expectedCode); +}; + +const uncompleteFeature = async (featureName: string, expectedCode = 200) => { + return app.request + .post( + `/api/admin/projects/default/features/${featureName}/lifecycle/uncomplete`, + ) + .expect(expectedCode); +}; function reachedStage(name: StageName) { return new Promise((resolve) => @@ -70,10 +85,10 @@ function reachedStage(name: StageName) { ); } -const expectFeatureStage = async (stage: StageName) => { +const expectFeatureStage = async (featureName: string, stage: StageName) => { const { body: feature } = await app.getProjectFeatures( 'default', - 'my_feature_a', + featureName, ); expect(feature.lifecycle).toMatchObject({ stage, @@ -85,7 +100,7 @@ test('should return lifecycle stages', async () => { await app.createFeature('my_feature_a'); eventStore.emit(FEATURE_CREATED, { featureName: 'my_feature_a' }); await reachedStage('initial'); - await expectFeatureStage('initial'); + await expectFeatureStage('my_feature_a', 'initial'); eventBus.emit(CLIENT_METRICS, { bucket: { toggles: { @@ -110,20 +125,42 @@ test('should return lifecycle stages', async () => { environment: 'non-existent', }); await reachedStage('live'); - await expectFeatureStage('live'); + await expectFeatureStage('my_feature_a', 'live'); eventStore.emit(FEATURE_ARCHIVED, { featureName: 'my_feature_a' }); await reachedStage('archived'); const { body } = await getFeatureLifecycle('my_feature_a'); expect(body).toEqual([ - { stage: 'initial', enteredStageAt: expect.any(String) }, - { stage: 'live', enteredStageAt: expect.any(String) }, - { stage: 'archived', enteredStageAt: expect.any(String) }, + { + stage: 'initial', + enteredStageAt: expect.any(String), + }, + { + stage: 'live', + enteredStageAt: expect.any(String), + }, + { + stage: 'archived', + enteredStageAt: expect.any(String), + }, ]); - - await expectFeatureStage('archived'); + await expectFeatureStage('my_feature_a', 'archived'); eventStore.emit(FEATURE_REVIVED, { featureName: 'my_feature_a' }); await reachedStage('initial'); }); + +test('should be able to toggle between completed/uncompleted', async () => { + await app.createFeature('my_feature_b'); + + await completeFeature('my_feature_b'); + + await expectFeatureStage('my_feature_b', 'completed'); + + await uncompleteFeature('my_feature_b'); + + const { body } = await getFeatureLifecycle('my_feature_b'); + + expect(body).toEqual([]); +}); diff --git a/src/lib/types/events.ts b/src/lib/types/events.ts index e5901d04b3..5bb12f6685 100644 --- a/src/lib/types/events.ts +++ b/src/lib/types/events.ts @@ -29,6 +29,7 @@ export const DROP_FEATURE_TAGS = 'drop-feature-tags' as const; export const FEATURE_UNTAGGED = 'feature-untagged' as const; export const FEATURE_STALE_ON = 'feature-stale-on' as const; export const FEATURE_COMPLETED = 'feature-completed' as const; +export const FEATURE_UNCOMPLETED = 'feature-uncompleted' as const; export const FEATURE_STALE_OFF = 'feature-stale-off' as const; export const DROP_FEATURES = 'drop-features' as const; export const FEATURE_ENVIRONMENT_ENABLED = @@ -208,6 +209,8 @@ export const IEventTypes = [ FEATURE_STRATEGY_ADD, FEATURE_STRATEGY_REMOVE, FEATURE_TYPE_UPDATED, + FEATURE_COMPLETED, + FEATURE_UNCOMPLETED, STRATEGY_ORDER_CHANGED, DROP_FEATURE_TAGS, FEATURE_UNTAGGED, @@ -370,6 +373,7 @@ class BaseEvent implements IBaseEvent { readonly createdByUserId: number; readonly ip: string; + /** * @param type the type of the event we're creating. * @param auditUser User info used to track which user performed the action. Includes username (email or username), userId and ip @@ -424,7 +428,11 @@ export class FeatureEnvironmentEvent extends BaseEvent { this.environment = p.environment; } } -export type StrategyIds = { strategyIds: string[] }; + +export type StrategyIds = { + strategyIds: string[]; +}; + export class StrategiesOrderChangedEvent extends BaseEvent { readonly project: string; @@ -459,9 +467,13 @@ export class FeatureVariantEvent extends BaseEvent { readonly featureName: string; - readonly data: { variants: IVariant[] }; + readonly data: { + variants: IVariant[]; + }; - readonly preData: { variants: IVariant[] }; + readonly preData: { + variants: IVariant[]; + }; constructor(p: { project: string; @@ -485,9 +497,13 @@ export class EnvironmentVariantEvent extends BaseEvent { readonly featureName: string; - readonly data: { variants: IVariant[] }; + readonly data: { + variants: IVariant[]; + }; - readonly preData: { variants: IVariant[] }; + readonly preData: { + variants: IVariant[]; + }; /** */ @@ -507,9 +523,11 @@ export class EnvironmentVariantEvent extends BaseEvent { this.preData = { variants: p.oldVariants }; } } + export class ProjectCreatedEvent extends BaseEvent { readonly project: string; readonly data: any; + constructor(eventData: { data: any; project: string; @@ -525,6 +543,7 @@ export class ProjectUpdatedEvent extends BaseEvent { readonly project: string; readonly data: any; readonly preData: any; + constructor(eventData: { data: any; preData: any; @@ -540,6 +559,7 @@ export class ProjectUpdatedEvent extends BaseEvent { export class ProjectDeletedEvent extends BaseEvent { readonly project: string; + constructor(eventData: { project: string; auditUser: IAuditUser; @@ -552,6 +572,7 @@ export class ProjectDeletedEvent extends BaseEvent { export class RoleUpdatedEvent extends BaseEvent { readonly data: any; readonly preData: any; + constructor(eventData: { auditUser: IAuditUser; data: any; @@ -562,6 +583,7 @@ export class RoleUpdatedEvent extends BaseEvent { this.preData = eventData.preData; } } + export class FeatureChangeProjectEvent extends BaseEvent { readonly project: string; @@ -582,7 +604,10 @@ export class FeatureChangeProjectEvent extends BaseEvent { const { newProject, oldProject, featureName } = p; this.project = newProject; this.featureName = featureName; - this.data = { newProject, oldProject }; + this.data = { + newProject, + oldProject, + }; } } @@ -607,10 +632,37 @@ export class FeatureCreatedEvent extends BaseEvent { } } +export class FeatureCompletedEvent extends BaseEvent { + readonly featureName: string; + + constructor(p: { + featureName: string; + auditUser: IAuditUser; + }) { + super(FEATURE_COMPLETED, p.auditUser); + const { featureName } = p; + this.featureName = featureName; + } +} + +export class FeatureUncompletedEvent extends BaseEvent { + readonly featureName: string; + + constructor(p: { + featureName: string; + auditUser: IAuditUser; + }) { + super(FEATURE_UNCOMPLETED, p.auditUser); + const { featureName } = p; + this.featureName = featureName; + } +} + export class FeatureUpdatedEvent extends BaseEvent { readonly data: any; readonly featureName: string; readonly project: string; + constructor(eventData: { project: string; featureName: string; @@ -628,6 +680,7 @@ export class FeatureTaggedEvent extends BaseEvent { readonly data: any; readonly featureName: string; readonly project: string; + constructor(eventData: { project: string; featureName: string; @@ -644,6 +697,7 @@ export class FeatureTaggedEvent extends BaseEvent { export class FeatureTypeUpdatedEvent extends BaseEvent { readonly data: any; readonly preData: any; + constructor(eventData: { data: any; preData: any; @@ -654,10 +708,12 @@ export class FeatureTypeUpdatedEvent extends BaseEvent { this.preData = eventData.preData; } } + export class FeatureDependencyAddedEvent extends BaseEvent { readonly project: string; readonly featureName: string; readonly data: any; + constructor(eventData: { project: string; featureName: string; @@ -675,6 +731,7 @@ export class FeatureDependencyRemovedEvent extends BaseEvent { readonly project: string; readonly featureName: string; readonly data: any; + constructor(eventData: { project: string; featureName: string; @@ -687,6 +744,7 @@ export class FeatureDependencyRemovedEvent extends BaseEvent { this.data = eventData.data; } } + export class FeatureDependenciesRemovedEvent extends BaseEvent { readonly project: string; readonly featureName: string; @@ -705,6 +763,7 @@ export class FeatureDependenciesRemovedEvent extends BaseEvent { export class FeaturesImportedEvent extends BaseEvent { readonly project: string; readonly environment: string; + constructor(eventData: { project: string; environment: string; @@ -892,6 +951,7 @@ export class FeatureStrategyRemoveEvent extends BaseEvent { export class FeatureFavoritedEvent extends BaseEvent { readonly featureName: string; readonly data: any; + constructor(eventData: { featureName: string; data: any; @@ -906,6 +966,7 @@ export class FeatureFavoritedEvent extends BaseEvent { export class ProjectFavoritedEvent extends BaseEvent { readonly project: string; readonly data: any; + constructor(eventData: { project: string; data: any; @@ -920,6 +981,7 @@ export class ProjectFavoritedEvent extends BaseEvent { export class FeatureUnfavoritedEvent extends BaseEvent { readonly featureName: string; readonly data: any; + constructor(eventData: { featureName: string; data: any; @@ -934,6 +996,7 @@ export class FeatureUnfavoritedEvent extends BaseEvent { export class ProjectUnfavoritedEvent extends BaseEvent { readonly project: string; readonly data: any; + constructor(eventData: { project: string; data: any; @@ -1367,6 +1430,7 @@ export class UserDeletedEvent extends BaseEvent { export class TagTypeCreatedEvent extends BaseEvent { readonly data: any; + constructor(eventData: { auditUser: IAuditUser; data: any; @@ -1378,6 +1442,7 @@ export class TagTypeCreatedEvent extends BaseEvent { export class TagTypeDeletedEvent extends BaseEvent { readonly preData: any; + constructor(eventData: { auditUser: IAuditUser; preData: any; @@ -1389,6 +1454,7 @@ export class TagTypeDeletedEvent extends BaseEvent { export class TagTypeUpdatedEvent extends BaseEvent { readonly data: any; + constructor(eventData: { auditUser: IAuditUser; data: any; @@ -1400,6 +1466,7 @@ export class TagTypeUpdatedEvent extends BaseEvent { export class TagCreatedEvent extends BaseEvent { readonly data: any; + constructor(eventData: { auditUser: IAuditUser; data: any; @@ -1411,6 +1478,7 @@ export class TagCreatedEvent extends BaseEvent { export class TagDeletedEvent extends BaseEvent { readonly data: any; + constructor(eventData: { auditUser: IAuditUser; data: any; @@ -1422,6 +1490,7 @@ export class TagDeletedEvent extends BaseEvent { export class PatCreatedEvent extends BaseEvent { readonly data: any; + constructor(eventData: { auditUser: IAuditUser; data: any; @@ -1430,8 +1499,10 @@ export class PatCreatedEvent extends BaseEvent { this.data = eventData.data; } } + export class PatDeletedEvent extends BaseEvent { readonly data: any; + constructor(eventData: { auditUser: IAuditUser; data: any; @@ -1444,6 +1515,7 @@ export class PatDeletedEvent extends BaseEvent { export class ProjectEnvironmentAdded extends BaseEvent { readonly project: string; readonly environment: string; + constructor(eventData: { project: string; environment: string; @@ -1458,6 +1530,7 @@ export class ProjectEnvironmentAdded extends BaseEvent { export class ProjectEnvironmentRemoved extends BaseEvent { readonly project: string; readonly environment: string; + constructor(eventData: { project: string; environment: string; @@ -1471,6 +1544,7 @@ export class ProjectEnvironmentRemoved extends BaseEvent { export class FeaturesExportedEvent extends BaseEvent { readonly data: any; + constructor(eventData: { auditUser: IAuditUser; data: any; @@ -1482,6 +1556,7 @@ export class FeaturesExportedEvent extends BaseEvent { export class RoleCreatedEvent extends BaseEvent { readonly data: any; + constructor(eventData: { data: any; auditUser: IAuditUser; @@ -1493,6 +1568,7 @@ export class RoleCreatedEvent extends BaseEvent { export class RoleDeletedEvent extends BaseEvent { readonly preData: any; + constructor(eventData: { preData: any; auditUser: IAuditUser; @@ -1501,8 +1577,10 @@ export class RoleDeletedEvent extends BaseEvent { this.preData = eventData.preData; } } + export class StrategyCreatedEvent extends BaseEvent { readonly data: any; + constructor(eventData: { data: any; auditUser: IAuditUser; @@ -1511,8 +1589,10 @@ export class StrategyCreatedEvent extends BaseEvent { this.data = eventData.data; } } + export class StrategyUpdatedEvent extends BaseEvent { readonly data: any; + constructor(eventData: { data: any; auditUser: IAuditUser; @@ -1521,8 +1601,10 @@ export class StrategyUpdatedEvent extends BaseEvent { this.data = eventData.data; } } + export class StrategyDeletedEvent extends BaseEvent { readonly data: any; + constructor(eventData: { data: any; auditUser: IAuditUser; @@ -1531,8 +1613,10 @@ export class StrategyDeletedEvent extends BaseEvent { this.data = eventData.data; } } + export class StrategyDeprecatedEvent extends BaseEvent { readonly data: any; + constructor(eventData: { data: any; auditUser: IAuditUser; @@ -1541,8 +1625,10 @@ export class StrategyDeprecatedEvent extends BaseEvent { this.data = eventData.data; } } + export class StrategyReactivatedEvent extends BaseEvent { readonly data: any; + constructor(eventData: { data: any; auditUser: IAuditUser; @@ -1557,6 +1643,7 @@ export class DefaultStrategyUpdatedEvent extends BaseEvent { readonly environment: string; readonly preData: any; readonly data: any; + constructor(eventData: { project: string; environment: string; @@ -1574,6 +1661,7 @@ export class DefaultStrategyUpdatedEvent extends BaseEvent { export class AddonConfigCreatedEvent extends BaseEvent { readonly data: any; + constructor(eventData: { auditUser: IAuditUser; data: any; @@ -1586,6 +1674,7 @@ export class AddonConfigCreatedEvent extends BaseEvent { export class AddonConfigUpdatedEvent extends BaseEvent { readonly data: any; readonly preData: any; + constructor(eventData: { auditUser: IAuditUser; data: any; @@ -1599,6 +1688,7 @@ export class AddonConfigUpdatedEvent extends BaseEvent { export class AddonConfigDeletedEvent extends BaseEvent { readonly preData: any; + constructor(eventData: { auditUser: IAuditUser; preData: any; @@ -1611,6 +1701,7 @@ export class AddonConfigDeletedEvent extends BaseEvent { export class SegmentCreatedEvent extends BaseEvent { readonly project: string; readonly data: any; + constructor(eventData: { auditUser: IAuditUser; project: string; @@ -1626,6 +1717,7 @@ export class SegmentUpdatedEvent extends BaseEvent { readonly data: any; readonly preData: any; readonly project: string; + constructor(eventData: { auditUser: IAuditUser; project: string; @@ -1638,9 +1730,11 @@ export class SegmentUpdatedEvent extends BaseEvent { this.preData = eventData.preData; } } + export class SegmentDeletedEvent extends BaseEvent { readonly preData: any; readonly project?: string; + constructor(eventData: { auditUser: IAuditUser; preData: any; @@ -1655,6 +1749,7 @@ export class SegmentDeletedEvent extends BaseEvent { export class GroupUpdatedEvent extends BaseEvent { readonly preData: any; readonly data: any; + constructor(eventData: { data: any; preData: any; @@ -1668,6 +1763,7 @@ export class GroupUpdatedEvent extends BaseEvent { export class GroupDeletedEvent extends BaseEvent { readonly preData: any; + constructor(eventData: { preData: any; auditUser: IAuditUser;