mirror of
https://github.com/Unleash/unleash.git
synced 2025-03-18 00:19:49 +01:00
feat: tag feature on creation (#7664)
Now it is possible to tag feature on creation.
This commit is contained in:
parent
369518cd7d
commit
1e3c690185
@ -1256,7 +1256,7 @@ class FeatureToggleService {
|
|||||||
await this.validateName(value.name);
|
await this.validateName(value.name);
|
||||||
await this.validateFeatureFlagNameAgainstPattern(value.name, projectId);
|
await this.validateFeatureFlagNameAgainstPattern(value.name, projectId);
|
||||||
|
|
||||||
const exists = await this.projectStore.hasProject(projectId);
|
const projectExists = await this.projectStore.hasProject(projectId);
|
||||||
|
|
||||||
if (await this.projectStore.isFeatureLimitReached(projectId)) {
|
if (await this.projectStore.isFeatureLimitReached(projectId)) {
|
||||||
throw new InvalidOperationError(
|
throw new InvalidOperationError(
|
||||||
@ -1266,7 +1266,7 @@ class FeatureToggleService {
|
|||||||
|
|
||||||
await this.validateFeatureFlagLimit();
|
await this.validateFeatureFlagLimit();
|
||||||
|
|
||||||
if (exists) {
|
if (projectExists) {
|
||||||
let featureData: FeatureToggleInsert;
|
let featureData: FeatureToggleInsert;
|
||||||
if (isValidated) {
|
if (isValidated) {
|
||||||
featureData = { createdByUserId: auditUser.id, ...value };
|
featureData = { createdByUserId: auditUser.id, ...value };
|
||||||
@ -1301,6 +1301,16 @@ class FeatureToggleService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (value.tags && value.tags.length > 0) {
|
||||||
|
const mapTagsToFeatureTagInserts = value.tags.map((tag) => ({
|
||||||
|
tagValue: tag.value,
|
||||||
|
tagType: tag.type,
|
||||||
|
createdByUserId: auditUser.id,
|
||||||
|
featureName: featureName,
|
||||||
|
}));
|
||||||
|
await this.tagStore.tagFeatures(mapTagsToFeatureTagInserts);
|
||||||
|
}
|
||||||
|
|
||||||
await this.eventService.storeEvent(
|
await this.eventService.storeEvent(
|
||||||
new FeatureCreatedEvent({
|
new FeatureCreatedEvent({
|
||||||
featureName,
|
featureName,
|
||||||
|
@ -8,7 +8,10 @@ test('createFeatureSchema', () => {
|
|||||||
description:
|
description:
|
||||||
'Controls disabling of the comments section in case of an incident',
|
'Controls disabling of the comments section in case of an incident',
|
||||||
impressionData: false,
|
impressionData: false,
|
||||||
tags: ['simple:test', 'simple:test2'],
|
tags: [
|
||||||
|
{ type: 'simple', value: 'tag' },
|
||||||
|
{ type: 'simple', value: 'mytag' },
|
||||||
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import type { FromSchema } from 'json-schema-to-ts';
|
import type { FromSchema } from 'json-schema-to-ts';
|
||||||
|
import { tagSchema } from './tag-schema';
|
||||||
|
|
||||||
export const createFeatureSchema = {
|
export const createFeatureSchema = {
|
||||||
$id: '#/components/schemas/createFeatureSchema',
|
$id: '#/components/schemas/createFeatureSchema',
|
||||||
@ -32,14 +33,17 @@ export const createFeatureSchema = {
|
|||||||
},
|
},
|
||||||
tags: {
|
tags: {
|
||||||
type: 'array',
|
type: 'array',
|
||||||
|
description: 'Tags to add to the feature.',
|
||||||
items: {
|
items: {
|
||||||
type: 'string',
|
$ref: '#/components/schemas/tagSchema',
|
||||||
example: 'simple:test',
|
|
||||||
},
|
},
|
||||||
description: 'List of tags associated with the feature',
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
components: {},
|
components: {
|
||||||
|
schemas: {
|
||||||
|
tagSchema,
|
||||||
|
},
|
||||||
|
},
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export type CreateFeatureSchema = FromSchema<typeof createFeatureSchema>;
|
export type CreateFeatureSchema = FromSchema<typeof createFeatureSchema>;
|
||||||
|
@ -14,6 +14,7 @@ import { tagTypeSchema } from './tag-type-schema';
|
|||||||
import { strategyVariantSchema } from './strategy-variant-schema';
|
import { strategyVariantSchema } from './strategy-variant-schema';
|
||||||
import { featureDependenciesSchema } from './feature-dependencies-schema';
|
import { featureDependenciesSchema } from './feature-dependencies-schema';
|
||||||
import { dependentFeatureSchema } from './dependent-feature-schema';
|
import { dependentFeatureSchema } from './dependent-feature-schema';
|
||||||
|
import { tagSchema } from './tag-schema';
|
||||||
|
|
||||||
export const exportResultSchema = {
|
export const exportResultSchema = {
|
||||||
$id: '#/components/schemas/exportResultSchema',
|
$id: '#/components/schemas/exportResultSchema',
|
||||||
@ -194,6 +195,7 @@ export const exportResultSchema = {
|
|||||||
tagTypeSchema,
|
tagTypeSchema,
|
||||||
featureDependenciesSchema,
|
featureDependenciesSchema,
|
||||||
dependentFeatureSchema,
|
dependentFeatureSchema,
|
||||||
|
tagSchema,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
} as const;
|
} as const;
|
||||||
|
@ -8,6 +8,7 @@ import { featureStrategySchema } from './feature-strategy-schema';
|
|||||||
import { environmentSchema } from './environment-schema';
|
import { environmentSchema } from './environment-schema';
|
||||||
import { featureEnvironmentSchema } from './feature-environment-schema';
|
import { featureEnvironmentSchema } from './feature-environment-schema';
|
||||||
import { strategyVariantSchema } from './strategy-variant-schema';
|
import { strategyVariantSchema } from './strategy-variant-schema';
|
||||||
|
import { tagSchema } from './tag-schema';
|
||||||
|
|
||||||
export const featuresSchema = {
|
export const featuresSchema = {
|
||||||
$id: '#/components/schemas/featuresSchema',
|
$id: '#/components/schemas/featuresSchema',
|
||||||
@ -40,6 +41,7 @@ export const featuresSchema = {
|
|||||||
strategyVariantSchema,
|
strategyVariantSchema,
|
||||||
parametersSchema,
|
parametersSchema,
|
||||||
variantSchema,
|
variantSchema,
|
||||||
|
tagSchema,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
} as const;
|
} as const;
|
||||||
|
@ -104,6 +104,15 @@ export const featureMetadataSchema = joi
|
|||||||
.unique((a, b) => a.name === b.name)
|
.unique((a, b) => a.name === b.name)
|
||||||
.optional()
|
.optional()
|
||||||
.items(variantsSchema),
|
.items(variantsSchema),
|
||||||
|
tags: joi
|
||||||
|
.array()
|
||||||
|
.optional()
|
||||||
|
.items(
|
||||||
|
joi.object().keys({
|
||||||
|
type: joi.string().required(),
|
||||||
|
value: joi.string().required(),
|
||||||
|
}),
|
||||||
|
),
|
||||||
createdByUserId: joi.number(),
|
createdByUserId: joi.number(),
|
||||||
})
|
})
|
||||||
.options({ allowUnknown: false, stripUnknown: true, abortEarly: false });
|
.options({ allowUnknown: false, stripUnknown: true, abortEarly: false });
|
||||||
|
@ -63,6 +63,7 @@ export interface FeatureToggleDTO {
|
|||||||
createdAt?: Date;
|
createdAt?: Date;
|
||||||
impressionData?: boolean;
|
impressionData?: boolean;
|
||||||
variants?: IVariant[];
|
variants?: IVariant[];
|
||||||
|
tags?: ITag[];
|
||||||
createdByUserId?: number;
|
createdByUserId?: number;
|
||||||
createdBy?: {
|
createdBy?: {
|
||||||
id: number;
|
id: number;
|
||||||
|
@ -358,3 +358,25 @@ test('returns a feature flags impression data for a different project', async ()
|
|||||||
expect(projectFlag.impressionData).toBe(true);
|
expect(projectFlag.impressionData).toBe(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('Can add tags while creating feature flag', async () => {
|
||||||
|
const featureName = 'test.feature.with.tagss';
|
||||||
|
const tags = [{ value: 'tag1', type: 'simple' }];
|
||||||
|
|
||||||
|
await app.request.post('/api/admin/tags').send(tags[0]);
|
||||||
|
|
||||||
|
await app.request.post('/api/admin/projects/default/features').send({
|
||||||
|
name: featureName,
|
||||||
|
type: 'killswitch',
|
||||||
|
tags,
|
||||||
|
});
|
||||||
|
|
||||||
|
const { body } = await app.request
|
||||||
|
.get(`/api/admin/features/${featureName}/tags`)
|
||||||
|
.expect('Content-Type', /json/)
|
||||||
|
.expect(200);
|
||||||
|
|
||||||
|
expect(body).toMatchObject({
|
||||||
|
tags,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user