From e2a09b465d120a714fdfdc20523adbbb9c9becaf Mon Sep 17 00:00:00 2001 From: Marco Zeisler Date: Mon, 11 Jan 2021 18:53:12 +0100 Subject: [PATCH] added simple navigation to switch from images to map view; added simple images view skeleton; remove unnecessary websocket support; --- frontend/src/app/app.module.ts | 41 +++++++++++++------ .../app/component/images/images.component.css | 0 .../component/images/images.component.html | 23 +++++++++++ .../app/component/images/images.component.ts | 32 +++++++++++++++ .../component/landing/landing.component.html | 17 +++++++- .../component/landing/landing.component.ts | 13 +++++- .../src/app/component/map/map.component.css | 0 .../src/app/component/map/map.component.html | 1 + .../src/app/component/map/map.component.ts | 20 +++++++++ frontend/src/app/interfaces/interface.ts | 20 +++++++++ frontend/src/app/services/rest.service.ts | 36 ++++++++++++---- frontend/src/styles.css | 6 ++- middleware/app_be/routing.py | 17 -------- middleware/app_be/settings.py | 4 -- middleware/app_be/urls.py | 1 - middleware/app_be/views/ws_api.py | 18 -------- 16 files changed, 184 insertions(+), 65 deletions(-) create mode 100644 frontend/src/app/component/images/images.component.css create mode 100644 frontend/src/app/component/images/images.component.html create mode 100644 frontend/src/app/component/images/images.component.ts create mode 100644 frontend/src/app/component/map/map.component.css create mode 100644 frontend/src/app/component/map/map.component.html create mode 100644 frontend/src/app/component/map/map.component.ts delete mode 100644 middleware/app_be/routing.py delete mode 100644 middleware/app_be/views/ws_api.py diff --git a/frontend/src/app/app.module.ts b/frontend/src/app/app.module.ts index f2a7639..8ccec84 100644 --- a/frontend/src/app/app.module.ts +++ b/frontend/src/app/app.module.ts @@ -12,21 +12,36 @@ import {BrowserAnimationsModule} from '@angular/platform-browser/animations'; import {MatButtonModule} from '@angular/material/button'; import {MatInputModule} from '@angular/material/input'; import {MatSlideToggleModule} from '@angular/material/slide-toggle'; +import {MatListModule} from '@angular/material/list'; +import {MatExpansionModule} from '@angular/material/expansion'; +import {MatCardModule} from '@angular/material/card'; +import {MatPaginatorModule} from '@angular/material/paginator'; +import {MatTableModule} from '@angular/material/table'; +import {MatTabsModule} from '@angular/material/tabs'; +import { ImagesComponent } from './component/images/images.component'; +import { MapComponent } from './component/map/map.component'; @NgModule({ - declarations: [LandingComponent], - imports: [ - ReactiveFormsModule, - BrowserModule, - BrowserAnimationsModule, - LoggerModule.forRoot({level: environment.log_level, serverLogLevel: NgxLoggerLevel.ERROR}), - HttpClientModule, - MatFormFieldModule, - FormsModule, - MatButtonModule, - MatInputModule, - MatSlideToggleModule - ], + declarations: [LandingComponent, ImagesComponent, MapComponent], + imports: [ + ReactiveFormsModule, + BrowserModule, + BrowserAnimationsModule, + LoggerModule.forRoot({level: environment.log_level, serverLogLevel: NgxLoggerLevel.ERROR}), + HttpClientModule, + MatFormFieldModule, + FormsModule, + MatButtonModule, + MatInputModule, + MatSlideToggleModule, + MatListModule, + MatExpansionModule, + MatCardModule, + MatPaginatorModule, + MatTableModule, + MatTabsModule, + + ], // enables injecting providers: [ RestService, diff --git a/frontend/src/app/component/images/images.component.css b/frontend/src/app/component/images/images.component.css new file mode 100644 index 0000000..e69de29 diff --git a/frontend/src/app/component/images/images.component.html b/frontend/src/app/component/images/images.component.html new file mode 100644 index 0000000..8e618f6 --- /dev/null +++ b/frontend/src/app/component/images/images.component.html @@ -0,0 +1,23 @@ +

Available Images

+ +
+ Name + Date +
+ + + + {{image.name}} + {{image.datetime}} + + TEST + + + diff --git a/frontend/src/app/component/images/images.component.ts b/frontend/src/app/component/images/images.component.ts new file mode 100644 index 0000000..a74c42b --- /dev/null +++ b/frontend/src/app/component/images/images.component.ts @@ -0,0 +1,32 @@ +import {Component, Input, OnInit} from '@angular/core'; +import {PageEvent} from '@angular/material/paginator'; +import {ImageMetadata} from '../../interfaces/interface'; + +@Component({ + selector: 'app-images', + templateUrl: './images.component.html', + styleUrls: ['./images.component.css'] +}) +export class ImagesComponent implements OnInit { + + @Input() + images: ImageMetadata[]; + + pageSizeOptions: number[] = [5, 10, 25, 100]; + lastPageEvent: PageEvent; + + constructor() { } + + ngOnInit(): void { + this.lastPageEvent = {pageIndex: 0, pageSize: this.pageSizeOptions[0], length: this.images.length}; + } + + paginationGetStart(): number { + return this.lastPageEvent.pageIndex * this.lastPageEvent.pageSize; + } + + paginationGetEnd(): number { + return this.paginationGetStart() + this.lastPageEvent.pageSize; + } + +} diff --git a/frontend/src/app/component/landing/landing.component.html b/frontend/src/app/component/landing/landing.component.html index eba20f2..f665cae 100644 --- a/frontend/src/app/component/landing/landing.component.html +++ b/frontend/src/app/component/landing/landing.component.html @@ -1 +1,16 @@ -

Federated Storage Infrastructure for IoT Sensor Data

+

+ Federated Storage Infrastructure for IoT Sensor Data + + {{storage.key}} ✓ + {{storage.key}} x + +

+ + + + + + + + + diff --git a/frontend/src/app/component/landing/landing.component.ts b/frontend/src/app/component/landing/landing.component.ts index a62e3d5..910aaae 100644 --- a/frontend/src/app/component/landing/landing.component.ts +++ b/frontend/src/app/component/landing/landing.component.ts @@ -1,6 +1,7 @@ import {Component, OnInit} from '@angular/core'; import {RestService} from '../../services/rest.service'; import {NGXLogger} from 'ngx-logger'; +import {ImageMetadata, StorageHealth} from '../../interfaces/interface'; @Component({ selector: 'app-landing', @@ -9,12 +10,22 @@ import {NGXLogger} from 'ngx-logger'; }) export class LandingComponent implements OnInit { + storageHealth: StorageHealth; + images: ImageMetadata[] = []; + constructor( - private logger: NGXLogger, + public logger: NGXLogger, private restService: RestService ) { } ngOnInit(): void { + this.restService.healthCheck().toPromise().then( + storageHealth => this.storageHealth = storageHealth + ).catch(err => this.logger.error(err)); + + this.restService.getAllImages().toPromise().then(images => this.images = images).catch(err => this.logger.error(err)); } + + } diff --git a/frontend/src/app/component/map/map.component.css b/frontend/src/app/component/map/map.component.css new file mode 100644 index 0000000..e69de29 diff --git a/frontend/src/app/component/map/map.component.html b/frontend/src/app/component/map/map.component.html new file mode 100644 index 0000000..73515aa --- /dev/null +++ b/frontend/src/app/component/map/map.component.html @@ -0,0 +1 @@ +

Image Locations

diff --git a/frontend/src/app/component/map/map.component.ts b/frontend/src/app/component/map/map.component.ts new file mode 100644 index 0000000..0e669a4 --- /dev/null +++ b/frontend/src/app/component/map/map.component.ts @@ -0,0 +1,20 @@ +import {Component, Input, OnInit} from '@angular/core'; +import {ImageMetadata} from '../../interfaces/interface'; + +@Component({ + selector: 'app-map', + templateUrl: './map.component.html', + styleUrls: ['./map.component.css'] +}) +export class MapComponent implements OnInit { + + @Input() + images: ImageMetadata[]; + + constructor() { + } + + ngOnInit(): void { + } + +} diff --git a/frontend/src/app/interfaces/interface.ts b/frontend/src/app/interfaces/interface.ts index e69de29..e7b0fa2 100644 --- a/frontend/src/app/interfaces/interface.ts +++ b/frontend/src/app/interfaces/interface.ts @@ -0,0 +1,20 @@ +export interface StorageHealth { + [storage: string]: boolean; +} + +export interface ImageMetadata { + datetime: string; + device_id: string; + filename: string; + frame_num: number; + identifier: string; + latitude: number; + location: [number, number]; + longitude: number; + name: string; + place_ident: string; + seq_id: string; + seq_num_frames: number; + sha512: string; + selected?: boolean; +} diff --git a/frontend/src/app/services/rest.service.ts b/frontend/src/app/services/rest.service.ts index 25591aa..bf073dd 100644 --- a/frontend/src/app/services/rest.service.ts +++ b/frontend/src/app/services/rest.service.ts @@ -3,6 +3,8 @@ import {Injectable} from '@angular/core'; import {NGXLogger} from 'ngx-logger'; import {environment} from '../../environments/environment'; import {Observable} from 'rxjs'; +import {tap} from 'rxjs/operators'; +import {StorageHealth} from '../interfaces/interface'; @Injectable() export class RestService { @@ -21,34 +23,50 @@ export class RestService { } public getAllImages(): Observable { - return this.http.get(this.getImageUrl + 'all'); + return this.http.get(this.getImageUrl + 'all').pipe( + tap(next => this.logger.debug('getAllImages', next)) + ); } public getImage(id: string): Observable { - return this.http.get(this.getImageUrl + id); + return this.http.get(this.getImageUrl + id).pipe( + tap(next => this.logger.debug('getImage', id, next)) + ); } public getImageVersion(id: string, version: string): Observable { - return this.http.get(this.getImageUrl + id + '/version/' + version); + return this.http.get(this.getImageUrl + id + '/version/' + version).pipe( + tap(next => this.logger.debug('getImageVersion', id, version, next)) + ); } public deleteAllImages(): Observable { - return this.http.delete(this.deleteImageUrl + 'all'); + return this.http.delete(this.deleteImageUrl + 'all').pipe( + tap(next => this.logger.debug('deleteAllImages', next)) + ); } public deleteImage(id: string): Observable { - return this.http.delete(this.deleteImageUrl + id); + return this.http.delete(this.deleteImageUrl + id).pipe( + tap(next => this.logger.debug('deleteImage', id, next)) + ); } public postImage(id: string, image: any): Observable { - return this.http.post(this.postImageUrl + id, image); + return this.http.post(this.postImageUrl + id, image).pipe( + tap(next => this.logger.debug('postImage', id, image, next)) + ); } public updateImage(id: string, image: any): Observable { - return this.http.put(this.updateImageUrl + id, image); + return this.http.put(this.updateImageUrl + id, image).pipe( + tap(next => this.logger.debug('updateImage', id, image, next)) + ); } - public healthCheck(): Observable { - return this.http.get(this.healthCheckUrl); + public healthCheck(): Observable { + return this.http.get(this.healthCheckUrl).pipe( + tap(next => this.logger.debug('healthCheck', next)) + ); } } diff --git a/frontend/src/styles.css b/frontend/src/styles.css index 95220d8..99d58e2 100644 --- a/frontend/src/styles.css +++ b/frontend/src/styles.css @@ -8,6 +8,10 @@ body { margin: auto; } -h1 { +h1, h2 { margin-top: 1em; } + +h2 { + margin-bottom: 1.5em; +} diff --git a/middleware/app_be/routing.py b/middleware/app_be/routing.py deleted file mode 100644 index b635884..0000000 --- a/middleware/app_be/routing.py +++ /dev/null @@ -1,17 +0,0 @@ -from django.conf.urls import url - -from channels.routing import ProtocolTypeRouter, URLRouter -from channels.sessions import SessionMiddlewareStack -from django.core.asgi import get_asgi_application - -from .views.ws_api import CustomConsumer - -application = ProtocolTypeRouter({ - # Django's ASGI application to handle traditional HTTP requests - "http": get_asgi_application(), - - # WebSocket send handler - "websocket": SessionMiddlewareStack(URLRouter([ - url(r"^test-ws-endpoint/$", CustomConsumer.as_asgi()), - ])) -}) diff --git a/middleware/app_be/settings.py b/middleware/app_be/settings.py index 47a9414..bbba9e2 100644 --- a/middleware/app_be/settings.py +++ b/middleware/app_be/settings.py @@ -8,9 +8,6 @@ https://docs.djangoproject.com/en/2.0/ref/settings/ import datetime import os -# set the websocket routing module location here -ASGI_APPLICATION = 'app_be.routing.application' - # Build paths inside the project like this: os.path.join(BASE_DIR, ...) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__)) @@ -34,7 +31,6 @@ INSTALLED_APPS = [ 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', - 'channels', 'rest_framework', ] diff --git a/middleware/app_be/urls.py b/middleware/app_be/urls.py index df54cfa..f4d73de 100644 --- a/middleware/app_be/urls.py +++ b/middleware/app_be/urls.py @@ -22,7 +22,6 @@ from app_be.views.rest_api import TestApiClass, ImageEndpoint, HealthEndpoint urlpatterns = [ path('admin/', admin.site.urls), - url(r'^test/', TestApiClass.test_api), url(r'^image/get/all$', ImageEndpoint.image_api_get_all), url(r'^image/get/(?P[\w-]+)$', ImageEndpoint.image_api_get_single), url(r'^image/get/(?P[\w-]+)/version/(?P[\w-]+)$', ImageEndpoint.image_api_get_single_version), diff --git a/middleware/app_be/views/ws_api.py b/middleware/app_be/views/ws_api.py deleted file mode 100644 index a648867..0000000 --- a/middleware/app_be/views/ws_api.py +++ /dev/null @@ -1,18 +0,0 @@ -import logging - -from channels.generic.websocket import WebsocketConsumer - - -logger = logging.getLogger(__name__) - - -class CustomConsumer(WebsocketConsumer): - def connect(self): - self.accept() - - def receive(self, text_data=None, bytes_data=None): - self.send('1. response: {}'.format(text_data)) - self.send('2. response: {}'.format(text_data)) - - def disconnect(self, code): - pass