mirror of
https://github.com/BrenBroZAYT/gameyfin.git
synced 2026-06-16 08:15:48 +00:00
Various improvements to game management interface
This commit is contained in:
Generated
+35
@@ -20,6 +20,7 @@
|
|||||||
"@angular/platform-browser-dynamic": "^14.0.0",
|
"@angular/platform-browser-dynamic": "^14.0.0",
|
||||||
"@angular/router": "^14.0.0",
|
"@angular/router": "^14.0.0",
|
||||||
"@angular/youtube-player": "^14.1.0",
|
"@angular/youtube-player": "^14.1.0",
|
||||||
|
"mat-table-filter": "^10.2.0",
|
||||||
"rxjs": "~7.5.0",
|
"rxjs": "~7.5.0",
|
||||||
"tslib": "^2.3.0",
|
"tslib": "^2.3.0",
|
||||||
"zone.js": "~0.11.4"
|
"zone.js": "~0.11.4"
|
||||||
@@ -7591,6 +7592,11 @@
|
|||||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
|
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/lodash-es": {
|
||||||
|
"version": "4.17.21",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
|
||||||
|
"integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="
|
||||||
|
},
|
||||||
"node_modules/lodash.debounce": {
|
"node_modules/lodash.debounce": {
|
||||||
"version": "4.0.8",
|
"version": "4.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
|
||||||
@@ -7889,6 +7895,21 @@
|
|||||||
"node": ">= 8"
|
"node": ">= 8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/mat-table-filter": {
|
||||||
|
"version": "10.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mat-table-filter/-/mat-table-filter-10.2.0.tgz",
|
||||||
|
"integrity": "sha512-IOuqsn+hKJRP7xRbhd71AzOoPH5FuzM9D8ySxk8OH2OqvdFeWOfwwgl1dEEwdV9L59We5OnlA9/5hd95w7/FvQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"lodash-es": "^4.17.20",
|
||||||
|
"tslib": "^2.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@angular/cdk": ">=10.2.7",
|
||||||
|
"@angular/common": ">=10.2.4",
|
||||||
|
"@angular/core": ">=10.2.4",
|
||||||
|
"@angular/material": ">=10.2.7"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/media-typer": {
|
"node_modules/media-typer": {
|
||||||
"version": "0.3.0",
|
"version": "0.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
|
||||||
@@ -17668,6 +17689,11 @@
|
|||||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
|
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"lodash-es": {
|
||||||
|
"version": "4.17.21",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
|
||||||
|
"integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="
|
||||||
|
},
|
||||||
"lodash.debounce": {
|
"lodash.debounce": {
|
||||||
"version": "4.0.8",
|
"version": "4.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
|
||||||
@@ -17903,6 +17929,15 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"mat-table-filter": {
|
||||||
|
"version": "10.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mat-table-filter/-/mat-table-filter-10.2.0.tgz",
|
||||||
|
"integrity": "sha512-IOuqsn+hKJRP7xRbhd71AzOoPH5FuzM9D8ySxk8OH2OqvdFeWOfwwgl1dEEwdV9L59We5OnlA9/5hd95w7/FvQ==",
|
||||||
|
"requires": {
|
||||||
|
"lodash-es": "^4.17.20",
|
||||||
|
"tslib": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"media-typer": {
|
"media-typer": {
|
||||||
"version": "0.3.0",
|
"version": "0.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
"@angular/platform-browser-dynamic": "^14.0.0",
|
"@angular/platform-browser-dynamic": "^14.0.0",
|
||||||
"@angular/router": "^14.0.0",
|
"@angular/router": "^14.0.0",
|
||||||
"@angular/youtube-player": "^14.1.0",
|
"@angular/youtube-player": "^14.1.0",
|
||||||
|
"mat-table-filter": "^10.2.0",
|
||||||
"rxjs": "~7.5.0",
|
"rxjs": "~7.5.0",
|
||||||
"tslib": "^2.3.0",
|
"tslib": "^2.3.0",
|
||||||
"zone.js": "~0.11.4"
|
"zone.js": "~0.11.4"
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import {UnmappedFileDto} from "../models/dtos/UnmappedFileDto";
|
|||||||
export interface LibraryManagementApi {
|
export interface LibraryManagementApi {
|
||||||
mapGame(pathToSlugDto: PathToSlugDto): Observable<DetectedGameDto>;
|
mapGame(pathToSlugDto: PathToSlugDto): Observable<DetectedGameDto>;
|
||||||
getUnmappedFiles(): Observable<UnmappedFileDto[]>;
|
getUnmappedFiles(): Observable<UnmappedFileDto[]>;
|
||||||
confirmGameMapping(slug: string): Observable<DetectedGameDto>;
|
confirmGameMapping(slug: string, confirm: boolean): Observable<DetectedGameDto>;
|
||||||
deleteGame(slug: string): Observable<Response>;
|
deleteGame(slug: string): Observable<Response>;
|
||||||
deleteUnmappedFile(id: number): Observable<Response>;
|
deleteUnmappedFile(id: number): Observable<Response>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import {NavbarLayoutComponent} from "./layouts/navbar-layout/navbar-layout.compo
|
|||||||
import {LibraryOverviewComponent} from "./components/library-overview/library-overview.component";
|
import {LibraryOverviewComponent} from "./components/library-overview/library-overview.component";
|
||||||
import {GameDetailViewComponent} from "./components/game-detail-view/game-detail-view.component";
|
import {GameDetailViewComponent} from "./components/game-detail-view/game-detail-view.component";
|
||||||
import {LibraryManagementComponent} from "./components/library-management/library-management.component";
|
import {LibraryManagementComponent} from "./components/library-management/library-management.component";
|
||||||
|
import {MappedGamesTableComponent} from "./components/mapped-games-table/mapped-games-table.component";
|
||||||
|
|
||||||
const appRoutes: Routes = [
|
const appRoutes: Routes = [
|
||||||
{
|
{
|
||||||
@@ -23,6 +24,10 @@ const appRoutes: Routes = [
|
|||||||
path: 'library-management',
|
path: 'library-management',
|
||||||
component: LibraryManagementComponent
|
component: LibraryManagementComponent
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'test',
|
||||||
|
component: MappedGamesTableComponent
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '',
|
path: '',
|
||||||
redirectTo: '/library',
|
redirectTo: '/library',
|
||||||
|
|||||||
@@ -38,6 +38,12 @@ import {MatChipsModule} from "@angular/material/chips";
|
|||||||
import { LibraryManagementComponent } from './components/library-management/library-management.component';
|
import { LibraryManagementComponent } from './components/library-management/library-management.component';
|
||||||
import {MatTooltipModule} from "@angular/material/tooltip";
|
import {MatTooltipModule} from "@angular/material/tooltip";
|
||||||
import {MapGameDialogComponent} from "./components/map-game-dialog/map-game-dialog.component";
|
import {MapGameDialogComponent} from "./components/map-game-dialog/map-game-dialog.component";
|
||||||
|
import {MatSlideToggleModule} from "@angular/material/slide-toggle";
|
||||||
|
import {MatCheckboxModule} from "@angular/material/checkbox";
|
||||||
|
import {A11yModule} from "@angular/cdk/a11y";
|
||||||
|
import { MappedGamesTableComponent } from './components/mapped-games-table/mapped-games-table.component';
|
||||||
|
import {MatTableFilterModule} from "mat-table-filter";
|
||||||
|
import { UnmappedFilesTableComponent } from './components/unmapped-files-table/unmapped-files-table.component';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
@@ -52,38 +58,44 @@ import {MapGameDialogComponent} from "./components/map-game-dialog/map-game-dial
|
|||||||
GameScreenshotComponent,
|
GameScreenshotComponent,
|
||||||
GameVideoComponent,
|
GameVideoComponent,
|
||||||
LibraryManagementComponent,
|
LibraryManagementComponent,
|
||||||
MapGameDialogComponent
|
MapGameDialogComponent,
|
||||||
],
|
MappedGamesTableComponent,
|
||||||
imports: [
|
UnmappedFilesTableComponent
|
||||||
BrowserModule,
|
|
||||||
AppRoutingModule,
|
|
||||||
BrowserAnimationsModule,
|
|
||||||
FormsModule,
|
|
||||||
MatFormFieldModule,
|
|
||||||
MatCardModule,
|
|
||||||
MatTabsModule,
|
|
||||||
MatToolbarModule,
|
|
||||||
MatMenuModule,
|
|
||||||
MatIconModule,
|
|
||||||
HttpClientModule,
|
|
||||||
FormsModule,
|
|
||||||
ReactiveFormsModule,
|
|
||||||
MatDialogModule,
|
|
||||||
MatButtonModule,
|
|
||||||
MatInputModule,
|
|
||||||
FlexModule,
|
|
||||||
MatProgressSpinnerModule,
|
|
||||||
MatTableModule,
|
|
||||||
MatPaginatorModule,
|
|
||||||
MatSortModule,
|
|
||||||
MatSnackBarModule,
|
|
||||||
MatGridListModule,
|
|
||||||
FlexLayoutModule,
|
|
||||||
GridModule,
|
|
||||||
YouTubePlayerModule,
|
|
||||||
MatChipsModule,
|
|
||||||
MatTooltipModule
|
|
||||||
],
|
],
|
||||||
|
imports: [
|
||||||
|
BrowserModule,
|
||||||
|
AppRoutingModule,
|
||||||
|
BrowserAnimationsModule,
|
||||||
|
FormsModule,
|
||||||
|
MatFormFieldModule,
|
||||||
|
MatCardModule,
|
||||||
|
MatTabsModule,
|
||||||
|
MatToolbarModule,
|
||||||
|
MatMenuModule,
|
||||||
|
MatIconModule,
|
||||||
|
HttpClientModule,
|
||||||
|
FormsModule,
|
||||||
|
ReactiveFormsModule,
|
||||||
|
MatDialogModule,
|
||||||
|
MatButtonModule,
|
||||||
|
MatInputModule,
|
||||||
|
FlexModule,
|
||||||
|
MatProgressSpinnerModule,
|
||||||
|
MatTableModule,
|
||||||
|
MatPaginatorModule,
|
||||||
|
MatSortModule,
|
||||||
|
MatSnackBarModule,
|
||||||
|
MatGridListModule,
|
||||||
|
FlexLayoutModule,
|
||||||
|
GridModule,
|
||||||
|
YouTubePlayerModule,
|
||||||
|
MatChipsModule,
|
||||||
|
MatTooltipModule,
|
||||||
|
MatSlideToggleModule,
|
||||||
|
MatCheckboxModule,
|
||||||
|
A11yModule,
|
||||||
|
MatTableFilterModule
|
||||||
|
],
|
||||||
providers: [
|
providers: [
|
||||||
{
|
{
|
||||||
provide: HTTP_INTERCEPTORS,
|
provide: HTTP_INTERCEPTORS,
|
||||||
|
|||||||
@@ -10,11 +10,7 @@ import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog';
|
|||||||
<button mat-raised-button color="primary" (click)="onClick()">OK</button>
|
<button mat-raised-button color="primary" (click)="onClick()">OK</button>
|
||||||
</mat-dialog-actions>
|
</mat-dialog-actions>
|
||||||
`,
|
`,
|
||||||
styles: [`
|
styles: []
|
||||||
mat-dialog-content {
|
|
||||||
min-width: 250px;
|
|
||||||
}
|
|
||||||
`]
|
|
||||||
})
|
})
|
||||||
export class ErrorDialogComponent implements OnInit {
|
export class ErrorDialogComponent implements OnInit {
|
||||||
|
|
||||||
|
|||||||
@@ -1,70 +1,10 @@
|
|||||||
<div *ngIf="loggedIn && (this.unmappedFiles.length > 0 || this.mappedGames.length > 0)" fxFlexFill fxLayoutAlign="center start">
|
<div *ngIf="loggedIn && (this.unmappedFiles.length > 0 || this.mappedGames.length > 0)" fxFlexFill fxLayoutAlign="center start">
|
||||||
<mat-tab-group>
|
<mat-tab-group>
|
||||||
<mat-tab label="Game mappings">
|
<mat-tab label="Game mappings">
|
||||||
<table mat-table [dataSource]="mappedGames" class="mat-elevation-z8">
|
<mapped-games-table [mappedGames]="mappedGames"></mapped-games-table>
|
||||||
<ng-container matColumnDef="path">
|
|
||||||
<th mat-header-cell *matHeaderCellDef> Path</th>
|
|
||||||
<td mat-cell *matCellDef="let element"> {{element.path}} </td>
|
|
||||||
</ng-container>
|
|
||||||
|
|
||||||
<ng-container matColumnDef="game">
|
|
||||||
<th mat-header-cell *matHeaderCellDef> Game</th>
|
|
||||||
<td mat-cell *matCellDef="let element"> {{element.title}} ({{getFullYearFromTimestamp(element.releaseDate)}}
|
|
||||||
)
|
|
||||||
</td>
|
|
||||||
</ng-container>
|
|
||||||
|
|
||||||
<ng-container matColumnDef="actions">
|
|
||||||
<th mat-header-cell *matHeaderCellDef>
|
|
||||||
<button mat-icon-button (click)="refreshMappedGamesList()">
|
|
||||||
<mat-icon>refresh</mat-icon>
|
|
||||||
</button>
|
|
||||||
</th>
|
|
||||||
<td mat-cell *matCellDef="let element">
|
|
||||||
<button mat-icon-button (click)="confirmGameMapping(element)" [disabled]="element.confirmedMatch">
|
|
||||||
<mat-icon>check</mat-icon>
|
|
||||||
</button>
|
|
||||||
<button mat-icon-button (click)="openCorrectMappingDialog(element)">
|
|
||||||
<mat-icon>edit</mat-icon>
|
|
||||||
</button>
|
|
||||||
<button mat-icon-button (click)="deleteGameMapping(element)">
|
|
||||||
<mat-icon>delete</mat-icon>
|
|
||||||
</button>
|
|
||||||
</td>
|
|
||||||
</ng-container>
|
|
||||||
|
|
||||||
<tr mat-header-row *matHeaderRowDef="gameMappingTableColumns"></tr>
|
|
||||||
<tr mat-row *matRowDef="let row; columns: gameMappingTableColumns;"></tr>
|
|
||||||
</table>
|
|
||||||
</mat-tab>
|
</mat-tab>
|
||||||
|
|
||||||
|
|
||||||
<mat-tab label="Unmapped files">
|
<mat-tab label="Unmapped files">
|
||||||
<table mat-table [dataSource]="unmappedFiles" class="mat-elevation-z8">
|
<unmapped-files-table [unmappedFiles]="unmappedFiles"></unmapped-files-table>
|
||||||
<ng-container matColumnDef="path">
|
|
||||||
<th mat-header-cell *matHeaderCellDef> Path</th>
|
|
||||||
<td mat-cell *matCellDef="let element"> {{element.path}} </td>
|
|
||||||
</ng-container>
|
|
||||||
|
|
||||||
<ng-container matColumnDef="actions">
|
|
||||||
<th mat-header-cell *matHeaderCellDef>
|
|
||||||
<button mat-icon-button (click)="refreshUnmappedFilesList()">
|
|
||||||
<mat-icon>refresh</mat-icon>
|
|
||||||
</button>
|
|
||||||
</th>
|
|
||||||
<td mat-cell *matCellDef="let element">
|
|
||||||
<button mat-icon-button (click)="openMapUnmappedFileDialog(element)">
|
|
||||||
<mat-icon>edit</mat-icon>
|
|
||||||
</button>
|
|
||||||
<button mat-icon-button (click)="deleteUnmappedFile(element)">
|
|
||||||
<mat-icon>delete</mat-icon>
|
|
||||||
</button>
|
|
||||||
</td>
|
|
||||||
</ng-container>
|
|
||||||
|
|
||||||
<tr mat-header-row *matHeaderRowDef="unmappedGameTableColumns"></tr>
|
|
||||||
<tr mat-row *matRowDef="let row; columns: unmappedGameTableColumns;"></tr>
|
|
||||||
</table>
|
|
||||||
</mat-tab>
|
</mat-tab>
|
||||||
</mat-tab-group>
|
</mat-tab-group>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -3,17 +3,8 @@
|
|||||||
@import 'src/app/theme/default-theme';
|
@import 'src/app/theme/default-theme';
|
||||||
@import 'src/app/components/library-overview/library-overview.component';
|
@import 'src/app/components/library-overview/library-overview.component';
|
||||||
|
|
||||||
td, th {
|
|
||||||
padding: 16px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
table {
|
|
||||||
min-width: 50vw;
|
|
||||||
}
|
|
||||||
|
|
||||||
mat-tab-group {
|
mat-tab-group {
|
||||||
$config: mat.get-color-config($custom-theme);
|
$config: mat.get-color-config($custom-theme);
|
||||||
$background: map.get($config, background);
|
$background: map.get($config, background);
|
||||||
background: mat.get-color-from-palette($background, app-bar);
|
background: mat.get-color-from-palette($background, app-bar);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
import {Component, OnInit} from '@angular/core';
|
import {Component, OnInit} from '@angular/core';
|
||||||
import {DetectedGameDto} from "../../models/dtos/DetectedGameDto";
|
|
||||||
import {GamesService} from "../../services/games.service";
|
import {GamesService} from "../../services/games.service";
|
||||||
import {LibraryManagementService} from "../../services/library-management.service";
|
import {LibraryManagementService} from "../../services/library-management.service";
|
||||||
|
import {DetectedGameDto} from "../../models/dtos/DetectedGameDto";
|
||||||
import {UnmappedFileDto} from "../../models/dtos/UnmappedFileDto";
|
import {UnmappedFileDto} from "../../models/dtos/UnmappedFileDto";
|
||||||
import {LibraryService} from "../../services/library.service";
|
|
||||||
import {DialogService} from "../../services/dialog.service";
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-library-management',
|
selector: 'app-library-management',
|
||||||
@@ -12,58 +10,21 @@ import {DialogService} from "../../services/dialog.service";
|
|||||||
styleUrls: ['./library-management.component.scss']
|
styleUrls: ['./library-management.component.scss']
|
||||||
})
|
})
|
||||||
export class LibraryManagementComponent implements OnInit {
|
export class LibraryManagementComponent implements OnInit {
|
||||||
|
loggedIn: boolean = false;
|
||||||
gameMappingTableColumns: string[] = ["path", "game", "actions"];
|
|
||||||
unmappedGameTableColumns: string[] = ["path", "actions"];
|
|
||||||
|
|
||||||
mappedGames!: DetectedGameDto[];
|
mappedGames!: DetectedGameDto[];
|
||||||
unmappedFiles!: UnmappedFileDto[];
|
unmappedFiles!: UnmappedFileDto[];
|
||||||
|
|
||||||
loggedIn: boolean = false;
|
constructor(private gamesService: GamesService,
|
||||||
|
private libraryManagementService: LibraryManagementService) {
|
||||||
constructor(private gameService: GamesService,
|
|
||||||
private libraryManagementService: LibraryManagementService,
|
|
||||||
private dialogService: DialogService) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.refreshMappedGamesList();
|
this.gamesService.getAllGames().subscribe(games => this.mappedGames = games);
|
||||||
this.refreshUnmappedFilesList();
|
this.libraryManagementService.getUnmappedFiles().subscribe(uf => {
|
||||||
}
|
this.unmappedFiles = uf;
|
||||||
|
|
||||||
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;
|
|
||||||
this.loggedIn = true;
|
this.loggedIn = true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,6 @@
|
|||||||
</form>
|
</form>
|
||||||
</mat-dialog-content>
|
</mat-dialog-content>
|
||||||
<mat-dialog-actions align="end">
|
<mat-dialog-actions align="end">
|
||||||
<button mat-raised-button mat-dialog-close color="accent">Cancel</button>
|
<button mat-raised-button [mat-dialog-close]="false" color="accent">Cancel</button>
|
||||||
<button mat-raised-button (click)="submit()">OK</button>
|
<button mat-raised-button (click)="submit()" [disabled]="newSlugInput?.value?.length < 1" color="primary">OK</button>
|
||||||
</mat-dialog-actions>
|
</mat-dialog-actions>
|
||||||
|
|||||||
@@ -27,11 +27,11 @@ export class MapGameDialogComponent implements OnInit {
|
|||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
}
|
}
|
||||||
|
|
||||||
close() {
|
|
||||||
this.dialogRef.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
submit(): void {
|
submit(): void {
|
||||||
this.libraryManagementService.mapGame(new PathToSlugDto(this.newSlugInput.value, this.path)).subscribe(() => this.close())
|
this.libraryManagementService.mapGame(new PathToSlugDto(this.newSlugInput.value, this.path)).subscribe({
|
||||||
|
next: () => this.dialogRef.close(true),
|
||||||
|
error: () => this.dialogRef.close(false)
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
<div class="mat-elevation-z8">
|
||||||
|
<table mat-table matSort matTableFilter [dataSource]="dataSource" [exampleEntity]="filter" [debounceTime]="0">
|
||||||
|
<!-- Path column -->
|
||||||
|
<ng-container matColumnDef="path">
|
||||||
|
<th mat-header-cell *matHeaderCellDef mat-sort-header>Path</th>
|
||||||
|
<td mat-cell *matCellDef="let element"> {{element.path}} </td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<!-- Game column -->
|
||||||
|
<ng-container matColumnDef="game">
|
||||||
|
<th mat-header-cell *matHeaderCellDef mat-sort-header>Game</th>
|
||||||
|
<td mat-cell *matCellDef="let element"> {{element.title}} ({{getFullYearFromTimestamp(element.releaseDate)}})</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="actions">
|
||||||
|
<th mat-header-cell *matHeaderCellDef>
|
||||||
|
<button mat-icon-button (click)="toggleShowOnlyUnconfirmedMatches()">
|
||||||
|
<mat-icon *ngIf="showOnlyUnconfirmedMatches" matTooltip="Show all game mappings" matTooltipPosition="below" color="warn">playlist_add_check_circle</mat-icon>
|
||||||
|
<mat-icon *ngIf="!showOnlyUnconfirmedMatches" matTooltip="Show only unconfirmed game mappings" matTooltipPosition="below" fontSet="material-icons-outlined">playlist_add_check_circle</mat-icon>
|
||||||
|
</button>
|
||||||
|
<button mat-icon-button (click)="refreshMappedGamesList()">
|
||||||
|
<mat-icon matTooltip="Refresh game list" matTooltipPosition="below">refresh</mat-icon>
|
||||||
|
</button>
|
||||||
|
</th>
|
||||||
|
|
||||||
|
<!-- Action column -->
|
||||||
|
<td mat-cell *matCellDef="let element">
|
||||||
|
<button mat-icon-button (click)="toggleConfirmGameMapping(element)" [color]="element.confirmedMatch ? 'primary' : 'warn'">
|
||||||
|
<mat-icon [matTooltip]="element.confirmedMatch ? 'Unconfirm match':'Confirm match'" matTooltipPosition="below">check</mat-icon>
|
||||||
|
</button>
|
||||||
|
<button mat-icon-button (click)="openCorrectMappingDialog(element)">
|
||||||
|
<mat-icon>edit</mat-icon>
|
||||||
|
</button>
|
||||||
|
<button mat-icon-button (click)="deleteGameMapping(element)">
|
||||||
|
<mat-icon>delete</mat-icon>
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||||
|
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<mat-paginator
|
||||||
|
[length]="dataSource?.data?.length"
|
||||||
|
[pageIndex]="0"
|
||||||
|
[pageSize]="15"
|
||||||
|
[pageSizeOptions]="[10, 15, 25, 50]">
|
||||||
|
</mat-paginator>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
table {
|
||||||
|
min-width: 50vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-column-path {
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
.mat-column-game {
|
||||||
|
width: 35%;
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
|
import { MatPaginatorModule } from '@angular/material/paginator';
|
||||||
|
import { MatSortModule } from '@angular/material/sort';
|
||||||
|
import { MatTableModule } from '@angular/material/table';
|
||||||
|
|
||||||
|
import { MappedGamesTableComponent } from './mapped-games-table.component';
|
||||||
|
|
||||||
|
describe('MappedGamesTableComponent', () => {
|
||||||
|
let component: MappedGamesTableComponent;
|
||||||
|
let fixture: ComponentFixture<MappedGamesTableComponent>;
|
||||||
|
|
||||||
|
beforeEach(waitForAsync(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
declarations: [ MappedGamesTableComponent ],
|
||||||
|
imports: [
|
||||||
|
NoopAnimationsModule,
|
||||||
|
MatPaginatorModule,
|
||||||
|
MatSortModule,
|
||||||
|
MatTableModule,
|
||||||
|
]
|
||||||
|
}).compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(MappedGamesTableComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should compile', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
import {AfterViewInit, Component, Input, OnChanges, SimpleChanges, ViewChild} from '@angular/core';
|
||||||
|
import {MatPaginator} from '@angular/material/paginator';
|
||||||
|
import {MatSort} from '@angular/material/sort';
|
||||||
|
import {MatTable, MatTableDataSource} from '@angular/material/table';
|
||||||
|
import {DetectedGameDto} from "../../models/dtos/DetectedGameDto";
|
||||||
|
import {GamesService} from "../../services/games.service";
|
||||||
|
import {LibraryManagementService} from "../../services/library-management.service";
|
||||||
|
import {DialogService} from "../../services/dialog.service";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'mapped-games-table',
|
||||||
|
templateUrl: './mapped-games-table.component.html',
|
||||||
|
styleUrls: ['./mapped-games-table.component.scss']
|
||||||
|
})
|
||||||
|
export class MappedGamesTableComponent implements AfterViewInit, OnChanges {
|
||||||
|
@ViewChild(MatPaginator) paginator!: MatPaginator;
|
||||||
|
@ViewChild(MatSort) sort!: MatSort;
|
||||||
|
@ViewChild(MatTable) table!: MatTable<DetectedGameDto>;
|
||||||
|
@Input() mappedGames!: DetectedGameDto[];
|
||||||
|
|
||||||
|
dataSource: MatTableDataSource<DetectedGameDto> = new MatTableDataSource();
|
||||||
|
|
||||||
|
displayedColumns: string[] = ["path", "game", "actions"];
|
||||||
|
|
||||||
|
showOnlyUnconfirmedMatches: boolean = false;
|
||||||
|
|
||||||
|
filter: DetectedGameDto = new DetectedGameDto();
|
||||||
|
|
||||||
|
constructor(private gamesService: GamesService,
|
||||||
|
private libraryManagementService: LibraryManagementService,
|
||||||
|
private dialogService: DialogService) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngAfterViewInit(): void {
|
||||||
|
this.dataSource.sort = this.sort;
|
||||||
|
this.dataSource.sortingDataAccessor = (item: DetectedGameDto, property: string) => {
|
||||||
|
if (property === 'game') {
|
||||||
|
return item.title;
|
||||||
|
}
|
||||||
|
return (item as any)[property];
|
||||||
|
};
|
||||||
|
|
||||||
|
this.dataSource.paginator = this.paginator;
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnChanges(changes: SimpleChanges): void {
|
||||||
|
this.refreshData(changes['mappedGames'].currentValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
refreshMappedGamesList(): void {
|
||||||
|
this.gamesService.getAllGames(true).subscribe(games => this.refreshData(games));
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleShowOnlyUnconfirmedMatches() {
|
||||||
|
this.showOnlyUnconfirmedMatches = !this.showOnlyUnconfirmedMatches;
|
||||||
|
this.filter.confirmedMatch = this.showOnlyUnconfirmedMatches ? false : undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
getFullYearFromTimestamp(timestamp: number): number {
|
||||||
|
return new Date(timestamp).getFullYear();
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleConfirmGameMapping(mappedGame: DetectedGameDto): void {
|
||||||
|
this.libraryManagementService.confirmGameMapping(mappedGame.slug, !mappedGame.confirmedMatch).subscribe(() => {
|
||||||
|
mappedGame.confirmedMatch = !mappedGame.confirmedMatch;
|
||||||
|
this.refreshData(this.dataSource.data);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteGameMapping(mappedGame: DetectedGameDto): void {
|
||||||
|
this.libraryManagementService.deleteGame(mappedGame.slug).subscribe(
|
||||||
|
() => this.refreshData(this.dataSource.data.filter(game => game !== mappedGame))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
openCorrectMappingDialog(mappedGame: DetectedGameDto): void {
|
||||||
|
this.dialogService.correctGameMappingDialog(mappedGame);
|
||||||
|
}
|
||||||
|
|
||||||
|
private refreshData(newData: DetectedGameDto[]): void {
|
||||||
|
this.dataSource.data = newData;
|
||||||
|
|
||||||
|
// Dirty hack to force a re-render
|
||||||
|
// Did not find a better solution
|
||||||
|
this.paginator?._changePageSize(this.paginator?.pageSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
<div class="mat-elevation-z8">
|
||||||
|
<table mat-table matSort [dataSource]="dataSource">
|
||||||
|
<!-- Path column -->
|
||||||
|
<ng-container matColumnDef="path">
|
||||||
|
<th mat-header-cell *matHeaderCellDef mat-sort-header> Path</th>
|
||||||
|
<td mat-cell *matCellDef="let element"> {{element.path}} </td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<!-- Actions column -->
|
||||||
|
<ng-container matColumnDef="actions">
|
||||||
|
<th mat-header-cell *matHeaderCellDef>
|
||||||
|
<button mat-icon-button (click)="refreshUnmappedFilesList()">
|
||||||
|
<mat-icon>refresh</mat-icon>
|
||||||
|
</button>
|
||||||
|
</th>
|
||||||
|
<td mat-cell *matCellDef="let element">
|
||||||
|
<button mat-icon-button (click)="openMapUnmappedFileDialog(element)">
|
||||||
|
<mat-icon>edit</mat-icon>
|
||||||
|
</button>
|
||||||
|
<button mat-icon-button (click)="deleteUnmappedFile(element)">
|
||||||
|
<mat-icon>delete</mat-icon>
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||||
|
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<mat-paginator
|
||||||
|
[length]="dataSource?.data?.length"
|
||||||
|
[pageIndex]="0"
|
||||||
|
[pageSize]="15"
|
||||||
|
[pageSizeOptions]="[10, 15, 25, 50]">
|
||||||
|
</mat-paginator>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
table {
|
||||||
|
min-width: 50vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-column-path {
|
||||||
|
width: 85%;
|
||||||
|
}
|
||||||
|
|
||||||
+34
@@ -0,0 +1,34 @@
|
|||||||
|
import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
|
import { MatPaginatorModule } from '@angular/material/paginator';
|
||||||
|
import { MatSortModule } from '@angular/material/sort';
|
||||||
|
import { MatTableModule } from '@angular/material/table';
|
||||||
|
|
||||||
|
import { UnmappedFilesTableComponent } from './unmapped-files-table.component';
|
||||||
|
|
||||||
|
describe('UnmappedFilesTableComponent', () => {
|
||||||
|
let component: UnmappedFilesTableComponent;
|
||||||
|
let fixture: ComponentFixture<UnmappedFilesTableComponent>;
|
||||||
|
|
||||||
|
beforeEach(waitForAsync(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
declarations: [ UnmappedFilesTableComponent ],
|
||||||
|
imports: [
|
||||||
|
NoopAnimationsModule,
|
||||||
|
MatPaginatorModule,
|
||||||
|
MatSortModule,
|
||||||
|
MatTableModule,
|
||||||
|
]
|
||||||
|
}).compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(UnmappedFilesTableComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should compile', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
import {AfterViewInit, Component, Input, OnChanges, SimpleChanges, ViewChild} from '@angular/core';
|
||||||
|
import {MatPaginator} from '@angular/material/paginator';
|
||||||
|
import {MatSort} from '@angular/material/sort';
|
||||||
|
import {MatTable, MatTableDataSource} from '@angular/material/table';
|
||||||
|
import {UnmappedFileDto} from "../../models/dtos/UnmappedFileDto";
|
||||||
|
import {GamesService} from "../../services/games.service";
|
||||||
|
import {LibraryManagementService} from "../../services/library-management.service";
|
||||||
|
import {DialogService} from "../../services/dialog.service";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'unmapped-files-table',
|
||||||
|
templateUrl: './unmapped-files-table.component.html',
|
||||||
|
styleUrls: ['./unmapped-files-table.component.scss']
|
||||||
|
})
|
||||||
|
export class UnmappedFilesTableComponent implements AfterViewInit, OnChanges {
|
||||||
|
@ViewChild(MatPaginator) paginator!: MatPaginator;
|
||||||
|
@ViewChild(MatSort) sort!: MatSort;
|
||||||
|
@ViewChild(MatTable) table!: MatTable<UnmappedFileDto>;
|
||||||
|
@Input() unmappedFiles!: UnmappedFileDto[];
|
||||||
|
|
||||||
|
dataSource: MatTableDataSource<UnmappedFileDto> = new MatTableDataSource();
|
||||||
|
|
||||||
|
displayedColumns: string[] = ["path", "actions"];
|
||||||
|
|
||||||
|
constructor(private gameService: GamesService,
|
||||||
|
private libraryManagementService: LibraryManagementService,
|
||||||
|
private dialogService: DialogService) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngAfterViewInit(): void {
|
||||||
|
this.dataSource.sort = this.sort;
|
||||||
|
this.dataSource.paginator = this.paginator;
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnChanges(changes: SimpleChanges): void {
|
||||||
|
this.refreshData(changes['unmappedFiles'].currentValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
refreshUnmappedFilesList(): void {
|
||||||
|
this.libraryManagementService.getUnmappedFiles().subscribe(unmappedFiles => this.refreshData(unmappedFiles));
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteUnmappedFile(unmappedFile: UnmappedFileDto): void {
|
||||||
|
this.libraryManagementService.deleteUnmappedFile(unmappedFile.id).subscribe(
|
||||||
|
() => this.refreshData(this.dataSource.data.filter(uf => uf !== unmappedFile))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
openMapUnmappedFileDialog(unmappedFile: UnmappedFileDto): void {
|
||||||
|
this.dialogService.mapUnmappedGameDialog(unmappedFile).subscribe(gameSuccessfullyMapped => {
|
||||||
|
if (gameSuccessfullyMapped) this.refreshData(this.dataSource.data.filter(uf => uf !== unmappedFile));
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private refreshData(newData: UnmappedFileDto[]): void {
|
||||||
|
this.dataSource.data = newData;
|
||||||
|
|
||||||
|
// Dirty hack to force a re-render
|
||||||
|
// Did not find a better solution
|
||||||
|
this.paginator?._changePageSize(this.paginator?.pageSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -29,5 +29,5 @@ export class DetectedGameDto {
|
|||||||
|
|
||||||
path!: string;
|
path!: string;
|
||||||
diskSize!: number;
|
diskSize!: number;
|
||||||
confirmedMatch!: boolean;
|
confirmedMatch!: boolean | undefined;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import {ErrorDialogComponent} from '../components/error-dialog/error-dialog.comp
|
|||||||
import {DetectedGameDto} from "../models/dtos/DetectedGameDto";
|
import {DetectedGameDto} from "../models/dtos/DetectedGameDto";
|
||||||
import {MapGameDialogComponent} from "../components/map-game-dialog/map-game-dialog.component";
|
import {MapGameDialogComponent} from "../components/map-game-dialog/map-game-dialog.component";
|
||||||
import {UnmappedFileDto} from "../models/dtos/UnmappedFileDto";
|
import {UnmappedFileDto} from "../models/dtos/UnmappedFileDto";
|
||||||
|
import {Observable} from "rxjs";
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
@@ -19,6 +20,7 @@ export class DialogService {
|
|||||||
dialogConfig.disableClose = true;
|
dialogConfig.disableClose = true;
|
||||||
dialogConfig.autoFocus = true;
|
dialogConfig.autoFocus = true;
|
||||||
dialogConfig.closeOnNavigation = true;
|
dialogConfig.closeOnNavigation = true;
|
||||||
|
dialogConfig.minWidth = '25vw';
|
||||||
|
|
||||||
dialogConfig.data = {
|
dialogConfig.data = {
|
||||||
message
|
message
|
||||||
@@ -27,33 +29,35 @@ export class DialogService {
|
|||||||
this.dialog.open(ErrorDialogComponent, dialogConfig);
|
this.dialog.open(ErrorDialogComponent, dialogConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
public correctGameMappingDialog(game: DetectedGameDto): void {
|
public correctGameMappingDialog(game: DetectedGameDto): Observable<any> {
|
||||||
const dialogConfig = new MatDialogConfig();
|
const dialogConfig = new MatDialogConfig();
|
||||||
|
|
||||||
dialogConfig.disableClose = true;
|
dialogConfig.disableClose = true;
|
||||||
dialogConfig.autoFocus = true;
|
dialogConfig.autoFocus = true;
|
||||||
dialogConfig.closeOnNavigation = true;
|
dialogConfig.closeOnNavigation = true;
|
||||||
|
dialogConfig.minWidth = '25vw';
|
||||||
|
|
||||||
dialogConfig.data = {
|
dialogConfig.data = {
|
||||||
path: game.path,
|
path: game.path,
|
||||||
slug: game.slug
|
slug: game.slug
|
||||||
};
|
};
|
||||||
|
|
||||||
this.dialog.open(MapGameDialogComponent, dialogConfig);
|
return this.dialog.open(MapGameDialogComponent, dialogConfig).afterClosed();
|
||||||
}
|
}
|
||||||
|
|
||||||
public mapUnmappedGameDialog(unmappedFile: UnmappedFileDto): void {
|
public mapUnmappedGameDialog(unmappedFile: UnmappedFileDto): Observable<any> {
|
||||||
const dialogConfig = new MatDialogConfig();
|
const dialogConfig = new MatDialogConfig();
|
||||||
|
|
||||||
dialogConfig.disableClose = true;
|
dialogConfig.disableClose = true;
|
||||||
dialogConfig.autoFocus = true;
|
dialogConfig.autoFocus = true;
|
||||||
dialogConfig.closeOnNavigation = true;
|
dialogConfig.closeOnNavigation = true;
|
||||||
|
dialogConfig.minWidth = '25vw';
|
||||||
|
|
||||||
dialogConfig.data = {
|
dialogConfig.data = {
|
||||||
path: unmappedFile.path
|
path: unmappedFile.path
|
||||||
};
|
};
|
||||||
|
|
||||||
this.dialog.open(MapGameDialogComponent, dialogConfig);
|
return this.dialog.open(MapGameDialogComponent, dialogConfig).afterClosed();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,6 +54,10 @@ export class GamesService implements GamesApi {
|
|||||||
return this.http.get<Map<string, string>>(`${this.apiPath}/game-mappings`);
|
return this.http.get<Map<string, string>>(`${this.apiPath}/game-mappings`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
removeGameFromCache(slug: string): void {
|
||||||
|
this.cache.delete(slug);
|
||||||
|
}
|
||||||
|
|
||||||
private cacheGames(gameList: DetectedGameDto[]): void {
|
private cacheGames(gameList: DetectedGameDto[]): void {
|
||||||
this.cache.clear();
|
this.cache.clear();
|
||||||
gameList.forEach(game => this.cache.set(game.slug, game));
|
gameList.forEach(game => this.cache.set(game.slug, game));
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import {Injectable} from '@angular/core';
|
import {Injectable} from '@angular/core';
|
||||||
import {HttpClient} from "@angular/common/http";
|
import {HttpClient, HttpParams} from "@angular/common/http";
|
||||||
import {Observable} from "rxjs";
|
import {Observable} from "rxjs";
|
||||||
import {DetectedGameDto} from "../models/dtos/DetectedGameDto";
|
import {DetectedGameDto} from "../models/dtos/DetectedGameDto";
|
||||||
import {PathToSlugDto} from "../models/dtos/PathToSlugDto";
|
import {PathToSlugDto} from "../models/dtos/PathToSlugDto";
|
||||||
import {UnmappedFileDto} from "../models/dtos/UnmappedFileDto";
|
import {UnmappedFileDto} from "../models/dtos/UnmappedFileDto";
|
||||||
import {LibraryManagementApi} from "../api/LibraryManagementApi";
|
import {LibraryManagementApi} from "../api/LibraryManagementApi";
|
||||||
|
import {GamesService} from "./games.service";
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
@@ -13,7 +14,8 @@ export class LibraryManagementService implements LibraryManagementApi {
|
|||||||
|
|
||||||
private readonly apiPath = '/library-management';
|
private readonly apiPath = '/library-management';
|
||||||
|
|
||||||
constructor(private http: HttpClient) {
|
constructor(private http: HttpClient,
|
||||||
|
private gamesService: GamesService) {
|
||||||
}
|
}
|
||||||
|
|
||||||
mapGame(pathToSlugDto: PathToSlugDto): Observable<DetectedGameDto> {
|
mapGame(pathToSlugDto: PathToSlugDto): Observable<DetectedGameDto> {
|
||||||
@@ -24,11 +26,15 @@ export class LibraryManagementService implements LibraryManagementApi {
|
|||||||
return this.http.get<UnmappedFileDto[]>(`${this.apiPath}/unmapped-files`);
|
return this.http.get<UnmappedFileDto[]>(`${this.apiPath}/unmapped-files`);
|
||||||
}
|
}
|
||||||
|
|
||||||
confirmGameMapping(slug: string): Observable<DetectedGameDto> {
|
confirmGameMapping(slug: string, confirm: boolean): Observable<DetectedGameDto> {
|
||||||
return this.http.get<DetectedGameDto>(`${this.apiPath}/confirm-game/${slug}`);
|
let queryParams = new HttpParams();
|
||||||
|
queryParams = queryParams.append("confirm", confirm);
|
||||||
|
|
||||||
|
return this.http.get<DetectedGameDto>(`${this.apiPath}/confirm-game/${slug}`, {params:queryParams});
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteGame(slug: string): Observable<Response> {
|
deleteGame(slug: string): Observable<Response> {
|
||||||
|
this.gamesService.removeGameFromCache(slug);
|
||||||
return this.http.delete<Response>(`${this.apiPath}/delete-game/${slug}`);
|
return this.http.delete<Response>(`${this.apiPath}/delete-game/${slug}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user