diff --git a/backend/src/services/target-calculation-service.ts b/backend/src/services/target-calculation-service.ts
index d42c722..3263672 100644
--- a/backend/src/services/target-calculation-service.ts
+++ b/backend/src/services/target-calculation-service.ts
@@ -702,7 +702,8 @@ RESULT:
const userTimeSavings = distinctUsers.map(userId => {
const userSurveys = this.surveysWeekly.filter(survey => survey.userId === userId);
const totalPercent = userSurveys.reduce((sum, survey) => {
- const percentTimeSaved = typeof survey.percentTimeSaved === 'number' ? survey.percentTimeSaved : 0;
+ // Always parse percentTimeSaved as float
+ const percentTimeSaved = survey.percentTimeSaved != null ? parseFloat(survey.percentTimeSaved as any) : 0;
return sum + percentTimeSaved;
}, 0);
return totalPercent / userSurveys.length; // Average percent time saved per user
@@ -711,9 +712,9 @@ RESULT:
// Average across all users
const avgPercentTimeSaved = userTimeSavings.reduce((sum, percent) => sum + percent, 0) / userTimeSavings.length;
- // Convert settings values to numbers
- const hoursPerYear = typeof this.settings.hoursPerYear === 'number' ? this.settings.hoursPerYear : 2000;
- const percentCoding = typeof this.settings.percentCoding === 'number' ? this.settings.percentCoding : 50;
+ // Convert settings values to numbers (parse from string if needed)
+ const hoursPerYear = this.settings.hoursPerYear != null ? parseFloat(this.settings.hoursPerYear as any) : 2000;
+ const percentCoding = this.settings.percentCoding != null ? parseFloat(this.settings.percentCoding as any) : 50;
// Calculate weekly hours saved based on settings and average percent
const weeklyHours = hoursPerYear / 50; // Assuming 50 working weeks
@@ -721,7 +722,7 @@ RESULT:
const avgWeeklyTimeSaved = weeklyDevHours * (avgPercentTimeSaved / 100);
// Calculate max based on settings
- const maxPercentTimeSaved = typeof this.settings.percentTimeSaved === 'number' ? this.settings.percentTimeSaved : 20;
+ const maxPercentTimeSaved = this.settings.percentTimeSaved != null ? parseFloat(this.settings.percentTimeSaved as any) : 20;
const maxWeeklyTimeSaved = weeklyDevHours * (maxPercentTimeSaved / 100);
const result = {
@@ -785,11 +786,11 @@ RESULT:
const adoptedDevs = this.calculateAdoptedDevs().current;
const weeklyTimeSavedHrs = this.calculateWeeklyTimeSavedHrs().current;
- // Ensure all values are properly typed as numbers
- const hoursPerYear = typeof this.settings.hoursPerYear === 'number' ? this.settings.hoursPerYear : 2000;
+ // Always parse settings values as numbers (from string if needed)
+ const hoursPerYear = this.settings.hoursPerYear != null ? parseFloat(this.settings.hoursPerYear as any) : 2000;
const weeksInYear = Math.round(hoursPerYear / 40) || 50; // Calculate weeks and ensure it's a number
- const devCostPerYear = typeof this.settings.devCostPerYear === 'number' ? this.settings.devCostPerYear : 0;
+ const devCostPerYear = this.settings.devCostPerYear != null ? parseFloat(this.settings.devCostPerYear as any) : 0;
const hourlyRate = devCostPerYear > 0 ? (devCostPerYear / hoursPerYear) : 50;
const annualSavings = weeklyTimeSavedHrs * weeksInYear * hourlyRate * adoptedDevs;
@@ -824,8 +825,8 @@ RESULT:
const adoptedDevs = this.calculateAdoptedDevs().current;
const weeklyTimeSavedHrs = this.calculateWeeklyTimeSavedHrs().current;
- // Convert hours per year to number
- const hoursPerYear = typeof this.settings.hoursPerYear === 'number' ? this.settings.hoursPerYear : 2000;
+ // Always parse hours per year as number
+ const hoursPerYear = this.settings.hoursPerYear != null ? parseFloat(this.settings.hoursPerYear as any) : 2000;
const hoursPerWeek = hoursPerYear / 50 || 40; // Default to 40 if undefined
// Calculate productivity boost factor (not percentage)
diff --git a/backend/src/services/value-modeling-explanation.md b/backend/src/services/value-modeling-explanation.md
new file mode 100644
index 0000000..e69de29
diff --git a/frontend/src/app/main/copilot/copilot-value-modeling/copilot-value-modeling.component.html b/frontend/src/app/main/copilot/copilot-value-modeling/copilot-value-modeling.component.html
index 1368ba7..93f145c 100644
--- a/frontend/src/app/main/copilot/copilot-value-modeling/copilot-value-modeling.component.html
+++ b/frontend/src/app/main/copilot/copilot-value-modeling/copilot-value-modeling.component.html
@@ -1,6 +1,14 @@
Org Metrics
diff --git a/frontend/src/app/main/copilot/copilot-value-modeling/copilot-value-modeling.component.ts b/frontend/src/app/main/copilot/copilot-value-modeling/copilot-value-modeling.component.ts
index b0a72a2..f3cb28a 100644
--- a/frontend/src/app/main/copilot/copilot-value-modeling/copilot-value-modeling.component.ts
+++ b/frontend/src/app/main/copilot/copilot-value-modeling/copilot-value-modeling.component.ts
@@ -37,6 +37,7 @@ export class CopilotValueModelingComponent implements OnInit {
orgDataSource: TableTarget[] = [];
userDataSource: TableTarget[] = [];
impactDataSource: TableTarget[] = [];
+ showSaveAllButton = false;
private readonly _destroy$ = new Subject
();
keyToNameMap: Record = {
seats: 'Seats',
@@ -128,7 +129,9 @@ export class CopilotValueModelingComponent implements OnInit {
saveTargets() {
const targets: Targets = this.transformBackToTargets(this.orgDataSource, this.userDataSource, this.impactDataSource);
- this.targetsService.saveTargets(targets).subscribe();
+ this.targetsService.saveTargets(targets).subscribe(() => {
+ this.showSaveAllButton = false;
+ });
}
openEditDialog(target: Target) {
@@ -144,6 +147,17 @@ export class CopilotValueModelingComponent implements OnInit {
}
});
}
+
+ resetTargets() {
+ // Call the backend endpoint to recalculate targets
+ this.targetsService.recalculateTargets().subscribe((result: any) => {
+ const targets = result.targets || result; // handle both {targets, logs} and just targets
+ this.orgDataSource = this.transformTargets(targets.org);
+ this.userDataSource = this.transformTargets(targets.user);
+ this.impactDataSource = this.transformTargets(targets.impact);
+ this.showSaveAllButton = true;
+ });
+ }
}
@Component({
diff --git a/frontend/src/app/main/copilot/copilot-value/time-saved-chart/time-saved-chart.component.ts b/frontend/src/app/main/copilot/copilot-value/time-saved-chart/time-saved-chart.component.ts
index 8ceea2e..9df7124 100644
--- a/frontend/src/app/main/copilot/copilot-value/time-saved-chart/time-saved-chart.component.ts
+++ b/frontend/src/app/main/copilot/copilot-value/time-saved-chart/time-saved-chart.component.ts
@@ -29,7 +29,7 @@ export class TimeSavedChartComponent implements OnInit, OnChanges {
text: 'Time Saved (Hrs per Week)'
},
min: 0,
- max: 10,
+ max: 10, // Will be updated dynamically
labels: {
format: '{value}hrs'
},
@@ -45,7 +45,7 @@ export class TimeSavedChartComponent implements OnInit, OnChanges {
}
}],
plotLines: [{
- value: 5,
+ value: 5, // Will be updated dynamically
color: 'var(--sys-primary)',
dashStyle: 'Dash',
width: 2,
@@ -91,6 +91,7 @@ export class TimeSavedChartComponent implements OnInit, OnChanges {
this._chartOptions.yAxis = Object.assign({}, this.chartOptions?.yAxis, this._chartOptions.yAxis);
this._chartOptions.tooltip = Object.assign({}, this.chartOptions?.tooltip, this._chartOptions.tooltip);
this._chartOptions = Object.assign({}, this.chartOptions, this._chartOptions);
+ this.updateYAxisFromTargets();
}
ngOnChanges() {
@@ -101,6 +102,41 @@ export class TimeSavedChartComponent implements OnInit, OnChanges {
};
this.updateFlag = true;
}
+ this.updateYAxisFromTargets();
+ }
+
+ private updateYAxisFromTargets() {
+ if (this.targets?.user?.weeklyTimeSavedHrs) {
+ const targetValue = this.targets.user.weeklyTimeSavedHrs.target;
+ const maxValue = Math.max(
+ targetValue * 1.5,
+ this.targets.user.weeklyTimeSavedHrs.max || 10,
+ 10
+ );
+ const yAxis = {
+ ...this._chartOptions.yAxis,
+ max: maxValue,
+ plotLines: [{
+ value: targetValue,
+ color: 'var(--sys-primary)',
+ dashStyle: 'Dash' as Highcharts.DashStyleValue,
+ width: 2,
+ label: {
+ text: 'Target Level',
+ align: 'left' as Highcharts.AlignValue,
+ style: {
+ color: 'var(--sys-primary)'
+ }
+ },
+ zIndex: 2
+ }]
+ };
+ this._chartOptions = {
+ ...this._chartOptions,
+ yAxis
+ };
+ this.updateFlag = true;
+ }
}
}
diff --git a/frontend/src/app/services/api/targets.service.ts b/frontend/src/app/services/api/targets.service.ts
index 86f4ea1..59ba1bd 100644
--- a/frontend/src/app/services/api/targets.service.ts
+++ b/frontend/src/app/services/api/targets.service.ts
@@ -77,5 +77,10 @@ export class TargetsService {
saveTargets(targets: Targets) {
return this.http.post(`${this.apiUrl}`, targets);
}
+
+ recalculateTargets() {
+ // Calls the backend endpoint to recalculate targets
+ return this.http.get(`${this.apiUrl}/calculate`);
+ }
}