mirror of
https://github.com/Unleash/unleash.git
synced 2025-02-23 00:22:19 +01:00
fix: Adds feature-variant-updated event. (#1189)
This triggers when we update or overwrite variants, and will include the previous variants and the new variants. Co-authored-by: Ivar Østhus <ivarconr@gmail.com>
This commit is contained in:
parent
b05216bc76
commit
994db02f84
@ -259,12 +259,13 @@ export default class FeatureToggleStore implements IFeatureToggleStore {
|
||||
}
|
||||
|
||||
async saveVariants(
|
||||
project: string,
|
||||
featureName: string,
|
||||
newVariants: IVariant[],
|
||||
): Promise<FeatureToggle> {
|
||||
const row = await this.db(TABLE)
|
||||
.update({ variants: JSON.stringify(newVariants) })
|
||||
.where({ name: featureName })
|
||||
.where({ project: project, name: featureName })
|
||||
.returning(FEATURE_COLUMNS);
|
||||
return this.rowToFeature(row[0]);
|
||||
}
|
||||
|
@ -7,6 +7,8 @@ import { Request, Response } from 'express';
|
||||
import { Operation } from 'fast-json-patch';
|
||||
import { UPDATE_FEATURE } from '../../../types/permissions';
|
||||
import { IVariant } from '../../../types/model';
|
||||
import { extractUsername } from '../../../util/extract-user';
|
||||
import { IAuthRequest } from '../../unleash-types';
|
||||
|
||||
const PREFIX = '/:projectId/features/:featureName/variants';
|
||||
|
||||
@ -47,13 +49,17 @@ export default class VariantsController extends Controller {
|
||||
}
|
||||
|
||||
async patchVariants(
|
||||
req: Request<FeatureParams, any, Operation[], any>,
|
||||
req: IAuthRequest<FeatureParams, any, Operation[]>,
|
||||
res: Response,
|
||||
): Promise<void> {
|
||||
const { featureName } = req.params;
|
||||
const { projectId, featureName } = req.params;
|
||||
const userName = extractUsername(req);
|
||||
|
||||
const updatedFeature = await this.featureService.updateVariants(
|
||||
featureName,
|
||||
projectId,
|
||||
req.body,
|
||||
userName,
|
||||
);
|
||||
res.status(200).json({
|
||||
version: '1',
|
||||
@ -62,13 +68,16 @@ export default class VariantsController extends Controller {
|
||||
}
|
||||
|
||||
async overwriteVariants(
|
||||
req: Request<FeatureParams, any, IVariant[], any>,
|
||||
req: IAuthRequest<FeatureParams, any, IVariant[], any>,
|
||||
res: Response,
|
||||
): Promise<void> {
|
||||
const { featureName } = req.params;
|
||||
const { projectId, featureName } = req.params;
|
||||
const userName = extractUsername(req);
|
||||
const updatedFeature = await this.featureService.saveVariants(
|
||||
featureName,
|
||||
projectId,
|
||||
req.body,
|
||||
userName,
|
||||
);
|
||||
res.status(200).json({
|
||||
version: '1',
|
||||
|
@ -11,6 +11,7 @@ import {
|
||||
variantsArraySchema,
|
||||
} from '../schema/feature-schema';
|
||||
import {
|
||||
FEATURE_UPDATED,
|
||||
FeatureArchivedEvent,
|
||||
FeatureChangeProjectEvent,
|
||||
FeatureCreatedEvent,
|
||||
@ -22,7 +23,7 @@ import {
|
||||
FeatureStrategyAddEvent,
|
||||
FeatureStrategyRemoveEvent,
|
||||
FeatureStrategyUpdateEvent,
|
||||
FEATURE_UPDATED,
|
||||
FeatureVariantEvent,
|
||||
} from '../types/events';
|
||||
import NotFoundError from '../error/notfound-error';
|
||||
import {
|
||||
@ -36,8 +37,8 @@ import { IFeatureToggleStore } from '../types/stores/feature-toggle-store';
|
||||
import {
|
||||
FeatureToggle,
|
||||
FeatureToggleDTO,
|
||||
FeatureToggleWithEnvironment,
|
||||
FeatureToggleLegacy,
|
||||
FeatureToggleWithEnvironment,
|
||||
IEnvironmentDetail,
|
||||
IFeatureEnvironmentInfo,
|
||||
IFeatureOverview,
|
||||
@ -232,6 +233,7 @@ class FeatureToggleService {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* PUT /api/admin/projects/:projectId/features/:featureName/strategies/:strategyId ?
|
||||
* {
|
||||
@ -910,20 +912,43 @@ class FeatureToggleService {
|
||||
|
||||
async updateVariants(
|
||||
featureName: string,
|
||||
project: string,
|
||||
newVariants: Operation[],
|
||||
createdBy: string,
|
||||
): Promise<FeatureToggle> {
|
||||
const oldVariants = await this.getVariants(featureName);
|
||||
const { newDocument } = await applyPatch(oldVariants, newVariants);
|
||||
return this.saveVariants(featureName, newDocument);
|
||||
return this.saveVariants(featureName, project, newDocument, createdBy);
|
||||
}
|
||||
|
||||
async saveVariants(
|
||||
featureName: string,
|
||||
project: string,
|
||||
newVariants: IVariant[],
|
||||
createdBy: string,
|
||||
): Promise<FeatureToggle> {
|
||||
await variantsArraySchema.validateAsync(newVariants);
|
||||
const fixedVariants = this.fixVariantWeights(newVariants);
|
||||
return this.featureToggleStore.saveVariants(featureName, fixedVariants);
|
||||
const oldVariants = await this.featureToggleStore.getVariants(
|
||||
featureName,
|
||||
);
|
||||
const featureToggle = await this.featureToggleStore.saveVariants(
|
||||
project,
|
||||
featureName,
|
||||
fixedVariants,
|
||||
);
|
||||
const tags = await this.tagStore.getAllTagsForFeature(featureName);
|
||||
await this.eventStore.store(
|
||||
new FeatureVariantEvent({
|
||||
project,
|
||||
featureName,
|
||||
createdBy,
|
||||
tags,
|
||||
oldVariants,
|
||||
newVariants: featureToggle.variants,
|
||||
}),
|
||||
);
|
||||
return featureToggle;
|
||||
}
|
||||
|
||||
fixVariantWeights(variants: IVariant[]): IVariant[] {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { FeatureToggle, IStrategyConfig, ITag } from './model';
|
||||
import { FeatureToggle, IStrategyConfig, ITag, IVariant } from './model';
|
||||
|
||||
export const APPLICATION_CREATED = 'application-created';
|
||||
|
||||
@ -7,6 +7,7 @@ export const FEATURE_CREATED = 'feature-created';
|
||||
export const FEATURE_DELETED = 'feature-deleted';
|
||||
export const FEATURE_UPDATED = 'feature-updated';
|
||||
export const FEATURE_METADATA_UPDATED = 'feature-metadata-updated';
|
||||
export const FEATURE_VARIANTS_UPDATED = 'feature-variants-updated';
|
||||
export const FEATURE_PROJECT_CHANGE = 'feature-project-change';
|
||||
export const FEATURE_ARCHIVED = 'feature-archived';
|
||||
export const FEATURE_REVIVED = 'feature-revived';
|
||||
@ -140,6 +141,31 @@ export class FeatureEnvironmentEvent extends BaseEvent {
|
||||
}
|
||||
}
|
||||
|
||||
export class FeatureVariantEvent extends BaseEvent {
|
||||
readonly project: string;
|
||||
|
||||
readonly featureName: string;
|
||||
|
||||
readonly data: {
|
||||
oldVariants: IVariant[];
|
||||
newVariants: IVariant[];
|
||||
};
|
||||
|
||||
constructor(p: {
|
||||
project: string;
|
||||
featureName: string;
|
||||
createdBy: string;
|
||||
tags: ITag[];
|
||||
oldVariants: IVariant[];
|
||||
newVariants: IVariant[];
|
||||
}) {
|
||||
super(FEATURE_VARIANTS_UPDATED, p.createdBy, p.tags);
|
||||
this.project = p.project;
|
||||
this.featureName = p.featureName;
|
||||
this.data = { oldVariants: p.oldVariants, newVariants: p.newVariants };
|
||||
}
|
||||
}
|
||||
|
||||
export class FeatureChangeProjectEvent extends BaseEvent {
|
||||
readonly project: string;
|
||||
|
||||
|
@ -18,6 +18,7 @@ export interface IFeatureToggleStore extends Store<FeatureToggle, string> {
|
||||
getAll(query?: Partial<IFeatureToggleQuery>): Promise<FeatureToggle[]>;
|
||||
getVariants(featureName: string): Promise<IVariant[]>;
|
||||
saveVariants(
|
||||
project: string,
|
||||
featureName: string,
|
||||
newVariants: IVariant[],
|
||||
): Promise<FeatureToggle>;
|
||||
|
@ -38,10 +38,14 @@ beforeAll(async () => {
|
||||
const createVariants = async (
|
||||
featureName: string,
|
||||
variants: IVariant[],
|
||||
projectId: string = 'default',
|
||||
username: string = 'test',
|
||||
) => {
|
||||
await app.services.featureToggleServiceV2.saveVariants(
|
||||
featureName,
|
||||
projectId,
|
||||
variants,
|
||||
username,
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -134,6 +134,7 @@ export default class FakeFeatureToggleStore implements IFeatureToggleStore {
|
||||
}
|
||||
|
||||
async saveVariants(
|
||||
project: string,
|
||||
featureName: string,
|
||||
newVariants: IVariant[],
|
||||
): Promise<FeatureToggle> {
|
||||
|
Loading…
Reference in New Issue
Block a user