@@ -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']); | |||
} | |||
} |