mirror of
https://github.com/Unleash/unleash.git
synced 2025-01-25 00:07:47 +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,
|
id: row.id,
|
||||||
description: row.description,
|
description: row.description,
|
||||||
health: row.health,
|
health: row.health,
|
||||||
featureCount: row.number_of_features,
|
featureCount: Number(row.number_of_features) || 0,
|
||||||
memberCount: row.number_of_users || 0,
|
memberCount: Number(row.number_of_users) || 0,
|
||||||
updatedAt: row.updated_at,
|
updatedAt: row.updated_at,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -4,17 +4,23 @@ import { constraintSchema } from './spec/constraint-schema';
|
|||||||
import { createFeatureSchema } from './spec/create-feature-schema';
|
import { createFeatureSchema } from './spec/create-feature-schema';
|
||||||
import { createStrategySchema } from './spec/create-strategy-schema';
|
import { createStrategySchema } from './spec/create-strategy-schema';
|
||||||
import { emptySchema } from './spec/empty-schema';
|
import { emptySchema } from './spec/empty-schema';
|
||||||
|
import { environmentSchema } from './spec/environment-schema';
|
||||||
import { featureEnvironmentSchema } from './spec/feature-environment-schema';
|
import { featureEnvironmentSchema } from './spec/feature-environment-schema';
|
||||||
import { featureSchema } from './spec/feature-schema';
|
import { featureSchema } from './spec/feature-schema';
|
||||||
import { featureStrategySchema } from './spec/feature-strategy-schema';
|
import { featureStrategySchema } from './spec/feature-strategy-schema';
|
||||||
import { featureVariantsSchema } from './spec/feature-variants-schema';
|
import { featureVariantsSchema } from './spec/feature-variants-schema';
|
||||||
import { featuresSchema } from './spec/features-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 { mapValues } from '../util/map-values';
|
||||||
import { omitKeys } from '../util/omit-keys';
|
import { omitKeys } from '../util/omit-keys';
|
||||||
import { overrideSchema } from './spec/override-schema';
|
import { overrideSchema } from './spec/override-schema';
|
||||||
import { parametersSchema } from './spec/parameters-schema';
|
import { parametersSchema } from './spec/parameters-schema';
|
||||||
import { patchSchema } from './spec/patch-schema';
|
import { patchSchema } from './spec/patch-schema';
|
||||||
import { patchesSchema } from './spec/patches-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 { strategySchema } from './spec/strategy-schema';
|
||||||
import { tagSchema } from './spec/tag-schema';
|
import { tagSchema } from './spec/tag-schema';
|
||||||
import { tagsSchema } from './spec/tags-schema';
|
import { tagsSchema } from './spec/tags-schema';
|
||||||
@ -33,11 +39,13 @@ export type SchemaRef = typeof schemas[keyof typeof schemas]['components'];
|
|||||||
|
|
||||||
export interface AdminApiOperation
|
export interface AdminApiOperation
|
||||||
extends Omit<OpenAPIV3.OperationObject, 'tags'> {
|
extends Omit<OpenAPIV3.OperationObject, 'tags'> {
|
||||||
|
operationId: string;
|
||||||
tags: ['admin'];
|
tags: ['admin'];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ClientApiOperation
|
export interface ClientApiOperation
|
||||||
extends Omit<OpenAPIV3.OperationObject, 'tags'> {
|
extends Omit<OpenAPIV3.OperationObject, 'tags'> {
|
||||||
|
operationId: string;
|
||||||
tags: ['client'];
|
tags: ['client'];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,15 +55,21 @@ export const schemas = {
|
|||||||
createFeatureSchema,
|
createFeatureSchema,
|
||||||
createStrategySchema,
|
createStrategySchema,
|
||||||
emptySchema,
|
emptySchema,
|
||||||
|
environmentSchema,
|
||||||
featureEnvironmentSchema,
|
featureEnvironmentSchema,
|
||||||
featureSchema,
|
featureSchema,
|
||||||
featureStrategySchema,
|
featureStrategySchema,
|
||||||
featureVariantsSchema,
|
featureVariantsSchema,
|
||||||
featuresSchema,
|
featuresSchema,
|
||||||
|
healthOverviewSchema,
|
||||||
|
healthReportSchema,
|
||||||
overrideSchema,
|
overrideSchema,
|
||||||
parametersSchema,
|
parametersSchema,
|
||||||
patchSchema,
|
patchSchema,
|
||||||
patchesSchema,
|
patchesSchema,
|
||||||
|
projectEnvironmentSchema,
|
||||||
|
projectSchema,
|
||||||
|
projectsSchema,
|
||||||
strategySchema,
|
strategySchema,
|
||||||
tagSchema,
|
tagSchema,
|
||||||
tagsSchema,
|
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' },
|
payload: { type: 'a', value: 'b' },
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
environments: [
|
||||||
|
{
|
||||||
|
name: 'a',
|
||||||
|
type: 'b',
|
||||||
|
enabled: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
|
@ -4,6 +4,7 @@ import { strategySchema } from './strategy-schema';
|
|||||||
import { constraintSchema } from './constraint-schema';
|
import { constraintSchema } from './constraint-schema';
|
||||||
import { overrideSchema } from './override-schema';
|
import { overrideSchema } from './override-schema';
|
||||||
import { parametersSchema } from './parameters-schema';
|
import { parametersSchema } from './parameters-schema';
|
||||||
|
import { environmentSchema } from './environment-schema';
|
||||||
|
|
||||||
export const featureSchema = {
|
export const featureSchema = {
|
||||||
$id: '#/components/schemas/featureSchema',
|
$id: '#/components/schemas/featureSchema',
|
||||||
@ -48,7 +49,7 @@ export const featureSchema = {
|
|||||||
environments: {
|
environments: {
|
||||||
type: 'array',
|
type: 'array',
|
||||||
items: {
|
items: {
|
||||||
type: 'object',
|
$ref: '#/components/schemas/environmentSchema',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
strategies: {
|
strategies: {
|
||||||
@ -67,6 +68,7 @@ export const featureSchema = {
|
|||||||
components: {
|
components: {
|
||||||
schemas: {
|
schemas: {
|
||||||
constraintSchema,
|
constraintSchema,
|
||||||
|
environmentSchema,
|
||||||
overrideSchema,
|
overrideSchema,
|
||||||
parametersSchema,
|
parametersSchema,
|
||||||
strategySchema,
|
strategySchema,
|
||||||
|
@ -5,6 +5,7 @@ import { variantSchema } from './variant-schema';
|
|||||||
import { overrideSchema } from './override-schema';
|
import { overrideSchema } from './override-schema';
|
||||||
import { constraintSchema } from './constraint-schema';
|
import { constraintSchema } from './constraint-schema';
|
||||||
import { strategySchema } from './strategy-schema';
|
import { strategySchema } from './strategy-schema';
|
||||||
|
import { environmentSchema } from './environment-schema';
|
||||||
|
|
||||||
export const featuresSchema = {
|
export const featuresSchema = {
|
||||||
$id: '#/components/schemas/featuresSchema',
|
$id: '#/components/schemas/featuresSchema',
|
||||||
@ -25,6 +26,7 @@ export const featuresSchema = {
|
|||||||
components: {
|
components: {
|
||||||
schemas: {
|
schemas: {
|
||||||
constraintSchema,
|
constraintSchema,
|
||||||
|
environmentSchema,
|
||||||
featureSchema,
|
featureSchema,
|
||||||
overrideSchema,
|
overrideSchema,
|
||||||
parametersSchema,
|
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 { serializeDates } from '../../types/serialize-dates';
|
||||||
import { OpenApiService } from '../../services/openapi-service';
|
import { OpenApiService } from '../../services/openapi-service';
|
||||||
import { createResponseSchema } from '../../openapi';
|
import { createResponseSchema } from '../../openapi';
|
||||||
|
import { EmptySchema } from '../../openapi/spec/empty-schema';
|
||||||
|
|
||||||
export default class ArchiveController extends Controller {
|
export default class ArchiveController extends Controller {
|
||||||
private readonly logger: Logger;
|
private readonly logger: Logger;
|
||||||
@ -42,6 +43,7 @@ export default class ArchiveController extends Controller {
|
|||||||
middleware: [
|
middleware: [
|
||||||
openApiService.validPath({
|
openApiService.validPath({
|
||||||
tags: ['admin'],
|
tags: ['admin'],
|
||||||
|
operationId: 'getArchivedFeatures',
|
||||||
responses: { 200: createResponseSchema('featuresSchema') },
|
responses: { 200: createResponseSchema('featuresSchema') },
|
||||||
deprecated: true,
|
deprecated: true,
|
||||||
}),
|
}),
|
||||||
@ -56,18 +58,42 @@ export default class ArchiveController extends Controller {
|
|||||||
middleware: [
|
middleware: [
|
||||||
openApiService.validPath({
|
openApiService.validPath({
|
||||||
tags: ['admin'],
|
tags: ['admin'],
|
||||||
|
operationId: 'getArchivedFeaturesByProjectId',
|
||||||
responses: { 200: createResponseSchema('featuresSchema') },
|
responses: { 200: createResponseSchema('featuresSchema') },
|
||||||
deprecated: true,
|
deprecated: true,
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
this.delete('/:featureName', this.deleteFeature, DELETE_FEATURE);
|
this.route({
|
||||||
this.post(
|
method: 'delete',
|
||||||
'/revive/:featureName',
|
path: '/:featureName',
|
||||||
this.reviveFeatureToggle,
|
acceptAnyContentType: true,
|
||||||
UPDATE_FEATURE,
|
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(
|
async getArchivedFeatures(
|
||||||
@ -104,8 +130,8 @@ export default class ArchiveController extends Controller {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async deleteFeature(
|
async deleteFeature(
|
||||||
req: IAuthRequest<any, { featureName: string }, any, any>,
|
req: IAuthRequest<{ featureName: string }>,
|
||||||
res: Response,
|
res: Response<EmptySchema>,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const { featureName } = req.params;
|
const { featureName } = req.params;
|
||||||
const user = extractUsername(req);
|
const user = extractUsername(req);
|
||||||
@ -113,7 +139,10 @@ export default class ArchiveController extends Controller {
|
|||||||
res.status(200).end();
|
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 userName = extractUsername(req);
|
||||||
const { featureName } = req.params;
|
const { featureName } = req.params;
|
||||||
await this.featureService.reviveToggle(featureName, userName);
|
await this.featureService.reviveToggle(featureName, userName);
|
||||||
|
@ -5,7 +5,8 @@ import { IUnleashServices } from '../../../types/services';
|
|||||||
import { Logger } from '../../../logger';
|
import { Logger } from '../../../logger';
|
||||||
import EnvironmentService from '../../../services/environment-service';
|
import EnvironmentService from '../../../services/environment-service';
|
||||||
import { UPDATE_PROJECT } from '../../../types/permissions';
|
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';
|
const PREFIX = '/:projectId/environments';
|
||||||
|
|
||||||
@ -14,10 +15,6 @@ interface IProjectEnvironmentParams {
|
|||||||
environment: string;
|
environment: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface EnvironmentBody {
|
|
||||||
environment: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default class EnvironmentsController extends Controller {
|
export default class EnvironmentsController extends Controller {
|
||||||
private logger: Logger;
|
private logger: Logger;
|
||||||
|
|
||||||
@ -25,49 +22,79 @@ export default class EnvironmentsController extends Controller {
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
config: IUnleashConfig,
|
config: IUnleashConfig,
|
||||||
{ environmentService }: Pick<IUnleashServices, 'environmentService'>,
|
{
|
||||||
|
environmentService,
|
||||||
|
openApiService,
|
||||||
|
}: Pick<IUnleashServices, 'environmentService' | 'openApiService'>,
|
||||||
) {
|
) {
|
||||||
super(config);
|
super(config);
|
||||||
|
|
||||||
this.logger = config.getLogger('admin-api/project/environments.ts');
|
this.logger = config.getLogger('admin-api/project/environments.ts');
|
||||||
this.environmentService = environmentService;
|
this.environmentService = environmentService;
|
||||||
this.post(PREFIX, this.addEnvironmentToProject, UPDATE_PROJECT);
|
|
||||||
this.delete(
|
this.route({
|
||||||
`${PREFIX}/:environment`,
|
method: 'post',
|
||||||
this.removeEnvironmentFromProject,
|
path: PREFIX,
|
||||||
UPDATE_PROJECT,
|
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(
|
async addEnvironmentToProject(
|
||||||
req: Request<
|
req: Request<
|
||||||
Omit<IProjectEnvironmentParams, 'environment'>,
|
Omit<IProjectEnvironmentParams, 'environment'>,
|
||||||
any,
|
void,
|
||||||
EnvironmentBody,
|
ProjectEnvironmentSchema
|
||||||
any
|
|
||||||
>,
|
>,
|
||||||
res: Response,
|
res: Response,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const { projectId } = req.params;
|
const { projectId } = req.params;
|
||||||
|
const { environment } = req.body;
|
||||||
const { environment } = await addEnvironment.validateAsync(req.body);
|
|
||||||
|
|
||||||
await this.environmentService.addEnvironmentToProject(
|
await this.environmentService.addEnvironmentToProject(
|
||||||
environment,
|
environment,
|
||||||
projectId,
|
projectId,
|
||||||
);
|
);
|
||||||
|
|
||||||
res.status(200).end();
|
res.status(200).end();
|
||||||
}
|
}
|
||||||
|
|
||||||
async removeEnvironmentFromProject(
|
async removeEnvironmentFromProject(
|
||||||
req: Request<IProjectEnvironmentParams, any, any, any>,
|
req: Request<IProjectEnvironmentParams>,
|
||||||
res: Response,
|
res: Response<void>,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const { projectId, environment } = req.params;
|
const { projectId, environment } = req.params;
|
||||||
|
|
||||||
await this.environmentService.removeEnvironmentFromProject(
|
await this.environmentService.removeEnvironmentFromProject(
|
||||||
environment,
|
environment,
|
||||||
projectId,
|
projectId,
|
||||||
);
|
);
|
||||||
|
|
||||||
res.status(200).end();
|
res.status(200).end();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,28 +5,74 @@ import { IUnleashConfig } from '../../../types/option';
|
|||||||
import ProjectHealthService from '../../../services/project-health-service';
|
import ProjectHealthService from '../../../services/project-health-service';
|
||||||
import { Logger } from '../../../logger';
|
import { Logger } from '../../../logger';
|
||||||
import { IArchivedQuery, IProjectParam } from '../../../types/model';
|
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 {
|
export default class ProjectHealthReport extends Controller {
|
||||||
private projectHealthService: ProjectHealthService;
|
private projectHealthService: ProjectHealthService;
|
||||||
|
|
||||||
|
private openApiService: OpenApiService;
|
||||||
|
|
||||||
private logger: Logger;
|
private logger: Logger;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
config: IUnleashConfig,
|
config: IUnleashConfig,
|
||||||
{
|
{
|
||||||
projectHealthService,
|
projectHealthService,
|
||||||
}: Pick<IUnleashServices, 'projectHealthService'>,
|
openApiService,
|
||||||
|
}: Pick<IUnleashServices, 'projectHealthService' | 'openApiService'>,
|
||||||
) {
|
) {
|
||||||
super(config);
|
super(config);
|
||||||
this.logger = config.getLogger('/admin-api/project/health-report');
|
this.logger = config.getLogger('/admin-api/project/health-report');
|
||||||
this.projectHealthService = projectHealthService;
|
this.projectHealthService = projectHealthService;
|
||||||
this.get('/:projectId', this.getProjectOverview);
|
this.openApiService = openApiService;
|
||||||
this.get('/:projectId/health-report', this.getProjectHealthReport);
|
|
||||||
|
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(
|
async getProjectHealthOverview(
|
||||||
req: Request<IProjectParam, any, any, IArchivedQuery>,
|
req: Request<IProjectParam, unknown, unknown, IArchivedQuery>,
|
||||||
res: Response,
|
res: Response<HealthOverviewSchema>,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const { projectId } = req.params;
|
const { projectId } = req.params;
|
||||||
const { archived } = req.query;
|
const { archived } = req.query;
|
||||||
@ -34,20 +80,27 @@ export default class ProjectHealthReport extends Controller {
|
|||||||
projectId,
|
projectId,
|
||||||
archived,
|
archived,
|
||||||
);
|
);
|
||||||
res.json(overview);
|
this.openApiService.respondWithValidation(
|
||||||
|
200,
|
||||||
|
res,
|
||||||
|
healthOverviewSchema.$id,
|
||||||
|
serializeDates(overview),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getProjectHealthReport(
|
async getProjectHealthReport(
|
||||||
req: Request<IProjectParam, any, any, any>,
|
req: Request<IProjectParam>,
|
||||||
res: Response,
|
res: Response<HealthReportSchema>,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const { projectId } = req.params;
|
const { projectId } = req.params;
|
||||||
const overview = await this.projectHealthService.getProjectHealthReport(
|
const overview = await this.projectHealthService.getProjectHealthReport(
|
||||||
projectId,
|
projectId,
|
||||||
);
|
);
|
||||||
res.json({
|
this.openApiService.respondWithValidation(
|
||||||
version: 2,
|
200,
|
||||||
...overview,
|
res,
|
||||||
});
|
healthReportSchema.$id,
|
||||||
|
serializeDates(overview),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,24 +7,62 @@ import EnvironmentsController from './environments';
|
|||||||
import ProjectHealthReport from './health-report';
|
import ProjectHealthReport from './health-report';
|
||||||
import ProjectService from '../../../services/project-service';
|
import ProjectService from '../../../services/project-service';
|
||||||
import VariantsController from './variants';
|
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 {
|
export default class ProjectApi extends Controller {
|
||||||
private projectService: ProjectService;
|
private projectService: ProjectService;
|
||||||
|
|
||||||
|
private openApiService: OpenApiService;
|
||||||
|
|
||||||
constructor(config: IUnleashConfig, services: IUnleashServices) {
|
constructor(config: IUnleashConfig, services: IUnleashServices) {
|
||||||
super(config);
|
super(config);
|
||||||
this.projectService = services.projectService;
|
this.projectService = services.projectService;
|
||||||
|
this.openApiService = services.openApiService;
|
||||||
|
|
||||||
this.get('/', this.getProjects);
|
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 ProjectFeaturesController(config, services).router);
|
||||||
this.use('/', new EnvironmentsController(config, services).router);
|
this.use('/', new EnvironmentsController(config, services).router);
|
||||||
this.use('/', new ProjectHealthReport(config, services).router);
|
this.use('/', new ProjectHealthReport(config, services).router);
|
||||||
this.use('/', new VariantsController(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({
|
const projects = await this.projectService.getProjects({
|
||||||
id: 'default',
|
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);
|
const errors = validateSchema(schema, data);
|
||||||
|
|
||||||
if (errors) {
|
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);
|
res.status(status).json(data);
|
||||||
|
@ -160,6 +160,29 @@ Object {
|
|||||||
"emptySchema": Object {
|
"emptySchema": Object {
|
||||||
"description": "emptySchema",
|
"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 {
|
"featureEnvironmentSchema": Object {
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"properties": Object {
|
"properties": Object {
|
||||||
@ -207,7 +230,7 @@ Object {
|
|||||||
},
|
},
|
||||||
"environments": Object {
|
"environments": Object {
|
||||||
"items": Object {
|
"items": Object {
|
||||||
"type": "object",
|
"$ref": "#/components/schemas/environmentSchema",
|
||||||
},
|
},
|
||||||
"type": "array",
|
"type": "array",
|
||||||
},
|
},
|
||||||
@ -336,6 +359,102 @@ Object {
|
|||||||
],
|
],
|
||||||
"type": "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 {
|
"overrideSchema": Object {
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"properties": Object {
|
"properties": Object {
|
||||||
@ -393,6 +512,74 @@ Object {
|
|||||||
},
|
},
|
||||||
"type": "array",
|
"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 {
|
"strategySchema": Object {
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"properties": Object {
|
"properties": Object {
|
||||||
@ -691,6 +878,7 @@ Object {
|
|||||||
"/api/admin/archive/features": Object {
|
"/api/admin/archive/features": Object {
|
||||||
"get": Object {
|
"get": Object {
|
||||||
"deprecated": true,
|
"deprecated": true,
|
||||||
|
"operationId": "getArchivedFeatures",
|
||||||
"responses": Object {
|
"responses": Object {
|
||||||
"200": Object {
|
"200": Object {
|
||||||
"content": Object {
|
"content": Object {
|
||||||
@ -711,6 +899,7 @@ Object {
|
|||||||
"/api/admin/archive/features/{projectId}": Object {
|
"/api/admin/archive/features/{projectId}": Object {
|
||||||
"get": Object {
|
"get": Object {
|
||||||
"deprecated": true,
|
"deprecated": true,
|
||||||
|
"operationId": "getArchivedFeaturesByProjectId",
|
||||||
"parameters": Array [
|
"parameters": Array [
|
||||||
Object {
|
Object {
|
||||||
"in": "path",
|
"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 {
|
"/api/admin/features": Object {
|
||||||
"get": Object {
|
"get": Object {
|
||||||
"deprecated": true,
|
"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 {
|
"/api/admin/projects/{projectId}/features": Object {
|
||||||
"get": Object {
|
"get": Object {
|
||||||
"operationId": "getFeatures",
|
"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 {
|
"/api/admin/ui-config": Object {
|
||||||
"get": Object {
|
"get": Object {
|
||||||
"operationId": "getUIConfig",
|
"operationId": "getUIConfig",
|
||||||
|
Loading…
Reference in New Issue
Block a user