diff --git a/frontend/src/component/project/Project/ProjectInsights/ChangeRequests/ChangeRequests.test.tsx b/frontend/src/component/project/Project/ProjectInsights/ChangeRequests/ChangeRequests.test.tsx
index f3c28f1747..c7abfec409 100644
--- a/frontend/src/component/project/Project/ProjectInsights/ChangeRequests/ChangeRequests.test.tsx
+++ b/frontend/src/component/project/Project/ProjectInsights/ChangeRequests/ChangeRequests.test.tsx
@@ -12,6 +12,18 @@ const setupEnterpriseApi = () => {
current: { enterprise: 'present' },
},
});
+ testServerRoute(
+ server,
+ '/api/admin/projects/default/change-requests/count',
+ {
+ total: 14,
+ approved: 2,
+ applied: 0,
+ rejected: 0,
+ reviewRequired: 10,
+ scheduled: 2,
+ },
+ );
};
const setupOssApi = () => {
@@ -22,23 +34,11 @@ const setupOssApi = () => {
});
};
-const changeRequests = {
- applied: 0,
- total: 0,
- approved: 0,
- scheduled: 0,
- reviewRequired: 0,
- rejected: 0,
-};
-
test('Show enterprise hints', async () => {
setupOssApi();
render(
- }
- />
+ } />
,
{
route: '/projects/default',
@@ -52,10 +52,7 @@ test('Show change requests info', async () => {
setupEnterpriseApi();
render(
- }
- />
+ } />
,
{
route: '/projects/default',
@@ -63,4 +60,7 @@ test('Show change requests info', async () => {
);
await screen.findByText('To be applied');
+ await screen.findByText('10');
+ await screen.findByText('4');
+ await screen.findByText('14');
});
diff --git a/frontend/src/component/project/Project/ProjectInsights/ChangeRequests/ChangeRequests.tsx b/frontend/src/component/project/Project/ProjectInsights/ChangeRequests/ChangeRequests.tsx
index 4b321a2463..ff25afb72e 100644
--- a/frontend/src/component/project/Project/ProjectInsights/ChangeRequests/ChangeRequests.tsx
+++ b/frontend/src/component/project/Project/ProjectInsights/ChangeRequests/ChangeRequests.tsx
@@ -4,8 +4,7 @@ import { Link } from 'react-router-dom';
import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
import { PremiumFeature } from 'component/common/PremiumFeature/PremiumFeature';
-import type { ProjectInsightsSchemaChangeRequests } from '../../../../../openapi';
-import type { FC } from 'react';
+import { useChangeRequestsCount } from 'hooks/api/getters/useChangeRequestsCount/useChangeRequestsCount';
const Container = styled(Box)(({ theme }) => ({
display: 'flex',
@@ -83,14 +82,13 @@ const BigNumber = styled(Typography)(({ theme }) => ({
color: theme.palette.text.primary,
}));
-export const ChangeRequests: FC<{
- changeRequests: ProjectInsightsSchemaChangeRequests;
-}> = ({ changeRequests }) => {
+export const ChangeRequests = () => {
const projectId = useRequiredPathParam('projectId');
const { isOss, isPro } = useUiConfig();
+ const { data } = useChangeRequestsCount(projectId);
const { total, applied, rejected, reviewRequired, scheduled, approved } =
- changeRequests;
+ data;
const toBeApplied = scheduled + approved;
if (isOss() || isPro()) {
diff --git a/frontend/src/component/project/Project/ProjectInsights/ProjectInsights.tsx b/frontend/src/component/project/Project/ProjectInsights/ProjectInsights.tsx
index 78034b9112..de89803c4c 100644
--- a/frontend/src/component/project/Project/ProjectInsights/ProjectInsights.tsx
+++ b/frontend/src/component/project/Project/ProjectInsights/ProjectInsights.tsx
@@ -61,9 +61,7 @@ export const ProjectInsights = () => {
- {data.changeRequests && (
-
- )}
+
);
diff --git a/frontend/src/component/project/Project/ProjectOverviewChangeRequests.tsx b/frontend/src/component/project/Project/ProjectOverviewChangeRequests.tsx
index 4c97bd3c4d..702c737adb 100644
--- a/frontend/src/component/project/Project/ProjectOverviewChangeRequests.tsx
+++ b/frontend/src/component/project/Project/ProjectOverviewChangeRequests.tsx
@@ -48,7 +48,7 @@ export const ProjectOverviewChangeRequests: FC<{ project: string }> = ({
useChangeRequestsEnabled(project);
const { data } = useChangeRequestsCount(project);
- if (!isChangeRequestConfiguredInAnyEnv) {
+ if (!isChangeRequestConfiguredInAnyEnv()) {
return null;
}
diff --git a/frontend/src/hooks/api/getters/useProjectInsights/useProjectInsights.ts b/frontend/src/hooks/api/getters/useProjectInsights/useProjectInsights.ts
index 89d6274287..fdb43ac4a5 100644
--- a/frontend/src/hooks/api/getters/useProjectInsights/useProjectInsights.ts
+++ b/frontend/src/hooks/api/getters/useProjectInsights/useProjectInsights.ts
@@ -49,14 +49,6 @@ const placeholderData: ProjectInsightsSchema = {
currentMembers: 0,
change: 0,
},
- changeRequests: {
- total: 0,
- applied: 0,
- approved: 0,
- rejected: 0,
- reviewRequired: 0,
- scheduled: 0,
- },
};
export const useProjectInsights = (projectId: string) => {
diff --git a/frontend/src/openapi/models/index.ts b/frontend/src/openapi/models/index.ts
index 0e91fcaff1..3ddae3fa96 100644
--- a/frontend/src/openapi/models/index.ts
+++ b/frontend/src/openapi/models/index.ts
@@ -879,7 +879,6 @@ export * from './projectCreatedSchemaMode';
export * from './projectDoraMetricsSchema';
export * from './projectEnvironmentSchema';
export * from './projectInsightsSchema';
-export * from './projectInsightsSchemaChangeRequests';
export * from './projectInsightsSchemaHealth';
export * from './projectInsightsSchemaMembers';
export * from './projectOverviewSchema';
diff --git a/frontend/src/openapi/models/projectInsightsSchema.ts b/frontend/src/openapi/models/projectInsightsSchema.ts
index d85187bff6..95246e6b23 100644
--- a/frontend/src/openapi/models/projectInsightsSchema.ts
+++ b/frontend/src/openapi/models/projectInsightsSchema.ts
@@ -3,7 +3,6 @@
* Do not edit manually.
* See `gen:api` script in package.json
*/
-import type { ProjectInsightsSchemaChangeRequests } from './projectInsightsSchemaChangeRequests';
import type { FeatureTypeCountSchema } from './featureTypeCountSchema';
import type { ProjectInsightsSchemaHealth } from './projectInsightsSchemaHealth';
import type { ProjectDoraMetricsSchema } from './projectDoraMetricsSchema';
@@ -14,8 +13,6 @@ import type { ProjectStatsSchema } from './projectStatsSchema';
* A high-level overview of a project insights. It contains information such as project statistics, overall health, types of flags, members overview, change requests overview.
*/
export interface ProjectInsightsSchema {
- /** Count of change requests in different stages of the [process](https://docs.getunleash.io/reference/change-requests#change-request-flow). Only for enterprise users. */
- changeRequests?: ProjectInsightsSchemaChangeRequests;
/** The number of features of each type */
featureTypeCounts: FeatureTypeCountSchema[];
/** Health summary of the project */
diff --git a/frontend/src/openapi/models/projectInsightsSchemaChangeRequests.ts b/frontend/src/openapi/models/projectInsightsSchemaChangeRequests.ts
deleted file mode 100644
index 5ce8e17e6b..0000000000
--- a/frontend/src/openapi/models/projectInsightsSchemaChangeRequests.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-/**
- * Generated by Orval
- * Do not edit manually.
- * See `gen:api` script in package.json
- */
-
-/**
- * Count of change requests in different stages of the [process](https://docs.getunleash.io/reference/change-requests#change-request-flow). Only for enterprise users.
- */
-export type ProjectInsightsSchemaChangeRequests = {
- /** The number of applied change requests */
- applied: number;
- /** The number of approved change requests */
- approved: number;
- /** The number of rejected change requests */
- rejected: number;
- /** The number of change requests awaiting the review */
- reviewRequired: number;
- /** The number of scheduled change requests */
- scheduled: number;
- /** The number of total change requests in this project */
- total: number;
-};
diff --git a/src/lib/features/project-insights/createProjectInsightsService.ts b/src/lib/features/project-insights/createProjectInsightsService.ts
index 8793d4ec68..68b46ac394 100644
--- a/src/lib/features/project-insights/createProjectInsightsService.ts
+++ b/src/lib/features/project-insights/createProjectInsightsService.ts
@@ -8,8 +8,6 @@ import FeatureTypeStore from '../../db/feature-type-store';
import FakeFeatureTypeStore from '../../../test/fixtures/fake-feature-type-store';
import { ProjectInsightsService } from './project-insights-service';
import ProjectStore from '../project/project-store';
-import { ProjectInsightsReadModel } from './project-insights-read-model';
-import { FakeProjectInsightsReadModel } from './fake-project-insights-read-model';
import FeatureStrategiesStore from '../feature-toggle/feature-toggle-strategies-store';
import FakeFeatureStrategiesStore from '../feature-toggle/fakes/fake-feature-strategies-store';
@@ -39,18 +37,14 @@ export const createProjectInsightsService = (
getLogger,
flagResolver,
);
- const projectInsightsReadModel = new ProjectInsightsReadModel(db);
- return new ProjectInsightsService(
- {
- projectStore,
- featureToggleStore,
- featureTypeStore,
- projectStatsStore,
- featureStrategiesStore,
- },
- projectInsightsReadModel,
- );
+ return new ProjectInsightsService({
+ projectStore,
+ featureToggleStore,
+ featureTypeStore,
+ projectStatsStore,
+ featureStrategiesStore,
+ });
};
export const createFakeProjectInsightsService = () => {
@@ -59,23 +53,18 @@ export const createFakeProjectInsightsService = () => {
const featureTypeStore = new FakeFeatureTypeStore();
const projectStatsStore = new FakeProjectStatsStore();
const featureStrategiesStore = new FakeFeatureStrategiesStore();
- const projectInsightsReadModel = new FakeProjectInsightsReadModel();
- const projectInsightsService = new ProjectInsightsService(
- {
- projectStore,
- featureToggleStore,
- featureTypeStore,
- projectStatsStore,
- featureStrategiesStore,
- },
- projectInsightsReadModel,
- );
+ const projectInsightsService = new ProjectInsightsService({
+ projectStore,
+ featureToggleStore,
+ featureTypeStore,
+ projectStatsStore,
+ featureStrategiesStore,
+ });
return {
projectInsightsService,
projectStatsStore,
featureToggleStore,
projectStore,
- projectInsightsReadModel,
};
};
diff --git a/src/lib/features/project-insights/fake-project-insights-read-model.ts b/src/lib/features/project-insights/fake-project-insights-read-model.ts
deleted file mode 100644
index 01084aef2b..0000000000
--- a/src/lib/features/project-insights/fake-project-insights-read-model.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-import type {
- ChangeRequestCounts,
- IProjectInsightsReadModel,
-} from './project-insights-read-model-type';
-
-const changeRequestCounts: ChangeRequestCounts = {
- total: 0,
- approved: 0,
- applied: 0,
- rejected: 0,
- reviewRequired: 0,
- scheduled: 0,
-};
-
-export class FakeProjectInsightsReadModel implements IProjectInsightsReadModel {
- private counts: Record = {};
-
- async getChangeRequests(projectId: string): Promise {
- return this.counts[projectId] ?? changeRequestCounts;
- }
-
- async setChangeRequests(projectId: string, counts: ChangeRequestCounts) {
- this.counts[projectId] = counts;
- }
-}
diff --git a/src/lib/features/project-insights/project-insights-read-model-type.ts b/src/lib/features/project-insights/project-insights-read-model-type.ts
deleted file mode 100644
index f100d77299..0000000000
--- a/src/lib/features/project-insights/project-insights-read-model-type.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-export type ChangeRequestCounts = {
- total: number;
- approved: number;
- applied: number;
- rejected: number;
- reviewRequired: number;
- scheduled: number;
-};
-
-export interface IProjectInsightsReadModel {
- getChangeRequests(projectId: string): Promise;
-}
diff --git a/src/lib/features/project-insights/project-insights-read-model.test.ts b/src/lib/features/project-insights/project-insights-read-model.test.ts
deleted file mode 100644
index ff8fdd20b1..0000000000
--- a/src/lib/features/project-insights/project-insights-read-model.test.ts
+++ /dev/null
@@ -1,66 +0,0 @@
-import dbInit, { type ITestDb } from '../../../test/e2e/helpers/database-init';
-import getLogger from '../../../test/fixtures/no-logger';
-import type { IUser } from '../../types';
-import type { IProjectInsightsReadModel } from './project-insights-read-model-type';
-import {
- type ChangeRequestDBState,
- ProjectInsightsReadModel,
-} from './project-insights-read-model';
-
-let projectInsightsReadModel: IProjectInsightsReadModel;
-let user: IUser;
-let db: ITestDb;
-const projectId = 'default';
-
-beforeAll(async () => {
- db = await dbInit('project_insights_read_model', getLogger);
- projectInsightsReadModel = new ProjectInsightsReadModel(db.rawDatabase);
- user = await db.stores.userStore.insert({
- username: 'test',
- });
-});
-
-afterAll(async () => {
- await db.destroy();
-});
-
-beforeEach(async () => {
- await db.rawDatabase.table('change_requests').delete();
-});
-
-const createChangeRequest = (id: number, state: string) =>
- db.rawDatabase.table('change_requests').insert({
- id,
- state,
- environment: 'default',
- project: projectId,
- created_by: user.id,
- });
-
-test('can read change request status counts', async () => {
- const states: ChangeRequestDBState[] = [
- 'Approved',
- 'Approved',
- 'Applied',
- 'Rejected',
- 'Scheduled',
- 'In review',
- 'Draft',
- 'Cancelled',
- ];
- await Promise.all(
- states.map((state, id) => createChangeRequest(id, state)),
- );
-
- const changeRequests =
- await projectInsightsReadModel.getChangeRequests(projectId);
-
- expect(changeRequests).toEqual({
- total: 6,
- approved: 2,
- applied: 1,
- rejected: 1,
- reviewRequired: 1,
- scheduled: 1,
- });
-});
diff --git a/src/lib/features/project-insights/project-insights-read-model.ts b/src/lib/features/project-insights/project-insights-read-model.ts
deleted file mode 100644
index e3fbf8e3a3..0000000000
--- a/src/lib/features/project-insights/project-insights-read-model.ts
+++ /dev/null
@@ -1,61 +0,0 @@
-import type {
- ChangeRequestCounts,
- IProjectInsightsReadModel,
-} from './project-insights-read-model-type';
-import type { Db } from '../../db/db';
-
-export type ChangeRequestDBState =
- | 'Draft'
- | 'Cancelled'
- | 'Approved'
- | 'In review'
- | 'Applied'
- | 'Scheduled'
- | 'Rejected';
-
-export class ProjectInsightsReadModel implements IProjectInsightsReadModel {
- private db: Db;
-
- constructor(db: Db) {
- this.db = db;
- }
-
- async getChangeRequests(projectId: string): Promise {
- const changeRequestCounts: ChangeRequestCounts = {
- total: 0,
- approved: 0,
- applied: 0,
- rejected: 0,
- reviewRequired: 0,
- scheduled: 0,
- };
-
- const rows: Array<{ state: ChangeRequestDBState; count: string }> =
- await this.db('change_requests')
- .select('state')
- .count('* as count')
- .where('project', '=', projectId)
- .groupBy('state');
-
- return rows.reduce((acc, current) => {
- if (current.state === 'Applied') {
- acc.applied = Number(current.count);
- acc.total += Number(current.count);
- } else if (current.state === 'Approved') {
- acc.approved = Number(current.count);
- acc.total += Number(current.count);
- } else if (current.state === 'Rejected') {
- acc.rejected = Number(current.count);
- acc.total += Number(current.count);
- } else if (current.state === 'In review') {
- acc.reviewRequired = Number(current.count);
- acc.total += Number(current.count);
- } else if (current.state === 'Scheduled') {
- acc.scheduled = Number(current.count);
- acc.total += Number(current.count);
- }
-
- return acc;
- }, changeRequestCounts);
- }
-}
diff --git a/src/lib/features/project-insights/project-insights-service.test.ts b/src/lib/features/project-insights/project-insights-service.test.ts
index d72c819866..65bcf5ffce 100644
--- a/src/lib/features/project-insights/project-insights-service.test.ts
+++ b/src/lib/features/project-insights/project-insights-service.test.ts
@@ -6,21 +6,12 @@ test('Return basic insights', async () => {
projectStatsStore,
featureToggleStore,
projectStore,
- projectInsightsReadModel,
} = createFakeProjectInsightsService();
await featureToggleStore.create('default', {
name: 'irrelevant',
createdByUserId: 1,
type: 'release',
});
- await projectInsightsReadModel.setChangeRequests('default', {
- total: 5,
- approved: 1,
- applied: 1,
- rejected: 1,
- reviewRequired: 1,
- scheduled: 1,
- });
await projectStore.create({
id: 'default',
name: 'irrelevant',
@@ -57,14 +48,6 @@ test('Return basic insights', async () => {
rating: 100,
},
leadTime: { features: [], projectAverage: 0 },
- changeRequests: {
- total: 5,
- approved: 1,
- applied: 1,
- rejected: 1,
- reviewRequired: 1,
- scheduled: 1,
- },
members: { currentMembers: 0, change: 0 },
});
});
diff --git a/src/lib/features/project-insights/project-insights-service.ts b/src/lib/features/project-insights/project-insights-service.ts
index eed9750dda..e98d134e4e 100644
--- a/src/lib/features/project-insights/project-insights-service.ts
+++ b/src/lib/features/project-insights/project-insights-service.ts
@@ -13,7 +13,6 @@ import type {
ProjectInsightsSchema,
} from '../../openapi';
import { calculateProjectHealth } from '../../domain/project-health/project-health';
-import type { IProjectInsightsReadModel } from './project-insights-read-model-type';
import { subDays } from 'date-fns';
export class ProjectInsightsService {
@@ -27,31 +26,25 @@ export class ProjectInsightsService {
private projectStatsStore: IProjectStatsStore;
- private projectInsightsReadModel: IProjectInsightsReadModel;
-
- constructor(
- {
- projectStore,
- featureToggleStore,
- featureTypeStore,
- projectStatsStore,
- featureStrategiesStore,
- }: Pick<
- IUnleashStores,
- | 'projectStore'
- | 'featureToggleStore'
- | 'projectStatsStore'
- | 'featureTypeStore'
- | 'featureStrategiesStore'
- >,
- projectInsightsReadModel: IProjectInsightsReadModel,
- ) {
+ constructor({
+ projectStore,
+ featureToggleStore,
+ featureTypeStore,
+ projectStatsStore,
+ featureStrategiesStore,
+ }: Pick<
+ IUnleashStores,
+ | 'projectStore'
+ | 'featureToggleStore'
+ | 'projectStatsStore'
+ | 'featureTypeStore'
+ | 'featureStrategiesStore'
+ >) {
this.projectStore = projectStore;
this.featureToggleStore = featureToggleStore;
this.featureTypeStore = featureTypeStore;
this.featureStrategiesStore = featureStrategiesStore;
this.projectStatsStore = projectStatsStore;
- this.projectInsightsReadModel = projectInsightsReadModel;
}
async getDoraMetrics(projectId: string): Promise {
@@ -143,31 +136,23 @@ export class ProjectInsightsService {
}
async getProjectInsights(projectId: string) {
- const [
- stats,
- featureTypeCounts,
- health,
- leadTime,
- changeRequests,
- members,
- ] = await Promise.all([
- this.projectStatsStore.getProjectStats(projectId),
- this.featureToggleStore.getFeatureTypeCounts({
- projectId,
- archived: false,
- }),
- this.getHealthInsights(projectId),
- this.getDoraMetrics(projectId),
- this.projectInsightsReadModel.getChangeRequests(projectId),
- this.getProjectMembers(projectId),
- ]);
+ const [stats, featureTypeCounts, health, leadTime, members] =
+ await Promise.all([
+ this.projectStatsStore.getProjectStats(projectId),
+ this.featureToggleStore.getFeatureTypeCounts({
+ projectId,
+ archived: false,
+ }),
+ this.getHealthInsights(projectId),
+ this.getDoraMetrics(projectId),
+ this.getProjectMembers(projectId),
+ ]);
return {
stats,
featureTypeCounts,
health,
leadTime,
- changeRequests,
members,
};
}
diff --git a/src/lib/features/project-insights/projects-insights.e2e.test.ts b/src/lib/features/project-insights/projects-insights.e2e.test.ts
index 94b93138d7..a7205c1cda 100644
--- a/src/lib/features/project-insights/projects-insights.e2e.test.ts
+++ b/src/lib/features/project-insights/projects-insights.e2e.test.ts
@@ -53,13 +53,5 @@ test('project insights happy path', async () => {
staleCount: 0,
rating: 100,
},
- changeRequests: {
- total: 0,
- approved: 0,
- applied: 0,
- rejected: 0,
- reviewRequired: 0,
- scheduled: 0,
- },
});
});
diff --git a/src/lib/openapi/spec/project-insights-schema.ts b/src/lib/openapi/spec/project-insights-schema.ts
index f06ce050f3..f6f97705f3 100644
--- a/src/lib/openapi/spec/project-insights-schema.ts
+++ b/src/lib/openapi/spec/project-insights-schema.ts
@@ -80,53 +80,6 @@ export const projectInsightsSchema = {
},
description: 'Active/inactive users summary',
},
- changeRequests: {
- type: 'object',
- required: [
- 'total',
- 'applied',
- 'rejected',
- 'reviewRequired',
- 'approved',
- 'scheduled',
- ],
- properties: {
- total: {
- type: 'number',
- description:
- 'The number of total change requests in this project',
- example: 10,
- },
- applied: {
- type: 'number',
- description: 'The number of applied change requests',
- example: 5,
- },
- rejected: {
- type: 'number',
- description: 'The number of rejected change requests',
- example: 2,
- },
- reviewRequired: {
- type: 'number',
- description:
- 'The number of change requests awaiting the review',
- example: 2,
- },
- approved: {
- type: 'number',
- description: 'The number of approved change requests',
- example: 1,
- },
- scheduled: {
- type: 'number',
- description: 'The number of scheduled change requests',
- example: 1,
- },
- },
- description:
- 'Count of change requests in different stages of the [process](https://docs.getunleash.io/reference/change-requests#change-request-flow). Only for enterprise users.',
- },
},
components: {
schemas: {