1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-02-09 00:18:00 +01:00

feat: exclude archived projects from insights and project stats (#7843)

This commit is contained in:
Mateusz Kwasniewski 2024-08-13 10:00:04 +02:00 committed by GitHub
parent 0934c6ccd8
commit fcf1329816
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 60 additions and 21 deletions

View File

@ -1,9 +1,9 @@
import type { IEnvironmentStore } from '../../../lib/features/project-environments/environment-store-type'; import type { IEnvironmentStore } from '../project-environments/environment-store-type';
import dbInit, { type ITestDb } from '../helpers/database-init'; import dbInit, { type ITestDb } from '../../../test/e2e/helpers/database-init';
import getLogger from '../../fixtures/no-logger'; import getLogger from '../../../test/fixtures/no-logger';
import type { IProjectStore, IUnleashStores } from '../../../lib/types'; import type { IProjectStore, IUnleashStores } from '../../types';
import type { IProjectInsert } from '../../../lib/features/project/project-store-type'; import type { IProjectInsert } from './project-store-type';
let stores: IUnleashStores; let stores: IUnleashStores;
let db: ITestDb; let db: ITestDb;
@ -11,7 +11,9 @@ let projectStore: IProjectStore;
let environmentStore: IEnvironmentStore; let environmentStore: IEnvironmentStore;
beforeAll(async () => { beforeAll(async () => {
db = await dbInit('project_store_serial', getLogger); db = await dbInit('project_store_serial', getLogger, {
experimental: { flags: { archiveProjects: true } },
});
stores = db.stores; stores = db.stores;
projectStore = stores.projectStore; projectStore = stores.projectStore;
environmentStore = stores.environmentStore; environmentStore = stores.environmentStore;
@ -21,6 +23,25 @@ afterAll(async () => {
await db.destroy(); await db.destroy();
}); });
test('should exclude archived projects', async () => {
const project = {
id: 'archive-me',
name: 'archive-me',
description: 'Blah',
mode: 'open' as const,
};
await projectStore.create(project);
await projectStore.archive(project.id);
const allProjects = await projectStore.getAll();
const count = await projectStore.count();
const modeCounts = await projectStore.getProjectModeCounts();
expect(allProjects).toMatchObject([{ id: 'default' }]);
expect(count).toBe(1);
expect(modeCounts).toMatchObject([{ mode: 'open', count: 1 }]);
});
test('should have default project', async () => { test('should have default project', async () => {
const project = await projectStore.get('default'); const project = await projectStore.get('default');
expect(project).toBeDefined(); expect(project).toBeDefined();

View File

@ -131,8 +131,9 @@ class ProjectStore implements IProjectStore {
) )
.leftJoin('project_stats', 'project_stats.project', 'projects.id') .leftJoin('project_stats', 'project_stats.project', 'projects.id')
.orderBy('projects.name', 'asc'); .orderBy('projects.name', 'asc');
if (this.flagResolver.isEnabled('archiveProjects')) { if (this.flagResolver.isEnabled('archiveProjects')) {
projects = projects.where('projects.archived_at', null); projects = projects.where(`${TABLE}.archived_at`, null);
} }
if (query) { if (query) {
@ -221,12 +222,18 @@ class ProjectStore implements IProjectStore {
} }
async getAll(query: IProjectQuery = {}): Promise<IProject[]> { async getAll(query: IProjectQuery = {}): Promise<IProject[]> {
const rows = await this.db let projects = this.db
.select(COLUMNS) .select(COLUMNS)
.from(TABLE) .from(TABLE)
.where(query) .where(query)
.orderBy('name', 'asc'); .orderBy('name', 'asc');
if (this.flagResolver.isEnabled('archiveProjects')) {
projects = projects.where(`${TABLE}.archived_at`, null);
}
const rows = await projects;
return rows.map(this.mapRow); return rows.map(this.mapRow);
} }
@ -706,14 +713,17 @@ class ProjectStore implements IProjectStore {
} }
async count(): Promise<number> { async count(): Promise<number> {
return this.db let count = this.db.from(TABLE).count('*');
.from(TABLE)
.count('*') if (this.flagResolver.isEnabled('archiveProjects')) {
.then((res) => Number(res[0].count)); count = count.where(`${TABLE}.archived_at`, null);
}
return count.then((res) => Number(res[0].count));
} }
async getProjectModeCounts(): Promise<ProjectModeCount[]> { async getProjectModeCounts(): Promise<ProjectModeCount[]> {
const result: ProjectModeCount[] = await this.db let query = this.db
.select( .select(
this.db.raw( this.db.raw(
`COALESCE(${SETTINGS_TABLE}.project_mode, 'open') as mode`, `COALESCE(${SETTINGS_TABLE}.project_mode, 'open') as mode`,
@ -729,11 +739,18 @@ class ProjectStore implements IProjectStore {
.groupBy( .groupBy(
this.db.raw(`COALESCE(${SETTINGS_TABLE}.project_mode, 'open')`), this.db.raw(`COALESCE(${SETTINGS_TABLE}.project_mode, 'open')`),
); );
if (this.flagResolver.isEnabled('archiveProjects')) {
query = query.where(`${TABLE}.archived_at`, null);
}
const result: ProjectModeCount[] = await query;
return result.map(this.mapProjectModeCount); return result.map(this.mapProjectModeCount);
} }
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
mapProjectModeCount(row): ProjectModeCount { private mapProjectModeCount(row): ProjectModeCount {
return { return {
mode: row.mode, mode: row.mode,
count: Number(row.count), count: Number(row.count),
@ -741,7 +758,7 @@ class ProjectStore implements IProjectStore {
} }
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
mapLinkRow(row): IEnvironmentProjectLink { private mapLinkRow(row): IEnvironmentProjectLink {
return { return {
environmentName: row.environment_name, environmentName: row.environment_name,
projectId: row.project_id, projectId: row.project_id,
@ -749,7 +766,7 @@ class ProjectStore implements IProjectStore {
} }
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
mapRow(row): IProject { private mapRow(row): IProject {
if (!row) { if (!row) {
throw new NotFoundError('No project found'); throw new NotFoundError('No project found');
} }
@ -772,7 +789,7 @@ class ProjectStore implements IProjectStore {
}; };
} }
mapProjectEnvironmentRow(row: { private mapProjectEnvironmentRow(row: {
environment_name: string; environment_name: string;
default_strategy: CreateFeatureStrategySchema; default_strategy: CreateFeatureStrategySchema;
}): ProjectEnvironment { }): ProjectEnvironment {
@ -785,7 +802,7 @@ class ProjectStore implements IProjectStore {
}; };
} }
getAggregatedApplicationsData(rows): IProjectApplication[] { private getAggregatedApplicationsData(rows): IProjectApplication[] {
const entriesMap = new Map<string, IProjectApplication>(); const entriesMap = new Map<string, IProjectApplication>();
rows.forEach((row) => { rows.forEach((row) => {

View File

@ -50,7 +50,7 @@ export default class FakeProjectStore implements IProjectStore {
async getProjectsWithCounts(): Promise<IProjectWithCount[]> { async getProjectsWithCounts(): Promise<IProjectWithCount[]> {
return this.projects return this.projects
.filter((project) => project.archivedAt !== null) .filter((project) => project.archivedAt === null)
.map((project) => { .map((project) => {
return { return {
...project, ...project,
@ -105,7 +105,8 @@ export default class FakeProjectStore implements IProjectStore {
destroy(): void {} destroy(): void {}
async count(): Promise<number> { async count(): Promise<number> {
return this.projects.length; return this.projects.filter((project) => project.archivedAt === null)
.length;
} }
async get(key: string): Promise<IProject> { async get(key: string): Promise<IProject> {
@ -117,7 +118,7 @@ export default class FakeProjectStore implements IProjectStore {
} }
async getAll(): Promise<IProject[]> { async getAll(): Promise<IProject[]> {
return this.projects; return this.projects.filter((project) => project.archivedAt === null);
} }
// eslint-disable-next-line @typescript-eslint/no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars