gsd 4 months ago
parent
commit
219b77f915
  1. 2
      ui/src/app/app.component.html
  2. 10
      ui/src/app/app.component.ts
  3. 5
      ui/src/app/auth/AuthInterceptor.ts
  4. 31
      ui/src/app/components/nodes/nodes-map.component.ts
  5. 5
      ui/src/app/components/nodes/nodes.styles.scss
  6. 2
      ui/src/app/components/packet/NetworkStatus.component.ts
  7. 2
      ui/src/styles.scss
  8. 37
      ui/src/styles/vw-style.scss
  9. 3
      webExtensions/publicEndpoints.py

2
ui/src/app/app.component.html

@ -4,7 +4,7 @@
</button>
<span>MeshCenter</span>
<span class="spacer"></span>
<p *ngIf="userNode">{{userNode.long_name}} ({{userNode.num}}) snr: {{userNode.snr}}</p>
<p *ngIf="userNode">{{(isHandset | async) ? (userNode.short_name) : (userNode.long_name + ' ' + userNode.num + ' ' + userNode.snr)}}</p>
<button *ngIf="userNode" mat-button (click)="logout()">Выйти</button>
</mat-toolbar>
<mat-drawer-container class="container" autosize style="height: calc(100% - 36px)">

10
ui/src/app/app.component.ts

