1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-02-09 00:18:00 +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:
Jaanus Sellin 2024-02-12 16:00:59 +02:00 committed by GitHub
parent b48d25a226
commit 5a75093cbc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
32 changed files with 257 additions and 110 deletions

View File

@ -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';

View File

@ -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,

View File

@ -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';

View File

@ -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';

View File

@ -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';

View File

@ -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';

View File

@ -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';

View File

@ -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';

View File

@ -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';

View File

@ -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),
);
}
}

View File

@ -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(

View File

@ -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[]>;
}

View File

@ -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',
@ -112,7 +114,8 @@ class ProjectStore implements IProjectStore {
`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
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],
@ -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;

View File

@ -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,

View File

@ -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',
},
sdkVersion: {
'The environments that the application is using. This is the same as the environment in the SDK configuration.',
type: 'array',
items: {
type: 'string',
description:
'The version of the SDK that is being used by the application',
},
environment: {
example: ['development', 'production'],
},
instances: {
description:
'The instances of the application that are using the SDK.',
type: 'array',
items: {
type: 'string',
description:
'The environment that the application is running in. This is coming from token configured in the SDK configuration.',
},
example: ['prod-b4ca', 'prod-ac8a'],
},
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<

View 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
>;

View File

@ -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'],
},
],
},
];

View File

@ -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;

View File

@ -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;

View File

@ -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';

View File

@ -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';

View File

@ -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,

View File

@ -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,

View File

@ -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;

View File

@ -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';

View File

@ -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';

View File

@ -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;

View File

@ -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';

View File

@ -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';

View File

@ -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;

View File

@ -1,4 +1,4 @@
import { IProjectStats } from '../../lib/services/project-service';
import { IProjectStats } from '../../lib/features/project/project-service';
import {
ICreateEnabledDates,
IProjectStatsStore,

View File

@ -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.');
}
}