Skip to content

Commit

Permalink
Bugfix/programming submission/submission state ui fixes (#825)
Browse files Browse the repository at this point in the history
  • Loading branch information
thilo-behnke authored and krusche committed Sep 16, 2019
1 parent 2ac6019 commit 852b3ed
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 8 deletions.
@@ -1,5 +1,5 @@
<div *ngIf="buildingSummary; else loadingState" class="d-flex">
<div id="result-eta" class="badge badge-secondary d-flex flex-column justify-content-between mr-3">
<div id="result-eta" *ngIf="hasBuildingSubmissions" class="badge badge-secondary d-flex flex-column justify-content-between mr-3">
<fa-icon icon="clock"></fa-icon>
<span
[ngbTooltip]="'artemisApp.programmingExercise.resultETATooltip' | translate"
Expand Down
Expand Up @@ -21,6 +21,7 @@ export class ProgrammmingExerciseInstructorSubmissionStateComponent implements O
@Input() exerciseId: number;

hasFailedSubmissions = false;
hasBuildingSubmissions = false;
buildingSummary: { [submissionState: string]: number };
isBuildingFailedSubmissions = false;
isTriggeringBuildAll = false;
Expand Down Expand Up @@ -48,10 +49,11 @@ export class ProgrammmingExerciseInstructorSubmissionStateComponent implements O
.pipe(
map(this.sumSubmissionStates),
// If we would update the UI with every small change, it would seem very hectic. So we always take the latest value after 1 second.
debounceTime(1000),
debounceTime(500),
tap((buildingSummary: { [submissionState: string]: number }) => {
this.buildingSummary = buildingSummary;
this.hasFailedSubmissions = this.buildingSummary[ProgrammingSubmissionState.HAS_FAILED_SUBMISSION] > 0;
this.hasBuildingSubmissions = this.buildingSummary[ProgrammingSubmissionState.IS_BUILDING_PENDING_SUBMISSION] > 0;
}),
)
.subscribe();
Expand Down
4 changes: 2 additions & 2 deletions src/main/webapp/i18n/de/programmingExercise.json
Expand Up @@ -97,8 +97,8 @@
"resubmitAll": "Alle erneut ausführen",
"resubmitAllTooltip": "Führe die letzte Abgabe aller Teilnahmen erneut aus. Das Ergebnis wird als bewertet gekennzeichnet.",
"resubmitAllDialog": "ACHTUNG: Die erneute Abgabe aller Teilnahmen ist eine sehr aufwändige Operation. Diese Aktion wird für jede Teilnahme dieser Übung einen CI Build starten. Das bedeutet, dass alle Ergebnisse der Studierenden anhand ihres letzten Commits neu berechnet und mit dem neu erzeugten Ergebnis überschreiben werden!",
"resubmitFailed": "Alle erneut ausführen",
"resubmitFailedTootip": "Führe die letzte Abgabe aller gescheiterten Teilnahmen erneut aus. Das Ergebnis wird als bewertet gekennzeichnet.",
"resubmitFailed": "Gescheiterte Teilnahmen erneut ausführen",
"resubmitFailedTooltip": "Führe die letzte Abgabe aller gescheiterten Teilnahmen erneut aus. Gescheiterte Teilnahmen besitzen kein Ergebnis für die letzte Abgabe. Gescheiterte Abgaben können bei Kommunikationsfehlern zwischen dem CI System und Artemis entstehen. Die entstehenden Ergebnisse werden als bewertet gekennzeichnet.",
"buildingSubmissions": "Laufende Abgaben: {{number}}",
"failedSubmissions": "Gescheiterte Abgaben: {{number}}",
"resultETA": "Ergebnis Wartezeit: {{eta}}",
Expand Down
2 changes: 1 addition & 1 deletion src/main/webapp/i18n/en/programmingExercise.json
Expand Up @@ -98,7 +98,7 @@
"resubmitAllTooltip": "Trigger the last submission of all participations again. The results will be rated.",
"resubmitAllDialog": "WARNING: Triggering all participations again is a very expensive operation. This action will start a CI build for every participation in this exercise. This means that all results of the students will be calculated again and overridden with a newly generated result based on their last commit!",
"resubmitFailed": "Trigger failed",
"resubmitFailedTooltip": "Trigger the last submission of all failed participations again. The results will be rated.",
"resubmitFailedTooltip": "Trigger the last submission of all failed participations again. Failed submissions don't have a result for their latest submission. This can e.g. happen due to communication errors between the CI system and Artemis. The created results will be rated.",
"buildingSubmissions": "Building submissions: {{number}}",
"failedSubmissions": "Failed submissions: {{number}}",
"resultETA": "Result ETA: {{eta}}",
Expand Down
Expand Up @@ -34,6 +34,12 @@ describe('ProgrammingExerciseInstructorSubmissionState', () => {

const exercise = { id: 20 } as Exercise;

const resultEtaId = '#result-eta';

const getResultEtaContainer = () => {
return debugElement.query(By.css(resultEtaId));
};

beforeEach(async () => {
return TestBed.configureTestingModule({
imports: [TranslateModule.forRoot(), ArtemisTestModule, ArtemisProgrammingExerciseActionsModule],
Expand Down Expand Up @@ -87,6 +93,42 @@ describe('ProgrammingExerciseInstructorSubmissionState', () => {
expect(getBuildState()).to.be.null;
});

it('should show the result eta if there is at least one building submission', fakeAsync(() => {
const isBuildingSubmissionState = {
1: { submissionState: ProgrammingSubmissionState.HAS_NO_PENDING_SUBMISSION, submission: null, participationId: 4 },
4: { submissionState: ProgrammingSubmissionState.IS_BUILDING_PENDING_SUBMISSION, submission: null, participationId: 5 },
} as ExerciseSubmissionState;
comp.exerciseId = exercise.id;

triggerChanges(comp, { property: 'exerciseId', currentValue: comp.exerciseId });
getExerciseSubmissionStateSubject.next(isBuildingSubmissionState);

tick(500);

fixture.detectChanges();

const resultEta = getResultEtaContainer();
expect(resultEta).to.exist;
}));

it('should not show the result eta if there is no building submission', fakeAsync(() => {
const isNotBuildingSubmission = {
1: { submissionState: ProgrammingSubmissionState.HAS_NO_PENDING_SUBMISSION, submission: null, participationId: 4 },
4: { submissionState: ProgrammingSubmissionState.HAS_FAILED_SUBMISSION, submission: null, participationId: 5 },
} as ExerciseSubmissionState;
comp.exerciseId = exercise.id;

triggerChanges(comp, { property: 'exerciseId', currentValue: comp.exerciseId });
getExerciseSubmissionStateSubject.next(isNotBuildingSubmission);

tick(500);

fixture.detectChanges();

const resultEta = getResultEtaContainer();
expect(resultEta).not.to.exist;
}));

it('should show & enable the trigger all button and the build state once the build summary is loaded', fakeAsync(() => {
const noPendingSubmissionState = {
1: { submissionState: ProgrammingSubmissionState.HAS_NO_PENDING_SUBMISSION, submission: null, participationId: 4 },
Expand All @@ -99,7 +141,7 @@ describe('ProgrammingExerciseInstructorSubmissionState', () => {
getExerciseSubmissionStateSubject.next(noPendingSubmissionState);

// Wait for a second as the view is updated with a debounce.
tick(1000);
tick(500);

fixture.detectChanges();

Expand All @@ -120,15 +162,20 @@ describe('ProgrammingExerciseInstructorSubmissionState', () => {
const noPendingSubmissionState = {
1: { submissionState: ProgrammingSubmissionState.HAS_NO_PENDING_SUBMISSION, submission: null, participationId: 55 },
4: { submissionState: ProgrammingSubmissionState.HAS_FAILED_SUBMISSION, submission: null, participationId: 76 },
5: { submissionState: ProgrammingSubmissionState.IS_BUILDING_PENDING_SUBMISSION, submission: null, participationId: 76 },
} as ExerciseSubmissionState;
const compressedSummary = { [ProgrammingSubmissionState.HAS_NO_PENDING_SUBMISSION]: 1, [ProgrammingSubmissionState.HAS_FAILED_SUBMISSION]: 1 };
const compressedSummary = {
[ProgrammingSubmissionState.HAS_NO_PENDING_SUBMISSION]: 1,
[ProgrammingSubmissionState.HAS_FAILED_SUBMISSION]: 1,
[ProgrammingSubmissionState.IS_BUILDING_PENDING_SUBMISSION]: 1,
};
comp.exerciseId = exercise.id;

triggerChanges(comp, { property: 'exerciseId', currentValue: comp.exerciseId });
getExerciseSubmissionStateSubject.next(noPendingSubmissionState);

// Wait for a second as the view is updated with a debounce.
tick(1000);
tick(500);

fixture.detectChanges();

Expand All @@ -138,6 +185,7 @@ describe('ProgrammingExerciseInstructorSubmissionState', () => {
expect(comp.isBuildingFailedSubmissions).to.be.false;
expect(comp.buildingSummary).to.deep.equal(compressedSummary);

expect(getResultEtaContainer()).to.exist;
expect(getTriggerAllButton()).to.exist;
expect(getTriggerAllButton().disabled).to.be.false;
expect(getTriggerFailedButton()).to.exist;
Expand Down

0 comments on commit 852b3ed

Please sign in to comment.