info field. ability to go wwithout defaults

This commit is contained in:
2022-05-27 17:14:31 +03:00
parent 8391ad9850
commit 93705f758f
7 changed files with 194 additions and 95 deletions

View File

@@ -18,41 +18,69 @@ Setup:
{
"type": "checkbox",
"name": "my_check",
"default": "off"
"title": "Click to enable",
"default": "on"
},
{
"type": "info",
"title": "Piece of text shown here."
},
{
"type": "number",
"name": "my_number",
"default": "1.0"
"default": "1.0",
"title": "Only numbers allowed."
},
{
"type": "text",
"name": "my_text",
"title": "Any text here",
"default": "some text"
},
{
"type": "range",
"name": "my_slider",
"title": "Slide away!",
"default": "75",
"min": "0",
"max": "100"
},
{
"type": "select",
"title": "Select any from these",
"name": "my_selection",
"default": "select2",
"options": [
"option1",
"select2"
"select2",
"select4",
"select5",
"select9"
]
}
]
}
```
- Copy some images under data/images/
- Start the docker instance
- Open the URL in http://localhost:$EXPOSE
## Label types
Label entries require "type" and "name". All labels can include
a "title" field, which is added as a hover-on text, and "default" for
the default value.
In some cases more fields required.
- checkbox: If "default": "on", checkbox is selected. Otherwise it is unselected.
- text: Any string, if no default: ""
- number: Any number entry, if no default: ""
- range: Requires "min" and "max" values. if no default, default = min.
- select: Requires a list of "options".
- info: Not a selection. Add "title" field to show text instead.
## With nginx:
```

View File

