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): add properties to a class from other ontologies (DEV-689 / DEV-880) #721

Merged
merged 9 commits into from May 4, 2022
29 changes: 11 additions & 18 deletions src/app/project/ontology/ontology.component.html
Expand Up @@ -58,8 +58,7 @@ <h2 class="mat-title">
<mat-toolbar class="ontology-editor-header">
<mat-toolbar-row>
<span class="ontology-info">
<h3 class="mat-title space-reducer"
[matTooltip]="ontology.comment ? ontology.comment : ontology.id"
<h3 class="mat-title space-reducer" [matTooltip]="ontology.comment ? ontology.comment : ontology.id"
matTooltipPosition="above">
{{ontology?.label}}
</h3>
Expand Down Expand Up @@ -179,29 +178,23 @@ <h2 class="mat-title">
<mat-sidenav-content class="ontology-editor-canvas drag-drop-stop">
<div class="ontology-editor-grid classes" *ngIf="view === 'classes'">
<!-- list of resource classes -->
<app-resource-class-info *ngFor="let resClass of ontoClasses"
[resourceClass]="resClass"
[projectCode]="projectCode"
[projectStatus]="project.status"
[ontoProperties]="ontoProperties"
[expanded]="expandClasses"
[(lastModificationDate)]="lastModificationDate"
<app-resource-class-info *ngFor="let resClass of ontoClasses" [resourceClass]="resClass"
[projectCode]="projectCode" [projectStatus]="project.status" [ontologies]="ontologies"
[expanded]="expandClasses" [(lastModificationDate)]="lastModificationDate"
(editResourceClass)="openResourceClassForm('editResourceClass', $event)"
(deleteResourceClass)="delete('ResourceClass', $event)"
(updateCardinality)="initOntology($event)">
</app-resource-class-info>
</div>
<div class="ontology-editor-list properties" *ngIf="view === 'properties'">
<!-- list of resource properties -->
<mat-list>
<mat-list-item class="property" *ngFor="let prop of ontoProperties; let odd = odd" [class.odd]="odd">
<!-- list of properties of current ontology -->
<mat-list class="without-padding">
<mat-list-item class="property" *ngFor="let prop of ontoProperties.properties; let odd = odd"
[class.odd]="odd">
<!-- display only properties with guiOrder and if they exist in list of properties;
objectType is not a linkValue (otherwise we have the property twice) -->
<app-property-info
[propDef]="ontology?.properties[prop.id]"
[projectCode]="projectCode"
[projectStatus]="project.status"
[(lastModificationDate)]="lastModificationDate"
if objectType is a linkValue hide it (otherwise we have the property twice) -->
<app-property-info [propDef]="ontology?.properties[prop.id]" [projectCode]="projectCode"
[projectStatus]="project.status" [(lastModificationDate)]="lastModificationDate"
(editResourceProperty)="openPropertyForm('editProperty', $event)"
(deleteResourceProperty)="delete('Property', $event)">
</app-property-info>
Expand Down
33 changes: 27 additions & 6 deletions src/app/project/ontology/ontology.component.ts
Expand Up @@ -41,6 +41,11 @@ export interface CardinalityInfo {
property: PropertyInfoObject;
}

export interface OntologyProperties {
ontology: string;
properties: PropertyDefinition[];
}

