diff --git a/package-lock.json b/package-lock.json
index 184f15af9e..58ddfe4dfe 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -32706,4 +32706,4 @@
"integrity": "sha512-LXVLVEq0NNOqK/fLJo3d0kfzd4sxwn2/h67/02pjCjfKDxgx1i9QqpvtHD8CrBnSSwMw5+dy11O7FRX5mkO7Cg=="
}
}
-}
+}
\ No newline at end of file
diff --git a/src/app/main/dialog/dialog.component.html b/src/app/main/dialog/dialog.component.html
index 44bcfca612..6e45243c48 100644
--- a/src/app/main/dialog/dialog.component.html
+++ b/src/app/main/dialog/dialog.component.html
@@ -160,10 +160,37 @@
+
+
+
+ Do you want to delete this node?
+
+
+
+
+
+
+
+
+
+ Unable to delete this list node as it is in use.
+
+
+
+
+
+
-
-
+
Do you want to delete this list?
+
diff --git a/src/app/project/list/list-item-form/list-item-form.component.spec.ts b/src/app/project/list/list-item-form/list-item-form.component.spec.ts
index 62e1288153..6657da62c0 100644
--- a/src/app/project/list/list-item-form/list-item-form.component.spec.ts
+++ b/src/app/project/list/list-item-form/list-item-form.component.spec.ts
@@ -1,69 +1,181 @@
-import { HttpClientModule } from '@angular/common/http';
+import { OverlayContainer } from '@angular/cdk/overlay';
+import { HarnessLoader } from '@angular/cdk/testing';
+import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
+import { Component, OnInit, ViewChild } from '@angular/core';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
-import { ReactiveFormsModule } from '@angular/forms';
+import { MatButtonModule } from '@angular/material/button';
+import { MatButtonHarness } from '@angular/material/button/testing';
+import { MatDialogModule, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
+import { MatDialogHarness } from '@angular/material/dialog/testing';
import { MatIconModule } from '@angular/material/icon';
-import { MatInputModule } from '@angular/material/input';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
-import { RouterTestingModule } from '@angular/router/testing';
-import { KnoraApiConnection } from '@dasch-swiss/dsp-js';
+import { ApiResponseData, DeleteListNodeResponse, ListsEndpointAdmin, StringLiteral } from '@dasch-swiss/dsp-js';
import {
- AppInitService,
DspActionModule,
- DspApiConfigToken,
- DspApiConnectionToken,
- DspCoreModule
+ DspApiConnectionToken
} from '@dasch-swiss/dsp-ui';
import { TranslateModule } from '@ngx-translate/core';
+import { of } from 'rxjs';
+import { AjaxResponse } from 'rxjs/ajax';
+import { DialogHeaderComponent } from 'src/app/main/dialog/dialog-header/dialog-header.component';
import { DialogComponent } from 'src/app/main/dialog/dialog.component';
-import { ErrorComponent } from 'src/app/main/error/error.component';
-import { TestConfig } from 'test.config';
-import { ListItemFormComponent } from './list-item-form.component';
+import { ListItemFormComponent, ListNodeOperation } from './list-item-form.component';
+
+/**
+ * Test host component to simulate parent component.
+ */
+@Component({
+ template: `
+
+ `
+})
+class TestHostComponent implements OnInit {
+
+ @ViewChild('listItemForm') listItemForm: ListItemFormComponent;
+
+ iri = 'http://rdfh.ch/lists/0001/notUsedList01';
+
+ language = 'en';
+
+ projectIri = 'http://rdfh.ch/projects/0001';
+
+ projectCode = '0001';
+
+ labels: StringLiteral[];
+
+ constructor() {}
+
+ ngOnInit() {
+ this.labels = [
+ {
+ value: 'node 1',
+ language: 'en'
+ }
+ ];
+ }
+
+}
describe('ListItemFormComponent', () => {
- let component: ListItemFormComponent;
- let fixture: ComponentFixture;
+ let testHostComponent: TestHostComponent;
+ let testHostFixture: ComponentFixture;
+ let rootLoader: HarnessLoader;
+ let overlayContainer: OverlayContainer;
beforeEach(async(() => {
+
+ const listsEndpointSpyObj = {
+ admin: {
+ listsEndpoint: jasmine.createSpyObj('listsEndpoint', ['deleteListNode'])
+ }
+ };
+
TestBed.configureTestingModule({
declarations: [
ListItemFormComponent,
+ TestHostComponent,
DialogComponent,
- ErrorComponent
+ DialogHeaderComponent
],
imports: [
BrowserAnimationsModule,
DspActionModule,
- DspCoreModule,
- HttpClientModule,
MatIconModule,
- MatInputModule,
- ReactiveFormsModule,
- RouterTestingModule,
+ MatDialogModule,
+ MatButtonModule,
TranslateModule.forRoot()
],
providers: [
- AppInitService,
{
- provide: DspApiConfigToken,
- useValue: TestConfig.ApiConfig
+ provide: DspApiConnectionToken,
+ useValue: listsEndpointSpyObj
},
{
- provide: DspApiConnectionToken,
- useValue: new KnoraApiConnection(TestConfig.ApiConfig)
- }
+ provide: MAT_DIALOG_DATA,
+ useValue: {}
+ },
+ {
+ provide: MatDialogRef,
+ useValue: {}
+ },
]
-
})
.compileComponents();
}));
beforeEach(() => {
- fixture = TestBed.createComponent(ListItemFormComponent);
- component = fixture.componentInstance;
- fixture.detectChanges();
+ testHostFixture = TestBed.createComponent(TestHostComponent);
+ testHostComponent = testHostFixture.componentInstance;
+ testHostFixture.detectChanges();
+
+ expect(testHostComponent).toBeTruthy();
+
+ testHostComponent.listItemForm.showActionBubble = true;
+ testHostFixture.detectChanges();
+
+ overlayContainer = TestBed.inject(OverlayContainer);
+ rootLoader = TestbedHarnessEnvironment.documentRootLoader(testHostFixture);
});
- it('should create', () => {
- expect(component).toBeTruthy();
+ afterEach(async () => {
+ const dialogs = await rootLoader.getAllHarnesses(MatDialogHarness);
+ await Promise.all(dialogs.map(async d => await d.close()));
+
+ // angular won't call this for us so we need to do it ourselves to avoid leaks.
+ overlayContainer.ngOnDestroy();
+ });
+
+ it('should show a dialog box when the delete button is clicked', async () => {
+
+ const deleteListNodeResponse: DeleteListNodeResponse = new DeleteListNodeResponse();
+ deleteListNodeResponse.node.children = [];
+ deleteListNodeResponse.node.id = 'http://rdfh.ch/lists/0001/notUsedList';
+ deleteListNodeResponse.node.isRootNode = true;
+ deleteListNodeResponse.node.name = 'notUsedList';
+ deleteListNodeResponse.node.projectIri = 'http://rdfh.ch/projects/0001';
+
+ const listSpy = TestBed.inject(DspApiConnectionToken);
+
+ (listSpy.admin.listsEndpoint as jasmine.SpyObj).deleteListNode.and.callFake(
+ () => {
+
+ const response = deleteListNodeResponse;
+
+ return of(ApiResponseData.fromAjaxResponse({response} as AjaxResponse));
+ }
+ );
+
+ spyOn(testHostComponent.listItemForm.refreshParent, 'emit');
+
+ const deleteButton = await rootLoader.getHarness(MatButtonHarness.with({selector: '.delete'}));
+ await deleteButton.click();
+
+ const dialogHarnesses = await rootLoader.getAllHarnesses(MatDialogHarness);
+
+ expect(dialogHarnesses.length).toEqual(1);
+
+ const confirmButton = await rootLoader.getHarness(MatButtonHarness.with({selector: '.confirm-button'}));
+
+ await confirmButton.click();
+
+ const listNodeOperation: ListNodeOperation = new ListNodeOperation();
+ listNodeOperation.listNode = deleteListNodeResponse.node;
+ listNodeOperation.operation = 'delete';
+
+ testHostFixture.whenStable().then(() => {
+ expect(listSpy.admin.listsEndpoint.deleteListNode).toHaveBeenCalledWith(testHostComponent.iri);
+ expect(listSpy.admin.listsEndpoint.deleteListNode).toHaveBeenCalledTimes(1);
+
+ expect(testHostComponent.listItemForm.refreshParent.emit).toHaveBeenCalledWith(listNodeOperation);
+ expect(testHostComponent.listItemForm.refreshParent.emit).toHaveBeenCalledTimes(1);
+ });
+
});
});
diff --git a/src/app/project/list/list-item-form/list-item-form.component.ts b/src/app/project/list/list-item-form/list-item-form.component.ts
index dcca6ec66d..3edfbf6824 100644
--- a/src/app/project/list/list-item-form/list-item-form.component.ts
+++ b/src/app/project/list/list-item-form/list-item-form.component.ts
@@ -1,15 +1,15 @@
-import { trigger, state, style, transition, animate } from '@angular/animations';
+import { animate, state, style, transition, trigger } from '@angular/animations';
import { Component, EventEmitter, Inject, Input, OnInit, Output } from '@angular/core';
-import { FormGroup } from '@angular/forms';
import { MatDialog, MatDialogConfig } from '@angular/material/dialog';
import {
ApiResponseData,
ApiResponseError,
ChildNodeInfo,
CreateChildNodeRequest,
+ DeleteListNodeResponse,
KnoraApiConnection,
ListInfoResponse,
- ListNodeInfo,
+ ListNode,
ListNodeInfoResponse,
StringLiteral
} from '@dasch-swiss/dsp-js';
@@ -17,6 +17,11 @@ import { DspApiConnectionToken } from '@dasch-swiss/dsp-ui';
import { DialogComponent } from 'src/app/main/dialog/dialog.component';
import { ErrorHandlerService } from 'src/app/main/error/error-handler.service';
+export class ListNodeOperation {
+ operation: 'create' | 'update' | 'delete' | 'reposition';
+ listNode: ListNode;
+}
+
@Component({
selector: 'app-list-item-form',
templateUrl: './list-item-form.component.html',
@@ -71,7 +76,7 @@ export class ListItemFormComponent implements OnInit {
// set main / pre-defined language
@Input() language?: string;
- @Output() refreshParent: EventEmitter = new EventEmitter();
+ @Output() refreshParent: EventEmitter = new EventEmitter();
loading: boolean;
@@ -127,25 +132,36 @@ export class ListItemFormComponent implements OnInit {
this.loading = true;
// generate the data payload
- const listItem: CreateChildNodeRequest = new CreateChildNodeRequest();
- listItem.parentNodeIri = this.parentIri;
- listItem.projectIri = this.projectIri;
- listItem.name = this.projectcode + '-' + Math.random().toString(36).substr(2) + Math.random().toString(36).substr(2);
+ const childNode: CreateChildNodeRequest = new CreateChildNodeRequest();
+ childNode.parentNodeIri = this.parentIri;
+ childNode.projectIri = this.projectIri;
+ childNode.name = this.projectcode + '-' + Math.random().toString(36).substr(2) + Math.random().toString(36).substr(2);
// initialize labels
let i = 0;
for (const l of this.labels) {
- listItem.labels[i] = new StringLiteral();
- listItem.labels[i].language = l.language;
- listItem.labels[i].value = l.value;
+ childNode.labels[i] = new StringLiteral();
+ childNode.labels[i].language = l.language;
+ childNode.labels[i].value = l.value;
i++;
}
- listItem.comments = []; // TODO: comments are not yet implemented in the template
+ childNode.comments = []; // TODO: comments are not yet implemented in the template
+
+ // init data to emit to parent
+ const listNodeOperation: ListNodeOperation = new ListNodeOperation();
// send payload to dsp-api's api
- this._dspApiConnection.admin.listsEndpoint.createChildNode(listItem).subscribe(
+ this._dspApiConnection.admin.listsEndpoint.createChildNode(childNode).subscribe(
(response: ApiResponseData) => {
- this.refreshParent.emit(response.body.nodeinfo);
+ // this needs to return a ListNode as opposed to a ListNodeInfo, so we make one
+ listNodeOperation.listNode = new ListNode();
+ listNodeOperation.listNode.hasRootNode = response.body.nodeinfo.hasRootNode;
+ listNodeOperation.listNode.id = response.body.nodeinfo.id;
+ listNodeOperation.listNode.labels = response.body.nodeinfo.labels;
+ listNodeOperation.listNode.name = response.body.nodeinfo.name;
+ listNodeOperation.listNode.position = response.body.nodeinfo.position;
+ listNodeOperation.operation = 'create';
+ this.refreshParent.emit(listNodeOperation);
this.loading = false;
},
(error: ApiResponseError) => {
@@ -182,7 +198,7 @@ export class ListItemFormComponent implements OnInit {
}
/**
- * Called when the 'edit' button is clicked.
+ * Called when the 'edit' or 'delete' button is clicked.
*
* @param mode mode to tell DialogComponent which part of the template to show.
* @param name label of the node; for now this is always the first label in the array.
@@ -203,12 +219,49 @@ export class ListItemFormComponent implements OnInit {
dialogConfig
);
- dialogRef.afterClosed().subscribe((data: ChildNodeInfo) => {
- // update the view if data was passed back
- // data is only passed back when clicking the 'update' button
- if (data) {
- this.refreshParent.emit(data as ListNodeInfo);
+ dialogRef.afterClosed().subscribe((data: ChildNodeInfo | boolean) => {
+
+ // init data to emit to parent
+ const listNodeOperation = new ListNodeOperation();
+
+ if (data instanceof ChildNodeInfo) { // update
+ // the call to DSP-API to update the node is done in the child component
+ listNodeOperation.listNode = (data as ListNode);
+ listNodeOperation.operation = 'update';
+
+ // emit data to parent to update the view
+ this.refreshParent.emit(listNodeOperation);
this.labels = data.labels;
+ } else if (typeof(data) === 'boolean' && data === true) { // delete
+ // delete the node
+ this._dspApiConnection.admin.listsEndpoint.deleteListNode(iri).subscribe(
+ (response: ApiResponseData) => {
+ listNodeOperation.listNode = response.body.node;
+ listNodeOperation.operation = 'delete';
+
+ // emit data to parent to update the view
+ this.refreshParent.emit(listNodeOperation);
+ },
+ (error: ApiResponseError) => {
+ // if DSP-API returns a 400, it is likely that the list node is in use so we inform the user of this
+ if (error.status === 400) {
+ const errorDialogConfig: MatDialogConfig = {
+ width: '640px',
+ position: {
+ top: '112px'
+ },
+ data: { mode: 'deleteListNodeError'}
+ };
+
+ // open the dialog box
+ this._dialog.open(DialogComponent, errorDialogConfig);
+ } else {
+ // use default error behavior
+ this._errorHandler.showMessage(error);
+ }
+
+ }
+ );
}
});
}
diff --git a/src/app/project/list/list-item/list-item.component.html b/src/app/project/list/list-item/list-item.component.html
index 0a9153a4f1..5149cede05 100644
--- a/src/app/project/list/list-item/list-item.component.html
+++ b/src/app/project/list/list-item/list-item.component.html
@@ -17,7 +17,7 @@
0"
[language]="language" [childNode]="true" [list]="node.children" [parentIri]="node.id"
- [projectIri]="projectIri" [projectcode]="projectcode">
+ [projectIri]="projectIri" [projectcode]="projectcode" (refreshChildren)="updateParentNodeChildren($event, node.position)">
diff --git a/src/app/project/list/list-item/list-item.component.spec.ts b/src/app/project/list/list-item/list-item.component.spec.ts
index ce3575e03b..c563ffcf44 100644
--- a/src/app/project/list/list-item/list-item.component.spec.ts
+++ b/src/app/project/list/list-item/list-item.component.spec.ts
@@ -1,66 +1,204 @@
-import { HttpClientTestingModule } from '@angular/common/http/testing';
+import { Component, CUSTOM_ELEMENTS_SCHEMA, OnInit, resolveForwardRef, ViewChild } from '@angular/core';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ReactiveFormsModule } from '@angular/forms';
import { MatIconModule } from '@angular/material/icon';
import { MatInputModule } from '@angular/material/input';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
-import { RouterTestingModule } from '@angular/router/testing';
-import { KnoraApiConnection } from '@dasch-swiss/dsp-js';
+import { ApiResponseData, ListNode, ListNodeInfo, ListResponse, ListsEndpointAdmin, StringLiteral } from '@dasch-swiss/dsp-js';
import {
- AppInitService,
DspActionModule,
- DspApiConfigToken,
DspApiConnectionToken
} from '@dasch-swiss/dsp-ui';
+import { of } from 'rxjs';
+import { AjaxResponse } from 'rxjs/ajax';
import { DialogComponent } from 'src/app/main/dialog/dialog.component';
import { ErrorComponent } from 'src/app/main/error/error.component';
-import { TestConfig } from 'test.config';
-import { ListItemFormComponent } from '../list-item-form/list-item-form.component';
+import { ListItemFormComponent, ListNodeOperation } from '../list-item-form/list-item-form.component';
import { ListItemComponent } from './list-item.component';
+/**
+ * Test host component to simulate parent component.
+ */
+@Component({
+ template: `
+
+ `
+})
+class TestHostComponent implements OnInit {
+
+ @ViewChild('listItem') listItem: ListItemComponent;
+
+ list: ListNodeInfo[];
+
+ parentIri = 'http://rdfh.ch/lists/0001/otherTreeList';
+
+ projectIri = 'http://rdfh.ch/projects/0001';
+
+ projectCode = '0001';
+
+ constructor() {}
+
+ ngOnInit() {
+ this.list = [
+ {
+ comments: [],
+ id: 'http://rdfh.ch/lists/0001/otherTreeList',
+ labels: [{value: 'Tree List Node', language: 'en'}],
+ isRootNode: true
+ }
+ ];
+ }
+
+}
+
+/**
+ * Mock ListItemForm.
+ */
+@Component({
+ template: ``
+})
+class MockListItemFormComponent { }
+
describe('ListItemComponent', () => {
- let component: ListItemComponent;
- let fixture: ComponentFixture;
+ let testHostComponent: TestHostComponent;
+ let testHostFixture: ComponentFixture;
beforeEach(async(() => {
+
+ const listsEndpointSpyObj = {
+ admin: {
+ listsEndpoint: jasmine.createSpyObj('listsEndpoint', ['getList'])
+ }
+ };
+
TestBed.configureTestingModule({
declarations: [
ListItemComponent,
- ListItemFormComponent,
- DialogComponent,
- ErrorComponent
+ MockListItemFormComponent,
+ TestHostComponent
],
imports: [
BrowserAnimationsModule,
DspActionModule,
- HttpClientTestingModule,
- MatIconModule,
- MatInputModule,
- ReactiveFormsModule,
- RouterTestingModule
+ MatIconModule
],
providers: [
- AppInitService,
- {
- provide: DspApiConfigToken,
- useValue: TestConfig.ApiConfig
- },
{
provide: DspApiConnectionToken,
- useValue: new KnoraApiConnection(TestConfig.ApiConfig)
+ useValue: listsEndpointSpyObj
}
- ]
+ ],
+ schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
.compileComponents();
}));
beforeEach(() => {
- fixture = TestBed.createComponent(ListItemComponent);
- component = fixture.componentInstance;
- fixture.detectChanges();
+
+ const dspConnSpy = TestBed.inject(DspApiConnectionToken);
+
+ (dspConnSpy.admin.listsEndpoint as jasmine.SpyObj).getList.and.callFake(
+ () => {
+ const response = new ListResponse();
+ response.list.listinfo.id = 'http://rdfh.ch/lists/0001/otherTreeList';
+ response.list.listinfo.isRootNode = true;
+ response.list.listinfo.labels = [{value: 'Tree List Node Root', language: 'en'}];
+ response.list.children = [
+ {
+ comments: [],
+ labels: [{value: 'Tree List Node 01', language: 'en'}],
+ id: 'http://rdfh.ch/lists/0001/otherTreeList01',
+ children: [
+ {
+ comments: [],
+ labels: [{value: 'Tree List Node 03', language: 'en'}],
+ id: 'http://rdfh.ch/lists/0001/otherTreeList03',
+ children: []
+ }
+ ]
+ },
+ {
+ comments: [],
+ labels: [{value: 'Tree List Node 02', language: 'en'}],
+ id: 'http://rdfh.ch/lists/0001/otherTreeList02',
+ children: []
+ }
+ ];
+ return of(ApiResponseData.fromAjaxResponse({response} as AjaxResponse));
+ }
+ );
+
+ testHostFixture = TestBed.createComponent(TestHostComponent);
+ testHostComponent = testHostFixture.componentInstance;
+ testHostFixture.detectChanges();
+
+ expect(testHostComponent).toBeTruthy();
+ expect(testHostComponent.listItem.list.length).toEqual(2);
+ });
+
+ it('should update the view to show a newly created node', () => {
+ const listNodeOperation: ListNodeOperation = new ListNodeOperation();
+ listNodeOperation.listNode = {
+ children: [],
+ comments: [],
+ hasRootNode: 'http://rdfh.ch/lists/0001/otherTreeList',
+ id: 'http://rdfh.ch/lists/0001/otherTreeList04',
+ labels: [{value: 'Tree List Node 04', language: 'en'}]
+ };
+ listNodeOperation.operation = 'create';
+
+ testHostComponent.listItem.updateView(listNodeOperation);
+
+ expect(testHostComponent.listItem.list.length).toEqual(3);
});
- it('should create', () => {
- expect(component).toBeTruthy();
+ it('should update the view to show an updated node', () => {
+ const listNodeOperation: ListNodeOperation = new ListNodeOperation();
+ listNodeOperation.listNode = {
+ children: undefined,
+ comments: [],
+ hasRootNode: 'http://rdfh.ch/lists/0001/otherTreeList',
+ id: 'http://rdfh.ch/lists/0001/otherTreeList01',
+ labels: [{value: 'Tree List Node 0123', language: 'en'}],
+ position: 0
+ };
+ listNodeOperation.operation = 'update';
+
+ testHostComponent.listItem.updateView(listNodeOperation);
+
+ expect(testHostComponent.listItem.list.length).toEqual(2);
+
+ expect(testHostComponent.listItem.list[0].labels).toEqual([{value: 'Tree List Node 0123', language: 'en'}]);
+ });
+
+ it('should update the view to remove a deleted node', () => {
+ const listNodeOperation: ListNodeOperation = new ListNodeOperation();
+ listNodeOperation.listNode = {
+ children: [
+ {
+ comments: [],
+ labels: [{value: 'Tree List Node 02', language: 'en'}],
+ id: 'http://rdfh.ch/lists/0001/otherTreeList02',
+ children: []
+ }
+ ],
+ comments: [],
+ isRootNode: true,
+ id: 'http://rdfh.ch/lists/0001/otherTreeList01',
+ labels: [{value: 'Tree List Root', language: 'en'}],
+ projectIri: 'http://rdfh.ch/projects/0001'
+ };
+ listNodeOperation.operation = 'delete';
+
+ testHostComponent.listItem.updateView(listNodeOperation);
+
+ expect(testHostComponent.listItem.list.length).toEqual(1);
+
+ expect(testHostComponent.listItem.list[0].labels).toEqual([{value: 'Tree List Node 02', language: 'en'}]);
});
});
diff --git a/src/app/project/list/list-item/list-item.component.ts b/src/app/project/list/list-item/list-item.component.ts
index 850d97f6d2..4fae0f1e96 100644
--- a/src/app/project/list/list-item/list-item.component.ts
+++ b/src/app/project/list/list-item/list-item.component.ts
@@ -1,14 +1,14 @@
-import { Component, Inject, Input, OnInit } from '@angular/core';
+import { Component, EventEmitter, Inject, Input, OnInit, Output } from '@angular/core';
import {
ApiResponseData,
ApiResponseError,
- ChildNodeInfo,
KnoraApiConnection,
ListNode,
ListResponse
} from '@dasch-swiss/dsp-js';
import { DspApiConnectionToken } from '@dasch-swiss/dsp-ui';
import { ErrorHandlerService } from 'src/app/main/error/error-handler.service';
+import { ListNodeOperation } from '../list-item-form/list-item-form.component';
@Component({
selector: 'app-list-item',
@@ -29,6 +29,8 @@ export class ListItemComponent implements OnInit {
@Input() language?: string;
+ @Output() refreshChildren: EventEmitter = new EventEmitter();
+
expandedNode: string;
constructor(
@@ -37,8 +39,7 @@ export class ListItemComponent implements OnInit {
) { }
ngOnInit() {
-
- // in case of parent node: do not run the following request
+ // in case of parent node: run the following request to get the entire list
if (!this.childNode) {
this._dspApiConnection.admin.listsEndpoint.getList(this.parentIri).subscribe(
(result: ApiResponseData) => {
@@ -66,7 +67,6 @@ export class ListItemComponent implements OnInit {
* @param id id of parent node for which the 'expand' button was clicked.
*/
toggleChildren(id: string) {
-
if (this.showChildren(id)) {
this.expandedNode = undefined;
} else {
@@ -78,28 +78,54 @@ export class ListItemComponent implements OnInit {
/**
* Called when the 'refreshParent' event from ListItemFormComponent is triggered.
*
- * @param data info about the node; can be a root node or child node.
+ * @param data info about the operation that was performed on the node and should be reflected in the UI.
* @param firstNode states whether or not the node is a new child node; defaults to false.
*/
- updateView(data: ListNode, firstNode: boolean = false) {
-
- if (data instanceof ChildNodeInfo) {
- this.list[data.position].labels = data.labels;
- this.list[data.position].comments = data.comments;
- } else {
- // update the view by updating the existing list
- if (firstNode) {
- // in case of new child node, we have to use the children from list
- const index: number = this.list.findIndex(item => item.id === this.expandedNode);
- this.list[index].children.push(data);
-
- } else {
- this.list.push(data);
+ updateView(data: ListNodeOperation, firstNode: boolean = false) {
+ // update the view by updating the existing list
+ if (data instanceof ListNodeOperation) {
+ switch (data.operation) {
+ case 'create': {
+ if (firstNode) {
+ // in case of new child node, we have to use the children from list
+ const index: number = this.list.findIndex(item => item.id === this.expandedNode);
+ this.list[index].children.push(data.listNode);
+
+ } else {
+ this.list.push(data.listNode);
+ }
+ break;
+ }
+ case 'update': {
+ // use the position from the response from DSP-API to find the correct node to update
+ this.list[data.listNode.position].labels = data.listNode.labels;
+ this.list[data.listNode.position].comments = data.listNode.comments;
+ break;
+ }
+ case 'delete': {
+ // conveniently, the response returned by DSP-API contains the entire list without the deleted node within its 'children'
+ // we can just reassign the list to this
+ this.list = data.listNode.children;
+
+ // emit the updated list of children to the parent node
+ this.refreshChildren.emit(this.list);
+ break;
+ }
+ default: {
+ break;
+ }
}
-
- data.children = [];
}
+ }
+ /**
+ * updates the children of the parent node
+ *
+ * @param children the updated list of children nodes
+ * @param position the position of the parent node
+ */
+ updateParentNodeChildren(children: ListNode[], position: number) {
+ this.list[position].children = children;
}
}
diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json
index aa4e39ecb2..9db6fc45b0 100644
--- a/src/assets/i18n/en.json
+++ b/src/assets/i18n/en.json
@@ -151,7 +151,8 @@
},
"lists": {
"title": {
- "delete": "Delete list"
+ "deleteList": "Delete list",
+ "deleteListNode": "Delete list node"
}
},
"resource": {