mirror of
				https://github.com/Unleash/unleash.git
				synced 2025-10-27 11:02:16 +01:00 
			
		
		
		
	feat: project owners in project service (#6935)
Schema and integrating into service and controller for project owners --------- Co-authored-by: Thomas Heartman <thomas@getunleash.io>
This commit is contained in:
		
							parent
							
								
									7d01dbb748
								
							
						
					
					
						commit
						66ec9a2f2f
					
				@ -43,6 +43,7 @@ import FeatureSearchStore from '../features/feature-search/feature-search-store'
 | 
			
		||||
import { InactiveUsersStore } from '../users/inactive/inactive-users-store';
 | 
			
		||||
import { TrafficDataUsageStore } from '../features/traffic-data-usage/traffic-data-usage-store';
 | 
			
		||||
import { SegmentReadModel } from '../features/segment/segment-read-model';
 | 
			
		||||
import { ProjectOwnersReadModel } from '../features/project/project-owners-read-model';
 | 
			
		||||
 | 
			
		||||
export const createStores = (
 | 
			
		||||
    config: IUnleashConfig,
 | 
			
		||||
@ -148,6 +149,7 @@ export const createStores = (
 | 
			
		||||
        inactiveUsersStore: new InactiveUsersStore(db, eventBus, getLogger),
 | 
			
		||||
        trafficDataUsageStore: new TrafficDataUsageStore(db, getLogger),
 | 
			
		||||
        segmentReadModel: new SegmentReadModel(db),
 | 
			
		||||
        projectOwnersReadModel: new ProjectOwnersReadModel(db),
 | 
			
		||||
    };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -41,6 +41,8 @@ import {
 | 
			
		||||
import FakeFeatureTagStore from '../../../test/fixtures/fake-feature-tag-store';
 | 
			
		||||
import FeatureTypeStore from '../../db/feature-type-store';
 | 
			
		||||
import FakeFeatureTypeStore from '../../../test/fixtures/fake-feature-type-store';
 | 
			
		||||
import { ProjectOwnersReadModel } from './project-owners-read-model';
 | 
			
		||||
import { FakeProjectOwnersReadModel } from './fake-project-owners-read-model';
 | 
			
		||||
 | 
			
		||||
export const createProjectService = (
 | 
			
		||||
    db: Db,
 | 
			
		||||
@ -54,6 +56,7 @@ export const createProjectService = (
 | 
			
		||||
        getLogger,
 | 
			
		||||
        flagResolver,
 | 
			
		||||
    );
 | 
			
		||||
    const projectOwnersReadModel = new ProjectOwnersReadModel(db);
 | 
			
		||||
    const groupStore = new GroupStore(db);
 | 
			
		||||
    const featureToggleStore = new FeatureToggleStore(
 | 
			
		||||
        db,
 | 
			
		||||
@ -115,6 +118,7 @@ export const createProjectService = (
 | 
			
		||||
            featureTypeStore,
 | 
			
		||||
            accountStore,
 | 
			
		||||
            projectStatsStore,
 | 
			
		||||
            projectOwnersReadModel,
 | 
			
		||||
        },
 | 
			
		||||
        config,
 | 
			
		||||
        accessService,
 | 
			
		||||
@ -131,6 +135,7 @@ export const createFakeProjectService = (
 | 
			
		||||
): ProjectService => {
 | 
			
		||||
    const { getLogger } = config;
 | 
			
		||||
    const eventStore = new FakeEventStore();
 | 
			
		||||
    const projectOwnersReadModel = new FakeProjectOwnersReadModel();
 | 
			
		||||
    const projectStore = new FakeProjectStore();
 | 
			
		||||
    const groupStore = new FakeGroupStore();
 | 
			
		||||
    const featureToggleStore = new FakeFeatureToggleStore();
 | 
			
		||||
@ -169,6 +174,7 @@ export const createFakeProjectService = (
 | 
			
		||||
    return new ProjectService(
 | 
			
		||||
        {
 | 
			
		||||
            projectStore,
 | 
			
		||||
            projectOwnersReadModel,
 | 
			
		||||
            eventStore,
 | 
			
		||||
            featureToggleStore,
 | 
			
		||||
            environmentStore,
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										16
									
								
								src/lib/features/project/fake-project-owners-read-model.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src/lib/features/project/fake-project-owners-read-model.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,16 @@
 | 
			
		||||
import type { IProjectWithCount } from '../../types';
 | 
			
		||||
import type {
 | 
			
		||||
    IProjectOwnersReadModel,
 | 
			
		||||
    IProjectWithCountAndOwners,
 | 
			
		||||
} from './project-owners-read-model.type';
 | 
			
		||||
 | 
			
		||||
export class FakeProjectOwnersReadModel implements IProjectOwnersReadModel {
 | 
			
		||||
    async addOwners(
 | 
			
		||||
        projects: IProjectWithCount[],
 | 
			
		||||
    ): Promise<IProjectWithCountAndOwners[]> {
 | 
			
		||||
        return projects.map((project) => ({
 | 
			
		||||
            ...project,
 | 
			
		||||
            owners: [{ ownerType: 'system' }],
 | 
			
		||||
        }));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -197,9 +197,19 @@ export default class ProjectController extends Controller {
 | 
			
		||||
            user.id,
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // if (this.flagResolver.isEnabled('projectsListNewCards')) {
 | 
			
		||||
        //   TODO: get project owners and add to response
 | 
			
		||||
        // }
 | 
			
		||||
        if (this.flagResolver.isEnabled('projectsListNewCards')) {
 | 
			
		||||
            const projectsWithOwners =
 | 
			
		||||
                await this.projectService.addOwnersToProjects(projects);
 | 
			
		||||
 | 
			
		||||
            this.openApiService.respondWithValidation(
 | 
			
		||||
                200,
 | 
			
		||||
                res,
 | 
			
		||||
                projectsSchema.$id,
 | 
			
		||||
                { version: 1, projects: serializeDates(projectsWithOwners) },
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.openApiService.respondWithValidation(
 | 
			
		||||
            200,
 | 
			
		||||
 | 
			
		||||
@ -19,7 +19,10 @@ const mockProjectWithCounts = (name: string) => ({
 | 
			
		||||
 | 
			
		||||
describe('unit tests', () => {
 | 
			
		||||
    test('maps owners to projects', () => {
 | 
			
		||||
        const projects = [{ name: 'project1' }, { name: 'project2' }] as any;
 | 
			
		||||
        const projects = [
 | 
			
		||||
            { id: 'project1', name: 'Project one' },
 | 
			
		||||
            { id: 'project2', name: 'Project two' },
 | 
			
		||||
        ] as any;
 | 
			
		||||
 | 
			
		||||
        const owners = {
 | 
			
		||||
            project1: [{ ownerType: 'user' as const, name: 'Owner Name' }],
 | 
			
		||||
@ -32,13 +35,21 @@ describe('unit tests', () => {
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        expect(projectsWithOwners).toMatchObject([
 | 
			
		||||
            { name: 'project1', owners: [{ name: 'Owner Name' }] },
 | 
			
		||||
            { name: 'project2', owners: [{ name: 'Owner Name' }] },
 | 
			
		||||
            {
 | 
			
		||||
                id: 'project1',
 | 
			
		||||
                name: 'Project one',
 | 
			
		||||
                owners: [{ name: 'Owner Name' }],
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                id: 'project2',
 | 
			
		||||
                name: 'Project two',
 | 
			
		||||
                owners: [{ name: 'Owner Name' }],
 | 
			
		||||
            },
 | 
			
		||||
        ]);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    test('returns "system" when a project has no owners', async () => {
 | 
			
		||||
        const projects = [{ name: 'project1' }, { name: 'project2' }] as any;
 | 
			
		||||
        const projects = [{ id: 'project1' }, { id: 'project2' }] as any;
 | 
			
		||||
 | 
			
		||||
        const owners = {};
 | 
			
		||||
 | 
			
		||||
@ -48,8 +59,14 @@ describe('unit tests', () => {
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        expect(projectsWithOwners).toMatchObject([
 | 
			
		||||
            { name: 'project1', owners: [{ ownerType: 'system' }] },
 | 
			
		||||
            { name: 'project2', owners: [{ ownerType: 'system' }] },
 | 
			
		||||
            {
 | 
			
		||||
                id: 'project1',
 | 
			
		||||
                owners: [{ ownerType: 'system' }],
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                id: 'project2',
 | 
			
		||||
                owners: [{ ownerType: 'system' }],
 | 
			
		||||
            },
 | 
			
		||||
        ]);
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
@ -66,7 +83,7 @@ let group2: IGroup;
 | 
			
		||||
 | 
			
		||||
beforeAll(async () => {
 | 
			
		||||
    db = await dbInit('project_owners_read_model_serial', getLogger);
 | 
			
		||||
    readModel = new ProjectOwnersReadModel(db.rawDatabase, db.stores.roleStore);
 | 
			
		||||
    readModel = new ProjectOwnersReadModel(db.rawDatabase);
 | 
			
		||||
    ownerRoleId = (await db.stores.roleStore.getRoleByName(RoleName.OWNER)).id;
 | 
			
		||||
 | 
			
		||||
    const ownerData = {
 | 
			
		||||
@ -107,14 +124,7 @@ afterAll(async () => {
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
afterEach(async () => {
 | 
			
		||||
    if (db) {
 | 
			
		||||
        const projects = await db.stores.projectStore.getAll();
 | 
			
		||||
        for (const project of projects) {
 | 
			
		||||
            // Clean only project roles, not all roles
 | 
			
		||||
            await db.stores.roleStore.removeRolesForProject(project.id);
 | 
			
		||||
        }
 | 
			
		||||
        await db.stores.projectStore.deleteAll();
 | 
			
		||||
    }
 | 
			
		||||
    db.stores.roleStore;
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
describe('integration tests', () => {
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,12 @@
 | 
			
		||||
import type { Db } from '../../db/db';
 | 
			
		||||
import { RoleName, type IProjectWithCount, type IRoleStore } from '../../types';
 | 
			
		||||
import { RoleName, type IProjectWithCount } from '../../types';
 | 
			
		||||
import type {
 | 
			
		||||
    GroupProjectOwner,
 | 
			
		||||
    IProjectOwnersReadModel,
 | 
			
		||||
    IProjectWithCountAndOwners,
 | 
			
		||||
    ProjectOwnersDictionary,
 | 
			
		||||
    UserProjectOwner,
 | 
			
		||||
} from './project-owners-read-model.type';
 | 
			
		||||
 | 
			
		||||
const T = {
 | 
			
		||||
    ROLE_USER: 'role_user',
 | 
			
		||||
@ -8,34 +15,11 @@ const T = {
 | 
			
		||||
    USERS: 'users',
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
type SystemOwner = { ownerType: 'system' };
 | 
			
		||||
type UserProjectOwner = {
 | 
			
		||||
    ownerType: 'user';
 | 
			
		||||
    name: string;
 | 
			
		||||
    email?: string;
 | 
			
		||||
    imageUrl?: string;
 | 
			
		||||
};
 | 
			
		||||
type GroupProjectOwner = {
 | 
			
		||||
    ownerType: 'group';
 | 
			
		||||
    name: string;
 | 
			
		||||
};
 | 
			
		||||
type ProjectOwners =
 | 
			
		||||
    | [SystemOwner]
 | 
			
		||||
    | Array<UserProjectOwner | GroupProjectOwner>;
 | 
			
		||||
 | 
			
		||||
export type ProjectOwnersDictionary = Record<string, ProjectOwners>;
 | 
			
		||||
 | 
			
		||||
type IProjectWithCountAndOwners = IProjectWithCount & {
 | 
			
		||||
    owners: ProjectOwners;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export class ProjectOwnersReadModel {
 | 
			
		||||
export class ProjectOwnersReadModel implements IProjectOwnersReadModel {
 | 
			
		||||
    private db: Db;
 | 
			
		||||
    roleStore: IRoleStore;
 | 
			
		||||
 | 
			
		||||
    constructor(db: Db, roleStore: IRoleStore) {
 | 
			
		||||
    constructor(db: Db) {
 | 
			
		||||
        this.db = db;
 | 
			
		||||
        this.roleStore = roleStore;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static addOwnerData(
 | 
			
		||||
@ -44,7 +28,7 @@ export class ProjectOwnersReadModel {
 | 
			
		||||
    ): IProjectWithCountAndOwners[] {
 | 
			
		||||
        return projects.map((project) => ({
 | 
			
		||||
            ...project,
 | 
			
		||||
            owners: owners[project.name] || [{ ownerType: 'system' }],
 | 
			
		||||
            owners: owners[project.id] || [{ ownerType: 'system' }],
 | 
			
		||||
        }));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -119,7 +103,9 @@ export class ProjectOwnersReadModel {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async getAllProjectOwners(): Promise<ProjectOwnersDictionary> {
 | 
			
		||||
        const ownerRole = await this.roleStore.getRoleByName(RoleName.OWNER);
 | 
			
		||||
        const ownerRole = await this.db(T.ROLES)
 | 
			
		||||
            .where({ name: RoleName.OWNER })
 | 
			
		||||
            .first();
 | 
			
		||||
        const usersDict = await this.getAllProjectUsersByRole(ownerRole.id);
 | 
			
		||||
        const groupsDict = await this.getAllProjectGroupsByRole(ownerRole.id);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										28
									
								
								src/lib/features/project/project-owners-read-model.type.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								src/lib/features/project/project-owners-read-model.type.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,28 @@
 | 
			
		||||
import type { IProjectWithCount } from '../../types';
 | 
			
		||||
 | 
			
		||||
export type SystemOwner = { ownerType: 'system' };
 | 
			
		||||
export type UserProjectOwner = {
 | 
			
		||||
    ownerType: 'user';
 | 
			
		||||
    name: string;
 | 
			
		||||
    email?: string;
 | 
			
		||||
    imageUrl?: string;
 | 
			
		||||
};
 | 
			
		||||
export type GroupProjectOwner = {
 | 
			
		||||
    ownerType: 'group';
 | 
			
		||||
    name: string;
 | 
			
		||||
};
 | 
			
		||||
type ProjectOwners =
 | 
			
		||||
    | [SystemOwner]
 | 
			
		||||
    | Array<UserProjectOwner | GroupProjectOwner>;
 | 
			
		||||
 | 
			
		||||
export type ProjectOwnersDictionary = Record<string, ProjectOwners>;
 | 
			
		||||
 | 
			
		||||
export type IProjectWithCountAndOwners = IProjectWithCount & {
 | 
			
		||||
    owners: ProjectOwners;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export interface IProjectOwnersReadModel {
 | 
			
		||||
    addOwners(
 | 
			
		||||
        projects: IProjectWithCount[],
 | 
			
		||||
    ): Promise<IProjectWithCountAndOwners[]>;
 | 
			
		||||
}
 | 
			
		||||
@ -50,6 +50,7 @@ import {
 | 
			
		||||
    RoleName,
 | 
			
		||||
    SYSTEM_USER_ID,
 | 
			
		||||
    type ProjectCreated,
 | 
			
		||||
    type IProjectOwnersReadModel,
 | 
			
		||||
} from '../../types';
 | 
			
		||||
import type {
 | 
			
		||||
    IProjectAccessModel,
 | 
			
		||||
@ -77,8 +78,6 @@ import type {
 | 
			
		||||
    IProjectQuery,
 | 
			
		||||
} from './project-store-type';
 | 
			
		||||
 | 
			
		||||
const getCreatedBy = (user: IUser) => user.email || user.username || 'unknown';
 | 
			
		||||
 | 
			
		||||
type Days = number;
 | 
			
		||||
type Count = number;
 | 
			
		||||
 | 
			
		||||
@ -112,6 +111,8 @@ function includes(
 | 
			
		||||
export default class ProjectService {
 | 
			
		||||
    private projectStore: IProjectStore;
 | 
			
		||||
 | 
			
		||||
    private projectOwnersReadModel: IProjectOwnersReadModel;
 | 
			
		||||
 | 
			
		||||
    private accessService: AccessService;
 | 
			
		||||
 | 
			
		||||
    private eventStore: IEventStore;
 | 
			
		||||
@ -147,6 +148,7 @@ export default class ProjectService {
 | 
			
		||||
    constructor(
 | 
			
		||||
        {
 | 
			
		||||
            projectStore,
 | 
			
		||||
            projectOwnersReadModel,
 | 
			
		||||
            eventStore,
 | 
			
		||||
            featureToggleStore,
 | 
			
		||||
            environmentStore,
 | 
			
		||||
@ -157,6 +159,7 @@ export default class ProjectService {
 | 
			
		||||
        }: Pick<
 | 
			
		||||
            IUnleashStores,
 | 
			
		||||
            | 'projectStore'
 | 
			
		||||
            | 'projectOwnersReadModel'
 | 
			
		||||
            | 'eventStore'
 | 
			
		||||
            | 'featureToggleStore'
 | 
			
		||||
            | 'environmentStore'
 | 
			
		||||
@ -174,6 +177,7 @@ export default class ProjectService {
 | 
			
		||||
        privateProjectChecker: IPrivateProjectChecker,
 | 
			
		||||
    ) {
 | 
			
		||||
        this.projectStore = projectStore;
 | 
			
		||||
        this.projectOwnersReadModel = projectOwnersReadModel;
 | 
			
		||||
        this.environmentStore = environmentStore;
 | 
			
		||||
        this.featureEnvironmentStore = featureEnvironmentStore;
 | 
			
		||||
        this.accessService = accessService;
 | 
			
		||||
@ -218,6 +222,12 @@ export default class ProjectService {
 | 
			
		||||
        return projects;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async addOwnersToProjects(
 | 
			
		||||
        projects: IProjectWithCount[],
 | 
			
		||||
    ): Promise<IProjectWithCount[]> {
 | 
			
		||||
        return this.projectOwnersReadModel.addOwners(projects);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async getProject(id: string): Promise<IProject> {
 | 
			
		||||
        return this.projectStore.get(id);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -89,6 +89,74 @@ export const projectSchema = {
 | 
			
		||||
            description:
 | 
			
		||||
                'The average time from when a feature was created to when it was enabled in the "production" environment during the current window',
 | 
			
		||||
        },
 | 
			
		||||
        owners: {
 | 
			
		||||
            description:
 | 
			
		||||
                'The users and/or groups that have the "owner" role in this project. If no such users or groups exist, the list will contain the "system" owner instead.',
 | 
			
		||||
            oneOf: [
 | 
			
		||||
                {
 | 
			
		||||
                    type: 'array',
 | 
			
		||||
                    minItems: 1,
 | 
			
		||||
                    items: {
 | 
			
		||||
                        anyOf: [
 | 
			
		||||
                            {
 | 
			
		||||
                                type: 'object',
 | 
			
		||||
                                required: ['ownerType', 'name'],
 | 
			
		||||
                                properties: {
 | 
			
		||||
                                    ownerType: {
 | 
			
		||||
                                        type: 'string',
 | 
			
		||||
                                        enum: ['user'],
 | 
			
		||||
                                    },
 | 
			
		||||
                                    name: {
 | 
			
		||||
                                        type: 'string',
 | 
			
		||||
                                        example: 'User Name',
 | 
			
		||||
                                    },
 | 
			
		||||
                                    imageUrl: {
 | 
			
		||||
                                        type: 'string',
 | 
			
		||||
                                        nullable: true,
 | 
			
		||||
                                        example:
 | 
			
		||||
                                            'https://example.com/image.jpg',
 | 
			
		||||
                                    },
 | 
			
		||||
                                    email: {
 | 
			
		||||
                                        type: 'string',
 | 
			
		||||
                                        nullable: true,
 | 
			
		||||
                                        example: 'user@example.com',
 | 
			
		||||
                                    },
 | 
			
		||||
                                },
 | 
			
		||||
                            },
 | 
			
		||||
                            {
 | 
			
		||||
                                type: 'object',
 | 
			
		||||
                                required: ['ownerType', 'name'],
 | 
			
		||||
                                properties: {
 | 
			
		||||
                                    ownerType: {
 | 
			
		||||
                                        type: 'string',
 | 
			
		||||
                                        enum: ['group'],
 | 
			
		||||
                                    },
 | 
			
		||||
                                    name: {
 | 
			
		||||
                                        type: 'string',
 | 
			
		||||
                                        example: 'Group Name',
 | 
			
		||||
                                    },
 | 
			
		||||
                                },
 | 
			
		||||
                            },
 | 
			
		||||
                        ],
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    type: 'array',
 | 
			
		||||
                    minItems: 1,
 | 
			
		||||
                    maxItems: 1,
 | 
			
		||||
                    items: {
 | 
			
		||||
                        type: 'object',
 | 
			
		||||
                        required: ['ownerType'],
 | 
			
		||||
                        properties: {
 | 
			
		||||
                            ownerType: {
 | 
			
		||||
                                type: 'string',
 | 
			
		||||
                                enum: ['system'],
 | 
			
		||||
                            },
 | 
			
		||||
                        },
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
            ],
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
    components: {},
 | 
			
		||||
} as const;
 | 
			
		||||
 | 
			
		||||
@ -40,6 +40,7 @@ import { IFeatureSearchStore } from '../features/feature-search/feature-search-s
 | 
			
		||||
import type { IInactiveUsersStore } from '../users/inactive/types/inactive-users-store-type';
 | 
			
		||||
import { ITrafficDataUsageStore } from '../features/traffic-data-usage/traffic-data-usage-store-type';
 | 
			
		||||
import { ISegmentReadModel } from '../features/segment/segment-read-model-type';
 | 
			
		||||
import { IProjectOwnersReadModel } from '../features/project/project-owners-read-model.type';
 | 
			
		||||
 | 
			
		||||
export interface IUnleashStores {
 | 
			
		||||
    accessStore: IAccessStore;
 | 
			
		||||
@ -84,6 +85,7 @@ export interface IUnleashStores {
 | 
			
		||||
    inactiveUsersStore: IInactiveUsersStore;
 | 
			
		||||
    trafficDataUsageStore: ITrafficDataUsageStore;
 | 
			
		||||
    segmentReadModel: ISegmentReadModel;
 | 
			
		||||
    projectOwnersReadModel: IProjectOwnersReadModel;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export {
 | 
			
		||||
@ -127,4 +129,5 @@ export {
 | 
			
		||||
    IFeatureSearchStore,
 | 
			
		||||
    ITrafficDataUsageStore,
 | 
			
		||||
    ISegmentReadModel,
 | 
			
		||||
    IProjectOwnersReadModel,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										2
									
								
								src/test/fixtures/store.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								src/test/fixtures/store.ts
									
									
									
									
										vendored
									
									
								
							@ -43,6 +43,7 @@ import FakeFeatureSearchStore from '../../lib/features/feature-search/fake-featu
 | 
			
		||||
import { FakeInactiveUsersStore } from '../../lib/users/inactive/fakes/fake-inactive-users-store';
 | 
			
		||||
import { FakeTrafficDataUsageStore } from '../../lib/features/traffic-data-usage/fake-traffic-data-usage-store';
 | 
			
		||||
import { FakeSegmentReadModel } from '../../lib/features/segment/fake-segment-read-model';
 | 
			
		||||
import { FakeProjectOwnersReadModel } from '../../lib/features/project/fake-project-owners-read-model';
 | 
			
		||||
 | 
			
		||||
const db = {
 | 
			
		||||
    select: () => ({
 | 
			
		||||
@ -95,6 +96,7 @@ const createStores: () => IUnleashStores = () => {
 | 
			
		||||
        inactiveUsersStore: new FakeInactiveUsersStore(),
 | 
			
		||||
        trafficDataUsageStore: new FakeTrafficDataUsageStore(),
 | 
			
		||||
        segmentReadModel: new FakeSegmentReadModel(),
 | 
			
		||||
        projectOwnersReadModel: new FakeProjectOwnersReadModel(),
 | 
			
		||||
    };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user