Merge branch 'master' into 4-mongodb_api

This commit is contained in:
Tobias Eidelpes
2021-01-19 12:10:59 +01:00
15 changed files with 330 additions and 74 deletions
@@ -3,6 +3,8 @@ import {RestService} from '../../services/rest.service';
import {NGXLogger} from 'ngx-logger';
import {MatSnackBar} from '@angular/material/snack-bar';
import {ImageMetadata} from '../../interfaces/interface';
// @ts-ignore
import metaFile from '../../../../../iotclient/metadata_full.json';
@Component({
selector: 'app-file-uploader',
@@ -40,34 +42,36 @@ export class FileUploaderComponent implements OnInit {
if (this.filename) {
this.id = this.filename;
metaDict['filename'] = this.filename;
} else {
this.id = this.currentFileName;
metaDict['filename'] = this.currentFileName;
}
metaDict['filename'] = this.currentFileName;
if (this.mode === 'post') {
if (this.longitude && this.latitude) {
metaDict['longitude'] = Number.parseFloat(this.longitude);
metaDict['latitude'] = Number.parseFloat(this.latitude);
} else if (this.meta && this.meta.longitude && this.meta.latitude) {
if (this.meta && this.meta.longitude && this.meta.latitude) {
metaDict['longitude'] = this.meta.longitude;
metaDict['latitude'] = this.meta.latitude;
} else if (this.longitude && this.latitude) {
metaDict['longitude'] = Number.parseFloat(this.longitude);
metaDict['latitude'] = Number.parseFloat(this.latitude);
} else {
throw new Error('Long/Lat necessary if new file!');
}
}
if (this.name) {
metaDict['name'] = this.name;
} else if (this.meta && this.meta.name) {
if (this.meta && this.meta.name) {
metaDict['name'] = this.meta.name;
} else if (this.name) {
metaDict['name'] = this.name;
} else {
if (this.mode === 'post') {
throw new Error('Name necessary if new file');
}
}
// metaDict['name'] = this.currentFileName;
if (this.tag) {
metaDict['tag'] = this.tag;
} else if (this.meta && this.meta.tag) {
@@ -95,6 +99,7 @@ export class FileUploaderComponent implements OnInit {
}
ngOnInit(): void {
this.logger.debug('meta', metaFile);
}
onFileSelected(fileEvent: Event) {
@@ -109,6 +114,12 @@ export class FileUploaderComponent implements OnInit {
this.file = e.target.result;
this.currentFileName = file.name;
this.logger.debug('Selected file', this.currentFileName, this.file);
const metaData = this.loadMetaForFile();
if (metaData) {
this.name = metaData.name;
this.longitude = metaData.longitude + '';
this.latitude = metaData.latitude + '';
}
};
reader.readAsArrayBuffer(file);
@@ -150,4 +161,14 @@ export class FileUploaderComponent implements OnInit {
}
}
private loadMetaForFile() {
const metaData = (metaFile as {
filename: string,
latitude: number;
longitude: number;
name: string;
}[]).find(m => m.filename === this.currentFileName);
this.logger.debug('Found corresponding meta', this.currentFileName, metaData);
return metaData;
}
}
@@ -3,21 +3,27 @@
<div style="font-weight: bolder; font-size: 20px">
<span style="width: 22.5em; display: inline-block; margin-left: 1.15em">Name</span>
<span style="width: 22.5em; display: inline-block">Date</span>
<span style="width: 22.5em; display: inline-block">File valid</span>
<span style="width: 22.5em; display: inline-block">File available | valid</span>
</div>
<mat-expansion-panel
*ngFor="let image of filterOnlyNewestImageVersion() | slice:paginationGetStart():paginationGetEnd()"
(opened)="loadImage(getImageIndex(image), image.filename.split('.')[0])"
*ngFor="let image of filterOnlyNewestImageVersion() | slice:paginationGetStart():paginationGetEnd(); let i = index"
(opened)="openImageExpansion[i][0] = true; loadImage(getImageIndex(image), image.identifier)"
(closed)="openImageExpansion[i][0] = false;"
[expanded]="openImageExpansion[i][0]"
>
<!-- (opened)="loadImage(getImageIndex(image), image.filename.split('.')[0])"-->
<mat-expansion-panel-header (click)="$event.stopPropagation()">
<h4 style="width: 25em"
>{{image.name}}</h4>
<h4 style="width: 25em"
>{{image.datetime}}</h4>
<h4 style="width: 25em; color: red">
✓ | X (TO BE DONE)
<h4 style="width: 25em; margin-left: 6em;" *ngIf="image.available !== undefined || image.valid !== undefined;
else loadingValidity">
{{image.available ? '✓' : 'X' }} | {{image.valid ? '✓' : 'X' }}
</h4>
<ng-template #loadingValidity>
<h4 style="width: 25em; margin-left: 7em;">...</h4>
</ng-template>
<span style="float: right; margin-left: auto; margin-right: 1em;">
<button mat-raised-button color="warn"
(click)="deleteImage(image); $event.stopPropagation()">
@@ -43,17 +49,16 @@
<ng-template #loadingImage>
<mat-spinner style="margin: auto;"></mat-spinner>
</ng-template>
</div>
</mat-grid-tile>
<mat-grid-tile colspan="3">
<div style="display: block; width: 100%">
<h3>Metadata:</h3>
<p *ngIf="image.version">version: {{image.version}}</p>
<p *ngIf="image.filename">filename: {{image.filename}}</p>
<p *ngIf="image.latitude">latitude: {{image.latitude}}</p>
<p *ngIf="image.longitude">longitude: {{image.longitude}}</p>
<p *ngIf="image.version">version: {{image.version}}</p>
</div>
</mat-grid-tile>
</mat-grid-list>
@@ -61,21 +66,57 @@
<app-file-uploader [mode]="'put'"
[filename]="image.filename.split('.')[0]"
[meta]=image
(reload)="this.reload.emit()"
(reload)="reload.emit(); checkValidity()"
></app-file-uploader>
<!-- (reload)="image.image_b64 = undefined; this.loadImage(getImageIndex(image), image.identifier)"-->
<ng-container *ngIf="getRelatedImageMeta(image); let relatedImageMetadata">
<mat-expansion-panel *ngIf="relatedImageMetadata.length > 0">
<ng-container *ngIf="getRelatedImageMeta(image); let relatedImages">
<mat-expansion-panel *ngIf="relatedImages.length > 0" [expanded]="openImageExpansion[i][1]">
<mat-expansion-panel-header>
Previous version meta
Previous versions
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<div *ngFor="let imageMeta of relatedImageMetadata">
<p *ngIf="imageMeta.filename">filename: {{imageMeta.filename}}</p>
<p *ngIf="imageMeta.latitude">latitude: {{imageMeta.latitude}}</p>
<p *ngIf="imageMeta.longitude">longitude: {{imageMeta.longitude}}</p>
<p *ngIf="imageMeta.version">version: {{imageMeta.version}}</p>
</div>
<mat-expansion-panel *ngFor="let relImage of relatedImages.slice().reverse(); let j = index"
(opened)="loadImage(-1, relImage.identifier, relImage);
openImageExpansion[i][2+j]=true"
(closed)="openImageExpansion[i][2+j] = false"
[expanded]="openImageExpansion[i][2+j]"
>
<!-- <mat-divider></mat-divider>-->
<!-- <p *ngIf="imageMeta.version">version: {{imageMeta.version}}</p>-->
<!-- <p *ngIf="imageMeta.name">name: {{imageMeta.name}}</p>-->
<!-- <p *ngIf="imageMeta.tag">tag: {{imageMeta.tag}}</p>-->
<!-- <p *ngIf="imageMeta.filename">filename: {{imageMeta.filename}}</p>-->
<!-- <p *ngIf="imageMeta.latitude">latitude: {{imageMeta.latitude}}</p>-->
<!-- <p *ngIf="imageMeta.longitude">longitude: {{imageMeta.longitude}}</p>-->
<mat-expansion-panel-header>
<p>version: {{relImage.version ? relImage.version : 0}}</p>
</mat-expansion-panel-header>
<mat-grid-list cols="4" rowHeight="22em" style="width: 100%; margin: auto">
<mat-grid-tile style="justify-content: left!important;" colspan="1">
<div style="width: 20em; height: 20em; border: solid; margin-bottom: 1em; display: flex">
<img *ngIf="relImage.image_b64, let subB64; else loadingSubImage"
[src]="subB64"
style="width: 100%; margin: auto" [alt]="image.filename"/>
<ng-template #loadingSubImage>
<mat-spinner style="margin: auto;"></mat-spinner>
</ng-template>
</div>
</mat-grid-tile>
<mat-grid-tile colspan="3">
<div style="display: block; width: 100%">
<p *ngIf="relImage.filename">filename: {{relImage.filename}}</p>
<p *ngIf="relImage.latitude">latitude: {{relImage.latitude}}</p>
<p *ngIf="relImage.longitude">longitude: {{relImage.longitude}}</p>
</div>
</mat-grid-tile>
</mat-grid-list>
</mat-expansion-panel>
</ng-template>
</mat-expansion-panel>
</ng-container>
@@ -87,11 +128,12 @@
[length]="filterOnlyNewestImageVersion().length"
[pageSize]="pageSizeOptions[0]"
[pageSizeOptions]="pageSizeOptions"
(page)="lastPageEvent = $event"
(page)="lastPageEvent = $event; openImageExpansion = ALL_CLOSED_DEFAULT; checkValidity()"
showFirstLastButtons
hidePageSize
></mat-paginator>
<mat-divider style="margin-top: 2em"></mat-divider>
<h3>Upload New Image</h3>
<app-file-uploader [mode]="'post'" (reload)="reload.emit()"></app-file-uploader>
<app-file-uploader [mode]="'post'" (reload)="reload.emit(); checkValidity()"></app-file-uploader>
<mat-divider style="margin-top: 2em"></mat-divider>
@@ -20,6 +20,9 @@ export class ImagesComponent implements OnInit, AfterViewInit {
pageSizeOptions: number[] = [5, 10, 25, 100];
lastPageEvent: PageEvent;
ALL_CLOSED_DEFAULT = [...Array(5)].map(() => this.getDefaultBoolDict(false));
openImageExpansion = this.ALL_CLOSED_DEFAULT;
constructor(
public restService: RestService,
private logger: NGXLogger,
@@ -27,8 +30,15 @@ export class ImagesComponent implements OnInit, AfterViewInit {
) {
}
private getDefaultBoolDict(value: boolean) {
return new Proxy({}, {
get: (target, name) => name in target ? target[name] : value
});
}
ngOnInit(): void {
this.lastPageEvent = {pageIndex: 0, pageSize: this.pageSizeOptions[0], length: this.images.length};
this.checkValidity();
}
ngAfterViewInit(): void {
@@ -50,29 +60,58 @@ export class ImagesComponent implements OnInit, AfterViewInit {
}).catch(err => this.logger.error(err));
}
loadImage(i: number, id: string): void {
this.restService.getImage(id).toPromise().then(image => {
this.images[i].image_b64 = 'data:image/jpg;base64,' + image.image_data;
this.logger.debug('image_b64', i, id, this.images[i].image_b64);
}).catch(err => {
this.logger.error('loadImage', i, id, err);
});
loadImage(i: number, id: string, relImage?: ImageMetadata): void {
if (!relImage) {
this.restService.getImage(id).toPromise().then(image => {
this.images[i].image_b64 = 'data:image/jpg;base64,' + image.image_data;
this.logger.debug('image_b64', i, id, this.images[i].image_b64);
}).catch(err => {
this.logger.error('loadImage', i, id, err);
});
} else {
this.restService.getImage(id).toPromise().then(image => {
relImage.image_b64 = 'data:image/jpg;base64,' + image.image_data;
this.logger.debug('image_b64', i, id, relImage.image_b64);
}).catch(err => {
this.logger.error('loadImage', i, id, err);
});
}
}
filterOnlyNewestImageVersion() {
return this.images.filter(image => !image.previous);
return this.images.filter(image => !image.identifier.includes('_'));
}
getImageIndex(image: ImageMetadata) {
return this.images.findIndex(img => image === img);
}
getRelatedImageMeta(image: ImageMetadata, images: ImageMetadata[] = []) {
const found = this.images.find(im => im.previous === image.identifier);
if (found) {
return this.getRelatedImageMeta(found, images.concat(found));
} else {
return images;
}
getRelatedImageMeta(image: ImageMetadata) {
return this.images.filter(im => im.identifier.includes(image.identifier) && im.identifier !== image.identifier);
}
checkValidity() {
setTimeout(() => {
const start = this.paginationGetStart();
const end = this.paginationGetEnd();
const filteredImages = this.filterOnlyNewestImageVersion();
this.logger.debug('check validity', start, end, filteredImages);
for (let i = start; i < end; i++) {
try {
filteredImages[i].valid = undefined;
filteredImages[i].available = undefined;
this.restService.checkImageValid(filteredImages[i].identifier).toPromise().then(
res => {
filteredImages[i].valid = res.valid;
filteredImages[i].available = res.available;
}
);
} catch {
this.logger.debug('skip non-existing index', i);
}
}
}, 500);
}
}
@@ -28,7 +28,19 @@ export class LandingComponent implements OnInit {
}
loadImages(): void {
this.restService.getAllImages().toPromise().then(images => this.images = images).catch(err => this.logger.error(err));
this.restService.getAllImages().toPromise().then(images =>
this.images = images.sort((im1, im2) => {
if (im1.name > im2.name) {
return 1;
}
if (im1.name < im2.name) {
return -1;
}
return 0;
})
).catch(err => this.logger.error(err));
}
@@ -5,15 +5,33 @@
[longitude]="longitude"
[zoom]="2">
<agm-marker
*ngFor="let image of images"
*ngFor="let image of getImagesForMap()"
[latitude]="image.latitude"
[longitude]="image.longitude"
[opacity]="1"
[markerDraggable]="true"
(markerClick)="selectMarker($event)"
[markerDraggable]="false"
(markerClick)="loadImage(selectMarker($event))"
></agm-marker>
</agm-map>
<p *ngIf="selectedImage">
<div *ngIf="selectedImage">
Latitude: {{ selectedImage.latitude }} Longitude: {{ selectedImage.longitude }} Name: {{selectedImage.name}}
</p>
<mat-divider style="margin-bottom: 1em;"></mat-divider>
<div style="width: 20em; height: 20em; border: solid; margin-bottom: 1em; display: flex">
<img *ngIf="selectedImage.image_b64, let b64; else loadingImage"
[src]="b64"
style="width: 100%; margin: auto" [alt]="selectedImage.filename"/>
<ng-template #loadingImage>
<mat-spinner style="margin: auto;"></mat-spinner>
</ng-template>
</div>
<p *ngIf="selectedImage.filename">filename: {{selectedImage.filename}}</p>
<!-- <p *ngIf="selectedImage.latitude">latitude: {{selectedImage.latitude}}</p>-->
<!-- <p *ngIf="selectedImage.longitude">longitude: {{selectedImage.longitude}}</p>-->
<p *ngIf="selectedImage.version">version: {{selectedImage.version}}</p>
<p *ngIf="selectedImage.tag">tag: {{selectedImage.tag}}</p>
<!-- <p *ngIf="selectedImage.name">name: {{selectedImage.name}}</p>-->
</div>
@@ -1,5 +1,6 @@
import {Component, Input, OnInit} from '@angular/core';
import {ImageMetadata} from '../../interfaces/interface';
import {RestService} from '../../services/rest.service';
// @ts-ignore
@Component({
@@ -16,7 +17,7 @@ export class MapComponent implements OnInit {
latitude = 43.879078;
longitude = -103.4615581;
constructor() {
constructor(private restService: RestService) {
}
@@ -25,6 +26,25 @@ export class MapComponent implements OnInit {
}
selectMarker(event) {
this.selectedImage = this.images.find(image => image.latitude === event.latitude && image.longitude === event.longitude);
console.log(event, this.images);
this.selectedImage = this.images.find(image =>
image.latitude === event.latitude && image.longitude === event.longitude && !image.identifier.includes('_')
);
return this.selectedImage;
}
getImagesForMap() {
return this.images.filter(im => !im.identifier.includes('_'));
}
loadImage(image: ImageMetadata): void {
image.image_b64 = '';
this.restService.getImage(image.identifier).toPromise().then(im => {
image.image_b64 = 'data:image/jpg;base64,' + im.image_data;
}).catch(err => {
console.error('loadImage', image, err);
});
}
}
+7
View File
@@ -3,6 +3,8 @@ export interface StorageHealth {
}
export interface ImageMetadata {
available?: boolean;
valid?: boolean;
id: string;
datetime: string;
device_id: string;
@@ -34,3 +36,8 @@ export interface ImagePostResponse {
id: string;
filename: string;
}
export interface Validity {
available: boolean;
valid: boolean;
}
+9 -3
View File
@@ -4,12 +4,11 @@ import {NGXLogger} from 'ngx-logger';
import {environment} from '../../environments/environment';
import {Observable} from 'rxjs';
import {tap} from 'rxjs/operators';
import {GetImageResponse, ImagePostResponse, StorageHealth} from '../interfaces/interface';
import {GetImageResponse, ImagePostResponse, StorageHealth, Validity} from '../interfaces/interface';
@Injectable()
export class RestService {
constructor(
constructor(
private logger: NGXLogger,
private http: HttpClient
) {
@@ -21,6 +20,7 @@ export class RestService {
private deleteImageUrl = this.imageUrl + '/delete';
private postImageUrl = this.imageUrl + '/post';
private updateImageUrl = this.imageUrl + '/update';
private getValidityOfImageUrl = this.imageUrl + '/status';
private healthCheckUrl = this.currentLocation + '/check';
public getAllImages(): Observable<any> {
@@ -78,4 +78,10 @@ export class RestService {
tap(next => this.logger.debug('healthCheck', next))
);
}
public checkImageValid(id: string): Observable<Validity> {
return this.http.get<Validity>(this.getValidityOfImageUrl + '/' + id).pipe(
tap(next => this.logger.debug('checkValid', id, next))
);
}
}
+3 -1
View File
@@ -17,7 +17,9 @@
"es2017",
"dom"
],
"allowJs": true
"allowJs": true,
"resolveJsonModule": true,
"esModuleInterop": true
}
}