mirror of
https://github.com/Unleash/unleash.git
synced 2025-02-04 00:18:01 +01:00
Feat: OpenAPI controller - Bootstrap UI (#1773)
* rename bootstrap ui controller * sort openapi schema imports * add bootstrap ui json schema * test bootstrap ui schema * openapi bootstrap ui route * fix: bootstrap ui schema type * bootstrap ui e2e test * simplify bootstrap-ui testing mock * fix: update after review
This commit is contained in:
parent
a607dea284
commit
2729999bed
@ -1,118 +1,120 @@
|
|||||||
import { OpenAPIV3 } from 'openapi-types';
|
import { OpenAPIV3 } from 'openapi-types';
|
||||||
|
import { addonParameterSchema } from './spec/addon-parameter-schema';
|
||||||
|
import { addonSchema } from './spec/addon-schema';
|
||||||
|
import { addonsSchema } from './spec/addons-schema';
|
||||||
|
import { addonTypeSchema } from './spec/addon-type-schema';
|
||||||
import { apiTokenSchema } from './spec/api-token-schema';
|
import { apiTokenSchema } from './spec/api-token-schema';
|
||||||
import { apiTokensSchema } from './spec/api-tokens-schema';
|
import { apiTokensSchema } from './spec/api-tokens-schema';
|
||||||
|
import { applicationSchema } from './spec/application-schema';
|
||||||
|
import { applicationsSchema } from './spec/applications-schema';
|
||||||
|
import { bootstrapUiSchema } from './spec/bootstrap-ui-schema';
|
||||||
|
import { changePasswordSchema } from './spec/change-password-schema';
|
||||||
|
import { clientApplicationSchema } from './spec/client-application-schema';
|
||||||
|
import { clientFeatureSchema } from './spec/client-feature-schema';
|
||||||
|
import { clientFeaturesQuerySchema } from './spec/client-features-query-schema';
|
||||||
|
import { clientFeaturesSchema } from './spec/client-features-schema';
|
||||||
|
import { clientMetricsSchema } from './spec/client-metrics-schema';
|
||||||
|
import { clientVariantSchema } from './spec/client-variant-schema';
|
||||||
import { cloneFeatureSchema } from './spec/clone-feature-schema';
|
import { cloneFeatureSchema } from './spec/clone-feature-schema';
|
||||||
import { constraintSchema } from './spec/constraint-schema';
|
import { constraintSchema } from './spec/constraint-schema';
|
||||||
import { contextFieldSchema } from './spec/context-field-schema';
|
import { contextFieldSchema } from './spec/context-field-schema';
|
||||||
import { contextFieldsSchema } from './spec/context-fields-schema';
|
import { contextFieldsSchema } from './spec/context-fields-schema';
|
||||||
import { createApiTokenSchema } from './spec/create-api-token-schema';
|
import { createApiTokenSchema } from './spec/create-api-token-schema';
|
||||||
import { createFeatureSchema } from './spec/create-feature-schema';
|
import { createFeatureSchema } from './spec/create-feature-schema';
|
||||||
import { createUserSchema } from './spec/create-user-schema';
|
|
||||||
import { createFeatureStrategySchema } from './spec/create-feature-strategy-schema';
|
import { createFeatureStrategySchema } from './spec/create-feature-strategy-schema';
|
||||||
|
import { createUserSchema } from './spec/create-user-schema';
|
||||||
|
import { dateSchema } from './spec/date-schema';
|
||||||
|
import { emailSchema } from './spec/email-schema';
|
||||||
import { environmentSchema } from './spec/environment-schema';
|
import { environmentSchema } from './spec/environment-schema';
|
||||||
import { environmentsSchema } from './spec/environments-schema';
|
import { environmentsSchema } from './spec/environments-schema';
|
||||||
|
import { eventSchema } from './spec/event-schema';
|
||||||
|
import { eventsSchema } from './spec/events-schema';
|
||||||
|
import { exportParametersSchema } from './spec/export-parameters-schema';
|
||||||
|
import { featureEnvironmentMetricsSchema } from './spec/feature-environment-metrics-schema';
|
||||||
import { featureEnvironmentSchema } from './spec/feature-environment-schema';
|
import { featureEnvironmentSchema } from './spec/feature-environment-schema';
|
||||||
|
import { featureEventsSchema } from './spec/feature-events-schema';
|
||||||
|
import { featureMetricsSchema } from './spec/feature-metrics-schema';
|
||||||
import { featureSchema } from './spec/feature-schema';
|
import { featureSchema } from './spec/feature-schema';
|
||||||
|
import { featuresSchema } from './spec/features-schema';
|
||||||
import { featureStrategySchema } from './spec/feature-strategy-schema';
|
import { featureStrategySchema } from './spec/feature-strategy-schema';
|
||||||
|
import { featureStrategySegmentSchema } from './spec/feature-strategy-segment-schema';
|
||||||
|
import { featureTagSchema } from './spec/feature-tag-schema';
|
||||||
import { featureTypeSchema } from './spec/feature-type-schema';
|
import { featureTypeSchema } from './spec/feature-type-schema';
|
||||||
import { featureTypesSchema } from './spec/feature-types-schema';
|
import { featureTypesSchema } from './spec/feature-types-schema';
|
||||||
|
import { featureUsageSchema } from './spec/feature-usage-schema';
|
||||||
import { featureVariantsSchema } from './spec/feature-variants-schema';
|
import { featureVariantsSchema } from './spec/feature-variants-schema';
|
||||||
import { featuresSchema } from './spec/features-schema';
|
|
||||||
import { feedbackSchema } from './spec/feedback-schema';
|
import { feedbackSchema } from './spec/feedback-schema';
|
||||||
import { healthCheckSchema } from './spec/health-check-schema';
|
import { healthCheckSchema } from './spec/health-check-schema';
|
||||||
import { healthOverviewSchema } from './spec/health-overview-schema';
|
import { healthOverviewSchema } from './spec/health-overview-schema';
|
||||||
import { healthReportSchema } from './spec/health-report-schema';
|
import { healthReportSchema } from './spec/health-report-schema';
|
||||||
|
import { idSchema } from './spec/id-schema';
|
||||||
import { legalValueSchema } from './spec/legal-value-schema';
|
import { legalValueSchema } from './spec/legal-value-schema';
|
||||||
import { loginSchema } from './spec/login-schema';
|
import { loginSchema } from './spec/login-schema';
|
||||||
import { idSchema } from './spec/id-schema';
|
|
||||||
import { mapValues } from '../util/map-values';
|
import { mapValues } from '../util/map-values';
|
||||||
import { nameSchema } from './spec/name-schema';
|
|
||||||
import { meSchema } from './spec/me-schema';
|
import { meSchema } from './spec/me-schema';
|
||||||
|
import { nameSchema } from './spec/name-schema';
|
||||||
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 { passwordSchema } from './spec/password-schema';
|
import { passwordSchema } from './spec/password-schema';
|
||||||
import { patchSchema } from './spec/patch-schema';
|
|
||||||
import { patchesSchema } from './spec/patches-schema';
|
import { patchesSchema } from './spec/patches-schema';
|
||||||
|
import { patchSchema } from './spec/patch-schema';
|
||||||
import { permissionSchema } from './spec/permission-schema';
|
import { permissionSchema } from './spec/permission-schema';
|
||||||
import { projectEnvironmentSchema } from './spec/project-environment-schema';
|
import { projectEnvironmentSchema } from './spec/project-environment-schema';
|
||||||
import { projectSchema } from './spec/project-schema';
|
import { projectSchema } from './spec/project-schema';
|
||||||
import { projectsSchema } from './spec/projects-schema';
|
import { projectsSchema } from './spec/projects-schema';
|
||||||
|
import { resetPasswordSchema } from './spec/reset-password-schema';
|
||||||
import { roleSchema } from './spec/role-schema';
|
import { roleSchema } from './spec/role-schema';
|
||||||
|
import { segmentSchema } from './spec/segment-schema';
|
||||||
import { sortOrderSchema } from './spec/sort-order-schema';
|
import { sortOrderSchema } from './spec/sort-order-schema';
|
||||||
import { splashSchema } from './spec/splash-schema';
|
import { splashSchema } from './spec/splash-schema';
|
||||||
|
import { stateSchema } from './spec/state-schema';
|
||||||
|
import { strategiesSchema } from './spec/strategies-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';
|
||||||
import { tagTypeSchema } from './spec/tag-type-schema';
|
import { tagTypeSchema } from './spec/tag-type-schema';
|
||||||
import { tagTypesSchema } from './spec/tag-types-schema';
|
import { tagTypesSchema } from './spec/tag-types-schema';
|
||||||
|
import { tagWithVersionSchema } from './spec/tag-with-version-schema';
|
||||||
|
import { tokenUserSchema } from './spec/token-user-schema';
|
||||||
import { uiConfigSchema } from './spec/ui-config-schema';
|
import { uiConfigSchema } from './spec/ui-config-schema';
|
||||||
|
import { updateApiTokenSchema } from './spec/update-api-token-schema';
|
||||||
import { updateFeatureSchema } from './spec/update-feature-schema';
|
import { updateFeatureSchema } from './spec/update-feature-schema';
|
||||||
import { updateFeatureStrategySchema } from './spec/update-feature-strategy-schema';
|
import { updateFeatureStrategySchema } from './spec/update-feature-strategy-schema';
|
||||||
import { updateApiTokenSchema } from './spec/update-api-token-schema';
|
|
||||||
import { updateTagTypeSchema } from './spec/update-tag-type-schema';
|
import { updateTagTypeSchema } from './spec/update-tag-type-schema';
|
||||||
import { upsertContextFieldSchema } from './spec/upsert-context-field-schema';
|
|
||||||
import { updateUserSchema } from './spec/update-user-schema';
|
import { updateUserSchema } from './spec/update-user-schema';
|
||||||
|
import { upsertContextFieldSchema } from './spec/upsert-context-field-schema';
|
||||||
|
import { upsertStrategySchema } from './spec/upsert-strategy-schema';
|
||||||
import { userSchema } from './spec/user-schema';
|
import { userSchema } from './spec/user-schema';
|
||||||
import { usersSchema } from './spec/users-schema';
|
import { usersSchema } from './spec/users-schema';
|
||||||
import { usersSearchSchema } from './spec/users-search-schema';
|
import { usersSearchSchema } from './spec/users-search-schema';
|
||||||
|
import { validatePasswordSchema } from './spec/validate-password-schema';
|
||||||
import { validateTagTypeSchema } from './spec/validate-tag-type-schema';
|
import { validateTagTypeSchema } from './spec/validate-tag-type-schema';
|
||||||
import { variantSchema } from './spec/variant-schema';
|
import { variantSchema } from './spec/variant-schema';
|
||||||
import { variantsSchema } from './spec/variants-schema';
|
import { variantsSchema } from './spec/variants-schema';
|
||||||
import { versionSchema } from './spec/version-schema';
|
import { versionSchema } from './spec/version-schema';
|
||||||
import { featureEnvironmentMetricsSchema } from './spec/feature-environment-metrics-schema';
|
|
||||||
import { featureUsageSchema } from './spec/feature-usage-schema';
|
|
||||||
import { featureMetricsSchema } from './spec/feature-metrics-schema';
|
|
||||||
import { addonSchema } from './spec/addon-schema';
|
|
||||||
import { addonsSchema } from './spec/addons-schema';
|
|
||||||
import { addonParameterSchema } from './spec/addon-parameter-schema';
|
|
||||||
import { addonTypeSchema } from './spec/addon-type-schema';
|
|
||||||
import { applicationSchema } from './spec/application-schema';
|
|
||||||
import { applicationsSchema } from './spec/applications-schema';
|
|
||||||
import { tagWithVersionSchema } from './spec/tag-with-version-schema';
|
|
||||||
import { tokenUserSchema } from './spec/token-user-schema';
|
|
||||||
import { changePasswordSchema } from './spec/change-password-schema';
|
|
||||||
import { validatePasswordSchema } from './spec/validate-password-schema';
|
|
||||||
import { resetPasswordSchema } from './spec/reset-password-schema';
|
|
||||||
import { featureStrategySegmentSchema } from './spec/feature-strategy-segment-schema';
|
|
||||||
import { segmentSchema } from './spec/segment-schema';
|
|
||||||
import { stateSchema } from './spec/state-schema';
|
|
||||||
import { featureTagSchema } from './spec/feature-tag-schema';
|
|
||||||
import { exportParametersSchema } from './spec/export-parameters-schema';
|
|
||||||
import { emailSchema } from './spec/email-schema';
|
|
||||||
import { strategySchema } from './spec/strategy-schema';
|
|
||||||
import { strategiesSchema } from './spec/strategies-schema';
|
|
||||||
import { upsertStrategySchema } from './spec/upsert-strategy-schema';
|
|
||||||
import { clientFeaturesQuerySchema } from './spec/client-features-query-schema';
|
|
||||||
import { clientFeatureSchema } from './spec/client-feature-schema';
|
|
||||||
import { clientFeaturesSchema } from './spec/client-features-schema';
|
|
||||||
import { eventSchema } from './spec/event-schema';
|
|
||||||
import { eventsSchema } from './spec/events-schema';
|
|
||||||
import { featureEventsSchema } from './spec/feature-events-schema';
|
|
||||||
import { clientApplicationSchema } from './spec/client-application-schema';
|
|
||||||
import { clientMetricsSchema } from './spec/client-metrics-schema';
|
|
||||||
import { dateSchema } from './spec/date-schema';
|
|
||||||
import { clientVariantSchema } from './spec/client-variant-schema';
|
|
||||||
import { IServerOption } from '../types';
|
import { IServerOption } from '../types';
|
||||||
import { URL } from 'url';
|
import { URL } from 'url';
|
||||||
|
|
||||||
// All schemas in `openapi/spec` should be listed here.
|
// All schemas in `openapi/spec` should be listed here.
|
||||||
export const schemas = {
|
export const schemas = {
|
||||||
|
addonParameterSchema,
|
||||||
addonSchema,
|
addonSchema,
|
||||||
addonsSchema,
|
addonsSchema,
|
||||||
addonTypeSchema,
|
addonTypeSchema,
|
||||||
addonParameterSchema,
|
|
||||||
apiTokenSchema,
|
apiTokenSchema,
|
||||||
apiTokensSchema,
|
apiTokensSchema,
|
||||||
applicationSchema,
|
applicationSchema,
|
||||||
applicationsSchema,
|
applicationsSchema,
|
||||||
clientApplicationSchema,
|
bootstrapUiSchema,
|
||||||
clientMetricsSchema,
|
|
||||||
cloneFeatureSchema,
|
|
||||||
clientFeatureSchema,
|
|
||||||
clientFeaturesSchema,
|
|
||||||
clientVariantSchema,
|
|
||||||
clientFeaturesQuerySchema,
|
|
||||||
changePasswordSchema,
|
changePasswordSchema,
|
||||||
|
clientApplicationSchema,
|
||||||
|
clientFeatureSchema,
|
||||||
|
clientFeaturesQuerySchema,
|
||||||
|
clientFeaturesSchema,
|
||||||
|
clientMetricsSchema,
|
||||||
|
clientVariantSchema,
|
||||||
|
cloneFeatureSchema,
|
||||||
constraintSchema,
|
constraintSchema,
|
||||||
contextFieldSchema,
|
contextFieldSchema,
|
||||||
contextFieldsSchema,
|
contextFieldsSchema,
|
||||||
@ -127,33 +129,33 @@ export const schemas = {
|
|||||||
eventSchema,
|
eventSchema,
|
||||||
eventsSchema,
|
eventsSchema,
|
||||||
exportParametersSchema,
|
exportParametersSchema,
|
||||||
featureEnvironmentSchema,
|
|
||||||
featureEnvironmentMetricsSchema,
|
featureEnvironmentMetricsSchema,
|
||||||
|
featureEnvironmentSchema,
|
||||||
featureEventsSchema,
|
featureEventsSchema,
|
||||||
featureSchema,
|
|
||||||
featureMetricsSchema,
|
featureMetricsSchema,
|
||||||
featureUsageSchema,
|
featureSchema,
|
||||||
|
featuresSchema,
|
||||||
featureStrategySchema,
|
featureStrategySchema,
|
||||||
featureStrategySegmentSchema,
|
featureStrategySegmentSchema,
|
||||||
featureTagSchema,
|
featureTagSchema,
|
||||||
featureTypeSchema,
|
featureTypeSchema,
|
||||||
featureTypesSchema,
|
featureTypesSchema,
|
||||||
|
featureUsageSchema,
|
||||||
featureVariantsSchema,
|
featureVariantsSchema,
|
||||||
featuresSchema,
|
|
||||||
feedbackSchema,
|
feedbackSchema,
|
||||||
healthCheckSchema,
|
healthCheckSchema,
|
||||||
healthOverviewSchema,
|
healthOverviewSchema,
|
||||||
healthReportSchema,
|
healthReportSchema,
|
||||||
|
idSchema,
|
||||||
legalValueSchema,
|
legalValueSchema,
|
||||||
loginSchema,
|
loginSchema,
|
||||||
nameSchema,
|
|
||||||
idSchema,
|
|
||||||
meSchema,
|
meSchema,
|
||||||
|
nameSchema,
|
||||||
overrideSchema,
|
overrideSchema,
|
||||||
parametersSchema,
|
parametersSchema,
|
||||||
passwordSchema,
|
passwordSchema,
|
||||||
patchSchema,
|
|
||||||
patchesSchema,
|
patchesSchema,
|
||||||
|
patchSchema,
|
||||||
permissionSchema,
|
permissionSchema,
|
||||||
projectEnvironmentSchema,
|
projectEnvironmentSchema,
|
||||||
projectSchema,
|
projectSchema,
|
||||||
@ -167,24 +169,24 @@ export const schemas = {
|
|||||||
strategiesSchema,
|
strategiesSchema,
|
||||||
strategySchema,
|
strategySchema,
|
||||||
tagSchema,
|
tagSchema,
|
||||||
tagWithVersionSchema,
|
|
||||||
tagsSchema,
|
tagsSchema,
|
||||||
tagTypeSchema,
|
tagTypeSchema,
|
||||||
tagTypesSchema,
|
tagTypesSchema,
|
||||||
|
tagWithVersionSchema,
|
||||||
tokenUserSchema,
|
tokenUserSchema,
|
||||||
uiConfigSchema,
|
uiConfigSchema,
|
||||||
|
updateApiTokenSchema,
|
||||||
updateFeatureSchema,
|
updateFeatureSchema,
|
||||||
updateFeatureStrategySchema,
|
updateFeatureStrategySchema,
|
||||||
updateApiTokenSchema,
|
|
||||||
updateTagTypeSchema,
|
updateTagTypeSchema,
|
||||||
|
updateUserSchema,
|
||||||
upsertContextFieldSchema,
|
upsertContextFieldSchema,
|
||||||
upsertStrategySchema,
|
upsertStrategySchema,
|
||||||
validatePasswordSchema,
|
|
||||||
validateTagTypeSchema,
|
|
||||||
updateUserSchema,
|
|
||||||
userSchema,
|
userSchema,
|
||||||
usersSchema,
|
usersSchema,
|
||||||
usersSearchSchema,
|
usersSearchSchema,
|
||||||
|
validatePasswordSchema,
|
||||||
|
validateTagTypeSchema,
|
||||||
variantSchema,
|
variantSchema,
|
||||||
variantsSchema,
|
variantsSchema,
|
||||||
versionSchema,
|
versionSchema,
|
||||||
|
157
src/lib/openapi/spec/bootstrap-ui-schema.test.ts
Normal file
157
src/lib/openapi/spec/bootstrap-ui-schema.test.ts
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
import { validateSchema } from '../validate';
|
||||||
|
import { BootstrapUiSchema } from './bootstrap-ui-schema';
|
||||||
|
|
||||||
|
test('bootstrapUiSchema', () => {
|
||||||
|
const data: BootstrapUiSchema = {
|
||||||
|
uiConfig: {
|
||||||
|
flags: { E: true },
|
||||||
|
authenticationType: 'open-source',
|
||||||
|
unleashUrl: 'http://localhost:4242',
|
||||||
|
version: '4.14.0-beta.0',
|
||||||
|
baseUriPath: '',
|
||||||
|
versionInfo: {
|
||||||
|
current: { oss: '4.14.0-beta.0', enterprise: '' },
|
||||||
|
latest: {},
|
||||||
|
isLatest: true,
|
||||||
|
instanceId: '51c9190a-4ff5-4f47-b73a-7aebe06f9331',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
isAPI: false,
|
||||||
|
id: 1,
|
||||||
|
username: 'admin',
|
||||||
|
imageUrl:
|
||||||
|
'https://gravatar.com/avatar/21232f297a57a5a743894a0e4a801fc3?size=42&default=retro',
|
||||||
|
seenAt: '2022-06-27T12:19:15.838Z',
|
||||||
|
loginAttempts: 0,
|
||||||
|
createdAt: '2022-04-08T10:59:25.072Z',
|
||||||
|
permissions: [
|
||||||
|
{ permission: 'READ_API_TOKEN' },
|
||||||
|
{
|
||||||
|
project: 'default',
|
||||||
|
environment: 'staging',
|
||||||
|
permission: 'CREATE_FEATURE_STRATEGY',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
project: 'default',
|
||||||
|
environment: 'staging',
|
||||||
|
permission: 'UPDATE_FEATURE_STRATEGY',
|
||||||
|
},
|
||||||
|
{ project: 'default', permission: 'UPDATE_FEATURE' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
email: false,
|
||||||
|
context: [
|
||||||
|
{
|
||||||
|
name: 'appName',
|
||||||
|
description: 'Allows you to constrain on application name',
|
||||||
|
stickiness: false,
|
||||||
|
sortOrder: 2,
|
||||||
|
legalValues: [],
|
||||||
|
createdAt: '2022-04-08T10:59:24.374Z',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'currentTime',
|
||||||
|
description: '',
|
||||||
|
stickiness: false,
|
||||||
|
sortOrder: 10,
|
||||||
|
legalValues: [],
|
||||||
|
createdAt: '2022-05-18T08:15:18.917Z',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'environment',
|
||||||
|
description:
|
||||||
|
'Allows you to constrain on application environment',
|
||||||
|
stickiness: false,
|
||||||
|
sortOrder: 0,
|
||||||
|
legalValues: [],
|
||||||
|
createdAt: '2022-04-08T10:59:24.374Z',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'userId',
|
||||||
|
description: 'Allows you to constrain on userId',
|
||||||
|
stickiness: false,
|
||||||
|
sortOrder: 1,
|
||||||
|
legalValues: [],
|
||||||
|
createdAt: '2022-04-08T10:59:24.374Z',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
featureTypes: [
|
||||||
|
{
|
||||||
|
id: 'release',
|
||||||
|
name: 'Release',
|
||||||
|
description:
|
||||||
|
'Release feature toggles are used to release new features.',
|
||||||
|
lifetimeDays: 40,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'experiment',
|
||||||
|
name: 'Experiment',
|
||||||
|
description:
|
||||||
|
'Experiment feature toggles are used to test and verify multiple different versions of a feature.',
|
||||||
|
lifetimeDays: 40,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'operational',
|
||||||
|
name: 'Operational',
|
||||||
|
description:
|
||||||
|
'Operational feature toggles are used to control aspects of a rollout.',
|
||||||
|
lifetimeDays: 7,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
tagTypes: [
|
||||||
|
{
|
||||||
|
name: 'simple',
|
||||||
|
description: 'Used to simplify filtering of features',
|
||||||
|
icon: '#',
|
||||||
|
},
|
||||||
|
{ name: 'hashtag', description: '', icon: null },
|
||||||
|
],
|
||||||
|
strategies: [
|
||||||
|
{
|
||||||
|
displayName: 'Standard',
|
||||||
|
name: 'default',
|
||||||
|
editable: false,
|
||||||
|
description:
|
||||||
|
'The standard strategy is strictly on / off for your entire userbase.',
|
||||||
|
parameters: [],
|
||||||
|
deprecated: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: null,
|
||||||
|
name: 'gradualRolloutRandom',
|
||||||
|
editable: true,
|
||||||
|
description:
|
||||||
|
'Randomly activate the feature toggle. No stickiness.',
|
||||||
|
parameters: [
|
||||||
|
{
|
||||||
|
name: 'percentage',
|
||||||
|
type: 'percentage',
|
||||||
|
description: '',
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
deprecated: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
projects: [
|
||||||
|
{
|
||||||
|
name: 'Default',
|
||||||
|
id: 'default',
|
||||||
|
description: 'Default project',
|
||||||
|
health: 74,
|
||||||
|
featureCount: 10,
|
||||||
|
memberCount: 3,
|
||||||
|
updatedAt: '2022-06-28T17:33:53.963Z',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(
|
||||||
|
validateSchema('#/components/schemas/bootstrapUiSchema', {}),
|
||||||
|
).not.toBeUndefined();
|
||||||
|
|
||||||
|
expect(
|
||||||
|
validateSchema('#/components/schemas/bootstrapUiSchema', data),
|
||||||
|
).toBeUndefined();
|
||||||
|
});
|
94
src/lib/openapi/spec/bootstrap-ui-schema.ts
Normal file
94
src/lib/openapi/spec/bootstrap-ui-schema.ts
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
import { FromSchema } from 'json-schema-to-ts';
|
||||||
|
import { uiConfigSchema } from './ui-config-schema';
|
||||||
|
import { userSchema } from './user-schema';
|
||||||
|
import { permissionSchema } from './permission-schema';
|
||||||
|
import { featureTypeSchema } from './feature-type-schema';
|
||||||
|
import { tagTypeSchema } from './tag-type-schema';
|
||||||
|
import { contextFieldSchema } from './context-field-schema';
|
||||||
|
import { strategySchema } from './strategy-schema';
|
||||||
|
import { projectSchema } from './project-schema';
|
||||||
|
import { versionSchema } from './version-schema';
|
||||||
|
import { legalValueSchema } from './legal-value-schema';
|
||||||
|
|
||||||
|
export const bootstrapUiSchema = {
|
||||||
|
$id: '#/components/schemas/bootstrapUiSchema',
|
||||||
|
type: 'object',
|
||||||
|
additionalProperties: false,
|
||||||
|
required: [
|
||||||
|
'uiConfig',
|
||||||
|
'user',
|
||||||
|
'email',
|
||||||
|
'context',
|
||||||
|
'featureTypes',
|
||||||
|
'tagTypes',
|
||||||
|
'strategies',
|
||||||
|
'projects',
|
||||||
|
],
|
||||||
|
properties: {
|
||||||
|
uiConfig: {
|
||||||
|
$ref: '#/components/schemas/uiConfigSchema',
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
type: 'object',
|
||||||
|
required: [...userSchema.required],
|
||||||
|
properties: {
|
||||||
|
...userSchema.properties,
|
||||||
|
permissions: {
|
||||||
|
type: 'array',
|
||||||
|
items: {
|
||||||
|
$ref: '#/components/schemas/permissionSchema',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
email: {
|
||||||
|
type: 'boolean',
|
||||||
|
},
|
||||||
|
context: {
|
||||||
|
type: 'array',
|
||||||
|
items: {
|
||||||
|
$ref: '#/components/schemas/contextFieldSchema',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
featureTypes: {
|
||||||
|
type: 'array',
|
||||||
|
items: {
|
||||||
|
$ref: '#/components/schemas/featureTypeSchema',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
tagTypes: {
|
||||||
|
type: 'array',
|
||||||
|
items: {
|
||||||
|
$ref: '#/components/schemas/tagTypeSchema',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
strategies: {
|
||||||
|
type: 'array',
|
||||||
|
items: {
|
||||||
|
$ref: '#/components/schemas/strategySchema',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
projects: {
|
||||||
|
type: 'array',
|
||||||
|
items: {
|
||||||
|
$ref: '#/components/schemas/projectSchema',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
schemas: {
|
||||||
|
uiConfigSchema,
|
||||||
|
userSchema,
|
||||||
|
permissionSchema,
|
||||||
|
contextFieldSchema,
|
||||||
|
featureTypeSchema,
|
||||||
|
tagTypeSchema,
|
||||||
|
strategySchema,
|
||||||
|
projectSchema,
|
||||||
|
versionSchema,
|
||||||
|
legalValueSchema,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export type BootstrapUiSchema = FromSchema<typeof bootstrapUiSchema>;
|
@ -14,6 +14,7 @@ export const tagTypeSchema = {
|
|||||||
},
|
},
|
||||||
icon: {
|
icon: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
|
nullable: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
components: {},
|
components: {},
|
||||||
|
@ -5,15 +5,7 @@ export const uiConfigSchema = {
|
|||||||
$id: '#/components/schemas/uiConfigSchema',
|
$id: '#/components/schemas/uiConfigSchema',
|
||||||
type: 'object',
|
type: 'object',
|
||||||
additionalProperties: false,
|
additionalProperties: false,
|
||||||
required: [
|
required: ['version', 'unleashUrl', 'baseUriPath', 'versionInfo'],
|
||||||
'version',
|
|
||||||
'unleashUrl',
|
|
||||||
'baseUriPath',
|
|
||||||
'versionInfo',
|
|
||||||
'disablePasswordAuth',
|
|
||||||
'segmentValuesLimit',
|
|
||||||
'strategySegmentsLimit',
|
|
||||||
],
|
|
||||||
properties: {
|
properties: {
|
||||||
slogan: {
|
slogan: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
|
63
src/lib/routes/admin-api/bootstrap-ui.test.ts
Normal file
63
src/lib/routes/admin-api/bootstrap-ui.test.ts
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
import supertest from 'supertest';
|
||||||
|
import { createTestConfig } from '../../../test/config/test-config';
|
||||||
|
import { randomId } from '../../util/random-id';
|
||||||
|
|
||||||
|
import createStores from '../../../test/fixtures/store';
|
||||||
|
import getApp from '../../app';
|
||||||
|
import { createServices } from '../../services';
|
||||||
|
const uiConfig = {
|
||||||
|
headerBackground: 'red',
|
||||||
|
slogan: 'hello',
|
||||||
|
};
|
||||||
|
|
||||||
|
async function getSetup() {
|
||||||
|
const base = `/random${randomId()}`;
|
||||||
|
const config = createTestConfig({
|
||||||
|
server: { baseUriPath: base },
|
||||||
|
ui: uiConfig,
|
||||||
|
});
|
||||||
|
const stores = createStores();
|
||||||
|
const services = createServices(stores, config);
|
||||||
|
|
||||||
|
const app = await getApp(config, stores, services);
|
||||||
|
|
||||||
|
return {
|
||||||
|
base,
|
||||||
|
request: supertest(app),
|
||||||
|
destroy: () => {
|
||||||
|
services.versionService.destroy();
|
||||||
|
services.clientInstanceService.destroy();
|
||||||
|
services.apiTokenService.destroy();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
let request;
|
||||||
|
let base;
|
||||||
|
let destroy;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
const setup = await getSetup();
|
||||||
|
request = setup.request;
|
||||||
|
base = setup.base;
|
||||||
|
destroy = setup.destroy;
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
destroy();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should get ui config', async () => {
|
||||||
|
const { body } = await request
|
||||||
|
.get(`${base}/api/admin/ui-bootstrap`)
|
||||||
|
.expect('Content-Type', /json/)
|
||||||
|
.expect(200);
|
||||||
|
|
||||||
|
expect(body.uiConfig.slogan).toEqual('hello');
|
||||||
|
expect(body.email).toEqual(false);
|
||||||
|
expect(body.user).toHaveProperty('permissions');
|
||||||
|
expect(body.context).toBeInstanceOf(Array);
|
||||||
|
expect(body.tagTypes).toBeInstanceOf(Array);
|
||||||
|
expect(body.strategies).toBeInstanceOf(Array);
|
||||||
|
expect(body.projects).toBeInstanceOf(Array);
|
||||||
|
});
|
@ -19,8 +19,20 @@ import { ITagType } from '../../types/stores/tag-type-store';
|
|||||||
import { IStrategy } from '../../types/stores/strategy-store';
|
import { IStrategy } from '../../types/stores/strategy-store';
|
||||||
import { IProject } from '../../types/model';
|
import { IProject } from '../../types/model';
|
||||||
import { IUserPermission } from '../../types/stores/access-store';
|
import { IUserPermission } from '../../types/stores/access-store';
|
||||||
|
import { OpenApiService } from '../../services/openapi-service';
|
||||||
|
import { NONE } from '../../types/permissions';
|
||||||
|
import { createResponseSchema } from '../../openapi';
|
||||||
|
import {
|
||||||
|
BootstrapUiSchema,
|
||||||
|
bootstrapUiSchema,
|
||||||
|
} from '../../openapi/spec/bootstrap-ui-schema';
|
||||||
|
import { serializeDates } from '../../types/serialize-dates';
|
||||||
|
|
||||||
class BootstrapController extends Controller {
|
/**
|
||||||
|
* Provides admin UI configuration.
|
||||||
|
* Not to be confused with SDK bootstrapping.
|
||||||
|
*/
|
||||||
|
class BootstrapUIController extends Controller {
|
||||||
private logger: Logger;
|
private logger: Logger;
|
||||||
|
|
||||||
private accessService: AccessService;
|
private accessService: AccessService;
|
||||||
@ -39,6 +51,8 @@ class BootstrapController extends Controller {
|
|||||||
|
|
||||||
private versionService: VersionService;
|
private versionService: VersionService;
|
||||||
|
|
||||||
|
private openApiService: OpenApiService;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
config: IUnleashConfig,
|
config: IUnleashConfig,
|
||||||
{
|
{
|
||||||
@ -50,6 +64,7 @@ class BootstrapController extends Controller {
|
|||||||
emailService,
|
emailService,
|
||||||
versionService,
|
versionService,
|
||||||
featureTypeService,
|
featureTypeService,
|
||||||
|
openApiService,
|
||||||
}: Pick<
|
}: Pick<
|
||||||
IUnleashServices,
|
IUnleashServices,
|
||||||
| 'contextService'
|
| 'contextService'
|
||||||
@ -60,6 +75,7 @@ class BootstrapController extends Controller {
|
|||||||
| 'emailService'
|
| 'emailService'
|
||||||
| 'versionService'
|
| 'versionService'
|
||||||
| 'featureTypeService'
|
| 'featureTypeService'
|
||||||
|
| 'openApiService'
|
||||||
>,
|
>,
|
||||||
) {
|
) {
|
||||||
super(config);
|
super(config);
|
||||||
@ -71,15 +87,30 @@ class BootstrapController extends Controller {
|
|||||||
this.featureTypeService = featureTypeService;
|
this.featureTypeService = featureTypeService;
|
||||||
this.emailService = emailService;
|
this.emailService = emailService;
|
||||||
this.versionService = versionService;
|
this.versionService = versionService;
|
||||||
|
this.openApiService = openApiService;
|
||||||
|
|
||||||
this.logger = config.getLogger(
|
this.logger = config.getLogger('routes/admin-api/bootstrap-ui.ts');
|
||||||
'routes/admin-api/bootstrap-controller.ts',
|
this.route({
|
||||||
);
|
method: 'get',
|
||||||
|
path: '',
|
||||||
this.get('/', this.bootstrap);
|
handler: this.bootstrap,
|
||||||
|
permission: NONE,
|
||||||
|
middleware: [
|
||||||
|
openApiService.validPath({
|
||||||
|
tags: ['other'],
|
||||||
|
operationId: 'getBootstrapUiData',
|
||||||
|
responses: {
|
||||||
|
202: createResponseSchema('bootstrapUiSchema'),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async bootstrap(req: AuthedRequest, res: Response): Promise<void> {
|
async bootstrap(
|
||||||
|
req: AuthedRequest,
|
||||||
|
res: Response<BootstrapUiSchema>,
|
||||||
|
): Promise<void> {
|
||||||
const jobs: [
|
const jobs: [
|
||||||
Promise<IContextField[]>,
|
Promise<IContextField[]>,
|
||||||
Promise<IFeatureType[]>,
|
Promise<IFeatureType[]>,
|
||||||
@ -117,18 +148,26 @@ class BootstrapController extends Controller {
|
|||||||
versionInfo,
|
versionInfo,
|
||||||
};
|
};
|
||||||
|
|
||||||
res.json({
|
this.openApiService.respondWithValidation(
|
||||||
|
200,
|
||||||
|
res,
|
||||||
|
bootstrapUiSchema.$id,
|
||||||
|
{
|
||||||
uiConfig,
|
uiConfig,
|
||||||
user: { ...req.user, permissions: userPermissions },
|
user: {
|
||||||
|
...serializeDates(req.user),
|
||||||
|
permissions: userPermissions,
|
||||||
|
},
|
||||||
email: this.emailService.isEnabled(),
|
email: this.emailService.isEnabled(),
|
||||||
context,
|
context: serializeDates(context),
|
||||||
featureTypes,
|
featureTypes,
|
||||||
tagTypes,
|
tagTypes,
|
||||||
strategies,
|
strategies,
|
||||||
projects,
|
projects: serializeDates(projects),
|
||||||
});
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default BootstrapController;
|
export default BootstrapUIController;
|
||||||
module.exports = BootstrapController;
|
module.exports = BootstrapUIController;
|
@ -12,7 +12,7 @@ import UserController from './user';
|
|||||||
import ConfigController from './config';
|
import ConfigController from './config';
|
||||||
import { ContextController } from './context';
|
import { ContextController } from './context';
|
||||||
import ClientMetricsController from './client-metrics';
|
import ClientMetricsController from './client-metrics';
|
||||||
import BootstrapController from './bootstrap';
|
import BootstrapUIController from './bootstrap-ui';
|
||||||
import StateController from './state';
|
import StateController from './state';
|
||||||
import TagController from './tag';
|
import TagController from './tag';
|
||||||
import TagTypeController from './tag-type';
|
import TagTypeController from './tag-type';
|
||||||
@ -65,7 +65,7 @@ class AdminApi extends Controller {
|
|||||||
);
|
);
|
||||||
this.app.use(
|
this.app.use(
|
||||||
'/ui-bootstrap',
|
'/ui-bootstrap',
|
||||||
new BootstrapController(config, services).router,
|
new BootstrapUIController(config, services).router,
|
||||||
);
|
);
|
||||||
this.app.use(
|
this.app.use(
|
||||||
'/context',
|
'/context',
|
||||||
|
@ -293,6 +293,111 @@ Object {
|
|||||||
},
|
},
|
||||||
"type": "object",
|
"type": "object",
|
||||||
},
|
},
|
||||||
|
"bootstrapUiSchema": Object {
|
||||||
|
"additionalProperties": false,
|
||||||
|
"properties": Object {
|
||||||
|
"context": Object {
|
||||||
|
"items": Object {
|
||||||
|
"$ref": "#/components/schemas/contextFieldSchema",
|
||||||
|
},
|
||||||
|
"type": "array",
|
||||||
|
},
|
||||||
|
"email": Object {
|
||||||
|
"type": "boolean",
|
||||||
|
},
|
||||||
|
"featureTypes": Object {
|
||||||
|
"items": Object {
|
||||||
|
"$ref": "#/components/schemas/featureTypeSchema",
|
||||||
|
},
|
||||||
|
"type": "array",
|
||||||
|
},
|
||||||
|
"projects": Object {
|
||||||
|
"items": Object {
|
||||||
|
"$ref": "#/components/schemas/projectSchema",
|
||||||
|
},
|
||||||
|
"type": "array",
|
||||||
|
},
|
||||||
|
"strategies": Object {
|
||||||
|
"items": Object {
|
||||||
|
"$ref": "#/components/schemas/strategySchema",
|
||||||
|
},
|
||||||
|
"type": "array",
|
||||||
|
},
|
||||||
|
"tagTypes": Object {
|
||||||
|
"items": Object {
|
||||||
|
"$ref": "#/components/schemas/tagTypeSchema",
|
||||||
|
},
|
||||||
|
"type": "array",
|
||||||
|
},
|
||||||
|
"uiConfig": Object {
|
||||||
|
"$ref": "#/components/schemas/uiConfigSchema",
|
||||||
|
},
|
||||||
|
"user": Object {
|
||||||
|
"properties": Object {
|
||||||
|
"createdAt": Object {
|
||||||
|
"format": "date-time",
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"email": Object {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"emailSent": Object {
|
||||||
|
"type": "boolean",
|
||||||
|
},
|
||||||
|
"id": Object {
|
||||||
|
"type": "number",
|
||||||
|
},
|
||||||
|
"imageUrl": Object {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"inviteLink": Object {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"isAPI": Object {
|
||||||
|
"type": "boolean",
|
||||||
|
},
|
||||||
|
"loginAttempts": Object {
|
||||||
|
"type": "number",
|
||||||
|
},
|
||||||
|
"name": Object {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"permissions": Object {
|
||||||
|
"items": Object {
|
||||||
|
"$ref": "#/components/schemas/permissionSchema",
|
||||||
|
},
|
||||||
|
"type": "array",
|
||||||
|
},
|
||||||
|
"rootRole": Object {
|
||||||
|
"type": "number",
|
||||||
|
},
|
||||||
|
"seenAt": Object {
|
||||||
|
"format": "date-time",
|
||||||
|
"nullable": true,
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"username": Object {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"required": Array [
|
||||||
|
"id",
|
||||||
|
],
|
||||||
|
"type": "object",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"required": Array [
|
||||||
|
"uiConfig",
|
||||||
|
"user",
|
||||||
|
"email",
|
||||||
|
"context",
|
||||||
|
"featureTypes",
|
||||||
|
"tagTypes",
|
||||||
|
"strategies",
|
||||||
|
"projects",
|
||||||
|
],
|
||||||
|
"type": "object",
|
||||||
|
},
|
||||||
"changePasswordSchema": Object {
|
"changePasswordSchema": Object {
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"properties": Object {
|
"properties": Object {
|
||||||
@ -1962,6 +2067,7 @@ Object {
|
|||||||
"type": "string",
|
"type": "string",
|
||||||
},
|
},
|
||||||
"icon": Object {
|
"icon": Object {
|
||||||
|
"nullable": true,
|
||||||
"type": "string",
|
"type": "string",
|
||||||
},
|
},
|
||||||
"name": Object {
|
"name": Object {
|
||||||
@ -2122,9 +2228,6 @@ Object {
|
|||||||
"unleashUrl",
|
"unleashUrl",
|
||||||
"baseUriPath",
|
"baseUriPath",
|
||||||
"versionInfo",
|
"versionInfo",
|
||||||
"disablePasswordAuth",
|
|
||||||
"segmentValuesLimit",
|
|
||||||
"strategySegmentsLimit",
|
|
||||||
],
|
],
|
||||||
"type": "object",
|
"type": "object",
|
||||||
},
|
},
|
||||||
@ -5167,6 +5270,26 @@ If the provided project does not exist, the list of events will be empty.",
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"/api/admin/ui-bootstrap": Object {
|
||||||
|
"get": Object {
|
||||||
|
"operationId": "getBootstrapUiData",
|
||||||
|
"responses": Object {
|
||||||
|
"202": Object {
|
||||||
|
"content": Object {
|
||||||
|
"application/json": Object {
|
||||||
|
"schema": Object {
|
||||||
|
"$ref": "#/components/schemas/bootstrapUiSchema",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"description": "bootstrapUiSchema",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"tags": Array [
|
||||||
|
"other",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
"/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