gui FEATURE manipulate with the leaf-lists in configuration data
diff --git a/frontend/config/config.component.ts b/frontend/config/config.component.ts
index ee12741..c31acfd 100644
--- a/frontend/config/config.component.ts
+++ b/frontend/config/config.component.ts
@@ -35,7 +35,6 @@
} else {
activeSession.dataVisibility = 'root';
}
- console.log(activeSession.data);
}
this.sessionsService.storeData();
this.loading = false;
diff --git a/frontend/config/modifications.service.ts b/frontend/config/modifications.service.ts
index 7327ffa..e553df8 100644
--- a/frontend/config/modifications.service.ts
+++ b/frontend/config/modifications.service.ts
@@ -179,7 +179,20 @@
}
}
- delete(activeSession, node) {
+ isDeleted(node, value = null): boolean {
+ if ('deleted' in node) {
+ if (typeof node['deleted'] === 'boolean') {
+ return node['deleted'];
+ } else if (value) {
+ if (node['deleted'].indexOf(value) != -1) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ delete(activeSession, node, value = null) {
if ('new' in node) {
/* removing newly created subtree */
let parent = this.nodeParent(activeSession, node);
@@ -210,13 +223,21 @@
/* new record */
record['type'] = 'delete';
record['original'] = node;
- node['deleted'] = true;
node['dirty'] = true;
} else if (record['type'] == 'change') {
record['type'] = 'delete';
node['value'] = record['original'];
delete record['original'];
delete record['value'];
+ }
+ if (value) {
+ if (!('deleted' in node) || typeof node['deleted'] === 'boolean') {
+ node['deleted'] = [];
+ }
+ node['deleted'].push(value);
+ } else if (node['info']['type'] == 8) {
+ node['deleted'] = node['value'].slice(0);
+ } else {
node['deleted'] = true;
}
}
@@ -282,6 +303,27 @@
delete node['schemaChildren'];
}
+ private list_nextpos(node, path: string): number {
+ let search;
+ if ('new' in node) {
+ search = node['children'];
+ } else {
+ search = node['newChildren'];
+ }
+ let pos = 1;
+ if (search.length) {
+ for (let sibling of search) {
+ if (sibling['path'].substr(0, path.length + 1) == path + '[') {
+ let n = parseInt(sibling['path'].substring(path.length + 1));
+ if (n >= pos) {
+ pos = n + 1;
+ }
+ }
+ }
+ }
+ return pos;
+ }
+
create(activeSession, node, index) {
//console.trace();
let newNode = {};
@@ -324,26 +366,13 @@
}
this.setEdit(activeSession, newNode, true)
break;
+ case 8: /* leaf-list */
+ newNode['path'] = newNode['path'] + '[' + this.list_nextpos(node, newNode['path']) + ']';
+ this.setEdit(activeSession, newNode, true)
+ console.log(newNode);
+ break;
case 16: /* list */
- let search;
- if ('new' in node) {
- search = node['children'];
- } else {
- search = node['newChildren'];
- }
- let pos = 1;
- if (search.length) {
- for (let sibling of search) {
- if (sibling['path'].substr(0, newNode['path'].length + 1) == newNode['path'] + '[') {
- let n = parseInt(sibling['path'].substring(newNode['path'].length + 1));
- if (n >= pos) {
- pos = n + 1;
- }
- }
- }
- }
- newNode['path'] = newNode['path'] + '[' + pos + ']';
-
+ newNode['path'] = newNode['path'] + '[' + this.list_nextpos(node, newNode['path']) + ']';
newNode['children'] = [];
/* open creation dialog for nodes inside the created list */
this.sessionsService.childrenSchemas(activeSession.key, newNode['info']['path'], newNode).then(result => {
@@ -405,8 +434,8 @@
delete node['creatingChild'];
}
if ('deleted' in node) {
- node['dirty'] = false;
- node['deleted'] = false;
+ delete node['dirty'];
+ delete node['deleted'];
}
if ('new' in node) {
@@ -516,9 +545,10 @@
return 'invalid number (' + count + ') of keys in ' + node['path'];
}
}
+
+ /* recursion */
if (node['info']['type'] == 16 || node['info']['type'] == 1) {
for (let i in node['children']) {;
- console.log(node['children'][i]);
if (node['children'][i]['info']['type'] == 4) {
/* leaf */
if (!('value' in node['children'][i])) {
@@ -528,6 +558,12 @@
console.log('not confirmed node ' + node['children'][i]['path'] + ', removing it');
node['children'].splice(i, 1);
}
+ } else if (node['children'][i]['info']['type'] == 8) {
+ /* leaf-list */
+ if (!('value' in node['children'][i])) {
+ console.log('not confirmed node ' + node['children'][i]['path'] + ', removing it');
+ node['children'].splice(i, 1);
+ }
} else {
/* recursion */
let msg = this.resolveKeys(node['children'][i], false);
@@ -544,6 +580,8 @@
for (let i in node['info']['keys']) {
node['path'] = node['path'] + '[' + node['info']['keys'][i] + '=\'' + node['children'][i]['value'] + '\']'
}
+ } else if (node['info']['type'] == 8 && top) {
+ node['path'] = node['path'].slice(0, node['path'].lastIndexOf('[') + 1) + '.=\'' + node['value'][0] + '\']'
}
return null;
}
@@ -553,6 +591,12 @@
//console.log(JSON.stringify(mod));
if (!('data' in activeSession.modifications[mod])) {
continue;
+ } else if (activeSession.modifications[mod]['data']['info']['type'] == 4 || activeSession.modifications[mod]['data']['info']['type'] == 8) {
+ /* remove not confirmed leaf/leaf-lists */
+ if (!('value' in activeSession.modifications[mod]['data'])) {
+ console.log('not confirmed node ' + activeSession.modifications[mod]['data']['path'] + ', removing it');
+ this.removeModificationsRecord(activeSession, mod);
+ }
}
let err = this.resolveKeys(activeSession.modifications[mod]['data']);
if (err) {
diff --git a/frontend/config/tree-create.html b/frontend/config/tree-create.html
index 26a6ef3..a0ed34d 100644
--- a/frontend/config/tree-create.html
+++ b/frontend/config/tree-create.html
@@ -3,7 +3,7 @@
class="node_edit" [class.dialog]="node['schemaChildren']"
treeScrollTo [node]="node">
<ng-container *ngIf="node['schemaChildren'].length; else nothingToCreate">
- <tree-indent [node]="node" [indentation]="indentation" [type]="'edit'"></tree-indent>
+ <tree-indent [node]="node" [indentation]="indentation" [type]="'create'"></tree-indent>
<select (change)="creatingDialogSelect(node, $event.target.value, $event.currentTarget)">
<option disabled selected value="-1" style="display: none"> </option>
<ng-container *ngFor="let schema of node['schemaChildren']; let i='index'">
diff --git a/frontend/config/tree-indent.html b/frontend/config/tree-indent.html
index 2d3fd82..0c0978d 100644
--- a/frontend/config/tree-indent.html
+++ b/frontend/config/tree-indent.html
@@ -1,61 +1,76 @@
-<ng-container *ngIf="type == 'edit' || node['new'] || node['deleted']; else menu">
- <img *ngIf="type == 'edit' && node['info']['type'] != 4" class="icon_action" src="assets/netopeer/icons/close.svg"
- onmouseover="this.src='assets/netopeer/icons/close_active.svg'"
- onmouseout="this.src='assets/netopeer/icons/close.svg'"
- (click)="closeCreatingDialog(node)"/>
- <img *ngIf="node['info']['type'] == 4 && (type == 'edit' || node['info']['key'])" class="icon_action" src="assets/netopeer/icons/tree_empty.svg"/>
- <img *ngIf="type != 'edit' && node['dirty'] && !node['info']['key']" class="icon_action" src="assets/netopeer/icons/close.svg"
- onmouseover="this.src='assets/netopeer/icons/close_active.svg'"
- onmouseout="this.src='assets/netopeer/icons/close.svg'"
- (click)="cancelModification(node)"/>
+<ng-container *ngIf="(getType() != 'root' && !node['info']['config']) || getType() == 'edit'; else nonempty">
+ <img class="icon" src="assets/netopeer/icons/tree_empty.svg"/>
</ng-container>
-<ng-template #menu >
- <span *ngIf="type == 'root' || node['info']['config']; else empty"
- (mouseenter)="showEditMenu($event)"
- (mouseleave)="hideEditMenu($event.currentTarget.lastElementChild)">
- <img class="icon_action" src="assets/netopeer/icons/menu.svg"
- onmouseover="this.src='assets/netopeer/icons/menu_active.svg'"
- onmouseout="this.src='assets/netopeer/icons/menu.svg'"/>
- <div class="editmenu msg-rounded">
- <div *ngIf="type != 'root' && !node['info']['key']" class="button_action" title="remove subtree {{node['path']}}"
- onmouseover="this.firstElementChild.src='assets/netopeer/icons/close_active.svg'"
- onmouseout="this.firstElementChild.src='assets/netopeer/icons/close.svg'"
- (click)="deleteSubtree(node);hideEditMenu($event.currentTarget.parentElement);">
- <img class="icon_action" src="assets/netopeer/icons/close.svg" />
- delete
+<ng-template #nonempty>
+ <ng-container *ngIf="getType() == 'create'">
+ <img class="icon_action" src="assets/netopeer/icons/close.svg" title="stop creating nodes here"
+ onmouseover="this.src='assets/netopeer/icons/close_active.svg'"
+ onmouseout="this.src='assets/netopeer/icons/close.svg'"
+ (click)="closeCreatingDialog(node)"/>
+ </ng-container>
+ <ng-container *ngIf="getType() == 'new' || getType() == 'deleted'">
+ <img class="icon_action" src="assets/netopeer/icons/close.svg" title="cancel modification"
+ onmouseover="this.src='assets/netopeer/icons/close_active.svg'"
+ onmouseout="this.src='assets/netopeer/icons/close.svg'"
+ (click)="cancelModification(node)"/>
+ </ng-container>
+ <ng-container *ngIf="getType() == 'value'">
+ <ng-container [ngSwitch]="modsService.isDeleted(node, value)">
+ <img *ngSwitchCase="false" title="delete value"
+ class="icon_action" src="assets/netopeer/icons/close.svg"
+ onmouseover="this.src='assets/netopeer/icons/close_active.svg'"
+ onmouseout="this.src='assets/netopeer/icons/close.svg'"
+ (click)="deleteSubtree(node, value)"/>
+ <img *ngSwitchCase="true" title="cancel modification"
+ class="icon_action" src="assets/netopeer/icons/close.svg"
+ onmouseover="this.src='assets/netopeer/icons/close_active.svg'"
+ onmouseout="this.src='assets/netopeer/icons/close.svg'"
+ (click)="cancelModification(node, value)"/>
+ </ng-container>
+ </ng-container>
+ <ng-container *ngIf="getType() == 'current' || getType() == 'root'">
+ <span (mouseenter)="showEditMenu($event)" (mouseleave)="hideEditMenu($event.currentTarget.lastElementChild)">
+ <img class="icon_action" src="assets/netopeer/icons/menu.svg"
+ onmouseover="this.src='assets/netopeer/icons/menu_active.svg'"
+ onmouseout="this.src='assets/netopeer/icons/menu.svg'"/>
+ <div class="editmenu msg-rounded">
+ <div *ngIf="getType() != 'root' && !node['info']['key']" class="button_action" title="remove subtree {{node['path']}}"
+ onmouseover="this.firstElementChild.src='assets/netopeer/icons/close_active.svg'"
+ onmouseout="this.firstElementChild.src='assets/netopeer/icons/close.svg'"
+ (click)="deleteSubtree(node);hideEditMenu($event.currentTarget.parentElement);">
+ <img class="icon_action" src="assets/netopeer/icons/close.svg" />
+ delete
+ </div>
+ <div *ngIf="getType() != 'root'" class="button_action" title="create sibling data node(s)"
+ onmouseover="this.firstElementChild.src='assets/netopeer/icons/add_active.svg'"
+ onmouseout="this.firstElementChild.src='assets/netopeer/icons/add.svg'"
+ (click)="openCreatingDialog($event.currentTarget, node, true);hideEditMenu($event.currentTarget.parentElement);">
+ <img class="icon_action" src="assets/netopeer/icons/add.svg" />
+ create sibling
+ </div>
+ <div *ngIf="getType() == 'root' || (node['info']['type'] != 4 && node['info']['type'] != 8)"
+ class="button_action" title="create children data node(s)"
+ onmouseover="this.firstElementChild.src='assets/netopeer/icons/add_active.svg'"
+ onmouseout="this.firstElementChild.src='assets/netopeer/icons/add.svg'"
+ (click)="openCreatingDialog($event.currentTarget, node, flase);hideEditMenu($event.currentTarget.parentElement);">
+ <img class="icon_action" src="assets/netopeer/icons/add.svg" />
+ create children
+ </div>
</div>
- <div *ngIf="type != 'root'" class="button_action" title="create sibling data node(s)"
- onmouseover="this.firstElementChild.src='assets/netopeer/icons/add_active.svg'"
- onmouseout="this.firstElementChild.src='assets/netopeer/icons/add.svg'"
- (click)="openCreatingDialog($event.currentTarget, node, true);hideEditMenu($event.currentTarget.parentElement);">
- <img class="icon_action" src="assets/netopeer/icons/add.svg" />
- create sibling
- </div>
- <div *ngIf="type == 'root' || (node['info']['type'] != 4 && node['info']['type'] != 8)"
- class="button_action" title="create children data node(s)"
- onmouseover="this.firstElementChild.src='assets/netopeer/icons/add_active.svg'"
- onmouseout="this.firstElementChild.src='assets/netopeer/icons/add.svg'"
- (click)="openCreatingDialog($event.currentTarget, node, flase);hideEditMenu($event.currentTarget.parentElement);">
- <img class="icon_action" src="assets/netopeer/icons/add.svg" />
- create children
- </div>
- </div>
- </span>
- <ng-template #empty>
- <img class="icon" src="assets/netopeer/icons/tree_empty.svg" />
- </ng-template>
+ </span>
+ </ng-container>
</ng-template>
<ng-container *ngFor="let indent of indentation">
<img *ngIf="!indent" class="indentation" src="assets/netopeer/icons/tree_cont.svg" />
<img *ngIf="indent" class="indentation" src="assets/netopeer/icons/tree_empty.svg" />
</ng-container>
-<ng-container *ngIf="type != 'edit' || node['info']['type'] != 4">
- <ng-container *ngIf="type == 'value'; else nodes">
- <img class="indentation" src="assets/netopeer/icons/tree_empty.svg" />
+<ng-container [ngSwitch]="getType()">
+ <img *ngSwitchCase="'value'" class="indentation" src="assets/netopeer/icons/tree_empty.svg" />
+ <img *ngSwitchCase="'root'" class="indentation" src="assets/netopeer/icons/tree_root.svg" />
+ <img *ngSwitchCase="'edit'" class="indentation" src="assets/netopeer/icons/tree_empty.svg" />
+ <img *ngSwitchCase="'create'" class="indentation" src="assets/netopeer/icons/tree_last_branch.svg" />
+ <ng-container *ngSwitchDefault>
+ <img *ngIf="node['last']" class="indentation" src="assets/netopeer/icons/tree_last_branch.svg" />
+ <img *ngIf="!node['last']" class="indentation" src="assets/netopeer/icons/tree_branch.svg" />
</ng-container>
- <ng-template #nodes>
- <img *ngIf="type == 'edit' || node['last']" class="indentation" src="assets/netopeer/icons/tree_last_branch.svg" />
- <img *ngIf="type == 'current' && !node['last']" class="indentation" src="assets/netopeer/icons/tree_branch.svg" />
- <img *ngIf="type == 'root'" class="indentation" src="assets/netopeer/icons/tree_root.svg" />
- </ng-template>
-</ng-container>
\ No newline at end of file
+</ng-container>
diff --git a/frontend/config/tree.component.html b/frontend/config/tree.component.html
index b8d0fea..ce7faee 100644
--- a/frontend/config/tree.component.html
+++ b/frontend/config/tree.component.html
@@ -26,7 +26,7 @@
<div class="subtree" *ngIf="node['path'] != '/' && (node['info']['config'] || activeSession.statusVisibility)"
[class.status]="!node['info']['config']">
- <div class="node" [class.dirty]="node['dirty']" [class.deleted]="node['deleted']"
+ <div class="node" [class.dirty]="node['dirty']" [class.deleted]="modsService.isDeleted(node)"
[class.yang-container]="node['info']['type'] == 1"
[class.yang-leaf]="node['info']['type'] == 4"
[class.yang-leaflist]="node['info']['type'] == 8"
@@ -38,7 +38,7 @@
<!-- BEGIN nodetype-specific code -->
<!-- leaf -->
- <ng-container *ngIf="node['info']['type'] == 4">
+ <ng-container *ngIf="node['info']['type'] == 4 || (node['new'] && node['info']['type'] == 8)">
<ng-container *ngIf="node['info']['key']">
<img class="icon" src="assets/netopeer/icons/key.svg" alt="key" title="list key"/>
</ng-container>
@@ -83,19 +83,24 @@
<span *ngIf="node['info']['datatype'] != node['info']['datatypebase']">({{node['info']['datatypebase']}})</span>
</div>
</ng-container>
+ <ng-container *ngIf="node['info']['type'] == 8">
+ <div class="value">{{node['info']['datatype']}}
+ <span *ngIf="node['info']['datatype'] != node['info']['datatypebase']">({{node['info']['datatypebase']}})</span>
+ </div>
+ </ng-container>
<!-- END nodetype-specific code -->
<div class="module_name">{{node['info']['module']}}</div>
</div>
<!-- BEGIN nodetype-specific code -->
- <!-- leaf's edit value -->
- <ng-container *ngIf="node['info']['type'] == 4">
+ <!-- leaf/leaf-list's edit value -->
+ <ng-container *ngIf="node['info']['type'] == 4 || node['info']['type'] == 8">
<div class="node_edit" [class.dirty]="node['dirty']" *ngIf="node['edit']">
<tree-indent [node]="node" [indentation]="inheritIndentation(node)" [type]="'edit'"></tree-indent>
<img *ngIf="node['edit'] " class="icon_action" src="assets/netopeer/icons/close.svg"
alt="cancel" title="cancel editing" tabindex=0
- (click)="node['edit']=false" (keyup.enter)="node['edit']=false"
+ (click)="changeValueCancel(node)" (keyup.enter)="changeValueCancel(node)"
onmouseover="this.src='assets/netopeer/icons/close_active.svg'"
onmouseout="this.src='assets/netopeer/icons/close.svg'" />
<img *ngIf="node['edit']" class="icon_action icon_hidden" src="assets/netopeer/icons/confirm.svg"
@@ -112,21 +117,22 @@
</ng-container>
</select>
<input *ngIf="!node['info']['values']"
- id="{{node['path']}}_input" type="text" class="value" value="{{node['value']}}" tabindex=0
+ id="{{node['path']}}_input" type="text" class="value" value="{{nodeValue(node)}}" tabindex=0
(keyup)="checkValue(node, $event.target)" (change)="checkValue(node, $event.target)"
(keyup.enter)="changeValue(node, $event.target)" (keyup.escape)="changeValueCancel(node)"
checkLeafValue [node]="node" (onCheckValue)="checkValue($event.node, $event.element)"/>
</div>
</ng-container>
- <!-- leaflist's values -->
- <ng-container *ngIf="node['info']['type'] == 8">
- <div class="node yang-leaflist" *ngFor="let value of node['value']">
- <tree-indent [node]="node" [indentation]="inheritIndentation(node)" [type]="'value'" ></tree-indent>
- <div class="value_standalone">{{value}}</div>
- </div>
- </ng-container>
- <!-- END nodetype-specific code -->
+ <!-- leaflist's values -->
+ <ng-container *ngIf="node['info']['type'] == 8 && !node['edit'] && !modsService.isDeleted(node)">
+ <div *ngFor="let value of node['value']"
+ class="node yang-leaflist" [class.dirty]="node['dirty']" [class.deleted]="modsService.isDeleted(node, value)">
+ <tree-indent [node]="node" [indentation]="inheritIndentation(node)" [type]="'value'" [value]="value"></tree-indent>
+ <div class="value_standalone">{{value}}</div>
+ </div>
+ </ng-container>
+ <!-- END nodetype-specific code -->
<!-- recursion - show children -->
<div class="loading" *ngIf="node['loading']">
diff --git a/frontend/config/tree.component.ts b/frontend/config/tree.component.ts
index ef04a3b..23c2c30 100644
--- a/frontend/config/tree.component.ts
+++ b/frontend/config/tree.component.ts
@@ -77,10 +77,11 @@
})
export class TreeIndent implements OnInit {
@Input() node;
+ @Input() value;
@Input() indentation;
- @Input() type = "current";
+ @Input() type;
activeSession: Session;
- timeout;
+ private timeout;
constructor(private modsService: ModificationsService, private sessionsService: SessionsService) {}
@@ -88,6 +89,20 @@
this.activeSession = this.sessionsService.getActiveSession();
}
+ getType():string {
+ if (this.type) {
+ return this.type;
+ } else {
+ if (this.node && ('new' in this.node)) {
+ return "new";
+ } else if (this.node && ('deleted' in this.node)) {
+ return "deleted";
+ } else {
+ return "current";
+ }
+ }
+ }
+
showEditMenu(event) {
this.timeout = setTimeout(() => {
let menu = event.target.lastElementChild;
@@ -102,11 +117,29 @@
menu.style.visibility = "hidden";
}
- deleteSubtree(node) {
- this.modsService.delete(this.activeSession, node);
+ deleteSubtree(node, value = null) {
+ this.modsService.delete(this.activeSession, node, value);
this.sessionsService.storeData();
}
+ /* 0 - not deleted, 1 - deleted value, 2 - deleted all values */
+ isDeleted(): number {
+ if ('deleted' in this.node) {
+ if (typeof this.node['deleted'] === 'boolean') {
+ if (this.node['deleted']) {
+ return 2;
+ } else {
+ return 0;
+ }
+ } else if (this.value) {
+ if (this.node['deleted'].indexOf(this.value) != -1) {
+ return 1;
+ }
+ }
+ }
+ return 0;
+ }
+
openCreatingDialog(element, node, parent = false) {
if (parent) {
node = this.modsService.nodeParent(this.activeSession, node);
@@ -125,8 +158,13 @@
this.modsService.createClose(node, reason);
}
- cancelModification(node) {
- this.modsService.cancelModification(this.activeSession, node, false);
+ cancelModification(node, value = null) {
+ if (value && node['deleted'].length > 1) {
+ let i = node['deleted'].indexOf(value);
+ node['deleted'].splice(i, 1);
+ } else {
+ this.modsService.cancelModification(this.activeSession, node, false);
+ }
this.sessionsService.storeData();
}
}
@@ -218,7 +256,10 @@
changeValueCancel(node) {
if ('value' in node) {
this.modsService.setEdit(this.activeSession, node, false);
+ } else {
+ this.modsService.cancelModification(this.activeSession, node, false);
}
+ this.sessionsService.storeData();
}
changeValue(node, target) {
@@ -232,10 +273,25 @@
input = target.nextElementSibling;
}
- this.modsService.change(this.activeSession, node, input.value);
+ if (node['info']['type'] == 8) {
+ this.modsService.change(this.activeSession, node, [input.value]);
+ } else {
+ this.modsService.change(this.activeSession, node, input.value);
+ }
this.sessionsService.storeData();
}
+ nodeValue(node, index:number = 0): string {
+ if ('value' in node) {
+ if (node['info']['type'] == 4) {
+ return node['value'];
+ } else if (node['info']['type'] == 8 && node['value'].length > index) {
+ return node['value'][index];
+ }
+ }
+ return null;
+ }
+
newChildrenToShow(node) {
if ('newChildren' in node) {
return node['newChildren'];