mirror of
				https://github.com/Unleash/unleash.git
				synced 2025-10-27 11:02:16 +01:00 
			
		
		
		
	feat: project applications e2e PoC (#6189)
1. Adding store layer 2. Updating schemas 3. Refactoring project files that I touched into feature oriented architecture Next steps E2E tests.
This commit is contained in:
		
							parent
							
								
									b48d25a226
								
							
						
					
					
						commit
						5a75093cbc
					
				| @ -9,7 +9,7 @@ import ClientApplicationsStore from './client-applications-store'; | ||||
| import ContextFieldStore from './context-field-store'; | ||||
| import SettingStore from './setting-store'; | ||||
| import UserStore from './user-store'; | ||||
| import ProjectStore from './project-store'; | ||||
| import ProjectStore from '../features/project/project-store'; | ||||
| import TagStore from './tag-store'; | ||||
| import TagTypeStore from '../features/tag-type/tag-type-store'; | ||||
| import AddonStore from './addon-store'; | ||||
|  | ||||
| @ -3,7 +3,7 @@ import { Logger, LogProvider } from '../logger'; | ||||
| import metricsHelper from '../util/metrics-helper'; | ||||
| import { DB_TIME } from '../metric-events'; | ||||
| import EventEmitter from 'events'; | ||||
| import { IProjectStats } from '../services/project-service'; | ||||
| import { IProjectStats } from '../features/project/project-service'; | ||||
| import { | ||||
|     ICreateEnabledDates, | ||||
|     IProjectStatsStore, | ||||
|  | ||||
| @ -5,7 +5,7 @@ import { ImportTogglesStore } from './import-toggles-store'; | ||||
| import FeatureToggleStore from '../feature-toggle/feature-toggle-store'; | ||||
| import TagStore from '../../db/tag-store'; | ||||
| import TagTypeStore from '../tag-type/tag-type-store'; | ||||
| import ProjectStore from '../../db/project-store'; | ||||
| import ProjectStore from '../project/project-store'; | ||||
| import FeatureTagStore from '../../db/feature-tag-store'; | ||||
| import StrategyStore from '../../db/strategy-store'; | ||||
| import ContextFieldStore from '../../db/context-field-store'; | ||||
|  | ||||
| @ -7,7 +7,7 @@ import { | ||||
| import FeatureStrategiesStore from './feature-toggle-strategies-store'; | ||||
| import FeatureToggleStore from './feature-toggle-store'; | ||||
| import FeatureToggleClientStore from '../client-feature-toggles/client-feature-toggle-store'; | ||||
| import ProjectStore from '../../db/project-store'; | ||||
| import ProjectStore from '../project/project-store'; | ||||
| import { FeatureEnvironmentStore } from '../../db/feature-environment-store'; | ||||
| import ContextFieldStore from '../../db/context-field-store'; | ||||
| import GroupStore from '../../db/group-store'; | ||||
|  | ||||
| @ -11,7 +11,7 @@ import { IUnleashConfig } from '../../types'; | ||||
| import { Db } from '../../db/db'; | ||||
| import FeatureToggleStore from '../feature-toggle/feature-toggle-store'; | ||||
| import UserStore from '../../db/user-store'; | ||||
| import ProjectStore from '../../db/project-store'; | ||||
| import ProjectStore from '../project/project-store'; | ||||
| import EnvironmentStore from '../project-environments/environment-store'; | ||||
| import StrategyStore from '../../db/strategy-store'; | ||||
| import ContextFieldStore from '../../db/context-field-store'; | ||||
|  | ||||
| @ -11,7 +11,7 @@ import { IContextFieldStore } from '../../types/stores/context-field-store'; | ||||
| import { IEnvironmentStore } from '../project-environments/environment-store-type'; | ||||
| import { IFeatureToggleStore } from '../feature-toggle/types/feature-toggle-store-type'; | ||||
| import { IGroupStore } from '../../types/stores/group-store'; | ||||
| import { IProjectStore } from '../../types/stores/project-store'; | ||||
| import { IProjectStore } from '../../features/project/project-store-type'; | ||||
| import { IStrategyStore } from '../../types/stores/strategy-store'; | ||||
| import { IUserStore } from '../../types/stores/user-store'; | ||||
| import { ISegmentStore } from '../../types/stores/segment-store'; | ||||
| @ -25,7 +25,7 @@ import { | ||||
| } from '../../types'; | ||||
| import { CUSTOM_ROOT_ROLE_TYPE } from '../../util'; | ||||
| import { type GetActiveUsers } from './getActiveUsers'; | ||||
| import { ProjectModeCount } from '../../db/project-store'; | ||||
| import { ProjectModeCount } from '../project/project-store'; | ||||
| import { GetProductionChanges } from './getProductionChanges'; | ||||
| 
 | ||||
| export type TimeRange = 'allTime' | '30d' | '7d'; | ||||
|  | ||||
| @ -7,7 +7,7 @@ import EnvironmentService from './environment-service'; | ||||
| import EnvironmentStore from './environment-store'; | ||||
| import FeatureStrategiesStore from '../feature-toggle/feature-toggle-strategies-store'; | ||||
| import { FeatureEnvironmentStore } from '../../db/feature-environment-store'; | ||||
| import ProjectStore from '../../db/project-store'; | ||||
| import ProjectStore from '../project/project-store'; | ||||
| import FakeFeatureEnvironmentStore from '../../../test/fixtures/fake-feature-environment-store'; | ||||
| import FakeProjectStore from '../../../test/fixtures/fake-project-store'; | ||||
| import FakeFeatureStrategiesStore from '../feature-toggle/fakes/fake-feature-strategies-store'; | ||||
|  | ||||
| @ -17,7 +17,7 @@ import { BadDataError, UNIQUE_CONSTRAINT_VIOLATION } from '../../error'; | ||||
| import NameExistsError from '../../error/name-exists-error'; | ||||
| import { sortOrderSchema } from '../../services/state-schema'; | ||||
| import NotFoundError from '../../error/notfound-error'; | ||||
| import { IProjectStore } from '../../types/stores/project-store'; | ||||
| import { IProjectStore } from '../../features/project/project-store-type'; | ||||
| import MinimumOneEnvironmentError from '../../error/minimum-one-environment-error'; | ||||
| import { IFlagResolver } from '../../types/experimental'; | ||||
| import { CreateFeatureStrategySchema } from '../../openapi'; | ||||
|  | ||||
| @ -12,7 +12,7 @@ import { | ||||
| } from '../../services'; | ||||
| import FakeGroupStore from '../../../test/fixtures/fake-group-store'; | ||||
| import FakeEventStore from '../../../test/fixtures/fake-event-store'; | ||||
| import ProjectStore from '../../db/project-store'; | ||||
| import ProjectStore from './project-store'; | ||||
| import FeatureToggleStore from '../feature-toggle/feature-toggle-store'; | ||||
| import { FeatureEnvironmentStore } from '../../db/feature-environment-store'; | ||||
| import ProjectStatsStore from '../../db/project-stats-store'; | ||||
|  | ||||
| @ -11,7 +11,7 @@ import { | ||||
| import ProjectFeaturesController from '../feature-toggle/feature-toggle-controller'; | ||||
| import EnvironmentsController from '../project-environments/environments'; | ||||
| import ProjectHealthReport from '../../routes/admin-api/project/health-report'; | ||||
| import ProjectService from '../../services/project-service'; | ||||
| import ProjectService from './project-service'; | ||||
| import VariantsController from '../../routes/admin-api/project/variants'; | ||||
| import { | ||||
|     createResponseSchema, | ||||
| @ -267,7 +267,7 @@ export default class ProjectController extends Controller { | ||||
|             200, | ||||
|             res, | ||||
|             projectApplicationsSchema.$id, | ||||
|             applications, | ||||
|             serializeDates(applications), | ||||
|         ); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -1,12 +1,12 @@ | ||||
| import { subDays } from 'date-fns'; | ||||
| import { ValidationError } from 'joi'; | ||||
| import { IUser } from '../types/user'; | ||||
| import { AccessService, AccessWithRoles } from './access-service'; | ||||
| import NameExistsError from '../error/name-exists-error'; | ||||
| import InvalidOperationError from '../error/invalid-operation-error'; | ||||
| import { nameType } from '../routes/util'; | ||||
| import { projectSchema } from './project-schema'; | ||||
| import NotFoundError from '../error/notfound-error'; | ||||
| import { IUser } from '../../types/user'; | ||||
| import { AccessService, AccessWithRoles } from '../../services/access-service'; | ||||
| import NameExistsError from '../../error/name-exists-error'; | ||||
| import InvalidOperationError from '../../error/invalid-operation-error'; | ||||
| import { nameType } from '../../routes/util'; | ||||
| import { projectSchema } from '../../services/project-schema'; | ||||
| import NotFoundError from '../../error/notfound-error'; | ||||
| import { | ||||
|     DEFAULT_PROJECT, | ||||
|     FeatureToggle, | ||||
| @ -42,34 +42,32 @@ import { | ||||
|     IProjectUpdate, | ||||
|     IProjectHealth, | ||||
|     SYSTEM_USER, | ||||
| } from '../types'; | ||||
| import { | ||||
|     IProjectQuery, | ||||
|     IProjectEnterpriseSettingsUpdate, | ||||
|     IProjectApplication, | ||||
|     IProjectStore, | ||||
| } from '../types/stores/project-store'; | ||||
| } from '../../types'; | ||||
| import { | ||||
|     IProjectAccessModel, | ||||
|     IRoleDescriptor, | ||||
| } from '../types/stores/access-store'; | ||||
| import FeatureToggleService from '../features/feature-toggle/feature-toggle-service'; | ||||
| import IncompatibleProjectError from '../error/incompatible-project-error'; | ||||
| import ProjectWithoutOwnerError from '../error/project-without-owner-error'; | ||||
| import { arraysHaveSameItems } from '../util'; | ||||
| import { GroupService } from './group-service'; | ||||
| import { IGroupRole } from '../types/group'; | ||||
| import { FavoritesService } from './favorites-service'; | ||||
| import { calculateAverageTimeToProd } from '../features/feature-toggle/time-to-production/time-to-production'; | ||||
| import { IProjectStatsStore } from '../types/stores/project-stats-store-type'; | ||||
| import { uniqueByKey } from '../util/unique'; | ||||
| import { BadDataError, PermissionError } from '../error'; | ||||
| } from '../../types/stores/access-store'; | ||||
| import FeatureToggleService from '../feature-toggle/feature-toggle-service'; | ||||
| import IncompatibleProjectError from '../../error/incompatible-project-error'; | ||||
| import ProjectWithoutOwnerError from '../../error/project-without-owner-error'; | ||||
| import { arraysHaveSameItems } from '../../util'; | ||||
| import { GroupService } from '../../services/group-service'; | ||||
| import { IGroupRole } from '../../types/group'; | ||||
| import { FavoritesService } from '../../services/favorites-service'; | ||||
| import { calculateAverageTimeToProd } from '../feature-toggle/time-to-production/time-to-production'; | ||||
| import { IProjectStatsStore } from '../../types/stores/project-stats-store-type'; | ||||
| import { uniqueByKey } from '../../util/unique'; | ||||
| import { BadDataError, PermissionError } from '../../error'; | ||||
| import { ProjectDoraMetricsSchema } from '../../openapi'; | ||||
| import { checkFeatureNamingData } from '../feature-naming-pattern/feature-naming-validation'; | ||||
| import { IPrivateProjectChecker } from '../private-project/privateProjectCheckerType'; | ||||
| import EventService from '../events/event-service'; | ||||
| import { | ||||
|     ProjectDoraMetricsSchema, | ||||
|     ProjectApplicationsSchema, | ||||
| } from '../openapi'; | ||||
| import { checkFeatureNamingData } from '../features/feature-naming-pattern/feature-naming-validation'; | ||||
| import { IPrivateProjectChecker } from '../features/private-project/privateProjectCheckerType'; | ||||
| import EventService from '../features/events/event-service'; | ||||
|     IProjectEnterpriseSettingsUpdate, | ||||
|     IProjectQuery, | ||||
| } from './project-store-type'; | ||||
| 
 | ||||
| const getCreatedBy = (user: IUser) => user.email || user.username || 'unknown'; | ||||
| 
 | ||||
| @ -903,10 +901,10 @@ export default class ProjectService { | ||||
|         }; | ||||
|     } | ||||
| 
 | ||||
|     async getApplications( | ||||
|         projectId: string, | ||||
|     ): Promise<ProjectApplicationsSchema> { | ||||
|         return []; | ||||
|     async getApplications(projectId: string): Promise<IProjectApplication[]> { | ||||
|         const applications = | ||||
|             await this.projectStore.getApplicationsByProject(projectId); | ||||
|         return applications; | ||||
|     } | ||||
| 
 | ||||
|     async changeRole( | ||||
| @ -2,15 +2,16 @@ import { | ||||
|     IEnvironmentProjectLink, | ||||
|     IProjectMembersCount, | ||||
|     ProjectModeCount, | ||||
| } from '../../db/project-store'; | ||||
| } from './project-store'; | ||||
| import { | ||||
|     IEnvironment, | ||||
|     IFeatureNaming, | ||||
|     IProject, | ||||
|     IProjectApplication, | ||||
|     IProjectWithCount, | ||||
|     ProjectMode, | ||||
| } from '../model'; | ||||
| import { Store } from './store'; | ||||
| } from '../../types/model'; | ||||
| import { Store } from '../../types/stores/store'; | ||||
| import { CreateFeatureStrategySchema } from '../../openapi'; | ||||
| 
 | ||||
| export interface IProjectInsert { | ||||
| @ -121,4 +122,5 @@ export interface IProjectStore extends Store<IProject, string> { | ||||
|     isFeatureLimitReached(id: string): Promise<boolean>; | ||||
| 
 | ||||
|     getProjectModeCounts(): Promise<ProjectModeCount[]>; | ||||
|     getApplicationsByProject(projectId: string): Promise<IProjectApplication[]>; | ||||
| } | ||||
| @ -1,15 +1,17 @@ | ||||
| import { Knex } from 'knex'; | ||||
| import { Logger, LogProvider } from '../logger'; | ||||
| import { Logger, LogProvider } from '../../logger'; | ||||
| 
 | ||||
| import NotFoundError from '../error/notfound-error'; | ||||
| import NotFoundError from '../../error/notfound-error'; | ||||
| import { | ||||
|     IEnvironment, | ||||
|     IFlagResolver, | ||||
|     IProject, | ||||
|     IProjectApplication, | ||||
|     IProjectApplicationSdk, | ||||
|     IProjectUpdate, | ||||
|     IProjectWithCount, | ||||
|     ProjectMode, | ||||
| } from '../types'; | ||||
| } from '../../types'; | ||||
| import { | ||||
|     IProjectHealthUpdate, | ||||
|     IProjectInsert, | ||||
| @ -18,14 +20,14 @@ import { | ||||
|     IProjectEnterpriseSettingsUpdate, | ||||
|     IProjectStore, | ||||
|     ProjectEnvironment, | ||||
| } from '../types/stores/project-store'; | ||||
| import { DEFAULT_ENV } from '../util'; | ||||
| import metricsHelper from '../util/metrics-helper'; | ||||
| import { DB_TIME } from '../metric-events'; | ||||
| } from '../../features/project/project-store-type'; | ||||
| import { DEFAULT_ENV } from '../../util'; | ||||
| import metricsHelper from '../../util/metrics-helper'; | ||||
| import { DB_TIME } from '../../metric-events'; | ||||
| import EventEmitter from 'events'; | ||||
| import { Db } from './db'; | ||||
| import { Db } from '../../db/db'; | ||||
| import Raw = Knex.Raw; | ||||
| import { CreateFeatureStrategySchema } from '../openapi'; | ||||
| import { CreateFeatureStrategySchema } from '../../openapi'; | ||||
| 
 | ||||
| const COLUMNS = [ | ||||
|     'id', | ||||
| @ -110,11 +112,12 @@ class ProjectStore implements IProjectStore { | ||||
|     async isFeatureLimitReached(id: string): Promise<boolean> { | ||||
|         const result = await this.db.raw( | ||||
|             `SELECT EXISTS(SELECT 1
 | ||||
|              FROM project_settings | ||||
|              LEFT JOIN features ON project_settings.project = features.project | ||||
|              WHERE project_settings.project = ? AND features.archived_at IS NULL | ||||
|              GROUP BY project_settings.project | ||||
|              HAVING project_settings.feature_limit <= COUNT(features.project)) AS present`,
 | ||||
|                            FROM project_settings | ||||
|                                     LEFT JOIN features ON project_settings.project = features.project | ||||
|                            WHERE project_settings.project = ? | ||||
|                              AND features.archived_at IS NULL | ||||
|                            GROUP BY project_settings.project | ||||
|                            HAVING project_settings.feature_limit <= COUNT(features.project)) AS present`,
 | ||||
|             [id], | ||||
|         ); | ||||
|         const { present } = result.rows[0]; | ||||
| @ -254,9 +257,10 @@ class ProjectStore implements IProjectStore { | ||||
|     } | ||||
| 
 | ||||
|     async updateHealth(healthUpdate: IProjectHealthUpdate): Promise<void> { | ||||
|         await this.db(TABLE) | ||||
|             .where({ id: healthUpdate.id }) | ||||
|             .update({ health: healthUpdate.health, updated_at: new Date() }); | ||||
|         await this.db(TABLE).where({ id: healthUpdate.id }).update({ | ||||
|             health: healthUpdate.health, | ||||
|             updated_at: new Date(), | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     async create( | ||||
| @ -575,13 +579,45 @@ class ProjectStore implements IProjectStore { | ||||
|         return Number(members.count); | ||||
|     } | ||||
| 
 | ||||
|     async getApplicationsByProject( | ||||
|         projectId: string, | ||||
|     ): Promise<IProjectApplication[]> { | ||||
|         const query = this.db | ||||
|             .with('applications', (qb) => { | ||||
|                 qb.select('project', 'app_name', 'environment') | ||||
|                     .distinct() | ||||
|                     .from('client_metrics_env as cme') | ||||
|                     .leftJoin('features as f', 'cme.feature_name', 'f.name') | ||||
|                     .where('project', projectId); | ||||
|             }) | ||||
|             .select( | ||||
|                 'a.app_name', | ||||
|                 'a.environment', | ||||
|                 'ci.instance_id', | ||||
|                 'ci.sdk_version', | ||||
|             ) | ||||
|             .from('applications as a') | ||||
|             .leftJoin('client_instances as ci', function () { | ||||
|                 this.on('ci.app_name', 'a.app_name').andOn( | ||||
|                     'ci.environment', | ||||
|                     'a.environment', | ||||
|                 ); | ||||
|             }); | ||||
|         const rows = await query; | ||||
|         const applications = this.getAggregatedApplicationsData(rows); | ||||
|         return applications; | ||||
|     } | ||||
| 
 | ||||
|     async getDefaultStrategy( | ||||
|         projectId: string, | ||||
|         environment: string, | ||||
|     ): Promise<CreateFeatureStrategySchema | null> { | ||||
|         const rows = await this.db(PROJECT_ENVIRONMENTS) | ||||
|             .select('default_strategy') | ||||
|             .where({ project_id: projectId, environment_name: environment }); | ||||
|             .where({ | ||||
|                 project_id: projectId, | ||||
|                 environment_name: environment, | ||||
|             }); | ||||
| 
 | ||||
|         return rows.length > 0 ? rows[0].default_strategy : null; | ||||
|     } | ||||
| @ -595,7 +631,10 @@ class ProjectStore implements IProjectStore { | ||||
|             .update({ | ||||
|                 default_strategy: strategy, | ||||
|             }) | ||||
|             .where({ project_id: projectId, environment_name: environment }) | ||||
|             .where({ | ||||
|                 project_id: projectId, | ||||
|                 environment_name: environment, | ||||
|             }) | ||||
|             .returning('default_strategy'); | ||||
| 
 | ||||
|         return rows[0].default_strategy; | ||||
| @ -680,6 +719,43 @@ class ProjectStore implements IProjectStore { | ||||
|                     : row.default_strategy, | ||||
|         }; | ||||
|     } | ||||
| 
 | ||||
|     getAggregatedApplicationsData(rows): IProjectApplication[] { | ||||
|         const entriesMap: Map<string, IProjectApplication> = new Map(); | ||||
|         const orderedEntries: IProjectApplication[] = []; | ||||
| 
 | ||||
|         const getSdk = (sdkParts: string[]): IProjectApplicationSdk => { | ||||
|             return { | ||||
|                 name: sdkParts[0], | ||||
|                 versions: [sdkParts[1]], | ||||
|             }; | ||||
|         }; | ||||
| 
 | ||||
|         rows.forEach((row) => { | ||||
|             let entry = entriesMap.get(row.app_name); | ||||
|             const sdkParts = row.sdk_version.split(':'); | ||||
| 
 | ||||
|             if (!entry) { | ||||
|                 entry = { | ||||
|                     name: row.app_name, | ||||
|                     environments: [row.environment], | ||||
|                     instances: [row.instance_id], | ||||
|                     sdks: [getSdk(sdkParts)], | ||||
|                 }; | ||||
|                 entriesMap.set(row.feature_name, entry); | ||||
|                 orderedEntries.push(entry); | ||||
|             } | ||||
| 
 | ||||
|             const sdk = entry.sdks.find((sdk) => sdk.name === sdkParts[0]); | ||||
|             if (!sdk) { | ||||
|                 entry.sdks.push(getSdk(sdkParts)); | ||||
|             } else { | ||||
|                 sdk.versions.push(sdkParts[1]); | ||||
|             } | ||||
|         }); | ||||
| 
 | ||||
|         return orderedEntries; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| export default ProjectStore; | ||||
| @ -196,6 +196,7 @@ import { segmentStrategiesSchema } from './spec/segment-strategies-schema'; | ||||
| import { featureDependenciesSchema } from './spec/feature-dependencies-schema'; | ||||
| import { projectApplicationsSchema } from './spec/project-applications-schema'; | ||||
| import { projectApplicationSchema } from './spec/project-application-schema'; | ||||
| import { projectApplicationSdkSchema } from './spec/project-application-sdk-schema'; | ||||
| 
 | ||||
| // Schemas must have an $id property on the form "#/components/schemas/mySchema".
 | ||||
| export type SchemaId = (typeof schemas)[keyof typeof schemas]['$id']; | ||||
| @ -326,6 +327,7 @@ export const schemas: UnleashSchemas = { | ||||
|     playgroundStrategySchema, | ||||
|     profileSchema, | ||||
|     projectApplicationSchema, | ||||
|     projectApplicationSdkSchema, | ||||
|     projectApplicationsSchema, | ||||
|     projectEnvironmentSchema, | ||||
|     projectSchema, | ||||
|  | ||||
| @ -1,34 +1,45 @@ | ||||
| import { FromSchema } from 'json-schema-to-ts'; | ||||
| import { projectApplicationSdkSchema } from './project-application-sdk-schema'; | ||||
| 
 | ||||
| export const projectApplicationSchema = { | ||||
|     $id: '#/components/schemas/projectApplicationSchema', | ||||
|     type: 'object', | ||||
|     additionalProperties: false, | ||||
|     required: ['appName', 'instanceId', 'sdkVersion', 'environment'], | ||||
|     required: ['name', 'environments', 'instances', 'sdks'], | ||||
|     description: 'A project application instance.', | ||||
|     properties: { | ||||
|         appName: { | ||||
|         name: { | ||||
|             type: 'string', | ||||
|             description: | ||||
|                 'Name of the application that is using the SDK. This is the same as the appName in the SDK configuration.', | ||||
|         }, | ||||
|         instanceId: { | ||||
|             type: 'string', | ||||
|         environments: { | ||||
|             description: | ||||
|                 'The unique identifier of the application instance. This is the same as the instanceId in the SDK configuration', | ||||
|                 'The environments that the application is using. This is the same as the environment in the SDK configuration.', | ||||
|             type: 'array', | ||||
|             items: { | ||||
|                 type: 'string', | ||||
|             }, | ||||
|             example: ['development', 'production'], | ||||
|         }, | ||||
|         sdkVersion: { | ||||
|             type: 'string', | ||||
|         instances: { | ||||
|             description: | ||||
|                 'The version of the SDK that is being used by the application', | ||||
|                 'The instances of the application that are using the SDK.', | ||||
|             type: 'array', | ||||
|             items: { | ||||
|                 type: 'string', | ||||
|             }, | ||||
|             example: ['prod-b4ca', 'prod-ac8a'], | ||||
|         }, | ||||
|         environment: { | ||||
|             type: 'string', | ||||
|             description: | ||||
|                 'The environment that the application is running in. This is coming from token configured in the SDK configuration.', | ||||
|         sdks: { | ||||
|             type: 'array', | ||||
|             description: 'The SDKs that the application is using.', | ||||
|             items: { | ||||
|                 $ref: '#/components/schemas/projectApplicationSdkSchema', | ||||
|             }, | ||||
|         }, | ||||
|     }, | ||||
|     components: {}, | ||||
|     components: { projectApplicationSdkSchema }, | ||||
| } as const; | ||||
| 
 | ||||
| export type ProjectApplicationSchema = FromSchema< | ||||
|  | ||||
							
								
								
									
										31
									
								
								src/lib/openapi/spec/project-application-sdk-schema.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								src/lib/openapi/spec/project-application-sdk-schema.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,31 @@ | ||||
| import { FromSchema } from 'json-schema-to-ts'; | ||||
| 
 | ||||
| export const projectApplicationSdkSchema = { | ||||
|     $id: '#/components/schemas/projectApplicationSdkSchema', | ||||
|     type: 'object', | ||||
|     additionalProperties: false, | ||||
|     required: ['name', 'versions'], | ||||
|     description: 'A project application instance SDK.', | ||||
|     properties: { | ||||
|         name: { | ||||
|             type: 'string', | ||||
|             description: | ||||
|                 'Name of the SDK package that the application is using.', | ||||
|             example: 'unleash-client-node', | ||||
|         }, | ||||
|         versions: { | ||||
|             description: | ||||
|                 'The versions of the SDK that the application is using.', | ||||
|             type: 'array', | ||||
|             items: { | ||||
|                 type: 'string', | ||||
|             }, | ||||
|             example: ['4.1.1'], | ||||
|         }, | ||||
|     }, | ||||
|     components: {}, | ||||
| } as const; | ||||
| 
 | ||||
| export type ProjectApplicationSdkSchema = FromSchema< | ||||
|     typeof projectApplicationSdkSchema | ||||
| >; | ||||
| @ -4,10 +4,15 @@ import { ProjectApplicationsSchema } from './project-applications-schema'; | ||||
| test('projectApplicationsSchema', () => { | ||||
|     const data: ProjectApplicationsSchema = [ | ||||
|         { | ||||
|             appName: 'my-weba-app', | ||||
|             instanceId: 'app1:3:4', | ||||
|             sdkVersion: '4.1.1', | ||||
|             environment: 'production', | ||||
|             name: 'my-weba-app', | ||||
|             environments: ['development', 'production'], | ||||
|             instances: ['instance-414122'], | ||||
|             sdks: [ | ||||
|                 { | ||||
|                     name: 'unleash-client-node', | ||||
|                     versions: ['4.1.1'], | ||||
|                 }, | ||||
|             ], | ||||
|         }, | ||||
|     ]; | ||||
| 
 | ||||
|  | ||||
| @ -1,5 +1,6 @@ | ||||
| import { FromSchema } from 'json-schema-to-ts'; | ||||
| import { projectApplicationSchema } from './project-application-schema'; | ||||
| import { projectApplicationSdkSchema } from './project-application-sdk-schema'; | ||||
| 
 | ||||
| export const projectApplicationsSchema = { | ||||
|     $id: '#/components/schemas/projectApplicationsSchema', | ||||
| @ -11,6 +12,7 @@ export const projectApplicationsSchema = { | ||||
|     components: { | ||||
|         schemas: { | ||||
|             projectApplicationSchema, | ||||
|             projectApplicationSdkSchema, | ||||
|         }, | ||||
|     }, | ||||
| } as const; | ||||
|  | ||||
| @ -23,7 +23,7 @@ import { | ||||
|     profileSchema, | ||||
|     ProfileSchema, | ||||
| } from '../../../openapi/spec/profile-schema'; | ||||
| import ProjectService from '../../../services/project-service'; | ||||
| import ProjectService from '../../../features/project/project-service'; | ||||
| 
 | ||||
| class UserController extends Controller { | ||||
|     private accessService: AccessService; | ||||
|  | ||||
| @ -4,7 +4,7 @@ import { | ||||
|     IContextFieldDto, | ||||
|     IContextFieldStore, | ||||
| } from '../types/stores/context-field-store'; | ||||
| import { IProjectStore } from '../types/stores/project-store'; | ||||
| import { IProjectStore } from '../features/project/project-store-type'; | ||||
| import { IFeatureStrategiesStore, IUnleashStores } from '../types/stores'; | ||||
| import { IUnleashConfig } from '../types/option'; | ||||
| import { ContextFieldStrategiesSchema } from '../openapi/spec/context-field-strategies-schema'; | ||||
|  | ||||
| @ -3,7 +3,7 @@ import FeatureTypeService from './feature-type-service'; | ||||
| import EventService from '../features/events/event-service'; | ||||
| import HealthService from './health-service'; | ||||
| 
 | ||||
| import ProjectService from './project-service'; | ||||
| import ProjectService from '../features/project/project-service'; | ||||
| import StateService from './state-service'; | ||||
| import ClientInstanceService from '../features/metrics/instance/instance-service'; | ||||
| import ClientMetricsServiceV2 from '../features/metrics/client-metrics/metrics-service-v2'; | ||||
|  | ||||
| @ -4,8 +4,8 @@ import { Logger } from '../logger'; | ||||
| import type { IProject, IProjectHealthReport } from '../types/model'; | ||||
| import type { IFeatureToggleStore } from '../features/feature-toggle/types/feature-toggle-store-type'; | ||||
| import type { IFeatureTypeStore } from '../types/stores/feature-type-store'; | ||||
| import type { IProjectStore } from '../types/stores/project-store'; | ||||
| import ProjectService from './project-service'; | ||||
| import type { IProjectStore } from '../features/project/project-store-type'; | ||||
| import ProjectService from '../features/project/project-service'; | ||||
| import { | ||||
|     calculateHealthRating, | ||||
|     calculateProjectHealth, | ||||
|  | ||||
| @ -36,7 +36,7 @@ import { | ||||
|     IFeatureTag, | ||||
|     IFeatureTagStore, | ||||
| } from '../types/stores/feature-tag-store'; | ||||
| import { IProjectStore } from '../types/stores/project-store'; | ||||
| import { IProjectStore } from '../features/project/project-store-type'; | ||||
| import { | ||||
|     ITagType, | ||||
|     ITagTypeStore, | ||||
|  | ||||
| @ -3,9 +3,9 @@ import { LogProvider } from '../logger'; | ||||
| import { IRole } from './stores/access-store'; | ||||
| import { IUser } from './user'; | ||||
| import { ALL_OPERATORS } from '../util'; | ||||
| import { IProjectStats } from '../services/project-service'; | ||||
| import { IProjectStats } from '../features/project/project-service'; | ||||
| import { CreateFeatureStrategySchema } from '../openapi'; | ||||
| import { ProjectEnvironment } from './stores/project-store'; | ||||
| import { ProjectEnvironment } from '../features/project/project-store-type'; | ||||
| 
 | ||||
| export type Operator = (typeof ALL_OPERATORS)[number]; | ||||
| 
 | ||||
| @ -478,6 +478,18 @@ export interface IProject { | ||||
|     featureNaming?: IFeatureNaming; | ||||
| } | ||||
| 
 | ||||
| export interface IProjectApplication { | ||||
|     name: string; | ||||
|     environments: string[]; | ||||
|     instances: string[]; | ||||
|     sdks: IProjectApplicationSdk[]; | ||||
| } | ||||
| 
 | ||||
| export interface IProjectApplicationSdk { | ||||
|     name: string; | ||||
|     versions: string[]; | ||||
| } | ||||
| 
 | ||||
| // mimics UpdateProjectSchema
 | ||||
| export interface IProjectUpdate { | ||||
|     id: string; | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| import { AccessService } from '../services/access-service'; | ||||
| import AddonService from '../services/addon-service'; | ||||
| import ProjectService from '../services/project-service'; | ||||
| import ProjectService from '../features/project/project-service'; | ||||
| import StateService from '../services/state-service'; | ||||
| import StrategyService from '../services/strategy-service'; | ||||
| import TagTypeService from '../features/tag-type/tag-type-service'; | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| import { IProjectStore } from './stores/project-store'; | ||||
| import { IProjectStore } from '../features/project/project-store-type'; | ||||
| import { IEventStore } from './stores/event-store'; | ||||
| import { IFeatureTypeStore } from './stores/feature-type-store'; | ||||
| import { IStrategyStore } from './stores/strategy-store'; | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| import { DoraFeaturesSchema } from '../../openapi'; | ||||
| import { IProjectStats } from '../../services/project-service'; | ||||
| import { IProjectStats } from '../../features/project/project-service'; | ||||
| 
 | ||||
| export interface ICreateEnabledDates { | ||||
|     created: Date; | ||||
|  | ||||
| @ -5,7 +5,7 @@ import { createTestConfig } from '../../config/test-config'; | ||||
| import { ApiTokenType, IApiToken } from '../../../lib/types/models/api-token'; | ||||
| import { DEFAULT_ENV } from '../../../lib/util/constants'; | ||||
| import { addDays, subDays } from 'date-fns'; | ||||
| import ProjectService from '../../../lib/services/project-service'; | ||||
| import ProjectService from '../../../lib/features/project/project-service'; | ||||
| import { createProjectService } from '../../../lib/features'; | ||||
| import { EventService } from '../../../lib/services'; | ||||
| import { IUnleashStores } from '../../../lib/types'; | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| import dbInit, { ITestDb } from '../helpers/database-init'; | ||||
| import getLogger from '../../fixtures/no-logger'; | ||||
| import FeatureToggleService from '../../../lib/features/feature-toggle/feature-toggle-service'; | ||||
| import ProjectService from '../../../lib/services/project-service'; | ||||
| import ProjectService from '../../../lib/features/project/project-service'; | ||||
| import { AccessService } from '../../../lib/services/access-service'; | ||||
| import { MOVE_FEATURE_TOGGLE } from '../../../lib/types/permissions'; | ||||
| import { createTestConfig } from '../../config/test-config'; | ||||
|  | ||||
| @ -1,12 +1,9 @@ | ||||
| import { | ||||
|     IProjectInsert, | ||||
|     IProjectStore, | ||||
| } from '../../../lib/types/stores/project-store'; | ||||
| import { IEnvironmentStore } from '../../../lib/features/project-environments/environment-store-type'; | ||||
| 
 | ||||
| import dbInit, { ITestDb } from '../helpers/database-init'; | ||||
| import getLogger from '../../fixtures/no-logger'; | ||||
| import { IUnleashStores } from '../../../lib/types'; | ||||
| import { IProjectStore, IUnleashStores } from '../../../lib/types'; | ||||
| import { IProjectInsert } from '../../../lib/features/project/project-store-type'; | ||||
| 
 | ||||
| let stores: IUnleashStores; | ||||
| let db: ITestDb; | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| import { IProjectStats } from '../../lib/services/project-service'; | ||||
| import { IProjectStats } from '../../lib/features/project/project-service'; | ||||
| import { | ||||
|     ICreateEnabledDates, | ||||
|     IProjectStatsStore, | ||||
|  | ||||
							
								
								
									
										23
									
								
								src/test/fixtures/fake-project-store.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										23
									
								
								src/test/fixtures/fake-project-store.ts
									
									
									
									
										vendored
									
									
								
							| @ -1,17 +1,22 @@ | ||||
| import { | ||||
|     IProjectHealthUpdate, | ||||
|     IProjectInsert, | ||||
|     IEnvironment, | ||||
|     IProject, | ||||
|     IProjectApplication, | ||||
|     IProjectStore, | ||||
|     ProjectEnvironment, | ||||
| } from '../../lib/types/stores/project-store'; | ||||
| import { IEnvironment, IProject, IProjectWithCount } from '../../lib/types'; | ||||
|     IProjectWithCount, | ||||
| } from '../../lib/types'; | ||||
| import NotFoundError from '../../lib/error/notfound-error'; | ||||
| import { | ||||
|     IEnvironmentProjectLink, | ||||
|     IProjectMembersCount, | ||||
|     ProjectModeCount, | ||||
| } from '../../lib/db/project-store'; | ||||
| } from '../../lib/features/project/project-store'; | ||||
| import { CreateFeatureStrategySchema } from '../../lib/openapi'; | ||||
| import { | ||||
|     IProjectHealthUpdate, | ||||
|     IProjectInsert, | ||||
|     ProjectEnvironment, | ||||
| } from '../../lib/features/project/project-store-type'; | ||||
| 
 | ||||
| export default class FakeProjectStore implements IProjectStore { | ||||
|     projects: IProject[] = []; | ||||
| @ -202,4 +207,10 @@ export default class FakeProjectStore implements IProjectStore { | ||||
|     updateProjectEnterpriseSettings(update: IProjectInsert): Promise<void> { | ||||
|         throw new Error('Method not implemented.'); | ||||
|     } | ||||
|     // eslint-disable-next-line @typescript-eslint/no-unused-vars
 | ||||
|     getApplicationsByProject( | ||||
|         projectId: string, | ||||
|     ): Promise<IProjectApplication[]> { | ||||
|         throw new Error('Method not implemented.'); | ||||
|     } | ||||
| } | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user