mirror of
				https://github.com/Unleash/unleash.git
				synced 2025-10-27 11:02:16 +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.validateFeatureFlagNameAgainstPattern(value.name, projectId);
 | 
			
		||||
 | 
			
		||||
        const exists = await this.projectStore.hasProject(projectId);
 | 
			
		||||
        const projectExists = await this.projectStore.hasProject(projectId);
 | 
			
		||||
 | 
			
		||||
        if (await this.projectStore.isFeatureLimitReached(projectId)) {
 | 
			
		||||
            throw new InvalidOperationError(
 | 
			
		||||
@ -1266,7 +1266,7 @@ class FeatureToggleService {
 | 
			
		||||
 | 
			
		||||
        await this.validateFeatureFlagLimit();
 | 
			
		||||
 | 
			
		||||
        if (exists) {
 | 
			
		||||
        if (projectExists) {
 | 
			
		||||
            let featureData: FeatureToggleInsert;
 | 
			
		||||
            if (isValidated) {
 | 
			
		||||
                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(
 | 
			
		||||
                new FeatureCreatedEvent({
 | 
			
		||||
                    featureName,
 | 
			
		||||
 | 
			
		||||
@ -8,7 +8,10 @@ test('createFeatureSchema', () => {
 | 
			
		||||
        description:
 | 
			
		||||
            'Controls disabling of the comments section in case of an incident',
 | 
			
		||||
        impressionData: false,
 | 
			
		||||
        tags: ['simple:test', 'simple:test2'],
 | 
			
		||||
        tags: [
 | 
			
		||||
            { type: 'simple', value: 'tag' },
 | 
			
		||||
            { type: 'simple', value: 'mytag' },
 | 
			
		||||
        ],
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    expect(
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,5 @@
 | 
			
		||||
import type { FromSchema } from 'json-schema-to-ts';
 | 
			
		||||
import { tagSchema } from './tag-schema';
 | 
			
		||||
 | 
			
		||||
export const createFeatureSchema = {
 | 
			
		||||
    $id: '#/components/schemas/createFeatureSchema',
 | 
			
		||||
@ -32,14 +33,17 @@ export const createFeatureSchema = {
 | 
			
		||||
        },
 | 
			
		||||
        tags: {
 | 
			
		||||
            type: 'array',
 | 
			
		||||
            description: 'Tags to add to the feature.',
 | 
			
		||||
            items: {
 | 
			
		||||
                type: 'string',
 | 
			
		||||
                example: 'simple:test',
 | 
			
		||||
                $ref: '#/components/schemas/tagSchema',
 | 
			
		||||
            },
 | 
			
		||||
            description: 'List of tags associated with the feature',
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
    components: {},
 | 
			
		||||
    components: {
 | 
			
		||||
        schemas: {
 | 
			
		||||
            tagSchema,
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
} as const;
 | 
			
		||||
 | 
			
		||||
export type CreateFeatureSchema = FromSchema<typeof createFeatureSchema>;
 | 
			
		||||
 | 
			
		||||
@ -14,6 +14,7 @@ import { tagTypeSchema } from './tag-type-schema';
 | 
			
		||||
import { strategyVariantSchema } from './strategy-variant-schema';
 | 
			
		||||
import { featureDependenciesSchema } from './feature-dependencies-schema';
 | 
			
		||||
import { dependentFeatureSchema } from './dependent-feature-schema';
 | 
			
		||||
import { tagSchema } from './tag-schema';
 | 
			
		||||
 | 
			
		||||
export const exportResultSchema = {
 | 
			
		||||
    $id: '#/components/schemas/exportResultSchema',
 | 
			
		||||
@ -194,6 +195,7 @@ export const exportResultSchema = {
 | 
			
		||||
            tagTypeSchema,
 | 
			
		||||
            featureDependenciesSchema,
 | 
			
		||||
            dependentFeatureSchema,
 | 
			
		||||
            tagSchema,
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
} as const;
 | 
			
		||||
 | 
			
		||||
@ -8,6 +8,7 @@ import { featureStrategySchema } from './feature-strategy-schema';
 | 
			
		||||
import { environmentSchema } from './environment-schema';
 | 
			
		||||
import { featureEnvironmentSchema } from './feature-environment-schema';
 | 
			
		||||
import { strategyVariantSchema } from './strategy-variant-schema';
 | 
			
		||||
import { tagSchema } from './tag-schema';
 | 
			
		||||
 | 
			
		||||
export const featuresSchema = {
 | 
			
		||||
    $id: '#/components/schemas/featuresSchema',
 | 
			
		||||
@ -40,6 +41,7 @@ export const featuresSchema = {
 | 
			
		||||
            strategyVariantSchema,
 | 
			
		||||
            parametersSchema,
 | 
			
		||||
            variantSchema,
 | 
			
		||||
            tagSchema,
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
} as const;
 | 
			
		||||
 | 
			
		||||
@ -104,6 +104,15 @@ export const featureMetadataSchema = joi
 | 
			
		||||
            .unique((a, b) => a.name === b.name)
 | 
			
		||||
            .optional()
 | 
			
		||||
            .items(variantsSchema),
 | 
			
		||||
        tags: joi
 | 
			
		||||
            .array()
 | 
			
		||||
            .optional()
 | 
			
		||||
            .items(
 | 
			
		||||
                joi.object().keys({
 | 
			
		||||
                    type: joi.string().required(),
 | 
			
		||||
                    value: joi.string().required(),
 | 
			
		||||
                }),
 | 
			
		||||
            ),
 | 
			
		||||
        createdByUserId: joi.number(),
 | 
			
		||||
    })
 | 
			
		||||
    .options({ allowUnknown: false, stripUnknown: true, abortEarly: false });
 | 
			
		||||
 | 
			
		||||
@ -63,6 +63,7 @@ export interface FeatureToggleDTO {
 | 
			
		||||
    createdAt?: Date;
 | 
			
		||||
    impressionData?: boolean;
 | 
			
		||||
    variants?: IVariant[];
 | 
			
		||||
    tags?: ITag[];
 | 
			
		||||
    createdByUserId?: number;
 | 
			
		||||
    createdBy?: {
 | 
			
		||||
        id: number;
 | 
			
		||||
 | 
			
		||||
@ -358,3 +358,25 @@ test('returns a feature flags impression data for a different project', async ()
 | 
			
		||||
            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