feat: Bit of frontend changes
This commit is contained in:
@@ -31,9 +31,6 @@ Configure by setting up _/docker/.env_ (copy [/docker/.env.example](docker/.env.
|
|||||||
|
|
||||||
(Please note that the _bind\_url_ should be left unconfigured as it is used in the [/docker/docker-compose.yml](docker/docker-compose.yml) config file. Otherwise the proxy-pass may break.)
|
(Please note that the _bind\_url_ should be left unconfigured as it is used in the [/docker/docker-compose.yml](docker/docker-compose.yml) config file. Otherwise the proxy-pass may break.)
|
||||||
|
|
||||||
### Privacy policy
|
|
||||||
The website contains links to _privacy-policy.html_. You can (and should) set up this privacy policy page. Empty dummy files already exist in the [_docker/_](docker) and [_frontend/src/_](frontend/src) directories.
|
|
||||||
|
|
||||||
## API
|
## API
|
||||||
API-Documentation: [openapi.yml](openapi.yml)
|
API-Documentation: [openapi.yml](openapi.yml)
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,4 @@
|
|||||||
use std::{
|
use std::{collections::HashMap, io::Error};
|
||||||
collections::HashMap,
|
|
||||||
io::Error,
|
|
||||||
};
|
|
||||||
|
|
||||||
use log::{debug, error};
|
use log::{debug, error};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use tokio::io::{AsyncBufReadExt, BufReader, BufWriter};
|
use tokio::io::{AsyncBufReadExt, BufReader, BufWriter};
|
||||||
@@ -113,6 +109,8 @@ pub async fn init<A: ToSocketAddrs>(
|
|||||||
.await?;
|
.await?;
|
||||||
tcp_stream_writer.flush().await?;
|
tcp_stream_writer.flush().await?;
|
||||||
|
|
||||||
|
debug!("Sent login: '{}'", login_message.trim());
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let mut line = String::new();
|
let mut line = String::new();
|
||||||
|
|
||||||
@@ -131,7 +129,7 @@ pub async fn init<A: ToSocketAddrs>(
|
|||||||
|
|
||||||
let current_timestamp = get_current_timestamp();
|
let current_timestamp = get_current_timestamp();
|
||||||
|
|
||||||
debug!("Got line: '{line}'");
|
debug!("Got line: '{}'", line.trim());
|
||||||
|
|
||||||
line_received_tx
|
line_received_tx
|
||||||
.send(current_timestamp)
|
.send(current_timestamp)
|
||||||
|
|||||||
@@ -20,4 +20,3 @@ services:
|
|||||||
- "127.0.0.1:9000:8080"
|
- "127.0.0.1:9000:8080"
|
||||||
volumes:
|
volumes:
|
||||||
- ./nginx.conf:/etc/nginx/nginx.conf:ro
|
- ./nginx.conf:/etc/nginx/nginx.conf:ro
|
||||||
- ./privacy-policy.html:/usr/share/nginx/html/privacy-policy.html:ro
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ http {
|
|||||||
server_name _;
|
server_name _;
|
||||||
|
|
||||||
add_header Content-Security-Policy "default-src 'self' 'unsafe-inline' data:;";
|
add_header Content-Security-Policy "default-src 'self' 'unsafe-inline' data:;";
|
||||||
add_header Permissions-Policy "geolocation=(), midi=(), camera=(), usb=(), payment=(), vr=(), speaker=(), ambient-light-sensor=(), gyroscope=(), microphone=(), usb=(), interest-cohort=()";
|
add_header Permissions-Policy "geolocation=(self), midi=(), camera=(), usb=(), payment=(), vr=(), speaker=(), ambient-light-sensor=(), gyroscope=(), microphone=(), usb=(), interest-cohort=()";
|
||||||
add_header Referer "no-referrer";
|
add_header Referer "no-referrer";
|
||||||
add_header Referrer-Policy "no-referrer";
|
add_header Referrer-Policy "no-referrer";
|
||||||
add_header Strict-Transport-Security "max-age=63072000" always;
|
add_header Strict-Transport-Security "max-age=63072000" always;
|
||||||
@@ -26,10 +26,10 @@ http {
|
|||||||
|
|
||||||
client_max_body_size 1;
|
client_max_body_size 1;
|
||||||
|
|
||||||
|
access_log off;
|
||||||
|
error_log /dev/null emerg;
|
||||||
|
|
||||||
location /r/ {
|
location /r/ {
|
||||||
# Do not log location data
|
|
||||||
access_log off;
|
|
||||||
error_log /dev/null emerg;
|
|
||||||
proxy_pass http://backend:9000/r/;
|
proxy_pass http://backend:9000/r/;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,11 +41,6 @@ http {
|
|||||||
gzip_types *;
|
gzip_types *;
|
||||||
expires 1d;
|
expires 1d;
|
||||||
|
|
||||||
location = /privacy-policy.html {
|
|
||||||
root /usr/share/nginx/html;
|
|
||||||
try_files /privacy-policy.html =404;
|
|
||||||
}
|
|
||||||
|
|
||||||
location / {
|
location / {
|
||||||
proxy_pass http://frontend:80/;
|
proxy_pass http://frontend:80/;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
<!-- Fill this privacy policy. -->
|
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "echo \"Error: no test specified\" && exit 1",
|
"test": "echo \"Error: no test specified\" && exit 1",
|
||||||
"copy-dependencies": "rm -rf dist && rsync -av --exclude='*.handlebars' src/ dist/ && cp node_modules/handlebars/dist/handlebars.min.js dist/ && cp node_modules/bootstrap/dist/js/bootstrap.min.js dist && cp node_modules/bootstrap/dist/js/bootstrap.min.js.map dist && cp node_modules/bootstrap/dist/css/bootstrap.min.css dist && cp node_modules/bootstrap/dist/css/bootstrap.min.css.map dist",
|
"copy-dependencies": "rm -rf dist && rsync -av --exclude='*.handlebars' src/ dist/ && cp node_modules/handlebars/dist/handlebars.min.js dist/ && cp node_modules/bootstrap/dist/js/bootstrap.min.js dist && cp node_modules/bootstrap/dist/js/bootstrap.min.js.map dist && cp node_modules/bootstrap/dist/css/bootstrap.min.css dist && cp node_modules/bootstrap/dist/css/bootstrap.min.css.map dist",
|
||||||
"compile": "handlebars src/table.handlebars -f dist/table.handlebars.compiled.js",
|
"compile": "handlebars src/table.handlebars -f dist/table.handlebars.dist.js",
|
||||||
"dev": "npm run copy-dependencies && npm run compile && cd dist && python3 -m http.server 8080"
|
"dev": "npm run copy-dependencies && npm run compile && cd dist && python3 -m http.server 8080"
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="de">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
@@ -13,90 +13,81 @@
|
|||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<nav class="navbar navbar-dark bg-dark">
|
|
||||||
<div class="container">
|
|
||||||
<a class="navbar-brand" href="#">
|
|
||||||
above_me
|
|
||||||
</a>
|
|
||||||
<div class="links">
|
|
||||||
<a href="privacy-policy.html">
|
|
||||||
Privacy policy
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h3>See what's flying right above you!</h1>
|
<div class="intro">
|
||||||
|
<div>
|
||||||
|
<p>
|
||||||
|
Klicke auf <i>Was fliegt über mir?</i> oder gebe hier spezifische Koordinaten und einen Suchradius
|
||||||
|
ein, um zu sehen, was in deiner Nähe gerade fliegt.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Die Daten dieser Webseite basieren auf den Services des
|
||||||
|
<a href="http://wiki.glidernet.org/" target="_blank">Open Glider Network</a>.
|
||||||
|
(Vielen Dank für eure offenen APIs! 😊)
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="button-container">
|
<div class="button-container">
|
||||||
<button type="button" class="btn btn-primary btn-lg" onclick="onClickWhatsAboveMe()"
|
<button type="button" class="btn btn-primary btn-lg" onclick="onClickWhatsAboveMe()"
|
||||||
aria-describedby="whats-above-me-hint">What's above
|
aria-describedby="whats-above-me-hint">Was fliegt über mir?</button>
|
||||||
me?</button>
|
|
||||||
<div id="whats-above-me-hint" class="form-text">
|
<div id="whats-above-me-hint" class="form-text">
|
||||||
By clicking this button you accept our <a href="privacy-policy.html">privacy policy</a> and also
|
Mit Klick auf den Button wird deine aktuelle Position vom Browser übermittelt und es werden die
|
||||||
that
|
Flugzeuge
|
||||||
your current position is sent to the webserver.
|
in deiner Nähe abgefragt. Weder deine Position noch die Anfrage an den Server werden dabei geloggt
|
||||||
|
oder gespeichert.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="alert alert-danger status-message" role="alert" id="no-position-available">
|
<div class="alert alert-danger status-message" role="alert" id="no-position-available">
|
||||||
Error. Position for your device could not be loaded. Please check if you gave permission to this site to
|
Es ist ein Fehler aufgetreten: Dein Browser erlaubt der Webseite nicht, den Standort zu ermitteln.<br>
|
||||||
access your position.
|
Prüfe die Webseitenberechtigungen und versuche es dann erneut.
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="alert alert-danger status-message" role="alert" id="http-error">
|
<div class="alert alert-danger status-message" role="alert" id="http-error">
|
||||||
Error. Could not fetch data. Open the developer console for more information.
|
Es ist ein Fehler aufgetreten: Die Daten konnten nicht geladen werden.<br>
|
||||||
|
(Öffne die Entwicklungskonsole für weitere Informationen.)
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="alert alert-info status-message" role="alert" id="loading-position">
|
<div class="alert alert-info status-message" role="alert" id="loading-position">
|
||||||
Loading position...
|
Position wird vom Browser angefragt…
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="table-container" class="overflow-auto"></div>
|
</div>
|
||||||
|
<div id="table-container" class="overflow-auto"></div>
|
||||||
|
|
||||||
<p>
|
<form>
|
||||||
Either click <i>What's above me?</i> to automatically fetch your location
|
<div class="mb-3">
|
||||||
or enter specific coordinates and range and see whats flying above you right now.
|
<label for="latitude" class="form-label">Breitengrad (Latitude)</label>
|
||||||
</p>
|
<input class="form-control" type="number" name="latitude" id="latitude" placeholder="48.858222"
|
||||||
<p>
|
min="-90" max="90" step=".000000001">
|
||||||
This site works with data provided by the
|
</div>
|
||||||
<a href="http://wiki.glidernet.org/" target="_blank">Open Glider Network</a>.
|
<div class="mb-3">
|
||||||
(Thank you for your open data & APIs! 😊)
|
<label for="longitude" class="form-label">Längengrad (Longitude)</label>
|
||||||
</p>
|
<input class="form-control" type="number" name="longitude" id="longitude" placeholder="2.2945"
|
||||||
|
min="-180" max="180" step=".000000001">
|
||||||
<form>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="latitude" class="form-label">Latitude</label>
|
<label for="range" class="form-label">Range</label>
|
||||||
<input class="form-control" type="number" name="latitude" id="latitude" placeholder="48.858222"
|
<input class="form-control" type="number" name="range" id="range" min="1" max="20" value="20"
|
||||||
min="-90" max="90" step=".000000001">
|
placeholder="1 - 20 km" aria-describedby="range-help" step="1">
|
||||||
|
<div id="range-help" class="form-text">
|
||||||
|
Suchradius (in <i>km</i>) um die angegebenen Koordinaten.
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
</div>
|
||||||
<label for="longitude" class="form-label">Longitude</label>
|
<div class="mb-3 button-container">
|
||||||
<input class="form-control" type="number" name="longitude" id="longitude" placeholder="2.2945"
|
<button type="submit" class="btn btn-primary" aria-describedby="submit-hint">Was fliegt hier?</button>
|
||||||
min="-180" max="180" step=".000000001">
|
<div id="submit-hint" class="form-text">
|
||||||
|
Mit Klick auf <i>Was fliegt hier?</i> werden die Flugzeuge für die angegebenen Koordinaten
|
||||||
|
abgefragt.
|
||||||
|
Weder die Koordinaten noch die Anfrage an den Server werden dabei geloggt oder gespeichert.
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
</div>
|
||||||
<label for="range" class="form-label">Range</label>
|
</form>
|
||||||
<input class="form-control" type="number" name="range" id="range" min="1" max="20" value="20"
|
|
||||||
placeholder="1 - 20 km" aria-describedby="range-help" step="1">
|
|
||||||
<div id="range-help" class="form-text">
|
|
||||||
Range (in <i>km</i>) around given coordinates that should be filtered for.
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="mb-3 button-container">
|
|
||||||
<button type="submit" class="btn btn-primary" aria-describedby="submit-hint">Submit</button>
|
|
||||||
<div id="submit-hint" class="form-text">
|
|
||||||
By clicking this button you accept our <a href="privacy-policy.html">privacy policy</a> and also
|
|
||||||
that the given position is sent to the webserver.
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="bootstrap.min.js"></script>
|
<script src="bootstrap.min.js"></script>
|
||||||
<script src="handlebars.min.js"></script>
|
<script src="handlebars.min.js"></script>
|
||||||
<script src="table.handlebars.compiled.js"></script>
|
<script src="table.handlebars.dist.js"></script>
|
||||||
<script src="main.js"></script>
|
<script src="main.js"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
<!-- Fill this privacy policy. -->
|
|
||||||
@@ -1,5 +1,26 @@
|
|||||||
nav {
|
html, body {
|
||||||
margin-bottom: 3%;
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
display: grid;
|
||||||
|
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
grid-template-columns: 100%;
|
||||||
|
grid-template-rows: auto 1fr auto;
|
||||||
|
grid-template-areas:
|
||||||
|
"intro"
|
||||||
|
"table"
|
||||||
|
"form";
|
||||||
|
|
||||||
|
padding-top: 5%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.intro {
|
||||||
|
grid-area: intro;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button-container {
|
.button-container {
|
||||||
@@ -10,6 +31,7 @@ nav {
|
|||||||
}
|
}
|
||||||
|
|
||||||
form {
|
form {
|
||||||
|
grid-area: form;
|
||||||
margin-top: 12.5%;
|
margin-top: 12.5%;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,7 +54,7 @@ form .button-container {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#table-container {
|
#table-container {
|
||||||
margin: 5% 0;
|
grid-area: table;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user