diff --git a/src/app/project/ontology/ontology.component.scss b/src/app/project/ontology/ontology.component.scss
index fe740f0cd6..b385f4c099 100644
--- a/src/app/project/ontology/ontology.component.scss
+++ b/src/app/project/ontology/ontology.component.scss
@@ -27,7 +27,6 @@ $width: 340px;
max-width: 1280px;
min-height: calc(100vh - #{$header-height} - #{$tab-bar-margin} - 100px);
border: 1px dotted $primary_200;
- background: $primary_200;
position: relative;
margin: 0 auto 60px auto;
}
@@ -45,8 +44,18 @@ $width: 340px;
height: $sub-header-height;
}
+ .ontology-editor-sidenav {
+ width: 160px;
+
+ button {
+ width: 100%;
+ text-align: left;
+ }
+ }
+
.ontology-editor-canvas {
min-height: calc(100vh - #{$sub-header-height} - #{$header-height} - #{$tab-bar-margin} - 100px);
+ border-right: 1px solid rgba(0, 0, 0, 0.12);
.ontology-editor-grid {
display: grid;
@@ -54,6 +63,9 @@ $width: 340px;
grid-template-columns: repeat(auto-fill, minmax($width, 1fr));
grid-gap: 6px;
}
+ .ontology-editor-list {
+ margin: 16px;
+ }
}
}
@@ -68,7 +80,7 @@ $width: 340px;
background-color: #fff;
.resource-class-header {
- margin: -12px -12px 12px -12px;
+ margin: -12px -12px 0 -12px;
width: calc(100% + 24px);
min-height: 48px !important;
height: 48px;
@@ -98,47 +110,15 @@ $width: 340px;
.switch-view-label {
margin-right: 16px;
}
-
- button.active {
- background-color: $black-12-opacity;
- }
}
-/*
-.ontology-container {
- // display: flex;
- // flex-direction: row;
- width: 100%;
-
- .ontology-editor {
- overflow: hidden;
- }
-
- .ontology-default-elements {
- width: 220px;
- // TODO: fix height
- height: 100vh;
- position: fixed;
- right: 0;
- top: 0;
- padding: 72px 6px 6px;
- background: rgb(255, 255, 255);
-
- .list-item {
- border: 1px solid black;
- padding: 6px;
- margin: 6px;
- }
- ul {
- padding-inline-start: 0;
+.active {
+ background-color: $black-12-opacity;
+}
- li {
- list-style-type: none;
- }
- }
- }
+.note {
+ padding: 2px;
}
- */
.add-resource-class {
position: absolute;
@@ -160,6 +140,5 @@ $width: 340px;
}
button.space-reducer {
- // max-height: 32px;
margin: 0;
}
diff --git a/src/app/project/ontology/ontology.component.ts b/src/app/project/ontology/ontology.component.ts
index 92241996cd..11abd9f27e 100644
--- a/src/app/project/ontology/ontology.component.ts
+++ b/src/app/project/ontology/ontology.component.ts
@@ -15,12 +15,13 @@ import {
OntologiesMetadata,
OntologyMetadata,
ProjectResponse,
+ PropertyDefinition,
ReadOntology,
ReadProject,
ResourceClassDefinition,
UpdateOntology
} from '@dasch-swiss/dsp-js';
-import { DspApiConnectionToken, Session, SessionService } from '@dasch-swiss/dsp-ui';
+import { DspApiConnectionToken, Session, SessionService, SortingService } from '@dasch-swiss/dsp-ui';
import { CacheService } from 'src/app/main/cache/cache.service';
import { DialogComponent } from 'src/app/main/dialog/dialog.component';
import { ErrorHandlerService } from 'src/app/main/error/error-handler.service';
@@ -67,6 +68,8 @@ export class OntologyComponent implements OnInit {
ontoClasses: ClassDefinition[];
+ ontoProperties: PropertyDefinition[];
+
// selected ontology id
ontologyIri: string = undefined;
@@ -74,7 +77,7 @@ export class OntologyComponent implements OnInit {
ontologyForm: FormGroup;
// display resource classes as grid or as graph
- view: 'grid' | 'graph' = 'grid';
+ view: 'classes' | 'properties' | 'graph' = 'classes';
// i18n setup
itemPluralMapping = {
@@ -105,6 +108,7 @@ export class OntologyComponent implements OnInit {
private _route: ActivatedRoute,
private _router: Router,
private _session: SessionService,
+ private _sortingService: SortingService,
private _titleService: Title
) {
@@ -113,10 +117,19 @@ export class OntologyComponent implements OnInit {
this.projectcode = params.get('shortcode');
});
- // get ontology iri from route
- if (this._route.snapshot && this._route.snapshot.params.id) {
- this.ontologyIri = decodeURIComponent(this._route.snapshot.params.id);
- // set the page title in case of only one project ontology
+ if (this._route.snapshot) {
+ // get ontology iri from route
+ if (this._route.snapshot.params.id) {
+ this.ontologyIri = decodeURIComponent(this._route.snapshot.params.id);
+ }
+ // get view from route: classes, properties or graph
+ this.view = (this._route.snapshot.params.view ? this._route.snapshot.params.view : 'classes');
+ }
+
+ //
+
+ // set the page title
+ if (this.ontologyIri) {
this._titleService.setTitle('Project ' + this.projectcode + ' | Data model');
} else {
// set the page title in case of more than one existing project ontologies
@@ -217,7 +230,7 @@ export class OntologyComponent implements OnInit {
// because there will be no form to select ontlogy
if (response.ontologies.length === 1) {
// open this ontology
- this.openOntologyRoute(response.ontologies[0].id);
+ this.openOntologyRoute(response.ontologies[0].id, this.view);
this.ontologyIri = response.ontologies[0].id;
}
loadAndCache();
@@ -246,10 +259,14 @@ export class OntologyComponent implements OnInit {
}
- // open ontology route by iri
- openOntologyRoute(id: string) {
- this.loadOntology = true;
- const goto = 'project/' + this.projectcode + '/ontologies/' + encodeURIComponent(id);
+ /**
+ * Opens ontology route by iri
+ * @param id ontology id/iri
+ * @param view 'classes' | 'properties' | ' graph'
+ */
+ openOntologyRoute(id: string, view: 'classes' | 'properties' | 'graph' = 'classes') {
+ this.view = view;
+ const goto = 'project/' + this.projectcode + '/ontologies/' + encodeURIComponent(id) + '/' + view;
this._router.navigateByUrl(goto, { skipLocationChange: false });
}
@@ -274,10 +291,24 @@ export class OntologyComponent implements OnInit {
for (const c of classKeys) {
const splittedSubClass = this.ontology.classes[c].subClassOf[0].split('#');
- if (splittedSubClass[0] !== Constants.StandoffOntology && splittedSubClass[1] !== 'StandoffTag' && splittedSubClass[1] !== 'StandoffLinkTag') {
+ if (splittedSubClass[0] !== Constants.StandoffOntology && splittedSubClass[1] !== 'StandoffTag' && splittedSubClass[1] !== 'StandoffLinkTag' && splittedSubClass[1] !== 'StandoffEventTag') {
this.ontoClasses.push(this.ontology.classes[c]);
}
}
+ this.ontoClasses = this._sortingService.keySortByAlphabetical(this.ontoClasses, 'label');
+
+ // grab the onto properties information to display
+ this.ontoProperties = [];
+ const propKeys: string[] = Object.keys(response.properties);
+ // create list of resource classes without standoff classes
+ for (const p of propKeys) {
+ const standoff = (this.ontology.properties[p].subjectType ? this.ontology.properties[p].subjectType.includes('Standoff') : false);
+ if (this.ontology.properties[p].objectType !== Constants.LinkValue && !standoff) {
+ this.ontoProperties.push(this.ontology.properties[p]);
+ }
+ }
+
+ this.ontoProperties = this._sortingService.keySortByAlphabetical(this.ontoProperties, 'label');
this.loadOntology = false;
}
@@ -294,7 +325,7 @@ export class OntologyComponent implements OnInit {
this.ontology = undefined;
this.ontoClasses = [];
- this.openOntologyRoute(id);
+ this.openOntologyRoute(id, this.view);
this.getOntology(id);
}
@@ -478,14 +509,6 @@ export class OntologyComponent implements OnInit {
});
}
- /**
- *
- * @param view 'grid' | ' graph'
- */
- toggleView(view: 'grid' | 'graph') {
- this.view = view;
- }
-
setCache() {
// set cache for current ontology
this._cache.set('currentOntology', this.ontology);
diff --git a/src/app/project/ontology/property-info/property-info.component.html b/src/app/project/ontology/property-info/property-info.component.html
index c5d1168f6a..a26e046820 100644
--- a/src/app/project/ontology/property-info/property-info.component.html
+++ b/src/app/project/ontology/property-info/property-info.component.html
@@ -1,5 +1,5 @@
- =0" mat-list-icon class="order additional-info">{{propCard.guiOrder}})
+ =0" mat-list-icon class="order additional-info">{{propCard.guiOrder}})
@@ -17,7 +17,25 @@
- {{propInfo.multiple ? 'check_box' : 'check_box_outline_blank' }} multiple
- {{propInfo.required ? 'check_box' : 'check_box_outline_blank' }} required
+
+
+ {{propInfo.multiple ? 'check_box' : 'check_box_outline_blank' }} multiple
+ {{propInfo.required ? 'check_box' : 'check_box_outline_blank' }} required
+
+
+
+
+ Property is used in:
+
+
+ {{c.label}}
+ ,
+
+
+
+ This property is not used in a class
+
+
+
diff --git a/src/app/project/ontology/property-info/property-info.component.scss b/src/app/project/ontology/property-info/property-info.component.scss
index 29793d34ca..160e1defdd 100644
--- a/src/app/project/ontology/property-info/property-info.component.scss
+++ b/src/app/project/ontology/property-info/property-info.component.scss
@@ -3,6 +3,10 @@
.mat-list-item {
height: 56px !important;
+ margin: 4px 0;
+ &:hover {
+ background-color: $black-12-opacity;
+ }
}
.additional-info {
@@ -35,3 +39,7 @@
position: relative;
}
}
+
+.not-used {
+ color: $warn;
+}
diff --git a/src/app/project/ontology/property-info/property-info.component.ts b/src/app/project/ontology/property-info/property-info.component.ts
index 7a7f2479b4..3af7aac457 100644
--- a/src/app/project/ontology/property-info/property-info.component.ts
+++ b/src/app/project/ontology/property-info/property-info.component.ts
@@ -2,12 +2,11 @@ import { AfterContentInit, Component, Input, OnInit } from '@angular/core';
import { MatIconRegistry } from '@angular/material/icon';
import { DomSanitizer } from '@angular/platform-browser';
import {
- ApiResponseData,
Constants,
IHasProperty,
ListNodeInfo,
- ListsResponse,
ReadOntology,
+ ResourceClassDefinitionWithAllLanguages,
ResourcePropertyDefinitionWithAllLanguages
} from '@dasch-swiss/dsp-js';
import { CacheService } from 'src/app/main/cache/cache.service';
@@ -23,7 +22,7 @@ export class PropertyInfoComponent implements OnInit, AfterContentInit {
@Input() propDef: ResourcePropertyDefinitionWithAllLanguages;
- @Input() propCard: IHasProperty;
+ @Input() propCard?: IHasProperty;
@Input() projectcode: string;
@@ -36,6 +35,9 @@ export class PropertyInfoComponent implements OnInit, AfterContentInit {
propAttribute: string;
+ // list of resource classes where the property is used
+ resClasses: ResourceClassDefinitionWithAllLanguages[] = [];
+
constructor(
private _cache: CacheService,
private _domSanitizer: DomSanitizer,
@@ -55,23 +57,26 @@ export class PropertyInfoComponent implements OnInit, AfterContentInit {
ngOnInit(): void {
// convert cardinality from js-lib convention to app convention
- switch (this.propCard.cardinality) {
- case 0:
- this.propInfo.multiple = false;
- this.propInfo.required = true;
- break;
- case 1:
- this.propInfo.multiple = false;
- this.propInfo.required = false;
- break;
- case 2:
- this.propInfo.multiple = true;
- this.propInfo.required = false;
- break;
- case 3:
- this.propInfo.multiple = true;
- this.propInfo.required = true;
- break;
+ // if cardinality is defined; only in resource class view
+ if (this.propCard) {
+ switch (this.propCard.cardinality) {
+ case 0:
+ this.propInfo.multiple = false;
+ this.propInfo.required = true;
+ break;
+ case 1:
+ this.propInfo.multiple = false;
+ this.propInfo.required = false;
+ break;
+ case 2:
+ this.propInfo.multiple = true;
+ this.propInfo.required = false;
+ break;
+ case 3:
+ this.propInfo.multiple = true;
+ this.propInfo.required = true;
+ break;
+ }
}
// find gui ele from list of default property-types to set type value
@@ -130,6 +135,28 @@ export class PropertyInfoComponent implements OnInit, AfterContentInit {
);
}
+ // get all classes where the property is used
+ if (!this.propCard) {
+ this._cache.get('currentOntology').subscribe(
+ (ontology: ReadOntology) => {
+ const classes = ontology.getAllClassDefinitions();
+ for (const c of classes) {
+ if (c.propertiesList.find(i => i.propertyIndex === this.propDef.id)) {
+ this.resClasses.push(c as ResourceClassDefinitionWithAllLanguages);
+ }
+ // 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]);
+ // }
+ }
+ }
+ );
+
+
+
+ }
+
}
}