mirror of
https://github.com/Unleash/unleash.git
synced 2025-03-23 00:16:25 +01:00
refactor: remove change requests from project insights api (#6685)
This commit is contained in:
parent
501da974d6
commit
d4f52cdb54
@ -12,6 +12,18 @@ const setupEnterpriseApi = () => {
|
|||||||
current: { enterprise: 'present' },
|
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 = () => {
|
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 () => {
|
test('Show enterprise hints', async () => {
|
||||||
setupOssApi();
|
setupOssApi();
|
||||||
render(
|
render(
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route
|
<Route path={'/projects/:projectId'} element={<ChangeRequests />} />
|
||||||
path={'/projects/:projectId'}
|
|
||||||
element={<ChangeRequests changeRequests={changeRequests} />}
|
|
||||||
/>
|
|
||||||
</Routes>,
|
</Routes>,
|
||||||
{
|
{
|
||||||
route: '/projects/default',
|
route: '/projects/default',
|
||||||
@ -52,10 +52,7 @@ test('Show change requests info', async () => {
|
|||||||
setupEnterpriseApi();
|
setupEnterpriseApi();
|
||||||
render(
|
render(
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route
|
<Route path={'/projects/:projectId'} element={<ChangeRequests />} />
|
||||||
path={'/projects/:projectId'}
|
|
||||||
element={<ChangeRequests changeRequests={changeRequests} />}
|
|
||||||
/>
|
|
||||||
</Routes>,
|
</Routes>,
|
||||||
{
|
{
|
||||||
route: '/projects/default',
|
route: '/projects/default',
|
||||||
@ -63,4 +60,7 @@ test('Show change requests info', async () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
await screen.findByText('To be applied');
|
await screen.findByText('To be applied');
|
||||||
|
await screen.findByText('10');
|
||||||
|
await screen.findByText('4');
|
||||||
|
await screen.findByText('14');
|
||||||
});
|
});
|
||||||
|
@ -4,8 +4,7 @@ import { Link } from 'react-router-dom';
|
|||||||
import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
|
import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
|
||||||
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
|
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
|
||||||
import { PremiumFeature } from 'component/common/PremiumFeature/PremiumFeature';
|
import { PremiumFeature } from 'component/common/PremiumFeature/PremiumFeature';
|
||||||
import type { ProjectInsightsSchemaChangeRequests } from '../../../../../openapi';
|
import { useChangeRequestsCount } from 'hooks/api/getters/useChangeRequestsCount/useChangeRequestsCount';
|
||||||
import type { FC } from 'react';
|
|
||||||
|
|
||||||
const Container = styled(Box)(({ theme }) => ({
|
const Container = styled(Box)(({ theme }) => ({
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
@ -83,14 +82,13 @@ const BigNumber = styled(Typography)(({ theme }) => ({
|
|||||||
color: theme.palette.text.primary,
|
color: theme.palette.text.primary,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export const ChangeRequests: FC<{
|
export const ChangeRequests = () => {
|
||||||
changeRequests: ProjectInsightsSchemaChangeRequests;
|
|
||||||
}> = ({ changeRequests }) => {
|
|
||||||
const projectId = useRequiredPathParam('projectId');
|
const projectId = useRequiredPathParam('projectId');
|
||||||
const { isOss, isPro } = useUiConfig();
|
const { isOss, isPro } = useUiConfig();
|
||||||
|
const { data } = useChangeRequestsCount(projectId);
|
||||||
|
|
||||||
const { total, applied, rejected, reviewRequired, scheduled, approved } =
|
const { total, applied, rejected, reviewRequired, scheduled, approved } =
|
||||||
changeRequests;
|
data;
|
||||||
const toBeApplied = scheduled + approved;
|
const toBeApplied = scheduled + approved;
|
||||||
|
|
||||||
if (isOss() || isPro()) {
|
if (isOss() || isPro()) {
|
||||||
|
@ -61,9 +61,7 @@ export const ProjectInsights = () => {
|
|||||||
<ProjectMembers projectId={projectId} members={data.members} />
|
<ProjectMembers projectId={projectId} members={data.members} />
|
||||||
</NarrowContainer>
|
</NarrowContainer>
|
||||||
<WideContainer>
|
<WideContainer>
|
||||||
{data.changeRequests && (
|
<ChangeRequests />
|
||||||
<ChangeRequests changeRequests={data.changeRequests} />
|
|
||||||
)}
|
|
||||||
</WideContainer>
|
</WideContainer>
|
||||||
</Grid>
|
</Grid>
|
||||||
);
|
);
|
||||||
|
@ -48,7 +48,7 @@ export const ProjectOverviewChangeRequests: FC<{ project: string }> = ({
|
|||||||
useChangeRequestsEnabled(project);
|
useChangeRequestsEnabled(project);
|
||||||
const { data } = useChangeRequestsCount(project);
|
const { data } = useChangeRequestsCount(project);
|
||||||
|
|
||||||
if (!isChangeRequestConfiguredInAnyEnv) {
|
if (!isChangeRequestConfiguredInAnyEnv()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,14 +49,6 @@ const placeholderData: ProjectInsightsSchema = {
|
|||||||
currentMembers: 0,
|
currentMembers: 0,
|
||||||
change: 0,
|
change: 0,
|
||||||
},
|
},
|
||||||
changeRequests: {
|
|
||||||
total: 0,
|
|
||||||
applied: 0,
|
|
||||||
approved: 0,
|
|
||||||
rejected: 0,
|
|
||||||
reviewRequired: 0,
|
|
||||||
scheduled: 0,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useProjectInsights = (projectId: string) => {
|
export const useProjectInsights = (projectId: string) => {
|
||||||
|
@ -879,7 +879,6 @@ export * from './projectCreatedSchemaMode';
|
|||||||
export * from './projectDoraMetricsSchema';
|
export * from './projectDoraMetricsSchema';
|
||||||
export * from './projectEnvironmentSchema';
|
export * from './projectEnvironmentSchema';
|
||||||
export * from './projectInsightsSchema';
|
export * from './projectInsightsSchema';
|
||||||
export * from './projectInsightsSchemaChangeRequests';
|
|
||||||
export * from './projectInsightsSchemaHealth';
|
export * from './projectInsightsSchemaHealth';
|
||||||
export * from './projectInsightsSchemaMembers';
|
export * from './projectInsightsSchemaMembers';
|
||||||
export * from './projectOverviewSchema';
|
export * from './projectOverviewSchema';
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
* Do not edit manually.
|
* Do not edit manually.
|
||||||
* See `gen:api` script in package.json
|
* See `gen:api` script in package.json
|
||||||
*/
|
*/
|
||||||
import type { ProjectInsightsSchemaChangeRequests } from './projectInsightsSchemaChangeRequests';
|
|
||||||
import type { FeatureTypeCountSchema } from './featureTypeCountSchema';
|
import type { FeatureTypeCountSchema } from './featureTypeCountSchema';
|
||||||
import type { ProjectInsightsSchemaHealth } from './projectInsightsSchemaHealth';
|
import type { ProjectInsightsSchemaHealth } from './projectInsightsSchemaHealth';
|
||||||
import type { ProjectDoraMetricsSchema } from './projectDoraMetricsSchema';
|
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.
|
* 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 {
|
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 */
|
/** The number of features of each type */
|
||||||
featureTypeCounts: FeatureTypeCountSchema[];
|
featureTypeCounts: FeatureTypeCountSchema[];
|
||||||
/** Health summary of the project */
|
/** Health summary of the project */
|
||||||
|
@ -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;
|
|
||||||
};
|
|
@ -8,8 +8,6 @@ import FeatureTypeStore from '../../db/feature-type-store';
|
|||||||
import FakeFeatureTypeStore from '../../../test/fixtures/fake-feature-type-store';
|
import FakeFeatureTypeStore from '../../../test/fixtures/fake-feature-type-store';
|
||||||
import { ProjectInsightsService } from './project-insights-service';
|
import { ProjectInsightsService } from './project-insights-service';
|
||||||
import ProjectStore from '../project/project-store';
|
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 FeatureStrategiesStore from '../feature-toggle/feature-toggle-strategies-store';
|
||||||
import FakeFeatureStrategiesStore from '../feature-toggle/fakes/fake-feature-strategies-store';
|
import FakeFeatureStrategiesStore from '../feature-toggle/fakes/fake-feature-strategies-store';
|
||||||
|
|
||||||
@ -39,18 +37,14 @@ export const createProjectInsightsService = (
|
|||||||
getLogger,
|
getLogger,
|
||||||
flagResolver,
|
flagResolver,
|
||||||
);
|
);
|
||||||
const projectInsightsReadModel = new ProjectInsightsReadModel(db);
|
|
||||||
|
|
||||||
return new ProjectInsightsService(
|
return new ProjectInsightsService({
|
||||||
{
|
|
||||||
projectStore,
|
projectStore,
|
||||||
featureToggleStore,
|
featureToggleStore,
|
||||||
featureTypeStore,
|
featureTypeStore,
|
||||||
projectStatsStore,
|
projectStatsStore,
|
||||||
featureStrategiesStore,
|
featureStrategiesStore,
|
||||||
},
|
});
|
||||||
projectInsightsReadModel,
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const createFakeProjectInsightsService = () => {
|
export const createFakeProjectInsightsService = () => {
|
||||||
@ -59,23 +53,18 @@ export const createFakeProjectInsightsService = () => {
|
|||||||
const featureTypeStore = new FakeFeatureTypeStore();
|
const featureTypeStore = new FakeFeatureTypeStore();
|
||||||
const projectStatsStore = new FakeProjectStatsStore();
|
const projectStatsStore = new FakeProjectStatsStore();
|
||||||
const featureStrategiesStore = new FakeFeatureStrategiesStore();
|
const featureStrategiesStore = new FakeFeatureStrategiesStore();
|
||||||
const projectInsightsReadModel = new FakeProjectInsightsReadModel();
|
const projectInsightsService = new ProjectInsightsService({
|
||||||
const projectInsightsService = new ProjectInsightsService(
|
|
||||||
{
|
|
||||||
projectStore,
|
projectStore,
|
||||||
featureToggleStore,
|
featureToggleStore,
|
||||||
featureTypeStore,
|
featureTypeStore,
|
||||||
projectStatsStore,
|
projectStatsStore,
|
||||||
featureStrategiesStore,
|
featureStrategiesStore,
|
||||||
},
|
});
|
||||||
projectInsightsReadModel,
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
projectInsightsService,
|
projectInsightsService,
|
||||||
projectStatsStore,
|
projectStatsStore,
|
||||||
featureToggleStore,
|
featureToggleStore,
|
||||||
projectStore,
|
projectStore,
|
||||||
projectInsightsReadModel,
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -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<string, ChangeRequestCounts> = {};
|
|
||||||
|
|
||||||
async getChangeRequests(projectId: string): Promise<ChangeRequestCounts> {
|
|
||||||
return this.counts[projectId] ?? changeRequestCounts;
|
|
||||||
}
|
|
||||||
|
|
||||||
async setChangeRequests(projectId: string, counts: ChangeRequestCounts) {
|
|
||||||
this.counts[projectId] = counts;
|
|
||||||
}
|
|
||||||
}
|
|
@ -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<ChangeRequestCounts>;
|
|
||||||
}
|
|
@ -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,
|
|
||||||
});
|
|
||||||
});
|
|
@ -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<ChangeRequestCounts> {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
@ -6,21 +6,12 @@ test('Return basic insights', async () => {
|
|||||||
projectStatsStore,
|
projectStatsStore,
|
||||||
featureToggleStore,
|
featureToggleStore,
|
||||||
projectStore,
|
projectStore,
|
||||||
projectInsightsReadModel,
|
|
||||||
} = createFakeProjectInsightsService();
|
} = createFakeProjectInsightsService();
|
||||||
await featureToggleStore.create('default', {
|
await featureToggleStore.create('default', {
|
||||||
name: 'irrelevant',
|
name: 'irrelevant',
|
||||||
createdByUserId: 1,
|
createdByUserId: 1,
|
||||||
type: 'release',
|
type: 'release',
|
||||||
});
|
});
|
||||||
await projectInsightsReadModel.setChangeRequests('default', {
|
|
||||||
total: 5,
|
|
||||||
approved: 1,
|
|
||||||
applied: 1,
|
|
||||||
rejected: 1,
|
|
||||||
reviewRequired: 1,
|
|
||||||
scheduled: 1,
|
|
||||||
});
|
|
||||||
await projectStore.create({
|
await projectStore.create({
|
||||||
id: 'default',
|
id: 'default',
|
||||||
name: 'irrelevant',
|
name: 'irrelevant',
|
||||||
@ -57,14 +48,6 @@ test('Return basic insights', async () => {
|
|||||||
rating: 100,
|
rating: 100,
|
||||||
},
|
},
|
||||||
leadTime: { features: [], projectAverage: 0 },
|
leadTime: { features: [], projectAverage: 0 },
|
||||||
changeRequests: {
|
|
||||||
total: 5,
|
|
||||||
approved: 1,
|
|
||||||
applied: 1,
|
|
||||||
rejected: 1,
|
|
||||||
reviewRequired: 1,
|
|
||||||
scheduled: 1,
|
|
||||||
},
|
|
||||||
members: { currentMembers: 0, change: 0 },
|
members: { currentMembers: 0, change: 0 },
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -13,7 +13,6 @@ import type {
|
|||||||
ProjectInsightsSchema,
|
ProjectInsightsSchema,
|
||||||
} from '../../openapi';
|
} from '../../openapi';
|
||||||
import { calculateProjectHealth } from '../../domain/project-health/project-health';
|
import { calculateProjectHealth } from '../../domain/project-health/project-health';
|
||||||
import type { IProjectInsightsReadModel } from './project-insights-read-model-type';
|
|
||||||
import { subDays } from 'date-fns';
|
import { subDays } from 'date-fns';
|
||||||
|
|
||||||
export class ProjectInsightsService {
|
export class ProjectInsightsService {
|
||||||
@ -27,10 +26,7 @@ export class ProjectInsightsService {
|
|||||||
|
|
||||||
private projectStatsStore: IProjectStatsStore;
|
private projectStatsStore: IProjectStatsStore;
|
||||||
|
|
||||||
private projectInsightsReadModel: IProjectInsightsReadModel;
|
constructor({
|
||||||
|
|
||||||
constructor(
|
|
||||||
{
|
|
||||||
projectStore,
|
projectStore,
|
||||||
featureToggleStore,
|
featureToggleStore,
|
||||||
featureTypeStore,
|
featureTypeStore,
|
||||||
@ -43,15 +39,12 @@ export class ProjectInsightsService {
|
|||||||
| 'projectStatsStore'
|
| 'projectStatsStore'
|
||||||
| 'featureTypeStore'
|
| 'featureTypeStore'
|
||||||
| 'featureStrategiesStore'
|
| 'featureStrategiesStore'
|
||||||
>,
|
>) {
|
||||||
projectInsightsReadModel: IProjectInsightsReadModel,
|
|
||||||
) {
|
|
||||||
this.projectStore = projectStore;
|
this.projectStore = projectStore;
|
||||||
this.featureToggleStore = featureToggleStore;
|
this.featureToggleStore = featureToggleStore;
|
||||||
this.featureTypeStore = featureTypeStore;
|
this.featureTypeStore = featureTypeStore;
|
||||||
this.featureStrategiesStore = featureStrategiesStore;
|
this.featureStrategiesStore = featureStrategiesStore;
|
||||||
this.projectStatsStore = projectStatsStore;
|
this.projectStatsStore = projectStatsStore;
|
||||||
this.projectInsightsReadModel = projectInsightsReadModel;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async getDoraMetrics(projectId: string): Promise<ProjectDoraMetricsSchema> {
|
async getDoraMetrics(projectId: string): Promise<ProjectDoraMetricsSchema> {
|
||||||
@ -143,14 +136,8 @@ export class ProjectInsightsService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getProjectInsights(projectId: string) {
|
async getProjectInsights(projectId: string) {
|
||||||
const [
|
const [stats, featureTypeCounts, health, leadTime, members] =
|
||||||
stats,
|
await Promise.all([
|
||||||
featureTypeCounts,
|
|
||||||
health,
|
|
||||||
leadTime,
|
|
||||||
changeRequests,
|
|
||||||
members,
|
|
||||||
] = await Promise.all([
|
|
||||||
this.projectStatsStore.getProjectStats(projectId),
|
this.projectStatsStore.getProjectStats(projectId),
|
||||||
this.featureToggleStore.getFeatureTypeCounts({
|
this.featureToggleStore.getFeatureTypeCounts({
|
||||||
projectId,
|
projectId,
|
||||||
@ -158,7 +145,6 @@ export class ProjectInsightsService {
|
|||||||
}),
|
}),
|
||||||
this.getHealthInsights(projectId),
|
this.getHealthInsights(projectId),
|
||||||
this.getDoraMetrics(projectId),
|
this.getDoraMetrics(projectId),
|
||||||
this.projectInsightsReadModel.getChangeRequests(projectId),
|
|
||||||
this.getProjectMembers(projectId),
|
this.getProjectMembers(projectId),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@ -167,7 +153,6 @@ export class ProjectInsightsService {
|
|||||||
featureTypeCounts,
|
featureTypeCounts,
|
||||||
health,
|
health,
|
||||||
leadTime,
|
leadTime,
|
||||||
changeRequests,
|
|
||||||
members,
|
members,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -53,13 +53,5 @@ test('project insights happy path', async () => {
|
|||||||
staleCount: 0,
|
staleCount: 0,
|
||||||
rating: 100,
|
rating: 100,
|
||||||
},
|
},
|
||||||
changeRequests: {
|
|
||||||
total: 0,
|
|
||||||
approved: 0,
|
|
||||||
applied: 0,
|
|
||||||
rejected: 0,
|
|
||||||
reviewRequired: 0,
|
|
||||||
scheduled: 0,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -80,53 +80,6 @@ export const projectInsightsSchema = {
|
|||||||
},
|
},
|
||||||
description: 'Active/inactive users summary',
|
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: {
|
components: {
|
||||||
schemas: {
|
schemas: {
|
||||||
|
Loading…
Reference in New Issue
Block a user