mirror of
https://github.com/30hours/3lips.git
synced 2025-02-16 14:07:09 +00:00
Initial UI outline
This commit is contained in:
parent
0b7f5aa839
commit
e3b7d91312
9 changed files with 218 additions and 0 deletions
16
Dockerfile
Normal file
16
Dockerfile
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
FROM python:3.9-slim
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
COPY src /app
|
||||||
|
|
||||||
|
# install any needed packages specified in requirements.txt
|
||||||
|
RUN pip install --no-cache-dir -r requirements.txt
|
||||||
|
|
||||||
|
# make port 5000 available to the world outside this container
|
||||||
|
EXPOSE 5000
|
||||||
|
|
||||||
|
# define environment variable
|
||||||
|
ENV FLASK_APP=main.py
|
||||||
|
|
||||||
|
# run Gunicorn instead of the default Flask development server
|
||||||
|
CMD ["gunicorn", "--bind", "0.0.0.0:5000", "main:app"]
|
12
docker-compose.yml
Normal file
12
docker-compose.yml
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
version: '3'
|
||||||
|
|
||||||
|
services:
|
||||||
|
|
||||||
|
3lips:
|
||||||
|
restart: always
|
||||||
|
build: .
|
||||||
|
image: 3lips
|
||||||
|
ports:
|
||||||
|
- 49156:5000
|
||||||
|
network_mode: bridge
|
||||||
|
container_name: 3lips
|
43
src/main.py
Normal file
43
src/main.py
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
# main.py
|
||||||
|
|
||||||
|
from flask import Flask, render_template, request, jsonify, send_from_directory
|
||||||
|
import os
|
||||||
|
|
||||||
|
app = Flask(__name__)
|
||||||
|
|
||||||
|
# store state data
|
||||||
|
servers = [
|
||||||
|
{"name": "radar4", "url": "radar4.30hours.dev"},
|
||||||
|
{"name": "radar5", "url": "radar5.30hours.dev"}
|
||||||
|
]
|
||||||
|
associators = [
|
||||||
|
{"name": "ADSB Associator", "id": "adsb-associator"}
|
||||||
|
]
|
||||||
|
coordregs = [
|
||||||
|
{"name": "Ellipse 2D Conic Intersection", "id": "ellipse-2d-conic-int"}
|
||||||
|
]
|
||||||
|
|
||||||
|
@app.route("/")
|
||||||
|
def index():
|
||||||
|
return render_template("index.html", servers=servers, \
|
||||||
|
associators=associators, coordregs=coordregs)
|
||||||
|
|
||||||
|
# serve static files from the /app/public folder
|
||||||
|
@app.route('/public/<path:file>')
|
||||||
|
def serve_static(file):
|
||||||
|
base_dir = os.path.abspath(os.path.dirname(__file__))
|
||||||
|
public_folder = os.path.join(base_dir, 'public')
|
||||||
|
return send_from_directory(public_folder, file)
|
||||||
|
|
||||||
|
@app.route("/api")
|
||||||
|
def api():
|
||||||
|
urls = request.args.getlist("url")
|
||||||
|
data = [{"url": url} for url in urls]
|
||||||
|
return jsonify(data)
|
||||||
|
|
||||||
|
@app.route("/map")
|
||||||
|
def map_page():
|
||||||
|
return render_template("map.html")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
app.run(debug=True)
|
19
src/public/js/index.js
Normal file
19
src/public/js/index.js
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
function toggle_button(button) {
|
||||||
|
button.classList.toggle('active');
|
||||||
|
var pressed = button.getAttribute('aria-pressed') === 'false' ? 'true' : 'false';
|
||||||
|
button.setAttribute('aria-pressed', pressed);
|
||||||
|
|
||||||
|
// fix button states
|
||||||
|
if (pressed === 'true') {
|
||||||
|
button.classList.add("btn-success");
|
||||||
|
button.classList.remove("btn-secondary");
|
||||||
|
} else {
|
||||||
|
button.classList.add("btn-secondary");
|
||||||
|
button.classList.remove("btn-success");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the value to server.url when the button is pressed
|
||||||
|
var serverUrl = button.getAttribute('server-url');
|
||||||
|
button.value = pressed === 'true' ? serverUrl : '';
|
||||||
|
console.log(button.value);
|
||||||
|
}
|
6
src/public/lib/bootstrap-5.2.3.min.css
vendored
Normal file
6
src/public/lib/bootstrap-5.2.3.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
6
src/public/lib/bootstrap-5.2.3.min.js
vendored
Normal file
6
src/public/lib/bootstrap-5.2.3.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
2
src/requirements.txt
Normal file
2
src/requirements.txt
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
Flask==3.0.1
|
||||||
|
gunicorn==21.2.0
|
99
src/templates/index.html
Normal file
99
src/templates/index.html
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>3lips</title>
|
||||||
|
<!-- load lib js -->
|
||||||
|
<script src="./public/lib/bootstrap-5.2.3.min.js"></script>
|
||||||
|
<!-- load lib css -->
|
||||||
|
<link rel="stylesheet" href="./public/lib/bootstrap-5.2.3.min.css">
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
margin: 20px;
|
||||||
|
}
|
||||||
|
label {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
input, select {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
.custom-location-fields {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.calculator-form {
|
||||||
|
max-width: 600px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
body .jumbotron h1 {
|
||||||
|
font-family: 'Helvetica', sans-serif !important;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 3.5rem !important;
|
||||||
|
}
|
||||||
|
@media (min-width: 768px) {
|
||||||
|
body .jumbotron h1 {
|
||||||
|
font-family: 'Helvetica', sans-serif !important;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 5rem !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body style="background-color:#f78c58;">
|
||||||
|
<div class="container-md">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="jumbotron">
|
||||||
|
<h1 class="display-4 text-center">3lips</h1>
|
||||||
|
<p class="lead">Coordinate registration for multi-static radar using ellipse intersections. Requires input of <a href="https://github.com/30hours/blah2" target="_blank">blah2</a> servers, and choice of algorithm for association and coordinate registration. This program exposes an API endpoint to generate geographic coordinates and a <a href="https://github.com/CesiumGS/cesium" target="_blank">Cesium</a> map for display.</p>
|
||||||
|
<p class="lead">See <a href="https://github.com/30hours/3lips" target="_blank">github.com/30hours/3lips</a> for more details.</p>
|
||||||
|
</div>
|
||||||
|
<div class="calculator-form">
|
||||||
|
|
||||||
|
<form action="/api" method="get">
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label fw-bold">Servers:</label>
|
||||||
|
{% for server in servers %}
|
||||||
|
<button type="button" class="btn btn-success toggle-button active w-100 mb-1" data-toggle="button" aria-pressed="true" server-url="{{ server.url }}" onclick="toggle_button(this)">{{ server.name }}</button>
|
||||||
|
<input type="hidden" name="url" value="{{ server.url }}">
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label fw-bold">Associator:</label>
|
||||||
|
<select class="form-select" name="associator">
|
||||||
|
{% for associator in associators %}
|
||||||
|
<option value="{{ associator.id }}">{{ associator.name }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label fw-bold">Coordinate Registration:</label>
|
||||||
|
<select class="form-select" name="associator">
|
||||||
|
{% for coordreg in coordregs %}
|
||||||
|
<option value="{{ coordreg.id }}">{{ coordreg.name }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-1">
|
||||||
|
<label class="form-label fw-bold">Run:</label>
|
||||||
|
<button type="submit" class="btn btn-dark w-100">API</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<button class="btn btn-dark w-100">Map</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script src="/public/js/index.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
15
src/templates/map.html
Normal file
15
src/templates/map.html
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
<!-- templates/map.html -->
|
||||||
|
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Map Page</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Map Page</h1>
|
||||||
|
<!-- Your map-related content goes here -->
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Reference in a new issue