@@ -15,6 +15,7 @@ from flask import (
from revprox import ReverseProxied
# configuration
VERSION = "2022.05.27"
IMAGEDIR = "/data/images/"
LABELDIR = "/data/labels/"
CONFIG_FILE = "/data/config.json"
@@ -33,6 +34,7 @@ app.wsgi_app = ReverseProxied(app.wsgi_app)
@app.before_request
def before_request_func():
g.version = app.config["VERSION"]
try:
with open(app.config["CONFIG_FILE"], "rt") as fp:
g.config = json.load(fp)
@@ -43,7 +45,7 @@ def before_request_func():
logging.warning("config.json could not be read. using defaults.")
g.labels = [
{"type": "checkbox", "name": "my_check", "default": "off"},
{"type": "text", "name": "my_text", "default": "1.0"},
{"type": "text", "name": "my_text", "default": "Some text"},
{
"type": "range",
"name": "my_slider",
@@ -55,8 +57,14 @@ def before_request_func():
g.config = {"title": "Labeler", "labels": g.labels}
g.users = ["user"]
if not "title" in g.config:
g.config["title"] = "Labeler"
for label in g.labels:
label["value"] = label["default"]
if label["type"] == "range":
label["value"] = label.get("default", label.get("min", ""))
else:
label["value"] = label.get("default", "")
def natural_key(string_):
@@ -152,12 +160,7 @@ def main(user=None):
user_name = get_user()
return render_template(
"main.html",
current_user=user_name,
users=g.users,
title=g.config.get("title", "Labeler"),
)
return render_template("main.html", current_user=user_name)
@app.route("/image", methods=["GET", "POST"])
@@ -194,5 +197,4 @@ def show_image(id=None):
labels=labels,
id_minus=id_minus,
id_plus=id_plus,
title=g.config.get("title", "Labeler"),
)

View File

@@ -1,5 +1,5 @@
class ReverseProxied(object):
'''Wrap the application in this middleware and configure the
"""Wrap the application in this middleware and configure the
front-end server to add these headers, to let you quietly bind
this to a URL other than / and to an HTTP scheme that is
different than what is used locally.
@@ -14,19 +14,20 @@ class ReverseProxied(object):
}
:param app: the WSGI application
'''
"""
def __init__(self, app):
self.app = app
def __call__(self, environ, start_response):
script_name = environ.get('HTTP_X_SCRIPT_NAME', '')
script_name = environ.get("HTTP_X_SCRIPT_NAME", "")
if script_name:
environ['SCRIPT_NAME'] = script_name
path_info = environ['PATH_INFO']
environ["SCRIPT_NAME"] = script_name
path_info = environ["PATH_INFO"]
if path_info.startswith(script_name):
environ['PATH_INFO'] = path_info[len(script_name):]
environ["PATH_INFO"] = path_info[len(script_name) :]
scheme = environ.get('HTTP_X_SCHEME', '')
scheme = environ.get("HTTP_X_SCHEME", "")
if scheme:
environ['wsgi.url_scheme'] = scheme
environ["wsgi.url_scheme"] = scheme
return self.app(environ, start_response)

View File

@@ -1,37 +1,87 @@
body { font-family: sans-serif; background: #888; margin: 0px;
min-height: 100vh; width: 100vw; overflow-x: hidden; }
a, h1, h2 { color: #377ba8; }
h1, h2 { font-family: 'Georgia', serif; margin: 0; }
h1 { border-bottom: 2px solid #eee; }
h2 { font-size: 1.2em; }
body {
font-family: sans-serif;
background: #888;
margin: 0px;
min-height: 100vh;
width: 100vw;
overflow-x: hidden;
}
tr,td,tbody { margin: 0px; }
.page {
margin: 0em;
padding: 0em;
background: #888;
min-height: 100vh;
width: 100vw;
}
.page { margin: 0em;
padding: 0em; background: #888; min-height: 100vh; width: 100vw;}
.entries { list-style: none; margin: 0; padding: 0; width:100%; min-height: 95vh; }
.entries {
list-style: none;
margin: 0;
padding: 0;
width: 100%;
min-height: 95vh;
}
.large { font-size: 3em; }
.right { text-align: right; }
.center { text-align: center; }
.large {
font-size: 3em;
}
#image { position: absolute;
left:0px; top:0px;
width: calc(100vw - 220px); /*height:95vh;*/ }
#img { max-width: calc(100vw - 220px); max-height:95vh;
width: auto; height: auto;
display: block; margin-left: auto;
margin-right: auto; }
.right {
text-align: right;
}
#img_title { overflow-x: hidden;
.center {
text-align: center;
}
#home {
position: absolute;
left: 0px;
bottom: 0px;
}
#home a {
color: black;
font-weight: bold;
font-size: large;
background-color: #aaa;
border-radius: 5px;
padding: 2px;
}
#image {
position: absolute;
left: 0px;
top: 0px;
width: calc(100vw - 220px);
/*height:95vh;*/
}
#img {
max-width: calc(100vw - 220px);
max-height: 95vh;
width: auto;
height: auto;
display: block;
margin-left: auto;
margin-right: auto;
}
#img_title {
overflow-x: hidden;
overflow-wrap: anywhere;
}
#topright { position: absolute;
right:0px; top:0px;
#topright {
position: absolute;
right: 0px;
top: 0px;
/*width: 20vw;*/
height: 95vh;
font-size: large; }
font-size: large;
}
.inputcontainer {
z-index: 1;
background-color: #aaa;
@@ -42,24 +92,34 @@ tr,td,tbody { margin: 0px; }
}
input, select {
input,
select {
width: 180px;
font-size: large;
}
input[type="text"] {
input[type="text"] {}
}
input[type="submit"] {
input[type="submit"] {}
}
input[type="checkbox"] {
width: 3em;
height: 1.5em;
}
label { display: block; }
output { display: block; font-weight: bold; }
label {
display: block;
}
output {
display: block;
font-weight: bold;
}
.info {
font-size: initial;
}
.button_next {
width: 2em;
@@ -67,12 +127,15 @@ output { display: block; font-weight: bold; }
font-size: large;
margin-top: 1em;
}
.float_left {
float: left;
}
.float_right {
float: right;
}
.button_save {
height: 3em;
margin-top: 1em;
@@ -80,6 +143,7 @@ output { display: block; font-weight: bold; }
margin-right: 1em;
clear: both;
}
.button_continue {
height: 4em;
margin-top: 3em;

View File

@@ -1,14 +1,15 @@
<!doctype html>
<!DOCTYPE html>
<html>
<head>
<title>{{ title }}</title>
<link rel=stylesheet type=text/css href="{{ url_for('static', filename='style.css') }}">
<meta name="viewport" content="width=440" />
<title>{{ g.config.title }}</title>
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='style.css') }}">
<meta name="viewport" content="width=440">
<meta name="VERSION" content="{{ g.version }}">
<script language="javascript" src="{{ url_for('static', filename='script.js') }}"></script>
</head>
<body>
<div class=page>
<div class="page">
{% block body %}{% endblock %}
</div>
</body>
</html>

View File

@@ -1,12 +1,11 @@
{% extends "layout.html" %}
{% block body %}
<div class="entries">
<div class="center inputcontainer">
<form action="{{ url_for('main') }}" method=post class=add-entry>
<label>Choose user:</label>
<select name="user_name">
{% for user in users %}
{% for user in g.users %}
<option value="{{user}}" {% if user == current_user %}SELECTED{% endif %} >{{user}}</option>
{% endfor %}
</select>

View File

@@ -11,29 +11,33 @@
<input type=hidden value="{{ image_name }}" name=image_name>
{% for label in labels %}
<div class=inputcontainer>
{% if label.type == "info" %}
<label class=info>{{ label.title }}</label>
{% else %}
<label>{{ label.name }}:</label>
<div class=center>
{% if label.type == "checkbox" %}
<input class=center type="checkbox" name="label_{{ label.name }}" {% if label.value == "on" %}checked{% endif %}>
<input class=center type="checkbox" name="label_{{ label.name }}" {% if label.value == "on" %}checked{% endif %} title="{{label.title}}">
{% endif %}
{% if label.type == "text" %}
<input type="text" name="label_{{ label.name }}" value="{{ label.value }}">
<input type="text" name="label_{{ label.name }}" value="{{ label.value }}" title="{{label.title}}">
{% endif %}
{% if label.type == "number" %}
<input type="number" step="any" name="label_{{ label.name }}" value="{{ label.value }}">
<input type="number" step="any" name="label_{{ label.name }}" value="{{ label.value }}" title="{{label.title}}">
{% endif %}
{% if label.type == "range" %}
<input type="range" name="label_{{ label.name }}" value="{{ label.value }}" min="{{ label.min }}" max="{{ label.max }}" oninput="this.nextElementSibling.value = this.value">
<input type="range" name="label_{{ label.name }}" value="{{ label.value }}" min="{{ label.min }}" max="{{ label.max }}" oninput="this.nextElementSibling.value = this.value" title="{{label.title}}">
<output>{{label.value}}</output>
{% endif %}
{% if label.type == "select" %}
<select name="label_{{ label.name }}">
<select name="label_{{ label.name }}" title="{{label.title}}">
{% for opt in label.options %}
<option value="{{opt}}" {% if opt == label.value %}SELECTED{% endif %}>{{opt}}</option>
{% endfor %}
</select>
{% endif %}
</div>
{% endif %}
</div>
{% endfor %}
<div class=center>
@@ -45,8 +49,8 @@
<button class="button_next float_right" onclick="location.href='{{ url_for('show_image', id = id_plus) }}';">&rarr;</button>
<button class="button_continue" onclick="location.href='{{ url_for('show_image') }}';">continue</button>
</div>
</div>
<div id="home"><a href="{{ url_for('main') }}" title="Back to user selection">🏠</a></div>
</div>
<img class=preload src="{{ url_for('static', filename=image_plus) }}" >