@ -2,6 +2,8 @@ import {Component, OnInit} from '@angular/core';
import {Route, Router} from "@angular/router";
import {NodeDTO} from "./entities/NodeDTO";
import {HttpClient} from "@angular/common/http";
import {map, Observable} from "rxjs";
import {BreakpointObserver, Breakpoints} from "@angular/cdk/layout";
@Component({
selector: 'app-root',
@ -10,9 +12,15 @@ import {HttpClient} from "@angular/common/http";
})
export class AppComponent implements OnInit {
constructor(private route: Router,
private http: HttpClient) {
private http: HttpClient,
private breakpointObserver: BreakpointObserver) {
}
isHandset: Observable<boolean> = this.breakpointObserver
.observe([Breakpoints.Handset])
.pipe(map(result => result.matches));
ngOnInit() {
this.http.get(`api/auth/me`).subscribe(
(res) => this.userNode = res as NodeDTO

5
ui/src/app/auth/AuthInterceptor.ts

@ -7,12 +7,13 @@ import {
HttpRequest
} from "@angular/common/http";
import {Component, Injectable, OnInit, ViewContainerRef} from "@angular/core";
import {catchError, Observable, startWith, throwError} from "rxjs";
import {catchError, map, Observable, startWith, throwError} from "rxjs";
import {MatDialog, MatDialogRef} from "@angular/material/dialog";
import {FormControl} from "@angular/forms";
import {NodeMiniDTO} from "../entities/NodeMiniDTO";
import {MatSnackBar} from "@angular/material/snack-bar";
import {D} from "@angular/cdk/keycodes";
import {BreakpointObserver, Breakpoints} from "@angular/cdk/layout";
@Component({
@ -124,7 +125,7 @@ export class AuthInterceptor implements HttpInterceptor {
catchError((error: HttpErrorResponse) => {
if (error.status === 401 && !this.dialogOpened) {
this.dialogOpened = true;
const ref = this.dialog.open(AuthDialog, {disableClose: true, width:"30%"})
const ref = this.dialog.open(AuthDialog, {disableClose: true, panelClass:"width-vw"})
ref.afterClosed().subscribe((res:any) => this.dialogOpened = false)
}
return throwError(() => error);

31
ui/src/app/components/nodes/nodes-map.component.ts

@ -4,6 +4,7 @@ import {HttpClient} from "@angular/common/http";
import {NodeDTO} from "../../entities/NodeDTO";
import {Subscription} from "rxjs";
import {DatePipe} from "@angular/common";
import {numToColor} from "../../utils/Utils";
@Component({
selector: "app-nodes-map",
@ -26,6 +27,8 @@ export class NodesMapComponent implements OnInit {
})
nodes: NodeDTO[] = []
numToColor = numToColor;
constructor(private http: HttpClient,
private datepipe: DatePipe) {
}
@ -42,7 +45,13 @@ export class NodesMapComponent implements OnInit {
() => {
this.nodes.filter((node) => node.havePosition).forEach(
(node) => {
L.marker(this.convertPosition(node), {icon: this.logo}).bindPopup(`<a href="network/status/${node.num}">${node.long_name} (${node.short_name})</a><p>snr: ${node.snr} hops: ${node.hops_away}</p><p>Изменена: ${this.datepipe.transform(node.position.time*1000, 'HH:mm dd.MM.yyyy')}</p>`).addTo(this.map)
L.marker(this.convertPosition(node), {
icon: this.createCircleIcon({
color: this.numToColor(node.num, 0),
text: node.short_name})
})
.bindPopup(`<a href="network/status/${node.num}">${node.long_name} (${node.short_name})</a><p>snr: ${node.snr} hops: ${node.hops_away}</p><p>Изменена: ${this.datepipe.transform(node.position.time*1000, 'HH:mm dd.MM.yyyy')}</p>`)
.addTo(this.map)
}
)
}
@ -72,4 +81,24 @@ export class NodesMapComponent implements OnInit {
tiles.addTo(this.map)
return Subscription.EMPTY;
}
private createCircleIcon(options: { color: string; text: string; size?: number }): L.DivIcon {
const size = options.size || 24;
const html = `
<div style="
width: ${size}px;
height: ${size}px;
border-radius: 50%;
background-color: ${options.color};
display: flex;
align-items: center;
justify-content: center;
color: white;
font-size: ${size * 0.35}px;
font-weight: bold;
text-shadow: 0 1px 2px rgba(0,0,0,0.5);
">${options.text}</div>
`;
return L.divIcon({ html, iconSize: [size, size], className: 'l-div-icon' });
}
}

5
ui/src/app/components/nodes/nodes.styles.scss

@ -19,3 +19,8 @@
:host ::ng-deep .leaflet-control-attribution {
display: none;
}
.l-div-icon {
border: unset;
background: unset;
}

2
ui/src/app/components/packet/NetworkStatus.component.ts

@ -12,7 +12,7 @@ import {DatePipe} from "@angular/common";
@Component({
selector: "app-network-status",
template: `
<div style="width: 80%; padding: 0 10%;">
<div class="width-vw width-padding">
<div [ngSwitch]="MODE">
<h1 *ngSwitchCase="'ALL'">Статистика всей сети (желательно нажать ф5 если до этого смотрели другую ноду)</h1>
<h1 *ngSwitchCase="'NODE'">Статистика ноды {{getNumName(NUM)}} в сети</h1>

2
ui/src/styles.scss

@ -1,3 +1,5 @@
@import "styles/vw-style";
/* You can add global styles to this file, and also import other style files */
html, body { height: 100%; }

37
ui/src/styles/vw-style.scss

@ -0,0 +1,37 @@
//
@media (max-width: 600px) {
.width-vw {
width: 100vw;
}
}
@media (max-width: 960px) {
.width-vw {
width: 100vw;
}
}
@media (max-width: 1280px) {
.width-vw {
width: 80vw;
}
}
//
@media (max-width: 600px) {
.width-padding {
padding: 0 0;
}
}
@media (max-width: 960px) {
.width-padding {
padding: 0 0;
}
}
@media (max-width: 1280px) {
.width-padding {
padding: 0 10vw;
}
}

3
webExtensions/publicEndpoints.py

@ -67,6 +67,9 @@ class WebExtension:
async def grabTile(request:Request, z:int, x:int, y:int):
try:
img = await self.core.tileManager.grabTile(z, x, y)
headers = {
"Cache-Control": f"public, max-age={86400*7}"
}
return Response(content=img, media_type="image/png")
except:
traceback.print_exc()

Loading…
Cancel
Save