Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(ontology): check if an ontology, a class or a property can be deleted (DSP-1750) #457

Merged
merged 22 commits into from Jun 22, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
57a6fe7
docs(ontology): fix 404 error on image
kilchenmann Jun 7, 2021
2057aeb
chore(deps): bump dsp-js version to 2.4.0
kilchenmann Jun 7, 2021
59a2a87
feat(ontology): disable delete class button
kilchenmann Jun 7, 2021
3a06c6e
refactor(ontology): clean up code
kilchenmann Jun 7, 2021
10fe80d
refactor(ontology): consistent submit button
kilchenmann Jun 7, 2021
43b99e0
feat(ontology): disable delete ontology button
kilchenmann Jun 7, 2021
6b7e75e
fix(ontology): use the right method
kilchenmann Jun 8, 2021
43d9d59
Merge branch 'main' into wip/dsp-1623-check-edit-properties
kilchenmann Jun 14, 2021
e7f38c6
feat(ontology): ask if res class can be deleted
kilchenmann Jun 14, 2021
95eca63
test(ontology): fix tests
kilchenmann Jun 15, 2021
ccb8ab4
test(ontology): bug fix in test
kilchenmann Jun 15, 2021
62783b2
test(ontology): bug fix in test
kilchenmann Jun 15, 2021
4ee9060
chore(ontology): undo previous changes
kilchenmann Jun 17, 2021
2470269
test(ontology): fix the test
kilchenmann Jun 17, 2021
f207e89
test(ontology): run all the tests
kilchenmann Jun 17, 2021
7f6e704
test(ontology): add test to new method
kilchenmann Jun 17, 2021
e6e928a
Merge branch 'main' into wip/dsp-1623-check-edit-properties
kilchenmann Jun 17, 2021
4aa4b43
test(ontology): enable all tests
kilchenmann Jun 17, 2021
6c87033
test(ontology): set correct test environment
kilchenmann Jun 17, 2021
78fa92b
feat(ontology): check if prop can be deleted
kilchenmann Jun 19, 2021
5db5353
test(ontology): enable all tests
kilchenmann Jun 19, 2021
7eea77b
fix(ontology): propCanBeDeleted shouldn't be in the cardinality setup
kilchenmann Jun 22, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
14 changes: 7 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Expand Up @@ -33,7 +33,7 @@
"@angular/platform-browser-dynamic": "^11.2.9",
"@angular/router": "^11.2.9",
"@ckeditor/ckeditor5-angular": "^1.2.3",
"@dasch-swiss/dsp-js": "^2.3.0",
"@dasch-swiss/dsp-js": "^2.4.0",
"@dasch-swiss/dsp-ui": "^1.4.0",
"@ngx-translate/core": "^12.1.2",
"@ngx-translate/http-loader": "5.0.0",
Expand Down
@@ -1,6 +1,4 @@
<dsp-progress-indicator *ngIf="loading"></dsp-progress-indicator>

