diff --git a/src/lib/features/personal-dashboard/personal-dashboard-read-model-type.ts b/src/lib/features/personal-dashboard/personal-dashboard-read-model-type.ts index 30dec2313e..98b2fd2ae3 100644 --- a/src/lib/features/personal-dashboard/personal-dashboard-read-model-type.ts +++ b/src/lib/features/personal-dashboard/personal-dashboard-read-model-type.ts @@ -13,9 +13,13 @@ export type BasePersonalProject = { export type PersonalProject = BasePersonalProject & { owners?: ProjectOwners; } & { - health: number; + technicalDebt: number; memberCount: number; featureCount: number; + /** + * @deprecated + */ + health: number; }; export interface IPersonalDashboardReadModel { diff --git a/src/lib/features/personal-dashboard/personal-dashboard-service.ts b/src/lib/features/personal-dashboard/personal-dashboard-service.ts index e3bcee557d..2c96f91691 100644 --- a/src/lib/features/personal-dashboard/personal-dashboard-service.ts +++ b/src/lib/features/personal-dashboard/personal-dashboard-service.ts @@ -96,6 +96,7 @@ export class PersonalDashboardService { id: project.id, name: project.name, health: project.health, + technicalDebt: 100 - (project.health || 0), memberCount: project.memberCount, featureCount: project.featureCount, })); @@ -193,6 +194,7 @@ export class PersonalDashboardService { projectInsights?.potentiallyStaleFeatureCount || 0; const staleFlags = projectInsights?.staleFeatureCount || 0; const currentHealth = projectInsights?.health || 0; + const technicalDebt = projectInsights?.technicalDebt || 0; return { latestEvents, @@ -206,6 +208,10 @@ export class PersonalDashboardService { potentiallyStaleFlags, staleFlags, activeFlags: totalFlags - staleFlags - potentiallyStaleFlags, + technicalDebt, + /** + * @deprecated + */ health: currentHealth, }, }; 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 513196c994..7381807ca8 100644 --- a/src/lib/features/project-insights/project-insights-service.test.ts +++ b/src/lib/features/project-insights/project-insights-service.test.ts @@ -47,6 +47,12 @@ test('Return basic insights', async () => { staleCount: 0, rating: 100, }, + technicalDebt: { + activeCount: 0, + potentiallyStaleCount: 0, + staleCount: 0, + rating: 0, + }, leadTime: { features: [], projectAverage: 0 }, 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 9b8bff93c1..3edb83e19c 100644 --- a/src/lib/features/project-insights/project-insights-service.ts +++ b/src/lib/features/project-insights/project-insights-service.ts @@ -93,6 +93,10 @@ export class ProjectInsightsService { activeCount, potentiallyStaleCount, staleCount, + technicalDebt: overview.technicalDebt, + /** + * @deprecated + */ rating: overview.health, }; } @@ -101,7 +105,14 @@ export class ProjectInsightsService { projectId: string, archived: boolean = false, userId?: number, - ): Promise<{ health: number; features: IFeatureOverview[] }> { + ): Promise<{ + technicalDebt: number; + features: IFeatureOverview[]; + /** + * @deprecated + */ + health: number; + }> { const [project, features] = await Promise.all([ this.projectStore.get(projectId), this.featureStrategiesStore.getFeatureOverview({ @@ -113,6 +124,7 @@ export class ProjectInsightsService { return { health: project?.health || 0, + technicalDebt: 100 - (project?.health || 0), features: features, }; } @@ -151,9 +163,23 @@ export class ProjectInsightsService { return { stats, featureTypeCounts, - health, + technicalDebt: { + rating: health.technicalDebt, + activeCount: health.activeCount, + potentiallyStaleCount: health.potentiallyStaleCount, + staleCount: health.staleCount, + }, leadTime, members, + /** + * @deprecated + */ + health: { + rating: health.rating, + activeCount: health.activeCount, + potentiallyStaleCount: health.potentiallyStaleCount, + staleCount: health.staleCount, + }, }; } } diff --git a/src/lib/features/project-status/project-status-service.ts b/src/lib/features/project-status/project-status-service.ts index 9528e773ed..b4252b8744 100644 --- a/src/lib/features/project-status/project-status-service.ts +++ b/src/lib/features/project-status/project-status-service.ts @@ -88,6 +88,9 @@ export class ProjectStatusService { health: { current: currentHealth, }, + technicalDebt: { + current: 100 - currentHealth, + }, lifecycleSummary, staleFlags: { total: staleFlagCount, diff --git a/src/lib/features/project/project-read-model-type.ts b/src/lib/features/project/project-read-model-type.ts index 7f08e22cde..827ad80529 100644 --- a/src/lib/features/project/project-read-model-type.ts +++ b/src/lib/features/project/project-read-model-type.ts @@ -18,12 +18,16 @@ export type ProjectForUi = { export type ProjectForInsights = { id: string; - health: number; + technicalDebt: number; memberCount: number; featureCount: number; staleFeatureCount: number; potentiallyStaleFeatureCount: number; avgTimeToProduction: number; + /** + * @deprecated + */ + health: number; }; export interface IProjectReadModel { diff --git a/src/lib/features/project/project-read-model.ts b/src/lib/features/project/project-read-model.ts index 7fbaa0bd51..5195bec593 100644 --- a/src/lib/features/project/project-read-model.ts +++ b/src/lib/features/project/project-read-model.ts @@ -42,6 +42,7 @@ const mapProjectForInsights = (row): ProjectForInsights => { Number(row.potentially_stale_feature_count) || 0, memberCount: Number(row.number_of_users) || 0, avgTimeToProduction: row.avg_time_to_prod_current_window || 0, + technicalDebt: 100 - (row.health || 0), }; }; diff --git a/src/lib/features/project/project-service.ts b/src/lib/features/project/project-service.ts index 6cf1238a9c..b567b59aab 100644 --- a/src/lib/features/project/project-service.ts +++ b/src/lib/features/project/project-service.ts @@ -1280,6 +1280,7 @@ export default class ProjectService { featureNaming: project.featureNaming, defaultStickiness: project.defaultStickiness, health: project.health || 0, + technicalDebt: 100 - (project.health || 0), favorite: favorite, updatedAt: project.updatedAt, createdAt: project.createdAt, @@ -1338,6 +1339,7 @@ export default class ProjectService { linkTemplates: project.linkTemplates, defaultStickiness: project.defaultStickiness, health: project.health || 0, + technicalDebt: 100 - (project.health || 0), favorite: favorite, updatedAt: project.updatedAt, archivedAt: project.archivedAt, diff --git a/src/lib/openapi/spec/health-overview-schema.ts b/src/lib/openapi/spec/health-overview-schema.ts index cd83c66e24..6b700861a3 100644 --- a/src/lib/openapi/spec/health-overview-schema.ts +++ b/src/lib/openapi/spec/health-overview-schema.ts @@ -26,6 +26,7 @@ export const healthOverviewSchema = { 'mode', 'members', 'health', + 'technicalDebt', 'environments', 'features', ], @@ -75,9 +76,17 @@ export const healthOverviewSchema = { }, health: { type: 'integer', - description: - 'The overall [health rating](https://docs.getunleash.io/reference/technical-debt#project-status) of the project.', + description: 'Use `technicalDebt` instead.', example: 95, + deprecated: true, + }, + technicalDebt: { + type: 'number', + example: 25, + minimum: 0, + maximum: 100, + description: + "An indicator of the [project's technical debt](https://docs.getunleash.io/reference/technical-debt#project-status) on a scale from 0 to 100", }, environments: { type: 'array', diff --git a/src/lib/openapi/spec/personal-dashboard-project-details-schema.ts b/src/lib/openapi/spec/personal-dashboard-project-details-schema.ts index dea70af959..457c7ae103 100644 --- a/src/lib/openapi/spec/personal-dashboard-project-details-schema.ts +++ b/src/lib/openapi/spec/personal-dashboard-project-details-schema.ts @@ -28,6 +28,7 @@ export const personalDashboardProjectDetailsSchema = { 'staleFlags', 'potentiallyStaleFlags', 'health', + 'technicalDebt', ], properties: { avgHealthCurrentWindow: { @@ -76,8 +77,17 @@ export const personalDashboardProjectDetailsSchema = { health: { type: 'integer', minimum: 0, - description: "The project's current health score", + description: 'Use `technicalDebt` instead.', example: 80, + deprecated: true, + }, + technicalDebt: { + type: 'integer', + example: 25, + minimum: 0, + maximum: 100, + description: + "An indicator of the [project's technical debt](https://docs.getunleash.io/reference/technical-debt#project-status) on a scale from 0 to 100", }, }, }, diff --git a/src/lib/openapi/spec/personal-dashboard-schema.ts b/src/lib/openapi/spec/personal-dashboard-schema.ts index f5d0b35199..89647b0088 100644 --- a/src/lib/openapi/spec/personal-dashboard-schema.ts +++ b/src/lib/openapi/spec/personal-dashboard-schema.ts @@ -84,6 +84,7 @@ export const personalDashboardSchema = { 'id', 'name', 'health', + 'technicalDebt', 'memberCount', 'featureCount', ], @@ -102,8 +103,16 @@ export const personalDashboardSchema = { type: 'integer', example: 50, minimum: 0, + deprecated: true, + description: 'Use `technicalDebt` instead.', + }, + technicalDebt: { + type: 'integer', + example: 25, + minimum: 0, + maximum: 100, description: - "An indicator of the [project's health](https://docs.getunleash.io/reference/technical-debt#project-status) on a scale from 0 to 100", + "An indicator of the [project's technical debt](https://docs.getunleash.io/reference/technical-debt#project-status) on a scale from 0 to 100", }, memberCount: { type: 'integer', diff --git a/src/lib/openapi/spec/project-insights-schema.ts b/src/lib/openapi/spec/project-insights-schema.ts index 576e840bf5..72154cc88c 100644 --- a/src/lib/openapi/spec/project-insights-schema.ts +++ b/src/lib/openapi/spec/project-insights-schema.ts @@ -8,7 +8,14 @@ export const projectInsightsSchema = { $id: '#/components/schemas/projectInsightsSchema', type: 'object', additionalProperties: false, - required: ['stats', 'leadTime', 'featureTypeCounts', 'health', 'members'], + required: [ + 'stats', + 'leadTime', + 'featureTypeCounts', + 'health', + 'technicalDebt', + 'members', + ], description: '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.', properties: { @@ -18,6 +25,7 @@ export const projectInsightsSchema = { }, health: { type: 'object', + deprecated: true, required: [ 'rating', 'activeCount', @@ -28,7 +36,7 @@ export const projectInsightsSchema = { rating: { type: 'integer', description: - "An indicator of the [project's health](https://docs.getunleash.io/reference/technical-debt#project-status) on a scale from 0 to 100", + "An indicator of the [project's technical debt](https://docs.getunleash.io/reference/technical-debt#project-status) on a scale from 0 to 100", example: 95, }, activeCount: { @@ -48,7 +56,44 @@ export const projectInsightsSchema = { example: 10, }, }, - description: 'Health summary of the project', + description: + 'Use `technicalDebt` instead. Summary of the project health', + }, + technicalDebt: { + type: 'object', + required: [ + 'rating', + 'activeCount', + 'potentiallyStaleCount', + 'staleCount', + ], + properties: { + rating: { + type: 'integer', + description: + "An indicator of the [project's technical debt](https://docs.getunleash.io/reference/technical-debt#project-status) on a scale from 0 to 100", + example: 25, + minimum: 0, + maximum: 100, + }, + activeCount: { + type: 'number', + description: 'The number of active feature flags.', + example: 12, + }, + potentiallyStaleCount: { + type: 'number', + description: + 'The number of potentially stale feature flags.', + example: 5, + }, + staleCount: { + type: 'number', + description: 'The number of stale feature flags.', + example: 10, + }, + }, + description: 'Summary of the projects technical debt', }, leadTime: { type: 'object', diff --git a/src/lib/openapi/spec/project-overview-schema.ts b/src/lib/openapi/spec/project-overview-schema.ts index d5efc3a57e..559caab5bf 100644 --- a/src/lib/openapi/spec/project-overview-schema.ts +++ b/src/lib/openapi/spec/project-overview-schema.ts @@ -84,8 +84,16 @@ export const projectOverviewSchema = { health: { type: 'number', example: 50, + deprecated: true, + description: 'Use `technicalDebt` instead.', + }, + technicalDebt: { + type: 'number', + example: 25, + minimum: 0, + maximum: 100, description: - "An indicator of the [project's health](https://docs.getunleash.io/reference/technical-debt#project-status) on a scale from 0 to 100", + "An indicator of the [project's technical debt](https://docs.getunleash.io/reference/technical-debt#project-status) on a scale from 0 to 100", }, environments: { type: 'array', diff --git a/src/lib/openapi/spec/project-schema.ts b/src/lib/openapi/spec/project-schema.ts index 5851db969c..16bf8a9043 100644 --- a/src/lib/openapi/spec/project-schema.ts +++ b/src/lib/openapi/spec/project-schema.ts @@ -28,8 +28,16 @@ export const projectSchema = { health: { type: 'number', example: 50, + description: 'Use `technicalDebt` instead.', + deprecated: true, + }, + technicalDebt: { + type: 'number', + example: 25, + minimum: 0, + maximum: 100, description: - "An indicator of the [project's health](https://docs.getunleash.io/reference/technical-debt#project-status) on a scale from 0 to 100", + "An indicator of the [project's technical debt](https://docs.getunleash.io/reference/technical-debt#project-status) on a scale from 0 to 100", }, featureCount: { type: 'number', diff --git a/src/lib/openapi/spec/project-status-schema.test.ts b/src/lib/openapi/spec/project-status-schema.test.ts index 2107d13e37..ffe87abf26 100644 --- a/src/lib/openapi/spec/project-status-schema.test.ts +++ b/src/lib/openapi/spec/project-status-schema.test.ts @@ -6,6 +6,9 @@ test('projectStatusSchema', () => { health: { current: 50, }, + technicalDebt: { + current: 50, + }, lifecycleSummary: { initial: { currentFlags: 0, diff --git a/src/lib/openapi/spec/project-status-schema.ts b/src/lib/openapi/spec/project-status-schema.ts index fd069e7b25..499697e657 100644 --- a/src/lib/openapi/spec/project-status-schema.ts +++ b/src/lib/openapi/spec/project-status-schema.ts @@ -32,6 +32,7 @@ export const projectStatusSchema = { 'activityCountByDate', 'resources', 'health', + 'technicalDebt', 'lifecycleSummary', 'staleFlags', ], @@ -57,6 +58,21 @@ export const projectStatusSchema = { }, }, }, + technicalDebt: { + type: 'object', + additionalProperties: false, + required: ['current'], + description: "Information about the project's health rating", + properties: { + current: { + type: 'integer', + minimum: 0, + maximum: 100, + description: `The project's current health score, based on the ratio of healthy flags to stale and potentially stale flags.`, + example: 100, + }, + }, + }, resources: { type: 'object', additionalProperties: false, diff --git a/src/lib/types/model.ts b/src/lib/types/model.ts index 999dacb506..3cb9906280 100644 --- a/src/lib/types/model.ts +++ b/src/lib/types/model.ts @@ -342,7 +342,7 @@ export interface IProjectHealth { features: IFeatureOverview[]; members: number; version: number; - health: number; + technicalDebt: number; favorite?: boolean; updatedAt?: Date; createdAt: Date | undefined; @@ -351,6 +351,10 @@ export interface IProjectHealth { featureLimit?: number; featureNaming?: IFeatureNaming; defaultStickiness: string; + /** + * @deprecated + */ + health: number; } export type ProjectOnboardingStatus = @@ -366,7 +370,7 @@ export interface IProjectOverview { featureTypeCounts: IFeatureTypeCount[]; members: number; version: number; - health: number; + technicalDebt: number; favorite?: boolean; updatedAt?: Date; archivedAt?: Date; @@ -378,6 +382,10 @@ export interface IProjectOverview { defaultStickiness: string; onboardingStatus: ProjectOnboardingStatus; linkTemplates?: IProjectLinkTemplate[]; + /** + * @deprecated + */ + health: number; } export interface IProjectHealthReport extends IProjectHealth {