| @@ -9,13 +9,19 @@ import { MatIconModule } from '@angular/material/icon'; | |||
| import { MatCommonModule } from '@angular/material/core'; | |||
| import { MatInputModule } from '@angular/material/input'; | |||
| import { DynamicDatabase } from './create-rule/class/dynamic-database'; | |||
| import {MatSnackBarModule} from '@angular/material/snack-bar'; | |||
| import {MatBottomSheetModule} from '@angular/material/bottom-sheet'; | |||
| import { OptionsShetComponent } from './options-shet/options-shet.component'; | |||
| @NgModule({ | |||
| declarations: [ | |||
| CreateRuleComponent | |||
| CreateRuleComponent, | |||
| OptionsShetComponent | |||
| ], | |||
| imports: [ | |||
| MatBottomSheetModule, | |||
| MatSnackBarModule, | |||
| CommonModule, | |||
| MatCardModule, | |||
| MatFormFieldModule, | |||
| @@ -1,11 +1,9 @@ | |||
| import { Injectable } from "@angular/core" | |||
| import { RippleRef } from "@angular/material/core"; | |||
| import { Injectable } from "@angular/core"; | |||
| import { BehaviorSubject, Subject } from "rxjs"; | |||
| import { map } from "rxjs/operators"; | |||
| import { CreateRuleDto, Rule, RulesService } from "../../../../../api"; | |||
| import { environment } from "../../../../environments/environment"; | |||
| import { RuleDataService } from "../../../service/rule-data.service"; | |||
| import { RuleFlatNode } from "./rule-flat-node"; | |||
| import { EventMessage } from "./event-message"; | |||
| @Injectable({ providedIn: 'root' }) | |||
| @@ -13,6 +11,7 @@ export class DynamicDatabase { | |||
| dataChange = new BehaviorSubject<Rule[]>([]); | |||
| childAdded = new Subject<Rule>(); | |||
| onEvent = new Subject<EventMessage>() | |||
| get data(): Rule[] { return this.dataChange.value; } | |||
| get count(): number { return this.dataChange.value.length }; | |||
| @@ -37,12 +36,41 @@ export class DynamicDatabase { | |||
| ) | |||
| ), | |||
| (err) => { | |||
| //TODO add toaster | |||
| this.onEvent.next( | |||
| { | |||
| event: 'Error', | |||
| error: err, | |||
| message: `Fehler beim abrufen der Regeln` | |||
| } | |||
| ); | |||
| } | |||
| } | |||
| getById = (ruleId: string) => { | |||
| const parentNode = this.getParentById(ruleId); | |||
| if (parentNode) { | |||
| return parentNode; | |||
| } | |||
| for (const rootRule of this.data) { | |||
| const found = this.findChildById(rootRule, ruleId); | |||
| if (found) { | |||
| return found; | |||
| } | |||
| } | |||
| return null; | |||
| } | |||
| findChildById = (parent: Rule, ruleId: string) => { | |||
| if (!parent.subRule) { | |||
| return null; | |||
| } | |||
| return parent.subRule.find(( | |||
| rule => rule.id === ruleId | |||
| )) | |||
| } | |||
| getParentById = (ruleId: string) => this.data.find(rule => rule.id === ruleId) | |||
| insertEmptyChild(parent: Rule) { | |||
| ; | |||
| if (!parent.subRule) { | |||
| parent.subRule = []; | |||
| } | |||
| @@ -50,12 +78,14 @@ export class DynamicDatabase { | |||
| { | |||
| text: '', | |||
| id: '0', | |||
| parentRule: parent, | |||
| parentRule: { | |||
| id: parent.id | |||
| }, | |||
| paragraph: this.ruleHelperService.getParagraphOfNextChild(parent), | |||
| created: 'today', | |||
| deletedAt: null, | |||
| updated: null, | |||
| } | |||
| } as Rule | |||
| ) | |||
| this.dataChange.next(this.data); | |||
| this.childAdded.next(parent); | |||
| @@ -81,6 +111,8 @@ export class DynamicDatabase { | |||
| } | |||
| this.rulesService.create(createSubRule).subscribe( | |||
| newSubRule => { | |||
| subRule.id = newSubRule.id; | |||
| this.dataChange.next(this.data); | |||
| if (typeof newSubRule.id !== 'undefined' && typeof newSubRule.parentRule?.id !== 'undefined') { | |||
| const updateParentRule: CreateRuleDto = { | |||
| paragraph: parent.paragraph, | |||
| @@ -91,31 +123,26 @@ export class DynamicDatabase { | |||
| //TODO Push updated message | |||
| this.update(parent.id, { | |||
| paragraph: parent.paragraph, | |||
| subRuleIds: [ | |||
| subRule: [ | |||
| ...parent.subRule | |||
| .filter(rule => rule.id !== "0") | |||
| .map(rule => rule.id), | |||
| subRule.id, | |||
| .filter(rule => rule.id !== "0"), | |||
| subRule, | |||
| ], | |||
| text: parent.text | |||
| }).subscribe( | |||
| (updated) => { | |||
| //todo add update message | |||
| }, | |||
| (err) => { | |||
| //TODO Push error message | |||
| console.error(err); | |||
| } | |||
| ) | |||
| }); | |||
| }, | |||
| (err) => { | |||
| //TODO Push error message | |||
| console.error(err); | |||
| this.onEvent.next( | |||
| { | |||
| event: 'Error', | |||
| error: err, | |||
| message: `Fehler beim aktualisieren von Regel ${parent.paragraph}` | |||
| } | |||
| ); | |||
| } | |||
| ) | |||
| return; | |||
| } | |||
| //TODO Push error message | |||
| } | |||
| ) | |||
| if (!parent.subRule) { | |||
| @@ -127,8 +154,43 @@ export class DynamicDatabase { | |||
| this.childAdded.next(parent); | |||
| } | |||
| update(id: string, changedData: Partial<CreateRuleDto>) { | |||
| return this.rulesService.update(id, changedData); | |||
| reload() { | |||
| this.dataChange.next(this.data); | |||
| } | |||
| update(id: string, changedData: Partial<Rule>) { | |||
| let ruleToUpdate = this.getById(id); | |||
| const updateDto = { | |||
| paragraph: !!changedData.paragraph ? changedData.paragraph : ruleToUpdate.paragraph, | |||
| text: !!changedData.text ? changedData.text : ruleToUpdate.text, | |||
| parentId: !!changedData.parentRule ? changedData.parentRule.id : null, | |||
| subRuleIds: [ | |||
| ...!!changedData.subRule ? | |||
| changedData.subRule | |||
| .map(rule => rule.id) | |||
| : [] | |||
| ] | |||
| } as CreateRuleDto | |||
| this.rulesService.update(id, updateDto).subscribe( | |||
| () => { | |||
| this.onEvent.next( | |||
| { | |||
| event: 'Update', | |||
| message: `Regel ${ruleToUpdate.paragraph} wurde erfolgreich aktualisiert` | |||
| } | |||
| ); | |||
| }, | |||
| (err) => { | |||
| this.onEvent.next( | |||
| { | |||
| event: 'Error', | |||
| error: err, | |||
| message: `Fehler beim aktualisieren der Regel ${ruleToUpdate.paragraph}` | |||
| } | |||
| ); | |||
| } | |||
| ) | |||
| this.dataChange.next(this.data); | |||
| } | |||
| insertParent(newRule: Rule) { | |||
| @@ -139,11 +201,24 @@ export class DynamicDatabase { | |||
| parentId: null | |||
| } | |||
| this.rulesService.create(createNewRule).subscribe( | |||
| () => { | |||
| //TODO created message | |||
| (created) => { | |||
| newRule.id = created.id; | |||
| this.dataChange.next(this.data); | |||
| this.onEvent.next( | |||
| { | |||
| event: 'Create', | |||
| message: `Regel ${createNewRule.paragraph} wurde erfolgreich erstellt` | |||
| } | |||
| ); | |||
| }, | |||
| (err) => { | |||
| //TODO Error message | |||
| this.onEvent.next( | |||
| { | |||
| event: 'Error', | |||
| error: err, | |||
| message: `Fehler beim anlegen der Regel ${createNewRule.paragraph}` | |||
| } | |||
| ); | |||
| } | |||
| ) | |||
| this.dataChange.next(this.data); | |||
| @@ -153,11 +228,21 @@ export class DynamicDatabase { | |||
| parent.deletedAt = "deleted"; | |||
| this.rulesService.remove(parent.id).subscribe( | |||
| (deleted) => { | |||
| //todo add update message | |||
| this.onEvent.next( | |||
| { | |||
| event: 'Restore', | |||
| message: `Regel ${parent.paragraph} wurde erfolgreich deaktiviert` | |||
| } | |||
| ); | |||
| }, | |||
| (err) => { | |||
| //TODO Push error message | |||
| console.error(err); | |||
| this.onEvent.next( | |||
| { | |||
| event: 'Error', | |||
| error: err, | |||
| message: `Fehler beim aktivieren von Regel ${parent.paragraph}` | |||
| } | |||
| ); | |||
| } | |||
| ); | |||
| this.dataChange.next(this.data); | |||
| @@ -172,11 +257,21 @@ export class DynamicDatabase { | |||
| } | |||
| this.rulesService.restore(rule.id).subscribe( | |||
| (deleted) => { | |||
| //todo add restored message | |||
| this.onEvent.next( | |||
| { | |||
| event: 'Restore', | |||
| message: `Regel ${rule.paragraph} wurde erfolgreich reaktiviert` | |||
| } | |||
| ); | |||
| }, | |||
| (err) => { | |||
| //TODO Push error message | |||
| console.error(err); | |||
| this.onEvent.next( | |||
| { | |||
| event: 'Error', | |||
| error: err, | |||
| message: `Fehler beim aktivieren der Regel ${rule.paragraph}` | |||
| } | |||
| ); | |||
| } | |||
| ); | |||
| this.dataChange.next(this.data); | |||
| @@ -189,26 +284,27 @@ export class DynamicDatabase { | |||
| (deleted) => { | |||
| this.update(parent.id, { | |||
| paragraph: parent.paragraph, | |||
| subRuleIds: [ | |||
| subRule: [ | |||
| ...parent.subRule | |||
| .filter(rule => rule.id !== "0") | |||
| .map(rule => rule.id) | |||
| ], | |||
| text: parent.text | |||
| }).subscribe( | |||
| (updated) => { | |||
| //todo add update message | |||
| }, | |||
| (err) => { | |||
| //TODO Push error message | |||
| console.error(err); | |||
| }); | |||
| this.onEvent.next( | |||
| { | |||
| event: 'Remove', | |||
| message: `Regel ${subRule.paragraph} wurde erfolgreich deaktiviert` | |||
| } | |||
| ); | |||
| //todo add update message | |||
| }, | |||
| (err) => { | |||
| //TODO Push error message | |||
| console.error(err); | |||
| this.onEvent.next( | |||
| { | |||
| event: 'Error', | |||
| error: err, | |||
| message: `Fehler beim deaktivieren von Regel ${subRule.paragraph}` | |||
| } | |||
| ); | |||
| } | |||
| ); | |||
| this.dataChange.next(this.data); | |||
| @@ -0,0 +1 @@ | |||
| export class EventMessage { event: 'Error' | 'Create' | 'Update' | 'Restore' | 'Remove'; message: string; error?: Error } | |||
| @@ -1,7 +1,13 @@ | |||
| import { Rule } from "../../../../../api"; | |||
| export class RuleFlatNode { | |||
| constructor(public item: Rule, public level = 1, public expandable = false, | |||
| public isLoading = false,public root = true) { } | |||
| constructor( | |||
| public item: Rule, | |||
| public level = 1, | |||
| public expandable = false, | |||
| public isLoading = false, | |||
| public root = true, | |||
| public editMode = false, | |||
| ) { } | |||
| } | |||
| @@ -1,47 +1,74 @@ | |||
| <mat-card class="wood-card"> | |||
| <mat-tree [dataSource]="dataSource" [treeControl]="treeControl"> | |||
| <mat-tree-node *matTreeNodeDef="let node" matTreeNodePadding> | |||
| <div> | |||
| <button mat-icon-button disabled></button> §{{ node.item.paragraph }} {{ node.item.text }} | |||
| <button *ngIf="node.root" mat-icon-button (click)="addEmptyRule(node)"> | |||
| <mat-icon>add</mat-icon> | |||
| </button> | |||
| <button mat-icon-button (click)="remove(node)"> | |||
| <mat-icon>remove</mat-icon> | |||
| <mat-tree [dataSource]="dataSource" [treeControl]="treeControl"> | |||
| <mat-tree-node *matTreeNodeDef="let node" matTreeNodePadding> | |||
| <div> | |||
| <button mat-icon-button disabled></button> | |||
| <span *ngIf="!node.editMode"> | |||
| §{{ node.item.paragraph }} {{ node.item.text }} | |||
| </span> | |||
| <span *ngIf="node.editMode"> | |||
| §{{ node.item.paragraph }} | |||
| <mat-form-field class="new-node-input"> | |||
| <mat-label>Updated Rule</mat-label> | |||
| <input [formControl]="text" [value]="node.item.text" matInput #itemValue placeholder="text" /> | |||
| </mat-form-field> | |||
| <button [disabled]="itemValue.value === ''" mat-button (click)="updateNode(node, itemValue.value)">Update</button> | |||
| </span> | |||
| <button mat-icon-button (click)="openOptions(node)"> | |||
| <mat-icon>more_vert</mat-icon> | |||
| </button> | |||
| </div> | |||
| </mat-tree-node> | |||
| <mat-tree-node *matTreeNodeDef="let node; when: hasChild" matTreeNodePadding> | |||
| <button mat-icon-button matTreeNodeToggle [attr.aria-label]="'Toggle ' + node.text"> | |||
| <mat-icon class="mat-icon-rtl-mirror"> | |||
| {{ treeControl.isExpanded(node) ? "expand_more" : "chevron_right" }} | |||
| </mat-icon> | |||
| </button> §{{ node.item.paragraph }} {{ node.item.text }} | |||
| <button *ngIf="node.root" mat-icon-button (click)="addEmptyRule(node)"> | |||
| <mat-icon>add</mat-icon> | |||
| </button> | |||
| <button mat-icon-button (click)="remove(node)"> | |||
| <mat-icon>remove</mat-icon> | |||
| </button> | |||
| </mat-tree-node> | |||
| <mat-tree-node *matTreeNodeDef="let node; when: hasNoContent" matTreeNodePadding> | |||
| <button mat-icon-button disabled></button> | |||
| <span>§{{ node.item.paragraph }}</span> | |||
| <mat-form-field class="new-node-input"> | |||
| <mat-label>New Rule</mat-label> | |||
| <input [formControl]="text" matInput #itemValue placeholder="text" /> | |||
| </mat-form-field> | |||
| <button mat-button (click)="addNode(node, itemValue.value)">Save</button> | |||
| </mat-tree-node> | |||
| <mat-tree-node class="disabled-node" *matTreeNodeDef="let node; when: isDeleted" matTreeNodePadding> | |||
| <button mat-icon-button (click)="restore(node)"> | |||
| <mat-icon>restore</mat-icon> | |||
| </button> | |||
| <span>§{{ node.item.paragraph }} {{node.item.text}}</span> | |||
| </mat-tree-node> | |||
| </mat-tree> | |||
| <button mat-icon-button (click)="addEmptyRule()"> | |||
| <mat-icon>add</mat-icon> | |||
| </div> | |||
| </mat-tree-node> | |||
| <mat-tree-node *matTreeNodeDef="let node; when: hasChild" matTreeNodePadding> | |||
| <button mat-icon-button matTreeNodeToggle [attr.aria-label]="'Toggle ' + node.text"> | |||
| <mat-icon class="mat-icon-rtl-mirror"> | |||
| {{ treeControl.isExpanded(node) ? "expand_more" : "chevron_right" }} | |||
| </mat-icon> | |||
| </button> | |||
| <span *ngIf="!node.editMode"> | |||
| §{{ node.item.paragraph }} {{ node.item.text }} | |||
| </span> | |||
| <span *ngIf="node.editMode"> | |||
| §{{ node.item.paragraph }} | |||
| <mat-form-field class="new-node-input"> | |||
| <mat-label>Updated Rule</mat-label> | |||
| <input [formControl]="text" [value]="node.item.text" matInput #itemValue placeholder="text" /> | |||
| </mat-form-field> | |||
| <button [disabled]="itemValue.value === ''" mat-button (click)="updateNode(node, itemValue.value)">Update</button> | |||
| </span> | |||
| <button mat-icon-button (click)="openOptions(node)"> | |||
| <mat-icon>more_vert</mat-icon> | |||
| </button> | |||
| </mat-tree-node> | |||
| <mat-tree-node *matTreeNodeDef="let node; when: hasNoContent" matTreeNodePadding> | |||
| <button mat-icon-button disabled></button> | |||
| <span>§{{ node.item.paragraph }}</span> | |||
| <mat-form-field class="new-node-input"> | |||
| <mat-label>New Rule</mat-label> | |||
| <input [formControl]="text" matInput #itemValue placeholder="text" /> | |||
| </mat-form-field> | |||
| <button [disabled]="itemValue.value === ''" mat-button (click)="addNode(node, itemValue.value)">Save</button> | |||
| </mat-tree-node> | |||
| <mat-tree-node class="disabled-node" *matTreeNodeDef="let node; when: isDeleted" matTreeNodePadding> | |||
| <button mat-icon-button (click)="restore(node)"> | |||
| <mat-icon>restore</mat-icon> | |||
| </button> | |||
| <span>§{{ node.item.paragraph }} {{node.item.text}}</span> | |||
| <button mat-icon-button (click)="openOptions(node)"> | |||
| <mat-icon>more_vert</mat-icon> | |||
| </button> | |||
| </mat-tree-node> | |||
| </mat-tree> | |||
| <button mat-icon-button (click)="addEmptyRule()"> | |||
| <mat-icon>add</mat-icon> | |||
| </button> | |||
| </mat-card> | |||
| @@ -1,9 +1,15 @@ | |||
| import { FlatTreeControl } from '@angular/cdk/tree'; | |||
| import { Component, OnInit } from '@angular/core'; | |||
| import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core'; | |||
| import { FormControl } from '@angular/forms'; | |||
| import { MatBottomSheet, MatBottomSheetConfig } from '@angular/material/bottom-sheet'; | |||
| import { MatSnackBar } from '@angular/material/snack-bar'; | |||
| import { MatTreeFlatDataSource, MatTreeFlattener } from '@angular/material/tree'; | |||
| import { Subject } from 'rxjs'; | |||
| import { Rule } from '../../../../api/model/rule'; | |||
| import { EventDialogComponent } from '../../event-dialog/event-dialog.component'; | |||
| import { OptionsShetComponent } from '../options-shet/options-shet.component'; | |||
| import { DynamicDatabase } from './class/dynamic-database'; | |||
| import { EventMessage } from './class/event-message'; | |||
| import { RuleFlatNode } from './class/rule-flat-node'; | |||
| @@ -17,9 +23,11 @@ export class CreateRuleComponent implements OnInit { | |||
| flatNodeMap = new Map<RuleFlatNode, Rule>(); | |||
| nestedNodeMap = new Map<Rule, RuleFlatNode>(); | |||
| text = new FormControl(''); | |||
| @ViewChild(TemplateRef) template: TemplateRef<any>; | |||
| private _transformer = (rule: Rule, level: number) => { | |||
| ; | |||
| const existingNode = this.nestedNodeMap.get(rule); | |||
| const flatNode = existingNode && existingNode.item.id === rule.id | |||
| ? existingNode | |||
| @@ -40,7 +48,7 @@ export class CreateRuleComponent implements OnInit { | |||
| dataSource: MatTreeFlatDataSource<Rule, RuleFlatNode>; | |||
| _database: DynamicDatabase; | |||
| constructor(database: DynamicDatabase) { | |||
| constructor(database: DynamicDatabase, private _snackBar: MatSnackBar, readonly bottomSheet: MatBottomSheet) { | |||
| this._database = database; | |||
| this.treeControl = new FlatTreeControl<RuleFlatNode>(this.getLevel, this.isExpandable); | |||
| this.treeFlattener = new MatTreeFlattener<Rule, RuleFlatNode, RuleFlatNode>( | |||
| @@ -51,16 +59,64 @@ export class CreateRuleComponent implements OnInit { | |||
| this._database.dataChange.subscribe(data => { | |||
| this.dataSource.data = data; | |||
| }); | |||
| this._database.onEvent.subscribe( | |||
| (event) => { | |||
| if (event.error) { | |||
| console.error(event.error); | |||
| } | |||
| this.openSnackBar(event) | |||
| } | |||
| ) | |||
| this._database.childAdded.subscribe(parent => this.treeControl.expand(this.nestedNodeMap.get(parent))) | |||
| } | |||
| ngOnInit(): void { | |||
| } | |||
| openOptions(node: RuleFlatNode) { | |||
| const onRemove = new Subject<RuleFlatNode>(); | |||
| const onAdd = new Subject<RuleFlatNode>(); | |||
| const onEdit = new Subject<RuleFlatNode>(); | |||
| this.bottomSheet.open(OptionsShetComponent, { | |||
| data: { | |||
| remove: onRemove, | |||
| add: onAdd, | |||
| edit: onEdit, | |||
| node: node | |||
| } | |||
| }); | |||
| onRemove.subscribe( | |||
| (node) => { | |||
| this.remove(node); | |||
| this.bottomSheet.dismiss(); | |||
| } | |||
| ) | |||
| onAdd.subscribe( | |||
| (node) => { | |||
| this.addEmptyRule(node); | |||
| this.bottomSheet.dismiss(); | |||
| } | |||
| ) | |||
| onEdit.subscribe( | |||
| (node) => { | |||
| this.openEdit(node); | |||
| this.bottomSheet.dismiss(); | |||
| } | |||
| ) | |||
| } | |||
| openSnackBar(event: EventMessage) { | |||
| this._snackBar.openFromComponent(EventDialogComponent, { | |||
| data: event, | |||
| duration: 1000, | |||
| }); | |||
| } | |||
| getLevel = (node: RuleFlatNode) => node.level; | |||
| isExpandable = (node: RuleFlatNode) => node.expandable; | |||
| getChildren = (node: Rule): Rule[] => node.subRule; | |||
| hasChild = (_: number, node: RuleFlatNode) => node.expandable && !this.isDeleted(_, node); | |||
| hasChild = (_: number, node: RuleFlatNode) => node.expandable && !this.isDeleted(_, node) && !this.inEditMode(_, node); | |||
| inEditMode = (_: number, node: RuleFlatNode) => node.editMode; | |||
| isDeleted = (_: number, _nodeData: RuleFlatNode) => _nodeData.item.deletedAt !== null; | |||
| hasNoContent = (_: number, _nodeData: RuleFlatNode) => _nodeData.item.text === ''; | |||
| hasContent = (_nodeData: RuleFlatNode) => _nodeData.item.text !== ""; | |||
| @@ -95,9 +151,11 @@ export class CreateRuleComponent implements OnInit { | |||
| } | |||
| async addNode(newNode: RuleFlatNode, text: string) { | |||
| ; | |||
| const newRule = this.flatNodeMap.get(newNode); | |||
| newRule.text = text; | |||
| if (!!newRule.parentRule) { | |||
| ; | |||
| const parentRule = this._database.getParentById(newRule.parentRule.id) | |||
| this._database.insertChild(parentRule, newRule) | |||
| return; | |||
| @@ -116,12 +174,29 @@ export class CreateRuleComponent implements OnInit { | |||
| this._database.removeChild(parent, ruleToRemove); | |||
| } | |||
| async openEdit(nodeToEdit: RuleFlatNode) { | |||
| nodeToEdit.editMode = true; | |||
| this._database.reload; | |||
| } | |||
| async restore(nodeToRestore: RuleFlatNode) { | |||
| const ruleToRestore = this.flatNodeMap.get(nodeToRestore); | |||
| this._database.restore(ruleToRestore); | |||
| } | |||
| async updateNode(updatedNode: RuleFlatNode, updatedText: string) { | |||
| const parentNode = this.getParentNode(updatedNode); | |||
| if (parentNode) { | |||
| updatedNode.item.parentRule = { | |||
| id: parentNode.item.id, | |||
| text: parentNode.item.text, | |||
| paragraph: parentNode.item.text | |||
| } | |||
| } | |||
| const updatedRule = this.flatNodeMap.get(updatedNode); | |||
| updatedRule.text = updatedText; | |||
| this._database.update(updatedRule.id, updatedRule) | |||
| } | |||
| } | |||
| @@ -0,0 +1,11 @@ | |||
| <span> | |||
| <button *ngIf="config.node.root" mat-icon-button (click)="config.add.next(config.node)"> | |||
| <mat-icon>add</mat-icon> | |||
| </button> | |||
| <button mat-icon-button (click)="config.remove.next(config.node)"> | |||
| <mat-icon>remove</mat-icon> | |||
| </button> | |||
| <button mat-icon-button (click)="config.edit.next(config.node)"> | |||
| <mat-icon>edit</mat-icon> | |||
| </button> | |||
| </span> | |||
| @@ -0,0 +1,25 @@ | |||
| import { ComponentFixture, TestBed } from '@angular/core/testing'; | |||
| import { OptionsShetComponent } from './options-shet.component'; | |||
| describe('OptionsShetComponent', () => { | |||
| let component: OptionsShetComponent; | |||
| let fixture: ComponentFixture<OptionsShetComponent>; | |||
| beforeEach(async () => { | |||
| await TestBed.configureTestingModule({ | |||
| declarations: [ OptionsShetComponent ] | |||
| }) | |||
| .compileComponents(); | |||
| }); | |||
| beforeEach(() => { | |||
| fixture = TestBed.createComponent(OptionsShetComponent); | |||
| component = fixture.componentInstance; | |||
| fixture.detectChanges(); | |||
| }); | |||
| it('should create', () => { | |||
| expect(component).toBeTruthy(); | |||
| }); | |||
| }); | |||
| @@ -0,0 +1,23 @@ | |||
| import { Component, Inject, OnInit } from '@angular/core'; | |||
| import { MAT_BOTTOM_SHEET_DATA } from '@angular/material/bottom-sheet'; | |||
| import { Subject } from 'rxjs'; | |||
| import { RuleFlatNode } from '../create-rule/class/rule-flat-node'; | |||
| @Component({ | |||
| selector: 'app-options-shet', | |||
| templateUrl: './options-shet.component.html', | |||
| styleUrls: ['./options-shet.component.scss'] | |||
| }) | |||
| export class OptionsShetComponent implements OnInit { | |||
| constructor(@Inject(MAT_BOTTOM_SHEET_DATA) public config: { | |||
| add: Subject<RuleFlatNode>, | |||
| remove: Subject<RuleFlatNode>, | |||
| edit: Subject<RuleFlatNode>, | |||
| node: RuleFlatNode | |||
| }) { } | |||
| ngOnInit(): void { | |||
| } | |||
| } | |||
| @@ -22,11 +22,13 @@ import { AuthModule } from './auth/auth.module'; | |||
| import { HTTP_INTERCEPTORS } from '@angular/common/http'; | |||
| import { AuthInterceptor } from './auth/interceptor/auth.interceptor'; | |||
| import { ErrorInterceptor } from './auth/interceptor/error.interceptor'; | |||
| import { EventDialogComponent } from './event-dialog/event-dialog.component'; | |||
| @NgModule({ | |||
| declarations: [ | |||
| DashboardComponent, | |||
| GridComponent, | |||
| MainComponent, | |||
| EventDialogComponent, | |||
| ], | |||
| imports: [ | |||
| BrowserModule, | |||
| @@ -21,8 +21,8 @@ export class ErrorInterceptor implements HttpInterceptor { | |||
| // auto logout if 401 response returned from api | |||
| this.authenticationService.logout(); | |||
| } | |||
| const error = err.error.message || err.statusText; | |||
| ; | |||
| const error = err.error?.message || err.statusText; | |||
| return throwError(error); | |||
| })) | |||
| } | |||
| @@ -0,0 +1,3 @@ | |||
| <span [ngClass]="{primary: event.event !== 'Error', warn: event.event === 'Error'}"> | |||
| {{event.message}} | |||
| </span> | |||
| @@ -0,0 +1,6 @@ | |||
| @import '~@angular/material/prebuilt-themes/deeppurple-amber.css'; | |||
| .primary {} | |||
| .warn { | |||
| background-color: red; | |||
| } | |||
| @@ -0,0 +1,25 @@ | |||
| import { ComponentFixture, TestBed } from '@angular/core/testing'; | |||
| import { EventDialogComponent } from './event-dialog.component'; | |||
| describe('EventDialogComponent', () => { | |||
| let component: EventDialogComponent; | |||
| let fixture: ComponentFixture<EventDialogComponent>; | |||
| beforeEach(async () => { | |||
| await TestBed.configureTestingModule({ | |||
| declarations: [ EventDialogComponent ] | |||
| }) | |||
| .compileComponents(); | |||
| }); | |||
| beforeEach(() => { | |||
| fixture = TestBed.createComponent(EventDialogComponent); | |||
| component = fixture.componentInstance; | |||
| fixture.detectChanges(); | |||
| }); | |||
| it('should create', () => { | |||
| expect(component).toBeTruthy(); | |||
| }); | |||
| }); | |||
| @@ -0,0 +1,16 @@ | |||
| import { Component, Inject, Input, OnInit } from '@angular/core'; | |||
| import { MAT_SNACK_BAR_DATA } from '@angular/material/snack-bar'; | |||
| import { EventMessage } from '../admin/create-rule/class/event-message'; | |||
| @Component({ | |||
| selector: 'app-event-dialog', | |||
| templateUrl: './event-dialog.component.html', | |||
| styleUrls: ['./event-dialog.component.scss'] | |||
| }) | |||
| export class EventDialogComponent implements OnInit { | |||
| constructor(@Inject(MAT_SNACK_BAR_DATA) public event: EventMessage) { } | |||
| ngOnInit(): void { | |||
| } | |||
| } | |||
| @@ -1,6 +1,8 @@ | |||
| <mat-toolbar> | |||
| <span > | |||
| <span> | |||
| <a href="https://ziermach.de/legal">legal</a> | |||
| </span | |||
| > | |||
| </mat-toolbar> | |||
| </span> | |||
| <span [routerLink]="['/admin/create']"> | |||
| <mat-icon>add</mat-icon> | |||
| </span> | |||
| </mat-toolbar> | |||
| @@ -1,3 +1,10 @@ | |||
| .mat-toolbar { | |||
| height: 3%; | |||
| height: 3%; | |||
| background: transparent; | |||
| color: white; | |||
| font-size: small; | |||
| } | |||
| a { | |||
| color: white | |||
| } | |||
| @@ -2,6 +2,8 @@ import { NgModule } from '@angular/core'; | |||
| import { CommonModule } from '@angular/common'; | |||
| import { FooterComponent } from './footer.component'; | |||
| import { MatToolbarModule } from '@angular/material/toolbar'; | |||
| import { MatIconModule } from '@angular/material/icon'; | |||
| import { RouterModule } from '@angular/router'; | |||
| @@ -11,7 +13,9 @@ import { MatToolbarModule } from '@angular/material/toolbar'; | |||
| ], | |||
| imports: [ | |||
| CommonModule, | |||
| MatToolbarModule | |||
| MatToolbarModule, | |||
| MatIconModule, | |||
| RouterModule, | |||
| ], | |||
| exports: [ | |||
| FooterComponent | |||
| @@ -2,11 +2,12 @@ | |||
| <mat-sidenav-content class="page-wrap"> | |||
| <mat-toolbar color="primary"> | |||
| <span routerLink="" class="mat-title title"> | |||
| <mat-icon mat-list-icon class="logo">bedroom_baby</mat-icon> Hof Hoppe</span | |||
| <mat-icon mat-list-icon class="logo">bedroom_baby</mat-icon> Hof Hoppe</span | |||
| > | |||
| </mat-toolbar> | |||
| <main class="content"> | |||
| <router-outlet></router-outlet> | |||
| </main> | |||
| </mat-sidenav-content> | |||
| </mat-toolbar> | |||
| <main class="content"> | |||
| <router-outlet></router-outlet> | |||
| </main> | |||
| <app-footer></app-footer> | |||
| </mat-sidenav-content> | |||
| </mat-sidenav-container> | |||
| @@ -1,10 +1,10 @@ | |||
| <mat-card class="dashboard-card wood-card"> | |||
| <mat-card-header> | |||
| <mat-card-title class="title mat-title"> | |||
| <mat-icon mat-list-icon class="logo">gavel</mat-icon> Regeln | |||
| </mat-card-title> | |||
| </mat-card-header> | |||
| <mat-card-content class="dashboard-card-content"> | |||
| <app-rule-list [rules]="rules"></app-rule-list> | |||
| </mat-card-content> | |||
| </mat-card> | |||
| <mat-card-header> | |||
| <mat-card-title class="title mat-title"> | |||
| <mat-icon mat-list-icon class="logo">gavel</mat-icon> Regeln | |||
| </mat-card-title> | |||
| </mat-card-header> | |||
| <mat-card-content class="dashboard-card-content"> | |||
| <app-rule-list [rules]="rules"></app-rule-list> | |||
| </mat-card-content> | |||
| </mat-card> | |||
| @@ -2,6 +2,7 @@ import { Component, OnInit } from '@angular/core'; | |||
| import { Rule } from '../../../../api/model/rule'; | |||
| import { RulesService } from '../../../../api/api/rules.service'; | |||
| import { RuleDataService } from '../../service/rule-data.service'; | |||
| import { Router } from '@angular/router'; | |||
| @Component({ | |||
| selector: 'app-rules', | |||
| templateUrl: './rules.component.html', | |||
| @@ -9,7 +10,11 @@ import { RuleDataService } from '../../service/rule-data.service'; | |||
| }) | |||
| export class RulesComponent implements OnInit { | |||
| rules: Rule[] = [] | |||
| constructor(protected rulesService: RulesService,protected ruleDataService: RuleDataService) { | |||
| constructor( | |||
| protected rulesService: RulesService, | |||
| protected ruleDataService: RuleDataService, | |||
| protected router: Router, | |||
| ) { | |||
| rulesService.configuration.basePath = 'http://localhost:3000'; | |||
| } | |||
| @@ -21,5 +26,8 @@ export class RulesComponent implements OnInit { | |||
| }) | |||
| } | |||
| openAdminArea() { | |||
| this.router.navigate(['/admin/create']); | |||
| } | |||
| } | |||