mirror of
https://gitlab.com/openstapps/openstapps.git
synced 2026-01-20 00:23:03 +00:00
feat: add HeBIS HDS search
This commit is contained in:
committed by
Jovan Krunić
parent
e4165901bb
commit
9a3241c42a
@@ -182,6 +182,9 @@ import {TitleCardComponent} from './elements/title-card.component';
|
||||
SkeletonSimpleCardComponent,
|
||||
SearchPageComponent,
|
||||
SimpleDataListComponent,
|
||||
ArticleDetailContentComponent,
|
||||
OriginDetailComponent,
|
||||
FavoriteButtonComponent,
|
||||
],
|
||||
})
|
||||
export class DataModule {}
|
||||
|
||||
@@ -66,9 +66,9 @@ export class DataDetailComponent {
|
||||
* @param translateService he translate provider
|
||||
*/
|
||||
constructor(
|
||||
private readonly route: ActivatedRoute,
|
||||
protected readonly route: ActivatedRoute,
|
||||
private readonly dataProvider: DataProvider,
|
||||
private readonly network: Network,
|
||||
protected readonly network: Network,
|
||||
private readonly favoritesService: FavoritesService,
|
||||
translateService: TranslateService,
|
||||
) {
|
||||
@@ -125,9 +125,7 @@ export class DataDetailComponent {
|
||||
* @param refresher Refresher component that triggers the update
|
||||
*/
|
||||
async refresh(refresher: IonRefresher) {
|
||||
await this.getItem(
|
||||
this.item?.uid ?? this.route.snapshot.paramMap.get('uid') ?? '',
|
||||
);
|
||||
await this.getItem(this.route.snapshot.paramMap.get('uid') ?? '');
|
||||
await refresher.complete();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,17 +13,24 @@
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {Component, OnInit} from '@angular/core';
|
||||
import {AlertController} from '@ionic/angular';
|
||||
import {Router} from '@angular/router';
|
||||
import {NGXLogger} from 'ngx-logger';
|
||||
import {
|
||||
debounceTime,
|
||||
distinctUntilChanged,
|
||||
startWith,
|
||||
take,
|
||||
} from 'rxjs/operators';
|
||||
import {combineLatest} from 'rxjs';
|
||||
import {SCThingType} from '@openstapps/core';
|
||||
import {FavoritesService} from './favorites.service';
|
||||
import {DataRoutingService} from '../data/data-routing.service';
|
||||
import {Router} from '@angular/router';
|
||||
import {ContextMenuService} from '../menu/context/context-menu.service';
|
||||
import {SearchPageComponent} from '../data/list/search-page.component';
|
||||
import {AlertController} from '@ionic/angular';
|
||||
import {DataProvider} from '../data/data.provider';
|
||||
import {SettingsProvider} from '../settings/settings.provider';
|
||||
import {NGXLogger} from 'ngx-logger';
|
||||
import {PositionService} from '../map/position.service';
|
||||
import {take} from 'rxjs/operators';
|
||||
|
||||
/**
|
||||
* The page for showing favorites
|
||||
@@ -62,9 +69,69 @@ export class FavoritesPageComponent
|
||||
|
||||
ngOnInit() {
|
||||
super.ngOnInit();
|
||||
for (const subscription of this.subscriptions) {
|
||||
subscription.unsubscribe();
|
||||
}
|
||||
|
||||
// Recreate subscriptions to handle different routing
|
||||
this.subscriptions.push(
|
||||
this.favoritesService.favoritesChanged$.subscribe(_favoritesMap => {
|
||||
this.fetchAndUpdateItems();
|
||||
combineLatest([
|
||||
this.queryTextChanged.pipe(
|
||||
debounceTime(this.searchQueryDueTime),
|
||||
distinctUntilChanged(),
|
||||
startWith(this.queryText),
|
||||
),
|
||||
this.contextMenuService.filterQueryChanged$.pipe(
|
||||
startWith(this.filterQuery),
|
||||
),
|
||||
this.contextMenuService.sortQueryChanged$.pipe(
|
||||
startWith(this.sortQuery),
|
||||
),
|
||||
this.favoritesService.favoritesChanged$,
|
||||
]).subscribe(async query => {
|
||||
this.queryText = query[0];
|
||||
this.filterQuery = query[1];
|
||||
this.sortQuery = query[2];
|
||||
this.from = 0;
|
||||
if (
|
||||
typeof this.filterQuery !== 'undefined' ||
|
||||
this.queryText?.length > 0 ||
|
||||
this.showDefaultData
|
||||
) {
|
||||
await this.fetchAndUpdateItems();
|
||||
this.queryChanged.next();
|
||||
}
|
||||
}),
|
||||
this.settingsProvider.settingsActionChanged$.subscribe(
|
||||
({type, payload}) => {
|
||||
if (type === 'stapps.settings.changed') {
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
const {category, name, value} = payload!;
|
||||
this.logger.log(`received event "settings.changed" with category:
|
||||
${category}, name: ${name}, value: ${JSON.stringify(value)}`);
|
||||
}
|
||||
},
|
||||
),
|
||||
this.dataRoutingService.itemSelectListener().subscribe(item => {
|
||||
if (this.itemRouting) {
|
||||
if (
|
||||
[
|
||||
SCThingType.Book,
|
||||
SCThingType.Periodical,
|
||||
SCThingType.Article,
|
||||
].includes(item.type)
|
||||
) {
|
||||
void this.router.navigate([
|
||||
'hebis-detail',
|
||||
(item.origin &&
|
||||
'originalId' in item.origin &&
|
||||
item.origin['originalId']) ||
|
||||
'',
|
||||
]);
|
||||
} else {
|
||||
void this.router.navigate(['data-detail', item.uid]);
|
||||
}
|
||||
}
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
/* eslint-disable @typescript-eslint/no-non-null-assertion,@typescript-eslint/no-explicit-any */
|
||||
/*
|
||||
* Copyright (C) 2018, 2019 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
*
|
||||
* 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 General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {CUSTOM_ELEMENTS_SCHEMA} from '@angular/core';
|
||||
import {ComponentFixture, TestBed, waitForAsync} from '@angular/core/testing';
|
||||
import {ActivatedRoute, RouterModule} from '@angular/router';
|
||||
import {IonRefresher} from '@ionic/angular';
|
||||
import {
|
||||
TranslateLoader,
|
||||
TranslateModule,
|
||||
TranslateService,
|
||||
} from '@ngx-translate/core';
|
||||
import {sampleThingsMap} from '../../../_helpers/data/sample-things';
|
||||
import {HebisRoutingModule} from '../hebis-routing.module';
|
||||
import {HebisModule} from '../hebis.module';
|
||||
import {DaiaAvailabilityComponent} from './daia-availability.component';
|
||||
import {Observable, of} from 'rxjs';
|
||||
import {StorageProvider} from '../../storage/storage.provider';
|
||||
import {DaiaDataProvider} from '../daia-data.provider';
|
||||
|
||||
const translations: any = {data: {detail: {TITLE: 'Foo'}}};
|
||||
|
||||
class TranslateFakeLoader implements TranslateLoader {
|
||||
getTranslation(_lang: string): Observable<any> {
|
||||
return of(translations);
|
||||
}
|
||||
}
|
||||
|
||||
describe('DaiaAvailabilityComponent', () => {
|
||||
let comp: DaiaAvailabilityComponent;
|
||||
let fixture: ComponentFixture<DaiaAvailabilityComponent>;
|
||||
let dataProvider: DaiaDataProvider;
|
||||
let refresher: IonRefresher;
|
||||
const sampleThing = sampleThingsMap.book[0];
|
||||
let translateService: TranslateService;
|
||||
|
||||
// @Component({ selector: 'stapps-data-list-item', template: '' })
|
||||
// class DataListItemComponent {
|
||||
// @Input() item;
|
||||
// }
|
||||
|
||||
const fakeActivatedRoute = {
|
||||
snapshot: {
|
||||
paramMap: {
|
||||
get: () => {
|
||||
return sampleThing.uid;
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const storageProviderSpy = jasmine.createSpyObj('StorageProvider', [
|
||||
'init',
|
||||
'get',
|
||||
'has',
|
||||
'put',
|
||||
'search',
|
||||
]);
|
||||
|
||||
beforeEach(
|
||||
waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
RouterModule.forRoot([], {relativeLinkResolution: 'legacy'}),
|
||||
HebisRoutingModule,
|
||||
HebisModule,
|
||||
TranslateModule.forRoot({
|
||||
loader: {provide: TranslateLoader, useClass: TranslateFakeLoader},
|
||||
}),
|
||||
],
|
||||
providers: [
|
||||
{
|
||||
provide: ActivatedRoute,
|
||||
useValue: fakeActivatedRoute,
|
||||
},
|
||||
{
|
||||
provide: StorageProvider,
|
||||
useValue: storageProviderSpy,
|
||||
},
|
||||
],
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||
}).compileComponents();
|
||||
}),
|
||||
);
|
||||
|
||||
beforeEach(async () => {
|
||||
dataProvider = TestBed.get(DaiaDataProvider);
|
||||
translateService = TestBed.get(TranslateService);
|
||||
refresher = jasmine.createSpyObj('refresher', ['complete']);
|
||||
spyOn(dataProvider, 'get' as any).and.returnValue(
|
||||
Promise.resolve(sampleThing),
|
||||
);
|
||||
spyOn(
|
||||
DaiaAvailabilityComponent.prototype,
|
||||
'getAvailability',
|
||||
).and.callThrough();
|
||||
fixture = await TestBed.createComponent(DaiaAvailabilityComponent);
|
||||
comp = fixture.componentInstance;
|
||||
translateService.use('foo');
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create component', () => expect(comp).toBeDefined());
|
||||
|
||||
it('should get the availability of an item', () => {
|
||||
comp.getAvailability(sampleThing.uid);
|
||||
expect(
|
||||
DaiaAvailabilityComponent.prototype.getAvailability,
|
||||
).toHaveBeenCalledWith(sampleThing.uid);
|
||||
});
|
||||
|
||||
it('should get the availability of an item when the view is entered', () => {
|
||||
comp.ngOnInit();
|
||||
expect(
|
||||
DaiaAvailabilityComponent.prototype.getAvailability,
|
||||
).toHaveBeenCalledWith(sampleThing.uid);
|
||||
});
|
||||
|
||||
it('should update the data item when refresh is called', async () => {
|
||||
await comp.refresh(refresher);
|
||||
expect(
|
||||
DaiaAvailabilityComponent.prototype.getAvailability,
|
||||
).toHaveBeenCalledWith(sampleThing.uid);
|
||||
expect(refresher.complete).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (C) 2018, 2019 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
*
|
||||
* 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 General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {Component, OnInit} from '@angular/core';
|
||||
import {ActivatedRoute} from '@angular/router';
|
||||
import {Network} from '@ionic-native/network/ngx';
|
||||
import {TranslateService} from '@ngx-translate/core';
|
||||
import {SCUuid} from '@openstapps/core';
|
||||
import {FavoritesService} from '../../favorites/favorites.service';
|
||||
import {DataProvider} from '../../data/data.provider';
|
||||
import {DataDetailComponent} from '../../data/detail/data-detail.component';
|
||||
import {DaiaDataProvider} from '../daia-data.provider';
|
||||
import {SCDaiaHoldings} from '../protocol/response';
|
||||
|
||||
/**
|
||||
* A Component to display an SCThing detailed
|
||||
*/
|
||||
@Component({
|
||||
selector: 'stapps-daia-availability',
|
||||
styleUrls: ['daia-availability.scss'],
|
||||
templateUrl: 'daia-availability.html',
|
||||
})
|
||||
export class DaiaAvailabilityComponent
|
||||
extends DataDetailComponent
|
||||
implements OnInit
|
||||
{
|
||||
holdings: SCDaiaHoldings[];
|
||||
|
||||
/**
|
||||
*
|
||||
* @param route the route the page was accessed from
|
||||
* @param dataProvider the data provider
|
||||
* @param network the network provider
|
||||
* @param favoritesService the favorites provider
|
||||
* @param translateService he translate provider
|
||||
* @param daiaDataProvider DaiaDataProvider
|
||||
*/
|
||||
constructor(
|
||||
route: ActivatedRoute,
|
||||
dataProvider: DataProvider,
|
||||
network: Network,
|
||||
favoritesService: FavoritesService,
|
||||
translateService: TranslateService,
|
||||
private daiaDataProvider: DaiaDataProvider,
|
||||
) {
|
||||
super(route, dataProvider, network, favoritesService, translateService);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if we have internet
|
||||
*/
|
||||
isDisconnected(): boolean {
|
||||
return this.network.type === this.network.Connection.NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize
|
||||
*/
|
||||
async ngOnInit() {
|
||||
const uid = this.route.snapshot.paramMap.get('uid') || '';
|
||||
await this.getAvailability(uid ?? '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides data item with given UID
|
||||
*
|
||||
* @param uid Unique identifier of a thing
|
||||
*/
|
||||
async getAvailability(uid: SCUuid) {
|
||||
this.daiaDataProvider.getAvailability(uid).then(holdings => {
|
||||
this.holdings = holdings;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
<ion-card>
|
||||
<ion-card-header>{{
|
||||
'hebisSearch.daia.availability' | translate
|
||||
}}</ion-card-header>
|
||||
<ion-card-content>
|
||||
<ng-container *ngFor="let holding of holdings">
|
||||
<ion-label
|
||||
><a [href]="holding.href" target="_blank">{{
|
||||
holding.label
|
||||
}}</a></ion-label
|
||||
>
|
||||
<ion-grid>
|
||||
<ion-row *ngIf="holding.signature">
|
||||
<ion-col size="3">{{
|
||||
'hebisSearch.daia.signature' | translate
|
||||
}}</ion-col>
|
||||
<ion-col
|
||||
size="9"
|
||||
*ngIf="
|
||||
!holding ||
|
||||
!holding.available ||
|
||||
holding.available.service !== 'openaccess'
|
||||
"
|
||||
>{{ holding.signature }}</ion-col
|
||||
>
|
||||
<ion-col size="9" *ngIf="holding.available.service === 'openaccess'">
|
||||
<a [href]="holding.available.href" target="_blank">{{
|
||||
'hebisSearch.daia.ejournal' | translate
|
||||
}}</a>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
<ion-row *ngIf="holding.storage && holding.storage.content">
|
||||
<ion-col size="3">{{
|
||||
'hebisSearch.daia.location' | translate
|
||||
}}</ion-col>
|
||||
<ion-col size="9" [innerHTML]="holding.storage.content"></ion-col>
|
||||
</ion-row>
|
||||
<ion-row *ngIf="holding.about">
|
||||
<ion-col size="3">{{
|
||||
'hebisSearch.daia.comment' | translate
|
||||
}}</ion-col>
|
||||
<ion-col size="9">{{ holding.about }}</ion-col>
|
||||
</ion-row>
|
||||
<ion-row
|
||||
*ngIf="holding.available && holding.available.service === 'loan'"
|
||||
>
|
||||
<ion-col size="3">{{
|
||||
'hebisSearch.daia.status' | translate
|
||||
}}</ion-col>
|
||||
<ion-col size="9"
|
||||
>{{ 'hebisSearch.daia.available' | translate }}
|
||||
<a
|
||||
[href]="holding.available.href"
|
||||
*ngIf="holding.available.href"
|
||||
target="_blank"
|
||||
>{{ 'hebisSearch.daia.order' | translate }}</a
|
||||
></ion-col
|
||||
>
|
||||
</ion-row>
|
||||
</ion-grid>
|
||||
</ng-container>
|
||||
</ion-card-content>
|
||||
</ion-card>
|
||||
@@ -0,0 +1,38 @@
|
||||
ion-card {
|
||||
margin: 0;
|
||||
box-shadow: none;
|
||||
ion-card-content {
|
||||
h1 {
|
||||
margin: 0;
|
||||
}
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
ion-card-header {
|
||||
color: var(--ion-color-dark);
|
||||
padding-top: 8px;
|
||||
padding-bottom: 4px;
|
||||
font-weight: bold;
|
||||
}
|
||||
ion-card-content {
|
||||
ion-label a {
|
||||
display: block;
|
||||
text-decoration: none;
|
||||
font-weight: 700;
|
||||
color: var(--ion-color-primary);
|
||||
margin: 20px 0 5px;
|
||||
}
|
||||
ion-grid {
|
||||
padding: 0;
|
||||
|
||||
ion-row {
|
||||
background-color: var(--ion-color-light);
|
||||
color: var(--ion-color-light-contrast);
|
||||
border-bottom: 1px solid #fff;
|
||||
|
||||
ion-col:first-child {
|
||||
font-weight: 700;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
121
src/app/modules/hebis/daia-data.provider.ts
Normal file
121
src/app/modules/hebis/daia-data.provider.ts
Normal file
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright (C) 2018-2021 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
*
|
||||
* 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 General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {Injectable} from '@angular/core';
|
||||
import {Client} from '@openstapps/api/lib/client';
|
||||
import {SCDaiaAvailabilityResponse, SCDaiaHoldings} from './protocol/response';
|
||||
import {StorageProvider} from '../storage/storage.provider';
|
||||
import {StAppsWebHttpClient} from '../data/stapps-web-http-client.provider';
|
||||
import {HttpClient} from '@angular/common/http';
|
||||
import {DataProvider} from '../data/data.provider';
|
||||
import {environment} from '../../../environments/environment';
|
||||
|
||||
/**
|
||||
* Generated class for the DataProvider provider.
|
||||
*
|
||||
* See https://angular.io/guide/dependency-injection for more info on providers
|
||||
* and Angular DI.
|
||||
*/
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class DaiaDataProvider extends DataProvider {
|
||||
/**
|
||||
* TODO
|
||||
*/
|
||||
storageProvider: StorageProvider;
|
||||
|
||||
httpClient: HttpClient;
|
||||
|
||||
backendUrl = environment.daia_url;
|
||||
|
||||
/**
|
||||
* TODO
|
||||
*
|
||||
* @param stAppsWebHttpClient TODO
|
||||
* @param storageProvider TODO
|
||||
* @param httpClient TODO
|
||||
*/
|
||||
constructor(
|
||||
stAppsWebHttpClient: StAppsWebHttpClient,
|
||||
storageProvider: StorageProvider,
|
||||
httpClient: HttpClient,
|
||||
) {
|
||||
super(stAppsWebHttpClient, storageProvider);
|
||||
this.storageProvider = storageProvider;
|
||||
this.httpClient = httpClient;
|
||||
this.client = new Client(
|
||||
stAppsWebHttpClient,
|
||||
this.backendUrl,
|
||||
this.appVersion,
|
||||
);
|
||||
}
|
||||
|
||||
async getAvailability(id: string): Promise<SCDaiaHoldings[]> {
|
||||
return new Promise(resolve =>
|
||||
this.httpClient
|
||||
.get<SCDaiaAvailabilityResponse>(this.backendUrl, {params: {id}})
|
||||
.subscribe((response: SCDaiaAvailabilityResponse) => {
|
||||
console.error(response);
|
||||
const holdings: SCDaiaHoldings[] = [];
|
||||
if (response && Array.isArray(response.document)) {
|
||||
response.document.map(document => {
|
||||
Array.isArray(document.item) &&
|
||||
document.item.map(element => {
|
||||
try {
|
||||
const {
|
||||
department: {
|
||||
id: departmentId,
|
||||
content: departmentLabel,
|
||||
href: departmentLink,
|
||||
} = {id: 'noDep', content: '', href: ''},
|
||||
label,
|
||||
about,
|
||||
available,
|
||||
storage,
|
||||
} = element;
|
||||
const holdingIndex = holdings.findIndex(
|
||||
holding => holding.id === departmentId,
|
||||
);
|
||||
|
||||
if (holdingIndex === -1) {
|
||||
holdings.push({
|
||||
id: departmentId,
|
||||
label: departmentLabel,
|
||||
href: departmentLink,
|
||||
signature: label,
|
||||
available:
|
||||
(Array.isArray(available) &&
|
||||
(available.find(
|
||||
item => item.service === 'openaccess',
|
||||
) ||
|
||||
available.find(
|
||||
item => item.service === 'loan',
|
||||
))) ||
|
||||
undefined,
|
||||
storage,
|
||||
about,
|
||||
});
|
||||
}
|
||||
} catch {
|
||||
// No element available
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
resolve(holdings);
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
104
src/app/modules/hebis/hebis-data.provider.ts
Normal file
104
src/app/modules/hebis/hebis-data.provider.ts
Normal file
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright (C) 2018-2021 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
*
|
||||
* 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 General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {Injectable} from '@angular/core';
|
||||
import {Client} from '@openstapps/api/lib/client';
|
||||
import {SCHebisSearchRequest} from './protocol/request';
|
||||
import {SCHebisSearchResponse} from './protocol/response';
|
||||
import {StorageProvider} from '../storage/storage.provider';
|
||||
import {StAppsWebHttpClient} from '../data/stapps-web-http-client.provider';
|
||||
import {HttpClient} from '@angular/common/http';
|
||||
import {DataProvider} from '../data/data.provider';
|
||||
import {SCHebisSearchRoute} from './protocol/route';
|
||||
|
||||
/**
|
||||
* Generated class for the DataProvider provider.
|
||||
*
|
||||
* See https://angular.io/guide/dependency-injection for more info on providers
|
||||
* and Angular DI.
|
||||
*/
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class HebisDataProvider extends DataProvider {
|
||||
/**
|
||||
* TODO
|
||||
*/
|
||||
storageProvider: StorageProvider;
|
||||
|
||||
httpClient: HttpClient;
|
||||
|
||||
/**
|
||||
* Instance of hebis search request route
|
||||
*/
|
||||
private readonly hebisSearchRoute = new SCHebisSearchRoute();
|
||||
|
||||
/**
|
||||
* TODO
|
||||
*
|
||||
* @param stAppsWebHttpClient TODO
|
||||
* @param storageProvider TODO
|
||||
* @param httpClient TODO
|
||||
*/
|
||||
constructor(
|
||||
stAppsWebHttpClient: StAppsWebHttpClient,
|
||||
storageProvider: StorageProvider,
|
||||
httpClient: HttpClient,
|
||||
) {
|
||||
super(stAppsWebHttpClient, storageProvider);
|
||||
this.storageProvider = storageProvider;
|
||||
this.httpClient = httpClient;
|
||||
this.client = new Client(
|
||||
stAppsWebHttpClient,
|
||||
this.backendUrl,
|
||||
this.appVersion,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a search request to the backend
|
||||
*
|
||||
* All results will be returned if no size is set in the request.
|
||||
*
|
||||
* @param searchRequest Search request
|
||||
*/
|
||||
async hebisSearch(
|
||||
searchRequest: SCHebisSearchRequest,
|
||||
): Promise<SCHebisSearchResponse> {
|
||||
let page: number | undefined = searchRequest.page;
|
||||
|
||||
if (typeof page === 'undefined') {
|
||||
const preFlightResponse =
|
||||
await this.client.invokeRoute<SCHebisSearchResponse>(
|
||||
this.hebisSearchRoute,
|
||||
undefined,
|
||||
{
|
||||
...searchRequest,
|
||||
page: 0,
|
||||
},
|
||||
);
|
||||
|
||||
page = preFlightResponse.pagination.total;
|
||||
}
|
||||
|
||||
return this.client.invokeRoute<SCHebisSearchResponse>(
|
||||
this.hebisSearchRoute,
|
||||
undefined,
|
||||
{
|
||||
...searchRequest,
|
||||
page,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2019 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
*
|
||||
* 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 General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {Component, Input} from '@angular/core';
|
||||
import {SCThings} from '@openstapps/core';
|
||||
|
||||
/**
|
||||
* TODO
|
||||
*/
|
||||
@Component({
|
||||
selector: 'stapps-hebis-detail-content',
|
||||
styleUrls: ['hebis-detail-content.scss'],
|
||||
templateUrl: 'hebis-detail-content.html',
|
||||
})
|
||||
export class HebisDetailContentComponent {
|
||||
/**
|
||||
* TODO
|
||||
*/
|
||||
@Input() item: SCThings;
|
||||
}
|
||||
36
src/app/modules/hebis/hebis-detail/hebis-detail-content.html
Normal file
36
src/app/modules/hebis/hebis-detail/hebis-detail-content.html
Normal file
@@ -0,0 +1,36 @@
|
||||
<div [ngSwitch]="item.type">
|
||||
<stapps-book-detail-content
|
||||
[item]="item"
|
||||
*ngSwitchCase="'book'"
|
||||
></stapps-book-detail-content>
|
||||
<stapps-periodical-detail-content
|
||||
[item]="item"
|
||||
*ngSwitchCase="'periodical'"
|
||||
></stapps-periodical-detail-content>
|
||||
<stapps-hebis-article-content
|
||||
[item]="item"
|
||||
*ngSwitchCase="'article'"
|
||||
></stapps-hebis-article-content>
|
||||
<ng-container *ngSwitchDefault>
|
||||
<ion-item class="ion-text-wrap" lines="inset">
|
||||
<ion-thumbnail slot="start" class="ion-margin-end">
|
||||
<ion-icon color="medium" [attr.name]="item.type | dataIcon"></ion-icon>
|
||||
</ion-thumbnail>
|
||||
<ion-grid>
|
||||
<ion-row>
|
||||
<ion-col>
|
||||
<div class="ion-text-wrap">
|
||||
<h2 class="name">{{ item.name }}</h2>
|
||||
<ion-note>{{ item.type }}</ion-note>
|
||||
</div>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
</ion-grid>
|
||||
</ion-item>
|
||||
<stapps-simple-card
|
||||
*ngIf="item.description"
|
||||
[title]="'description' | propertyNameTranslate: item | titlecase"
|
||||
[content]="'description' | thingTranslate: item"
|
||||
></stapps-simple-card>
|
||||
</ng-container>
|
||||
</div>
|
||||
28
src/app/modules/hebis/hebis-detail/hebis-detail-content.scss
Normal file
28
src/app/modules/hebis/hebis-detail/hebis-detail-content.scss
Normal file
@@ -0,0 +1,28 @@
|
||||
:host ::ng-deep {
|
||||
ion-card {
|
||||
margin: 0;
|
||||
box-shadow: none;
|
||||
ion-card-content {
|
||||
h1 {
|
||||
margin: 0;
|
||||
}
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
ion-card-header {
|
||||
color: var(--ion-color-dark);
|
||||
padding-top: 8px;
|
||||
padding-bottom: 4px;
|
||||
font-weight: bold;
|
||||
}
|
||||
ion-grid, ion-col {
|
||||
padding-inline-start: 0;
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
}
|
||||
ion-grid, ion-col {
|
||||
padding-inline-start: 0;
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
/* eslint-disable @typescript-eslint/no-non-null-assertion,@typescript-eslint/no-explicit-any */
|
||||
/*
|
||||
* Copyright (C) 2018, 2019 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
*
|
||||
* 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 General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {CUSTOM_ELEMENTS_SCHEMA} from '@angular/core';
|
||||
import {ComponentFixture, TestBed, waitForAsync} from '@angular/core/testing';
|
||||
import {ActivatedRoute, RouterModule} from '@angular/router';
|
||||
import {IonRefresher} from '@ionic/angular';
|
||||
import {
|
||||
TranslateLoader,
|
||||
TranslateModule,
|
||||
TranslateService,
|
||||
} from '@ngx-translate/core';
|
||||
import {sampleThingsMap} from '../../../_helpers/data/sample-things';
|
||||
import {HebisRoutingModule} from '../hebis-routing.module';
|
||||
import {HebisModule} from '../hebis.module';
|
||||
import {HebisDataProvider} from '../hebis-data.provider';
|
||||
import {HebisDetailComponent} from './hebis-detail.component';
|
||||
import {Observable, of} from 'rxjs';
|
||||
import {StorageProvider} from '../../storage/storage.provider';
|
||||
|
||||
const translations: any = {data: {detail: {TITLE: 'Foo'}}};
|
||||
|
||||
class TranslateFakeLoader implements TranslateLoader {
|
||||
getTranslation(_lang: string): Observable<any> {
|
||||
return of(translations);
|
||||
}
|
||||
}
|
||||
|
||||
describe('HebisDetailComponent', () => {
|
||||
let comp: HebisDetailComponent;
|
||||
let fixture: ComponentFixture<HebisDetailComponent>;
|
||||
let dataProvider: HebisDataProvider;
|
||||
let refresher: IonRefresher;
|
||||
const sampleThing = sampleThingsMap.book[0];
|
||||
let translateService: TranslateService;
|
||||
|
||||
// @Component({ selector: 'stapps-data-list-item', template: '' })
|
||||
// class DataListItemComponent {
|
||||
// @Input() item;
|
||||
// }
|
||||
|
||||
const fakeActivatedRoute = {
|
||||
snapshot: {
|
||||
paramMap: {
|
||||
get: () => {
|
||||
return sampleThing.uid;
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const storageProviderSpy = jasmine.createSpyObj('StorageProvider', [
|
||||
'init',
|
||||
'get',
|
||||
'has',
|
||||
'put',
|
||||
'search',
|
||||
]);
|
||||
|
||||
beforeEach(
|
||||
waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
RouterModule.forRoot([], {relativeLinkResolution: 'legacy'}),
|
||||
HebisRoutingModule,
|
||||
HebisModule,
|
||||
TranslateModule.forRoot({
|
||||
loader: {provide: TranslateLoader, useClass: TranslateFakeLoader},
|
||||
}),
|
||||
],
|
||||
providers: [
|
||||
{
|
||||
provide: ActivatedRoute,
|
||||
useValue: fakeActivatedRoute,
|
||||
},
|
||||
{
|
||||
provide: StorageProvider,
|
||||
useValue: storageProviderSpy,
|
||||
},
|
||||
],
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||
}).compileComponents();
|
||||
}),
|
||||
);
|
||||
|
||||
beforeEach(async () => {
|
||||
dataProvider = TestBed.get(HebisDataProvider);
|
||||
translateService = TestBed.get(TranslateService);
|
||||
refresher = jasmine.createSpyObj('refresher', ['complete']);
|
||||
spyOn(dataProvider, 'get' as any).and.returnValue(
|
||||
Promise.resolve(sampleThing),
|
||||
);
|
||||
spyOn(HebisDetailComponent.prototype, 'getItem').and.callThrough();
|
||||
fixture = await TestBed.createComponent(HebisDetailComponent);
|
||||
comp = fixture.componentInstance;
|
||||
translateService.use('foo');
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create component', () => expect(comp).toBeDefined());
|
||||
|
||||
it('should get a data item', () => {
|
||||
comp.getItem(sampleThing.uid);
|
||||
expect(HebisDetailComponent.prototype.getItem).toHaveBeenCalledWith(
|
||||
sampleThing.uid,
|
||||
);
|
||||
});
|
||||
|
||||
it('should get a data item when the view is entered', () => {
|
||||
comp.ionViewWillEnter();
|
||||
expect(HebisDetailComponent.prototype.getItem).toHaveBeenCalledWith(
|
||||
sampleThing.uid,
|
||||
);
|
||||
});
|
||||
|
||||
it('should update the data item when refresh is called', async () => {
|
||||
await comp.refresh(refresher);
|
||||
expect(HebisDetailComponent.prototype.getItem).toHaveBeenCalledWith(
|
||||
sampleThing.uid,
|
||||
);
|
||||
expect(refresher.complete).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
83
src/app/modules/hebis/hebis-detail/hebis-detail.component.ts
Normal file
83
src/app/modules/hebis/hebis-detail/hebis-detail.component.ts
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (C) 2018, 2019 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
*
|
||||
* 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 General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {Component} from '@angular/core';
|
||||
import {ActivatedRoute} from '@angular/router';
|
||||
import {Network} from '@ionic-native/network/ngx';
|
||||
import {TranslateService} from '@ngx-translate/core';
|
||||
import {SCUuid} from '@openstapps/core';
|
||||
import {HebisDataProvider} from '../hebis-data.provider';
|
||||
import {FavoritesService} from '../../favorites/favorites.service';
|
||||
import {DataProvider} from '../../data/data.provider';
|
||||
import {DataDetailComponent} from '../../data/detail/data-detail.component';
|
||||
import {SCDaiaHoldings} from '../protocol/response';
|
||||
|
||||
/**
|
||||
* A Component to display an SCThing detailed
|
||||
*/
|
||||
@Component({
|
||||
selector: 'stapps-hebis-detail',
|
||||
styleUrls: ['hebis-detail.scss'],
|
||||
templateUrl: 'hebis-detail.html',
|
||||
})
|
||||
export class HebisDetailComponent extends DataDetailComponent {
|
||||
holdings: SCDaiaHoldings[];
|
||||
|
||||
/**
|
||||
*
|
||||
* @param route the route the page was accessed from
|
||||
* @param dataProvider the data provider
|
||||
* @param network the network provider
|
||||
* @param favoritesService the favorites provider
|
||||
* @param translateService he translate provider
|
||||
* @param hebisDataProvider HebisDataProvider
|
||||
*/
|
||||
constructor(
|
||||
route: ActivatedRoute,
|
||||
dataProvider: DataProvider,
|
||||
network: Network,
|
||||
favoritesService: FavoritesService,
|
||||
translateService: TranslateService,
|
||||
private hebisDataProvider: HebisDataProvider,
|
||||
) {
|
||||
super(route, dataProvider, network, favoritesService, translateService);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if we have internet
|
||||
*/
|
||||
isDisconnected(): boolean {
|
||||
return this.network.type === this.network.Connection.NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize
|
||||
*/
|
||||
async ionViewWillEnter() {
|
||||
const uid = this.route.snapshot.paramMap.get('uid') || '';
|
||||
await this.getItem(uid ?? '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides data item with given UID
|
||||
*
|
||||
* @param uid Unique identifier of a thing
|
||||
*/
|
||||
async getItem(uid: SCUuid) {
|
||||
this.hebisDataProvider.hebisSearch({query: uid, page: 0}).then(result => {
|
||||
// eslint-disable-next-line unicorn/no-null
|
||||
this.item = (result.data && result.data[0]) || null;
|
||||
});
|
||||
}
|
||||
}
|
||||
51
src/app/modules/hebis/hebis-detail/hebis-detail.html
Normal file
51
src/app/modules/hebis/hebis-detail/hebis-detail.html
Normal file
@@ -0,0 +1,51 @@
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-buttons slot="start">
|
||||
<ion-back-button></ion-back-button>
|
||||
<ion-menu-button></ion-menu-button>
|
||||
</ion-buttons>
|
||||
<ion-title>{{ 'data.detail.TITLE' | translate }}</ion-title>
|
||||
<ion-buttons slot="primary">
|
||||
<stapps-favorite-button
|
||||
*ngIf="item"
|
||||
[item]="item"
|
||||
></stapps-favorite-button>
|
||||
</ion-buttons>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
<ion-content class="ion-no-padding">
|
||||
<ion-refresher slot="fixed" (ionRefresh)="refresh($event.target)">
|
||||
<ion-refresher-content
|
||||
pullingIcon="chevron-down-outline"
|
||||
pullingText="{{ 'data.REFRESH_ACTION' | translate }}"
|
||||
refreshingText="{{ 'data.REFRESHING' | translate }}"
|
||||
>
|
||||
</ion-refresher-content>
|
||||
</ion-refresher>
|
||||
<div [ngSwitch]="true">
|
||||
<ng-container *ngSwitchCase="!item && isDisconnected()">
|
||||
<div class="notFoundContainer">
|
||||
<ion-icon name="no-connection"> </ion-icon>
|
||||
<ion-label>
|
||||
{{ 'data.detail.COULD_NOT_CONNECT' | translate }}
|
||||
</ion-label>
|
||||
</div>
|
||||
</ng-container>
|
||||
<ng-container *ngSwitchCase="item === null">
|
||||
<div class="notFoundContainer">
|
||||
<ion-icon name="broken-link"> </ion-icon>
|
||||
<ion-label>
|
||||
{{ 'data.detail.NOT_FOUND' | translate }}
|
||||
</ion-label>
|
||||
</div>
|
||||
</ng-container>
|
||||
<ng-container *ngSwitchCase="!item && item !== null">
|
||||
<stapps-skeleton-list-item></stapps-skeleton-list-item>
|
||||
<stapps-skeleton-simple-card></stapps-skeleton-simple-card>
|
||||
</ng-container>
|
||||
<ng-container *ngSwitchDefault>
|
||||
<stapps-hebis-detail-content [item]="item"></stapps-hebis-detail-content>
|
||||
<stapps-daia-availability *ngIf="item"></stapps-daia-availability>
|
||||
</ng-container>
|
||||
</div>
|
||||
</ion-content>
|
||||
5
src/app/modules/hebis/hebis-detail/hebis-detail.scss
Normal file
5
src/app/modules/hebis/hebis-detail/hebis-detail.scss
Normal file
@@ -0,0 +1,5 @@
|
||||
::ng-deep {
|
||||
ion-card-header {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
32
src/app/modules/hebis/hebis-routing.module.ts
Normal file
32
src/app/modules/hebis/hebis-routing.module.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (C) 2018-2021 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
*
|
||||
* 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 General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {NgModule} from '@angular/core';
|
||||
import {RouterModule, Routes} from '@angular/router';
|
||||
import {HebisDetailComponent} from './hebis-detail/hebis-detail.component';
|
||||
import {HebisSearchPageComponent} from './list/hebis-search-page.component';
|
||||
|
||||
const hebisRoutes: Routes = [
|
||||
{path: 'hebis-search', component: HebisSearchPageComponent},
|
||||
{path: 'hebis-detail/:uid', component: HebisDetailComponent},
|
||||
];
|
||||
|
||||
/**
|
||||
* Module defining routes for data module
|
||||
*/
|
||||
@NgModule({
|
||||
exports: [RouterModule],
|
||||
imports: [RouterModule.forChild(hebisRoutes)],
|
||||
})
|
||||
export class HebisRoutingModule {}
|
||||
100
src/app/modules/hebis/hebis.module.ts
Normal file
100
src/app/modules/hebis/hebis.module.ts
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (C) 2018-2021 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
*
|
||||
* 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 General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {ScrollingModule} from '@angular/cdk/scrolling';
|
||||
import {CommonModule} from '@angular/common';
|
||||
import {HttpClientModule} from '@angular/common/http';
|
||||
import {NgModule} from '@angular/core';
|
||||
import {FormsModule} from '@angular/forms';
|
||||
import {Network} from '@ionic-native/network/ngx';
|
||||
import {IonicModule} from '@ionic/angular';
|
||||
import {TranslateModule} from '@ngx-translate/core';
|
||||
import {MarkdownModule} from 'ngx-markdown';
|
||||
import {MomentModule} from 'ngx-moment';
|
||||
import {ThingTranslateModule} from '../../translation/thing-translate.module';
|
||||
import {MenuModule} from '../menu/menu.module';
|
||||
import {StorageModule} from '../storage/storage.module';
|
||||
import {HebisDetailComponent} from './hebis-detail/hebis-detail.component';
|
||||
import {HebisDetailContentComponent} from './hebis-detail/hebis-detail-content.component';
|
||||
import {HebisSearchPageComponent} from './list/hebis-search-page.component';
|
||||
import {HebisDataProvider} from './hebis-data.provider';
|
||||
import {DaiaDataProvider} from './daia-data.provider';
|
||||
import {StAppsWebHttpClient} from '../data/stapps-web-http-client.provider';
|
||||
import {HebisRoutingModule} from './hebis-routing.module';
|
||||
import {DataModule} from '../data/data.module';
|
||||
|
||||
import {BookDetailContentComponent} from './types/book/book-detail-content.component';
|
||||
import {BookListItemComponent} from './types/book/book-list-item.component';
|
||||
|
||||
import {PeriodicalListItemComponent} from './types/periodical/periodical-list-item.component';
|
||||
import {PeriodicalDetailContentComponent} from './types/periodical/periodical-detail-content.component';
|
||||
import {HebisArticleListItemComponent} from './types/hebis-article/hebis-article-item.component';
|
||||
import {HebisArticleContentComponent} from './types/hebis-article/hebis-article-content.component';
|
||||
import {DataListComponent} from '../data/list/data-list.component';
|
||||
import {DaiaAvailabilityComponent} from './daia-availability/daia-availability.component';
|
||||
|
||||
/**
|
||||
* Module for handling data
|
||||
*/
|
||||
@NgModule({
|
||||
declarations: [
|
||||
HebisSearchPageComponent,
|
||||
HebisDetailComponent,
|
||||
HebisDetailContentComponent,
|
||||
DaiaAvailabilityComponent,
|
||||
BookDetailContentComponent,
|
||||
BookListItemComponent,
|
||||
PeriodicalDetailContentComponent,
|
||||
PeriodicalListItemComponent,
|
||||
HebisArticleListItemComponent,
|
||||
HebisArticleContentComponent,
|
||||
],
|
||||
entryComponents: [DataListComponent],
|
||||
imports: [
|
||||
CommonModule,
|
||||
DataModule,
|
||||
FormsModule,
|
||||
HebisRoutingModule,
|
||||
HttpClientModule,
|
||||
IonicModule.forRoot(),
|
||||
MarkdownModule.forRoot(),
|
||||
MenuModule,
|
||||
MomentModule.forRoot({
|
||||
relativeTimeThresholdOptions: {
|
||||
m: 59,
|
||||
},
|
||||
}),
|
||||
ScrollingModule,
|
||||
StorageModule,
|
||||
TranslateModule.forChild(),
|
||||
ThingTranslateModule.forChild(),
|
||||
],
|
||||
providers: [
|
||||
HebisDataProvider,
|
||||
DaiaDataProvider,
|
||||
Network,
|
||||
StAppsWebHttpClient,
|
||||
],
|
||||
exports: [
|
||||
HebisSearchPageComponent,
|
||||
HebisDetailComponent,
|
||||
HebisDetailContentComponent,
|
||||
DaiaAvailabilityComponent,
|
||||
PeriodicalDetailContentComponent,
|
||||
BookDetailContentComponent,
|
||||
HebisArticleListItemComponent,
|
||||
HebisArticleContentComponent,
|
||||
],
|
||||
})
|
||||
export class HebisModule {}
|
||||
186
src/app/modules/hebis/list/hebis-search-page.component.ts
Normal file
186
src/app/modules/hebis/list/hebis-search-page.component.ts
Normal file
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
* Copyright (C) 2018-2021 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
*
|
||||
* 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 General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {Component, Input, OnInit, OnDestroy} from '@angular/core';
|
||||
import {Router} from '@angular/router';
|
||||
import {AlertController} from '@ionic/angular';
|
||||
import {NGXLogger} from 'ngx-logger';
|
||||
import {combineLatest} from 'rxjs';
|
||||
import {debounceTime, distinctUntilChanged, startWith} from 'rxjs/operators';
|
||||
import {ContextMenuService} from '../../menu/context/context-menu.service';
|
||||
import {SettingsProvider} from '../../settings/settings.provider';
|
||||
import {DataRoutingService} from '../../data/data-routing.service';
|
||||
import {SearchPageComponent} from '../../data/list/search-page.component';
|
||||
import {HebisDataProvider} from '../hebis-data.provider';
|
||||
import {PositionService} from '../../map/position.service';
|
||||
|
||||
/**
|
||||
* HebisSearchPageComponent queries things and shows list of things as search results and filter as context menu
|
||||
*/
|
||||
@Component({
|
||||
selector: 'stapps-hebissearch-page',
|
||||
templateUrl: 'hebis-search-page.html',
|
||||
})
|
||||
export class HebisSearchPageComponent
|
||||
extends SearchPageComponent
|
||||
implements OnInit, OnDestroy
|
||||
{
|
||||
/**
|
||||
* If routing should be done if the user clicks on an item
|
||||
*/
|
||||
@Input() itemRouting? = true;
|
||||
|
||||
/**
|
||||
* Current page to start query
|
||||
*/
|
||||
page = 0;
|
||||
|
||||
/**
|
||||
* Injects the providers and creates subscriptions
|
||||
*
|
||||
* @param alertController AlertController
|
||||
* @param dataProvider HebisProvider
|
||||
* @param contextMenuService ContextMenuService
|
||||
* @param settingsProvider SettingsProvider
|
||||
* @param logger An angular logger
|
||||
* @param dataRoutingService DataRoutingService
|
||||
* @param router Router
|
||||
* @param positionService PositionService
|
||||
*/
|
||||
constructor(
|
||||
protected readonly alertController: AlertController,
|
||||
protected dataProvider: HebisDataProvider,
|
||||
protected readonly contextMenuService: ContextMenuService,
|
||||
protected readonly settingsProvider: SettingsProvider,
|
||||
protected readonly logger: NGXLogger,
|
||||
protected dataRoutingService: DataRoutingService,
|
||||
protected router: Router,
|
||||
protected positionService: PositionService,
|
||||
) {
|
||||
super(
|
||||
alertController,
|
||||
dataProvider,
|
||||
contextMenuService,
|
||||
settingsProvider,
|
||||
logger,
|
||||
dataRoutingService,
|
||||
router,
|
||||
positionService,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches items with set query configuration
|
||||
*
|
||||
* @param append If true fetched data gets appended to existing, override otherwise (default false)
|
||||
*/
|
||||
protected async fetchAndUpdateItems(append = false): Promise<void> {
|
||||
// build query search options
|
||||
const searchOptions: {page: number; query: string} = {
|
||||
page: this.page,
|
||||
query: '',
|
||||
};
|
||||
|
||||
if (this.queryText && this.queryText.length > 0) {
|
||||
// add query string
|
||||
searchOptions.query = this.queryText;
|
||||
}
|
||||
|
||||
return this.dataProvider.hebisSearch(searchOptions).then(
|
||||
async result => {
|
||||
/*this.singleTypeResponse =
|
||||
result.facets.find(facet => facet.field === 'type')?.buckets
|
||||
.length === 1;*/
|
||||
if (append) {
|
||||
let items = await this.items;
|
||||
// append results
|
||||
items = [...items, ...result.data];
|
||||
this.items = (async () => items)();
|
||||
} else {
|
||||
// override items with results
|
||||
this.items = (async () => {
|
||||
return result.data;
|
||||
})();
|
||||
}
|
||||
},
|
||||
async error => {
|
||||
const alert: HTMLIonAlertElement = await this.alertController.create({
|
||||
buttons: ['Dismiss'],
|
||||
header: 'Error',
|
||||
subHeader: error.message,
|
||||
});
|
||||
|
||||
await alert.present();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads next page of things
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
async loadMore(): Promise<void> {
|
||||
this.page += 1;
|
||||
await this.fetchAndUpdateItems(true);
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
//this.fetchAndUpdateItems();
|
||||
this.initialize();
|
||||
|
||||
this.subscriptions.push(
|
||||
combineLatest([
|
||||
this.queryTextChanged.pipe(
|
||||
debounceTime(this.searchQueryDueTime),
|
||||
distinctUntilChanged(),
|
||||
startWith(this.queryText),
|
||||
),
|
||||
]).subscribe(async query => {
|
||||
this.queryText = query[0];
|
||||
this.page = 0;
|
||||
if (this.queryText?.length > 0 || this.showDefaultData) {
|
||||
await this.fetchAndUpdateItems();
|
||||
this.queryChanged.next();
|
||||
}
|
||||
}),
|
||||
this.settingsProvider.settingsActionChanged$.subscribe(
|
||||
({type, payload}) => {
|
||||
if (type === 'stapps.settings.changed') {
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
const {category, name, value} = payload!;
|
||||
this.logger.log(`received event "settings.changed" with category:
|
||||
${category}, name: ${name}, value: ${JSON.stringify(value)}`);
|
||||
}
|
||||
},
|
||||
),
|
||||
this.dataRoutingService.itemSelectListener().subscribe(async item => {
|
||||
if (this.itemRouting) {
|
||||
void this.router.navigate([
|
||||
'hebis-detail',
|
||||
(item.origin &&
|
||||
'originalId' in item.origin &&
|
||||
item.origin['originalId']) ||
|
||||
'',
|
||||
]);
|
||||
}
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
for (const subscription of this.subscriptions) {
|
||||
subscription.unsubscribe();
|
||||
}
|
||||
}
|
||||
}
|
||||
39
src/app/modules/hebis/list/hebis-search-page.html
Normal file
39
src/app/modules/hebis/list/hebis-search-page.html
Normal file
@@ -0,0 +1,39 @@
|
||||
<stapps-context contentId="data-list"></stapps-context>
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-buttons slot="start">
|
||||
<ion-back-button></ion-back-button>
|
||||
<ion-menu-button></ion-menu-button>
|
||||
</ion-buttons>
|
||||
<ion-buttons slot="end">
|
||||
<ion-menu-button menu="context" auto-hide="false">
|
||||
<ion-icon name="options"></ion-icon>
|
||||
</ion-menu-button>
|
||||
</ion-buttons>
|
||||
<ion-searchbar
|
||||
(ngModelChange)="searchStringChanged($event)"
|
||||
[(ngModel)]="queryText"
|
||||
showClearButton="always"
|
||||
placeholder="{{ 'hebisSearch.search_bar.placeholder' | translate }}"
|
||||
>
|
||||
</ion-searchbar>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ion-content>
|
||||
<div
|
||||
[style.display]="!showDefaultData && !items && !loading ? 'block' : 'none'"
|
||||
>
|
||||
<ion-label class="centeredMessageContainer">
|
||||
{{ 'hebisSearch.instruction' | translate }}
|
||||
</ion-label>
|
||||
</div>
|
||||
<stapps-data-list
|
||||
id="data-list"
|
||||
[items]="items | async"
|
||||
[singleType]="singleTypeResponse"
|
||||
(loadmore)="loadMore()"
|
||||
[resetToTop]="queryChanged.asObservable()"
|
||||
[loading]="loading"
|
||||
></stapps-data-list>
|
||||
</ion-content>
|
||||
20
src/app/modules/hebis/protocol/request.ts
Normal file
20
src/app/modules/hebis/protocol/request.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import {SCLicensePlate} from '@openstapps/core';
|
||||
|
||||
export interface SCHebisSearchRequest {
|
||||
/**
|
||||
* HDS2 will supply results for the speficied insitute / university if available (Defaults to f-u)
|
||||
*/
|
||||
institute?: SCLicensePlate;
|
||||
/**
|
||||
* Simple pagination support (Defaults to 0)
|
||||
*/
|
||||
page?: number;
|
||||
/**
|
||||
* Search query for HDS
|
||||
*/
|
||||
query: string;
|
||||
}
|
||||
|
||||
export interface SCDaiaAvailabilityRequest {
|
||||
id: string;
|
||||
}
|
||||
58
src/app/modules/hebis/protocol/response.ts
Normal file
58
src/app/modules/hebis/protocol/response.ts
Normal file
@@ -0,0 +1,58 @@
|
||||
import {
|
||||
SCArticle,
|
||||
SCBook,
|
||||
SCPeriodical,
|
||||
SCSearchResultPagination,
|
||||
} from '@openstapps/core';
|
||||
|
||||
export interface SCHebisSearchResponse {
|
||||
/**
|
||||
* Response Array of SCBook type or Object
|
||||
*/
|
||||
data: Array<SCBook | SCArticle | SCPeriodical>;
|
||||
|
||||
/**
|
||||
* Pagination information
|
||||
*/
|
||||
pagination: SCSearchResultPagination;
|
||||
}
|
||||
|
||||
export interface SCDaiaAvailabilityResponse {
|
||||
document: Array<{
|
||||
item: Array<{
|
||||
id: string;
|
||||
label: string;
|
||||
department: SCDaiaSimpleContent;
|
||||
available: SCDaiaService[];
|
||||
unavailable: SCDaiaService[];
|
||||
debugInfo: string;
|
||||
about?: string;
|
||||
storage?: SCDaiaSimpleContent;
|
||||
}>;
|
||||
}>;
|
||||
institution: SCDaiaSimpleContent;
|
||||
timestamp: string;
|
||||
}
|
||||
|
||||
export interface SCDaiaSimpleContent {
|
||||
id: string;
|
||||
content: string;
|
||||
href?: string;
|
||||
}
|
||||
|
||||
export interface SCDaiaService {
|
||||
delay?: string;
|
||||
href?: string;
|
||||
service: string;
|
||||
limitations?: SCDaiaSimpleContent[];
|
||||
}
|
||||
|
||||
export interface SCDaiaHoldings {
|
||||
id: string;
|
||||
label: string;
|
||||
href?: string;
|
||||
signature: string;
|
||||
storage?: SCDaiaSimpleContent;
|
||||
available?: SCDaiaService;
|
||||
about?: string;
|
||||
}
|
||||
54
src/app/modules/hebis/protocol/route.ts
Normal file
54
src/app/modules/hebis/protocol/route.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
import {
|
||||
SCAbstractRoute,
|
||||
SCRouteHttpVerbs,
|
||||
SCInternalServerErrorResponse,
|
||||
SCMethodNotAllowedErrorResponse,
|
||||
SCRequestBodyTooLargeErrorResponse,
|
||||
SCSyntaxErrorResponse,
|
||||
SCUnsupportedMediaTypeErrorResponse,
|
||||
SCValidationErrorResponse,
|
||||
} from '@openstapps/core';
|
||||
|
||||
/**
|
||||
* Route for searching things
|
||||
*/
|
||||
export class SCHebisSearchRoute extends SCAbstractRoute {
|
||||
constructor() {
|
||||
super();
|
||||
this.errorNames = [
|
||||
SCInternalServerErrorResponse,
|
||||
SCMethodNotAllowedErrorResponse,
|
||||
SCRequestBodyTooLargeErrorResponse,
|
||||
SCSyntaxErrorResponse,
|
||||
SCUnsupportedMediaTypeErrorResponse,
|
||||
SCValidationErrorResponse,
|
||||
];
|
||||
this.method = SCRouteHttpVerbs.POST;
|
||||
this.requestBodyName = 'SCHebisSearchRequest';
|
||||
this.responseBodyName = 'SCHebisSearchResponse';
|
||||
this.statusCodeSuccess = 200;
|
||||
this.urlPath = '/hebissearch';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Route for availability
|
||||
*/
|
||||
export class SCDaiaRoute extends SCAbstractRoute {
|
||||
constructor() {
|
||||
super();
|
||||
this.errorNames = [
|
||||
SCInternalServerErrorResponse,
|
||||
SCMethodNotAllowedErrorResponse,
|
||||
SCRequestBodyTooLargeErrorResponse,
|
||||
SCSyntaxErrorResponse,
|
||||
SCUnsupportedMediaTypeErrorResponse,
|
||||
SCValidationErrorResponse,
|
||||
];
|
||||
this.method = SCRouteHttpVerbs.GET;
|
||||
this.requestBodyName = 'SCDaiaAvailabilityRequest';
|
||||
this.responseBodyName = 'SCDaiaAvailabilityResponse';
|
||||
this.statusCodeSuccess = 200;
|
||||
this.urlPath = '/UB_Frankfurt';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2019 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
*
|
||||
* 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 General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {Component, Input} from '@angular/core';
|
||||
import {SCBook} from '@openstapps/core';
|
||||
|
||||
/**
|
||||
* TODO
|
||||
*/
|
||||
@Component({
|
||||
selector: 'stapps-book-detail-content',
|
||||
templateUrl: 'book-detail-content.html',
|
||||
})
|
||||
export class BookDetailContentComponent {
|
||||
/**
|
||||
* TODO
|
||||
*/
|
||||
@Input() item: SCBook;
|
||||
}
|
||||
82
src/app/modules/hebis/types/book/book-detail-content.html
Normal file
82
src/app/modules/hebis/types/book/book-detail-content.html
Normal file
@@ -0,0 +1,82 @@
|
||||
<ion-card *ngIf="item.sameAs">
|
||||
<ion-card-header>{{
|
||||
'hebisSearch.detail.title' | translate
|
||||
}}</ion-card-header>
|
||||
<ion-card-content>
|
||||
<a [href]="item.sameAs" target="_blank">{{
|
||||
'name' | thingTranslate: item | titlecase
|
||||
}}</a>
|
||||
</ion-card-content>
|
||||
</ion-card>
|
||||
|
||||
<stapps-simple-card
|
||||
*ngIf="!item.sameAs"
|
||||
[title]="'name' | propertyNameTranslate: item | titlecase"
|
||||
[content]="'name' | thingTranslate: item"
|
||||
>
|
||||
</stapps-simple-card>
|
||||
|
||||
<stapps-simple-card
|
||||
*ngIf="item.description"
|
||||
[title]="'hebisSearch.detail.description' | translate"
|
||||
[content]="item.description"
|
||||
></stapps-simple-card>
|
||||
|
||||
<stapps-simple-card
|
||||
*ngIf="item.sourceOrganization"
|
||||
[title]="'sourceOrganization' | propertyNameTranslate: item | titlecase"
|
||||
[content]="item.sourceOrganization"
|
||||
></stapps-simple-card>
|
||||
|
||||
<ion-card *ngIf="item.authors && item.authors.length > 0">
|
||||
<ion-card-header>{{
|
||||
'authors' | propertyNameTranslate: item | titlecase
|
||||
}}</ion-card-header>
|
||||
<ion-card-content>
|
||||
<ion-label *ngFor="let author of item.authors">{{
|
||||
'name' | thingTranslate: author
|
||||
}}</ion-label>
|
||||
</ion-card-content>
|
||||
</ion-card>
|
||||
|
||||
<stapps-simple-card
|
||||
*ngIf="item.ISBNs"
|
||||
[title]="'ISBNs' | propertyNameTranslate: item | titlecase"
|
||||
[content]="item.ISBNs"
|
||||
>
|
||||
</stapps-simple-card>
|
||||
<stapps-simple-card
|
||||
*ngIf="item.firstPublished && !item.lastPublished"
|
||||
[title]="'hebisSearch.detail.firstPublished' | translate"
|
||||
[content]="item.firstPublished"
|
||||
>
|
||||
</stapps-simple-card>
|
||||
<stapps-simple-card
|
||||
*ngIf="item.firstPublished && item.lastPublished"
|
||||
[title]="'hebisSearch.detail.firstPublished' | translate"
|
||||
[content]="[item.firstPublished, item.lastPublished] | join: ' - '"
|
||||
>
|
||||
</stapps-simple-card>
|
||||
<ion-card *ngIf="item.publications">
|
||||
<ion-card-header>{{
|
||||
'publications' | propertyNameTranslate: item | titlecase
|
||||
}}</ion-card-header>
|
||||
<ion-card-content>
|
||||
<p *ngFor="let publication of item.publications">
|
||||
{{ publication.locations | join: ', ' }}
|
||||
{{ publication.locations && publication.publisher ? ':' : '' }}
|
||||
{{ publication.publisher }}
|
||||
</p>
|
||||
</ion-card-content>
|
||||
</ion-card>
|
||||
<ion-card *ngIf="item.categories">
|
||||
<ion-card-header>{{
|
||||
'categories' | propertyNameTranslate: item | titlecase
|
||||
}}</ion-card-header>
|
||||
<ion-card-content>
|
||||
<ion-chip [attr.color]="'primary'">
|
||||
<ion-icon [attr.name]="item.type | dataIcon"></ion-icon>
|
||||
<ion-label>{{ 'categories' | thingTranslate: item }}</ion-label>
|
||||
</ion-chip>
|
||||
</ion-card-content>
|
||||
</ion-card>
|
||||
31
src/app/modules/hebis/types/book/book-list-item.component.ts
Normal file
31
src/app/modules/hebis/types/book/book-list-item.component.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2019 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
*
|
||||
* 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 General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {Component, Input} from '@angular/core';
|
||||
import {SCBook} from '@openstapps/core';
|
||||
import {DataListItemComponent} from '../../../data/list/data-list-item.component';
|
||||
|
||||
/**
|
||||
* TODO
|
||||
*/
|
||||
@Component({
|
||||
selector: 'stapps-book-list-item',
|
||||
templateUrl: 'book-list-item.html',
|
||||
})
|
||||
export class BookListItemComponent extends DataListItemComponent {
|
||||
/**
|
||||
* TODO
|
||||
*/
|
||||
@Input() item: SCBook;
|
||||
}
|
||||
16
src/app/modules/hebis/types/book/book-list-item.html
Normal file
16
src/app/modules/hebis/types/book/book-list-item.html
Normal file
@@ -0,0 +1,16 @@
|
||||
<ion-grid>
|
||||
<ion-row>
|
||||
<ion-col>
|
||||
<h2 class="name">{{ 'name' | thingTranslate: item }}</h2>
|
||||
<p *ngIf="item.keywords">
|
||||
<stapps-long-inline-text
|
||||
[text]="item.keywords.join(', ')"
|
||||
[size]="110"
|
||||
></stapps-long-inline-text>
|
||||
</p>
|
||||
<ion-note>
|
||||
{{ 'type' | thingTranslate: item }}
|
||||
</ion-note>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
</ion-grid>
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2019 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
*
|
||||
* 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 General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {Component, Input} from '@angular/core';
|
||||
import {SCArticle} from '@openstapps/core';
|
||||
|
||||
/**
|
||||
* TODO
|
||||
*/
|
||||
@Component({
|
||||
selector: 'stapps-hebis-article-content',
|
||||
templateUrl: 'hebis-article-content.html',
|
||||
})
|
||||
export class HebisArticleContentComponent {
|
||||
/**
|
||||
* TODO
|
||||
*/
|
||||
@Input() item: SCArticle;
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
<ion-card *ngIf="item.sameAs">
|
||||
<ion-card-header>{{
|
||||
'hebisSearch.detail.title' | translate
|
||||
}}</ion-card-header>
|
||||
<ion-card-content>
|
||||
<a [href]="item.sameAs" target="_blank">{{
|
||||
'name' | thingTranslate: item | titlecase
|
||||
}}</a>
|
||||
</ion-card-content>
|
||||
</ion-card>
|
||||
|
||||
<stapps-simple-card
|
||||
*ngIf="!item.sameAs"
|
||||
[title]="'name' | propertyNameTranslate: item | titlecase"
|
||||
[content]="'name' | thingTranslate: item"
|
||||
>
|
||||
</stapps-simple-card>
|
||||
|
||||
<stapps-simple-card
|
||||
*ngIf="item.description"
|
||||
[title]="'hebisSearch.detail.description' | translate"
|
||||
[content]="item.description"
|
||||
></stapps-simple-card>
|
||||
|
||||
<stapps-simple-card
|
||||
*ngIf="item.sourceOrganization"
|
||||
[title]="'sourceOrganization' | propertyNameTranslate: item | titlecase"
|
||||
[content]="item.sourceOrganization"
|
||||
></stapps-simple-card>
|
||||
|
||||
<ion-card *ngIf="item.authors && item.authors.length > 0">
|
||||
<ion-card-header>{{
|
||||
'authors' | propertyNameTranslate: item | titlecase
|
||||
}}</ion-card-header>
|
||||
<ion-card-content>
|
||||
<ion-label *ngFor="let author of item.authors">{{
|
||||
'name' | thingTranslate: author
|
||||
}}</ion-label>
|
||||
</ion-card-content>
|
||||
</ion-card>
|
||||
|
||||
<stapps-simple-card
|
||||
*ngIf="item.firstPublished && !item.lastPublished"
|
||||
[title]="'hebisSearch.detail.firstPublished' | translate"
|
||||
[content]="item.firstPublished"
|
||||
>
|
||||
</stapps-simple-card>
|
||||
<stapps-simple-card
|
||||
*ngIf="item.firstPublished && item.lastPublished"
|
||||
[title]="'hebisSearch.detail.firstPublished' | translate"
|
||||
[content]="[item.firstPublished, item.lastPublished] | join: ' - '"
|
||||
>
|
||||
</stapps-simple-card>
|
||||
<ion-card *ngIf="item.publications">
|
||||
<ion-card-header>{{
|
||||
'publications' | propertyNameTranslate: item | titlecase
|
||||
}}</ion-card-header>
|
||||
<ion-card-content>
|
||||
<p *ngFor="let publication of item.publications">
|
||||
{{ publication.locations | join: ', ' }}
|
||||
{{ publication.locations && publication.publisher ? ':' : '' }}
|
||||
{{ publication.publisher }}
|
||||
</p>
|
||||
</ion-card-content>
|
||||
</ion-card>
|
||||
<ion-card *ngIf="item.categories">
|
||||
<ion-card-header>{{
|
||||
'categories' | propertyNameTranslate: item | titlecase
|
||||
}}</ion-card-header>
|
||||
<ion-card-content>
|
||||
<ion-chip [attr.color]="'primary'">
|
||||
<ion-icon [attr.name]="item.type | dataIcon"></ion-icon>
|
||||
<ion-label>{{ 'categories' | thingTranslate: item }}</ion-label>
|
||||
</ion-chip>
|
||||
</ion-card-content>
|
||||
</ion-card>
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2019 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
*
|
||||
* 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 General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {Component, Input} from '@angular/core';
|
||||
import {SCArticle} from '@openstapps/core';
|
||||
import {DataListItemComponent} from '../../../data/list/data-list-item.component';
|
||||
|
||||
/**
|
||||
* TODO
|
||||
*/
|
||||
@Component({
|
||||
selector: 'stapps-hebis-article-item',
|
||||
templateUrl: 'hebis-article-item.html',
|
||||
})
|
||||
export class HebisArticleListItemComponent extends DataListItemComponent {
|
||||
/**
|
||||
* TODO
|
||||
*/
|
||||
@Input() item: SCArticle;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<ion-grid>
|
||||
<ion-row>
|
||||
<ion-col>
|
||||
<h2 class="name">{{ 'name' | thingTranslate: item }}</h2>
|
||||
<p *ngIf="item.keywords">
|
||||
<stapps-long-inline-text
|
||||
[text]="item.keywords.join(', ')"
|
||||
[size]="110"
|
||||
></stapps-long-inline-text>
|
||||
</p>
|
||||
<ion-note>
|
||||
{{ 'type' | thingTranslate: item }}
|
||||
</ion-note>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
</ion-grid>
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2019 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
*
|
||||
* 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 General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {Component, Input} from '@angular/core';
|
||||
import {SCPeriodical} from '@openstapps/core';
|
||||
|
||||
/**
|
||||
* TODO
|
||||
*/
|
||||
@Component({
|
||||
selector: 'stapps-periodical-detail-content',
|
||||
templateUrl: 'periodical-detail-content.html',
|
||||
})
|
||||
export class PeriodicalDetailContentComponent {
|
||||
/**
|
||||
* TODO
|
||||
*/
|
||||
@Input() item: SCPeriodical;
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
<ion-card *ngIf="item.sameAs">
|
||||
<ion-card-header>{{
|
||||
'hebisSearch.detail.title' | translate
|
||||
}}</ion-card-header>
|
||||
<ion-card-content>
|
||||
<a [href]="item.sameAs" target="_blank">{{
|
||||
'name' | thingTranslate: item | titlecase
|
||||
}}</a>
|
||||
</ion-card-content>
|
||||
</ion-card>
|
||||
|
||||
<stapps-simple-card
|
||||
*ngIf="!item.sameAs"
|
||||
[title]="'name' | propertyNameTranslate: item | titlecase"
|
||||
[content]="'name' | thingTranslate: item"
|
||||
>
|
||||
</stapps-simple-card>
|
||||
|
||||
<stapps-simple-card
|
||||
*ngIf="item.description"
|
||||
[title]="'hebisSearch.detail.description' | translate"
|
||||
[content]="item.description"
|
||||
></stapps-simple-card>
|
||||
|
||||
<stapps-simple-card
|
||||
*ngIf="item.sourceOrganization"
|
||||
[title]="'sourceOrganization' | propertyNameTranslate: item | titlecase"
|
||||
[content]="item.sourceOrganization"
|
||||
></stapps-simple-card>
|
||||
|
||||
<ion-card *ngIf="item.authors && item.authors.length > 0">
|
||||
<ion-card-header>{{
|
||||
'authors' | propertyNameTranslate: item | titlecase
|
||||
}}</ion-card-header>
|
||||
<ion-card-content>
|
||||
<ion-label *ngFor="let author of item.authors">{{
|
||||
'name' | thingTranslate: author
|
||||
}}</ion-label>
|
||||
</ion-card-content>
|
||||
</ion-card>
|
||||
|
||||
<stapps-simple-card
|
||||
*ngIf="item.firstPublished && !item.lastPublished"
|
||||
[title]="'hebisSearch.detail.firstPublished' | translate"
|
||||
[content]="item.firstPublished"
|
||||
>
|
||||
</stapps-simple-card>
|
||||
<stapps-simple-card
|
||||
*ngIf="item.firstPublished && item.lastPublished"
|
||||
[title]="'hebisSearch.detail.firstPublished' | translate"
|
||||
[content]="[item.firstPublished, item.lastPublished] | join: ' - '"
|
||||
>
|
||||
</stapps-simple-card>
|
||||
<ion-card *ngIf="item.publications">
|
||||
<ion-card-header>{{
|
||||
'publications' | propertyNameTranslate: item | titlecase
|
||||
}}</ion-card-header>
|
||||
<ion-card-content>
|
||||
<p *ngFor="let publication of item.publications">
|
||||
{{ publication.locations | join: ', ' }}
|
||||
{{ publication.locations && publication.publisher ? ':' : '' }}
|
||||
{{ publication.publisher }}
|
||||
</p>
|
||||
</ion-card-content>
|
||||
</ion-card>
|
||||
<ion-card *ngIf="item.categories">
|
||||
<ion-card-header>{{
|
||||
'categories' | propertyNameTranslate: item | titlecase
|
||||
}}</ion-card-header>
|
||||
<ion-card-content>
|
||||
<ion-chip [attr.color]="'primary'">
|
||||
<ion-icon [attr.name]="item.type | dataIcon"></ion-icon>
|
||||
<ion-label>{{ 'categories' | thingTranslate: item }}</ion-label>
|
||||
</ion-chip>
|
||||
</ion-card-content>
|
||||
</ion-card>
|
||||
<stapps-simple-card
|
||||
*ngIf="item.ISSNs"
|
||||
[title]="'hebisSearch.detail.issn' | translate"
|
||||
[content]="item.ISSNs | join: ', '"
|
||||
>
|
||||
</stapps-simple-card>
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2019 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
*
|
||||
* 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 General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {Component, Input} from '@angular/core';
|
||||
import {SCPeriodical} from '@openstapps/core';
|
||||
import {DataListItemComponent} from '../../../data/list/data-list-item.component';
|
||||
|
||||
/**
|
||||
* TODO
|
||||
*/
|
||||
@Component({
|
||||
selector: 'stapps-periodical-list-item',
|
||||
templateUrl: 'periodical-list-item.html',
|
||||
})
|
||||
export class PeriodicalListItemComponent extends DataListItemComponent {
|
||||
/**
|
||||
* TODO
|
||||
*/
|
||||
@Input() item: SCPeriodical;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<ion-grid>
|
||||
<ion-row>
|
||||
<ion-col>
|
||||
<h2 class="name">{{ 'name' | thingTranslate: item }}</h2>
|
||||
<p *ngIf="item.keywords">
|
||||
<stapps-long-inline-text
|
||||
[text]="item.keywords.join(', ')"
|
||||
[size]="110"
|
||||
></stapps-long-inline-text>
|
||||
</p>
|
||||
<ion-note>
|
||||
{{ 'type' | thingTranslate: item }}
|
||||
</ion-note>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
</ion-grid>
|
||||
@@ -49,6 +49,7 @@ export class NavigationComponent implements OnInit {
|
||||
*/
|
||||
public pages = [
|
||||
{title: 'Search', url: '/search', icon: 'search'},
|
||||
{title: 'Hebis Search', url: '/hebis-search', icon: 'search'},
|
||||
{title: 'Schedule', url: '/schedule', icon: 'calendar'},
|
||||
{title: 'Settings', url: '/settings', icon: 'settings'},
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user