浏览代码

add restore and remove

master
Christian Ziermann 3 年前
父节点
当前提交
bb464228cd
共有 11 个文件被更改,包括 314 次插入59 次删除
  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 查看文件

responseType_ = 'text'; responseType_ = 'text';
} }


return this.httpClient.post<Rule>(`${this.configuration.basePath}/rules`,
return this.httpClient.post<Rule>(`${this.configuration.basePath}/rules/admin`,
createRuleDto, createRuleDto,
{ {
responseType: <any>responseType_, responseType: <any>responseType_,
); );
} }


/**
* @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 id
* @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body.
responseType_ = 'text'; 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_, responseType: <any>responseType_,
withCredentials: this.configuration.withCredentials, withCredentials: this.configuration.withCredentials,
* @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. * @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. * @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) { if (id === null || id === undefined) {
throw new Error('Required parameter id was null or undefined when calling update.'); throw new Error('Required parameter id was null or undefined when calling update.');
} }
if (httpHeaderAcceptSelected === undefined) { if (httpHeaderAcceptSelected === undefined) {
// to determine the Accept header // to determine the Accept header
const httpHeaderAccepts: string[] = [ const httpHeaderAccepts: string[] = [
'application/json'
]; ];
httpHeaderAcceptSelected = this.configuration.selectHeaderAccept(httpHeaderAccepts); httpHeaderAcceptSelected = this.configuration.selectHeaderAccept(httpHeaderAccepts);
} }
responseType_ = 'text'; 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, body,
{ {
responseType: <any>responseType_, responseType: <any>responseType_,

+ 14
- 1
api/api/rules.serviceInterface.ts 查看文件

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


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

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


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

/** /**
* *
* *
* @param id * @param id
* @param body * @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 查看文件

text: string; text: string;
parentRule?: Rule | null; parentRule?: Rule | null;
subRule?: Array<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 查看文件

import { map } from "rxjs/operators"; import { map } from "rxjs/operators";
import { CreateRuleDto, Rule, RulesService } from "../../../../../api"; import { CreateRuleDto, Rule, RulesService } from "../../../../../api";
import { environment } from "../../../../environments/environment"; import { environment } from "../../../../environments/environment";
import { RuleDataService } from "../../../service/rule-data.service";
import { RuleFlatNode } from "./rule-flat-node"; import { RuleFlatNode } from "./rule-flat-node";






get data(): Rule[] { return this.dataChange.value; } get data(): Rule[] { return this.dataChange.value; }
get count(): number { return this.dataChange.value.length }; 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]) } 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.configuration.basePath = environment.apiUrl;
this.rulesService.findAll()
this.rulesService.findAllAdmin()
.subscribe( .subscribe(
(rules: Rule[]) => this.dataChange.next( (rules: Rule[]) => this.dataChange.next(
rules rules
.filter(this.filterRuleWithParentFromRootLayer)
.sort(this.compareRulesByParagraph)
.filter(ruleHelperService.filterRuleWithParentFromRootLayer)
.sort(ruleHelperService.compareRulesByParagraph)
) )
), ),
(err) => { (err) => {
//TODO add toaster //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) getParentById = (ruleId: string) => this.data.find(rule => rule.id === ruleId)
insertEmptyChild(parent: Rule) { insertEmptyChild(parent: Rule) {
if (!parent.subRule) {
parent.subRule = [];
}
parent.subRule.push( parent.subRule.push(
{ {
text: '', text: '',
id: '0', id: '0',
parentRule: parent, parentRule: parent,
paragraph: this.getParagraphOfNextChild(parent)
paragraph: this.ruleHelperService.getParagraphOfNextChild(parent),
created: 'today',
deletedAt: null,
updated: null,
} }
) )
this.dataChange.next(this.data); this.dataChange.next(this.data);
text: '', text: '',
id: '0', id: '0',
parentRule: null, parentRule: null,
paragraph: `${this.count + 2}`
paragraph: `${this.count + 1}`,
created: 'today',
deletedAt: null,
updated: null,
}) })
} }
insertChild(parent: Rule, subRule: Rule) { insertChild(parent: Rule, subRule: Rule) {
paragraph: parent.paragraph, paragraph: parent.paragraph,
subRuleIds: [ subRuleIds: [
...parent.subRule ...parent.subRule
.filter(rule => rule.id === "0")
.map(rule => rule.id) ?? [],
.filter(rule => rule.id !== "0")
.map(rule => rule.id),
subRule.id, subRule.id,
], ],
text: parent.text text: parent.text


insertParent(newRule: Rule) { insertParent(newRule: Rule) {
const createNewRule: CreateRuleDto = { const createNewRule: CreateRuleDto = {
paragraph: `${this.count + 1}`,
paragraph: newRule.paragraph,
text: newRule.text, text: newRule.text,
subRuleIds: null, subRuleIds: null,
parentId: null parentId: null
this.dataChange.next(this.data); 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) { removeChild(parent: Rule, subRule: Rule) {
if (parent.subRule) { 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); this.dataChange.next(this.data);
} }
} }

+ 14
- 1
src/app/admin/create-rule/create-rule.component.html 查看文件

<button mat-icon-button disabled></button> §{{ node.item.paragraph }} {{ node.item.text }} <button mat-icon-button disabled></button> §{{ node.item.paragraph }} {{ node.item.text }}
<button *ngIf="node.root" mat-icon-button (click)="addEmptyRule(node)"> <button *ngIf="node.root" mat-icon-button (click)="addEmptyRule(node)">
<mat-icon>add</mat-icon> <mat-icon>add</mat-icon>
</button>
<button mat-icon-button (click)="remove(node)">
<mat-icon>remove</mat-icon>
</button> </button>
</div> </div>
</mat-tree-node> </mat-tree-node>
<button *ngIf="node.root" mat-icon-button (click)="addEmptyRule(node)"> <button *ngIf="node.root" mat-icon-button (click)="addEmptyRule(node)">
<mat-icon>add</mat-icon> <mat-icon>add</mat-icon>
</button> </button>
<button mat-icon-button (click)="remove(node)">
<mat-icon>remove</mat-icon>
</button>
</mat-tree-node> </mat-tree-node>
<mat-tree-node *matTreeNodeDef="let node; when: hasNoContent" matTreeNodePadding> <mat-tree-node *matTreeNodeDef="let node; when: hasNoContent" matTreeNodePadding>
<button mat-icon-button disabled></button> <button mat-icon-button disabled></button>
</mat-form-field> </mat-form-field>
<button mat-button (click)="addNode(node, itemValue.value)">Save</button> <button mat-button (click)="addNode(node, itemValue.value)">Save</button>
</mat-tree-node> </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> </mat-tree>
<button mat-icon-button (click)="addEmptyRule()"> <button mat-icon-button (click)="addEmptyRule()">
<mat-icon>add</mat-icon>
<mat-icon>add</mat-icon>
</button> </button>
</mat-card> </mat-card>

+ 4
- 0
src/app/admin/create-rule/create-rule.component.scss 查看文件



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

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

+ 22
- 1
src/app/admin/create-rule/create-rule.component.ts 查看文件

getLevel = (node: RuleFlatNode) => node.level; getLevel = (node: RuleFlatNode) => node.level;
isExpandable = (node: RuleFlatNode) => node.expandable; isExpandable = (node: RuleFlatNode) => node.expandable;
getChildren = (node: Rule): Rule[] => node.subRule; 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 === ''; hasNoContent = (_: number, _nodeData: RuleFlatNode) => _nodeData.item.text === '';
hasContent = (_nodeData: RuleFlatNode) => _nodeData.item.text !== ""; hasContent = (_nodeData: RuleFlatNode) => _nodeData.item.text !== "";


if (!!newRule.parentRule) { if (!!newRule.parentRule) {
const parentRule = this._database.getParentById(newRule.parentRule.id) const parentRule = this._database.getParentById(newRule.parentRule.id)
this._database.insertChild(parentRule, newRule) this._database.insertChild(parentRule, newRule)
return;
} }
this._database.insertParent(newRule) 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 查看文件

<mat-sidenav-container class="all-wrap"> <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-icon mat-list-icon class="logo">bedroom_baby</mat-icon> Hof Hoppe</span
> >
</mat-toolbar> </mat-toolbar>
<router-outlet></router-outlet> <router-outlet></router-outlet>
</main> </main>
</mat-sidenav-content> </mat-sidenav-content>
</mat-sidenav-container>
</mat-sidenav-container>

+ 6
- 2
src/app/rules/rules/rules.component.ts 查看文件

import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { Rule } from '../../../../api/model/rule'; import { Rule } from '../../../../api/model/rule';
import { RulesService } from '../../../../api/api/rules.service'; import { RulesService } from '../../../../api/api/rules.service';
import { RuleDataService } from '../../service/rule-data.service';
@Component({ @Component({
selector: 'app-rules', selector: 'app-rules',
templateUrl: './rules.component.html', templateUrl: './rules.component.html',
}) })
export class RulesComponent implements OnInit { export class RulesComponent implements OnInit {
rules: Rule[] = [] rules: Rule[] = []
constructor(protected rulesService: RulesService) {
constructor(protected rulesService: RulesService,protected ruleDataService: RuleDataService) {
rulesService.configuration.basePath = 'http://localhost:3000'; rulesService.configuration.basePath = 'http://localhost:3000';
} }



ngOnInit(): void { ngOnInit(): void {
this.rulesService.findAll('body').subscribe((rules: Rule[]) => { 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 查看文件

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 查看文件

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() { }
}

正在加载...
取消
保存