Merge pull request 'issue-5-product-gamesystems' (#11) from issue-5-product-gamesystems into main
All checks were successful
E2E Testing / test (push) Successful in 1m34s

Reviewed-on: #11
This commit is contained in:
sebastian 2024-02-16 20:02:12 +01:00
commit bd9cb7e7c5
18 changed files with 326 additions and 260 deletions

View File

@ -54,6 +54,14 @@ import {MatOption, MatSelect} from "@angular/material/select";
import {
ProductGamesystemEditorComponent
} from "./editor/gamesystem-editor/product-gamesystem-editor/product-gamesystem-editor.component";
import {
ProductTransitionEditorComponent
} from "./editor/gamesystem-editor/transition-editor/product-transition-editor/product-transition-editor.component";
import {
ProductStateEditorComponent
} from "./editor/gamesystem-editor/state-editor/product-state-editor/product-state-editor.component";
import {MatTooltip} from "@angular/material/tooltip";
import {MatCard, MatCardContent} from "@angular/material/card";
// AoT requires an exported function for factories
const httpLoaderFactory = (http: HttpClient): TranslateHttpLoader => new TranslateHttpLoader(http, './assets/i18n/', '.json');
@ -70,7 +78,10 @@ const httpLoaderFactory = (http: HttpClient): TranslateHttpLoader => new Transl
GamesystemEditorComponent,
SimpleGamesystemEditorComponent,
SimpleStateEditorComponent,
SimpleTransitionEditorComponent
SimpleTransitionEditorComponent,
ProductTransitionEditorComponent,
ProductStateEditorComponent,
ProductGamesystemEditorComponent
],
imports: [
BrowserModule,
@ -125,7 +136,9 @@ const httpLoaderFactory = (http: HttpClient): TranslateHttpLoader => new Transl
MatSelect,
MatOption,
MatHint,
ProductGamesystemEditorComponent
MatTooltip,
MatCard,
MatCardContent
],
providers: [],
bootstrap: [AppComponent]

View File

@ -1,2 +1,4 @@
<app-product-state-editor [gamesystem]="gamesystem" (onOpenGamesystemEditor)="onOpenGamesystemEditor($event)"></app-product-state-editor>
<div id="productStateEditor">
<app-product-transition-editor [gamesystem]="gamesystem" (onOpenGamesystem)="onOpenGamesystemEditor($event)"></app-product-transition-editor>
</div>

View File

@ -0,0 +1,3 @@
#productStateEditor {
margin-top: 20px;
}

View File

