Skip to content

Commit

Permalink
Merge branch 'develop' into feature/exams/quiz-pool-configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
rriyaldhi authored Jul 13, 2023
2 parents 3e0ac1a + 7701991 commit 746e454
Show file tree
Hide file tree
Showing 24 changed files with 195 additions and 82 deletions.
4 changes: 2 additions & 2 deletions docker/cypress-E2E-tests-postgres.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ services:
artemis-app:
condition: service_healthy
environment:
SORRY_CYPRESS_PROJECT_ID: "artemis-postgresql"
command: sh -c "cd /app/artemis/src/test/cypress && chmod 777 /root && npm ci && npm run cypress:record:postgresql"
SORRY_CYPRESS_PROJECT_ID: "artemis-postgres"
command: sh -c "cd /app/artemis/src/test/cypress && chmod 777 /root && npm ci && npm run cypress:record:postgres"

networks:
artemis:
Expand Down
3 changes: 2 additions & 1 deletion docker/cypress.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
services:
artemis-cypress:
# Cypress image with node and chrome browser installed (Cypress installation needs to be done separately because we require additional dependencies)
image: docker.io/cypress/browsers:node-18.16.0-chrome-113.0.5672.92-1-ff-113.0-edge-113.0.1774.35-1
image: docker.io/cypress/browsers:node-18.16.0-chrome-114.0.5735.133-1-ff-114.0.2-edge-114.0.1823.51-1
pull_policy: always
environment:
CYPRESS_baseUrl: "https://artemis-nginx"
Expand All @@ -24,6 +24,7 @@ services:
SORRY_CYPRESS_BUILD_ID: "${bamboo_buildNumber}"
SORRY_CYPRESS_BRANCH_NAME: "${bamboo_planRepository_branchName}"
SORRY_CYPRESS_PROJECT_ID: "artemis-mysql"
NO_COLOR: "1"
command: sh -c "cd /app/artemis/src/test/cypress && chmod 777 /root && npm ci && npm run cypress:run"
volumes:
- ..:/app/artemis
Expand Down
3 changes: 3 additions & 0 deletions docker/sorry-cypress/nginx.conf
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,9 @@ http {
ssl_ciphers 'TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384';
ssl_prefer_server_ciphers on;

# This is needed to allow video file uploads, that are greater than 1MB
client_max_body_size 100M;

location / {
proxy_pass http://sry-cypress-minio:9090;
proxy_http_version 1.1;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ export class CodeEditorTutorAssessmentInlineFeedbackComponent {
// Expose the function to the template
readonly roundScoreSpecifiedByCourseSettings = roundValueSpecifiedByCourseSettings;

public elementRef: ElementRef;

viewOnly: boolean;
oldFeedback: Feedback;

Expand All @@ -58,7 +60,9 @@ export class CodeEditorTutorAssessmentInlineFeedbackComponent {
faTrashAlt = faTrashAlt;
faExclamationTriangle = faExclamationTriangle;

constructor(private translateService: TranslateService, public structuredGradingCriterionService: StructuredGradingCriterionService) {}
constructor(private translateService: TranslateService, public structuredGradingCriterionService: StructuredGradingCriterionService, elementRef: ElementRef) {
this.elementRef = elementRef;
}

/**
* Updates the current feedback and sets props and emits the feedback to parent component
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
<div class="btn-inline-comment">
<fa-icon [icon]="faPlusSquare" size="lg"></fa-icon>
</div>
<div *ngFor="let line of lineCounter; let i = index" id="test-{{ i }}" class="inline-feedback-d-none">
<div *ngFor="let line of linesWithInlineFeedbackShown" class="inline-feedback">
<jhi-code-editor-tutor-assessment-inline-feedback
[selectedFile]="selectedFile"
[codeLine]="i"
[feedback]="fileFeedbackPerLine[i]"
[codeLine]="line"
[feedback]="fileFeedbackPerLine[line]"
[readOnly]="readOnlyManualFeedback"
[highlightDifferences]="highlightDifferences"
[course]="course"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,21 @@ import 'brace/mode/vhdl';
import 'brace/theme/dreamweaver';
import 'brace/theme/dracula';
import { AceEditorComponent } from 'app/shared/markdown-editor/ace-editor/ace-editor.component';
import { AfterViewInit, Component, EventEmitter, Input, OnChanges, OnDestroy, Output, SimpleChanges, ViewChild, ViewEncapsulation } from '@angular/core';
import {
AfterViewInit,
ChangeDetectorRef,
Component,
EventEmitter,
Input,
OnChanges,
OnDestroy,
Output,
QueryList,
SimpleChanges,
ViewChild,
ViewChildren,
ViewEncapsulation,
} from '@angular/core';
import { Subscription, fromEvent, of } from 'rxjs';
import { catchError, tap } from 'rxjs/operators';
import { CommitState, CreateFileChange, DeleteFileChange, EditorState, FileChange, RenameFileChange } from 'app/exercises/programming/shared/code-editor/model/code-editor.model';
Expand All @@ -29,6 +43,7 @@ import { fromPairs, pickBy } from 'lodash-es';
import { Feedback } from 'app/entities/feedback.model';
import { Course } from 'app/entities/course.model';
import { faCircleNotch, faPlusSquare } from '@fortawesome/free-solid-svg-icons';
import { CodeEditorTutorAssessmentInlineFeedbackComponent } from 'app/exercises/programming/assess/code-editor-tutor-assessment-inline-feedback.component';

export type Annotation = { fileName: string; row: number; column: number; text: string; type: string; timestamp: number; hash?: string };

Expand All @@ -42,6 +57,8 @@ export type Annotation = { fileName: string; row: number; column: number; text:
export class CodeEditorAceComponent implements AfterViewInit, OnChanges, OnDestroy {
@ViewChild('editor', { static: true })
editor: AceEditorComponent;
@ViewChildren(CodeEditorTutorAssessmentInlineFeedbackComponent)
inlineFeedbackComponents: QueryList<CodeEditorTutorAssessmentInlineFeedbackComponent>;
@Input()
selectedFile: string;
@Input()
Expand Down Expand Up @@ -93,9 +110,8 @@ export class CodeEditorAceComponent implements AfterViewInit, OnChanges, OnDestr
fileSession: { [fileName: string]: { code: string; cursor: { column: number; row: number } } } = {};
// Inline feedback variables
fileFeedbacks: Feedback[];
lineCounter: any[] = [];
private elementArray: Element[] = [];
fileFeedbackPerLine: { [line: number]: Feedback } = {};
linesWithNewFeedback: number[] = []; // lines with new feedback, which is not yet saved, but must already be displayed to be editable
editorSession: any;
markerIds: number[] = [];
gutterHighlights: Map<number, string[]> = new Map<number, string[]>();
Expand All @@ -105,7 +121,21 @@ export class CodeEditorAceComponent implements AfterViewInit, OnChanges, OnDestr
readonly faPlusSquare = faPlusSquare;
readonly faCircleNotch = faCircleNotch;

constructor(private repositoryFileService: CodeEditorRepositoryFileService, private fileService: CodeEditorFileService, protected localStorageService: LocalStorageService) {}
/**
* Get all line numbers in the current editor session that have inline feedback or new feedback (which is only shown temporarily)
*/
get linesWithInlineFeedbackShown(): number[] {
const lines = this.linesWithNewFeedback.concat(Object.keys(this.fileFeedbackPerLine).map((line) => parseInt(line)));
lines.sort((a, b) => a - b);
return lines;
}

constructor(
private repositoryFileService: CodeEditorRepositoryFileService,
private fileService: CodeEditorFileService,
protected localStorageService: LocalStorageService,
private changeDetectorRef: ChangeDetectorRef,
) {}

/**
* @function ngAfterViewInit
Expand Down Expand Up @@ -178,6 +208,8 @@ export class CodeEditorAceComponent implements AfterViewInit, OnChanges, OnDestr
}
});
}
// Remove open inline feedback widgets for new feedback
this.linesWithNewFeedback = [];
// We first remove the annotationChange subscription so the initial setValue doesn't count as an insert
if (this.annotationChange) {
this.annotationChange.unsubscribe();
Expand All @@ -199,10 +231,7 @@ export class CodeEditorAceComponent implements AfterViewInit, OnChanges, OnDestr
this.displayAnnotations();

// Setup inline feedbacks
// Get amount of lines of code in order to render for each line a corresponding inline feedback component
if (this.isTutorAssessment) {
const lines = this.editor.getEditor().getSession().getLength();
this.lineCounter = new Array(lines);
if (!this.feedbacks) {
this.feedbacks = [];
}
Expand Down Expand Up @@ -281,6 +310,13 @@ export class CodeEditorAceComponent implements AfterViewInit, OnChanges, OnDestr
if (this.annotationChange) {
this.annotationChange.unsubscribe();
}
// remove all line widgets so that no old ones are displayed when the editor is opened again
if (this.editorSession && this.editorSession.widgetManager) {
for (const line of this.linesWithInlineFeedbackShown) {
const widget = this.editorSession.lineWidgets.find((w: any) => w?.el === this.getInlineFeedbackNode(line));
this.editorSession.widgetManager.removeLineWidget(widget);
}
}
}

/**
Expand Down Expand Up @@ -419,7 +455,7 @@ export class CodeEditorAceComponent implements AfterViewInit, OnChanges, OnDestr

/**
* Displays the inline feedback of a line of code using lineWidgets. We first go through all feedbacks of the selected file
* and create a lineWidget for each feedback. The elementArray contains all inline feedback components which have been added as lineWidget.
* and create a lineWidget for each feedback.
*/
displayFeedbacks() {
this.fileFeedbacks.forEach((feedback) => {
Expand Down Expand Up @@ -450,19 +486,25 @@ export class CodeEditorAceComponent implements AfterViewInit, OnChanges, OnDestr
});
}

/**
* Get the wrapper div of an inline feedback as a DOM node
*
* @param line line of code where the feedback inline component is located
*/
getInlineFeedbackNode(line: number): Element | undefined {
return this.inlineFeedbackComponents.find((c) => c.codeLine === line)?.elementRef.nativeElement;
}

/**
* Add lineWidget for specific line of code.
* @param line line of code where the feedback inline component will be added to.
*/
addLineWidgetWithFeedback(line: number) {
// If the component was not found in the elementArray, we get it from the DOM and add it to elementArray
let inlineFeedback: Element | undefined = this.elementArray.find((element) => element.id === 'test-' + line);
if (!inlineFeedback) {
inlineFeedback = document.querySelector(`#test-${line}`) ?? undefined;
if (inlineFeedback) {
this.elementArray.push(inlineFeedback);
}
}
// Create new feedback element from the DOM
this.linesWithNewFeedback = [...this.linesWithNewFeedback, line];
// Update DOM so that the new feedback DOM node exists
this.changeDetectorRef.detectChanges();
const inlineFeedback = this.getInlineFeedbackNode(line);
if (inlineFeedback) {
const lineWidget = {
row: line,
Expand All @@ -474,12 +516,10 @@ export class CodeEditorAceComponent implements AfterViewInit, OnChanges, OnDestr
if (this.editorSession.lineWidgets) {
const displayedWidget = this.editorSession.lineWidgets.find((w: any) => w && w.row === lineWidget.row);
if (!displayedWidget) {
lineWidget.el.className = 'inline-feedback';
this.editorSession.widgetManager.addLineWidget(lineWidget);
lineWidget.el.querySelector('textarea')?.focus();
}
} else {
lineWidget.el.className = 'inline-feedback';
this.editorSession.widgetManager.addLineWidget(lineWidget);
lineWidget.el.querySelector('textarea')?.focus();
}
Expand All @@ -491,7 +531,7 @@ export class CodeEditorAceComponent implements AfterViewInit, OnChanges, OnDestr
* @param line Line of code which has inline feedback (lineWidget)
*/
adjustLineWidgetHeight(line: number) {
const widget = this.editorSession.lineWidgets.find((w: any) => w && w.el?.id === 'test-' + line);
const widget = this.editorSession.lineWidgets.find((w: any) => w?.el === this.getInlineFeedbackNode(line));
this.editorSession.widgetManager.removeLineWidget(widget);
this.editorSession.widgetManager.addLineWidget(widget);
}
Expand All @@ -510,6 +550,8 @@ export class CodeEditorAceComponent implements AfterViewInit, OnChanges, OnDestr
} else {
this.feedbacks.push(feedback);
this.fileFeedbackPerLine[line] = feedback;
// the feedback isn't new anymore
this.linesWithNewFeedback = this.linesWithNewFeedback.filter((l) => l !== line);
}
this.onUpdateFeedback.emit(this.feedbacks);
this.adjustLineWidgetHeight(line);
Expand All @@ -520,11 +562,14 @@ export class CodeEditorAceComponent implements AfterViewInit, OnChanges, OnDestr
* @param line
*/
cancelFeedback(line: number) {
if (!this.fileFeedbackPerLine[line]) {
const widget = this.editorSession.lineWidgets.filter((w: any) => w && w.el?.id === 'test-' + line)[0];
this.editorSession.widgetManager.removeLineWidget(widget);
} else {
if (this.fileFeedbackPerLine[line]) {
// feedback exists, just re-align height
this.adjustLineWidgetHeight(line);
} else {
const widget = this.editorSession.lineWidgets.filter((w: any) => w?.el === this.getInlineFeedbackNode(line))[0];
this.editorSession.widgetManager.removeLineWidget(widget);
// also remove from linesWithNewFeedback, it should not be shown anymore
this.linesWithNewFeedback = this.linesWithNewFeedback.filter((l) => l !== line);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,6 @@ Ace Editor
flex: 1 1 auto;
}

.inline-feedback-d-none {
display: none;
}

.inline-feedback {
display: block;
}
Expand Down Expand Up @@ -66,6 +62,11 @@ Ace Editor
}
}

.card-body > .inline-feedback {
/* The ACE Line Widget will copy this node to another place where it will be visible */
display: none;
}

.diff-newLine {
position: absolute;
background: var(--code-editor-diff-newline-background);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,8 @@ <h3 class="text-primary">
>
<fa-icon class="pe-3" [icon]="weeklyExercisesGrouped[weekKey].isCollapsed ? faAngleDown : faAngleUp"></fa-icon>
<span *ngIf="weeklyExercisesGrouped[weekKey].start && weeklyExercisesGrouped[weekKey].end">
{{ weeklyExercisesGrouped[weekKey].start | artemisDate : 'long-date' }} -
{{ weeklyExercisesGrouped[weekKey].end | artemisDate : 'long-date' }}
{{ weeklyExercisesGrouped[weekKey].start | artemisDate : 'short-date' }} -
{{ weeklyExercisesGrouped[weekKey].end | artemisDate : 'short-date' }}
</span>
<span *ngIf="!weeklyExercisesGrouped[weekKey].start || !weeklyExercisesGrouped[weekKey].end">
{{ 'artemisApp.courseOverview.exerciseList.noDateAssociated' | artemisTranslate }}
Expand Down
1 change: 1 addition & 0 deletions src/test/cypress/cypress.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export default defineConfig({
screenshotsFolder: 'screenshots',
videosFolder: 'videos',
video: true,
videoUploadOnPasses: false,
screenshotOnRunFailure: true,
viewportWidth: 1920,
viewportHeight: 1080,
Expand Down
2 changes: 1 addition & 1 deletion src/test/cypress/e2e/course/CourseCommunication.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ describe('Course communication', () => {
cy.login(studentOne, `/courses/${course.id}/discussion`);
courseCommunication.newPost();
courseCommunication.selectContextInModal(CourseWideContext.ORGANIZATION);
courseCommunication.setTitleInModal('Cypress Test Post');
courseCommunication.setTitleInModal('Test Post');
cy.fixture('loremIpsum.txt').then((text) => {
courseCommunication.setContentInModal(text);
});
Expand Down
16 changes: 8 additions & 8 deletions src/test/cypress/e2e/exam/ExamCreationDeletion.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ const examData = {
endDate: dayjs().add(2, 'day'),
numberOfExercises: 4,
maxPoints: 40,
startText: 'Cypress exam start text',
endText: 'Cypress exam end text',
confirmationStartText: 'Cypress exam confirmation start text',
confirmationEndText: 'Cypress exam confirmation end text',
startText: 'Exam start text',
endText: 'Exam end text',
confirmationStartText: 'Exam confirmation start text',
confirmationEndText: 'Exam confirmation end text',
};

const editedExamData = {
Expand All @@ -27,10 +27,10 @@ const editedExamData = {
endDate: dayjs().add(4, 'day'),
numberOfExercises: 3,
maxPoints: 30,
startText: 'Edited cypress exam start text',
endText: 'Edited cypress exam end text',
confirmationStartText: 'Edited cypress exam confirmation start text',
confirmationEndText: 'Edited cypress exam confirmation end text',
startText: 'Edited exam start text',
endText: 'Edited exam end text',
confirmationStartText: 'Edited exam confirmation start text',
confirmationEndText: 'Edited exam confirmation end text',
};

const dateFormat = 'MMM D, YYYY HH:mm';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ const examData = {
workingTime: 5,
numberOfExercises: 4,
maxPoints: 40,
startText: 'Cypress exam start text',
endText: 'Cypress exam end text',
confirmationStartText: 'Cypress exam confirmation start text',
confirmationEndText: 'Cypress exam confirmation end text',
startText: 'Exam start text',
endText: 'Exam end text',
confirmationStartText: 'Exam confirmation start text',
confirmationEndText: 'Exam confirmation end text',
};

describe('Test Exam creation/deletion', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ describe('Modeling Exercise Management Spec', () => {

it('Edit Existing Modeling Exercise', () => {
cy.visit(`/course-management/${course.id}/modeling-exercises/${modelingExercise.id}/edit`);
const newTitle = 'Cypress EDITED ME';
const newTitle = 'New Modeling Exercise Title';
const points = 100;
modelingExerciseCreation.setTitle(newTitle);
modelingExerciseCreation.pickDifficulty({ hard: true });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,9 @@ describe('Programming Exercise Management', () => {
courseManagementExercises.createProgrammingExercise();
cy.url().should('include', '/programming-exercises/new');
cy.log('Filling out programming exercise info...');
const exerciseTitle = 'Cypress programming exercise ' + generateUUID();
const exerciseTitle = 'Programming exercise ' + generateUUID();
programmingExerciseCreation.setTitle(exerciseTitle);
programmingExerciseCreation.setShortName('cypress' + generateUUID());
programmingExerciseCreation.setShortName('programming' + generateUUID());
programmingExerciseCreation.setPackageName('de.test');
programmingExerciseCreation.setPoints(100);
programmingExerciseCreation.checkAllowOnlineEditor();
Expand Down
Loading

0 comments on commit 746e454

Please sign in to comment.