1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-01-31 00:16:47 +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',
@ -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;

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

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