@Component({
selector: 'app-ontology',
templateUrl: './ontology.component.html',
Expand Down Expand Up @@ -92,7 +97,7 @@ export class OntologyComponent implements OnInit {
expandClasses = true;

// all properties in the current ontology
ontoProperties: PropertyDefinition[];
ontoProperties: OntologyProperties;

// form to select ontology from list
ontologyForm: FormGroup;
Expand Down Expand Up @@ -239,6 +244,7 @@ export class OntologyComponent implements OnInit {
}
if (response.ontologies.length === this.ontologies.length) {
this.ontologies = this._sortingService.keySortByAlphabetical(this.ontologies, 'label');

this._cache.set('currentProjectOntologies', this.ontologies);
this.setCache();
}
Expand Down Expand Up @@ -289,19 +295,24 @@ export class OntologyComponent implements OnInit {
}

initOntoProperties(allOntoProperties: PropertyDefinition[]) {

// reset the ontology properties
this.ontoProperties = [];
const listOfProperties = [];

// display only the properties which are not a subjectType of Standoff
allOntoProperties.forEach(resProp => {
const standoff = (resProp.subjectType ? resProp.subjectType.includes('Standoff') : false);
if (resProp.objectType !== Constants.LinkValue && !standoff) {
this.ontoProperties.push(resProp);
listOfProperties.push(resProp);
}
});

// sort properties by label
// --> TODO: add sort functionallity to the gui
this.ontoProperties = this._sortingService.keySortByAlphabetical(this.ontoProperties, 'label');
this.ontoProperties = {
ontology: this.ontology.id,
properties: this._sortingService.keySortByAlphabetical(listOfProperties, 'label')
};

}

/**
Expand Down Expand Up @@ -341,7 +352,15 @@ export class OntologyComponent implements OnInit {
resetOntologyView(ontology: ReadOntology) {
this.ontology = ontology;
this.lastModificationDate = this.ontology.lastModificationDate;
this._cache.set('currentOntology', this.ontology);
this._cache.set('currentOntology', ontology);

this._cache.get('currentProjectOntologies').subscribe(
(ontologies: ReadOntology[]) => {
// update current list of project ontologies
ontologies[ontologies.findIndex(onto => onto.id === ontology.id)] = ontology;
this._cache.set('currentProjectOntologies', ontologies);
}
);

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

dialogRef.afterClosed().subscribe(result => {
// get the ontologies for this project
this.initOntologiesList();
// update the view of resource class or list of properties
this.initOntology(this.ontologyIri);
});
Expand Down
Expand Up @@ -330,7 +330,6 @@ export class PropertyFormComponent implements OnInit {
// reset value of guiAttr
this.propertyForm.controls['guiAttr'].setValue(undefined);


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

this._dspApiConnection.v2.onto.addCardinalityToResourceClass(onto).subscribe(
(res: ResourceClassDefinitionWithAllLanguages) => {

this.lastModificationDate = res.lastModificationDate;
// close the dialog box
this.loading = false;
Expand Down
20 changes: 10 additions & 10 deletions src/app/project/ontology/property-info/property-info.component.html
@@ -1,4 +1,4 @@
<div class="property-info" (mouseenter)="mouseEnter()" (mouseleave)="mouseLeave()">
<div class="property-info" [class.standalone]="!propCard" (mouseenter)="mouseEnter()" (mouseleave)="mouseLeave()">

<div mat-line class="title" [class.with-line-break]="!propCard">
<span class="icon" *ngIf="propType" [matTooltip]="propType?.group + ': ' + propType?.label + ' (' + propDef.id.split('#')[1] + ')'"
Expand All @@ -23,7 +23,7 @@
<span [matTooltip]="'id: ' + propDef.id" matTooltipPosition="above" matTooltipClass="wide-tooltip" class="mat-caption">
{{propDef.id | split: '#':1}}
</span>
<span class="fill-remaining-space center">&nbsp;&middot;&nbsp;</span>
<span class="fill-remaining-space center"></span>
<!-- in case of res class: display cardinality -->
<span *ngIf="propCard">
<mat-icon class="multiple">{{propInfo.multiple ? 'check_box' : 'check_box_outline_blank' }}</mat-icon>
Expand All @@ -34,16 +34,16 @@
<!-- in case of ontology property: display corresponding resource classes -->
<span *ngIf="!propCard" class="white-space">
<span *ngIf="resClasses.length; else notUsed">
Property is used in:
<!-- <span>{{ resClasses.join(", ") }}</span> -->
<span class="mat-caption">&gt; Property is used in:</span>
<span *ngFor="let c of resClasses; let last = last">
<span [matTooltip]="c.comment" matTooltipPosition="above" class="link"
(click)="clickedOnClass.emit(c)">{{c.label}}</span>
<span *ngIf="!last">,&nbsp;</span>
<span [matTooltip]="c.comment" matTooltipPosition="above"
(click)="clickedOnClass.emit(c)">{{c.label}}</span><span *ngIf="!last">&nbsp;&middot;</span>
</span>
</span>
<ng-template #notUsed>
<span class="not-used">This property is not used in a class</span>
<span class="mat-caption">&gt;
<span class="not-used">This property is not used in a class.</span>
</span>
</ng-template>
</span>
</div>
Expand Down Expand Up @@ -77,8 +77,8 @@
</button>
</span>
<span matTooltipPosition="above"
[matTooltip]="((resClasses.length > 0) ? 'The property can\'t be deleted because it is used in a class' : 'Delete property')">
<button mat-button [disabled]="resClasses.length > 0" class="delete"
[matTooltip]="((!propCanBeDeleted) ? 'The property can\'t be deleted because it is used in a class' : 'Delete property')">
<button mat-button [disabled]="!propCanBeDeleted" class="delete"
(click)="deleteResourceProperty.emit({iri: propDef.id, label: propDef.label})">
<mat-icon>delete</mat-icon>
</button>
Expand Down
Expand Up @@ -4,6 +4,10 @@
width: 100%;
}

.property-info.standalone {
padding: 16px;
}

.additional-info {
color: $primary_700;
}
Expand Down Expand Up @@ -44,6 +48,7 @@

.not-used {
color: $warn;
font-size: 12px;
}

.type {
Expand Down
51 changes: 30 additions & 21 deletions src/app/project/ontology/property-info/property-info.component.ts
Expand Up @@ -55,6 +55,12 @@ export class Property {
}
}

export interface ShortInfo {
id: string;
label: string;
comment: string;
}

@Component({
selector: 'app-property-info',
templateUrl: './property-info.component.html',
Expand Down Expand Up @@ -103,8 +109,8 @@ export class PropertyInfoComponent implements OnChanges, AfterContentInit {
@Output() deleteResourceProperty: EventEmitter<DefaultClass> = new EventEmitter<DefaultClass>();
@Output() removePropertyFromClass: EventEmitter<DefaultClass> = new EventEmitter<DefaultClass>();

// submit res class iri ot open res class
@Output() clickedOnClass: EventEmitter<ResourceClassDefinitionWithAllLanguages> = new EventEmitter<ResourceClassDefinitionWithAllLanguages>();
// submit res class iri to open res class (not yet implemented)
@Output() clickedOnClass: EventEmitter<ShortInfo> = new EventEmitter<ShortInfo>();

propInfo: Property = new Property();

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

// list of resource classes where the property is used
resClasses: ResourceClassDefinitionWithAllLanguages[] = [];
resClasses: ShortInfo[] = [];

// disable edit property button in case the property type is not supported in DSP-APP
disableEditProperty = false;
Expand All @@ -140,7 +146,6 @@ export class PropertyInfoComponent implements OnChanges, AfterContentInit {
this._cache.get('currentOntology').subscribe(
(response: ReadOntology) => {
this.ontology = response;

}
);
}
Expand Down Expand Up @@ -180,13 +185,11 @@ export class PropertyInfoComponent implements OnChanges, AfterContentInit {
}

// get the default property type for this property
// if (this.propDef.guiElement) {
this._ontoService.getDefaultPropType(this.propDef).subscribe(
(prop: DefaultProperty) => {
this.propType = prop;
}
);
// }

}

Expand Down Expand Up @@ -234,19 +237,25 @@ export class PropertyInfoComponent implements OnChanges, AfterContentInit {

// get all classes where the property is used
if (!this.propCard) {

const classes = this.ontology.getAllClassDefinitions();
for (const c of classes) {
if (c.propertiesList.find(i => i.propertyIndex === this.propDef.id)) {
this.resClasses.push(c as ResourceClassDefinitionWithAllLanguages);
this.resClasses = [];
this._cache.get('currentProjectOntologies').subscribe(
(ontologies: ReadOntology[]) => {
ontologies.forEach(onto => {
const classes = onto.getAllClassDefinitions();
classes.forEach(resClass => {
if (resClass.propertiesList.find(prop => prop.propertyIndex === this.propDef.id)) {
// build own resClass object with id, label and comment
const propOfClass: ShortInfo = {
id: resClass.id,
label: resClass.label,
comment: onto.label + (resClass.comment ? ': ' + resClass.comment : '')
};
this.resClasses.push(propOfClass);
}
});
});
}
// const splittedSubClass = ontology.classes[c].subClassOf[0].split('#');

// if (splittedSubClass[0] !== Constants.StandoffOntology && splittedSubClass[1] !== 'StandoffTag' && splittedSubClass[1] !== 'StandoffLinkTag') {
// this.ontoClasses.push(this.ontology.classes[c]);
// }
}

);
}
}

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

Expand Down