Skip to content

Commit

Permalink
documents: improve brief views
Browse files Browse the repository at this point in the history
* Improves the display of brief views for documents.
* Adds a `publicationPipe` for displaying text for document's publications.
* Adds a configuration object to facilitate testing.
* Closes rero/sonar#253.

Co-Authored-by: Sébastien Délèze <sebastien.deleze@rero.ch>
  • Loading branch information
Sébastien Délèze committed Jul 21, 2020
1 parent cc78311 commit 5f74dee
Show file tree
Hide file tree
Showing 10 changed files with 324 additions and 36 deletions.
22 changes: 21 additions & 1 deletion projects/sonar/src/app/app-config.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,32 @@ import { CoreConfigService } from '@rero/ng-core';
import { environment } from '../environments/environment';

@Injectable({
providedIn: 'root'
providedIn: 'root',
})
export class AppConfigService extends CoreConfigService {
// View key for global search
globalSearchViewCode = 'sonar';

// Languages map.
languagesMap = [
{
code: 'en',
bibCode: 'eng',
},
{
code: 'fr',
bibCode: 'fre',
},
{
code: 'de',
bibCode: 'ger',
},
{
code: 'it',
bibCode: 'ita',
},
];

/**
* Constructor.
*/
Expand Down
1 change: 1 addition & 0 deletions projects/sonar/src/app/app-routing.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ const routes: Routes = [
adminMode: adminModeDisabled,
types: [
{
showLabel: false,
key: 'documents',
label: 'Documents',
component: DocumentComponent,
Expand Down
4 changes: 3 additions & 1 deletion projects/sonar/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import { HttpInterceptor } from './interceptor/http.interceptor';
import { LanguageValuePipe } from './pipe/language-value.pipe';
import { DetailComponent as DocumentDetailComponent } from './record/document/detail/detail.component';
import { DocumentComponent } from './record/document/document.component';
import { PublicationPipe } from './record/document/publication.pipe';
import { DetailComponent as OrganisationDetailComponent } from './record/organisation/detail/detail.component';
import { OrganisationComponent } from './record/organisation/organisation.component';
import { DetailComponent as UserDetailComponent } from './record/user/detail/detail.component';
Expand Down Expand Up @@ -77,7 +78,8 @@ export function minElementError(err: any, field: FormlyFieldConfig) {
FileLinkPipe,
HighlightJsonPipe,
ReviewComponent,
AdminComponent
AdminComponent,
PublicationPipe
],
imports: [
BrowserModule,
Expand Down
44 changes: 23 additions & 21 deletions projects/sonar/src/app/record/document/document.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
 along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<div class="row">
<div class="col-sm-2 text-center">
<div class="col-2 d-none d-lg-block text-center">
<ng-container *ngIf="thumbnail">
<a [href]="detailUrl.link" *ngIf="detailUrl.external; else routingLink">
<img [src]="thumbnail" class="img-thumbnail img-fluid p-2"
Expand All @@ -33,34 +33,36 @@
</span>
</p>
</ng-container>
</div>
<div class="col-sm-10">
<p class="m-0" *ngIf="record.metadata.organisation">
<i>{{ record.metadata.organisation.name | translate }}</i>
<p class="my-2" *ngIf="record.metadata.documentType">
<small>{{ ('document_type_' + record.metadata.documentType) | translate }}</small>
</p>
<h4 class="my-2">
<a [href]="detailUrl.link" *ngIf="detailUrl.external; else routingLink">{{
record.metadata.title[0].mainTitle | languageValue
}}</a>
</div>
<div class="col-12 col-lg-10">
<h4 class="mb-2">
<a [href]="detailUrl.link" *ngIf="detailUrl.external; else routingLink">
{{ record.metadata.title[0].mainTitle | languageValue }}<ng-container *ngIf="record.metadata.title[0].subtitle">
:&nbsp;{{ record.metadata.title[0].subtitle | languageValue }}</ng-container>
</a>
<ng-template #routingLink>
<a [routerLink]="detailUrl.link">
{{ record.metadata.title[0].mainTitle | languageValue }}
{{ record.metadata.title[0].mainTitle | languageValue }}<ng-container
*ngIf="record.metadata.title[0].subtitle">:&nbsp;{{ record.metadata.title[0].subtitle | languageValue }}
</ng-container>
</a>
</ng-template>
</h4>
<h5 *ngIf="record.metadata.title[0].subtitle" class="text-muted">
{{ record.metadata.title[0].subtitle | languageValue }}
</h5>
<p>
<ng-container *ngFor="let contributor of record.metadata.contribution">
<span class="badge badge-primary mr-1"
*ngIf="contributor.agent && contributor.agent.type === 'bf:Person' && contributor.role[0] === 'cre'">
{{ contributor.agent.preferred_name }}
</span>
<p class="mb-0">
<ng-container *ngFor="let contributor of record.metadata.contribution; let first = first;">
<ng-container *ngIf="!first">&nbsp;;&nbsp;</ng-container>
{{ contributor.agent.preferred_name }}
<span
*ngIf="contributor.role[0] !== 'cre'">({{ ('contribution_role_' + contributor.role[0]) | translate | lowercase }})</span>
</ng-container>
</p>
<div *ngIf="record.metadata.abstracts">
{{ record.metadata.abstracts | languageValue | truncateText: 30 }}
<p class="mb-2 d-none d-lg-block" *ngIf="record.metadata.partOf && record.metadata.partOf.length > 0">
{{ record.metadata.partOf[0] | publication }}</p>
<div class="d-none d-lg-block text-muted text-justify text-small" *ngIf="abstract">
{{ abstract | truncateText: 30 }}
</div>
</div>
</div>
104 changes: 98 additions & 6 deletions projects/sonar/src/app/record/document/document.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,26 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { Component, OnInit } from '@angular/core';
import { Component, OnDestroy, OnInit } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { ResultItem } from '@rero/ng-core';
import { Subscription } from 'rxjs';
import { AppConfigService } from '../../app-config.service';

const SORT_CONTRIBUTOR_PRIORITY = ['cre', 'ctb', 'dgs', 'edt', 'prt'];

@Component({
templateUrl: './document.component.html'
templateUrl: './document.component.html',
})
export class DocumentComponent implements ResultItem, OnInit {
export class DocumentComponent implements ResultItem, OnDestroy, OnInit {
// Record object
record: any;

// Type of resource
type: string;

// Detail URL object
detailUrl: { link: string, external: boolean };
detailUrl: { link: string; external: boolean };

// Thumbnail file for record
thumbnail: any;
Expand All @@ -42,15 +47,50 @@ export class DocumentComponent implements ResultItem, OnInit {
// Boolean giving the information is the main file is restricted
restricted: boolean;

// Abstract corresponding to current language.
abstract: string;

// Subscription to observables, used to unsubscribe to all at the same time.
private _subscription: Subscription = new Subscription();

/**
* Constructor.
*
* @param _configService Config service
* @param _translateService Translate service
*/
constructor(
private _configService: AppConfigService,
private _translateService: TranslateService
) {}

/**
* Component initialization.
* - Extracts and stores main file from document files.
* - Stores embargo information from main file.
* - Load thumbnail for the record.
*/
ngOnInit() {
// Initialize and sort contributors
if (!this.record.metadata.contribution) {
this.record.metadata.contribution = [];
}
this._sortContributors();

// Load abstract
this._storeAbstract();

// When language change, abstracts are sorted and first one is displayed.
this._subscription.add(
this._translateService.onLangChange.subscribe(() => {
this._storeAbstract();
})
);

if (this.record.metadata._files) {
this.mainFile = this.record.metadata._files.find((file: any) => file.type === 'file');
this.mainFile = this.record.metadata._files.find(
(file: any) => file.type === 'file'
);
if (this.mainFile) {
if (this.mainFile.restriction.date) {
this.embargoDate = this.mainFile.restriction.date;
Expand All @@ -65,6 +105,15 @@ export class DocumentComponent implements ResultItem, OnInit {
}
}

/**
* Component destruction.
*
* Unsubscribe from subscribers.
*/
ngOnDestroy() {
this._subscription.unsubscribe();
}

/**
* Load the thumbnail for record
*/
Expand All @@ -73,7 +122,9 @@ export class DocumentComponent implements ResultItem, OnInit {
return;
}

const thumbnail = this.record.metadata._files.find((file: any) => file.type === 'thumbnail');
const thumbnail = this.record.metadata._files.find(
(file: any) => file.type === 'thumbnail'
);

if (!thumbnail) {
return;
Expand All @@ -86,4 +137,45 @@ export class DocumentComponent implements ResultItem, OnInit {

this.thumbnail = `/documents/${this.record.metadata.pid}/files/${thumbnail.key}`;
}

/**
* Sort contributors by given priorities array constant.
*/
private _sortContributors() {
this.record.metadata.contribution = this.record.metadata.contribution.sort(
(a: any, b: any) => {
const aIndex = SORT_CONTRIBUTOR_PRIORITY.findIndex(
(role) => a.role[0] === role
);
const bIndex = SORT_CONTRIBUTOR_PRIORITY.findIndex(
(role) => b.role[0] === role
);
if (aIndex === bIndex) {
return 0;
}
return aIndex < bIndex ? -1 : 1;
}
);
}

private _storeAbstract() {
if (
!this.record.metadata.abstracts ||
this.record.metadata.abstracts.length === 0
) {
return null;
}

const currentLang = this._configService.languagesMap.find(
(item) => item.code === this._translateService.currentLang
);

const abstract = this.record.metadata.abstracts.find(
(item: any) => item.language === currentLang.bibCode
);

this.abstract = abstract
? abstract.value
: this.record.metadata.abstracts[0].value;
}
}
81 changes: 81 additions & 0 deletions projects/sonar/src/app/record/document/publication.pipe.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*
* SONAR User Interface
* Copyright (C) 2020 RERO
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { TestBed } from '@angular/core/testing';
import { TranslateService } from '@rero/ng-core';
import { mockedConfiguration } from '../../../../tests/utils';
import { PublicationPipe } from './publication.pipe';

let pipe: PublicationPipe;

describe('PublicationPipe', () => {
beforeEach(() => {
TestBed.configureTestingModule(mockedConfiguration);

pipe = new PublicationPipe(TestBed.get(TranslateService));
});

it('create an instance', () => {
expect(pipe).toBeTruthy();
});

it('should return empty publication', () => {
expect(pipe.transform({})).toBe('');
});

it('should return only document', () => {
expect(pipe.transform({ document: { title: 'Journal' } })).toBe('Journal');
});

it('should return document and year', () => {
expect(
pipe.transform({ document: { title: 'Journal' }, numberingYear: '2000' })
).toBe('Journal, 2000');
});

it('should return document, year and issue', () => {
expect(
pipe.transform({
document: { title: 'Journal' },
numberingYear: '2000',
numberingIssue: '12',
})
).toBe('Journal, 2000, no. 12');
});

it('should return document, year, issue and volume', () => {
expect(
pipe.transform({
document: { title: 'Journal' },
numberingYear: '2000',
numberingIssue: '12',
numberingVolume: '1',
})
).toBe('Journal, 2000, vol. 1, no. 12');
});

it('should return document, year, issue, volume and pages', () => {
expect(
pipe.transform({
document: { title: 'Journal' },
numberingYear: '2000',
numberingIssue: '12',
numberingVolume: '1',
numberingPages: '20-25',
})
).toBe('Journal, 2000, vol. 1, no. 12, p. 20-25');
});
});
Loading

0 comments on commit 5f74dee

Please # to comment.