diff --git a/cloudapp/jsconfig.json b/cloudapp/jsconfig.json new file mode 100644 index 0000000..ea58a4b --- /dev/null +++ b/cloudapp/jsconfig.json @@ -0,0 +1,6 @@ +{ + "compilerOptions": { + "experimentalDecorators": true, + "target": "es5" + } +} diff --git a/cloudapp/src/app/app-routing.module.ts b/cloudapp/src/app/app-routing.module.ts new file mode 100644 index 0000000..a7ac35d --- /dev/null +++ b/cloudapp/src/app/app-routing.module.ts @@ -0,0 +1,13 @@ +import { NgModule } from '@angular/core'; +import { Routes, RouterModule } from '@angular/router'; +import { MainComponent } from './main/main.component'; + +const routes: Routes = [ + { path: '', component: MainComponent }, +]; + +@NgModule({ + imports: [RouterModule.forRoot(routes, { useHash: true })], + exports: [RouterModule] +}) +export class AppRoutingModule { } diff --git a/cloudapp/src/app/app.component.ts b/cloudapp/src/app/app.component.ts new file mode 100644 index 0000000..7af5162 --- /dev/null +++ b/cloudapp/src/app/app.component.ts @@ -0,0 +1,12 @@ +import { Component } from '@angular/core'; +import { AppService } from './app.service'; + +@Component({ + selector: 'app-root', + template: '' +}) +export class AppComponent { + + constructor(private appService: AppService) { } + +} diff --git a/cloudapp/src/app/app.module.ts b/cloudapp/src/app/app.module.ts new file mode 100644 index 0000000..3b74e27 --- /dev/null +++ b/cloudapp/src/app/app.module.ts @@ -0,0 +1,31 @@ +import { NgModule } from '@angular/core'; +import { HttpClientModule } from '@angular/common/http'; +import { BrowserModule } from '@angular/platform-browser'; +import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; +import { MAT_FORM_FIELD_DEFAULT_OPTIONS } from '@angular/material/form-field'; +import { MaterialModule, getTranslateModule, AlertModule } from '@exlibris/exl-cloudapp-angular-lib'; + +import { AppComponent } from './app.component'; +import { AppRoutingModule } from './app-routing.module'; +import { MainComponent } from './main/main.component'; + +@NgModule({ + declarations: [ + AppComponent, + MainComponent + ], + imports: [ + MaterialModule, + BrowserModule, + BrowserAnimationsModule, + AppRoutingModule, + HttpClientModule, + AlertModule, + getTranslateModule(), + ], + providers: [ + { provide: MAT_FORM_FIELD_DEFAULT_OPTIONS, useValue: { appearance: 'standard' } }, + ], + bootstrap: [AppComponent] +}) +export class AppModule { } diff --git a/cloudapp/src/app/app.service.ts b/cloudapp/src/app/app.service.ts new file mode 100644 index 0000000..48b7707 --- /dev/null +++ b/cloudapp/src/app/app.service.ts @@ -0,0 +1,12 @@ + +import { Injectable } from '@angular/core'; +import { InitService } from '@exlibris/exl-cloudapp-angular-lib'; + +@Injectable({ + providedIn: 'root' +}) +export class AppService { + + constructor(private initService: InitService) {} + +} \ No newline at end of file diff --git a/cloudapp/src/app/main/main.component.html b/cloudapp/src/app/main/main.component.html new file mode 100644 index 0000000..20b904e --- /dev/null +++ b/cloudapp/src/app/main/main.component.html @@ -0,0 +1,42 @@ +
+

+ Welcome! +

+

Use this sample app to get you started. The app includes the following:

+ +

Use these building blocks to be on your way to developing your own Cloud App.

