diff --git a/frontend/src/app/components/library-management/library-management.component.html b/frontend/src/app/components/library-management/library-management.component.html new file mode 100644 index 0000000..4a7aba7 --- /dev/null +++ b/frontend/src/app/components/library-management/library-management.component.html @@ -0,0 +1,71 @@ +
+
+ + + + + + + + + + + + + + + + + + + + +
Path {{element.path}} Game {{element.title}} ({{getFullYearFromTimestamp(element.releaseDate)}}) + + + + + +
+
+ + + + + + + + + + + + + + + + +
Path {{element.path}} + + + + +
+
+
+
+ +
diff --git a/frontend/src/app/components/library-management/library-management.component.scss b/frontend/src/app/components/library-management/library-management.component.scss new file mode 100644 index 0000000..169006a --- /dev/null +++ b/frontend/src/app/components/library-management/library-management.component.scss @@ -0,0 +1,3 @@ +td, th { + padding: 16px !important; +} diff --git a/frontend/src/app/components/library-management/library-management.component.spec.ts b/frontend/src/app/components/library-management/library-management.component.spec.ts new file mode 100644 index 0000000..3ac170a --- /dev/null +++ b/frontend/src/app/components/library-management/library-management.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { LibraryManagementComponent } from './library-management.component'; + +describe('LibraryManagementComponent', () => { + let component: LibraryManagementComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ LibraryManagementComponent ] + }) + .compileComponents(); + + fixture = TestBed.createComponent(LibraryManagementComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/frontend/src/app/components/library-management/library-management.component.ts b/frontend/src/app/components/library-management/library-management.component.ts new file mode 100644 index 0000000..96f92ff --- /dev/null +++ b/frontend/src/app/components/library-management/library-management.component.ts @@ -0,0 +1,64 @@ +import {Component, OnInit} from '@angular/core'; +import {DetectedGameDto} from "../../models/dtos/DetectedGameDto"; +import {GamesService} from "../../services/games.service"; +import {LibraryManagementService} from "../../services/library-management.service"; +import {UnmappedFileDto} from "../../models/dtos/UnmappedFileDto"; +import {LibraryService} from "../../services/library.service"; +import {DialogService} from "../../services/dialog.service"; + +@Component({ + selector: 'app-library-management', + templateUrl: './library-management.component.html', + styleUrls: ['./library-management.component.scss'] +}) +export class LibraryManagementComponent implements OnInit { + + gameMappingTableColumns: string[] = ["path", "game", "actions"]; + unmappedGameTableColumns: string[] = ["path", "actions"]; + + mappedGames!: DetectedGameDto[]; + unmappedFiles!: UnmappedFileDto[]; + + constructor(private gameService: GamesService, + private libraryManagementService: LibraryManagementService, + private dialogService: DialogService) { + } + + ngOnInit(): void { + this.refreshMappedGamesList(); + this.refreshUnmappedFilesList(); + } + + refreshMappedGamesList(): void { + this.gameService.getAllGames().subscribe(games => this.mappedGames = games); + } + + getFullYearFromTimestamp(timestamp: number): number { + return new Date(timestamp).getFullYear(); + } + + confirmGameMapping(mappedGame: DetectedGameDto): void { + this.libraryManagementService.confirmGameMapping(mappedGame.slug).subscribe(() => mappedGame.confirmedMatch = true); + } + + deleteGameMapping(mappedGame: DetectedGameDto): void { + this.libraryManagementService.deleteGame(mappedGame.slug).subscribe(() => this.mappedGames = this.mappedGames.filter(game => game !== mappedGame)); + } + + openCorrectMappingDialog(mappedGame: DetectedGameDto): void { + this.dialogService.correctGameMappingDialog(mappedGame); + } + + refreshUnmappedFilesList(): void { + this.libraryManagementService.getUnmappedFiles().subscribe(unmappedFiles => this.unmappedFiles = unmappedFiles); + } + + deleteUnmappedFile(unmappedFile: UnmappedFileDto): void { + this.libraryManagementService.deleteUnmappedFile(unmappedFile.id).subscribe(() => this.unmappedFiles = this.unmappedFiles.filter(uf => uf !== unmappedFile)); + } + + openMapUnmappedFileDialog(unmappedFile: UnmappedFileDto): void { + this.dialogService.mapUnmappedGameDialog(unmappedFile); + } + +} diff --git a/frontend/src/app/components/map-game-dialog/map-game-dialog.component.html b/frontend/src/app/components/map-game-dialog/map-game-dialog.component.html new file mode 100644 index 0000000..25412bd --- /dev/null +++ b/frontend/src/app/components/map-game-dialog/map-game-dialog.component.html @@ -0,0 +1,15 @@ +

Map game to IGDB slug

+ +
+ +

Path: {{path}}

+ + + + +
+
+ + + + diff --git a/frontend/src/app/components/map-game-dialog/map-game-dialog.component.scss b/frontend/src/app/components/map-game-dialog/map-game-dialog.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/frontend/src/app/components/map-game-dialog/map-game-dialog.component.spec.ts b/frontend/src/app/components/map-game-dialog/map-game-dialog.component.spec.ts new file mode 100644 index 0000000..fc22839 --- /dev/null +++ b/frontend/src/app/components/map-game-dialog/map-game-dialog.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { MapGameDialogComponent } from './map-game-dialog.component'; + +describe('MapGameDialogComponent', () => { + let component: MapGameDialogComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ MapGameDialogComponent ] + }) + .compileComponents(); + + fixture = TestBed.createComponent(MapGameDialogComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/frontend/src/app/components/map-game-dialog/map-game-dialog.component.ts b/frontend/src/app/components/map-game-dialog/map-game-dialog.component.ts new file mode 100644 index 0000000..30df899 --- /dev/null +++ b/frontend/src/app/components/map-game-dialog/map-game-dialog.component.ts @@ -0,0 +1,37 @@ +import {Component, Inject, OnInit} from '@angular/core'; +import {FormBuilder, FormControl} from "@angular/forms"; +import {LibraryManagementService} from "../../services/library-management.service"; +import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog"; +import {PathToSlugDto} from "../../models/dtos/PathToSlugDto"; + +@Component({ + selector: 'app-map-game-dialog', + templateUrl: './map-game-dialog.component.html', + styleUrls: ['./map-game-dialog.component.scss'] +}) +export class MapGameDialogComponent implements OnInit { + + path: string; + currentSlug?: string; + newSlugInput: FormControl; + + constructor(private fb: FormBuilder, + private libraryManagementService: LibraryManagementService, + public dialogRef: MatDialogRef, + @Inject(MAT_DIALOG_DATA) data: any) { + this.path = data.path; + this.currentSlug = data.slug; + this.newSlugInput = new FormControl(this.currentSlug); + } + + ngOnInit() { + } + + close() { + this.dialogRef.close(); + } + + submit(): void { + this.libraryManagementService.mapGame(new PathToSlugDto(this.newSlugInput.value, this.path)).subscribe(() => this.close()) + } +} diff --git a/frontend/src/app/services/library-management.service.spec.ts b/frontend/src/app/services/library-management.service.spec.ts new file mode 100644 index 0000000..741b253 --- /dev/null +++ b/frontend/src/app/services/library-management.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { LibraryManagementService } from './library-management.service'; + +describe('LibraryManagementService', () => { + let service: LibraryManagementService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(LibraryManagementService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/frontend/src/app/services/library-management.service.ts b/frontend/src/app/services/library-management.service.ts new file mode 100644 index 0000000..23e992b --- /dev/null +++ b/frontend/src/app/services/library-management.service.ts @@ -0,0 +1,39 @@ +import {Injectable} from '@angular/core'; +import {HttpClient} from "@angular/common/http"; +import {Observable} from "rxjs"; +import {DetectedGameDto} from "../models/dtos/DetectedGameDto"; +import {PathToSlugDto} from "../models/dtos/PathToSlugDto"; +import {UnmappedFileDto} from "../models/dtos/UnmappedFileDto"; +import {LibraryManagementApi} from "../api/LibraryManagementApi"; + +@Injectable({ + providedIn: 'root' +}) +export class LibraryManagementService implements LibraryManagementApi { + + private readonly apiPath = '/library-management'; + + constructor(private http: HttpClient) { + } + + mapGame(pathToSlugDto: PathToSlugDto): Observable { + return this.http.post(`${this.apiPath}/map-path`, pathToSlugDto); + } + + getUnmappedFiles(): Observable { + return this.http.get(`${this.apiPath}/unmapped-files`); + } + + confirmGameMapping(slug: string): Observable { + return this.http.get(`${this.apiPath}/confirm-game/${slug}`); + } + + deleteGame(slug: string): Observable { + return this.http.delete(`${this.apiPath}/delete-game/${slug}`); + } + + deleteUnmappedFile(id: number): Observable { + return this.http.delete(`${this.apiPath}/delete-unmapped-file/${id}`); + } + +}