From f8c5cf5694a29a8c4bb63011ad01e30c96386de8 Mon Sep 17 00:00:00 2001 From: harunurhan Date: Fri, 24 Mar 2017 10:59:53 +0100 Subject: [PATCH] add local stroge backup * Fixes #120. Saves current version of data before window/tab is closed by the its url from where it was fetched earlier. And check before fetching a data if it exists on local stroge. Finally clear the data if it is save successfully. * Refactors api.service. --- package.json | 1 + src/app/app.module.ts | 4 +- .../editor-container.component.ts | 7 ++- ...ditor-holdingpen-toolbar-save.component.ts | 2 +- .../editor-holdingpen.component.ts | 7 ++- .../editor-toolbar-save.component.ts | 2 +- src/app/shared/services/api.service.ts | 43 +++++++++++-------- 7 files changed, 42 insertions(+), 24 deletions(-) diff --git a/package.json b/package.json index 6d38657..378dc22 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ "font-awesome": "^4.7.0", "lodash": "4.17.2", "ng2-json-editor": "~0.6.0", + "ng2-webstorage": "^1.5.1", "rxjs": "^5.0.1", "ts-helpers": "^1.1.1", "zone.js": "^0.7.2" diff --git a/src/app/app.module.ts b/src/app/app.module.ts index de725eb..9526181 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -4,6 +4,7 @@ import { APP_BASE_HREF } from '@angular/common'; import { HttpModule } from '@angular/http'; import { JsonEditorModule } from 'ng2-json-editor'; +import { Ng2Webstorage } from 'ng2-webstorage'; import { AppComponent } from './app.component'; import { EditorHoldingPenComponent } from './editor-holdingpen'; @@ -31,7 +32,8 @@ import { AppConfigService } from './app-config.service'; BrowserModule, HttpModule, routing, - JsonEditorModule + JsonEditorModule, + Ng2Webstorage ], providers: [ { provide: APP_BASE_HREF, useValue: '/editor' }, diff --git a/src/app/editor-container/editor-container.component.ts b/src/app/editor-container/editor-container.component.ts index f9bd5e0..dea9e4c 100644 --- a/src/app/editor-container/editor-container.component.ts +++ b/src/app/editor-container/editor-container.component.ts @@ -24,7 +24,6 @@ import { Component, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { ApiService } from '../shared/services'; - import { AppConfigService } from '../app-config.service'; @Component({ @@ -47,7 +46,11 @@ export class EditorContainerComponent implements OnInit { .subscribe(params => { this.apiService.fetchRecord(params['type'], params['recid']) .then(record => { - this.record = record['metadata']; + // load record.metadata or record (if it is from local storage) + this.record = record['metadata'] || record; + window.onbeforeunload = () => { + this.apiService.saveDataLocally(this.record); + }; this.config = this.appConfig.getConfigForRecord(this.record); return this.apiService.fetchUrl(this.record['$schema']); }).then(schema => { diff --git a/src/app/editor-holdingpen-toolbar/editor-holdingpen-toolbar-save/editor-holdingpen-toolbar-save.component.ts b/src/app/editor-holdingpen-toolbar/editor-holdingpen-toolbar-save/editor-holdingpen-toolbar-save.component.ts index a409e38..8439e32 100644 --- a/src/app/editor-holdingpen-toolbar/editor-holdingpen-toolbar-save/editor-holdingpen-toolbar-save.component.ts +++ b/src/app/editor-holdingpen-toolbar/editor-holdingpen-toolbar-save/editor-holdingpen-toolbar-save.component.ts @@ -34,7 +34,7 @@ export class EditorHoldingPenToolbarSaveComponent { constructor(private apiService: ApiService) { } onClickSave(event: Object) { - this.apiService.saveWorkflowObject(this.workflowObject) + this.apiService.saveData(this.workflowObject) .subscribe(resp => { window.location.href = `/holdingpen/${this.workflowObject.id}`; }); diff --git a/src/app/editor-holdingpen/editor-holdingpen.component.ts b/src/app/editor-holdingpen/editor-holdingpen.component.ts index 30a885e..abf5e56 100644 --- a/src/app/editor-holdingpen/editor-holdingpen.component.ts +++ b/src/app/editor-holdingpen/editor-holdingpen.component.ts @@ -23,9 +23,9 @@ import { Component, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; -import { ApiService } from '../shared/services'; import 'rxjs/add/operator/mergeMap'; +import { ApiService } from '../shared/services'; import { AppConfigService } from '../app-config.service'; @Component({ @@ -49,12 +49,17 @@ export class EditorHoldingPenComponent implements OnInit { this.apiService.fetchWorkflowObject(params['objectid']) .then(workflowObject => { this.workflowObject = workflowObject; + window.onbeforeunload = () => { + this.apiService.saveDataLocally(this.workflowObject); + }; this.config = this.appConfig.getConfigForRecord(this.workflowObject['metadata']); return this.apiService.fetchUrl(this.workflowObject['metadata']['$schema']); }).then(schema => { this.schema = schema; + }).catch(error => console.error(error)); }); + } onRecordChange(record: Object) { diff --git a/src/app/editor-toolbar/editor-toolbar-save/editor-toolbar-save.component.ts b/src/app/editor-toolbar/editor-toolbar-save/editor-toolbar-save.component.ts index c6bb61e..1d0c119 100644 --- a/src/app/editor-toolbar/editor-toolbar-save/editor-toolbar-save.component.ts +++ b/src/app/editor-toolbar/editor-toolbar-save/editor-toolbar-save.component.ts @@ -54,7 +54,7 @@ export class EditorToolbarSaveComponent { bodyHtml: this.domSanitizer.bypassSecurityTrustHtml(''), type: 'confirm', onConfirm: () => { - this.apiService.saveRecord(this.record).subscribe({ + this.apiService.saveData(this.record).subscribe({ next: () => { this.route.params .subscribe(params => { diff --git a/src/app/shared/services/api.service.ts b/src/app/shared/services/api.service.ts index 13009c2..4a322f8 100644 --- a/src/app/shared/services/api.service.ts +++ b/src/app/shared/services/api.service.ts @@ -22,21 +22,22 @@ import { Injectable } from '@angular/core'; import { Http } from '@angular/http'; + import { Observable } from 'rxjs/Observable'; import 'rxjs/add/operator/map'; import 'rxjs/add/operator/toPromise'; + import { AppConfigService } from '../../app-config.service'; +import { LocalStorageService } from 'ng2-webstorage'; @Injectable() export class ApiService { - // pid_type and pid_value (see invenio-pidstore) - private pidType: string; - private pidValue: string; - // workflow object id (see invenio-workflows) - private objectId: string; - constructor(private http: Http, private config: AppConfigService) { - } + private dataUrl: string; + + constructor(private http: Http, + private config: AppConfigService, + private localStorageService: LocalStorageService) { } fetchUrl(url: string): Promise { return this.http.get(url) @@ -44,26 +45,32 @@ export class ApiService { .toPromise(); } + private fetchFromUrlOrLocalStorage(url: string): Promise { + this.dataUrl = url; + let localCopy = this.localStorageService.retrieve(url); + if (localCopy && confirm('There is a local copy for this record, do you want to recover?')) { + return Promise.resolve(localCopy); + } else { + return this.fetchUrl(url); + } + } + fetchRecord(pidType: string, pidValue: string): Promise { - this.pidType = pidType; - this.pidValue = pidValue; - return this.fetchUrl(this.config.apiUrl(pidType, pidValue)); + return this.fetchFromUrlOrLocalStorage(this.config.apiUrl(pidType, pidValue)); } fetchWorkflowObject(objectId: string): Promise { - this.objectId = objectId; - return this.fetchUrl(this.config.holdingPenApiUrl(this.objectId)); + return this.fetchFromUrlOrLocalStorage(this.config.holdingPenApiUrl(objectId)); } - saveRecord(record: Object): Observable { + saveData(data: Object): Observable { + this.localStorageService.clear(this.dataUrl); return this.http - .put(this.config.apiUrl(this.pidType, this.pidValue), record) + .put(this.dataUrl, data) .map(res => res.json()); } - saveWorkflowObject(record: Object): Observable { - return this.http - .put(this.config.holdingPenApiUrl(this.objectId), record) - .map(res => res.json()); + saveDataLocally(data: Object) { + this.localStorageService.store(this.dataUrl, data); } }