Skip to content

Commit b90fc70

Browse files
authored
feat(ontology): add properties to a class from other ontologies (DEV-689 / DEV-880) (#721)
* feat(ontology): add properties to a class from other ontologies (DEV-689) * refactor(ontology): clean up commented code * fix(ontology): resolve prop cardinality and cache issues * refactor(ontology): clean up code and styling * fix(ontology): disable drag and drop in case of subclass (DEV-880) * fix(ontology): display classes where a prop is used * refactor(ontology): remove link class on res class because of missing link
1 parent 1b7384f commit b90fc70

10 files changed

Lines changed: 246 additions & 127 deletions

‎src/app/project/ontology/ontology.component.html‎

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -179,29 +179,23 @@ <h2 class="mat-title">
179179
<mat-sidenav-content class="ontology-editor-canvas drag-drop-stop">
180180
<div class="ontology-editor-grid classes" *ngIf="view === 'classes'">
181181
<!-- list of resource classes -->
182-
<app-resource-class-info *ngFor="let resClass of ontoClasses"
183-
[resourceClass]="resClass"
184-
[projectCode]="projectCode"
185-
[projectStatus]="project.status"
186-
[ontoProperties]="ontoProperties"
187-
[expanded]="expandClasses"
188-
[(lastModificationDate)]="lastModificationDate"
182+
<app-resource-class-info *ngFor="let resClass of ontoClasses" [resourceClass]="resClass"
183+
[projectCode]="projectCode" [projectStatus]="project.status" [ontologies]="ontologies"
184+
[expanded]="expandClasses" [(lastModificationDate)]="lastModificationDate"
189185
(editResourceClass)="openResourceClassForm('editResourceClass', $event)"
190186
(deleteResourceClass)="delete('ResourceClass', $event)"
191187
(updateCardinality)="initOntology($event)">
192188
</app-resource-class-info>
193189
</div>
194190
<div class="ontology-editor-list properties" *ngIf="view === 'properties'">
195-
<!-- list of resource properties -->
196-
<mat-list>
197-
<mat-list-item class="property" *ngFor="let prop of ontoProperties; let odd = odd" [class.odd]="odd">
191+
<!-- list of properties of current ontology -->
192+
<mat-list class="without-padding">
193+
<mat-list-item class="property" *ngFor="let prop of ontoProperties.properties; let odd = odd"
194+
[class.odd]="odd">
198195
<!-- display only properties with guiOrder and if they exist in list of properties;
199-
objectType is not a linkValue (otherwise we have the property twice) -->
200-
<app-property-info
201-
[propDef]="ontology?.properties[prop.id]"
202-
[projectCode]="projectCode"
203-
[projectStatus]="project.status"
204-
[(lastModificationDate)]="lastModificationDate"
196+
if objectType is a linkValue hide it (otherwise we have the property twice) -->
197+
<app-property-info [propDef]="ontology?.properties[prop.id]" [projectCode]="projectCode"
198+
[projectStatus]="project.status" [(lastModificationDate)]="lastModificationDate"
205199
(editResourceProperty)="openPropertyForm('editProperty', $event)"
206200
(deleteResourceProperty)="delete('Property', $event)">
207201
</app-property-info>

‎src/app/project/ontology/ontology.component.ts‎

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,11 @@ export interface CardinalityInfo {
4141
property: PropertyInfoObject;
4242
}
4343

44+
export interface OntologyProperties {
45+
ontology: string;
46+
properties: PropertyDefinition[];
47+
}
48+
4449
@Component({
4550
selector: 'app-ontology',
4651
templateUrl: './ontology.component.html',
@@ -92,7 +97,7 @@ export class OntologyComponent implements OnInit {
9297
expandClasses = true;
9398

9499
// all properties in the current ontology
95-
ontoProperties: PropertyDefinition[];
100+
ontoProperties: OntologyProperties;
96101

97102
// form to select ontology from list
98103
ontologyForm: FormGroup;
@@ -239,6 +244,7 @@ export class OntologyComponent implements OnInit {
239244
}
240245
if (response.ontologies.length === this.ontologies.length) {
241246
this.ontologies = this._sortingService.keySortByAlphabetical(this.ontologies, 'label');
247+
242248
this._cache.set('currentProjectOntologies', this.ontologies);
243249
this.setCache();
244250
}
@@ -289,19 +295,24 @@ export class OntologyComponent implements OnInit {
289295
}
290296

291297
initOntoProperties(allOntoProperties: PropertyDefinition[]) {
298+
292299
// reset the ontology properties
293-
this.ontoProperties = [];
300+
const listOfProperties = [];
294301

295302
// display only the properties which are not a subjectType of Standoff
296303
allOntoProperties.forEach(resProp => {
297304
const standoff = (resProp.subjectType ? resProp.subjectType.includes('Standoff') : false);
298305
if (resProp.objectType !== Constants.LinkValue && !standoff) {
299-
this.ontoProperties.push(resProp);
306+
listOfProperties.push(resProp);
300307
}
301308
});
309+
302310
// sort properties by label
303-
// --> TODO: add sort functionallity to the gui
304-
this.ontoProperties = this._sortingService.keySortByAlphabetical(this.ontoProperties, 'label');
311+
this.ontoProperties = {
312+
ontology: this.ontology.id,
313+
properties: this._sortingService.keySortByAlphabetical(listOfProperties, 'label')
314+
};
315+
305316
}
306317

307318
/**
@@ -341,7 +352,15 @@ export class OntologyComponent implements OnInit {
341352
resetOntologyView(ontology: ReadOntology) {
342353
this.ontology = ontology;
343354
this.lastModificationDate = this.ontology.lastModificationDate;
344-
this._cache.set('currentOntology', this.ontology);
355+
this._cache.set('currentOntology', ontology);
356+
357+
this._cache.get('currentProjectOntologies').subscribe(
358+
(ontologies: ReadOntology[]) => {
359+
// update current list of project ontologies
360+
ontologies[ontologies.findIndex(onto => onto.id === ontology.id)] = ontology;
361+
this._cache.set('currentProjectOntologies', ontologies);
362+
}
363+
);
345364

346365
// grab the onto class information to display
347366
this.initOntoClasses(ontology.getAllClassDefinitions());
@@ -457,6 +476,8 @@ export class OntologyComponent implements OnInit {
457476
);
458477

459478
dialogRef.afterClosed().subscribe(result => {
479+
// get the ontologies for this project
480+
this.initOntologiesList();
460481
// update the view of resource class or list of properties
461482
this.initOntology(this.ontologyIri);
462483
});

‎src/app/project/ontology/property-form/property-form.component.ts‎

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,6 @@ export class PropertyFormComponent implements OnInit {
330330
// reset value of guiAttr
331331
this.propertyForm.controls['guiAttr'].setValue(undefined);
332332

333-
334333
// set gui attribute value depending on gui element and existing property (edit mode)
335334
if (this.propertyInfo.propDef) {
336335
// the gui attribute can't be changed (at the moment?);
@@ -562,7 +561,6 @@ export class PropertyFormComponent implements OnInit {
562561

563562
this._dspApiConnection.v2.onto.addCardinalityToResourceClass(onto).subscribe(
564563
(res: ResourceClassDefinitionWithAllLanguages) => {
565-
566564
this.lastModificationDate = res.lastModificationDate;
567565
// close the dialog box
568566
this.loading = false;

‎src/app/project/ontology/property-info/property-info.component.html‎

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<div class="property-info" (mouseenter)="mouseEnter()" (mouseleave)="mouseLeave()">
1+
<div class="property-info" [class.standalone]="!propCard" (mouseenter)="mouseEnter()" (mouseleave)="mouseLeave()">
22

33
<div mat-line class="title" [class.with-line-break]="!propCard">
44
<span class="icon" *ngIf="propType" [matTooltip]="propType?.group + ': ' + propType?.label + ' (' + propDef.id.split('#')[1] + ')'"
@@ -23,7 +23,7 @@
2323
<span [matTooltip]="'id: ' + propDef.id" matTooltipPosition="above" matTooltipClass="wide-tooltip" class="mat-caption">
2424
{{propDef.id | split: '#':1}}
2525
</span>
26-
<span class="fill-remaining-space center">&nbsp;&middot;&nbsp;</span>
26+
<span class="fill-remaining-space center"></span>
2727
<!-- in case of res class: display cardinality -->
2828
<span *ngIf="propCard">
2929
<mat-icon class="multiple">{{propInfo.multiple ? 'check_box' : 'check_box_outline_blank' }}</mat-icon>
@@ -34,16 +34,16 @@
3434
<!-- in case of ontology property: display corresponding resource classes -->
3535
<span *ngIf="!propCard" class="white-space">
3636
<span *ngIf="resClasses.length; else notUsed">
37-
Property is used in:
38-
<!-- <span>{{ resClasses.join(", ") }}</span> -->
37+
<span class="mat-caption">&gt; Property is used in:</span>
3938
<span *ngFor="let c of resClasses; let last = last">
40-
<span [matTooltip]="c.comment" matTooltipPosition="above" class="link"
41-
(click)="clickedOnClass.emit(c)">{{c.label}}</span>
42-
<span *ngIf="!last">,&nbsp;</span>
39+
<span [matTooltip]="c.comment" matTooltipPosition="above"
40+
(click)="clickedOnClass.emit(c)">{{c.label}}</span><span *ngIf="!last">&nbsp;&middot;</span>
4341
</span>
4442
</span>
4543
<ng-template #notUsed>
46-
<span class="not-used">This property is not used in a class</span>
44+
<span class="mat-caption">&gt;
45+
<span class="not-used">This property is not used in a class.</span>
46+
</span>
4747
</ng-template>
4848
</span>
4949
</div>
@@ -77,8 +77,8 @@
7777
</button>
7878
</span>
7979
<span matTooltipPosition="above"
80-
[matTooltip]="((resClasses.length > 0) ? 'The property can\'t be deleted because it is used in a class' : 'Delete property')">
81-
<button mat-button [disabled]="resClasses.length > 0" class="delete"
80+
[matTooltip]="((!propCanBeDeleted) ? 'The property can\'t be deleted because it is used in a class' : 'Delete property')">
81+
<button mat-button [disabled]="!propCanBeDeleted" class="delete"
8282
(click)="deleteResourceProperty.emit({iri: propDef.id, label: propDef.label})">
8383
<mat-icon>delete</mat-icon>
8484
</button>

‎src/app/project/ontology/property-info/property-info.component.scss‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44
width: 100%;
55
}
66

7+
.property-info.standalone {
8+
padding: 16px;
9+
}
10+
711
.additional-info {
812
color: $primary_700;
913
}
@@ -44,6 +48,7 @@
4448

4549
.not-used {
4650
color: $warn;
51+
font-size: 12px;
4752
}
4853

4954
.type {

‎src/app/project/ontology/property-info/property-info.component.ts‎

Lines changed: 30 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,12 @@ export class Property {
5555
}
5656
}
5757

58+
export interface ShortInfo {
59+
id: string;
60+
label: string;
61+
comment: string;
62+
}
63+
5864
@Component({
5965
selector: 'app-property-info',
6066
templateUrl: './property-info.component.html',
@@ -103,8 +109,8 @@ export class PropertyInfoComponent implements OnChanges, AfterContentInit {
103109
@Output() deleteResourceProperty: EventEmitter<DefaultClass> = new EventEmitter<DefaultClass>();
104110
@Output() removePropertyFromClass: EventEmitter<DefaultClass> = new EventEmitter<DefaultClass>();
105111

106-
// submit res class iri ot open res class
107-
@Output() clickedOnClass: EventEmitter<ResourceClassDefinitionWithAllLanguages> = new EventEmitter<ResourceClassDefinitionWithAllLanguages>();
112+
// submit res class iri to open res class (not yet implemented)
113+
@Output() clickedOnClass: EventEmitter<ShortInfo> = new EventEmitter<ShortInfo>();
108114

109115
propInfo: Property = new Property();
110116

@@ -123,7 +129,7 @@ export class PropertyInfoComponent implements OnChanges, AfterContentInit {
123129
defaultProperties: PropertyCategory[] = DefaultProperties.data;
124130

125131
// list of resource classes where the property is used
126-
resClasses: ResourceClassDefinitionWithAllLanguages[] = [];
132+
resClasses: ShortInfo[] = [];
127133

128134
// disable edit property button in case the property type is not supported in DSP-APP
129135
disableEditProperty = false;
@@ -140,7 +146,6 @@ export class PropertyInfoComponent implements OnChanges, AfterContentInit {
140146
this._cache.get('currentOntology').subscribe(
141147
(response: ReadOntology) => {
142148
this.ontology = response;
143-
144149
}
145150
);
146151
}
@@ -180,13 +185,11 @@ export class PropertyInfoComponent implements OnChanges, AfterContentInit {
180185
}
181186

182187
// get the default property type for this property
183-
// if (this.propDef.guiElement) {
184188
this._ontoService.getDefaultPropType(this.propDef).subscribe(
185189
(prop: DefaultProperty) => {
186190
this.propType = prop;
187191
}
188192
);
189-
// }
190193

191194
}
192195

@@ -234,19 +237,25 @@ export class PropertyInfoComponent implements OnChanges, AfterContentInit {
234237

235238
// get all classes where the property is used
236239
if (!this.propCard) {
237-
238-
const classes = this.ontology.getAllClassDefinitions();
239-
for (const c of classes) {
240-
if (c.propertiesList.find(i => i.propertyIndex === this.propDef.id)) {
241-
this.resClasses.push(c as ResourceClassDefinitionWithAllLanguages);
240+
this.resClasses = [];
241+
this._cache.get('currentProjectOntologies').subscribe(
242+
(ontologies: ReadOntology[]) => {
243+
ontologies.forEach(onto => {
244+
const classes = onto.getAllClassDefinitions();
245+
classes.forEach(resClass => {
246+
if (resClass.propertiesList.find(prop => prop.propertyIndex === this.propDef.id)) {
247+
// build own resClass object with id, label and comment
248+
const propOfClass: ShortInfo = {
249+
id: resClass.id,
250+
label: resClass.label,
251+
comment: onto.label + (resClass.comment ? ': ' + resClass.comment : '')
252+
};
253+
this.resClasses.push(propOfClass);
254+
}
255+
});
256+
});
242257
}
243-
// const splittedSubClass = ontology.classes[c].subClassOf[0].split('#');
244-
245-
// if (splittedSubClass[0] !== Constants.StandoffOntology && splittedSubClass[1] !== 'StandoffTag' && splittedSubClass[1] !== 'StandoffLinkTag') {
246-
// this.ontoClasses.push(this.ontology.classes[c]);
247-
// }
248-
}
249-
258+
);
250259
}
251260
}
252261

@@ -290,10 +299,10 @@ export class PropertyInfoComponent implements OnChanges, AfterContentInit {
290299
this._dspApiConnection.v2.onto.canDeleteCardinalityFromResourceClass(onto).subscribe(
291300
(canDoRes: CanDoResponse) => {
292301
this.propCanBeDeleted = canDoRes.canDo;
293-
},
294-
(error: ApiResponseError) => {
295-
this._errorHandler.showMessage(error);
296302
}
303+
// since this request runs on mouseover, it can always
304+
// ends in a EditConflictException because of a wrong lastModificationDate.
305+
// so, it doesn't make sense to handle the error here and to open the snackbar
297306
);
298307
}
299308

‎src/app/project/ontology/resource-class-info/resource-class-info.component.html‎

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<mat-card-header class="resource-class-header" cdkDragHandle>
44
<!-- TODO: the res class icon is missing in ClassDefinition from DSP-JS-Lib; DSP-JS has to be updated first (s. DSP-1366) -->
55
<!-- <mat-icon mat-card-avatar>{{resourceClass.icon}}</mat-icon> -->
6-
<mat-card-title [matTooltip]="resourceClass.comment + ' (' + resourceClass.id.split('#')[1] + ')'" matTooltipPosition="above">
6+
<mat-card-title [matTooltip]="(resourceClass.comment ? resourceClass.comment : '')" matTooltipPosition="above">
77
{{resourceClass.label | appTruncate: 24}}
88
</mat-card-title>
99
<mat-card-subtitle>
@@ -43,13 +43,14 @@
4343
</mat-menu>
4444
</mat-card-header>
4545
<!-- resource class card content with list of properties -->
46+
4647
<mat-card-content *ngIf="expanded">
4748
<mat-list cdkDropList class="resource-class-properties" (cdkDropListDropped)="drop($event)"
4849
*ngIf="propsToDisplay.length; else noProperties">
49-
<div cdkDrag [cdkDragDisabled]="!ontology.lastModificationDate"
50+
<div cdkDrag [cdkDragDisabled]="!ontology.lastModificationDate || !cardinalityUpdateEnabled"
5051
*ngFor="let prop of propsToDisplay; let i = index;">
5152
<div class="drag-n-drop-placeholder" *cdkDragPlaceholder></div>
52-
<mat-list-item class="property">
53+
<mat-list-item class="property" [disabled]="loadProperty">
5354
<span cdkDragHandle mat-list-icon class="list-icon gui-order">
5455
<span [class.hide-on-hover]="cardinalityUpdateEnabled && lastModificationDate">{{i + 1}})</span>
5556
<span *ngIf="lastModificationDate && cardinalityUpdateEnabled"
@@ -59,8 +60,12 @@
5960
</span>
6061
<!-- display only properties if they exist in list of properties;
6162
objectType is not a linkValue (otherwise we have the property twice) -->
62-
<app-property-info class="property-info" [propDef]="ontology?.properties[prop.propertyIndex]"
63-
[propCard]="propsToDisplay[i]" [projectCode]="projectCode" [projectStatus]="projectStatus" [resourceIri]="resourceClass.id"
63+
<app-property-info class="property-info"
64+
[propDef]="propsToDisplay[i].propDef"
65+
[propCard]="propsToDisplay[i]"
66+
[projectCode]="projectCode"
67+
[projectStatus]="projectStatus"
68+
[resourceIri]="resourceClass.id"
6469
[(lastModificationDate)]="lastModificationDate"
6570
(removePropertyFromClass)="removeProperty($event)">
6671
</app-property-info>
@@ -83,13 +88,12 @@
8388

8489
<mat-menu #addPropertyMenu="matMenu" xPosition="after">
8590
<button mat-menu-item [matMenuTriggerFor]="newFromPropType">Create new from type</button>
86-
<button mat-menu-item [matMenuTriggerFor]="addExistingProp" [disabled]="!ontoProperties.length">Add existing property</button>
91+
<button mat-menu-item [matMenuTriggerFor]="addExistingProp">Add existing property</button>
8792
</mat-menu>
8893
<mat-menu #newFromPropType="matMenu">
8994
<ng-container *ngFor="let type of defaultProperties">
9095
<button mat-menu-item [matMenuTriggerFor]="sub_menu">{{type.group}}</button>
9196
<mat-menu #sub_menu="matMenu" class="default-nested-sub-menu">
92-
<!-- <button *ngFor="let subItem of my_menu[mainItem]" mat-menu-item>{{ subItem }}</button> -->
9397
<button mat-menu-item *ngFor="let ele of type.elements" [value]="ele"
9498
[matTooltip]="ele.description" matTooltipPosition="after"
9599
(click)="addNewProperty(ele)">
@@ -99,11 +103,16 @@
99103
</ng-container>
100104
</mat-menu>
101105
<mat-menu #addExistingProp="matMenu" class="default-nested-sub-menu">
102-
<button mat-menu-item *ngFor="let prop of existingProperties"
103-
[matTooltip]="prop.propDef.comment" matTooltipPosition="after"
104-
(click)="addExistingProperty(prop.propDef)">
105-
<mat-icon>{{prop.propType?.icon}}</mat-icon> {{prop.propDef.label}}
106-
</button>
106+
<ng-container *ngFor="let onto of existingProperties">
107+
<button mat-menu-item [disabled]="!onto.properties.length" [matMenuTriggerFor]="sub_menu">{{ onto.ontologyLabel }}</button>
108+
<mat-menu #sub_menu="matMenu" class="default-nested-sub-menu">
109+
<button mat-menu-item *ngFor="let prop of onto.properties" [matTooltip]="prop.propDef.comment" matTooltipPosition="after"
110+
(click)="addExistingProperty(prop)">
111+
<mat-icon>{{prop.propType?.icon}}</mat-icon> {{prop.propDef.label}}
112+
</button>
113+
</mat-menu>
114+
</ng-container>
115+
107116
</mat-menu>
108117
</mat-card-content>
109118
</mat-card>

0 commit comments

Comments
 (0)