mirror of
				https://github.com/Unleash/unleash.git
				synced 2025-10-27 11:02:16 +01:00 
			
		
		
		
	refactor: add OpenAPI schemas to more controllers (#1680)
This commit is contained in:
		
							parent
							
								
									09a6b578bf
								
							
						
					
					
						commit
						04c107a26e
					
				@ -108,8 +108,8 @@ class ProjectStore implements IProjectStore {
 | 
			
		||||
            id: row.id,
 | 
			
		||||
            description: row.description,
 | 
			
		||||
            health: row.health,
 | 
			
		||||
            featureCount: row.number_of_features,
 | 
			
		||||
            memberCount: row.number_of_users || 0,
 | 
			
		||||
            featureCount: Number(row.number_of_features) || 0,
 | 
			
		||||
            memberCount: Number(row.number_of_users) || 0,
 | 
			
		||||
            updatedAt: row.updated_at,
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -4,17 +4,23 @@ import { constraintSchema } from './spec/constraint-schema';
 | 
			
		||||
import { createFeatureSchema } from './spec/create-feature-schema';
 | 
			
		||||
import { createStrategySchema } from './spec/create-strategy-schema';
 | 
			
		||||
import { emptySchema } from './spec/empty-schema';
 | 
			
		||||
import { environmentSchema } from './spec/environment-schema';
 | 
			
		||||
import { featureEnvironmentSchema } from './spec/feature-environment-schema';
 | 
			
		||||
import { featureSchema } from './spec/feature-schema';
 | 
			
		||||
import { featureStrategySchema } from './spec/feature-strategy-schema';
 | 
			
		||||
import { featureVariantsSchema } from './spec/feature-variants-schema';
 | 
			
		||||
import { featuresSchema } from './spec/features-schema';
 | 
			
		||||
import { healthOverviewSchema } from './spec/health-overview-schema';
 | 
			
		||||
import { healthReportSchema } from './spec/health-report-schema';
 | 
			
		||||
import { mapValues } from '../util/map-values';
 | 
			
		||||
import { omitKeys } from '../util/omit-keys';
 | 
			
		||||
import { overrideSchema } from './spec/override-schema';
 | 
			
		||||
import { parametersSchema } from './spec/parameters-schema';
 | 
			
		||||
import { patchSchema } from './spec/patch-schema';
 | 
			
		||||
import { patchesSchema } from './spec/patches-schema';
 | 
			
		||||
import { projectEnvironmentSchema } from './spec/project-environment-schema';
 | 
			
		||||
import { projectSchema } from './spec/project-schema';
 | 
			
		||||
import { projectsSchema } from './spec/projects-schema';
 | 
			
		||||
import { strategySchema } from './spec/strategy-schema';
 | 
			
		||||
import { tagSchema } from './spec/tag-schema';
 | 
			
		||||
import { tagsSchema } from './spec/tags-schema';
 | 
			
		||||
@ -33,11 +39,13 @@ export type SchemaRef = typeof schemas[keyof typeof schemas]['components'];
 | 
			
		||||
 | 
			
		||||
export interface AdminApiOperation
 | 
			
		||||
    extends Omit<OpenAPIV3.OperationObject, 'tags'> {
 | 
			
		||||
    operationId: string;
 | 
			
		||||
    tags: ['admin'];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface ClientApiOperation
 | 
			
		||||
    extends Omit<OpenAPIV3.OperationObject, 'tags'> {
 | 
			
		||||
    operationId: string;
 | 
			
		||||
    tags: ['client'];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -47,15 +55,21 @@ export const schemas = {
 | 
			
		||||
    createFeatureSchema,
 | 
			
		||||
    createStrategySchema,
 | 
			
		||||
    emptySchema,
 | 
			
		||||
    environmentSchema,
 | 
			
		||||
    featureEnvironmentSchema,
 | 
			
		||||
    featureSchema,
 | 
			
		||||
    featureStrategySchema,
 | 
			
		||||
    featureVariantsSchema,
 | 
			
		||||
    featuresSchema,
 | 
			
		||||
    healthOverviewSchema,
 | 
			
		||||
    healthReportSchema,
 | 
			
		||||
    overrideSchema,
 | 
			
		||||
    parametersSchema,
 | 
			
		||||
    patchSchema,
 | 
			
		||||
    patchesSchema,
 | 
			
		||||
    projectEnvironmentSchema,
 | 
			
		||||
    projectSchema,
 | 
			
		||||
    projectsSchema,
 | 
			
		||||
    strategySchema,
 | 
			
		||||
    tagSchema,
 | 
			
		||||
    tagsSchema,
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										25
									
								
								src/lib/openapi/spec/environment-schema.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								src/lib/openapi/spec/environment-schema.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,25 @@
 | 
			
		||||
import { FromSchema } from 'json-schema-to-ts';
 | 
			
		||||
 | 
			
		||||
export const environmentSchema = {
 | 
			
		||||
    $id: '#/components/schemas/environmentSchema',
 | 
			
		||||
    type: 'object',
 | 
			
		||||
    additionalProperties: false,
 | 
			
		||||
    required: ['name', 'type', 'enabled'],
 | 
			
		||||
    properties: {
 | 
			
		||||
        name: {
 | 
			
		||||
            type: 'string',
 | 
			
		||||
        },
 | 
			
		||||
        type: {
 | 
			
		||||
            type: 'string',
 | 
			
		||||
        },
 | 
			
		||||
        enabled: {
 | 
			
		||||
            type: 'boolean',
 | 
			
		||||
        },
 | 
			
		||||
        sortOrder: {
 | 
			
		||||
            type: 'number',
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
    components: {},
 | 
			
		||||
} as const;
 | 
			
		||||
 | 
			
		||||
export type EnvironmentSchema = FromSchema<typeof environmentSchema>;
 | 
			
		||||
@ -25,6 +25,13 @@ test('featureSchema', () => {
 | 
			
		||||
                payload: { type: 'a', value: 'b' },
 | 
			
		||||
            },
 | 
			
		||||
        ],
 | 
			
		||||
        environments: [
 | 
			
		||||
            {
 | 
			
		||||
                name: 'a',
 | 
			
		||||
                type: 'b',
 | 
			
		||||
                enabled: true,
 | 
			
		||||
            },
 | 
			
		||||
        ],
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    expect(
 | 
			
		||||
 | 
			
		||||
@ -4,6 +4,7 @@ import { strategySchema } from './strategy-schema';
 | 
			
		||||
import { constraintSchema } from './constraint-schema';
 | 
			
		||||
import { overrideSchema } from './override-schema';
 | 
			
		||||
import { parametersSchema } from './parameters-schema';
 | 
			
		||||
import { environmentSchema } from './environment-schema';
 | 
			
		||||
 | 
			
		||||
export const featureSchema = {
 | 
			
		||||
    $id: '#/components/schemas/featureSchema',
 | 
			
		||||
@ -48,7 +49,7 @@ export const featureSchema = {
 | 
			
		||||
        environments: {
 | 
			
		||||
            type: 'array',
 | 
			
		||||
            items: {
 | 
			
		||||
                type: 'object',
 | 
			
		||||
                $ref: '#/components/schemas/environmentSchema',
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
        strategies: {
 | 
			
		||||
@ -67,6 +68,7 @@ export const featureSchema = {
 | 
			
		||||
    components: {
 | 
			
		||||
        schemas: {
 | 
			
		||||
            constraintSchema,
 | 
			
		||||
            environmentSchema,
 | 
			
		||||
            overrideSchema,
 | 
			
		||||
            parametersSchema,
 | 
			
		||||
            strategySchema,
 | 
			
		||||
 | 
			
		||||
@ -5,6 +5,7 @@ import { variantSchema } from './variant-schema';
 | 
			
		||||
import { overrideSchema } from './override-schema';
 | 
			
		||||
import { constraintSchema } from './constraint-schema';
 | 
			
		||||
import { strategySchema } from './strategy-schema';
 | 
			
		||||
import { environmentSchema } from './environment-schema';
 | 
			
		||||
 | 
			
		||||
export const featuresSchema = {
 | 
			
		||||
    $id: '#/components/schemas/featuresSchema',
 | 
			
		||||
@ -25,6 +26,7 @@ export const featuresSchema = {
 | 
			
		||||
    components: {
 | 
			
		||||
        schemas: {
 | 
			
		||||
            constraintSchema,
 | 
			
		||||
            environmentSchema,
 | 
			
		||||
            featureSchema,
 | 
			
		||||
            overrideSchema,
 | 
			
		||||
            parametersSchema,
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										62
									
								
								src/lib/openapi/spec/health-overview-schema.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								src/lib/openapi/spec/health-overview-schema.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,62 @@
 | 
			
		||||
import { FromSchema } from 'json-schema-to-ts';
 | 
			
		||||
import { parametersSchema } from './parameters-schema';
 | 
			
		||||
import { variantSchema } from './variant-schema';
 | 
			
		||||
import { overrideSchema } from './override-schema';
 | 
			
		||||
import { strategySchema } from './strategy-schema';
 | 
			
		||||
import { featureSchema } from './feature-schema';
 | 
			
		||||
import { constraintSchema } from './constraint-schema';
 | 
			
		||||
import { environmentSchema } from './environment-schema';
 | 
			
		||||
 | 
			
		||||
export const healthOverviewSchema = {
 | 
			
		||||
    $id: '#/components/schemas/healthOverviewSchema',
 | 
			
		||||
    type: 'object',
 | 
			
		||||
    additionalProperties: false,
 | 
			
		||||
    required: ['version', 'name'],
 | 
			
		||||
    properties: {
 | 
			
		||||
        version: {
 | 
			
		||||
            type: 'number',
 | 
			
		||||
        },
 | 
			
		||||
        name: {
 | 
			
		||||
            type: 'string',
 | 
			
		||||
        },
 | 
			
		||||
        description: {
 | 
			
		||||
            type: 'string',
 | 
			
		||||
        },
 | 
			
		||||
        members: {
 | 
			
		||||
            type: 'number',
 | 
			
		||||
        },
 | 
			
		||||
        health: {
 | 
			
		||||
            type: 'number',
 | 
			
		||||
        },
 | 
			
		||||
        environments: {
 | 
			
		||||
            type: 'array',
 | 
			
		||||
            items: {
 | 
			
		||||
                type: 'string',
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
        features: {
 | 
			
		||||
            type: 'array',
 | 
			
		||||
            items: {
 | 
			
		||||
                $ref: '#/components/schemas/featureSchema',
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
        updatedAt: {
 | 
			
		||||
            type: 'string',
 | 
			
		||||
            format: 'date-time',
 | 
			
		||||
            nullable: true,
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
    components: {
 | 
			
		||||
        schemas: {
 | 
			
		||||
            constraintSchema,
 | 
			
		||||
            environmentSchema,
 | 
			
		||||
            featureSchema,
 | 
			
		||||
            overrideSchema,
 | 
			
		||||
            parametersSchema,
 | 
			
		||||
            strategySchema,
 | 
			
		||||
            variantSchema,
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
} as const;
 | 
			
		||||
 | 
			
		||||
export type HealthOverviewSchema = FromSchema<typeof healthOverviewSchema>;
 | 
			
		||||
							
								
								
									
										27
									
								
								src/lib/openapi/spec/health-report-schema.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								src/lib/openapi/spec/health-report-schema.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,27 @@
 | 
			
		||||
import { FromSchema } from 'json-schema-to-ts';
 | 
			
		||||
import { healthOverviewSchema } from './health-overview-schema';
 | 
			
		||||
 | 
			
		||||
export const healthReportSchema = {
 | 
			
		||||
    ...healthOverviewSchema,
 | 
			
		||||
    $id: '#/components/schemas/healthReportSchema',
 | 
			
		||||
    required: [
 | 
			
		||||
        ...healthOverviewSchema.required,
 | 
			
		||||
        'potentiallyStaleCount',
 | 
			
		||||
        'activeCount',
 | 
			
		||||
        'staleCount',
 | 
			
		||||
    ],
 | 
			
		||||
    properties: {
 | 
			
		||||
        ...healthOverviewSchema.properties,
 | 
			
		||||
        potentiallyStaleCount: {
 | 
			
		||||
            type: 'number',
 | 
			
		||||
        },
 | 
			
		||||
        activeCount: {
 | 
			
		||||
            type: 'number',
 | 
			
		||||
        },
 | 
			
		||||
        staleCount: {
 | 
			
		||||
            type: 'number',
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
} as const;
 | 
			
		||||
 | 
			
		||||
export type HealthReportSchema = FromSchema<typeof healthReportSchema>;
 | 
			
		||||
							
								
								
									
										18
									
								
								src/lib/openapi/spec/project-environment-schema.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/lib/openapi/spec/project-environment-schema.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,18 @@
 | 
			
		||||
import { FromSchema } from 'json-schema-to-ts';
 | 
			
		||||
 | 
			
		||||
export const projectEnvironmentSchema = {
 | 
			
		||||
    $id: '#/components/schemas/projectEnvironmentSchema',
 | 
			
		||||
    type: 'object',
 | 
			
		||||
    additionalProperties: false,
 | 
			
		||||
    required: ['environment'],
 | 
			
		||||
    properties: {
 | 
			
		||||
        environment: {
 | 
			
		||||
            type: 'string',
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
    components: {},
 | 
			
		||||
} as const;
 | 
			
		||||
 | 
			
		||||
export type ProjectEnvironmentSchema = FromSchema<
 | 
			
		||||
    typeof projectEnvironmentSchema
 | 
			
		||||
>;
 | 
			
		||||
							
								
								
									
										40
									
								
								src/lib/openapi/spec/project-schema.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								src/lib/openapi/spec/project-schema.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,40 @@
 | 
			
		||||
import { FromSchema } from 'json-schema-to-ts';
 | 
			
		||||
 | 
			
		||||
export const projectSchema = {
 | 
			
		||||
    $id: '#/components/schemas/projectSchema',
 | 
			
		||||
    type: 'object',
 | 
			
		||||
    additionalProperties: false,
 | 
			
		||||
    required: ['id', 'name'],
 | 
			
		||||
    properties: {
 | 
			
		||||
        id: {
 | 
			
		||||
            type: 'string',
 | 
			
		||||
        },
 | 
			
		||||
        name: {
 | 
			
		||||
            type: 'string',
 | 
			
		||||
        },
 | 
			
		||||
        description: {
 | 
			
		||||
            type: 'string',
 | 
			
		||||
        },
 | 
			
		||||
        health: {
 | 
			
		||||
            type: 'number',
 | 
			
		||||
        },
 | 
			
		||||
        featureCount: {
 | 
			
		||||
            type: 'number',
 | 
			
		||||
        },
 | 
			
		||||
        memberCount: {
 | 
			
		||||
            type: 'number',
 | 
			
		||||
        },
 | 
			
		||||
        createdAt: {
 | 
			
		||||
            type: 'string',
 | 
			
		||||
            format: 'date-time',
 | 
			
		||||
        },
 | 
			
		||||
        updatedAt: {
 | 
			
		||||
            type: 'string',
 | 
			
		||||
            format: 'date-time',
 | 
			
		||||
            nullable: true,
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
    components: {},
 | 
			
		||||
} as const;
 | 
			
		||||
 | 
			
		||||
export type ProjectSchema = FromSchema<typeof projectSchema>;
 | 
			
		||||
							
								
								
									
										27
									
								
								src/lib/openapi/spec/projects-schema.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								src/lib/openapi/spec/projects-schema.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,27 @@
 | 
			
		||||
import { FromSchema } from 'json-schema-to-ts';
 | 
			
		||||
import { projectSchema } from './project-schema';
 | 
			
		||||
 | 
			
		||||
export const projectsSchema = {
 | 
			
		||||
    $id: '#/components/schemas/projectsSchema',
 | 
			
		||||
    type: 'object',
 | 
			
		||||
    additionalProperties: false,
 | 
			
		||||
    required: ['version', 'projects'],
 | 
			
		||||
    properties: {
 | 
			
		||||
        version: {
 | 
			
		||||
            type: 'integer',
 | 
			
		||||
        },
 | 
			
		||||
        projects: {
 | 
			
		||||
            type: 'array',
 | 
			
		||||
            items: {
 | 
			
		||||
                $ref: '#/components/schemas/projectSchema',
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
    components: {
 | 
			
		||||
        schemas: {
 | 
			
		||||
            projectSchema,
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
} as const;
 | 
			
		||||
 | 
			
		||||
export type ProjectsSchema = FromSchema<typeof projectsSchema>;
 | 
			
		||||
@ -14,6 +14,7 @@ import {
 | 
			
		||||
import { serializeDates } from '../../types/serialize-dates';
 | 
			
		||||
import { OpenApiService } from '../../services/openapi-service';
 | 
			
		||||
import { createResponseSchema } from '../../openapi';
 | 
			
		||||
import { EmptySchema } from '../../openapi/spec/empty-schema';
 | 
			
		||||
 | 
			
		||||
export default class ArchiveController extends Controller {
 | 
			
		||||
    private readonly logger: Logger;
 | 
			
		||||
@ -42,6 +43,7 @@ export default class ArchiveController extends Controller {
 | 
			
		||||
            middleware: [
 | 
			
		||||
                openApiService.validPath({
 | 
			
		||||
                    tags: ['admin'],
 | 
			
		||||
                    operationId: 'getArchivedFeatures',
 | 
			
		||||
                    responses: { 200: createResponseSchema('featuresSchema') },
 | 
			
		||||
                    deprecated: true,
 | 
			
		||||
                }),
 | 
			
		||||
@ -56,18 +58,42 @@ export default class ArchiveController extends Controller {
 | 
			
		||||
            middleware: [
 | 
			
		||||
                openApiService.validPath({
 | 
			
		||||
                    tags: ['admin'],
 | 
			
		||||
                    operationId: 'getArchivedFeaturesByProjectId',
 | 
			
		||||
                    responses: { 200: createResponseSchema('featuresSchema') },
 | 
			
		||||
                    deprecated: true,
 | 
			
		||||
                }),
 | 
			
		||||
            ],
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this.delete('/:featureName', this.deleteFeature, DELETE_FEATURE);
 | 
			
		||||
        this.post(
 | 
			
		||||
            '/revive/:featureName',
 | 
			
		||||
            this.reviveFeatureToggle,
 | 
			
		||||
            UPDATE_FEATURE,
 | 
			
		||||
        );
 | 
			
		||||
        this.route({
 | 
			
		||||
            method: 'delete',
 | 
			
		||||
            path: '/:featureName',
 | 
			
		||||
            acceptAnyContentType: true,
 | 
			
		||||
            handler: this.deleteFeature,
 | 
			
		||||
            permission: DELETE_FEATURE,
 | 
			
		||||
            middleware: [
 | 
			
		||||
                openApiService.validPath({
 | 
			
		||||
                    tags: ['admin'],
 | 
			
		||||
                    operationId: 'deleteFeature',
 | 
			
		||||
                    responses: { 200: createResponseSchema('emptySchema') },
 | 
			
		||||
                }),
 | 
			
		||||
            ],
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this.route({
 | 
			
		||||
            method: 'post',
 | 
			
		||||
            path: '/revive/:featureName',
 | 
			
		||||
            acceptAnyContentType: true,
 | 
			
		||||
            handler: this.reviveFeature,
 | 
			
		||||
            permission: UPDATE_FEATURE,
 | 
			
		||||
            middleware: [
 | 
			
		||||
                openApiService.validPath({
 | 
			
		||||
                    tags: ['admin'],
 | 
			
		||||
                    operationId: 'reviveFeature',
 | 
			
		||||
                    responses: { 200: createResponseSchema('emptySchema') },
 | 
			
		||||
                }),
 | 
			
		||||
            ],
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async getArchivedFeatures(
 | 
			
		||||
@ -104,8 +130,8 @@ export default class ArchiveController extends Controller {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async deleteFeature(
 | 
			
		||||
        req: IAuthRequest<any, { featureName: string }, any, any>,
 | 
			
		||||
        res: Response,
 | 
			
		||||
        req: IAuthRequest<{ featureName: string }>,
 | 
			
		||||
        res: Response<EmptySchema>,
 | 
			
		||||
    ): Promise<void> {
 | 
			
		||||
        const { featureName } = req.params;
 | 
			
		||||
        const user = extractUsername(req);
 | 
			
		||||
@ -113,7 +139,10 @@ export default class ArchiveController extends Controller {
 | 
			
		||||
        res.status(200).end();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async reviveFeatureToggle(req: IAuthRequest, res: Response): Promise<void> {
 | 
			
		||||
    async reviveFeature(
 | 
			
		||||
        req: IAuthRequest<{ featureName: string }>,
 | 
			
		||||
        res: Response<EmptySchema>,
 | 
			
		||||
    ): Promise<void> {
 | 
			
		||||
        const userName = extractUsername(req);
 | 
			
		||||
        const { featureName } = req.params;
 | 
			
		||||
        await this.featureService.reviveToggle(featureName, userName);
 | 
			
		||||
 | 
			
		||||
@ -5,7 +5,8 @@ import { IUnleashServices } from '../../../types/services';
 | 
			
		||||
import { Logger } from '../../../logger';
 | 
			
		||||
import EnvironmentService from '../../../services/environment-service';
 | 
			
		||||
import { UPDATE_PROJECT } from '../../../types/permissions';
 | 
			
		||||
import { addEnvironment } from '../../../schema/project-schema';
 | 
			
		||||
import { createRequestSchema, createResponseSchema } from '../../../openapi';
 | 
			
		||||
import { ProjectEnvironmentSchema } from '../../../openapi/spec/project-environment-schema';
 | 
			
		||||
 | 
			
		||||
const PREFIX = '/:projectId/environments';
 | 
			
		||||
 | 
			
		||||
@ -14,10 +15,6 @@ interface IProjectEnvironmentParams {
 | 
			
		||||
    environment: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface EnvironmentBody {
 | 
			
		||||
    environment: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default class EnvironmentsController extends Controller {
 | 
			
		||||
    private logger: Logger;
 | 
			
		||||
 | 
			
		||||
@ -25,49 +22,79 @@ export default class EnvironmentsController extends Controller {
 | 
			
		||||
 | 
			
		||||
    constructor(
 | 
			
		||||
        config: IUnleashConfig,
 | 
			
		||||
        { environmentService }: Pick<IUnleashServices, 'environmentService'>,
 | 
			
		||||
        {
 | 
			
		||||
            environmentService,
 | 
			
		||||
            openApiService,
 | 
			
		||||
        }: Pick<IUnleashServices, 'environmentService' | 'openApiService'>,
 | 
			
		||||
    ) {
 | 
			
		||||
        super(config);
 | 
			
		||||
 | 
			
		||||
        this.logger = config.getLogger('admin-api/project/environments.ts');
 | 
			
		||||
        this.environmentService = environmentService;
 | 
			
		||||
        this.post(PREFIX, this.addEnvironmentToProject, UPDATE_PROJECT);
 | 
			
		||||
        this.delete(
 | 
			
		||||
            `${PREFIX}/:environment`,
 | 
			
		||||
            this.removeEnvironmentFromProject,
 | 
			
		||||
            UPDATE_PROJECT,
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        this.route({
 | 
			
		||||
            method: 'post',
 | 
			
		||||
            path: PREFIX,
 | 
			
		||||
            handler: this.addEnvironmentToProject,
 | 
			
		||||
            permission: UPDATE_PROJECT,
 | 
			
		||||
            middleware: [
 | 
			
		||||
                openApiService.validPath({
 | 
			
		||||
                    tags: ['admin'],
 | 
			
		||||
                    operationId: 'addEnvironmentToProject',
 | 
			
		||||
                    requestBody: createRequestSchema(
 | 
			
		||||
                        'projectEnvironmentSchema',
 | 
			
		||||
                    ),
 | 
			
		||||
                    responses: { 200: createResponseSchema('emptySchema') },
 | 
			
		||||
                }),
 | 
			
		||||
            ],
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this.route({
 | 
			
		||||
            method: 'delete',
 | 
			
		||||
            path: `${PREFIX}/:environment`,
 | 
			
		||||
            acceptAnyContentType: true,
 | 
			
		||||
            handler: this.removeEnvironmentFromProject,
 | 
			
		||||
            permission: UPDATE_PROJECT,
 | 
			
		||||
            middleware: [
 | 
			
		||||
                openApiService.validPath({
 | 
			
		||||
                    tags: ['admin'],
 | 
			
		||||
                    operationId: 'removeEnvironmentFromProject',
 | 
			
		||||
                    responses: { 200: createResponseSchema('emptySchema') },
 | 
			
		||||
                }),
 | 
			
		||||
            ],
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async addEnvironmentToProject(
 | 
			
		||||
        req: Request<
 | 
			
		||||
            Omit<IProjectEnvironmentParams, 'environment'>,
 | 
			
		||||
            any,
 | 
			
		||||
            EnvironmentBody,
 | 
			
		||||
            any
 | 
			
		||||
            void,
 | 
			
		||||
            ProjectEnvironmentSchema
 | 
			
		||||
        >,
 | 
			
		||||
        res: Response,
 | 
			
		||||
    ): Promise<void> {
 | 
			
		||||
        const { projectId } = req.params;
 | 
			
		||||
 | 
			
		||||
        const { environment } = await addEnvironment.validateAsync(req.body);
 | 
			
		||||
        const { environment } = req.body;
 | 
			
		||||
 | 
			
		||||
        await this.environmentService.addEnvironmentToProject(
 | 
			
		||||
            environment,
 | 
			
		||||
            projectId,
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        res.status(200).end();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async removeEnvironmentFromProject(
 | 
			
		||||
        req: Request<IProjectEnvironmentParams, any, any, any>,
 | 
			
		||||
        res: Response,
 | 
			
		||||
        req: Request<IProjectEnvironmentParams>,
 | 
			
		||||
        res: Response<void>,
 | 
			
		||||
    ): Promise<void> {
 | 
			
		||||
        const { projectId, environment } = req.params;
 | 
			
		||||
 | 
			
		||||
        await this.environmentService.removeEnvironmentFromProject(
 | 
			
		||||
            environment,
 | 
			
		||||
            projectId,
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        res.status(200).end();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -5,28 +5,74 @@ import { IUnleashConfig } from '../../../types/option';
 | 
			
		||||
import ProjectHealthService from '../../../services/project-health-service';
 | 
			
		||||
import { Logger } from '../../../logger';
 | 
			
		||||
import { IArchivedQuery, IProjectParam } from '../../../types/model';
 | 
			
		||||
import { NONE } from '../../../types/permissions';
 | 
			
		||||
import { OpenApiService } from '../../../services/openapi-service';
 | 
			
		||||
import { createResponseSchema } from '../../../openapi';
 | 
			
		||||
import {
 | 
			
		||||
    healthOverviewSchema,
 | 
			
		||||
    HealthOverviewSchema,
 | 
			
		||||
} from '../../../openapi/spec/health-overview-schema';
 | 
			
		||||
import { serializeDates } from '../../../types/serialize-dates';
 | 
			
		||||
import {
 | 
			
		||||
    healthReportSchema,
 | 
			
		||||
    HealthReportSchema,
 | 
			
		||||
} from '../../../openapi/spec/health-report-schema';
 | 
			
		||||
 | 
			
		||||
export default class ProjectHealthReport extends Controller {
 | 
			
		||||
    private projectHealthService: ProjectHealthService;
 | 
			
		||||
 | 
			
		||||
    private openApiService: OpenApiService;
 | 
			
		||||
 | 
			
		||||
    private logger: Logger;
 | 
			
		||||
 | 
			
		||||
    constructor(
 | 
			
		||||
        config: IUnleashConfig,
 | 
			
		||||
        {
 | 
			
		||||
            projectHealthService,
 | 
			
		||||
        }: Pick<IUnleashServices, 'projectHealthService'>,
 | 
			
		||||
            openApiService,
 | 
			
		||||
        }: Pick<IUnleashServices, 'projectHealthService' | 'openApiService'>,
 | 
			
		||||
    ) {
 | 
			
		||||
        super(config);
 | 
			
		||||
        this.logger = config.getLogger('/admin-api/project/health-report');
 | 
			
		||||
        this.projectHealthService = projectHealthService;
 | 
			
		||||
        this.get('/:projectId', this.getProjectOverview);
 | 
			
		||||
        this.get('/:projectId/health-report', this.getProjectHealthReport);
 | 
			
		||||
        this.openApiService = openApiService;
 | 
			
		||||
 | 
			
		||||
        this.route({
 | 
			
		||||
            method: 'get',
 | 
			
		||||
            path: '/:projectId',
 | 
			
		||||
            handler: this.getProjectHealthOverview,
 | 
			
		||||
            permission: NONE,
 | 
			
		||||
            middleware: [
 | 
			
		||||
                openApiService.validPath({
 | 
			
		||||
                    tags: ['admin'],
 | 
			
		||||
                    operationId: 'getProjectHealthOverview',
 | 
			
		||||
                    responses: {
 | 
			
		||||
                        200: createResponseSchema('healthOverviewSchema'),
 | 
			
		||||
                    },
 | 
			
		||||
                }),
 | 
			
		||||
            ],
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this.route({
 | 
			
		||||
            method: 'get',
 | 
			
		||||
            path: '/:projectId/health-report',
 | 
			
		||||
            handler: this.getProjectHealthReport,
 | 
			
		||||
            permission: NONE,
 | 
			
		||||
            middleware: [
 | 
			
		||||
                openApiService.validPath({
 | 
			
		||||
                    tags: ['admin'],
 | 
			
		||||
                    operationId: 'getProjectHealthReport',
 | 
			
		||||
                    responses: {
 | 
			
		||||
                        200: createResponseSchema('healthReportSchema'),
 | 
			
		||||
                    },
 | 
			
		||||
                }),
 | 
			
		||||
            ],
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async getProjectOverview(
 | 
			
		||||
        req: Request<IProjectParam, any, any, IArchivedQuery>,
 | 
			
		||||
        res: Response,
 | 
			
		||||
    async getProjectHealthOverview(
 | 
			
		||||
        req: Request<IProjectParam, unknown, unknown, IArchivedQuery>,
 | 
			
		||||
        res: Response<HealthOverviewSchema>,
 | 
			
		||||
    ): Promise<void> {
 | 
			
		||||
        const { projectId } = req.params;
 | 
			
		||||
        const { archived } = req.query;
 | 
			
		||||
@ -34,20 +80,27 @@ export default class ProjectHealthReport extends Controller {
 | 
			
		||||
            projectId,
 | 
			
		||||
            archived,
 | 
			
		||||
        );
 | 
			
		||||
        res.json(overview);
 | 
			
		||||
        this.openApiService.respondWithValidation(
 | 
			
		||||
            200,
 | 
			
		||||
            res,
 | 
			
		||||
            healthOverviewSchema.$id,
 | 
			
		||||
            serializeDates(overview),
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async getProjectHealthReport(
 | 
			
		||||
        req: Request<IProjectParam, any, any, any>,
 | 
			
		||||
        res: Response,
 | 
			
		||||
        req: Request<IProjectParam>,
 | 
			
		||||
        res: Response<HealthReportSchema>,
 | 
			
		||||
    ): Promise<void> {
 | 
			
		||||
        const { projectId } = req.params;
 | 
			
		||||
        const overview = await this.projectHealthService.getProjectHealthReport(
 | 
			
		||||
            projectId,
 | 
			
		||||
        );
 | 
			
		||||
        res.json({
 | 
			
		||||
            version: 2,
 | 
			
		||||
            ...overview,
 | 
			
		||||
        });
 | 
			
		||||
        this.openApiService.respondWithValidation(
 | 
			
		||||
            200,
 | 
			
		||||
            res,
 | 
			
		||||
            healthReportSchema.$id,
 | 
			
		||||
            serializeDates(overview),
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -7,24 +7,62 @@ import EnvironmentsController from './environments';
 | 
			
		||||
import ProjectHealthReport from './health-report';
 | 
			
		||||
import ProjectService from '../../../services/project-service';
 | 
			
		||||
import VariantsController from './variants';
 | 
			
		||||
import { NONE } from '../../../types/permissions';
 | 
			
		||||
import {
 | 
			
		||||
    projectsSchema,
 | 
			
		||||
    ProjectsSchema,
 | 
			
		||||
} from '../../../openapi/spec/projects-schema';
 | 
			
		||||
import { OpenApiService } from '../../../services/openapi-service';
 | 
			
		||||
import { serializeDates } from '../../../types/serialize-dates';
 | 
			
		||||
import { createResponseSchema } from '../../../openapi';
 | 
			
		||||
 | 
			
		||||
export default class ProjectApi extends Controller {
 | 
			
		||||
    private projectService: ProjectService;
 | 
			
		||||
 | 
			
		||||
    private openApiService: OpenApiService;
 | 
			
		||||
 | 
			
		||||
    constructor(config: IUnleashConfig, services: IUnleashServices) {
 | 
			
		||||
        super(config);
 | 
			
		||||
        this.projectService = services.projectService;
 | 
			
		||||
        this.openApiService = services.openApiService;
 | 
			
		||||
 | 
			
		||||
        this.get('/', this.getProjects);
 | 
			
		||||
 | 
			
		||||
        this.route({
 | 
			
		||||
            path: '',
 | 
			
		||||
            method: 'get',
 | 
			
		||||
            handler: this.getProjects,
 | 
			
		||||
            permission: NONE,
 | 
			
		||||
            middleware: [
 | 
			
		||||
                services.openApiService.validPath({
 | 
			
		||||
                    tags: ['admin'],
 | 
			
		||||
                    operationId: 'getProjects',
 | 
			
		||||
                    responses: {
 | 
			
		||||
                        200: createResponseSchema('projectsSchema'),
 | 
			
		||||
                    },
 | 
			
		||||
                }),
 | 
			
		||||
            ],
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this.use('/', new ProjectFeaturesController(config, services).router);
 | 
			
		||||
        this.use('/', new EnvironmentsController(config, services).router);
 | 
			
		||||
        this.use('/', new ProjectHealthReport(config, services).router);
 | 
			
		||||
        this.use('/', new VariantsController(config, services).router);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async getProjects(req: Request, res: Response): Promise<void> {
 | 
			
		||||
    async getProjects(
 | 
			
		||||
        req: Request,
 | 
			
		||||
        res: Response<ProjectsSchema>,
 | 
			
		||||
    ): Promise<void> {
 | 
			
		||||
        const projects = await this.projectService.getProjects({
 | 
			
		||||
            id: 'default',
 | 
			
		||||
        });
 | 
			
		||||
        res.json({ version: 1, projects }).end();
 | 
			
		||||
 | 
			
		||||
        this.openApiService.respondWithValidation(
 | 
			
		||||
            200,
 | 
			
		||||
            res,
 | 
			
		||||
            projectsSchema.$id,
 | 
			
		||||
            { version: 1, projects: serializeDates(projects) },
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,6 +0,0 @@
 | 
			
		||||
import joi from 'joi';
 | 
			
		||||
 | 
			
		||||
export const addEnvironment = joi
 | 
			
		||||
    .object()
 | 
			
		||||
    .keys({ environment: joi.string().required() })
 | 
			
		||||
    .options({ stripUnknown: true, allowUnknown: false, abortEarly: false });
 | 
			
		||||
@ -73,7 +73,12 @@ export class OpenApiService {
 | 
			
		||||
        const errors = validateSchema(schema, data);
 | 
			
		||||
 | 
			
		||||
        if (errors) {
 | 
			
		||||
            this.logger.warn('Invalid response:', errors);
 | 
			
		||||
            this.logger.warn(
 | 
			
		||||
                'Invalid response:',
 | 
			
		||||
                process.env.NODE_ENV === 'development'
 | 
			
		||||
                    ? JSON.stringify(errors, null, 2)
 | 
			
		||||
                    : errors,
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        res.status(status).json(data);
 | 
			
		||||
 | 
			
		||||
@ -160,6 +160,29 @@ Object {
 | 
			
		||||
      "emptySchema": Object {
 | 
			
		||||
        "description": "emptySchema",
 | 
			
		||||
      },
 | 
			
		||||
      "environmentSchema": Object {
 | 
			
		||||
        "additionalProperties": false,
 | 
			
		||||
        "properties": Object {
 | 
			
		||||
          "enabled": Object {
 | 
			
		||||
            "type": "boolean",
 | 
			
		||||
          },
 | 
			
		||||
          "name": Object {
 | 
			
		||||
            "type": "string",
 | 
			
		||||
          },
 | 
			
		||||
          "sortOrder": Object {
 | 
			
		||||
            "type": "number",
 | 
			
		||||
          },
 | 
			
		||||
          "type": Object {
 | 
			
		||||
            "type": "string",
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
        "required": Array [
 | 
			
		||||
          "name",
 | 
			
		||||
          "type",
 | 
			
		||||
          "enabled",
 | 
			
		||||
        ],
 | 
			
		||||
        "type": "object",
 | 
			
		||||
      },
 | 
			
		||||
      "featureEnvironmentSchema": Object {
 | 
			
		||||
        "additionalProperties": false,
 | 
			
		||||
        "properties": Object {
 | 
			
		||||
@ -207,7 +230,7 @@ Object {
 | 
			
		||||
          },
 | 
			
		||||
          "environments": Object {
 | 
			
		||||
            "items": Object {
 | 
			
		||||
              "type": "object",
 | 
			
		||||
              "$ref": "#/components/schemas/environmentSchema",
 | 
			
		||||
            },
 | 
			
		||||
            "type": "array",
 | 
			
		||||
          },
 | 
			
		||||
@ -336,6 +359,102 @@ Object {
 | 
			
		||||
        ],
 | 
			
		||||
        "type": "object",
 | 
			
		||||
      },
 | 
			
		||||
      "healthOverviewSchema": Object {
 | 
			
		||||
        "additionalProperties": false,
 | 
			
		||||
        "properties": Object {
 | 
			
		||||
          "description": Object {
 | 
			
		||||
            "type": "string",
 | 
			
		||||
          },
 | 
			
		||||
          "environments": Object {
 | 
			
		||||
            "items": Object {
 | 
			
		||||
              "type": "string",
 | 
			
		||||
            },
 | 
			
		||||
            "type": "array",
 | 
			
		||||
          },
 | 
			
		||||
          "features": Object {
 | 
			
		||||
            "items": Object {
 | 
			
		||||
              "$ref": "#/components/schemas/featureSchema",
 | 
			
		||||
            },
 | 
			
		||||
            "type": "array",
 | 
			
		||||
          },
 | 
			
		||||
          "health": Object {
 | 
			
		||||
            "type": "number",
 | 
			
		||||
          },
 | 
			
		||||
          "members": Object {
 | 
			
		||||
            "type": "number",
 | 
			
		||||
          },
 | 
			
		||||
          "name": Object {
 | 
			
		||||
            "type": "string",
 | 
			
		||||
          },
 | 
			
		||||
          "updatedAt": Object {
 | 
			
		||||
            "format": "date-time",
 | 
			
		||||
            "nullable": true,
 | 
			
		||||
            "type": "string",
 | 
			
		||||
          },
 | 
			
		||||
          "version": Object {
 | 
			
		||||
            "type": "number",
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
        "required": Array [
 | 
			
		||||
          "version",
 | 
			
		||||
          "name",
 | 
			
		||||
        ],
 | 
			
		||||
        "type": "object",
 | 
			
		||||
      },
 | 
			
		||||
      "healthReportSchema": Object {
 | 
			
		||||
        "additionalProperties": false,
 | 
			
		||||
        "properties": Object {
 | 
			
		||||
          "activeCount": Object {
 | 
			
		||||
            "type": "number",
 | 
			
		||||
          },
 | 
			
		||||
          "description": Object {
 | 
			
		||||
            "type": "string",
 | 
			
		||||
          },
 | 
			
		||||
          "environments": Object {
 | 
			
		||||
            "items": Object {
 | 
			
		||||
              "type": "string",
 | 
			
		||||
            },
 | 
			
		||||
            "type": "array",
 | 
			
		||||
          },
 | 
			
		||||
          "features": Object {
 | 
			
		||||
            "items": Object {
 | 
			
		||||
              "$ref": "#/components/schemas/featureSchema",
 | 
			
		||||
            },
 | 
			
		||||
            "type": "array",
 | 
			
		||||
          },
 | 
			
		||||
          "health": Object {
 | 
			
		||||
            "type": "number",
 | 
			
		||||
          },
 | 
			
		||||
          "members": Object {
 | 
			
		||||
            "type": "number",
 | 
			
		||||
          },
 | 
			
		||||
          "name": Object {
 | 
			
		||||
            "type": "string",
 | 
			
		||||
          },
 | 
			
		||||
          "potentiallyStaleCount": Object {
 | 
			
		||||
            "type": "number",
 | 
			
		||||
          },
 | 
			
		||||
          "staleCount": Object {
 | 
			
		||||
            "type": "number",
 | 
			
		||||
          },
 | 
			
		||||
          "updatedAt": Object {
 | 
			
		||||
            "format": "date-time",
 | 
			
		||||
            "nullable": true,
 | 
			
		||||
            "type": "string",
 | 
			
		||||
          },
 | 
			
		||||
          "version": Object {
 | 
			
		||||
            "type": "number",
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
        "required": Array [
 | 
			
		||||
          "version",
 | 
			
		||||
          "name",
 | 
			
		||||
          "potentiallyStaleCount",
 | 
			
		||||
          "activeCount",
 | 
			
		||||
          "staleCount",
 | 
			
		||||
        ],
 | 
			
		||||
        "type": "object",
 | 
			
		||||
      },
 | 
			
		||||
      "overrideSchema": Object {
 | 
			
		||||
        "additionalProperties": false,
 | 
			
		||||
        "properties": Object {
 | 
			
		||||
@ -393,6 +512,74 @@ Object {
 | 
			
		||||
        },
 | 
			
		||||
        "type": "array",
 | 
			
		||||
      },
 | 
			
		||||
      "projectEnvironmentSchema": Object {
 | 
			
		||||
        "additionalProperties": false,
 | 
			
		||||
        "properties": Object {
 | 
			
		||||
          "environment": Object {
 | 
			
		||||
            "type": "string",
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
        "required": Array [
 | 
			
		||||
          "environment",
 | 
			
		||||
        ],
 | 
			
		||||
        "type": "object",
 | 
			
		||||
      },
 | 
			
		||||
      "projectSchema": Object {
 | 
			
		||||
        "additionalProperties": false,
 | 
			
		||||
        "properties": Object {
 | 
			
		||||
          "createdAt": Object {
 | 
			
		||||
            "format": "date-time",
 | 
			
		||||
            "type": "string",
 | 
			
		||||
          },
 | 
			
		||||
          "description": Object {
 | 
			
		||||
            "type": "string",
 | 
			
		||||
          },
 | 
			
		||||
          "featureCount": Object {
 | 
			
		||||
            "type": "number",
 | 
			
		||||
          },
 | 
			
		||||
          "health": Object {
 | 
			
		||||
            "type": "number",
 | 
			
		||||
          },
 | 
			
		||||
          "id": Object {
 | 
			
		||||
            "type": "string",
 | 
			
		||||
          },
 | 
			
		||||
          "memberCount": Object {
 | 
			
		||||
            "type": "number",
 | 
			
		||||
          },
 | 
			
		||||
          "name": Object {
 | 
			
		||||
            "type": "string",
 | 
			
		||||
          },
 | 
			
		||||
          "updatedAt": Object {
 | 
			
		||||
            "format": "date-time",
 | 
			
		||||
            "nullable": true,
 | 
			
		||||
            "type": "string",
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
        "required": Array [
 | 
			
		||||
          "id",
 | 
			
		||||
          "name",
 | 
			
		||||
        ],
 | 
			
		||||
        "type": "object",
 | 
			
		||||
      },
 | 
			
		||||
      "projectsSchema": Object {
 | 
			
		||||
        "additionalProperties": false,
 | 
			
		||||
        "properties": Object {
 | 
			
		||||
          "projects": Object {
 | 
			
		||||
            "items": Object {
 | 
			
		||||
              "$ref": "#/components/schemas/projectSchema",
 | 
			
		||||
            },
 | 
			
		||||
            "type": "array",
 | 
			
		||||
          },
 | 
			
		||||
          "version": Object {
 | 
			
		||||
            "type": "integer",
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
        "required": Array [
 | 
			
		||||
          "version",
 | 
			
		||||
          "projects",
 | 
			
		||||
        ],
 | 
			
		||||
        "type": "object",
 | 
			
		||||
      },
 | 
			
		||||
      "strategySchema": Object {
 | 
			
		||||
        "additionalProperties": false,
 | 
			
		||||
        "properties": Object {
 | 
			
		||||
@ -691,6 +878,7 @@ Object {
 | 
			
		||||
    "/api/admin/archive/features": Object {
 | 
			
		||||
      "get": Object {
 | 
			
		||||
        "deprecated": true,
 | 
			
		||||
        "operationId": "getArchivedFeatures",
 | 
			
		||||
        "responses": Object {
 | 
			
		||||
          "200": Object {
 | 
			
		||||
            "content": Object {
 | 
			
		||||
@ -711,6 +899,7 @@ Object {
 | 
			
		||||
    "/api/admin/archive/features/{projectId}": Object {
 | 
			
		||||
      "get": Object {
 | 
			
		||||
        "deprecated": true,
 | 
			
		||||
        "operationId": "getArchivedFeaturesByProjectId",
 | 
			
		||||
        "parameters": Array [
 | 
			
		||||
          Object {
 | 
			
		||||
            "in": "path",
 | 
			
		||||
@ -738,6 +927,66 @@ Object {
 | 
			
		||||
        ],
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
    "/api/admin/archive/revive/{featureName}": Object {
 | 
			
		||||
      "post": Object {
 | 
			
		||||
        "operationId": "reviveFeature",
 | 
			
		||||
        "parameters": Array [
 | 
			
		||||
          Object {
 | 
			
		||||
            "in": "path",
 | 
			
		||||
            "name": "featureName",
 | 
			
		||||
            "required": true,
 | 
			
		||||
            "schema": Object {
 | 
			
		||||
              "type": "string",
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
        ],
 | 
			
		||||
        "responses": Object {
 | 
			
		||||
          "200": Object {
 | 
			
		||||
            "content": Object {
 | 
			
		||||
              "application/json": Object {
 | 
			
		||||
                "schema": Object {
 | 
			
		||||
                  "$ref": "#/components/schemas/emptySchema",
 | 
			
		||||
                },
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
            "description": "emptySchema",
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
        "tags": Array [
 | 
			
		||||
          "admin",
 | 
			
		||||
        ],
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
    "/api/admin/archive/{featureName}": Object {
 | 
			
		||||
      "delete": Object {
 | 
			
		||||
        "operationId": "deleteFeature",
 | 
			
		||||
        "parameters": Array [
 | 
			
		||||
          Object {
 | 
			
		||||
            "in": "path",
 | 
			
		||||
            "name": "featureName",
 | 
			
		||||
            "required": true,
 | 
			
		||||
            "schema": Object {
 | 
			
		||||
              "type": "string",
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
        ],
 | 
			
		||||
        "responses": Object {
 | 
			
		||||
          "200": Object {
 | 
			
		||||
            "content": Object {
 | 
			
		||||
              "application/json": Object {
 | 
			
		||||
                "schema": Object {
 | 
			
		||||
                  "$ref": "#/components/schemas/emptySchema",
 | 
			
		||||
                },
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
            "description": "emptySchema",
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
        "tags": Array [
 | 
			
		||||
          "admin",
 | 
			
		||||
        ],
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
    "/api/admin/features": Object {
 | 
			
		||||
      "get": Object {
 | 
			
		||||
        "deprecated": true,
 | 
			
		||||
@ -894,6 +1143,135 @@ Object {
 | 
			
		||||
        ],
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
    "/api/admin/projects": Object {
 | 
			
		||||
      "get": Object {
 | 
			
		||||
        "operationId": "getProjects",
 | 
			
		||||
        "responses": Object {
 | 
			
		||||
          "200": Object {
 | 
			
		||||
            "content": Object {
 | 
			
		||||
              "application/json": Object {
 | 
			
		||||
                "schema": Object {
 | 
			
		||||
                  "$ref": "#/components/schemas/projectsSchema",
 | 
			
		||||
                },
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
            "description": "projectsSchema",
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
        "tags": Array [
 | 
			
		||||
          "admin",
 | 
			
		||||
        ],
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
    "/api/admin/projects/{projectId}": Object {
 | 
			
		||||
      "get": Object {
 | 
			
		||||
        "operationId": "getProjectHealthOverview",
 | 
			
		||||
        "parameters": Array [
 | 
			
		||||
          Object {
 | 
			
		||||
            "in": "path",
 | 
			
		||||
            "name": "projectId",
 | 
			
		||||
            "required": true,
 | 
			
		||||
            "schema": Object {
 | 
			
		||||
              "type": "string",
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
        ],
 | 
			
		||||
        "responses": Object {
 | 
			
		||||
          "200": Object {
 | 
			
		||||
            "content": Object {
 | 
			
		||||
              "application/json": Object {
 | 
			
		||||
                "schema": Object {
 | 
			
		||||
                  "$ref": "#/components/schemas/healthOverviewSchema",
 | 
			
		||||
                },
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
            "description": "healthOverviewSchema",
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
        "tags": Array [
 | 
			
		||||
          "admin",
 | 
			
		||||
        ],
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
    "/api/admin/projects/{projectId}/environments": Object {
 | 
			
		||||
      "post": Object {
 | 
			
		||||
        "operationId": "addEnvironmentToProject",
 | 
			
		||||
        "parameters": Array [
 | 
			
		||||
          Object {
 | 
			
		||||
            "in": "path",
 | 
			
		||||
            "name": "projectId",
 | 
			
		||||
            "required": true,
 | 
			
		||||
            "schema": Object {
 | 
			
		||||
              "type": "string",
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
        ],
 | 
			
		||||
        "requestBody": Object {
 | 
			
		||||
          "content": Object {
 | 
			
		||||
            "application/json": Object {
 | 
			
		||||
              "schema": Object {
 | 
			
		||||
                "$ref": "#/components/schemas/projectEnvironmentSchema",
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
          "description": "projectEnvironmentSchema",
 | 
			
		||||
          "required": true,
 | 
			
		||||
        },
 | 
			
		||||
        "responses": Object {
 | 
			
		||||
          "200": Object {
 | 
			
		||||
            "content": Object {
 | 
			
		||||
              "application/json": Object {
 | 
			
		||||
                "schema": Object {
 | 
			
		||||
                  "$ref": "#/components/schemas/emptySchema",
 | 
			
		||||
                },
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
            "description": "emptySchema",
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
        "tags": Array [
 | 
			
		||||
          "admin",
 | 
			
		||||
        ],
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
    "/api/admin/projects/{projectId}/environments/{environment}": Object {
 | 
			
		||||
      "delete": Object {
 | 
			
		||||
        "operationId": "removeEnvironmentFromProject",
 | 
			
		||||
        "parameters": Array [
 | 
			
		||||
          Object {
 | 
			
		||||
            "in": "path",
 | 
			
		||||
            "name": "projectId",
 | 
			
		||||
            "required": true,
 | 
			
		||||
            "schema": Object {
 | 
			
		||||
              "type": "string",
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
          Object {
 | 
			
		||||
            "in": "path",
 | 
			
		||||
            "name": "environment",
 | 
			
		||||
            "required": true,
 | 
			
		||||
            "schema": Object {
 | 
			
		||||
              "type": "string",
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
        ],
 | 
			
		||||
        "responses": Object {
 | 
			
		||||
          "200": Object {
 | 
			
		||||
            "content": Object {
 | 
			
		||||
              "application/json": Object {
 | 
			
		||||
                "schema": Object {
 | 
			
		||||
                  "$ref": "#/components/schemas/emptySchema",
 | 
			
		||||
                },
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
            "description": "emptySchema",
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
        "tags": Array [
 | 
			
		||||
          "admin",
 | 
			
		||||
        ],
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
    "/api/admin/projects/{projectId}/features": Object {
 | 
			
		||||
      "get": Object {
 | 
			
		||||
        "operationId": "getFeatures",
 | 
			
		||||
@ -1783,6 +2161,36 @@ Object {
 | 
			
		||||
        ],
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
    "/api/admin/projects/{projectId}/health-report": Object {
 | 
			
		||||
      "get": Object {
 | 
			
		||||
        "operationId": "getProjectHealthReport",
 | 
			
		||||
        "parameters": Array [
 | 
			
		||||
          Object {
 | 
			
		||||
            "in": "path",
 | 
			
		||||
            "name": "projectId",
 | 
			
		||||
            "required": true,
 | 
			
		||||
            "schema": Object {
 | 
			
		||||
              "type": "string",
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
        ],
 | 
			
		||||
        "responses": Object {
 | 
			
		||||
          "200": Object {
 | 
			
		||||
            "content": Object {
 | 
			
		||||
              "application/json": Object {
 | 
			
		||||
                "schema": Object {
 | 
			
		||||
                  "$ref": "#/components/schemas/healthReportSchema",
 | 
			
		||||
                },
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
            "description": "healthReportSchema",
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
        "tags": Array [
 | 
			
		||||
          "admin",
 | 
			
		||||
        ],
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
    "/api/admin/ui-config": Object {
 | 
			
		||||
      "get": Object {
 | 
			
		||||
        "operationId": "getUIConfig",
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user