From cc07b3fdc4b8860a1ee1b25f09039ba3f13ee509 Mon Sep 17 00:00:00 2001 From: Jan Tuomi Date: Tue, 11 Feb 2025 00:25:57 +0200 Subject: Add initial browser UI app --- browser/app.py | 69 ++++++++++++++++ browser/requirements.txt | 11 +++ browser/static/InclusiveSans-Regular.ttf | Bin 0 -> 57124 bytes browser/static/styles.css | 130 +++++++++++++++++++++++++++++++ browser/templates/aside.html.j2 | 16 ++++ browser/templates/base.html.j2 | 20 +++++ browser/templates/error.html.j2 | 6 ++ browser/templates/form_find.html.j2 | 6 ++ browser/templates/form_range.html.j2 | 8 ++ browser/templates/index.html.j2 | 28 +++++++ 10 files changed, 294 insertions(+) create mode 100644 browser/app.py create mode 100644 browser/requirements.txt create mode 100644 browser/static/InclusiveSans-Regular.ttf create mode 100644 browser/static/styles.css create mode 100644 browser/templates/aside.html.j2 create mode 100644 browser/templates/base.html.j2 create mode 100644 browser/templates/error.html.j2 create mode 100644 browser/templates/form_find.html.j2 create mode 100644 browser/templates/form_range.html.j2 create mode 100644 browser/templates/index.html.j2 (limited to 'browser') diff --git a/browser/app.py b/browser/app.py new file mode 100644 index 0000000..1398e93 --- /dev/null +++ b/browser/app.py @@ -0,0 +1,69 @@ +from dotenv import load_dotenv +load_dotenv() + +import os +import sys +import traceback +import tempfile +from flask import Flask, render_template +from flask_compress import Compress # type: ignore + +from log_db import DB, Bound + +app = Flask(__name__) +Compress(app) + +BASE_URL = os.environ["BASE_URL"] +DB_DIR = os.environ["DB_DIR"] if "DB_DIR" in os.environ else tempfile.TemporaryDirectory().name + +print("""\n""" + f"""BASE_URL: {BASE_URL}\n""" + f"""DB_DIR: {DB_DIR}\n""") + +db = DB \ + .configure() \ + .data_dir(DB_DIR) \ + .fields(["id", "name"]) \ + .primary_key("id") \ + .secondary_keys(["name"]) \ + .initialize() + +def error_page(message: str, code: int = 400): + return render_template("error.html.j2", error = message), code + +@app.errorhandler(404) +def not_found(e: Exception): + return error_page("Not found", 404) + +@app.errorhandler(405) +def method_not_allowed(e: Exception): + return error_page(str(e), 405) + +@app.errorhandler(Exception) +def error_handler(e: Exception): + traceback.print_exception(e, file=sys.stderr) + return error_page("Internal server error", 500) + +@app.get("/") +def index(): + return page_find() + +@app.get("/find") +def page_find(): + rows = db.range_by("id", Bound.unbounded(), Bound.unbounded(), limit=100) + + return render_template('index.html.j2', + selected_form = "form_find.html.j2", + field_names = ["id", "name"], + rows = rows, + ) + +@app.get("/range") +def page_range(): + rows = db.range_by("id", Bound.unbounded(), Bound.unbounded(), limit=100) + + return render_template('index.html.j2', + selected_form = "form_range.html.j2", + field_names = ["id", "name"], + rows = rows, + ) diff --git a/browser/requirements.txt b/browser/requirements.txt new file mode 100644 index 0000000..b6b9bff --- /dev/null +++ b/browser/requirements.txt @@ -0,0 +1,11 @@ +blinker==1.9.0 +Brotli==1.1.0 +click==8.1.8 +Flask==3.1.0 +Flask-Compress==1.17 +itsdangerous==2.2.0 +Jinja2==3.1.5 +MarkupSafe==3.0.2 +python-dotenv==1.0.1 +Werkzeug==3.1.3 +zstandard==0.23.0 diff --git a/browser/static/InclusiveSans-Regular.ttf b/browser/static/InclusiveSans-Regular.ttf new file mode 100644 index 0000000..3a30e79 Binary files /dev/null and b/browser/static/InclusiveSans-Regular.ttf differ diff --git a/browser/static/styles.css b/browser/static/styles.css new file mode 100644 index 0000000..73379e7 --- /dev/null +++ b/browser/static/styles.css @@ -0,0 +1,130 @@ +:root { + --blue: rgb(30, 99, 248); + --red: #d42f2f; + --yellow: #ff9800; + --black: rgb(0, 0, 0); + --white: rgb(255, 255, 255); + --gray: #666; + --light-gray-1: #f2f2f2; + --light-gray-2: #f8f6ff; + --gold-trans: #ffcd0455; + + --font-family: "Inclusive Sans", sans-serif; +} + +@font-face { + font-family: "Inclusive Sans"; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(/static/InclusiveSans-Regular.ttf) format("woff2"); +} + +html { + font-family: var(--font-family) !important; + font-size: 16px; +} + +body { + padding: 10px; + margin: 0 auto; + line-height: 24px; +} + +main { + display: flex; + flex-flow: row wrap; + justify-content: space-between; + align-items: flex-start; +} + +a, +.contrast { + color: var(--blue); +} + +h1 { + margin-bottom: 40px; +} + +h1 a { + color: var(--black); + text-decoration: none; +} + +h1:hover a { + border-bottom: 2px dotted var(--blue); + text-decoration: none; +} + +textarea, +input { + font-family: var(--font-family); + font-size: 16px; +} + +button, +input[type="submit"] { + cursor: pointer; + font-size: 16px; + border-radius: 4px; + text-shadow: none; + box-shadow: none; + padding: 5px 8px; + border: 0; + background-color: var(--blue); + color: var(--white); + + margin-top: 20px; +} + +button.red, +input[type="submit"].red { + background-color: var(--red); +} + +button.blue, +input[type="submit"].blue { + background-color: var(--blue); +} + +button.yellow, +input[type="submit"].yellow { + background-color: var(--yellow); +} + +input[type="text"], +input[type*="date"] { + font-size: 16px; + color: var(--black); +} + +input[type="text"]:disabled, +input[type*="date"]:disabled { + color: var(--gray); +} + +main > aside { + width: 250px; +} + +main > .results { + flex: 1; + overflow-y: scroll; + max-height: 100%; +} + +table { + width: 100%; +} + +th, +td { + min-width: 100px; + text-align: left; + padding: 7px 5px; +} + +tr:nth-of-type(odd) td { + background-color: var(--light-gray-2); +} diff --git a/browser/templates/aside.html.j2 b/browser/templates/aside.html.j2 new file mode 100644 index 0000000..eb8c9cf --- /dev/null +++ b/browser/templates/aside.html.j2 @@ -0,0 +1,16 @@ +{% block aside %} + +{% endblock %} diff --git a/browser/templates/base.html.j2 b/browser/templates/base.html.j2 new file mode 100644 index 0000000..a8a6cf7 --- /dev/null +++ b/browser/templates/base.html.j2 @@ -0,0 +1,20 @@ + + + + + + + + {% block head_meta %} + Database browser + + {% endblock %} + + + + + +

