Skip to content

Commit c838043

Browse files
authored
fix(ontology): support subproperty in ontology editor (DEV-332) (#643)
* fix(ontology): support subproperty in ontology editor (DEV-332) * refactor(ontology): delete console.log * fix(ontology): bug fix in part of prop * feat(ontology): add unsupported prop types to list of default * style(ontology): display hint in case of unsupported prop type * feat(ontology): function to get super and default prop * style(ontology): display hint in case of unsupported prop type * refactor(ontology): clean up code * feat(ontology): support subproperties (DEV-332) * chore(deps): bump js-lib to latest * refactor(ontology): clean up code * test(ontology): fix tests * refactor(ontology): clean up default props
1 parent 84c3c85 commit c838043

12 files changed

Lines changed: 338 additions & 272 deletions

‎package-lock.json‎

Lines changed: 72 additions & 140 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎package.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
"@angular/platform-browser-dynamic": "^12.2.14",
3434
"@angular/router": "^12.2.14",
3535
"@ckeditor/ckeditor5-angular": "^2.0.2",
36-
"@dasch-swiss/dsp-js": "^6.1.0",
36+
"@dasch-swiss/dsp-js": "^6.2.0",
3737
"@datadog/browser-rum": "^3.7.0",
3838
"@ngx-translate/core": "^12.1.2",
3939
"@ngx-translate/http-loader": "5.0.0",

‎src/app/project/ontology/default-data/default-properties.ts‎

Lines changed: 32 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,18 @@ export interface DefaultProperty {
3333
}
3434

3535
export class DefaultProperties {
36+
37+
public static unsupported: DefaultProperty = {
38+
icon: 'warning_amber',
39+
label: 'Unsupported property type',
40+
description: 'This property type is not supported in the ontology editor',
41+
subPropOf: undefined,
42+
objectType: undefined,
43+
guiEle: undefined,
44+
group: 'Warning'
45+
};
46+
47+
3648
public static data: PropertyCategory[] = [
3749
{
3850
group: 'Text',
@@ -43,7 +55,7 @@ export class DefaultProperties {
4355
description: 'Short text such as title or name',
4456
subPropOf: Constants.HasValue,
4557
objectType: Constants.TextValue,
46-
guiEle: Constants.SalsahGui + Constants.HashDelimiter + 'SimpleText', // better element would be: 'Input',
58+
guiEle: Constants.GuiSimpleText, // better element would be: 'Input',
4759
group: 'Text' // redundant information, but otherwise we don't get the main group name after selecting type
4860
},
4961
{
@@ -52,7 +64,7 @@ export class DefaultProperties {
5264
description: 'Long text such as description; could have line breaks',
5365
subPropOf: Constants.HasValue,
5466
objectType: Constants.TextValue,
55-
guiEle: Constants.SalsahGui + Constants.HashDelimiter + 'Textarea',
67+
guiEle: Constants.GuiTextarea,
5668
group: 'Text'
5769
},
5870
{
@@ -61,7 +73,7 @@ export class DefaultProperties {
6173
description: 'A rich text editor with formatting options',
6274
subPropOf: Constants.HasValue,
6375
objectType: Constants.TextValue,
64-
guiEle: Constants.SalsahGui + Constants.HashDelimiter + 'Richtext',
76+
guiEle: Constants.GuiRichText,
6577
group: 'Text'
6678
}
6779
]
@@ -75,7 +87,7 @@ export class DefaultProperties {
7587
description: 'Dropdown menu with values from predefined list',
7688
subPropOf: Constants.HasValue,
7789
objectType: Constants.ListValue,
78-
guiEle: Constants.SalsahGui + Constants.HashDelimiter + 'List', // better element would be: 'Pulldown' or 'Select'
90+
guiEle: Constants.GuiPulldown, // better element would be: 'Pulldown' or 'Select'
7991
group: 'List'
8092
}
8193
]
@@ -89,7 +101,7 @@ export class DefaultProperties {
89101
description: 'Yes or no, 1 or 0, true or false',
90102
subPropOf: Constants.HasValue,
91103
objectType: Constants.BooleanValue,
92-
guiEle: Constants.SalsahGui + Constants.HashDelimiter + 'Checkbox', // should be 'Toggle' but it's not supported in DSP-Tangoh,
104+
guiEle: Constants.GuiCheckbox, // should be 'Toggle' but it's not supported in DSP-Tangoh,
93105
group: 'Boolean'
94106
}
95107
]
@@ -103,25 +115,16 @@ export class DefaultProperties {
103115
description: 'A date field with day, month and year',
104116
subPropOf: Constants.HasValue,
105117
objectType: Constants.DateValue,
106-
guiEle: Constants.SalsahGui + Constants.HashDelimiter + 'Date',
118+
guiEle: Constants.GuiDatePicker,
107119
group: 'Date / Time'
108120
},
109-
// {
110-
// icon: 'date_range',
111-
// label: 'Period',
112-
// description: 'A period of time between two dates',
113-
// subPropOf: Constants.HasValue,
114-
// objectType: Constants.DateValue,
115-
// guiEle: Constants.SalsahGui + Constants.HashDelimiter + 'Date',
116-
// group: 'Date / Time'
117-
// },
118121
{
119122
icon: 'access_time',
120123
label: 'Timestamp',
121124
description: 'A single timestamp on a timeline',
122125
subPropOf: Constants.HasValue,
123126
objectType: Constants.TimeValue,
124-
guiEle: Constants.SalsahGui + Constants.HashDelimiter + 'TimeStamp',
127+
guiEle: Constants.GuiTimeStamp,
125128
group: 'Date / Time'
126129
},
127130
{
@@ -130,7 +133,7 @@ export class DefaultProperties {
130133
description: 'A time sequence with start and end point on a timeline',
131134
subPropOf: Constants.HasValue,
132135
objectType: Constants.IntervalValue,
133-
guiEle: Constants.SalsahGui + Constants.HashDelimiter + 'Interval',
136+
guiEle: Constants.GuiInterval,
134137
group: 'Date / Time'
135138
}
136139
]
@@ -144,7 +147,7 @@ export class DefaultProperties {
144147
description: 'Integer value',
145148
subPropOf: Constants.HasValue,
146149
objectType: Constants.IntValue,
147-
guiEle: Constants.SalsahGui + Constants.HashDelimiter + 'Spinbox', // 'Number',
150+
guiEle: Constants.GuiSpinbox, // 'Number',
148151
group: 'Number'
149152
},
150153
{
@@ -153,16 +156,16 @@ export class DefaultProperties {
153156
description: 'Decimal value',
154157
subPropOf: Constants.HasValue,
155158
objectType: Constants.DecimalValue,
156-
guiEle: Constants.SalsahGui + Constants.HashDelimiter + 'Spinbox', // 'Number',
159+
guiEle: Constants.GuiSpinbox, // 'Number',
157160
group: 'Number'
158161
},
159162
{
160163
icon: 'filter_3',
161164
label: 'Page number',
162165
description: 'The page number is needed for page classes in case of part of properties',
163-
subPropOf: Constants.KnoraApiV2 + Constants.HashDelimiter + 'seqnum',
166+
subPropOf: Constants.SeqNum,
164167
objectType: Constants.IntValue,
165-
guiEle: Constants.SalsahGui + Constants.HashDelimiter + 'Spinbox', // 'Number',
168+
guiEle: Constants.GuiSpinbox, // 'Number',
166169
group: 'Number'
167170
}
168171
]
@@ -176,26 +179,26 @@ export class DefaultProperties {
176179
description: 'Refers to a resource class',
177180
subPropOf: Constants.HasLinkTo,
178181
objectType: Constants.LinkValue,
179-
guiEle: Constants.SalsahGui + Constants.HashDelimiter + 'Searchbox', // 'Autocomplete',
182+
guiEle: Constants.GuiSearchbox, // 'Autocomplete',
180183
group: 'Link / Relation'
181184
},
182185
{
183186
icon: 'extension',
184187
label: 'Part of class',
185188
description: 'Is part of a resource class',
186-
subPropOf: Constants.KnoraApiV2 + Constants.HashDelimiter + 'isPartOf',
189+
subPropOf: Constants.IsPartOf,
187190
objectType: Constants.LinkValue,
188-
guiEle: Constants.SalsahGui + Constants.HashDelimiter + 'Searchbox', // 'Autocomplete',
189-
group: 'Relation'
191+
guiEle: Constants.GuiSearchbox, // 'Autocomplete',
192+
group: 'Link / Relation'
190193
},
191194
{
192195
icon: 'language',
193196
label: 'External URL',
194197
description: 'Link to an external website',
195198
subPropOf: Constants.HasValue,
196199
objectType: Constants.UriValue,
197-
guiEle: Constants.SalsahGui + Constants.HashDelimiter + 'SimpleText',
198-
group: 'Link'
200+
guiEle: Constants.GuiSimpleText,
201+
group: 'Link / Relation'
199202
}
200203
]
201204
},
@@ -208,7 +211,7 @@ export class DefaultProperties {
208211
description: 'Geographical location',
209212
subPropOf: Constants.HasValue,
210213
objectType: Constants.GeonameValue,
211-
guiEle: Constants.SalsahGui + Constants.HashDelimiter + 'Geonames',
214+
guiEle: Constants.GuiGeonames,
212215
group: 'Location'
213216
}
214217
]
@@ -222,7 +225,7 @@ export class DefaultProperties {
222225
description: 'A simple color value',
223226
subPropOf: Constants.HasValue,
224227
objectType: Constants.ColorValue,
225-
guiEle: Constants.SalsahGui + Constants.HashDelimiter + 'Colorpicker',
228+
guiEle: Constants.GuiColorPicker,
226229
group: 'Shape'
227230
}
228231
]

