Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Assignee duration statistics #404

Merged
merged 3 commits into from
Jan 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ export interface TaskStatistics {
}

export interface TimeStatistics {
durationTotal: number;
durationAvg: number;
evaluationTotal: number;
evaluationAvg: number;
pointsAvg: number;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ <h2>
<li class="list-group-item d-flex align-items-center bg-progress-purple" [style.--percentage.%]="stats.time.evaluationTotal / (stats.time.codeSearchSavings + stats.time.evaluationTotal) * 100">
<div class="me-auto">
Time spent Evaluating
<i class="bi-question-circle" ngbTooltip="How much time was spent manually evaluating tasks across all solutions"></i>
</div>
<app-statistic-value
[label]="weightedEvaluations ? '∅ per Point' : '∅ per Evaluation'"
Expand All @@ -90,8 +91,8 @@ <h2>
<div class="me-auto">
Time saved by Code Search
<i
class="bi-info-circle"
ngbTooltip="Approximately. Click for more info."
class="bi-question-circle"
ngbTooltip="The approximate time that was saved by Code Search. Click for more info."
ngbPopover="The time saved by Code Search is approximately calculated as a sum of each task's time savings.
The time taken to manually evaluate a task is multiplied by the number of automatic evaluations created by Code Search.
You can view the time savings for each task in the list below."
Expand All @@ -102,6 +103,16 @@ <h2>
<div class="border-end mx-3 align-self-stretch"></div>
<app-statistic-value label="of Total" [value]="(stats.time.codeSearchSavings / (stats.time.codeSearchSavings + stats.time.evaluationTotal)) | percent:'0.0'"></app-statistic-value>
</li>
<div class="my-1"></div>
<li class="list-group-item d-flex align-items-center">
<div class="me-auto">
Time per Solution
<i class="bi-question-circle" ngbTooltip="How much time was spent on average per solution, including overhead"></i>
</div>
<app-statistic-value label="∅ per Solution" [value]="stats.time.durationAvg | duration"></app-statistic-value>
<div class="border-end mx-3 align-self-stretch"></div>
<app-statistic-value label="Total" [value]="stats.time.durationTotal | duration"></app-statistic-value>
</li>
</ul>
</div>
</div>
Expand Down
6 changes: 6 additions & 0 deletions services/apps/assignments/src/statistics/statistics.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@ export class TaskStatistics {
}

export class TimeStatistics {
@ApiProperty()
durationTotal: number;

@ApiProperty()
durationAvg: number;

@ApiProperty()
evaluationTotal: number;

Expand Down
2 changes: 2 additions & 0 deletions services/apps/assignments/src/statistics/statistics.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ import {EvaluationModule} from '../evaluation/evaluation.module';
import {SolutionModule} from '../solution/solution.module';
import {StatisticsController} from './statistics.controller';
import {StatisticsService} from './statistics.service';
import {AssigneeModule} from '../assignee/assignee.module';

@Module({
imports: [
AssignmentModule,
EvaluationModule,
SolutionModule,
CommentModule,
AssigneeModule,
],
controllers: [StatisticsController],
providers: [StatisticsService],
Expand Down
34 changes: 31 additions & 3 deletions services/apps/assignments/src/statistics/statistics.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ import {
EvaluationStatistics,
SolutionStatistics,
TaskStatistics,
TimeStatistics
TimeStatistics,
} from './statistics.dto';
import {Types} from "mongoose";
import {Types} from 'mongoose';
import {AssigneeService} from '../assignee/assignee.service';

const outlierDuration = 60;

Expand All @@ -20,6 +21,7 @@ export class StatisticsService {
constructor(
private assignmentService: AssignmentService,
private solutionService: SolutionService,
private assigneeService: AssigneeService,
private evaluationService: EvaluationService,
private commentService: CommentService,
) {
Expand Down Expand Up @@ -59,13 +61,18 @@ export class StatisticsService {
comments,
solutions,
,
durationStats,
] = await Promise.all([
this.timeStatistics(assignment, taskStats, tasks),
this.countComments(assignment),
this.solutionStatistics(assignmentDoc),
this.fillEvaluationStatistics(assignment, taskStats, tasks, evaluations, weightedEvaluations),
this.durationStatistics(assignment),
]);

time.durationTotal = durationStats.total;
time.durationAvg = durationStats.total / durationStats.count;

// needs to happen after timeStatistics and fillEvaluationStatistics
for (const taskStat of taskStats.values()) {
time.codeSearchSavings += taskStat.count.codeSearch * taskStat.timeAvg;
Expand Down Expand Up @@ -133,7 +140,7 @@ export class StatisticsService {
time: {$sum: '$duration'},
count: {$sum: 1},
},
}
},
])) {
const {_id, time, count} = result;
const taskStat = taskStats.get(_id);
Expand All @@ -149,6 +156,8 @@ export class StatisticsService {
evaluationAvg: totalTime / eventCount,
pointsAvg: weightedTime / eventCount,
codeSearchSavings: 0, // NB: calculated later, once taskStats.count is set by fillEvaluationStatistics
durationAvg: 0, // calculated later
durationTotal: 0, // calculated later
};
}

Expand Down Expand Up @@ -195,4 +204,23 @@ export class StatisticsService {
pointsAvg: points / graded,
};
}

private async durationStatistics(assignment: Types.ObjectId) {
const [result] = await this.assigneeService.model.aggregate([
{
$match: {
assignment,
duration: {$exists: true},
},
},
{
$group: {
_id: null,
total: {$sum: '$duration'},
count: {$sum: 1},
},
},
]);
return result ?? {total: 0, count: 0};
}
}
Loading