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

Batch-Add and Housekeeping #484

Merged
merged 19 commits into from
Jul 11, 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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ We provide a dedicated __client__ DRES OpenApi specifications for systems to be

## Requirements

To deploy and run DRES, a JRE of at least Java 11 is required, e.g. the [OpenJDK 11](https://jdk.java.net/java-se-ri/11).
To deploy and run DRES, a JRE of at least Java 17 is required, e.g. the [OpenJDK 17](https://jdk.java.net/java-se-ri/17).
For development, besides the JDK, addtitionally [NPM](https://www.npmjs.com/) and the [Angular CLI](https://cli.angular.io/) is recommended.

## Citation
Expand Down
15 changes: 9 additions & 6 deletions backend/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ apply plugin: 'kotlin-kapt'
apply plugin: 'idea'

mainClassName = 'dev.dres.DRES'
sourceCompatibility = 11
sourceCompatibility = 17

/* Configuration for frontend classpath files (see dependencies). */
configurations {
Expand All @@ -37,11 +37,11 @@ repositories {
}

compileKotlin {
kotlinOptions.jvmTarget = "11"
kotlinOptions.jvmTarget = "17"
compilerOptions.freeCompilerArgs.add("-Xcontext-receivers")
}
compileTestKotlin {
kotlinOptions.jvmTarget = "11"
kotlinOptions.jvmTarget = "17"
compilerOptions.freeCompilerArgs.add("-Xcontext-receivers")
}

Expand Down Expand Up @@ -105,18 +105,18 @@ dependencies {
testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: version_junit

///// Jackson / Kotlin
implementation group: 'com.fasterxml.jackson.module', name: 'jackson-module-kotlin', version: '2.13.0'
implementation group: 'com.fasterxml.jackson.module', name: 'jackson-module-kotlin', version: version_jackson_kotlin

///// Kotlin
implementation group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib', version: version_kotlin
implementation group: 'org.jetbrains.kotlin', name: 'kotlin-reflect', version: version_kotlin
implementation group: 'org.jetbrains.kotlinx', name:'kotlinx-serialization-json', version: '1.6.2'
implementation group: 'org.jetbrains.kotlinx', name:'kotlinx-serialization-json', version: version_kotlinx_serialization
}

kapt {
correctErrorTypes true
useBuildCache true
targetCompatibility = 11
targetCompatibility = 17
}


Expand Down Expand Up @@ -220,3 +220,6 @@ startScripts {
windowsScript.text = windowsScript.text.replaceAll('set CLASSPATH=.*', 'set CLASSPATH=.;%APP_HOME%/lib/*')
}
}

/* Exclude logback-classic. 8. July 2024: Leak comes from openapi-annotation */
configurations.all*.exclude module: "logback-classic"
786 changes: 0 additions & 786 deletions frontend/.yarn/releases/yarn-3.2.0.cjs

This file was deleted.

875 changes: 875 additions & 0 deletions frontend/.yarn/releases/yarn-3.8.3.cjs

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion frontend/.yarnrc.yml
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
yarnPath: .yarn/releases/yarn-3.2.0.cjs
nodeLinker: node-modules

yarnPath: .yarn/releases/yarn-3.8.3.cjs
12 changes: 6 additions & 6 deletions frontend/angular.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"outputPath": "dist/dres-frontend",
"index": "src/index.html",
"main": "src/main.ts",
"polyfills": "src/polyfills.ts",
"polyfills": ["zone.js"],
"tsConfig": "tsconfig.app.json",
"aot": true,
"assets": ["src/immutable", "src/config.json"],
Expand Down Expand Up @@ -68,29 +68,29 @@
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"options": {
"browserTarget": "dres-frontend:build"
"buildTarget": "dres-frontend:build"
},
"configurations": {
"production": {
"browserTarget": "dres-frontend:build:production"
"buildTarget": "dres-frontend:build:production"
},
"development": {
"browserTarget": "dres-frontend:build:development"
"buildTarget": "dres-frontend:build:development"
}
},
"defaultConfiguration": "development"
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"browserTarget": "dres-frontend:build"
"buildTarget": "dres-frontend:build"
}
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "src/test.ts",
"polyfills": "src/polyfills.ts",
"polyfills": ["zone.js"],
"tsConfig": "tsconfig.spec.json",
"karmaConfig": "karma.conf.js",
"assets": ["src/favicon.ico", "src/assets"],
Expand Down
6 changes: 3 additions & 3 deletions frontend/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@ task packageFrontend(type: Zip) {
return file("$buildDir/lib/dres-frontend.jar").exists()
}
dependsOn buildFrontend
baseName 'dres-frontend'
extension 'jar'
destinationDir file("$buildDir/lib")
archiveBaseName = 'dres-frontend'
archiveExtension = 'jar'
destinationDirectory= file("$buildDir/lib")
from("$buildDir/dist") {
println("includeConfig: "+includeConfig)
if(!includeConfig){
Expand Down
52 changes: 26 additions & 26 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,34 +21,34 @@
},
"private": true,
"dependencies": {
"@angular/animations": "15.x",
"@angular/cdk": "15.x",
"@angular/common": "15.x",
"@angular/compiler": "15.x",
"@angular/core": "15.x",
"@angular/forms": "15.x",
"@angular/material": "15.x",
"@angular/platform-browser": "15.x",
"@angular/platform-browser-dynamic": "15.x",
"@angular/router": "15.x",
"angularx-qrcode": "15.x",
"apexcharts": "3.x",
"ng-apexcharts": "1.x",
"ngx-color-picker": "^14.0.0",
"@angular/animations": "17.3.11",
"@angular/cdk": "17.3.10",
"@angular/common": "17.3.11",
"@angular/compiler": "17.3.11",
"@angular/core": "17.3.11",
"@angular/forms": "17.3.11",
"@angular/material": "17.3.10",
"@angular/platform-browser": "17.3.11",
"@angular/platform-browser-dynamic": "17.3.11",
"@angular/router": "17.3.11",
"angularx-qrcode": "16.0.2",
"apexcharts": "^3.41.0",
"ng-apexcharts": "^1.11.0",
"ngx-color-picker": "^17.0.0",
"rxjs": "7.x",
"tslib": "2.x",
"zone.js": "0.13.x"
"zone.js": "0.14.x"
},
"devDependencies": {
"@angular-devkit/build-angular": "15.x",
"@angular-eslint/builder": "15.x",
"@angular-eslint/eslint-plugin": "15.x",
"@angular-eslint/eslint-plugin-template": "15.x",
"@angular-eslint/schematics": "15.x",
"@angular-eslint/template-parser": "15.x",
"@angular/cli": "15.x",
"@angular/compiler-cli": "15.x",
"@angular/language-service": "15.x",
"@angular-devkit/build-angular": "17.3.8",
"@angular-eslint/builder": "16.x",
"@angular-eslint/eslint-plugin": "16.x",
"@angular-eslint/eslint-plugin-template": "16.x",
"@angular-eslint/schematics": "16.x",
"@angular-eslint/template-parser": "16.x",
"@angular/cli": "17.3.8",
"@angular/compiler-cli": "17.3.11",
"@angular/language-service": "17.3.11",
"@types/jasmine": "3.6.x",
"@types/jasminewd2": "2.0.x",
"@types/node": "12.11.x",
Expand Down Expand Up @@ -77,7 +77,7 @@
"stylelint-config-standard": "^25.0.0",
"stylelint-config-standard-scss": "^3.0.0",
"ts-node": "8.3.x",
"typescript": "4.x"
"typescript": "5.2"
},
"packageManager": "yarn@3.2.0"
"packageManager": "yarn@3.8.3"
}
Original file line number Diff line number Diff line change
Expand Up @@ -126,17 +126,18 @@ export class CompetitionFormBuilder {
*
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this whole thing be called evaluationBuilder or something?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair enough. However, as there are more significant changes in the pipeline (see https://github.com/orgs/dres-dev/projects/6/views/2) I'd suggest to merge this one first, so that the development of the other tasks is not delayed.

I took the liberty to convert this to a proper issue to tackle in this development cycle: #486

* @param type The {@link ApiTargetOption} to add a {@link FormGroup} for.
* @param initialise The {@link ApiTarget} to add
* @param store Only if initialise is not null. Whether to store the target. Propagated to the individual methods
*/
public addTargetForm(type: ApiTargetOption, initialise?: ApiTarget) {
public addTargetForm(type: ApiTargetOption, initialise?: ApiTarget, store: boolean = false, item?: ApiMediaItem) {
const array = this.form.get('target') as UntypedFormArray;
const newIndex = array.length;
switch (type) {
case "SINGLE_MEDIA_ITEM":
const f = this.singleMediaItemTargetForm(newIndex, initialise);
const f = this.singleMediaItemTargetForm(newIndex, initialise, store, item);
array.push(f)
return f;
case "SINGLE_MEDIA_SEGMENT":
const targetForm = this.singleMediaSegmentTargetForm(newIndex, initialise);
const targetForm = this.singleMediaSegmentTargetForm(newIndex, initialise, store, item);
array.push(targetForm);
return targetForm;
case "JUDGEMENT":
Expand All @@ -150,6 +151,10 @@ export class CompetitionFormBuilder {
default:
break;
}

if(store){
this.storeFormData()
}
}

/**
Expand Down Expand Up @@ -358,7 +363,7 @@ export class CompetitionFormBuilder {
* @param index Index of the FormControl
* @param initialize The optional {RestTaskDescriptionTargetItem} containing the data to initialize the form with.
*/
private singleMediaItemTargetForm(index: number, initialize?: ApiTarget): UntypedFormGroup {
private singleMediaItemTargetForm(index: number, initialize?: ApiTarget, store: boolean = false, item?: ApiMediaItem): UntypedFormGroup {
/* Prepare auto complete field. */
const mediaItemFormControl = new UntypedFormControl(null, [Validators.required, RequireMatch]);
const typeFormControl = new UntypedFormControl(ApiTargetType.MEDIA_ITEM);
Expand All @@ -373,9 +378,16 @@ export class CompetitionFormBuilder {
)
);

let resolveRequired = true

/* Set passed media item */
if(initialize?.target && item){
mediaItemFormControl.setValue(item, {emitEvent: false})
resolveRequired = false
}

/* Load media item from API. */
if (initialize?.target && this.form.get('mediaCollection')) {
if (resolveRequired && initialize?.target && this.form.get('mediaCollection')) {
this.collectionService
.getApiV2MediaItemByMediaItemId(initialize?.target)
.pipe(first())
Expand All @@ -393,7 +405,7 @@ export class CompetitionFormBuilder {
* @param index Index of the FormControl
* @param initialize The optional {RestTaskDescriptionTargetItem} to initialize the form with.
*/
private singleMediaSegmentTargetForm(index: number, initialize?: ApiTarget) {
private singleMediaSegmentTargetForm(index: number, initialize?: ApiTarget, store: boolean = false, item?: ApiMediaItem) {
/* Prepare auto complete field. */
const mediaItemFormControl = new UntypedFormControl(null, [Validators.required, RequireMatch]);
const typeFormControl = new UntypedFormControl(ApiTargetType.MEDIA_ITEM_TEMPORAL_RANGE);
Expand All @@ -408,8 +420,16 @@ export class CompetitionFormBuilder {
)
);

let resolveRequired = true

/* Set passed media item */
if(initialize?.target && item){
mediaItemFormControl.setValue(item, {emitEvent:false})
resolveRequired = false
}

/* Load media item from API. */
if (initialize?.target && this.form.get('mediaCollection')) {
if (resolveRequired && initialize?.target && this.form.get('mediaCollection')) {
this.collectionService
.getApiV2MediaItemByMediaItemId(initialize.target)
.pipe(first())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ <h1 mat-dialog-title>Add task type</h1>
<mat-form-field style="width: 20%">
<mat-label>Duration [s]</mat-label>
<input type="text" matInput placeholder="Duration [s]" formControlName="defaultTaskDuration" />
<mat-error *ngIf="form.get('defaultTaskDuration')?.invalid">Required. Name must consist of at least three characters.</mat-error>
<mat-error *ngIf="form.get('defaultTaskDuration')?.invalid">Required. Must be between 1 and 999999 seconds.</mat-error>
</mat-form-field>
</p>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ export class CompetitionBuilderTaskTypeDialogComponent implements OnInit, AfterV
name: new UntypedFormControl(this.data?.name, [Validators.required, Validators.minLength(3)]),

/* Default Duration. Required */
defaultTaskDuration: new UntypedFormControl(this.data?.duration, [Validators.required, Validators.min(1)]),
defaultTaskDuration: new UntypedFormControl(this.data?.duration, [Validators.required, Validators.min(1), Validators.max(999999)]),

/* Target Type. Required */
target: new UntypedFormControl(this.data?.targetOption, [Validators.required]),
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/app/services/can-deactivate.guard.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { Observable } from 'rxjs';
import { ActivatedRouteSnapshot, CanDeactivate, RouterStateSnapshot, UrlTree } from '@angular/router';
import { ActivatedRouteSnapshot, RouterStateSnapshot, UrlTree } from '@angular/router';
import { Injectable } from '@angular/core';

export interface DeactivationGuarded {
canDeactivate(nextState?: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean;
}

@Injectable()
export class CanDeactivateGuard implements CanDeactivate<DeactivationGuarded> {
export class CanDeactivateGuard {
canDeactivate(
component: DeactivationGuarded,
currentRoute: ActivatedRouteSnapshot,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,9 @@ export class BatchAddTargetDialogComponent {
}

save(){
this.dialogRef.close(this.textArea.nativeElement.value?.split('\n'))
/* Sanitation: break up on newline and trim each line */
const lines = this.textArea.nativeElement.value?.trim().split('\n')
this.dialogRef.close(lines.map(it => it.trim()))
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ <h2>
</mat-button-toggle>
</mat-button-toggle-group>
-->
<button
<button *ngIf="hasCollectionSet()"
mat-button
aria-label="Batch Target Add"
matTooltip="Batch Target Add"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,20 @@ export class TaskTemplateEditorComponent implements OnInit, OnDestroy {
}

public isFormValid(){
return this.form == undefined || this.form.valid;
if(this.builderService.hasTouchedTasks()){
return this?.form?.valid || true;
}else{
return true;
}
}

public hasCollectionSet(){
if(this.form){
if(this.form.get('mediaCollection')?.value){
return true
}
}
return false
}

public fetchData(){
Expand Down Expand Up @@ -380,17 +393,13 @@ export class TaskTemplateEditorComponent implements OnInit, OnDestroy {
switch(this.taskType.targetOption){
case "SINGLE_MEDIA_ITEM":
case "SINGLE_MEDIA_SEGMENT":
const obs = r.map(it =>{
return this.collectionService.getApiV2CollectionByCollectionIdByStartsWith(this.form.get('mediaCollection').value, it.trim())
});
forkJoin(obs).subscribe(itemsList => {
itemsList.forEach(it => {
if(it.length > 0){
this.collectionService.postApiV2CollectionByCollectionIdResolve(this.form.get('mediaCollection').value, r)
.subscribe(items => {
items.forEach(it => {
const type = this.taskType.targetOption === "SINGLE_MEDIA_ITEM" ? ApiTargetType.MEDIA_ITEM : ApiTargetType.MEDIA_ITEM_TEMPORAL_RANGE;
this.formBuilder.addTargetForm(this.taskType.targetOption, {type: type, target: it[0].mediaItemId} as ApiTarget)
}
this.formBuilder.addTargetForm(this.taskType.targetOption, {type: type, target: it.mediaItemId} as ApiTarget, true, it)
})
})
})
break;
case "JUDGEMENT":
case "VOTE":
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<button mat-icon-button (click)="back()">
<mat-icon>arrow_back</mat-icon>
</button>
<h1>Edit evaluation template {{(builderService.templateAsObservable() | async)?.id}} <span *ngIf="(builderService.dirty() | async)" class="warn-color">(unsaved changes)</span></h1>
<h1 matTooltip="{{(builderService.templateAsObservable() | async)?.id}}">Edit evaluation template {{(builderService.templateAsObservable() | async)?.name}} <span *ngIf="(builderService.dirty() | async)" class="warn-color">(unsaved changes)</span></h1>
</div>

<div class="spacer-flex"></div>
Expand Down
Loading
Loading