‎src/app/project/ontology/ontology.service.spec.ts‎

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,22 @@
11
import { TestBed } from '@angular/core/testing';
2-
2+
import { CacheService } from 'src/app/main/cache/cache.service';
33
import { OntologyService } from './ontology.service';
44

5+
56
describe('OntologyService', () => {
67
let service: OntologyService;
78

9+
const cacheServiceSpy = jasmine.createSpyObj('CacheService', ['get']);
10+
811
beforeEach(() => {
9-
TestBed.configureTestingModule({});
12+
TestBed.configureTestingModule({
13+
providers: [
14+
{
15+
provide: CacheService,
16+
useValue: cacheServiceSpy
17+
},
18+
]
19+
});
1020
service = TestBed.inject(OntologyService);
1121
});
1222

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

Lines changed: 106 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,16 @@
11
import { Injectable } from '@angular/core';
2-
import { Cardinality, Constants } from '@dasch-swiss/dsp-js';
2+
import {
3+
Cardinality,
4+
Constants, ReadOntology,
5+
ResourcePropertyDefinitionWithAllLanguages
6+
} from '@dasch-swiss/dsp-js';
7+
import { Observable, of } from 'rxjs';
8+
import { CacheService } from 'src/app/main/cache/cache.service';
9+
import {
10+
DefaultProperties,
11+
DefaultProperty,
12+
PropertyCategory
13+
} from './default-data/default-properties';
314

415
/**
516
* helper methods for the ontology editor
@@ -9,7 +20,12 @@ import { Cardinality, Constants } from '@dasch-swiss/dsp-js';
920
})
1021
export class OntologyService {
1122

12-
constructor() { }
23+
// list of default property types
24+
defaultProperties: PropertyCategory[] = DefaultProperties.data;
25+
26+
constructor(
27+
private _cache: CacheService
28+
) { }
1329

1430
/**
1531
* create a unique name (id) for resource classes or properties;
@@ -79,4 +95,92 @@ export class OntologyService {
7995
return Cardinality._0_1;
8096
}
8197
}
98+
99+
getSuperProperty(property: ResourcePropertyDefinitionWithAllLanguages): string {
100+
// get ontology from property info
101+
const ontoIri = property.id.split(Constants.HashDelimiter)[0];
102+
103+
let superPropIri: string;
104+
105+
// get iri from sub properties
106+
if (property.subPropertyOf.length) {
107+
for (const subProp of property.subPropertyOf) {
108+
const baseOntoIri = subProp.split(Constants.HashDelimiter)[0];
109+
// compare with knora base ontology
110+
if (baseOntoIri !== Constants.KnoraApiV2) {
111+
// the property is not a subproperty of knora base ontology
112+
// get property iri from another ontology
113+
this._cache.get('currentProjectOntologies').subscribe(
114+
(ontologies: ReadOntology[]) => {
115+
const onto = ontologies.find(i => i.id === baseOntoIri);
116+
superPropIri = onto.properties[subProp].subPropertyOf[0];
117+
}
118+
);
119+
}
120+
121+
if (superPropIri) {
122+
break;
123+
}
124+
}
125+
}
126+
127+
return (superPropIri ? superPropIri : undefined);
128+
}
129+
130+
/**
131+
* get default property information for a certain ontology property
132+
*/
133+
getDefaultPropType(property: ResourcePropertyDefinitionWithAllLanguages): Observable<DefaultProperty> {
134+
let propType: DefaultProperty;
135+
136+
if (!property.guiElement) {
137+
// we don't know what element to use, so it's unsupported property
138+
return of (DefaultProperties.unsupported);
139+
}
140+
141+
for (const group of this.defaultProperties) {
142+
if (property.subPropertyOf.length) {
143+
for (const subProp of property.subPropertyOf) {
144+
// if subProp is of type "link to" or "part of" we have to check the subproperty;
145+
// otherwise we get the necessary property info from the objectType
146+
if (subProp === Constants.HasLinkTo || subProp === Constants.IsPartOf) {
147+
propType = (group.elements.find(i =>
148+
i.guiEle === property.guiElement && i.subPropOf === subProp
149+
));
150+
} else {
151+
152+
// if the property is type of number or list, the gui element is not relevant
153+
// because the app supports only one gui element (at the moment): the spinbox resp. the list pulldown
154+
if (property.objectType === Constants.DecimalValue || property.objectType === Constants.ListValue) {
155+
propType = (group.elements.find(i =>
156+
i.objectType === property.objectType
157+
));
158+
} else if (property.objectType === Constants.IntValue && subProp === Constants.SeqNum) {
159+
propType = (group.elements.find(i =>
160+
i.objectType === property.objectType && i.subPropOf === Constants.SeqNum
161+
));
162+
} else {
163+
propType = (group.elements.find(i =>
164+
i.guiEle === property.guiElement && i.objectType === property.objectType
165+
));
166+
}
167+
168+
}
169+
}
170+
if (propType) {
171+
break;
172+
}
173+
}
174+
}
175+
176+
if (!propType) {
177+
// property type could not be found in the list of default properties
178+
// maybe it's not supported e.g. if propDef.objectType === Constants.GeomValue || propDef.subPropertyOf[0] === Constants.HasRepresentation
179+
return of (DefaultProperties.unsupported);
180+
}
181+
182+
// return of(propType);
183+
return of (propType);
184+
185+
}
82186
}

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55

66
<p *ngIf="resClassIri && propertyInfo.propDef" class="note warning mat-caption center">
77
You're adding an already existing property to this class.
8-
The property can't modified here. If you want to modify it,
9-
go to the "properties" view.
8+
The property can't be modified here.<br>
9+
If you want to modify the label, the comment or the type, please go to the "properties" view.
1010
<!-- Be careful when editing it, it could have an effect in other resource classes if it is used there. -->
1111
</p>
1212

@@ -31,6 +31,9 @@
3131
</mat-option>
3232
</mat-optgroup>
3333
</mat-select>
34+
<mat-hint *ngIf="unsupportedPropertyType" class="ontology-warning-with-prefix">
35+
{{propertyForm.controls['propType'].value.description}}
36+
</mat-hint>
3437
</mat-form-field>
3538

3639
<!-- name -->

0 commit comments

Comments
 (0)