Merge branch 'master' into 4-mongodb_api
This commit is contained in:
@@ -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);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,9 @@
|
||||
"es2017",
|
||||
"dom"
|
||||
],
|
||||
"allowJs": true
|
||||
"allowJs": true,
|
||||
"resolveJsonModule": true,
|
||||
"esModuleInterop": true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user