mirror of
				https://github.com/Unleash/unleash.git
				synced 2025-10-27 11:02:16 +01:00 
			
		
		
		
	feat: bulk stale features (#3311)
This commit is contained in:
		
							parent
							
								
									240bb7b027
								
							
						
					
					
						commit
						6c813ab066
					
				@ -283,6 +283,17 @@ export default class FeatureToggleStore implements IFeatureToggleStore {
 | 
				
			|||||||
        return rows.map((row) => this.rowToFeature(row));
 | 
					        return rows.map((row) => this.rowToFeature(row));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    async batchStale(
 | 
				
			||||||
 | 
					        names: string[],
 | 
				
			||||||
 | 
					        stale: boolean,
 | 
				
			||||||
 | 
					    ): Promise<FeatureToggle[]> {
 | 
				
			||||||
 | 
					        const rows = await this.db(TABLE)
 | 
				
			||||||
 | 
					            .whereIn('name', names)
 | 
				
			||||||
 | 
					            .update({ stale })
 | 
				
			||||||
 | 
					            .returning(FEATURE_COLUMNS);
 | 
				
			||||||
 | 
					        return rows.map((row) => this.rowToFeature(row));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async delete(name: string): Promise<void> {
 | 
					    async delete(name: string): Promise<void> {
 | 
				
			||||||
        await this.db(TABLE)
 | 
					        await this.db(TABLE)
 | 
				
			||||||
            .where({ name }) // Feature toggle must be archived to allow deletion
 | 
					            .where({ name }) // Feature toggle must be archived to allow deletion
 | 
				
			||||||
 | 
				
			|||||||
@ -9,7 +9,7 @@ import {
 | 
				
			|||||||
    apiTokensSchema,
 | 
					    apiTokensSchema,
 | 
				
			||||||
    applicationSchema,
 | 
					    applicationSchema,
 | 
				
			||||||
    applicationsSchema,
 | 
					    applicationsSchema,
 | 
				
			||||||
    archiveFeaturesSchema,
 | 
					    batchFeaturesSchema,
 | 
				
			||||||
    changePasswordSchema,
 | 
					    changePasswordSchema,
 | 
				
			||||||
    clientApplicationSchema,
 | 
					    clientApplicationSchema,
 | 
				
			||||||
    clientFeatureSchema,
 | 
					    clientFeatureSchema,
 | 
				
			||||||
@ -144,6 +144,7 @@ import { bulkRegistrationSchema } from './spec/bulk-registration-schema';
 | 
				
			|||||||
import { bulkMetricsSchema } from './spec/bulk-metrics-schema';
 | 
					import { bulkMetricsSchema } from './spec/bulk-metrics-schema';
 | 
				
			||||||
import { clientMetricsEnvSchema } from './spec/client-metrics-env-schema';
 | 
					import { clientMetricsEnvSchema } from './spec/client-metrics-env-schema';
 | 
				
			||||||
import { updateTagsSchema } from './spec/update-tags-schema';
 | 
					import { updateTagsSchema } from './spec/update-tags-schema';
 | 
				
			||||||
 | 
					import { batchStaleSchema } from './spec/batch-stale-schema';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// All schemas in `openapi/spec` should be listed here.
 | 
					// All schemas in `openapi/spec` should be listed here.
 | 
				
			||||||
export const schemas = {
 | 
					export const schemas = {
 | 
				
			||||||
@ -156,7 +157,8 @@ export const schemas = {
 | 
				
			|||||||
    apiTokensSchema,
 | 
					    apiTokensSchema,
 | 
				
			||||||
    applicationSchema,
 | 
					    applicationSchema,
 | 
				
			||||||
    applicationsSchema,
 | 
					    applicationsSchema,
 | 
				
			||||||
    archiveFeaturesSchema,
 | 
					    batchFeaturesSchema,
 | 
				
			||||||
 | 
					    batchStaleSchema,
 | 
				
			||||||
    bulkRegistrationSchema,
 | 
					    bulkRegistrationSchema,
 | 
				
			||||||
    bulkMetricsSchema,
 | 
					    bulkMetricsSchema,
 | 
				
			||||||
    changePasswordSchema,
 | 
					    changePasswordSchema,
 | 
				
			||||||
 | 
				
			|||||||
@ -1,7 +1,7 @@
 | 
				
			|||||||
import { FromSchema } from 'json-schema-to-ts';
 | 
					import { FromSchema } from 'json-schema-to-ts';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const archiveFeaturesSchema = {
 | 
					export const batchFeaturesSchema = {
 | 
				
			||||||
    $id: '#/components/schemas/archiveFeaturesSchema',
 | 
					    $id: '#/components/schemas/batchFeaturesSchema',
 | 
				
			||||||
    type: 'object',
 | 
					    type: 'object',
 | 
				
			||||||
    required: ['features'],
 | 
					    required: ['features'],
 | 
				
			||||||
    properties: {
 | 
					    properties: {
 | 
				
			||||||
@ -17,4 +17,4 @@ export const archiveFeaturesSchema = {
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
} as const;
 | 
					} as const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export type ArchiveFeaturesSchema = FromSchema<typeof archiveFeaturesSchema>;
 | 
					export type BatchFeaturesSchema = FromSchema<typeof batchFeaturesSchema>;
 | 
				
			||||||
							
								
								
									
										23
									
								
								src/lib/openapi/spec/batch-stale-schema.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								src/lib/openapi/spec/batch-stale-schema.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,23 @@
 | 
				
			|||||||
 | 
					import { FromSchema } from 'json-schema-to-ts';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const batchStaleSchema = {
 | 
				
			||||||
 | 
					    $id: '#/components/schemas/batchStaleSchema',
 | 
				
			||||||
 | 
					    type: 'object',
 | 
				
			||||||
 | 
					    required: ['features', 'stale'],
 | 
				
			||||||
 | 
					    properties: {
 | 
				
			||||||
 | 
					        features: {
 | 
				
			||||||
 | 
					            type: 'array',
 | 
				
			||||||
 | 
					            items: {
 | 
				
			||||||
 | 
					                type: 'string',
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        stale: {
 | 
				
			||||||
 | 
					            type: 'boolean',
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    components: {
 | 
				
			||||||
 | 
					        schemas: {},
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					} as const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type BatchStaleSchema = FromSchema<typeof batchStaleSchema>;
 | 
				
			||||||
@ -131,4 +131,4 @@ export * from './import-toggles-validate-schema';
 | 
				
			|||||||
export * from './import-toggles-schema';
 | 
					export * from './import-toggles-schema';
 | 
				
			||||||
export * from './stickiness-schema';
 | 
					export * from './stickiness-schema';
 | 
				
			||||||
export * from './tags-bulk-add-schema';
 | 
					export * from './tags-bulk-add-schema';
 | 
				
			||||||
export * from './archive-features-schema';
 | 
					export * from './batch-features-schema';
 | 
				
			||||||
 | 
				
			|||||||
@ -20,7 +20,7 @@ import { extractUsername } from '../../../util';
 | 
				
			|||||||
import { IAuthRequest } from '../../unleash-types';
 | 
					import { IAuthRequest } from '../../unleash-types';
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
    AdminFeaturesQuerySchema,
 | 
					    AdminFeaturesQuerySchema,
 | 
				
			||||||
    ArchiveFeaturesSchema,
 | 
					    BatchFeaturesSchema,
 | 
				
			||||||
    CreateFeatureSchema,
 | 
					    CreateFeatureSchema,
 | 
				
			||||||
    CreateFeatureStrategySchema,
 | 
					    CreateFeatureStrategySchema,
 | 
				
			||||||
    createRequestSchema,
 | 
					    createRequestSchema,
 | 
				
			||||||
@ -46,6 +46,7 @@ import {
 | 
				
			|||||||
} from '../../../services';
 | 
					} from '../../../services';
 | 
				
			||||||
import { querySchema } from '../../../schema/feature-schema';
 | 
					import { querySchema } from '../../../schema/feature-schema';
 | 
				
			||||||
import NotFoundError from '../../../error/notfound-error';
 | 
					import NotFoundError from '../../../error/notfound-error';
 | 
				
			||||||
 | 
					import { BatchStaleSchema } from '../../../openapi/spec/batch-stale-schema';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface FeatureStrategyParams {
 | 
					interface FeatureStrategyParams {
 | 
				
			||||||
    projectId: string;
 | 
					    projectId: string;
 | 
				
			||||||
@ -76,6 +77,7 @@ export interface IFeatureProjectUserParams extends ProjectParam {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const PATH = '/:projectId/features';
 | 
					const PATH = '/:projectId/features';
 | 
				
			||||||
const PATH_ARCHIVE = '/:projectId/archive';
 | 
					const PATH_ARCHIVE = '/:projectId/archive';
 | 
				
			||||||
 | 
					const PATH_STALE = '/:projectId/stale';
 | 
				
			||||||
const PATH_FEATURE = `${PATH}/:featureName`;
 | 
					const PATH_FEATURE = `${PATH}/:featureName`;
 | 
				
			||||||
const PATH_FEATURE_CLONE = `${PATH_FEATURE}/clone`;
 | 
					const PATH_FEATURE_CLONE = `${PATH_FEATURE}/clone`;
 | 
				
			||||||
const PATH_ENV = `${PATH_FEATURE}/environments/:environment`;
 | 
					const PATH_ENV = `${PATH_FEATURE}/environments/:environment`;
 | 
				
			||||||
@ -418,8 +420,24 @@ export default class ProjectFeaturesController extends Controller {
 | 
				
			|||||||
                    operationId: 'archiveFeatures',
 | 
					                    operationId: 'archiveFeatures',
 | 
				
			||||||
                    description:
 | 
					                    description:
 | 
				
			||||||
                        'This endpoint archives the specified features.',
 | 
					                        'This endpoint archives the specified features.',
 | 
				
			||||||
                    summary: 'Archive a list of features',
 | 
					                    summary: 'Archives a list of features',
 | 
				
			||||||
                    requestBody: createRequestSchema('archiveFeaturesSchema'),
 | 
					                    requestBody: createRequestSchema('batchFeaturesSchema'),
 | 
				
			||||||
 | 
					                    responses: { 202: emptyResponse },
 | 
				
			||||||
 | 
					                }),
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        this.route({
 | 
				
			||||||
 | 
					            method: 'post',
 | 
				
			||||||
 | 
					            path: PATH_STALE,
 | 
				
			||||||
 | 
					            handler: this.staleFeatures,
 | 
				
			||||||
 | 
					            permission: UPDATE_FEATURE,
 | 
				
			||||||
 | 
					            middleware: [
 | 
				
			||||||
 | 
					                openApiService.validPath({
 | 
				
			||||||
 | 
					                    tags: ['Features'],
 | 
				
			||||||
 | 
					                    operationId: 'staleFeatures',
 | 
				
			||||||
 | 
					                    description: 'This endpoint stales the specified features.',
 | 
				
			||||||
 | 
					                    summary: 'Stales a list of features',
 | 
				
			||||||
 | 
					                    requestBody: createRequestSchema('batchStaleSchema'),
 | 
				
			||||||
                    responses: { 202: emptyResponse },
 | 
					                    responses: { 202: emptyResponse },
 | 
				
			||||||
                }),
 | 
					                }),
 | 
				
			||||||
            ],
 | 
					            ],
 | 
				
			||||||
@ -603,7 +621,7 @@ export default class ProjectFeaturesController extends Controller {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async archiveFeatures(
 | 
					    async archiveFeatures(
 | 
				
			||||||
        req: IAuthRequest<{ projectId: string }, void, ArchiveFeaturesSchema>,
 | 
					        req: IAuthRequest<{ projectId: string }, void, BatchFeaturesSchema>,
 | 
				
			||||||
        res: Response,
 | 
					        res: Response,
 | 
				
			||||||
    ): Promise<void> {
 | 
					    ): Promise<void> {
 | 
				
			||||||
        if (!this.flagResolver.isEnabled('bulkOperations')) {
 | 
					        if (!this.flagResolver.isEnabled('bulkOperations')) {
 | 
				
			||||||
@ -618,6 +636,27 @@ export default class ProjectFeaturesController extends Controller {
 | 
				
			|||||||
        res.status(202).end();
 | 
					        res.status(202).end();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    async staleFeatures(
 | 
				
			||||||
 | 
					        req: IAuthRequest<{ projectId: string }, void, BatchStaleSchema>,
 | 
				
			||||||
 | 
					        res: Response,
 | 
				
			||||||
 | 
					    ): Promise<void> {
 | 
				
			||||||
 | 
					        if (!this.flagResolver.isEnabled('bulkOperations')) {
 | 
				
			||||||
 | 
					            throw new NotFoundError('Bulk operations are not enabled');
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const { features, stale } = req.body;
 | 
				
			||||||
 | 
					        const { projectId } = req.params;
 | 
				
			||||||
 | 
					        const userName = extractUsername(req);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        await this.featureService.setToggleStaleness(
 | 
				
			||||||
 | 
					            features,
 | 
				
			||||||
 | 
					            stale,
 | 
				
			||||||
 | 
					            userName,
 | 
				
			||||||
 | 
					            projectId,
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        res.status(202).end();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async getFeatureEnvironment(
 | 
					    async getFeatureEnvironment(
 | 
				
			||||||
        req: Request<FeatureStrategyParams, any, any, any>,
 | 
					        req: Request<FeatureStrategyParams, any, any, any>,
 | 
				
			||||||
        res: Response<FeatureEnvironmentSchema>,
 | 
					        res: Response<FeatureEnvironmentSchema>,
 | 
				
			||||||
 | 
				
			|||||||
@ -1101,6 +1101,37 @@ class FeatureToggleService {
 | 
				
			|||||||
        );
 | 
					        );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    async setToggleStaleness(
 | 
				
			||||||
 | 
					        featureNames: string[],
 | 
				
			||||||
 | 
					        stale: boolean,
 | 
				
			||||||
 | 
					        createdBy: string,
 | 
				
			||||||
 | 
					        projectId: string,
 | 
				
			||||||
 | 
					    ): Promise<void> {
 | 
				
			||||||
 | 
					        await this.validateFeaturesContext(featureNames, projectId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const features = await this.featureToggleStore.getAllByNames(
 | 
				
			||||||
 | 
					            featureNames,
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        const relevantFeatures = features.filter(
 | 
				
			||||||
 | 
					            (feature) => feature.stale !== stale,
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        await this.featureToggleStore.batchStale(
 | 
				
			||||||
 | 
					            relevantFeatures.map((feature) => feature.name),
 | 
				
			||||||
 | 
					            stale,
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        await this.eventStore.batchStore(
 | 
				
			||||||
 | 
					            relevantFeatures.map(
 | 
				
			||||||
 | 
					                (feature) =>
 | 
				
			||||||
 | 
					                    new FeatureStaleEvent({
 | 
				
			||||||
 | 
					                        stale: stale,
 | 
				
			||||||
 | 
					                        project: projectId,
 | 
				
			||||||
 | 
					                        featureName: feature.name,
 | 
				
			||||||
 | 
					                        createdBy,
 | 
				
			||||||
 | 
					                    }),
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async updateEnabled(
 | 
					    async updateEnabled(
 | 
				
			||||||
        project: string,
 | 
					        project: string,
 | 
				
			||||||
        featureName: string,
 | 
					        featureName: string,
 | 
				
			||||||
 | 
				
			|||||||
@ -163,7 +163,7 @@ export class FeatureStaleEvent extends BaseEvent {
 | 
				
			|||||||
        project: string;
 | 
					        project: string;
 | 
				
			||||||
        featureName: string;
 | 
					        featureName: string;
 | 
				
			||||||
        createdBy: string | IUser;
 | 
					        createdBy: string | IUser;
 | 
				
			||||||
        tags: ITag[];
 | 
					        tags?: ITag[];
 | 
				
			||||||
    }) {
 | 
					    }) {
 | 
				
			||||||
        super(
 | 
					        super(
 | 
				
			||||||
            p.stale ? FEATURE_STALE_ON : FEATURE_STALE_OFF,
 | 
					            p.stale ? FEATURE_STALE_ON : FEATURE_STALE_OFF,
 | 
				
			||||||
 | 
				
			|||||||
@ -16,6 +16,10 @@ export interface IFeatureToggleStore extends Store<FeatureToggle, string> {
 | 
				
			|||||||
    update(project: string, data: FeatureToggleDTO): Promise<FeatureToggle>;
 | 
					    update(project: string, data: FeatureToggleDTO): Promise<FeatureToggle>;
 | 
				
			||||||
    archive(featureName: string): Promise<FeatureToggle>;
 | 
					    archive(featureName: string): Promise<FeatureToggle>;
 | 
				
			||||||
    batchArchive(featureNames: string[]): Promise<FeatureToggle[]>;
 | 
					    batchArchive(featureNames: string[]): Promise<FeatureToggle[]>;
 | 
				
			||||||
 | 
					    batchStale(
 | 
				
			||||||
 | 
					        featureNames: string[],
 | 
				
			||||||
 | 
					        stale: boolean,
 | 
				
			||||||
 | 
					    ): Promise<FeatureToggle[]>;
 | 
				
			||||||
    revive(featureName: string): Promise<FeatureToggle>;
 | 
					    revive(featureName: string): Promise<FeatureToggle>;
 | 
				
			||||||
    getAll(query?: Partial<IFeatureToggleQuery>): Promise<FeatureToggle[]>;
 | 
					    getAll(query?: Partial<IFeatureToggleQuery>): Promise<FeatureToggle[]>;
 | 
				
			||||||
    getAllByNames(names: string[]): Promise<FeatureToggle[]>;
 | 
					    getAllByNames(names: string[]): Promise<FeatureToggle[]>;
 | 
				
			||||||
 | 
				
			|||||||
@ -2845,3 +2845,26 @@ test('Should be able to bulk archive features', async () => {
 | 
				
			|||||||
        features: [{}, { name: featureName1 }, { name: featureName2 }],
 | 
					        features: [{}, { name: featureName1 }, { name: featureName2 }],
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test('Should batch stale features', async () => {
 | 
				
			||||||
 | 
					    const staledFeatureName1 = 'staledFeature1';
 | 
				
			||||||
 | 
					    const staledFeatureName2 = 'staledFeature2';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    await createFeatureToggle(staledFeatureName1);
 | 
				
			||||||
 | 
					    await createFeatureToggle(staledFeatureName2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    await app.request
 | 
				
			||||||
 | 
					        .post(`/api/admin/projects/${DEFAULT_PROJECT}/stale`)
 | 
				
			||||||
 | 
					        .send({
 | 
				
			||||||
 | 
					            features: [staledFeatureName1, staledFeatureName2],
 | 
				
			||||||
 | 
					            stale: true,
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					        .expect(202);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const { body } = await app.request
 | 
				
			||||||
 | 
					        .get(
 | 
				
			||||||
 | 
					            `/api/admin/projects/${DEFAULT_PROJECT}/features/${staledFeatureName1}`,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        .expect(200);
 | 
				
			||||||
 | 
					    expect(body.stale).toBeTruthy();
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
				
			|||||||
@ -328,7 +328,7 @@ exports[`should serve the OpenAPI spec 1`] = `
 | 
				
			|||||||
        },
 | 
					        },
 | 
				
			||||||
        "type": "object",
 | 
					        "type": "object",
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      "archiveFeaturesSchema": {
 | 
					      "batchFeaturesSchema": {
 | 
				
			||||||
        "properties": {
 | 
					        "properties": {
 | 
				
			||||||
          "features": {
 | 
					          "features": {
 | 
				
			||||||
            "items": {
 | 
					            "items": {
 | 
				
			||||||
@ -342,6 +342,24 @@ exports[`should serve the OpenAPI spec 1`] = `
 | 
				
			|||||||
        ],
 | 
					        ],
 | 
				
			||||||
        "type": "object",
 | 
					        "type": "object",
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
 | 
					      "batchStaleSchema": {
 | 
				
			||||||
 | 
					        "properties": {
 | 
				
			||||||
 | 
					          "features": {
 | 
				
			||||||
 | 
					            "items": {
 | 
				
			||||||
 | 
					              "type": "string",
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            "type": "array",
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "stale": {
 | 
				
			||||||
 | 
					            "type": "boolean",
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "required": [
 | 
				
			||||||
 | 
					          "features",
 | 
				
			||||||
 | 
					          "stale",
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        "type": "object",
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
      "bulkMetricsSchema": {
 | 
					      "bulkMetricsSchema": {
 | 
				
			||||||
        "properties": {
 | 
					        "properties": {
 | 
				
			||||||
          "applications": {
 | 
					          "applications": {
 | 
				
			||||||
@ -5998,11 +6016,11 @@ If the provided project does not exist, the list of events will be empty.",
 | 
				
			|||||||
          "content": {
 | 
					          "content": {
 | 
				
			||||||
            "application/json": {
 | 
					            "application/json": {
 | 
				
			||||||
              "schema": {
 | 
					              "schema": {
 | 
				
			||||||
                "$ref": "#/components/schemas/archiveFeaturesSchema",
 | 
					                "$ref": "#/components/schemas/batchFeaturesSchema",
 | 
				
			||||||
              },
 | 
					              },
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
          "description": "archiveFeaturesSchema",
 | 
					          "description": "batchFeaturesSchema",
 | 
				
			||||||
          "required": true,
 | 
					          "required": true,
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "responses": {
 | 
					        "responses": {
 | 
				
			||||||
@ -6010,7 +6028,7 @@ If the provided project does not exist, the list of events will be empty.",
 | 
				
			|||||||
            "description": "This response has no body.",
 | 
					            "description": "This response has no body.",
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "summary": "Archive a list of features",
 | 
					        "summary": "Archives a list of features",
 | 
				
			||||||
        "tags": [
 | 
					        "tags": [
 | 
				
			||||||
          "Features",
 | 
					          "Features",
 | 
				
			||||||
        ],
 | 
					        ],
 | 
				
			||||||
@ -7396,6 +7414,42 @@ If the provided project does not exist, the list of events will be empty.",
 | 
				
			|||||||
        ],
 | 
					        ],
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "/api/admin/projects/{projectId}/stale": {
 | 
				
			||||||
 | 
					      "post": {
 | 
				
			||||||
 | 
					        "description": "This endpoint stales the specified features.",
 | 
				
			||||||
 | 
					        "operationId": "staleFeatures",
 | 
				
			||||||
 | 
					        "parameters": [
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            "in": "path",
 | 
				
			||||||
 | 
					            "name": "projectId",
 | 
				
			||||||
 | 
					            "required": true,
 | 
				
			||||||
 | 
					            "schema": {
 | 
				
			||||||
 | 
					              "type": "string",
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        "requestBody": {
 | 
				
			||||||
 | 
					          "content": {
 | 
				
			||||||
 | 
					            "application/json": {
 | 
				
			||||||
 | 
					              "schema": {
 | 
				
			||||||
 | 
					                "$ref": "#/components/schemas/batchStaleSchema",
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "description": "batchStaleSchema",
 | 
				
			||||||
 | 
					          "required": true,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "responses": {
 | 
				
			||||||
 | 
					          "202": {
 | 
				
			||||||
 | 
					            "description": "This response has no body.",
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "summary": "Stales a list of features",
 | 
				
			||||||
 | 
					        "tags": [
 | 
				
			||||||
 | 
					          "Features",
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "/api/admin/projects/{projectId}/stickiness": {
 | 
					    "/api/admin/projects/{projectId}/stickiness": {
 | 
				
			||||||
      "get": {
 | 
					      "get": {
 | 
				
			||||||
        "operationId": "getProjectDefaultStickiness",
 | 
					        "operationId": "getProjectDefaultStickiness",
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										13
									
								
								src/test/fixtures/fake-feature-toggle-store.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										13
									
								
								src/test/fixtures/fake-feature-toggle-store.ts
									
									
									
									
										vendored
									
									
								
							@ -34,6 +34,19 @@ export default class FakeFeatureToggleStore implements IFeatureToggleStore {
 | 
				
			|||||||
        return features;
 | 
					        return features;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    async batchStale(
 | 
				
			||||||
 | 
					        featureNames: string[],
 | 
				
			||||||
 | 
					        stale: boolean,
 | 
				
			||||||
 | 
					    ): Promise<FeatureToggle[]> {
 | 
				
			||||||
 | 
					        const features = this.features.filter((feature) =>
 | 
				
			||||||
 | 
					            featureNames.includes(feature.name),
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        for (const feature of features) {
 | 
				
			||||||
 | 
					            feature.stale = stale;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return features;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async count(query: Partial<IFeatureToggleQuery>): Promise<number> {
 | 
					    async count(query: Partial<IFeatureToggleQuery>): Promise<number> {
 | 
				
			||||||
        return this.features.filter(this.getFilterQuery(query)).length;
 | 
					        return this.features.filter(this.getFilterQuery(query)).length;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user