diff --git a/src/main/webapp/app/exercise/import/exercise-import.component.html b/src/main/webapp/app/exercise/import/exercise-import.component.html index 0c5bd47c3cd32f12ee589c5780177243bf01b0f0..a64aa27cd49a473be01839489bef2ad1789a8957 100644 --- a/src/main/webapp/app/exercise/import/exercise-import.component.html +++ b/src/main/webapp/app/exercise/import/exercise-import.component.html @@ -49,14 +49,29 @@ <div *ngIf="exerciseInfo.keyword.length < 1" class="alert alert-danger"> <span jhiTranslate="exercise.validation.minKeywords"></span> </div> - </div> - <h4 class="mt-5" jhiTranslate="exercise.import.form.optionalAttributes">Optional Attributes</h4> <div class="form-group"> <label class="form-control-label" jhiTranslate="exercise.metadata.description">Description</label> - <input type="text" class="form-control" name="description" [(ngModel)]='exerciseInfo.description' - [value]="exerciseInfo.description ? exerciseInfo.description : ''"/> + <textarea class="form-control" name="description" #description="ngModel" required [(ngModel)]='exerciseInfo.description' + [value]="exerciseInfo.description ? exerciseInfo.description : ''"></textarea> + </div> + <div *ngIf="description.invalid && (description.dirty || description.touched)" class="alert alert-danger"> + <span *ngIf="description.errors?.required" jhiTranslate="exercise.validation.required"></span> </div> + <div class="form-group"> + <label class="form-control-label" jhiTranslate="exercise.metadata.language.mix">Language</label> + <br> + <div class="btn-group"> + <div class="p-2 btn" *ngFor="let language of getLanguages()" + [ngClass]="{ 'btn-primary': isLanguage(language), 'btn-outline-primary': !isLanguage(language) }" + (click)="setLanguage(language)" jhiTranslate="exercise.metadata.{{language.toUpperCase()}}"> + </div> + </div> + <div *ngIf="!isLanguageSet()" class="alert alert-danger"> + <span jhiTranslate="exercise.validation.required"></span> + </div> + </div> + <h4 class="mt-5" jhiTranslate="exercise.import.form.optionalAttributes">Optional Attributes</h4> <div class="form-group"> <ng-template #helpStructure> {{ 'exercise.help.structure' | translate}}</ng-template> <fa-icon icon="info-circle" @@ -66,11 +81,6 @@ <input type="text" disabled class="form-control" name="structure" [(ngModel)]='exerciseInfo.structure' [value]="exerciseInfo.structure ? exerciseInfo.structure : ''"/> </div> - <div class="form-group"> - <label class="form-control-label" jhiTranslate="exercise.metadata.language.singular">Language</label> - <input type="text" class="form-control" name="language" [(ngModel)]='exerciseInfo.languages' - [value]="exerciseInfo.languages ? exerciseInfo.languages : ''"/> - </div> <div class="form-group position-relative"> <label class="form-control-label" jhiTranslate="exercise.metadata.programmingLanguage.plural">Programming languages</label> <tag-input [(ngModel)]='exerciseInfo.programmingLanguages' @@ -100,10 +110,13 @@ <label class="col form-control-label" jhiTranslate="exercise.metadata.person.email">Email</label> </div> <div class="grid-striped mb-2"> - <div class="row rounded" *ngFor="let creator of exerciseInfo.creator"> - <span class="col text-center my-auto">{{creator.name}}</span> - <span class="col text-center my-auto">{{creator.affiliation}}</span> - <span class="col text-center my-auto">{{creator.email}}</span> + <div class="row rounded" *ngFor="let creator of exerciseInfo.creator; index as i;"> + <input type="text" name="creatorName{{i}}" [(ngModel)]="exerciseInfo.creator[i].name" + [value]="exerciseInfo.creator[i].name" class="col text-center my-auto form-control"/> + <input type="text" name="creatorAffiliation{{i}}" [(ngModel)]="exerciseInfo.creator[i].affiliation" + [value]="exerciseInfo.creator[i].affiliation" class="col text-center my-auto form-control"/> + <input type="text" name="creatorEmail{{i}}" [(ngModel)]="exerciseInfo.creator[i].email" + [value]="exerciseInfo.creator[i].email" class="col text-center my-auto form-control"/> <div class="btn btn-outline-primary col-1" (click)="removeCreator(creator)">-</div> </div> </div> @@ -119,7 +132,7 @@ <input type="text" class="form-control" name="source" [(ngModel)]='exerciseInfo.source' [value]="exerciseInfo.source ? exerciseInfo.source : ''"/> </div> - <button type="submit" [disabled]="importForm.form.invalid || isLoading" class="btn btn-outline-primary mt-3"> + <button type="submit" [disabled]="importForm.form.invalid || hasValidationErrors() || isLoading" class="btn btn-outline-primary mt-3"> <fa-icon class="align-middle" [icon]="'save'"></fa-icon> <span jhiTranslate="exercise.import.form.submit">Submit</span> </button> </form> diff --git a/src/main/webapp/app/exercise/import/exercise-import.component.ts b/src/main/webapp/app/exercise/import/exercise-import.component.ts index 123f6082c4903acce3e56d851a8af8d5dab4bb13..ce5c57694c704d3d9d719b53fc17187f1a6f857f 100644 --- a/src/main/webapp/app/exercise/import/exercise-import.component.ts +++ b/src/main/webapp/app/exercise/import/exercise-import.component.ts @@ -44,6 +44,9 @@ export class ExerciseImportComponent implements OnInit { this.toTitleCase(programmingLanguage) ); this.exerciseInfo.creator = data['creator']; + if (this.exerciseInfo.languages === undefined) { + this.exerciseInfo.languages = ['english']; // default value if none is set + } }, error => { this.jhiAlertService.error('Error loading info of artemis exercise: ' + error.error); @@ -60,6 +63,7 @@ export class ExerciseImportComponent implements OnInit { if (this.exerciseInfo!.difficulty !== null) { this.exerciseInfo!.difficulty = this.exerciseInfo!.difficulty?.toLowerCase(); } + this.mapExerciseInfoValues(); this.openGitlabPathSelectorModal().then(gitlabGroup => { if (gitlabGroup !== undefined) { this.isLoading = true; @@ -89,6 +93,42 @@ export class ExerciseImportComponent implements OnInit { }); } + /** + * Validation function for button-groups. + * At least one value must be set. + * @return true if invalid and false if valid + */ + hasValidationErrors() { + if (this.exerciseInfo?.keyword === undefined || this.exerciseInfo?.languages === undefined) { + return true; + } + + if (!(this.exerciseInfo.keyword.length > 0)) { + return true; + } + + if (!(this.exerciseInfo.languages.length > 0)) { + return true; + } + + return false; + } + + /** + * Used to map specific attributes of + * the currently imported exercise to correct metadata values + */ + mapExerciseInfoValues() { + let index = this.exerciseInfo!.languages.indexOf('english'); + if (index !== -1) { + this.exerciseInfo!.languages[index] = 'en'; + } + index = this.exerciseInfo!.languages.indexOf('german'); + if (index !== -1) { + this.exerciseInfo!.languages[index] = 'de'; + } + } + /** * Used to set the exercise's difficulty on * user's click @@ -98,6 +138,18 @@ export class ExerciseImportComponent implements OnInit { this.exerciseInfo!.difficulty = difficulty; } + /** + * Used to add a language to the exercise + * @param language to add + */ + setLanguage(language: string) { + if (this.exerciseInfo!.languages.includes(language)) { + this.exerciseInfo!.languages = this.exerciseInfo!.languages.filter(lang => lang !== language); + } else { + this.exerciseInfo!.languages.push(language); + } + } + /** * used to set the exercise's type * @param type to set @@ -145,6 +197,14 @@ export class ExerciseImportComponent implements OnInit { return ['simple', 'medium', 'advanced']; } + /** + * Utility function used to retrieve the possible languages + * for an exercise + */ + getLanguages() { + return ['english', 'german']; + } + /** * Utility function used to retrieve the possible types */ @@ -175,4 +235,20 @@ export class ExerciseImportComponent implements OnInit { return false; } } + + /** + * Utility function used to check if a given language is set + * in the imported exercsie + * @param language + */ + isLanguage(language: string) { + return this.exerciseInfo!.languages !== undefined && this.exerciseInfo!.languages.includes(language); + } + + /** + * Used to validate language input + */ + isLanguageSet() { + return this.exerciseInfo!.languages !== undefined && this.exerciseInfo!.languages.length > 0; + } }