<form [formGroup]="ontologyForm" (ngSubmit)="submitData()" class="form" *ngIf="!loading">
<form [formGroup]="ontologyForm" (ngSubmit)="submitData()" class="form">
<!-- auto complete list to select resource classes -->
<div class="form-content">
<mat-form-field class="large-field ontology-name">
Expand Down
Expand Up @@ -223,6 +223,7 @@ export class OntologyFormComponent implements OnInit {
this._dspApiConnection.v2.onto.updateOntology(ontologyData).subscribe(
(response: OntologyMetadata) => {
this.updateParent.emit(response.id);
this.loading = false;
this.closeDialog.emit(response.id);
},
(error: ApiResponseError) => {
Expand All @@ -246,6 +247,7 @@ export class OntologyFormComponent implements OnInit {
this._dspApiConnection.v2.onto.createOntology(ontologyData).subscribe(
(response: OntologyMetadata) => {
this.updateParent.emit(response.id);
this.loading = false;
this.closeDialog.emit(response.id);
},
(error: ApiResponseError) => {
Expand Down
4 changes: 2 additions & 2 deletions src/app/project/ontology/ontology.component.html
Expand Up @@ -109,8 +109,8 @@ <h2 class="mat-title">
</button>
</span>
<span
[matTooltip]="(ontology.lastModificationDate ? 'Delete data model' : 'This data model can\'t be edited because of missing lastModificationDate!')">
<button mat-button [disabled]="!ontology.lastModificationDate"
[matTooltip]="(ontology.lastModificationDate ? (ontologyCanBeDeleted ? 'Delete data model' : 'This data model can\'t be deleted because it is in use!') : 'This data model can\'t be deleted because of missing lastModificationDate!')">
<button mat-button [disabled]="!ontology.lastModificationDate || !ontologyCanBeDeleted"
(click)="$event.stopPropagation(); delete('Ontology', {iri: ontologyIri, label: ontology.label})">
<mat-icon>delete</mat-icon>
Delete
Expand Down
106 changes: 94 additions & 12 deletions src/app/project/ontology/ontology.component.spec.ts
@@ -1,5 +1,5 @@
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { ReactiveFormsModule } from '@angular/forms';
import { MatCardModule } from '@angular/material/card';
import { MatOptionModule } from '@angular/material/core';
Expand All @@ -14,34 +14,53 @@ import { MatTooltipModule } from '@angular/material/tooltip';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { ActivatedRoute } from '@angular/router';
import { RouterTestingModule } from '@angular/router/testing';
import { KnoraApiConnection } from '@dasch-swiss/dsp-js';
import { ApiResponseData, CanDoResponse, ListNodeInfo, ListsEndpointAdmin, ListsResponse, MockList, MockOntology, OntologiesEndpointV2, OntologiesMetadata, ReadOntology } from '@dasch-swiss/dsp-js';
import {
AppInitService,
DspActionModule,
DspApiConfigToken,
DspApiConnectionToken,
DspActionModule, DspApiConnectionToken,
DspCoreModule
} from '@dasch-swiss/dsp-ui';
import { of } from 'rxjs';
import { AjaxResponse } from 'rxjs/ajax';
import { CacheService } from 'src/app/main/cache/cache.service';
import { DialogComponent } from 'src/app/main/dialog/dialog.component';
import { ErrorComponent } from 'src/app/main/error/error.component';
import { TestConfig } from 'test.config';
import { OntologyVisualizerComponent } from './ontology-visualizer/ontology-visualizer.component';
import { OntologyComponent } from './ontology.component';
import { PropertyInfoComponent } from './property-info/property-info.component';
import { ResourceClassInfoComponent } from './resource-class-info/resource-class-info.component';

describe('OntologyComponent', () => {
let component: OntologyComponent;
let fixture: ComponentFixture<OntologyComponent>;

beforeEach(waitForAsync(() => {
const ontologyEndpointSpyObj = {
admin: {
listsEndpoint: jasmine.createSpyObj('listsEndpoint', ['getListsInProject'])
},
v2: {
onto: jasmine.createSpyObj('onto', [
'getOntologiesByProjectIri',
'getOntology',
'canDeleteOntology',
'deleteOntology',
'deleteResourceClass',
'deleteResourceProperty'
])
}
};

const cacheServiceSpy = jasmine.createSpyObj('CacheService', ['get', 'set']);

TestBed.configureTestingModule({
declarations: [
OntologyComponent,
OntologyVisualizerComponent,
DialogComponent,
ErrorComponent,
PropertyInfoComponent
PropertyInfoComponent,
ResourceClassInfoComponent
],
imports: [
BrowserAnimationsModule,
Expand Down Expand Up @@ -76,14 +95,13 @@ describe('OntologyComponent', () => {
}
}
},
AppInitService,
{
provide: DspApiConfigToken,
useValue: TestConfig.ApiConfig
provide: DspApiConnectionToken,
useValue: ontologyEndpointSpyObj
},
{
provide: DspApiConnectionToken,
useValue: new KnoraApiConnection(TestConfig.ApiConfig)
provide: CacheService,
useValue: cacheServiceSpy
}
]
})
Expand Down Expand Up @@ -111,8 +129,72 @@ describe('OntologyComponent', () => {
});

beforeEach(() => {
// set local storage session data
localStorage.setItem('session', JSON.stringify(TestConfig.CurrentSession));

// set cache with current ontology
const cacheSpy = TestBed.inject(CacheService);

(cacheSpy as jasmine.SpyObj<CacheService>).get.and.callFake(
() => {
const response: ReadOntology = MockOntology.mockReadOntology('http://0.0.0.0:3333/ontology/0001/anything/v2');
return of(response);
}
);

// can delete ontology request
const dspConnSpy = TestBed.inject(DspApiConnectionToken);
(dspConnSpy.v2.onto as jasmine.SpyObj<OntologiesEndpointV2>).canDeleteOntology.and.callFake(
() => {
const deleteResClass: CanDoResponse = {
'canDo': false
};

return of(deleteResClass);
}
);

(dspConnSpy.v2.onto as jasmine.SpyObj<OntologiesEndpointV2>).getOntologiesByProjectIri.and.callFake(
() => {
const response: OntologiesMetadata = MockOntology.mockOntologiesMetadata();
return of(response);
}
);

(dspConnSpy.v2.onto as jasmine.SpyObj<OntologiesEndpointV2>).getOntology.and.callFake(
() => {
const response: ReadOntology = MockOntology.mockReadOntology('http://0.0.0.0:3333/ontology/0001/anything/v2');
return of(response);
}
);

(dspConnSpy.admin.listsEndpoint as jasmine.SpyObj<ListsEndpointAdmin>).getListsInProject.and.callFake(
() => {
const response = new ListsResponse();

response.lists = new Array<ListNodeInfo>();

const mockList1 = new ListNodeInfo();
mockList1.comments = [];
mockList1.id = 'http://rdfh.ch/lists/0001/mockList01';
mockList1.isRootNode = true;
mockList1.labels = [{ language: 'en', value: 'Mock List 01' }];
mockList1.projectIri = 'http://rdfh.ch/projects/myProjectIri';

const mockList2 = new ListNodeInfo();
mockList2.comments = [];
mockList2.id = 'http://rdfh.ch/lists/0001/mockList02';
mockList2.isRootNode = true;
mockList2.labels = [{ language: 'en', value: 'Mock List 02' }];
mockList2.projectIri = 'http://rdfh.ch/projects/myProjectIri';

response.lists.push(mockList1, mockList2);

return of(ApiResponseData.fromAjaxResponse({ response } as AjaxResponse));
}
);


fixture = TestBed.createComponent(OntologyComponent);
component = fixture.componentInstance;
fixture.detectChanges();
Expand Down
13 changes: 13 additions & 0 deletions src/app/project/ontology/ontology.component.ts
Expand Up @@ -6,6 +6,7 @@ import { ActivatedRoute, Params, Router } from '@angular/router';
import {
ApiResponseData,
ApiResponseError,
CanDoResponse,
ClassDefinition,
Constants,
DeleteOntologyResponse,
Expand Down Expand Up @@ -81,6 +82,8 @@ export class OntologyComponent implements OnInit {
// when updating something inside the ontology
lastModificationDate: string;

ontologyCanBeDeleted: boolean;

// all resource classes in the current ontology
ontoClasses: ClassDefinition[];
// expand the resource class cards
Expand Down Expand Up @@ -344,6 +347,16 @@ export class OntologyComponent implements OnInit {
// grab the onto properties information to display
this.initOntoProperties(ontology.getAllPropertyDefinitions());

// check if the ontology can be deleted
this._dspApiConnection.v2.onto.canDeleteOntology(this.ontology.id).subscribe(
(response: CanDoResponse) => {
this.ontologyCanBeDeleted = response.canDo;
},
(error: ApiResponseError) => {
this._errorHandler.showMessage(error);
}
);

this.loadOntology = false;
}

Expand Down
Expand Up @@ -52,7 +52,7 @@
<mat-icon>tune</mat-icon>
</button>
<span
[matTooltip]="(resClasses.length > 0 ? 'The property can\'t be removed because it\'s in use' : 'Remove property from resource class')">
[matTooltip]="((resClasses.length > 0) ? 'The property can\'t be removed because it\'s in use' : 'Remove property from resource class')">
<!-- TODO: add "disabled" param as soon as we use DSP-API 13.9.1 and DSP-JS 2.4.0; use same value in matTooltip above -->
<button mat-button class="delete"
(click)="removePropertyFromClass.emit({iri: propDef.id, label: propDef.label})">
Expand All @@ -67,7 +67,7 @@
<mat-icon>edit</mat-icon>
</button>
<span
[matTooltip]="(resClasses.length > 0 ? 'The property can\'t be deleted because it\'s used in a class' : 'Delete property')">
[matTooltip]="((resClasses.length > 0 || !propCanBeDeleted)? 'The property can\'t be deleted because it\'s used in a class' : 'Delete property')">
<button mat-button [disabled]="resClasses.length > 0" class="delete"
(click)="deleteResourceProperty.emit({iri: propDef.id, label: propDef.label})">
<mat-icon>delete</mat-icon>
Expand Down
Expand Up @@ -2,7 +2,7 @@ import { OverlayContainer } from '@angular/cdk/overlay';
import { HarnessLoader } from '@angular/cdk/testing';
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
import { Component, DebugElement, ViewChild } from '@angular/core';
import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { MatButtonModule } from '@angular/material/button';
import { MatDialogModule, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
import { MatDialogHarness } from '@angular/material/dialog/testing';
Expand All @@ -12,8 +12,17 @@ import { MatSnackBarModule } from '@angular/material/snack-bar';
import { MatTooltipModule } from '@angular/material/tooltip';
import { By } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { Constants, IHasProperty, ListNodeInfo, MockOntology, ReadOntology, ResourcePropertyDefinitionWithAllLanguages } from '@dasch-swiss/dsp-js';
import { DspActionModule } from '@dasch-swiss/dsp-ui';
import {
CanDoResponse,
Constants,
IHasProperty,
ListNodeInfo,
MockOntology,
OntologiesEndpointV2,
ReadOntology,
ResourcePropertyDefinitionWithAllLanguages
} from '@dasch-swiss/dsp-js';
import { DspActionModule, DspApiConnectionToken } from '@dasch-swiss/dsp-ui';
import { of } from 'rxjs';
import { CacheService } from 'src/app/main/cache/cache.service';
import { DialogHeaderComponent } from 'src/app/main/dialog/dialog-header/dialog-header.component';
Expand Down Expand Up @@ -170,6 +179,12 @@ describe('PropertyInfoComponent', () => {

const cacheServiceSpy = jasmine.createSpyObj('CacheService', ['get']);

const ontologyEndpointSpyObj = {
v2: {
onto: jasmine.createSpyObj('onto', ['canDeleteResourceProperty'])
}
};

TestBed.configureTestingModule({
declarations: [
DialogComponent,
Expand All @@ -191,6 +206,10 @@ describe('PropertyInfoComponent', () => {
MatTooltipModule
],
providers: [
{
provide: DspApiConnectionToken,
useValue: ontologyEndpointSpyObj
},
{
provide: CacheService,
useValue: cacheServiceSpy
Expand All @@ -208,6 +227,19 @@ describe('PropertyInfoComponent', () => {
.compileComponents();
}));

beforeEach(() => {
const dspConnSpy = TestBed.inject(DspApiConnectionToken);
(dspConnSpy.v2.onto as jasmine.SpyObj<OntologiesEndpointV2>).canDeleteResourceProperty.and.callFake(
() => {
const deleteResProp: CanDoResponse = {
'canDo': false
};

return of(deleteResProp);
}
);
});

beforeEach(() => {
simpleTextHostFixture = TestBed.createComponent(SimpleTextHostComponent);
simpleTextHostComponent = simpleTextHostFixture.componentInstance;
Expand Down