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

fix(search): add missing search resource component (DEV-95) #548

Merged
merged 1 commit into from Oct 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions src/app/app.module.ts
Expand Up @@ -160,6 +160,7 @@ import { SearchSelectOntologyComponent } from './workspace/search/advanced-searc
import { ExpertSearchComponent } from './workspace/search/expert-search/expert-search.component';
import { FulltextSearchComponent } from './workspace/search/fulltext-search/fulltext-search.component';
import { SearchPanelComponent } from './workspace/search/search-panel/search-panel.component';
import { SearchResourceComponent } from './workspace/search/advanced-search/resource-and-property-selection/search-select-property/specify-property-value/search-resource/search-resource.component';

// translate: AoT requires an exported function for factories
export function httpLoaderFactory(httpClient: HttpClient) {
Expand Down Expand Up @@ -310,6 +311,7 @@ export function httpLoaderFactory(httpClient: HttpClient) {
UsersComponent,
UsersListComponent,
VisualizerComponent,
SearchResourceComponent,
],
imports: [
AngularSplitModule.forRoot(),
Expand Down
@@ -0,0 +1,7 @@
<app-resource-and-property-selection
#resAndPropSel
[formGroup]="form"
[activeOntology]="ontology"
[resourceClassRestriction]="restrictResourceClass"
[topLevel]="false">
</app-resource-and-property-selection>
@@ -0,0 +1,122 @@
import { Component, Inject, Input, OnInit, ViewChild } from '@angular/core';
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { FormBuilder, FormGroup, ReactiveFormsModule } from '@angular/forms';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { MockOntology, ResourcePropertyDefinition } from '@dasch-swiss/dsp-js';
import { ComparisonOperatorAndValue, GreaterThan, LinkedResource, PropertyWithValue, ValueLiteral } from '../operator';
import { SearchResourceComponent } from './search-resource.component';

/**
* test host component to simulate parent component.
*/
@Component({
template: `
<app-search-resource #searchRes [formGroup]="form" [restrictResourceClass]="resClass"></app-search-resource>`
})
class TestHostComponent implements OnInit {

@ViewChild('searchRes', { static: false }) searchResource: SearchResourceComponent;

form;

resClass: string;

constructor(@Inject(FormBuilder) private _fb: FormBuilder) {
}

ngOnInit() {
this.form = this._fb.group({});
this.resClass = 'http://0.0.0.0:3333/ontology/0001/anything/v2#Thing';
}
}

/**
* test component to simulate ResourceAndPropertySelectionComponent.
*/
@Component({
selector: 'app-resource-and-property-selection',
template: ''
})
class TestResourceAndPropertySelectionComponent implements OnInit {

@Input() formGroup: FormGroup;

@Input() activeOntology: string;

@Input() resourceClassRestriction?: string;

@Input() topLevel;

// mock ref to child comp.
resourceClassComponent = {
selectedResourceClassIri: 'http://0.0.0.0:3333/ontology/0001/anything/v2#Thing'
};

// mock ref to child comp.
propertyComponents = [];

ngOnInit() {

const anythingOnto = MockOntology.mockReadOntology('http://0.0.0.0:3333/ontology/0001/anything/v2');

const linkedResValue = new ComparisonOperatorAndValue(new GreaterThan(), new ValueLiteral('0.5', 'http://www.w3.org/2001/XMLSchema#decimal'));

const hasDecimal = anythingOnto.properties['http://0.0.0.0:3333/ontology/0001/anything/v2#hasDecimal'];

const linkedResourceWithVal = new PropertyWithValue(hasDecimal as ResourcePropertyDefinition, linkedResValue, false);

this.propertyComponents = [{
getPropertySelectedWithValue: () => linkedResourceWithVal
}];
}
}

describe('SearchResourceComponent', () => {
let testHostComponent: TestHostComponent;
let testHostFixture: ComponentFixture<TestHostComponent>;

beforeEach(waitForAsync(() => {

TestBed.configureTestingModule({
imports: [
BrowserAnimationsModule,
ReactiveFormsModule
],
declarations: [
SearchResourceComponent,
TestResourceAndPropertySelectionComponent,
TestHostComponent
]
})
.compileComponents();
}));

beforeEach(() => {
testHostFixture = TestBed.createComponent(TestHostComponent);
testHostComponent = testHostFixture.componentInstance;

testHostFixture.detectChanges();
});

it('should create', () => {
expect(testHostComponent).toBeTruthy();
expect(testHostComponent.searchResource).toBeTruthy();
});

it('should correctly determine the ontology from the resource class constraint', () => {
expect(testHostComponent.searchResource.restrictResourceClass).toEqual('http://0.0.0.0:3333/ontology/0001/anything/v2#Thing');
});

it('should return a specified resource', () => {

const linkedRes = testHostComponent.searchResource.getValue();

expect(linkedRes instanceof LinkedResource).toBeTrue();
expect((linkedRes as LinkedResource).resourceClass).toEqual('http://0.0.0.0:3333/ontology/0001/anything/v2#Thing');
expect((linkedRes as LinkedResource).properties.length).toEqual(1);

expect((linkedRes as LinkedResource).properties[0].property.id).toEqual('http://0.0.0.0:3333/ontology/0001/anything/v2#hasDecimal');

});

});
@@ -0,0 +1,63 @@
import { Component, Inject, Input, OnInit, ViewChild } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
import { Constants } from '@dasch-swiss/dsp-js';
import { ResourceAndPropertySelectionComponent } from '../../../resource-and-property-selection.component';
import { LinkedResource, PropertyValue, PropertyWithValue, Value } from '../operator';

// https://stackoverflow.com/questions/45661010/dynamic-nested-reactive-form-expressionchangedafterithasbeencheckederror
const resolvedPromise = Promise.resolve(null);

@Component({
selector: 'app-search-resource',
templateUrl: './search-resource.component.html',
styleUrls: ['./search-resource.component.scss']
})
export class SearchResourceComponent implements OnInit, PropertyValue {

// parent FormGroup
@Input() formGroup: FormGroup;

@Input() restrictResourceClass: string;

// reference to the component that controls the resource class selection
@ViewChild('resAndPropSel') resourceAndPropertySelection: ResourceAndPropertySelectionComponent;

type = Constants.Resource;

form: FormGroup;

ontology: string;

constructor(@Inject(FormBuilder) private _fb: FormBuilder) {
}

ngOnInit(): void {

this.form = this._fb.group({});

resolvedPromise.then(() => {
this.formGroup.addControl('propValue', this.form);
});

// get ontology from restriction
this.ontology = this.restrictResourceClass.split('#')[0];
}

getValue(): Value {

const resClassOption = this.resourceAndPropertySelection.resourceClassComponent.selectedResourceClassIri;

let resClass;

if (resClassOption !== false) {
resClass = resClassOption;
}

const properties: PropertyWithValue[] = this.resourceAndPropertySelection.propertyComponents.map(
(propComp) => propComp.getPropertySelectedWithValue()
);

return new LinkedResource(properties, resClass);
}

}
Expand Up @@ -7,16 +7,16 @@
</span>

<!-- select apt component for value specification using a switch case statement-->
<span
*ngIf="comparisonOperatorSelected !== undefined && comparisonOperatorSelected !== null && comparisonOperatorSelected.getClassName() != 'Exists'" [ngSwitch]="propertyValueType">
<span *ngIf="comparisonOperatorSelected !== undefined && comparisonOperatorSelected !== null && comparisonOperatorSelected.getClassName() != 'Exists'"
[ngSwitch]="propertyValueType">
<app-search-int-value #propertyValue [formGroup]="form" *ngSwitchCase="Constants.IntValue"></app-search-int-value>
<app-search-decimal-value #propertyValue [formGroup]="form" *ngSwitchCase="Constants.DecimalValue"></app-search-decimal-value>
<app-search-boolean-value #propertyValue [formGroup]="form" *ngSwitchCase="Constants.BooleanValue"></app-search-boolean-value>
<app-search-date-value #propertyValue [formGroup]="form" *ngSwitchCase="Constants.DateValue"></app-search-date-value>

<span *ngSwitchCase="Constants.Resource">
<span *ngIf="comparisonOperatorSelected.getClassName() == 'Match'; else elseBlock">
<!-- <app-search-resource #propertyValue [formGroup]="form" [restrictResourceClass]="objectClassConstraint"></app-search-resource> -->
<app-search-resource #propertyValue [formGroup]="form" [restrictResourceClass]="objectClassConstraint"></app-search-resource>
</span>
<ng-template #elseBlock>
<app-search-link-value #propertyValue [formGroup]="form" [restrictResourceClass]="objectClassConstraint"></app-search-link-value>
Expand Down