Skip to content
Permalink
Browse files
feat(resource): display incoming links (DSP-1846) (#507)
* adding incoming links

* fix: adding type

* test: incoming links

* test: checking amount of incoming link

* feat: pagination in incoming links

* fix(test): code style
  • Loading branch information
Vijeinath committed Aug 17, 2021
1 parent 5d79065 commit 9c3abce7a01a509d041cbd569d603ab52c931dda
@@ -176,9 +176,10 @@ FILTER NOT EXISTS {
*
* @param {string} resourceIri the Iri of the resource whose incoming links should be returned.
* @param {number} offset the offset to be used for paging. 0 is the default and is used to get the first page of results.
* @param {boolean} countQuery if set to true, the request returns only the CountQueryResponse; default value is `false`
* @returns {Observable<any>}
*/
getIncomingLinks(resourceIri: string, offset: number): Observable<ReadResourceSequence | ApiResponseError> {
getIncomingLinks(resourceIri: string, offset: number, countQuery: boolean = false): Observable<ReadResourceSequence | CountQueryResponse | ApiResponseError> {
const sparqlQueryStr = `
PREFIX knora-api: <http://api.knora.org/ontology/knora-api/simple/v2#>
@@ -211,7 +212,7 @@ FILTER NOT EXISTS {
} OFFSET ${offset}
`;

return this._dspApiConnection.v2.search.doExtendedSearch(sparqlQueryStr);
return countQuery ? this._dspApiConnection.v2.search.doExtendedSearchCountQuery(sparqlQueryStr) : this._dspApiConnection.v2.search.doExtendedSearch(sparqlQueryStr);
}
}

@@ -146,6 +146,36 @@ <h3 class="label mat-title">
</div>
</div>
</div>

<div *ngIf="incomingLinkResources.length > 0">
<div class="property border-top">
<div class="property-label">
<!-- label of the incoming links -->
<h3 class="label mat-subheading-1">
has incoming link
</h3>
</div>
<div class="property-value">
<div *ngIf="loading">
...Loading
</div>
<div *ngIf="!loading">
<!-- the value(s) of the incoming links -->
<div *ngFor="let inRes of incomingLinkResources">
<a [routerLink]="['/resource', inRes.id]" target="_blank">{{inRes.label}}</a>
</div>
<mat-paginator
[length]=numberOffAllIncomingLinkRes
[pageSize]="25"
[hidePageSize]="true"
[pageIndex]="pageEvent.pageIndex"
(page)="goToPage($event)">
</mat-paginator>
</div>
</div>
</div>
</div>

</div>
<ng-template #noProperties>The resource {{resource?.res.resourceClassLabel}} has no defined
properties.</ng-template>
@@ -166,6 +166,15 @@
color: rgba(0, 0, 0, 0.54);
}

:host::ng-deep .mat-paginator-container {
justify-content: start;
padding: 0;
}

:host::ng-deep .mat-paginator-range-label {
margin: 0;
}

@media screen and (max-width: 768px) {
.properties,
.incoming {
@@ -8,6 +8,7 @@ import { MatTooltipModule } from '@angular/material/tooltip';
import { By } from '@angular/platform-browser';
import { RouterTestingModule } from '@angular/router/testing';
import {
ApiResponseData,
ApiResponseError,
Constants,
IHasPropertyWithPropertyDefinition,
@@ -18,6 +19,7 @@ import {
ProjectsEndpointAdmin,
ReadLinkValue,
ReadResource,
ReadResourceSequence,
ReadValue,
ResourcePropertyDefinition,
SystemPropertyDefinition
@@ -37,6 +39,7 @@ import { of, Subscription } from 'rxjs';
import { TestConfig } from 'test.config';
import { DspResource } from '../dsp-resource';
import { PropertiesComponent } from './properties.component';
import { IncomingService } from '../incoming.service';

/**
* test host component to simulate parent component.
@@ -147,6 +150,8 @@ describe('PropertiesComponent', () => {

const userServiceSpy = jasmine.createSpyObj('UserService', ['getUser']);

const incomingServiceSpy = jasmine.createSpyObj('IncomingService', ['getIncomingLinks']);

TestBed.configureTestingModule({
imports: [
ClipboardModule,
@@ -174,6 +179,10 @@ describe('PropertiesComponent', () => {
provide: UserService,
useValue: userServiceSpy
},
{
provide: IncomingService,
useValue: incomingServiceSpy
},
]
})
.compileComponents();
@@ -224,13 +233,28 @@ describe('PropertiesComponent', () => {
}
);

const incomingLinksSpy = TestBed.inject(IncomingService);

(incomingLinksSpy as jasmine.SpyObj<IncomingService>).getIncomingLinks.and.callFake(
() => {
const resources = new ReadResource();
const incomingLinks = new ReadResourceSequence([resources], true);
return of(incomingLinks);
}
);

testHostFixture = TestBed.createComponent(TestPropertyParentComponent);
testHostComponent = testHostFixture.componentInstance;
testHostFixture.detectChanges();

expect(testHostComponent).toBeTruthy();
});

it('should get one incoming link', () => {

expect(testHostComponent.propertiesComponent.incomingLinkResources.length).toEqual(1);
});

it('should get the resource testding', () => {

expect(testHostComponent.parentResource).toBeTruthy();
@@ -1,11 +1,10 @@
import { Component, EventEmitter, Inject, Input, OnChanges, OnDestroy, OnInit, Output } from '@angular/core';
import { MatDialog, MatDialogConfig } from '@angular/material/dialog';
import { MatSnackBar } from '@angular/material/snack-bar';
import {
ApiResponseData,
ApiResponseError,
CardinalityUtil,
Constants,
Constants, CountQueryResponse,
DeleteResource,
DeleteResourceResponse,
DeleteValue,
@@ -41,6 +40,8 @@ import { ConfirmationWithComment, DialogComponent } from 'src/app/main/dialog/di
import { ErrorHandlerService } from 'src/app/main/error/error-handler.service';
import { DspResource } from '../dsp-resource';
import { RepresentationConstants } from '../representation/file-representation';
import { IncomingService } from '../incoming.service';
import { PageEvent } from '@angular/material/paginator';

@Component({
selector: 'app-properties',
@@ -110,6 +111,11 @@ export class PropertiesComponent implements OnInit, OnChanges, OnDestroy {
project: ReadProject;
user: ReadUser;

incomingLinkResources: ReadResource[] = [];
pageEvent: PageEvent;
numberOffAllIncomingLinkRes: number;
loading = false;

showAllProps = false; // show or hide empty properties

constructor(
@@ -119,10 +125,17 @@ export class PropertiesComponent implements OnInit, OnChanges, OnDestroy {
private _notification: NotificationService,
private _userService: UserService,
private _valueOperationEventService: ValueOperationEventService,
private _valueService: ValueService
private _valueService: ValueService,
private _incomingService: IncomingService
) { }

ngOnInit(): void {
// reset the page event
this.pageEvent = new PageEvent();
this.pageEvent.pageIndex = 0;

this._getIncomingLinks();

if (this.resource.res) {
// get user permissions
const allPermissions = PermissionUtil.allUserPermissions(
@@ -215,6 +228,15 @@ export class PropertiesComponent implements OnInit, OnChanges, OnDestroy {
// --> TODO: pop up project preview on hover
}

/**
* goes to the next page of the incoming link pagination
* @param page
*/
goToPage(page: PageEvent) {
this.pageEvent = page;
this._getIncomingLinks();
}

/**
* opens resource
* @param linkValue
@@ -436,6 +458,33 @@ export class PropertiesComponent implements OnInit, OnChanges, OnDestroy {
localStorage.setItem('showAllProps', JSON.stringify(this.showAllProps));
}

/**
* gets the number of incoming links and gets the incoming links.
* @private
*/
private _getIncomingLinks() {
this.loading = true;

if (this.pageEvent.pageIndex === 0) {
this._incomingService.getIncomingLinks(this.resource.res.id, this.pageEvent.pageIndex, true).subscribe(
(response: CountQueryResponse) => {
this.numberOffAllIncomingLinkRes = response.numberOfResults;
}
);
}

this._incomingService.getIncomingLinks(this.resource.res.id, this.pageEvent.pageIndex).subscribe(
(response: ReadResourceSequence) => {
if (response.resources.length > 0) {
this.incomingLinkResources = response.resources;
}
this.loading = false;
}, (error: ApiResponseError) => {
this.loading = false;
}
);
}

/**
* updates the standoff link value for the resource being displayed.
*

0 comments on commit 9c3abce

Please sign in to comment.