Database browser

+ {% block content %}{% endblock %} + + diff --git a/browser/templates/error.html.j2 b/browser/templates/error.html.j2 new file mode 100644 index 0000000..2d0dc19 --- /dev/null +++ b/browser/templates/error.html.j2 @@ -0,0 +1,6 @@ +{% extends "base.html.j2" %} + +{% block content %} +

Error

+{{ error }} +{% endblock %} diff --git a/browser/templates/form_find.html.j2 b/browser/templates/form_find.html.j2 new file mode 100644 index 0000000..54608b6 --- /dev/null +++ b/browser/templates/form_find.html.j2 @@ -0,0 +1,6 @@ +
+ + + + + diff --git a/browser/templates/form_range.html.j2 b/browser/templates/form_range.html.j2 new file mode 100644 index 0000000..76eb4d2 --- /dev/null +++ b/browser/templates/form_range.html.j2 @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/browser/templates/index.html.j2 b/browser/templates/index.html.j2 new file mode 100644 index 0000000..9713944 --- /dev/null +++ b/browser/templates/index.html.j2 @@ -0,0 +1,28 @@ +{% extends "base.html.j2" %} + +{% block content %} +
+ {% include "aside.html.j2" %} + +
+ + + + {% for field_name in field_names %} + + {% endfor %} + + + + {% for row in rows %} + + {% for field in row %} + + {% endfor %} + + {% endfor %} + +
{{ field_name }}
{{ field }}
+
+
+{% endblock %} -- cgit v1.3