mirror of
https://github.com/BrenBroZAYT/gameyfin.git
synced 2026-06-15 16:20:03 +00:00
Various improvements to game management interface
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user