mirror of
https://github.com/30hours/3lips.git
synced 2024-11-18 12:33:58 +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