Browse Source

add restore and remove

master
Christian Ziermann 3 years ago
parent
commit
bb464228cd
11 changed files with 314 additions and 59 deletions
  1. +105
    -8
      api/api/rules.service.ts
  2. +14
    -1
      api/api/rules.serviceInterface.ts
  3. +3
    -0
      api/model/rule.ts
  4. +88
    -42
      src/app/admin/create-rule/class/dynamic-database.ts
  5. +14
    -1
      src/app/admin/create-rule/create-rule.component.html
  6. +4
    -0
      src/app/admin/create-rule/create-rule.component.scss
  7. +22
    -1
      src/app/admin/create-rule/create-rule.component.ts
  8. +4
    -4
      src/app/main/main.component.html
  9. +6
    -2
      src/app/rules/rules/rules.component.ts
  10. +16
    -0
      src/app/service/rule-data.service.spec.ts
  11. +38
    -0
      src/app/service/rule-data.service.ts

+ 105
- 8
api/api/rules.service.ts View File

@@ -137,7 +137,7 @@ export class RulesService implements RulesServiceInterface {
responseType_ = 'text';
}

return this.httpClient.post<Rule>(`${this.configuration.basePath}/rules`,
return this.httpClient.post<Rule>(`${this.configuration.basePath}/rules/admin`,
createRuleDto,
{
responseType: <any>responseType_,
@@ -196,6 +196,53 @@ export class RulesService implements RulesServiceInterface {
);
}

/**
* @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body.
* @param reportProgress flag to report request and response progress.
*/
public findAllAdmin(observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json'}): Observable<Array<Rule>>;
public findAllAdmin(observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json'}): Observable<HttpResponse<Array<Rule>>>;
public findAllAdmin(observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json'}): Observable<HttpEvent<Array<Rule>>>;
public findAllAdmin(observe: any = 'body', reportProgress: boolean = false, options?: {httpHeaderAccept?: 'application/json'}): Observable<any> {

let headers = this.defaultHeaders;

let credential: string | undefined;
// authentication (basic) required
credential = this.configuration.lookupCredential('basic');
if (credential) {
headers = headers.set('Authorization', 'Basic ' + credential);
}

let httpHeaderAcceptSelected: string | undefined = options && options.httpHeaderAccept;
if (httpHeaderAcceptSelected === undefined) {
// to determine the Accept header
const httpHeaderAccepts: string[] = [
'application/json'
];
httpHeaderAcceptSelected = this.configuration.selectHeaderAccept(httpHeaderAccepts);
}
if (httpHeaderAcceptSelected !== undefined) {
headers = headers.set('Accept', httpHeaderAcceptSelected);
}


let responseType_: 'text' | 'json' = 'json';
if(httpHeaderAcceptSelected && httpHeaderAcceptSelected.startsWith('text')) {
responseType_ = 'text';
}

return this.httpClient.get<Array<Rule>>(`${this.configuration.basePath}/rules/admin`,
{
responseType: <any>responseType_,
withCredentials: this.configuration.withCredentials,
headers: headers,
observe: observe,
reportProgress: reportProgress
}
);
}

/**
* @param id
* @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body.
@@ -286,7 +333,58 @@ export class RulesService implements RulesServiceInterface {
responseType_ = 'text';
}

return this.httpClient.delete<any>(`${this.configuration.basePath}/rules/${encodeURIComponent(String(id))}`,
return this.httpClient.delete<any>(`${this.configuration.basePath}/rules/admin/${encodeURIComponent(String(id))}`,
{
responseType: <any>responseType_,
withCredentials: this.configuration.withCredentials,
headers: headers,
observe: observe,
reportProgress: reportProgress
}
);
}

/**
* @param id
* @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body.
* @param reportProgress flag to report request and response progress.
*/
public restore(id: string, observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: undefined}): Observable<any>;
public restore(id: string, observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: undefined}): Observable<HttpResponse<any>>;
public restore(id: string, observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: undefined}): Observable<HttpEvent<any>>;
public restore(id: string, observe: any = 'body', reportProgress: boolean = false, options?: {httpHeaderAccept?: undefined}): Observable<any> {
if (id === null || id === undefined) {
throw new Error('Required parameter id was null or undefined when calling restore.');
}

let headers = this.defaultHeaders;

let credential: string | undefined;
// authentication (basic) required
credential = this.configuration.lookupCredential('basic');
if (credential) {
headers = headers.set('Authorization', 'Basic ' + credential);
}

let httpHeaderAcceptSelected: string | undefined = options && options.httpHeaderAccept;
if (httpHeaderAcceptSelected === undefined) {
// to determine the Accept header
const httpHeaderAccepts: string[] = [
];
httpHeaderAcceptSelected = this.configuration.selectHeaderAccept(httpHeaderAccepts);
}
if (httpHeaderAcceptSelected !== undefined) {
headers = headers.set('Accept', httpHeaderAcceptSelected);
}


let responseType_: 'text' | 'json' = 'json';
if(httpHeaderAcceptSelected && httpHeaderAcceptSelected.startsWith('text')) {
responseType_ = 'text';
}

return this.httpClient.post<any>(`${this.configuration.basePath}/rules/admin/restore/${encodeURIComponent(String(id))}`,
null,
{
responseType: <any>responseType_,
withCredentials: this.configuration.withCredentials,
@@ -303,10 +401,10 @@ export class RulesService implements RulesServiceInterface {
* @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body.
* @param reportProgress flag to report request and response progress.
*/
public update(id: string, body: object, observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json'}): Observable<object>;
public update(id: string, body: object, observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json'}): Observable<HttpResponse<object>>;
public update(id: string, body: object, observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json'}): Observable<HttpEvent<object>>;
public update(id: string, body: object, observe: any = 'body', reportProgress: boolean = false, options?: {httpHeaderAccept?: 'application/json'}): Observable<any> {
public update(id: string, body: object, observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: undefined}): Observable<any>;
public update(id: string, body: object, observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: undefined}): Observable<HttpResponse<any>>;
public update(id: string, body: object, observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: undefined}): Observable<HttpEvent<any>>;
public update(id: string, body: object, observe: any = 'body', reportProgress: boolean = false, options?: {httpHeaderAccept?: undefined}): Observable<any> {
if (id === null || id === undefined) {
throw new Error('Required parameter id was null or undefined when calling update.');
}
@@ -327,7 +425,6 @@ export class RulesService implements RulesServiceInterface {
if (httpHeaderAcceptSelected === undefined) {
// to determine the Accept header
const httpHeaderAccepts: string[] = [
'application/json'
];
httpHeaderAcceptSelected = this.configuration.selectHeaderAccept(httpHeaderAccepts);
}
@@ -350,7 +447,7 @@ export class RulesService implements RulesServiceInterface {
responseType_ = 'text';
}

return this.httpClient.patch<object>(`${this.configuration.basePath}/rules/${encodeURIComponent(String(id))}`,
return this.httpClient.patch<any>(`${this.configuration.basePath}/rules/admin/${encodeURIComponent(String(id))}`,
body,
{
responseType: <any>responseType_,

+ 14
- 1
api/api/rules.serviceInterface.ts View File

@@ -38,6 +38,12 @@ export interface RulesServiceInterface {
*/
findAll(extraHttpRequestParams?: any): Observable<Array<Rule>>;

/**
*
*
*/
findAllAdmin(extraHttpRequestParams?: any): Observable<Array<Rule>>;

/**
*
*
@@ -52,12 +58,19 @@ export interface RulesServiceInterface {
*/
remove(id: string, extraHttpRequestParams?: any): Observable<{}>;

/**
*
*
* @param id
*/
restore(id: string, extraHttpRequestParams?: any): Observable<{}>;

/**
*
*
* @param id
* @param body
*/
update(id: string, body: object, extraHttpRequestParams?: any): Observable<object>;
update(id: string, body: object, extraHttpRequestParams?: any): Observable<{}>;

}

+ 3
- 0
api/model/rule.ts View File

@@ -17,5 +17,8 @@ export interface Rule {
text: string;
parentRule?: Rule | null;
subRule?: Array<Rule> | null;
created?: string | null;
updated?: string | null;
deletedAt?: string | null;
}


+ 88
- 42
src/app/admin/create-rule/class/dynamic-database.ts View File

@@ -4,6 +4,7 @@ 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";


@@ -15,58 +16,45 @@ export class DynamicDatabase {

get data(): Rule[] { return this.dataChange.value; }
get count(): number { return this.dataChange.value.length };
protected removeData(rule: Rule) {
const indexOfRule = this.dataChange.value.indexOf(rule);
if (indexOfRule !== -1) {
this.dataChange.value.splice(indexOfRule, 1)
this.dataChange.next(
this.data
);
}
}
protected addData(rule: Rule) { this.dataChange.next([...this.dataChange.value, rule]) }
constructor(protected rulesService: RulesService) {
constructor(protected rulesService: RulesService, protected ruleHelperService: RuleDataService) {
this.rulesService.configuration.basePath = environment.apiUrl;
this.rulesService.findAll()
this.rulesService.findAllAdmin()
.subscribe(
(rules: Rule[]) => this.dataChange.next(
rules
.filter(this.filterRuleWithParentFromRootLayer)
.sort(this.compareRulesByParagraph)
.filter(ruleHelperService.filterRuleWithParentFromRootLayer)
.sort(ruleHelperService.compareRulesByParagraph)
)
),
(err) => {
//TODO add toaster
}
}
getParagraphOfNextChild = (parentRule): string => `${parentRule.paragraph}.${parentRule.subRule.length + 1}`;
filterRuleWithParentFromRootLayer = (rootLayerRule: Rule) => typeof rootLayerRule.parentRule !== 'number';

compareRulesByParagraph = (ruleA: Rule, ruleB: Rule) => this.compareParahraph(ruleA.paragraph, ruleB.paragraph);


compareParahraph(paragraphA: string, paragraphB: string): 0 | 1 | -1 {
if (paragraphA === paragraphB) {
return 0;
}
const paragrapASections = paragraphA.split('.');
const paragrapBSections = paragraphB.split('.');
if (+paragrapASections[0] > +paragrapBSections[0]) {
return 1;
}
if (+paragrapASections[0] < +paragrapBSections[0]) {
return -1;
}
if (+paragrapASections[0] === +paragrapBSections[0]) {
let shiftedParagraphASections = paragrapASections;
shiftedParagraphASections.shift();
let shiftedParagraphBSections = paragrapBSections;
shiftedParagraphBSections.shift();
return this.compareParahraph(
shiftedParagraphASections.join('.'),
shiftedParagraphBSections.join('.'),
)
}
}
getParentById = (ruleId: string) => this.data.find(rule => rule.id === ruleId)
insertEmptyChild(parent: Rule) {
if (!parent.subRule) {
parent.subRule = [];
}
parent.subRule.push(
{
text: '',
id: '0',
parentRule: parent,
paragraph: this.getParagraphOfNextChild(parent)
paragraph: this.ruleHelperService.getParagraphOfNextChild(parent),
created: 'today',
deletedAt: null,
updated: null,
}
)
this.dataChange.next(this.data);
@@ -78,7 +66,10 @@ export class DynamicDatabase {
text: '',
id: '0',
parentRule: null,
paragraph: `${this.count + 2}`
paragraph: `${this.count + 1}`,
created: 'today',
deletedAt: null,
updated: null,
})
}
insertChild(parent: Rule, subRule: Rule) {
@@ -102,8 +93,8 @@ export class DynamicDatabase {
paragraph: parent.paragraph,
subRuleIds: [
...parent.subRule
.filter(rule => rule.id === "0")
.map(rule => rule.id) ?? [],
.filter(rule => rule.id !== "0")
.map(rule => rule.id),
subRule.id,
],
text: parent.text
@@ -142,7 +133,7 @@ export class DynamicDatabase {

insertParent(newRule: Rule) {
const createNewRule: CreateRuleDto = {
paragraph: `${this.count + 1}`,
paragraph: newRule.paragraph,
text: newRule.text,
subRuleIds: null,
parentId: null
@@ -158,13 +149,68 @@ export class DynamicDatabase {
this.dataChange.next(this.data);
}

removeParent(parent: Rule) {
parent.deletedAt = "deleted";
this.rulesService.remove(parent.id).subscribe(
(deleted) => {
//todo add update message
},
(err) => {
//TODO Push error message
console.error(err);
}
);
this.dataChange.next(this.data);
}

restore(rule: Rule) {
rule.deletedAt = null;
if (rule.subRule) {
rule.subRule.forEach((subRule) => {
this.restore(subRule);
})
}
this.rulesService.restore(rule.id).subscribe(
(deleted) => {
//todo add restored message
},
(err) => {
//TODO Push error message
console.error(err);
}
);
this.dataChange.next(this.data);
}

removeChild(parent: Rule, subRule: Rule) {
if (parent.subRule) {
const subRuleToRemove = this.findSubRuleFromParent(parent, subRule);
const indexIfSubRule = parent.subRule.indexOf(subRuleToRemove);
if (indexIfSubRule > -1) {
parent.subRule.splice(indexIfSubRule, 1);
}
subRule.deletedAt = "delted";
this.rulesService.remove(subRule.id).subscribe(
(deleted) => {
this.update(parent.id, {
paragraph: parent.paragraph,
subRuleIds: [
...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);
}
);
//todo add update message
},
(err) => {
//TODO Push error message
console.error(err);
}
);
this.dataChange.next(this.data);
}
}

+ 14
- 1
src/app/admin/create-rule/create-rule.component.html View File

@@ -5,6 +5,9 @@
<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>
</button>
</div>
</mat-tree-node>
@@ -17,6 +20,9 @@
<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>
@@ -27,8 +33,15 @@
</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>
<mat-icon>add</mat-icon>
</button>
</mat-card>

+ 4
- 0
src/app/admin/create-rule/create-rule.component.scss View File

@@ -17,4 +17,8 @@ mat-label {

.new-node-input {
padding-left: 2vw;
}

.disabled-node {
text-decoration: line-through;
}

+ 22
- 1
src/app/admin/create-rule/create-rule.component.ts View File

@@ -60,7 +60,8 @@ export class CreateRuleComponent implements OnInit {
getLevel = (node: RuleFlatNode) => node.level;
isExpandable = (node: RuleFlatNode) => node.expandable;
getChildren = (node: Rule): Rule[] => node.subRule;
hasChild = (_: number, node: RuleFlatNode) => node.expandable;
hasChild = (_: number, node: RuleFlatNode) => node.expandable && !this.isDeleted(_, node);
isDeleted = (_: number, _nodeData: RuleFlatNode) => _nodeData.item.deletedAt !== null;
hasNoContent = (_: number, _nodeData: RuleFlatNode) => _nodeData.item.text === '';
hasContent = (_nodeData: RuleFlatNode) => _nodeData.item.text !== "";

@@ -99,8 +100,28 @@ export class CreateRuleComponent implements OnInit {
if (!!newRule.parentRule) {
const parentRule = this._database.getParentById(newRule.parentRule.id)
this._database.insertChild(parentRule, newRule)
return;
}
this._database.insertParent(newRule)
}

async remove(nodeToRemove: RuleFlatNode) {
const ruleToRemove = this.flatNodeMap.get(nodeToRemove);
if (nodeToRemove.root) {
this._database.removeParent(ruleToRemove);
return
}
const parentNode = this.getParentNode(nodeToRemove);
const parent = this.flatNodeMap.get(parentNode);
this._database.removeChild(parent, ruleToRemove);
}


async restore(nodeToRestore: RuleFlatNode) {
const ruleToRestore = this.flatNodeMap.get(nodeToRestore);
this._database.restore(ruleToRestore);
}



}

+ 4
- 4
src/app/main/main.component.html View File

@@ -1,7 +1,7 @@
<mat-sidenav-container class="all-wrap">
<mat-sidenav-content class="page-wrap">
<mat-toolbar color="primary">
<span class="mat-title title" >
<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-toolbar>
@@ -9,4 +9,4 @@
<router-outlet></router-outlet>
</main>
</mat-sidenav-content>
</mat-sidenav-container>
</mat-sidenav-container>

+ 6
- 2
src/app/rules/rules/rules.component.ts View File

@@ -1,6 +1,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';
@Component({
selector: 'app-rules',
templateUrl: './rules.component.html',
@@ -8,13 +9,16 @@ import { RulesService } from '../../../../api/api/rules.service';
})
export class RulesComponent implements OnInit {
rules: Rule[] = []
constructor(protected rulesService: RulesService) {
constructor(protected rulesService: RulesService,protected ruleDataService: RuleDataService) {
rulesService.configuration.basePath = 'http://localhost:3000';
}


ngOnInit(): void {
this.rulesService.findAll('body').subscribe((rules: Rule[]) => {
this.rules = rules;
this.rules = rules
.sort(this.ruleDataService.compareRulesByParagraph)

})
}


+ 16
- 0
src/app/service/rule-data.service.spec.ts View File

@@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';

import { RuleDataService } from './rule-data.service';

describe('RuleDataService', () => {
let service: RuleDataService;

beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(RuleDataService);
});

it('should be created', () => {
expect(service).toBeTruthy();
});
});

+ 38
- 0
src/app/service/rule-data.service.ts View File

@@ -0,0 +1,38 @@
import { Injectable } from '@angular/core';
import { Rule } from '../../../api';

@Injectable({
providedIn: 'root'
})
export class RuleDataService {
getParagraphOfNextChild = (parentRule): string => `${parentRule.paragraph}.${parentRule.subRule.length + 1}`;
filterRuleWithParentFromRootLayer = (rootLayerRule: Rule) => typeof rootLayerRule.parentRule !== 'number';

compareRulesByParagraph = (ruleA: Rule, ruleB: Rule) => this.compareParahraph(ruleA.paragraph, ruleB.paragraph);


compareParahraph(paragraphA: string, paragraphB: string): 0 | 1 | -1 {
if (paragraphA === paragraphB) {
return 0;
}
const paragrapASections = paragraphA.split('.');
const paragrapBSections = paragraphB.split('.');
if (+paragrapASections[0] > +paragrapBSections[0]) {
return 1;
}
if (+paragrapASections[0] < +paragrapBSections[0]) {
return -1;
}
if (+paragrapASections[0] === +paragrapBSections[0]) {
let shiftedParagraphASections = paragrapASections;
shiftedParagraphASections.shift();
let shiftedParagraphBSections = paragrapBSections;
shiftedParagraphBSections.shift();
return this.compareParahraph(
shiftedParagraphASections.join('.'),
shiftedParagraphBSections.join('.'),
)
}
}
constructor() { }
}

Loading…
Cancel
Save