@ -10,11 +10,6 @@ import {
@Component({
selector: 'app-product-gamesystem-editor',
standalone: true,
imports: [
ProductStateEditorComponent,
ProductTransitionEditorComponent
],
templateUrl: './product-gamesystem-editor.component.html',
styleUrl: './product-gamesystem-editor.component.scss'
})

View File

@ -1,2 +1,4 @@
<app-simple-state-editor [states]="simpleGamesystem!.states" [gamesystem]="simpleGamesystem"></app-simple-state-editor>
<app-simple-transition-editor class="transition-editor" [gamesystem]="simpleGamesystem"></app-simple-transition-editor>
<div id="transition-editor">
<app-simple-transition-editor [gamesystem]="simpleGamesystem"></app-simple-transition-editor>
</div>

View File

@ -1,3 +1,4 @@
.transition-editor {
margin-top: 15px;
#transition-editor {
margin-top: 20px !important;
}

View File

@ -1,3 +1,9 @@
<mat-card>
<mat-card-content>
<mat-form-field appearance="fill" class="long-form">
<mat-label>Filter</mat-label>
<input matInput (keyup)="applyFilter($event)" placeholder="Filter" #input>
</mat-form-field>
<table mat-table [dataSource]="datasource" class="mat-elevation-z8">
<ng-container *ngFor="let col of displayedColumns; let i = index" [matColumnDef]="col">
<th mat-header-cell *matHeaderCellDef>{{col}}</th>
@ -12,3 +18,5 @@
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
</mat-card-content>
</mat-card>

View File

@ -5,3 +5,7 @@ table {
.mat-column-Initial {
width: 32px;
}
.long-form {
width: 100%;
}

View File

@ -2,43 +2,16 @@ import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
import {ProductGamesystem} from "../../../../game-model/gamesystems/ProductGamesystem";
import {SimpleGamesystem} from "../../../../game-model/gamesystems/SimpleGamesystem";
import {
MatCell, MatCellDef,
MatColumnDef, MatHeaderCell, MatHeaderCellDef,
MatHeaderRow,
MatHeaderRowDef,
MatRow,
MatRowDef,
MatTable,
MatTableDataSource
} from "@angular/material/table";
import {SimpleState} from "../../../../game-model/gamesystems/SimpleState";
import {State} from "../../../../game-model/gamesystems/State";
import {NgForOf, NgIf} from "@angular/common";
import {ProductState} from "../../../../game-model/gamesystems/ProductState";
import {MatIcon} from "@angular/material/icon";
import {Gamesystem} from "../../../../game-model/gamesystems/Gamesystem";
import {LeafGamesystemCalculator} from "../../product-gamesystem-editor/LeafGamesystemCalculator";
import {MatTooltip} from "@angular/material/tooltip";
import {ProductTransition} from "../../../../game-model/gamesystems/ProductTransition";
import {ProductState} from "../../../../game-model/gamesystems/ProductState";
@Component({
selector: 'app-product-state-editor',
standalone: true,
imports: [
MatTable,
MatRow,
MatRowDef,
MatHeaderRow,
MatHeaderRowDef,
MatColumnDef,
MatHeaderCell,
MatHeaderCellDef,
MatCell,
MatCellDef,
NgForOf,
NgIf,
MatIcon,
MatTooltip
],
templateUrl: './product-state-editor.component.html',
styleUrl: './product-state-editor.component.scss'
})
@ -47,7 +20,7 @@ export class ProductStateEditorComponent implements OnInit{
@Input() gamesystem: ProductGamesystem | undefined
@Output('onOpenGamesystemEditor') openGamesystemEditorEmitter = new EventEmitter<SimpleGamesystem>();
displayedColumns: string[] = [];
datasource = new MatTableDataSource();
datasource = new MatTableDataSource<ProductState>();
ngOnInit() {
@ -55,6 +28,10 @@ export class ProductStateEditorComponent implements OnInit{
this.generateColumnNamesRecursively(this.gamesystem!, "");
this.displayedColumns.push('Initial');
this.datasource.data = this.gamesystem!.states;
this.datasource.filterPredicate = (data: ProductState, filter: string) => {
const leaf_states = LeafGamesystemCalculator.calcLeafStates(data);
return leaf_states.some((state) => state.stateLabel.toLowerCase().includes(filter))
}
}
generateColumnNamesRecursively(gamesystem: ProductGamesystem, nestedColumnName: string) {
@ -79,4 +56,9 @@ export class ProductStateEditorComponent implements OnInit{
this.openGamesystemEditorEmitter.emit(clicked_gamesystem);
}
applyFilter(event: KeyboardEvent) {
const filterValue = (event.target as HTMLInputElement).value;
this.datasource.filter = filterValue.trim().toLowerCase();
}
}

View File

@ -1,3 +1,9 @@
<mat-card>
<mat-card-content>
<mat-form-field appearance="fill" class="long-form">
<mat-label>Filter</mat-label>
<input matInput (keyup)="applyFilter($event)" placeholder="Filter" #input>
</mat-form-field>
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8" multiTemplateDataRows>
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef>Label</th>
@ -75,3 +81,6 @@
</tr>
<tr mat-row *matRowDef="let row; columns: ['expandedDetail']" class="example-detail-row"></tr>
</table>
</mat-card-content>
</mat-card>

View File

@ -4,6 +4,8 @@ import {MatTableDataSource} from "@angular/material/table";
import {animate, state, style, transition, trigger} from "@angular/animations";
import {MatSnackBar} from "@angular/material/snack-bar";
import {SimpleGamesystem} from "../../../../game-model/gamesystems/SimpleGamesystem";
import {ProductState} from "../../../../game-model/gamesystems/ProductState";
import {LeafGamesystemCalculator} from "../../product-gamesystem-editor/LeafGamesystemCalculator";
@Component({
selector: 'app-simple-state-editor',
@ -21,7 +23,7 @@ export class SimpleStateEditorComponent implements OnInit{
@Input() states: SimpleState[] = [];
@Input() gamesystem: SimpleGamesystem | undefined
dataSource = new MatTableDataSource();
dataSource = new MatTableDataSource<SimpleState>();
displayedColumns = ["name", "initial", "edit", "delete"];
columnsToDisplayWithExpand = [...this.displayedColumns, 'expand'];
expandedElement: SimpleState | null = null;
@ -34,6 +36,9 @@ export class SimpleStateEditorComponent implements OnInit{
ngOnInit() {
this.dataSource.data = this.states;
this.dataSource.filterPredicate = (data: SimpleState, filter: string) => {
return data.stateLabel.toLowerCase().includes(filter);
}
}
editState(state: SimpleState) {
@ -83,4 +88,9 @@ export class SimpleStateEditorComponent implements OnInit{
onStateChange() {
this.gamesystem!.onModifyContent();
}
applyFilter(event: KeyboardEvent) {
const filterValue = (event.target as HTMLInputElement).value;
this.dataSource.filter = filterValue.trim().toLowerCase();
}
}

View File

@ -1,3 +1,9 @@
<mat-card>
<mat-card-content>
<mat-form-field class="long-form">
<mat-label>Filter</mat-label>
<input matInput (keyup)="applyFilter($event)" placeholder="Filter" #input>
</mat-form-field>
<table mat-table [dataSource]="dataSource">
<ng-container *ngFor="let col of displayedColumns; let i = index" [matColumnDef]="col.internalName">
<th mat-header-cell *matHeaderCellDef (dblclick)="openGamesystemEditor(i)">{{col.displayedName}}</th>
@ -39,4 +45,10 @@
<tr mat-header-row *matHeaderRowDef="columns;sticky:true"></tr>
<tr mat-row *matRowDef="let row; columns: columns;"></tr>
<tr class="mat-row" *matNoDataRow>
<td class="mat-cell" colspan="4">No data matching the filter "{{input.value}}"</td>
</tr>
</table>
</mat-card-content>
</mat-card>

View File

@ -2,19 +2,11 @@ import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
import {ProductGamesystem} from "../../../../game-model/gamesystems/ProductGamesystem";
import {SimpleGamesystem} from "../../../../game-model/gamesystems/SimpleGamesystem";
import {
MatCell, MatCellDef,
MatColumnDef,
MatHeaderCell,
MatHeaderCellDef, MatHeaderRow, MatHeaderRowDef, MatRow, MatRowDef,
MatTable,
MatTableDataSource
} from "@angular/material/table";
import {LeafGamesystemCalculator} from "../../product-gamesystem-editor/LeafGamesystemCalculator";
import {NgForOf, NgIf} from "@angular/common";
import {ProductTransition} from "../../../../game-model/gamesystems/ProductTransition";
import {ProductState} from "../../../../game-model/gamesystems/ProductState";
import {MatTooltip} from "@angular/material/tooltip";
class DisplayedColumnName {
displayedName: string
internalName: string
@ -27,22 +19,6 @@ class DisplayedColumnName {
}
@Component({
selector: 'app-product-transition-editor',
standalone: true,
imports: [
MatTable,
NgForOf,
MatColumnDef,
MatHeaderCell,
MatHeaderCellDef,
MatCell,
MatCellDef,
NgIf,
MatHeaderRow,
MatRow,
MatHeaderRowDef,
MatRowDef,
MatTooltip
],
templateUrl: './product-transition-editor.component.html',
styleUrl: './product-transition-editor.component.scss'
})
@ -51,7 +27,7 @@ export class ProductTransitionEditorComponent implements OnInit{
@Input() gamesystem: ProductGamesystem | undefined
@Output() onOpenGamesystem = new EventEmitter<SimpleGamesystem>();
dataSource = new MatTableDataSource();
dataSource = new MatTableDataSource<ProductTransition>();
displayedColumns: DisplayedColumnName[] = [];
columns: string[] = [];
numberLeafSystems: number = -1;
@ -66,6 +42,14 @@ export class ProductTransitionEditorComponent implements OnInit{
this.columns = this.displayedColumns.map(column => column.internalName)
this.dataSource.data = this.gamesystem.transitions;
this.dataSource.filterPredicate = (data: ProductTransition, filter: string) => {
const leaf_starting_states = LeafGamesystemCalculator.calcLeafStates(data.startingState);
const leaf_ending_states = LeafGamesystemCalculator.calcLeafStates(data.endingState);
const combined_leaf_states = leaf_starting_states.concat(leaf_ending_states);
return combined_leaf_states.some((state) => state.stateLabel.toLowerCase().includes(filter))
}
}
}
@ -79,8 +63,6 @@ export class ProductTransitionEditorComponent implements OnInit{
index = leafIndex - this.numberLeafSystems;
}
const leafStates = LeafGamesystemCalculator.calcLeafStates(state);
console.log(leafStates)
return leafStates[index];
@ -94,4 +76,9 @@ export class ProductTransitionEditorComponent implements OnInit{
this.onOpenGamesystem.emit(leafGamesystems[leafIndex - this.numberLeafSystems])
}
}
applyFilter(event: KeyboardEvent) {
const filterValue = (event.target as HTMLInputElement).value;
this.dataSource.filter = filterValue.trim().toLowerCase();
}
}

View File

@ -1,3 +1,10 @@
<mat-card>
<mat-card-content>
<mat-form-field class="long-form">
<mat-label>Filter</mat-label>
<input matInput (keyup)="applyFilter($event)" placeholder="Filter" #input>
</mat-form-field>
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8" multiTemplateDataRows>
<ng-container matColumnDef="starting-state">
<th mat-header-cell *matHeaderCellDef>Starting State</th>
@ -79,3 +86,6 @@
</tr>
<tr mat-row *matRowDef="let row; columns: ['expandedDetail']" class="example-detail-row"></tr>
</table>
</mat-card-content>
</mat-card>

View File

@ -13,6 +13,8 @@ import {
import {SimpleTransition} from "../../../../game-model/gamesystems/SimpleTransition";
import {animate, state, style, transition, trigger} from "@angular/animations";
import {SimpleState} from "../../../../game-model/gamesystems/SimpleState";
import {ProductTransition} from "../../../../game-model/gamesystems/ProductTransition";
import {LeafGamesystemCalculator} from "../../product-gamesystem-editor/LeafGamesystemCalculator";
@Component({
selector: 'app-simple-transition-editor',
@ -44,6 +46,9 @@ export class SimpleTransitionEditorComponent implements OnInit {
transitionEndingStateError = true;
ngOnInit() {
this.dataSource.data = this.gamesystem!.transitions;
this.dataSource.filterPredicate = (data: SimpleTransition, filter: string) => {
return [data.startingState, data.endingState].some((state) => state.stateLabel.toLowerCase().includes(filter))
}
}
addTransition() {
@ -83,4 +88,9 @@ export class SimpleTransitionEditorComponent implements OnInit {
this.dataSource.data = this.gamesystem!.transitions;
}
}
applyFilter(event: KeyboardEvent) {
const filterValue = (event.target as HTMLInputElement).value;
this.dataSource.filter = filterValue.trim().toLowerCase();
}
}

View File

@ -38,5 +38,16 @@ export class ProductState extends State<ProductTransition> {
return true;
}
existsInnerStateByLowerCaseLabel(label: string): boolean {
this.innerStates.forEach(innerState => {
if(innerState instanceof SimpleState && innerState.stateLabel.toLowerCase() === label) {
return true;
} else if(innerState instanceof ProductState) {
return innerState.existsInnerStateByLowerCaseLabel(label);
}
})
return false;
}
}

View File

@ -3,4 +3,7 @@ import {ProductState} from "./ProductState";
export class ProductTransition extends Transition<ProductState> {
containsInnerStateByLabel(label: string) {
return this.startingState.existsInnerStateByLowerCaseLabel(label) || this.endingState.existsInnerStateByLowerCaseLabel(label);
}
}