+
+ +
+ + + Page Entity + + +
{{ pageEntities | json }}
+
+
+
+ +
+ + + API Result + + + + + + + + +
+
+ +
\ No newline at end of file diff --git a/cloudapp/src/app/main/main.component.scss b/cloudapp/src/app/main/main.component.scss new file mode 100644 index 0000000..3a3fb20 --- /dev/null +++ b/cloudapp/src/app/main/main.component.scss @@ -0,0 +1,31 @@ +section>h1 { + padding: 5px 10px; + border-radius: 4px; + margin-top: 10px; +} + +textarea { + padding: 2px; + border-width: 1px; + $width: calc(100% - 6px); + width: $width; + max-width: $width; + height: 150px; + font-family: monospace; + display: block; +} + +textarea, +section { + margin-bottom: 10px; +} + +pre { + overflow: auto; + max-height: 200px; +} + +pre, +textarea { + font-size: 0.9em; +} \ No newline at end of file diff --git a/cloudapp/src/app/main/main.component.theme.scss b/cloudapp/src/app/main/main.component.theme.scss new file mode 100644 index 0000000..6ea1cc9 --- /dev/null +++ b/cloudapp/src/app/main/main.component.theme.scss @@ -0,0 +1,6 @@ +@mixin main-component-theme($theme, $typgraphy) { + section>h1 { + background-color: mat-color(map-get($theme, primary)); + color: mat-color(map-get($theme, primary), default-contrast); + } +} \ No newline at end of file diff --git a/cloudapp/src/app/main/main.component.ts b/cloudapp/src/app/main/main.component.ts new file mode 100644 index 0000000..5384310 --- /dev/null +++ b/cloudapp/src/app/main/main.component.ts @@ -0,0 +1,103 @@ +import { Subscription } from 'rxjs'; +import { Component, OnInit, OnDestroy } from '@angular/core'; +import { + CloudAppRestService, CloudAppEventsService, Request, HttpMethod, + Entity, PageInfo, RestErrorResponse, AlertService +} from '@exlibris/exl-cloudapp-angular-lib'; + +@Component({ + selector: 'app-main', + templateUrl: './main.component.html', + styleUrls: ['./main.component.scss'] +}) +export class MainComponent implements OnInit, OnDestroy { + + private pageLoad$: Subscription; + pageEntities: Entity[]; + private _apiResult: any; + + hasApiResult: boolean = false; + loading = false; + + constructor(private restService: CloudAppRestService, + private eventsService: CloudAppEventsService, + private alert: AlertService ) { } + + ngOnInit() { + this.pageLoad$ = this.eventsService.onPageLoad(this.onPageLoad); + } + + ngOnDestroy(): void { + this.pageLoad$.unsubscribe(); + } + + get apiResult() { + return this._apiResult; + } + + set apiResult(result: any) { + this._apiResult = result; + this.hasApiResult = result && Object.keys(result).length > 0; + } + + onPageLoad = (pageInfo: PageInfo) => { + this.pageEntities = pageInfo.entities; + if ((pageInfo.entities || []).length == 1) { + const entity = pageInfo.entities[0]; + this.restService.call(entity.link).subscribe(result => this.apiResult = result); + } else { + this.apiResult = {}; + } + } + + update(value: any) { + this.loading = true; + let requestBody = this.tryParseJson(value); + if (!requestBody) { + this.loading = false; + return this.alert.error('Failed to parse json'); + } + this.sendUpdateRequest(requestBody); + } + + refreshPage = () => { + this.loading = true; + this.eventsService.refreshPage().subscribe({ + next: () => this.alert.success('Success!'), + error: e => { + console.error(e); + this.alert.error('Failed to refresh page'); + }, + complete: () => this.loading = false + }); + } + + private sendUpdateRequest(requestBody: any) { + let request: Request = { + url: this.pageEntities[0].link, + method: HttpMethod.PUT, + requestBody + }; + this.restService.call(request).subscribe({ + next: result => { + this.apiResult = result; + this.refreshPage(); + }, + error: (e: RestErrorResponse) => { + this.alert.error('Failed to update data'); + console.error(e); + this.loading = false; + } + }); + } + + private tryParseJson(value: any) { + try { + return JSON.parse(value); + } catch (e) { + console.error(e); + } + return undefined; + } + +} diff --git a/cloudapp/src/assets/manifest.json b/cloudapp/src/assets/manifest.json new file mode 100644 index 0000000..6a14022 --- /dev/null +++ b/cloudapp/src/assets/manifest.json @@ -0,0 +1,5 @@ +{ + "id": "my-alma-cloud-app", + "title": "My Alma Cloud App", + "description": "My Alma Cloud App" +} \ No newline at end of file diff --git a/cloudapp/src/main.scss b/cloudapp/src/main.scss new file mode 100644 index 0000000..cf89247 --- /dev/null +++ b/cloudapp/src/main.scss @@ -0,0 +1,11 @@ + +@import './app/main/main.component.theme'; + +@mixin themed-styles($theme, $typography) { + /* Include themed component mixins or theme dependent styles here */ + @include main-component-theme($theme, $typography); +} + +@mixin global-styles { + /* Add global styles here */ +}