add footer version
2
data/www/browserconfig.xml
Executable file
@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<browserconfig><msapplication><tile><square70x70logo src="/favicon/ms-icon-70x70.png"/><square150x150logo src="/favicon/ms-icon-150x150.png"/><square310x310logo src="/favicon/ms-icon-310x310.png"/><TileColor>#692fbd</TileColor></tile></msapplication></browserconfig>
|
||||
@ -545,4 +545,17 @@ span.empty {
|
||||
text-transform: uppercase;
|
||||
opacity: 0.5;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
footer {
|
||||
align-self: stretch;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
display: flex;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
footer .version {
|
||||
opacity: 0.3;
|
||||
}
|
||||
BIN
data/www/favicon.ico
Executable file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
data/www/favicon/android-icon-144x144.png
Executable file
|
After Width: | Height: | Size: 18 KiB |
BIN
data/www/favicon/android-icon-192x192.png
Executable file
|
After Width: | Height: | Size: 27 KiB |
BIN
data/www/favicon/android-icon-36x36.png
Executable file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
data/www/favicon/android-icon-48x48.png
Executable file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
data/www/favicon/android-icon-72x72.png
Executable file
|
After Width: | Height: | Size: 6.9 KiB |
BIN
data/www/favicon/android-icon-96x96.png
Executable file
|
After Width: | Height: | Size: 10 KiB |
BIN
data/www/favicon/apple-icon-114x114.png
Executable file
|
After Width: | Height: | Size: 13 KiB |
BIN
data/www/favicon/apple-icon-120x120.png
Executable file
|
After Width: | Height: | Size: 14 KiB |
BIN
data/www/favicon/apple-icon-144x144.png
Executable file
|
After Width: | Height: | Size: 18 KiB |
BIN
data/www/favicon/apple-icon-152x152.png
Executable file
|
After Width: | Height: | Size: 20 KiB |
BIN
data/www/favicon/apple-icon-180x180.png
Executable file
|
After Width: | Height: | Size: 26 KiB |
BIN
data/www/favicon/apple-icon-57x57.png
Executable file
|
After Width: | Height: | Size: 5.1 KiB |
BIN
data/www/favicon/apple-icon-60x60.png
Executable file
|
After Width: | Height: | Size: 5.5 KiB |
BIN
data/www/favicon/apple-icon-72x72.png
Executable file
|
After Width: | Height: | Size: 6.9 KiB |
BIN
data/www/favicon/apple-icon-76x76.png
Executable file
|
After Width: | Height: | Size: 7.5 KiB |
BIN
data/www/favicon/apple-icon-precomposed.png
Executable file
|
After Width: | Height: | Size: 28 KiB |
BIN
data/www/favicon/apple-icon.png
Executable file
|
After Width: | Height: | Size: 28 KiB |
BIN
data/www/favicon/favicon-16x16.png
Executable file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
data/www/favicon/favicon-32x32.png
Executable file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
data/www/favicon/favicon-96x96.png
Executable file
|
After Width: | Height: | Size: 10 KiB |
BIN
data/www/favicon/ms-icon-144x144.png
Executable file
|
After Width: | Height: | Size: 18 KiB |
BIN
data/www/favicon/ms-icon-150x150.png
Executable file
|
After Width: | Height: | Size: 20 KiB |
BIN
data/www/favicon/ms-icon-310x310.png
Executable file
|
After Width: | Height: | Size: 61 KiB |
BIN
data/www/favicon/ms-icon-70x70.png
Executable file
|
After Width: | Height: | Size: 6.8 KiB |
@ -21,6 +21,17 @@ jQuery(document).ready(function ($) {
|
||||
|
||||
$(document).on('click', '.variable-edit', function () {
|
||||
const variable = JSON.parse($(this).parents('tr:eq(0)').attr('data-entity'));
|
||||
|
||||
if (variable['selectables']) {
|
||||
var $select = $('<select id="variable-edit-value" name="value" required="required"></select>');
|
||||
$.each(variable['selectables'], function(index, option) {
|
||||
$select.append($('<option></option>').val(option.key).html(option.label));
|
||||
});
|
||||
$('#variable-edit-value').replaceWith($select);
|
||||
} else {
|
||||
$('#variable-edit-value').replaceWith('<input type="text" name="value" id="variable-edit-value" required="required" />');
|
||||
}
|
||||
|
||||
showModal('modal-variable-edit');
|
||||
$('.modal-variable-edit input:visible:eq(0)').focus().select();
|
||||
$('#variable-edit-name').val(variable.name);
|
||||
|
||||
41
data/www/manifest.json
Executable file
@ -0,0 +1,41 @@
|
||||
{
|
||||
"name": "App",
|
||||
"icons": [
|
||||
{
|
||||
"src": "\/favicon/android-icon-36x36.png",
|
||||
"sizes": "36x36",
|
||||
"type": "image\/png",
|
||||
"density": "0.75"
|
||||
},
|
||||
{
|
||||
"src": "\/favicon/android-icon-48x48.png",
|
||||
"sizes": "48x48",
|
||||
"type": "image\/png",
|
||||
"density": "1.0"
|
||||
},
|
||||
{
|
||||
"src": "\/favicon/android-icon-72x72.png",
|
||||
"sizes": "72x72",
|
||||
"type": "image\/png",
|
||||
"density": "1.5"
|
||||
},
|
||||
{
|
||||
"src": "\/favicon/android-icon-96x96.png",
|
||||
"sizes": "96x96",
|
||||
"type": "image\/png",
|
||||
"density": "2.0"
|
||||
},
|
||||
{
|
||||
"src": "\/favicon/android-icon-144x144.png",
|
||||
"sizes": "144x144",
|
||||
"type": "image\/png",
|
||||
"density": "3.0"
|
||||
},
|
||||
{
|
||||
"src": "\/favicon/android-icon-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image\/png",
|
||||
"density": "4.0"
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -16,7 +16,16 @@ class FleetmodeScreenRestart(ObPlugin):
|
||||
return 'Fleetmode Screen Restart'
|
||||
|
||||
def use_variables(self) -> List[Variable]:
|
||||
return []
|
||||
return [
|
||||
# self.add_variable(
|
||||
# name="foo",
|
||||
# description="foo",
|
||||
# type=VariableType.SELECT_SINGLE,
|
||||
# value="foo",
|
||||
# editable=True,
|
||||
# selectables={"alpha": "Alpha", "beta": "Beta"}
|
||||
# )
|
||||
]
|
||||
|
||||
def use_hooks_registrations(self) -> List[HookRegistration]:
|
||||
return [
|
||||
|
||||
@ -24,7 +24,7 @@ class Application:
|
||||
|
||||
def start(self) -> None:
|
||||
self._web_server.run()
|
||||
|
||||
|
||||
def signal_handler(self, signal, frame) -> None:
|
||||
logging.info("Shutting down...")
|
||||
self._stop_event.set()
|
||||
|
||||
@ -55,9 +55,15 @@ class ObPlugin(abc.ABC):
|
||||
def get_plugin_variable_name(self, name: str) -> str:
|
||||
return "{}_{}".format(self.get_plugin_variable_prefix(), name)
|
||||
|
||||
def add_variable(self, name: str, value, type: VariableType, editable: bool, description: str) -> Variable:
|
||||
def add_variable(self, name: str, value='', type: VariableType = VariableType.STRING, editable: bool = True, description: str = '', selectables: Optional[Dict[str, str]] = None) -> Variable:
|
||||
return self._model_store.variable().set_variable(
|
||||
name=self.get_plugin_variable_name(name), value=value, type=type, editable=editable, description=description, plugin=self.use_id()
|
||||
name=self.get_plugin_variable_name(name),
|
||||
value=value,
|
||||
type=type,
|
||||
editable=editable,
|
||||
description=description,
|
||||
selectables=selectables if isinstance(selectables, dict) else None,
|
||||
plugin=self.use_id(),
|
||||
)
|
||||
|
||||
def add_static_hook_registration(self, hook: HookType, priority: int = 0) -> StaticHookRegistration:
|
||||
|
||||
@ -11,10 +11,12 @@ load_dotenv()
|
||||
class ConfigManager:
|
||||
|
||||
DEFAULT_PORT = 5000
|
||||
VERSION_FILE = 'version.txt'
|
||||
|
||||
def __init__(self, variable_manager: VariableManager):
|
||||
self._variable_manager = variable_manager
|
||||
self._CONFIG = {
|
||||
'version': None,
|
||||
'port': self.DEFAULT_PORT,
|
||||
'bind': '0.0.0.0',
|
||||
'debug': False,
|
||||
@ -26,6 +28,7 @@ class ConfigManager:
|
||||
'player_url': 'http://localhost:{}'.format(self.DEFAULT_PORT)
|
||||
}
|
||||
|
||||
self.load_version()
|
||||
self.load_from_env()
|
||||
self.load_from_args()
|
||||
|
||||
@ -49,9 +52,14 @@ class ConfigManager:
|
||||
parser.add_argument('--log-file', '-lf', default=self._CONFIG['log_file'], help='Log File path')
|
||||
parser.add_argument('--log-level', '-ll', default=self._CONFIG['log_level'], help='Log Level')
|
||||
parser.add_argument('--log-stdout', '-ls', default=self._CONFIG['log_stdout'], action='store_true', help='Log to standard output')
|
||||
parser.add_argument('--version', '-v', default=None, action='store_true', help='Get version number')
|
||||
|
||||
return parser.parse_args()
|
||||
|
||||
def load_version(self) -> str:
|
||||
with open(self.VERSION_FILE, 'r') as file:
|
||||
self._CONFIG['version'] = file.read()
|
||||
|
||||
def load_from_args(self) -> None:
|
||||
args = self.parse_arguments()
|
||||
|
||||
@ -67,6 +75,9 @@ class ConfigManager:
|
||||
self._CONFIG['log_level'] = args.log_level
|
||||
if args.log_stdout:
|
||||
self._CONFIG['log_stdout'] = args.log_stdout
|
||||
if args.version:
|
||||
print("Obscreen version v{} (https://github.com/jr-k/obscreen)".format(self._CONFIG['version']))
|
||||
sys.exit(0)
|
||||
|
||||
def load_from_env(self) -> None:
|
||||
for key in self._CONFIG:
|
||||
|
||||
@ -1,10 +1,13 @@
|
||||
from typing import Dict, Optional, List, Tuple, Union
|
||||
from src.model.entity.Variable import Variable
|
||||
from src.model.entity.Selectable import Selectable
|
||||
from src.model.enum.VariableType import VariableType
|
||||
from pysondb import PysonDB
|
||||
from pysondb.errors import IdDoesNotExistError
|
||||
from src.utils import get_keys
|
||||
import time
|
||||
|
||||
SELECTABLE_BOOLEAN = {"1": "✅", "0": "❌"}
|
||||
|
||||
class VariableManager:
|
||||
|
||||
@ -15,27 +18,37 @@ class VariableManager:
|
||||
self._var_map = {}
|
||||
self.reload()
|
||||
|
||||
def set_variable(self, name: str, value, type: VariableType, editable: bool, description: str, plugin: Optional[None] = None) -> Variable:
|
||||
def set_variable(self, name: str, value, type: VariableType, editable: bool, description: str, plugin: Optional[None] = None, selectables: Optional[Dict[str, str]] = None) -> Variable:
|
||||
if isinstance(value, bool) and value:
|
||||
value = '1'
|
||||
elif isinstance(value, bool) and not value:
|
||||
value = '0'
|
||||
|
||||
if type == VariableType.BOOL:
|
||||
selectables = SELECTABLE_BOOLEAN
|
||||
|
||||
default_var = {
|
||||
"name": name,
|
||||
"value": value,
|
||||
"type": type.value,
|
||||
"editable": editable,
|
||||
"description": description,
|
||||
"plugin": plugin
|
||||
"plugin": plugin,
|
||||
"selectables": ([{"key": key, "label": label} for key, label in selectables.items()]) if isinstance(selectables, dict) else None
|
||||
}
|
||||
variable = self.get_one_by_name(default_var['name'])
|
||||
|
||||
if not variable:
|
||||
self.add_form(default_var)
|
||||
variable = self.get_one_by_name(default_var['name'])
|
||||
elif variable.description != default_var['description']:
|
||||
self._db.update_by_id(variable.id, {"description": default_var['description']})
|
||||
else:
|
||||
same_selectables = get_keys(default_var, 'selectables') == get_keys(variable, 'selectables')
|
||||
|
||||
if variable.description != default_var['description']:
|
||||
self._db.update_by_id(variable.id, {"description": default_var['description']})
|
||||
|
||||
if not same_selectables:
|
||||
self._db.update_by_id(variable.id, {"selectables": default_var['selectables']})
|
||||
|
||||
if variable.name == 'last_restart':
|
||||
self._db.update_by_id(variable.id, {"value": time.time()})
|
||||
@ -44,7 +57,7 @@ class VariableManager:
|
||||
|
||||
def reload(self, lang_map: Optional[Dict] = None) -> None:
|
||||
default_vars = [
|
||||
{"name": "lang", "value": "en", "type": VariableType.STRING, "editable": True, "description": lang_map['settings_variable_help_lang'] if lang_map else ""},
|
||||
{"name": "lang", "value": "en", "type": VariableType.SELECT_SINGLE, "editable": True, "description": lang_map['settings_variable_help_lang'] if lang_map else "", "selectables": {"en": "English", "fr": "French"}},
|
||||
{"name": "fleet_enabled", "value": False, "type": VariableType.BOOL, "editable": True, "description": lang_map['settings_variable_help_fleet_enabled'] if lang_map else ""},
|
||||
{"name": "external_url", "value": "", "type": VariableType.STRING, "editable": True, "description": lang_map['settings_variable_help_external_url'] if lang_map else ""},
|
||||
{"name": "last_restart", "value": time.time(), "type": VariableType.TIMESTAMP, "editable": False, "description": lang_map['settings_variable_help_ro_editable'] if lang_map else ""},
|
||||
@ -76,6 +89,9 @@ class VariableManager:
|
||||
if id:
|
||||
raw_variable['id'] = id
|
||||
|
||||
if 'selectables' in raw_variable and raw_variable['selectables']:
|
||||
raw_variable['selectables'] = [Selectable(**selectable) for selectable in raw_variable['selectables']]
|
||||
|
||||
return Variable(**raw_variable)
|
||||
|
||||
@staticmethod
|
||||
@ -105,7 +121,8 @@ class VariableManager:
|
||||
return self.get_one_by(query=lambda v: v['name'] == name)
|
||||
|
||||
def get_one_by(self, query) -> Optional[Variable]:
|
||||
variables = self.hydrate_dict(self._db.get_by_query(query=query))
|
||||
object = self._db.get_by_query(query=query)
|
||||
variables = self.hydrate_dict(object)
|
||||
if len(variables) == 1:
|
||||
return variables[0]
|
||||
elif len(variables) > 1:
|
||||
|
||||
34
src/model/entity/Selectable.py
Executable file
@ -0,0 +1,34 @@
|
||||
|
||||
class Selectable:
|
||||
|
||||
def __init__(self, key: str = '', label: str = ''):
|
||||
self._key = key
|
||||
self._label = label
|
||||
|
||||
@property
|
||||
def key(self) -> str:
|
||||
return self._key
|
||||
|
||||
@key.setter
|
||||
def key(self, value: str):
|
||||
self._key = value
|
||||
|
||||
@property
|
||||
def label(self) -> str:
|
||||
return self._label
|
||||
|
||||
@label.setter
|
||||
def label(self, value: str):
|
||||
self._label = value
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"Selectable(" \
|
||||
f"key='{self.key}',\n" \
|
||||
f"label='{self.label}',\n" \
|
||||
f")"
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
return {
|
||||
"key": self.key,
|
||||
"label": self.label
|
||||
}
|
||||
@ -1,8 +1,9 @@
|
||||
import json
|
||||
import time
|
||||
|
||||
from typing import Optional, Union
|
||||
from typing import Optional, Union, Dict, List
|
||||
from src.model.enum.VariableType import VariableType
|
||||
from src.model.entity.Selectable import Selectable
|
||||
from src.utils import str_to_enum
|
||||
|
||||
|
||||
@ -10,7 +11,7 @@ class Variable:
|
||||
|
||||
def __init__(self, name: str = '', description: str = '', type: Union[VariableType, str] = VariableType.STRING,
|
||||
value: Union[int, bool, str] = '', editable: bool = True, id: Optional[str] = None,
|
||||
plugin: Optional[str] = None):
|
||||
plugin: Optional[str] = None, selectables: Optional[List[Selectable]] = None):
|
||||
self._id = id if id else None
|
||||
self._name = name
|
||||
self._type = str_to_enum(type, VariableType) if isinstance(type, str) else type
|
||||
@ -18,11 +19,23 @@ class Variable:
|
||||
self._value = value
|
||||
self._editable = editable
|
||||
self._plugin = plugin
|
||||
self._selectables = selectables
|
||||
|
||||
@property
|
||||
def id(self) -> Union[int, str]:
|
||||
return self._id
|
||||
|
||||
@property
|
||||
def selectables(self) -> List[Selectable]:
|
||||
return self._selectables
|
||||
|
||||
@selectables.setter
|
||||
def selectables(self, value: List[Selectable]):
|
||||
self._selectables = value
|
||||
|
||||
def add_selectable(self, value: Selectable):
|
||||
self._selectables.append(value)
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
return self._name
|
||||
@ -80,6 +93,7 @@ class Variable:
|
||||
f"description='{self.description}',\n" \
|
||||
f"editable='{self.editable}',\n" \
|
||||
f"plugin='{self.plugin}',\n" \
|
||||
f"selectables='{self.selectables}',\n" \
|
||||
f")"
|
||||
|
||||
def to_json(self) -> str:
|
||||
@ -94,6 +108,7 @@ class Variable:
|
||||
"description": self.description,
|
||||
"editable": self.editable,
|
||||
"plugin": self.plugin,
|
||||
"selectables": [selectable.to_dict() for selectable in self.selectables] if isinstance(self._selectables, list) else None
|
||||
}
|
||||
|
||||
def as_bool(self) -> bool:
|
||||
@ -105,18 +120,22 @@ class Variable:
|
||||
def as_int(self) -> int:
|
||||
return int(self._value)
|
||||
|
||||
def as_ctime(self):
|
||||
def as_ctime(self) -> int:
|
||||
return time.ctime(self._value)
|
||||
|
||||
def display(self):
|
||||
def display(self) -> Union[int, bool, str]:
|
||||
if self.type == VariableType.INT:
|
||||
return self.as_int()
|
||||
elif self.type == VariableType.BOOL:
|
||||
return self.as_bool()
|
||||
elif self.type == VariableType.TIMESTAMP:
|
||||
return self.as_ctime()
|
||||
elif self.type == VariableType.SELECT_SINGLE:
|
||||
for selectable in self.selectables:
|
||||
if selectable.key == self.value:
|
||||
return str(selectable.label)
|
||||
|
||||
return self.as_string()
|
||||
|
||||
def is_from_plugin(self):
|
||||
return self.plugin
|
||||
def is_from_plugin(self) -> Optional[str]:
|
||||
return self.plugin
|
||||
|
||||
@ -5,5 +5,6 @@ class VariableType(Enum):
|
||||
|
||||
BOOL = 'bool'
|
||||
STRING = 'string'
|
||||
SELECT_SINGLE = 'string'
|
||||
INT = 'int'
|
||||
TIMESTAMP = 'timestamp'
|
||||
|
||||
@ -22,6 +22,7 @@ class TemplateRenderer:
|
||||
globals = dict(
|
||||
STATIC_PREFIX="/{}/{}/".format(WebDirConstant.FOLDER_STATIC, WebDirConstant.FOLDER_STATIC_WEB_ASSETS),
|
||||
FLEET_ENABLED=self._model_store.variable().map().get('fleet_enabled').as_bool(),
|
||||
VERSION=self._model_store.config().map().get('version'),
|
||||
LANG=self._model_store.variable().map().get('lang').as_string(),
|
||||
HOOK=self._render_hook,
|
||||
)
|
||||
|
||||
23
src/utils.py
@ -2,10 +2,31 @@ import re
|
||||
import subprocess
|
||||
import platform
|
||||
|
||||
from typing import Optional
|
||||
from typing import Optional, List
|
||||
from enum import Enum
|
||||
|
||||
|
||||
def get_keys(dict_or_object, key_list_name: str, key_attr_name: str = 'key') -> Optional[List]:
|
||||
if dict_or_object is None:
|
||||
return None
|
||||
|
||||
is_dict = isinstance(dict_or_object, dict)
|
||||
is_object = not is_dict and isinstance(dict_or_object, object)
|
||||
|
||||
if is_dict:
|
||||
iterable = dict_or_object[key_list_name]
|
||||
if iterable is None:
|
||||
return None
|
||||
return [item[key_attr_name] for item in iterable]
|
||||
|
||||
if is_object:
|
||||
iterable = getattr(dict_or_object, key_list_name)
|
||||
if iterable is None:
|
||||
return None
|
||||
return [getattr(item, key_attr_name) for item in iterable]
|
||||
|
||||
return None
|
||||
|
||||
def str_to_enum(str_val: str, enum_class) -> Enum:
|
||||
for enum_item in enum_class:
|
||||
if enum_item.value == str_val:
|
||||
|
||||
@ -1 +1 @@
|
||||
1.4
|
||||
1.5
|
||||
@ -6,6 +6,24 @@
|
||||
</title>
|
||||
<meta name="robots" content="noindex, nofollow">
|
||||
<meta name="google" content="notranslate">
|
||||
<link rel="apple-touch-icon" sizes="57x57" href="{{ STATIC_PREFIX }}favicon/apple-icon-57x57.png">
|
||||
<link rel="apple-touch-icon" sizes="60x60" href="{{ STATIC_PREFIX }}favicon/apple-icon-60x60.png">
|
||||
<link rel="apple-touch-icon" sizes="72x72" href="{{ STATIC_PREFIX }}favicon/apple-icon-72x72.png">
|
||||
<link rel="apple-touch-icon" sizes="76x76" href="{{ STATIC_PREFIX }}favicon/apple-icon-76x76.png">
|
||||
<link rel="apple-touch-icon" sizes="114x114" href="{{ STATIC_PREFIX }}favicon/apple-icon-114x114.png">
|
||||
<link rel="apple-touch-icon" sizes="120x120" href="{{ STATIC_PREFIX }}favicon/apple-icon-120x120.png">
|
||||
<link rel="apple-touch-icon" sizes="144x144" href="{{ STATIC_PREFIX }}favicon/apple-icon-144x144.png">
|
||||
<link rel="apple-touch-icon" sizes="152x152" href="{{ STATIC_PREFIX }}favicon/apple-icon-152x152.png">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="{{ STATIC_PREFIX }}favicon/apple-icon-180x180.png">
|
||||
<link rel="icon" type="image/png" sizes="192x192" href="{{ STATIC_PREFIX }}favicon/android-icon-192x192.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="{{ STATIC_PREFIX }}favicon/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="96x96" href="{{ STATIC_PREFIX }}favicon/favicon-96x96.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="{{ STATIC_PREFIX }}favicon/favicon-16x16.png">
|
||||
<link rel="manifest" href="{{ STATIC_PREFIX }}/manifest.json">
|
||||
<meta name="msapplication-TileColor" content="#692fbd">
|
||||
<meta name="msapplication-TileImage" content="{{ STATIC_PREFIX }}favicon/ms-icon-144x144.png">
|
||||
<meta name="theme-color" content="#692fbd">
|
||||
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap" rel="stylesheet">
|
||||
@ -65,6 +83,8 @@
|
||||
{% block footer %}
|
||||
<footer>
|
||||
{{ HOOK(H_ROOT_FOOTER) }}
|
||||
|
||||
<p class="version">Obscreen version {{ VERSION }}</p>
|
||||
</footer>
|
||||
{% endblock %}
|
||||
</div>
|
||||
|
||||
@ -7,21 +7,21 @@
|
||||
<div class="form-group">
|
||||
<label for="screen-add-name">{{ l.fleet_screen_form_label_name }}</label>
|
||||
<div class="widget">
|
||||
<input name="name" type="text" id="screen-add-name" required="required"/>
|
||||
<input name="name" type="text" id="screen-add-name" required="required" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="screen-add-host">{{ l.fleet_screen_form_label_host }}</label>
|
||||
<div class="widget">
|
||||
<input type="text" name="host" id="screen-add-host" required="required"/>
|
||||
<input type="text" name="host" id="screen-add-host" required="required" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="screen-add-port">{{ l.fleet_screen_form_label_port }}</label>
|
||||
<div class="widget">
|
||||
<input type="number" name="port" id="screen-add-port" required="required"/>
|
||||
<input type="number" name="port" id="screen-add-port" required="required" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@ -4,26 +4,26 @@
|
||||
</h2>
|
||||
|
||||
<form action="/fleet/screen/edit" method="POST">
|
||||
<input type="hidden" name="id" id="screen-edit-id"/>
|
||||
<input type="hidden" name="id" id="screen-edit-id" />
|
||||
|
||||
<div class="form-group">
|
||||
<label for="screen-edit-name">{{ l.fleet_screen_form_label_name }}</label>
|
||||
<div class="widget">
|
||||
<input type="text" name="name" id="screen-edit-name" required="required"/>
|
||||
<input type="text" name="name" id="screen-edit-name" required="required" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="screen-edit-host">{{ l.fleet_screen_form_label_host }}</label>
|
||||
<div class="widget">
|
||||
<input type="text" name="host" id="screen-edit-host" required="required"/>
|
||||
<input type="text" name="host" id="screen-edit-host" required="required" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="screen-edit-port">{{ l.fleet_screen_form_label_port }}</label>
|
||||
<div class="widget">
|
||||
<input type="number" name="port" id="screen-edit-port" required="required"/>
|
||||
<input type="number" name="port" id="screen-edit-port" required="required" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@ -7,9 +7,9 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% set last_plugin = '' %}
|
||||
{% set ns = namespace(last_plugin='') %}
|
||||
{% for variable in variables %}
|
||||
{% if variable.plugin and last_plugin != variable.plugin %}
|
||||
{% if variable.plugin and ns.last_plugin != variable.plugin %}
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<h3>
|
||||
@ -26,8 +26,16 @@
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
{% if variable.value %}
|
||||
{{ variable.value }}
|
||||
{% if variable.value %}
|
||||
{% if variable.type.value == 'bool' %}
|
||||
{% if variable.display() %}
|
||||
✅
|
||||
{% else %}
|
||||
❌
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{{ variable.display() }}
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<span class="empty">{{ l.common_empty }}</span>
|
||||
{% endif %}
|
||||
@ -38,7 +46,7 @@
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% set last_plugin = variable.plugin %}
|
||||
{% set ns.last_plugin = variable.plugin %}
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
@ -4,19 +4,19 @@
|
||||
</h2>
|
||||
|
||||
<form action="/settings/variable/edit" method="POST">
|
||||
<input type="hidden" name="id" id="variable-edit-id"/>
|
||||
<input type="hidden" name="id" id="variable-edit-id" />
|
||||
|
||||
<div class="form-group">
|
||||
<label for="variable-edit-name">{{ l.settings_variable_form_label_name }}</label>
|
||||
<div class="widget">
|
||||
<input type="text" name="name" id="variable-edit-name" required="required" disabled="disabled"/>
|
||||
<input type="text" name="name" id="variable-edit-name" required="required" disabled="disabled" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="variable-edit-value">{{ l.settings_variable_form_label_value }}</label>
|
||||
<div class="widget">
|
||||
<input type="text" name="value" id="variable-edit-value" required="required"/>
|
||||
<input type="text" name="value" id="variable-edit-value" required="required" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
<div class="form-group">
|
||||
<label for="slide-add-name">{{ l.slideshow_slide_form_label_name }}</label>
|
||||
<div class="widget">
|
||||
<input name="name" type="text" id="slide-add-name" required="required"/>
|
||||
<input name="name" type="text" id="slide-add-name" required="required" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
@ -24,16 +24,16 @@
|
||||
<div class="form-group object-input">
|
||||
<label for="slide-add-duration">{{ l.slideshow_slide_form_label_object }}</label>
|
||||
<div class="widget">
|
||||
<input type="text" name="object" id="slide-add-object-input-text" class="slide-add-object-input"/>
|
||||
<input type="text" name="object" id="slide-add-object-input-text" class="slide-add-object-input" />
|
||||
<input type="file" name="object" id="slide-add-object-input-upload"
|
||||
class="slide-add-object-input hidden" disabled="disabled"/>
|
||||
class="slide-add-object-input hidden" disabled="disabled" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="slide-add-duration">{{ l.slideshow_slide_form_label_duration }}</label>
|
||||
<div class="widget">
|
||||
<input type="number" name="duration" id="slide-add-duration" required="required"/>
|
||||
<input type="number" name="duration" id="slide-add-duration" required="required" />
|
||||
<span>{{ l.slideshow_slide_form_label_duration_unit }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -4,12 +4,12 @@
|
||||
</h2>
|
||||
|
||||
<form action="/slideshow/slide/edit" method="POST">
|
||||
<input type="hidden" name="id" id="slide-edit-id"/>
|
||||
<input type="hidden" name="id" id="slide-edit-id" />
|
||||
|
||||
<div class="form-group">
|
||||
<label for="slide-edit-name">{{ l.slideshow_slide_form_label_name }}</label>
|
||||
<div class="widget">
|
||||
<input type="text" name="name" id="slide-edit-name" required="required"/>
|
||||
<input type="text" name="name" id="slide-edit-name" required="required" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
@ -26,14 +26,14 @@
|
||||
<div class="form-group">
|
||||
<label for="slide-edit-location">{{ l.slideshow_slide_form_label_location }}</label>
|
||||
<div class="widget">
|
||||
<input type="text" name="location" id="slide-edit-location" disabled="disabled"/>
|
||||
<input type="text" name="location" id="slide-edit-location" disabled="disabled" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="slide-edit-duration">{{ l.slideshow_slide_form_label_duration }}</label>
|
||||
<div class="widget">
|
||||
<input type="number" name="duration" id="slide-edit-duration" required="required"/>
|
||||
<input type="number" name="duration" id="slide-edit-duration" required="required" />
|
||||
<span>{{ l.slideshow_slide_form_label_duration_unit }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -34,13 +34,31 @@
|
||||
{% for ro_variable in ro_variables %}
|
||||
<tr>
|
||||
<td>{{ ro_variable.description }}</td>
|
||||
<td>{{ ro_variable.display() }}</td>
|
||||
<td>
|
||||
{% if ro_variable.type.value == 'bool' %}
|
||||
{% if ro_variable.display() %}
|
||||
✅
|
||||
{% else %}
|
||||
❌
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{{ ro_variable.display() }}
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% for env_key, env_value in env_variables.items() %}
|
||||
<tr>
|
||||
<td>{{ env_key }}</td>
|
||||
<td>{{ env_value }}</td>
|
||||
<td>
|
||||
{% if env_value == true %}
|
||||
✅
|
||||
{% elif env_value == false %}
|
||||
❌
|
||||
{% else %}
|
||||
{{ env_value }}
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
|
||||