Skip to content

Commit

Permalink
use record resouce and use route resolvers
Browse files Browse the repository at this point in the history
* Referencing inspirehep#307
  • Loading branch information
harunurhan committed Jan 26, 2018
1 parent 3d4f06a commit f58c445
Show file tree
Hide file tree
Showing 11 changed files with 177 additions and 74 deletions.
19 changes: 12 additions & 7 deletions src/app/core/services/record-api.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,14 @@ import { Observable } from 'rxjs/Observable';
import { environment } from '../../../environments/environment';
import { AppConfigService } from './app-config.service';
import { CommonApiService } from './common-api.service';
import { Ticket, RecordRevision } from '../../shared/interfaces';
import { Ticket, RecordRevision, RecordResources } from '../../shared/interfaces';
import { ApiError } from '../../shared/classes';
import { editorApiUrl, apiUrl } from '../../shared/config';

@Injectable()
export class RecordApiService extends CommonApiService {

private currentRecordApiUrl: string;
private currentRecordSaveApiUrl: string;
private currentRecordEditorApiUrl: string;
private currentRecordId: string;

Expand All @@ -55,17 +55,21 @@ export class RecordApiService extends CommonApiService {
.toPromise();
}

fetchRecord(pidType: string, pidValue: string): Promise<Object> {
fetchRecordResources(pidType: string, pidValue: string): Observable<RecordResources> {
this.currentRecordId = pidValue;
this.currentRecordApiUrl = `${apiUrl}/${pidType}/${pidValue}/db`;
this.currentRecordSaveApiUrl = `${apiUrl}/${pidType}/${pidValue}/db`;
this.currentRecordEditorApiUrl = `${editorApiUrl}/${pidType}/${pidValue}`;
this.newRecordFetched$.next(null);
return this.fetchUrl(this.currentRecordApiUrl);
return this.http
.get(this.currentRecordEditorApiUrl)
.map(res => res.json())
.catch(error => Observable.throw(new ApiError(error)));

}

saveRecord(record: object): Observable<void> {
return this.http
.put(this.currentRecordApiUrl, record)
.put(this.currentRecordSaveApiUrl, record)
.catch(error => Observable.throw(new ApiError(error)));
}

Expand Down Expand Up @@ -125,7 +129,8 @@ export class RecordApiService extends CommonApiService {
return this.http
.get(`${apiUrl}/${recordType}/?q=${query}&size=200`, { headers: this.returnOnlyIdsHeaders })
.map(res => res.json())
.map(json => json.hits.recids);
.map(json => json.hits.recids)
.catch(error => Observable.throw(new ApiError(error)));
}

preview(record: object): Promise<string> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,13 @@
*/

import { Component, Input, OnInit, OnChanges, SimpleChanges, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { ActivatedRoute, Router } from '@angular/router';
import { SchemaValidationProblems } from 'ng2-json-editor';
import { ToastrService } from 'ngx-toastr';

import { RecordApiService, AppConfigService, DomUtilsService, GlobalAppStateService } from '../../core/services';
import { SubscriberComponent } from '../../shared/classes';
import { RecordResources } from '../../shared/interfaces';
import { SubscriberComponent, ApiError } from '../../shared/classes';

@Component({
selector: 're-json-editor-wrapper',
Expand All @@ -47,6 +48,7 @@ export class JsonEditorWrapperComponent extends SubscriberComponent implements O
revision: object | undefined;

constructor(private changeDetectorRef: ChangeDetectorRef,
private router: Router,
private route: ActivatedRoute,
private apiService: RecordApiService,
private appConfigService: AppConfigService,
Expand All @@ -58,9 +60,19 @@ export class JsonEditorWrapperComponent extends SubscriberComponent implements O

ngOnChanges(changes: SimpleChanges) {
if ((changes['recordId'] || changes['recordType']) && this.recordId && this.recordType) {
// component loaded and being used by record-search
// component loaded and being used by record-search, not router
this.record = undefined; // don't display old record while new is loading
this.fetch(this.recordType, this.recordId);
this.apiService
.fetchRecordResources(this.recordType, this.recordId)
.subscribe(resources => {
this.assignResourcesToProperties(resources);
}, (error: ApiError) => {
if (error.status === 403) {
this.toastrService.error(`Logged in user can not access to the record: ${this.recordType}/${this.recordId}`, 'Forbidden');
} else {
this.toastrService.error('Could not load the record!', 'Error');
}
});
}
}

Expand All @@ -69,13 +81,12 @@ export class JsonEditorWrapperComponent extends SubscriberComponent implements O
this.domUtilsService.fitEditorHeightFullPageOnResize();
this.domUtilsService.fitEditorHeightFullPage();

if (!this.recordId || !this.recordType) {
// component loaded via router, @Input() aren't passed
this.route.params
.filter(params => params['recid'])
if (!this.recordId && !this.recordType) {
// component loaded via router, if @Input() aren't passed
this.route.data
.takeUntil(this.isDestroyed)
.subscribe(params => {
this.fetch(params['type'], params['recid']);
.subscribe((data: { resources: RecordResources }) => {
this.assignResourcesToProperties(data.resources);
});
}

Expand All @@ -87,6 +98,15 @@ export class JsonEditorWrapperComponent extends SubscriberComponent implements O
});
}

private assignResourcesToProperties(resources: RecordResources) {
this.record = resources.record;
this.globalAppStateService.jsonBeingEdited$.next(this.record);
this.globalAppStateService.isJsonUpdated$.next(false);
this.config = this.appConfigService.getConfigForRecord(this.record);
this.schema = resources.schema;
this.changeDetectorRef.markForCheck();
}

onRecordChange(record: object) {
// update record if the edited one is not revision.
if (!this.revision) {
Expand Down Expand Up @@ -115,44 +135,4 @@ export class JsonEditorWrapperComponent extends SubscriberComponent implements O
this.globalAppStateService
.validationProblems$.next(problems);
}

/**
* Performs api calls for a single record to be loaded
* and __assigns__ fetched data to class properties
*
* - checks permission
* - fetches record
* - fetches schema
*
* - shows toast message when any call fails
*/
private fetch(recordType: string, recordId: string) {
let loadingToastId;
this.apiService.checkEditorPermission(recordType, recordId)
.then(() => {
// TODO: move toast call out of then after https://github.com/angular/angular/pull/18352
loadingToastId = this.toastrService.info(
`Loading ${recordType}/${recordId}`, 'Wait').toastId;
return this.apiService.fetchRecord(recordType, recordId);
}).then(json => {
this.record = json['metadata'];
this.globalAppStateService
.jsonBeingEdited$.next(this.record);
this.globalAppStateService
.isJsonUpdated$.next(false);
this.config = this.appConfigService.getConfigForRecord(this.record);
return this.apiService.fetchUrl(this.record['$schema']);
}).then(schema => {
this.toastrService.clear(loadingToastId);
this.schema = schema;
this.changeDetectorRef.markForCheck();
}).catch(error => {
this.toastrService.clear(loadingToastId);
if (error.status === 403) {
this.toastrService.error(`Logged in user can not access to the record: ${recordType}/${recordId}`, 'Forbidden');
} else {
this.toastrService.error('Could not load the record!', 'Error');
}
});
}
}
21 changes: 18 additions & 3 deletions src/app/record-editor/record-editor.router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,34 @@ import { NgModule } from '@angular/core';

import { RecordSearchComponent } from './record-search';
import { JsonEditorWrapperComponent } from './json-editor-wrapper';
import { RecordResourcesResolver } from './record-resources.resolver';
import { RecordSearchResolver } from './record-search.resolver';


const recordEditorRoutes: Routes = [
{ path: ':type/search', component: RecordSearchComponent },
{ path: ':type/:recid', component: JsonEditorWrapperComponent }
{
path: ':type/search',
component: RecordSearchComponent,
resolve: { recids: RecordSearchResolver },
runGuardsAndResolvers: 'paramsOrQueryParamsChange'
},
{
path: ':type/:recid',
component: JsonEditorWrapperComponent,
resolve: { resources: RecordResourcesResolver }
}
];

@NgModule({
imports: [
RouterModule.forChild(recordEditorRoutes)
],
exports: [
RouterModule,
RouterModule
],
providers: [
RecordResourcesResolver,
RecordSearchResolver
]
})
export class RecordEditorRouter { }
46 changes: 46 additions & 0 deletions src/app/record-editor/record-resources.resolver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* This file is part of record-editor.
* Copyright (C) 2018 CERN.
*
* record-editor 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; either version 2 of the
* License, or (at your option) any later version.
*
* record-editor 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 record-editor; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
* In applying this license, CERN does not
* waive the privileges and immunities granted to it by virtue of its status
* as an Intergovernmental Organization or submit itself to any jurisdiction.
*/

import { Resolve, ActivatedRouteSnapshot, Router } from '@angular/router';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';

import { RecordApiService } from '../core/services';
import { RecordResources } from '../shared/interfaces';
import { ApiError } from '../shared/classes';

@Injectable()
export class RecordResourcesResolver implements Resolve<RecordResources> {
constructor(private router: Router,
private apiService: RecordApiService) { }

resolve(route: ActivatedRouteSnapshot): Observable<RecordResources> {
const params = route.params;
return this.apiService
.fetchRecordResources(params.type, params.recid)
.take(1)
.catch((error: ApiError) => {
this.router.navigate(['error', error.status]);
return null;
});
}
}
50 changes: 50 additions & 0 deletions src/app/record-editor/record-search.resolver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* This file is part of record-editor.
* Copyright (C) 2018 CERN.
*
* record-editor 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; either version 2 of the
* License, or (at your option) any later version.
*
* record-editor 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 record-editor; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
* In applying this license, CERN does not
* waive the privileges and immunities granted to it by virtue of its status
* as an Intergovernmental Organization or submit itself to any jurisdiction.
*/

import { Resolve, ActivatedRouteSnapshot, Router } from '@angular/router';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';

import { RecordResourcesResolver } from './record-resources.resolver';
import { RecordSearchService } from '../core/services';
import { RecordResources } from '../shared/interfaces';
import { ApiError } from '../shared/classes';

@Injectable()
export class RecordSearchResolver implements Resolve<Array<number>> {
constructor(private router: Router,
private recordSearchService: RecordSearchService) { }

resolve(route: ActivatedRouteSnapshot): Observable<Array<number>> {
if (!route.queryParams.query) {
return Observable.of([]);
}

return this.recordSearchService
.search(route.params.type, route.queryParams.query)
.take(1)
.catch((error: ApiError) => {
this.router.navigate(['error', error.status]);
return null;
});
}
}
22 changes: 10 additions & 12 deletions src/app/record-editor/record-search/record-search.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ interface RouteType {
export class RecordSearchComponent extends SubscriberComponent implements OnInit {

recordType: string;
recordCursor: number;
recordCursor = 0;
foundRecordIds: Array<number>;

constructor(private route: ActivatedRoute,
Expand All @@ -60,18 +60,16 @@ export class RecordSearchComponent extends SubscriberComponent implements OnInit
this.changeDetectorRef.markForCheck();
});

const searchSub = Observable.combineLatest(
this.route.params,
this.route.queryParams,
(params, queryParams) => {
return { params, queryParams };
}).do((route: RouteType) => {
this.recordType = route.params.type;
}).filter((route: RouteType) => Boolean(route.queryParams.query))
.switchMap((route: RouteType) => this.recordSearchService.search(route.params.type, route.queryParams.query))
this.route.params
.takeUntil(this.isDestroyed)
.subscribe(recordIds => {
this.foundRecordIds = recordIds;
.subscribe(params => {
this.recordType = params.type;
});

this.route.data
.takeUntil(this.isDestroyed)
.subscribe((data: { recids: Array<number> }) => {
this.foundRecordIds = data.recids;
this.changeDetectorRef.markForCheck();
});
}
Expand Down
4 changes: 2 additions & 2 deletions src/app/record-editor/search-bar/search-bar.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,9 @@ export class SearchBarComponent extends SubscriberComponent implements OnInit {
const query = this.query;
const isQueryNumber = !isNaN(+query);
if (isQueryNumber) {
this.router.navigate([`${this.recordType}/${query}`]);
this.router.navigate(['record', this.recordType, query]);
} else {
this.router.navigate([`${this.recordType}/search`], { queryParams: { query } });
this.router.navigate(['record', this.recordType, 'search'], { queryParams: { query } });
}
}

Expand Down
1 change: 1 addition & 0 deletions src/app/shared/interfaces/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ export { RecordRevision } from './record-revision';
export { SearchParams } from './search-params';
export { SavePreviewModalOptions } from './save-preview-modal-options';
export { AuthorExtractResult } from './author-extract-result';
export { RecordResources } from './record-resources';
6 changes: 6 additions & 0 deletions src/app/shared/interfaces/record-resources.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { JSONSchema } from 'ng2-json-editor';

export interface RecordResources {
schema: JSONSchema;
record: object;
}
1 change: 1 addition & 0 deletions src/app/shared/interfaces/search-params.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export interface SearchParams {
query: string;
cursor?: number;
}
1 change: 1 addition & 0 deletions src/polyfills.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,6 @@ import 'rxjs/add/operator/do';
import 'rxjs/add/operator/first';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/switchMap';
import 'rxjs/add/operator/take';
import 'rxjs/add/operator/takeUntil';
import 'rxjs/add/operator/toPromise';

0 comments on commit f58c445

Please sign in to comment.