add config through UI
This commit is contained in:
parent
51f1f55163
commit
709e065ed4
10
README.md
10
README.md
@ -16,6 +16,7 @@ cd obscreen && pip3 install -r requirements.txt && cp data/slideshow.json.dist d
|
||||
|
||||
## Configure
|
||||
- Server configuration is available in `config.py` file.
|
||||
- Application configuration is available in `http://localhost:5000/settings` page.
|
||||
|
||||
## Run
|
||||
|
||||
@ -62,11 +63,4 @@ sudo rm /etc/nginx/sites-enabled/default 2>/dev/null
|
||||
sudo ln -s "$(pwd)/system/nginx-obscreen" /etc/nginx/sites-enabled
|
||||
sudo systemctl reload nginx
|
||||
```
|
||||
2. Configure `nano config.py`
|
||||
```js
|
||||
{
|
||||
// ...
|
||||
"reverse_proxy_mode": True,
|
||||
// ...
|
||||
}
|
||||
```
|
||||
2. Set `reverse_proxy_mode` to `true` in settings page
|
||||
|
||||
@ -1,8 +1,5 @@
|
||||
config = {
|
||||
"config": False, # Enable autoreload for html/jinja files
|
||||
"port": 5000, # Application port
|
||||
"debug": False, # Enable autoreload for html/jinja files
|
||||
"reverse_proxy_mode": False, # True if you want to use nginx on port 80
|
||||
"lang": "en", # Language for manage view "fr" or "en"
|
||||
"lx_file": '/home/pi/.config/lxsession/LXDE-pi/autostart' # Path to lx autostart file,
|
||||
"fleet_enabled": False # Enable fleet management view
|
||||
"lx_file": '/home/pi/.config/lxsession/LXDE-pi/autostart' # Path to lx autostart file
|
||||
}
|
||||
|
||||
38
data/www/js/settings.js
Normal file
38
data/www/js/settings.js
Normal file
@ -0,0 +1,38 @@
|
||||
jQuery(document).ready(function ($) {
|
||||
const $modalsRoot = $('.modals');
|
||||
|
||||
const showModal = function (modalClass) {
|
||||
$modalsRoot.removeClass('hidden').find('form').trigger('reset');
|
||||
$modalsRoot.find('.modal').addClass('hidden');
|
||||
$modalsRoot.find('.modal.' + modalClass).removeClass('hidden');
|
||||
};
|
||||
|
||||
const hideModal = function () {
|
||||
$modalsRoot.addClass('hidden').find('form').trigger('reset');
|
||||
};
|
||||
|
||||
const main = function () {
|
||||
|
||||
};
|
||||
|
||||
$(document).on('click', '.modal-close', function () {
|
||||
hideModal();
|
||||
});
|
||||
|
||||
$(document).on('click', '.variable-edit', function () {
|
||||
const variable = JSON.parse($(this).parents('tr:eq(0)').attr('data-entity'));
|
||||
showModal('modal-variable-edit');
|
||||
$('.modal-variable-edit input:visible:eq(0)').focus().select();
|
||||
$('#variable-edit-name').val(variable.name);
|
||||
$('#variable-edit-value').val(variable.value);
|
||||
$('#variable-edit-id').val(variable.id);
|
||||
});
|
||||
|
||||
$(document).keyup(function (e) {
|
||||
if (e.key === "Escape") {
|
||||
hideModal();
|
||||
}
|
||||
});
|
||||
|
||||
main();
|
||||
});
|
||||
20
lang/en.json
20
lang/en.json
@ -46,11 +46,25 @@
|
||||
"fleet_screen_form_button_cancel": "Cancel",
|
||||
"js_fleet_screen_delete_confirmation": "Are you sure?",
|
||||
|
||||
"settings_page_title": "Settings",
|
||||
"settings_variable_panel": "Variables",
|
||||
"settings_variable_panel_th_name": "Name",
|
||||
"settings_variable_panel_th_description": "Help",
|
||||
"settings_variable_panel_th_value": "Value",
|
||||
"settings_variable_panel_th_activity": "Options",
|
||||
"settings_variable_form_edit_title": "Edit Variable",
|
||||
"settings_variable_form_edit_submit": "Save",
|
||||
"settings_variable_form_label_name": "Name",
|
||||
"settings_variable_form_label_value": "Value",
|
||||
"settings_variable_form_button_cancel": "Cancel",
|
||||
"settings_variable_help_port": "Application server port (restart needed)",
|
||||
"settings_variable_help_bind": "Application server bind (restart needed)",
|
||||
"settings_variable_help_lang": "Server language [fr,en] (restart needed)",
|
||||
"settings_variable_help_fleet_enabled": "Enable fleet screen management view (restart needed)",
|
||||
|
||||
"sysinfo_page_title": "System infos",
|
||||
"sysinfo_panel_title": "Infos",
|
||||
"sysinfo_panel_th_attribute": "Attribute",
|
||||
"sysinfo_panel_th_value": "Value",
|
||||
"sysinfo_panel_td_ipaddr": "IP Address",
|
||||
|
||||
"settings_page_title": "Settings"
|
||||
"sysinfo_panel_td_ipaddr": "IP Address"
|
||||
}
|
||||
|
||||
20
lang/fr.json
20
lang/fr.json
@ -46,11 +46,25 @@
|
||||
"fleet_screen_form_button_cancel": "Annuler",
|
||||
"js_fleet_screen_delete_confirmation": "Êtes-vous sûr ?",
|
||||
|
||||
"settings_page_title": "Paramètres",
|
||||
"settings_variable_panel": "Variables",
|
||||
"settings_variable_panel_th_name": "Nom",
|
||||
"settings_variable_panel_th_description": "Aide",
|
||||
"settings_variable_panel_th_value": "Valeur",
|
||||
"settings_variable_panel_th_activity": "Options",
|
||||
"settings_variable_form_edit_title": "Modification de la variable",
|
||||
"settings_variable_form_edit_submit": "Enregistrer",
|
||||
"settings_variable_form_label_name": "Nom",
|
||||
"settings_variable_form_label_value": "Valeur",
|
||||
"settings_variable_form_button_cancel": "Annuler",
|
||||
"settings_variable_help_port": "Port du serveur d'application (redémarrage nécessaire)",
|
||||
"settings_variable_help_bind": "Hôte d'attache du serveur d'application (redémarrage nécessaire)",
|
||||
"settings_variable_help_lang": "Langage de l'application [fr,en] (redémarrage nécessaire)",
|
||||
"settings_variable_help_fleet_enabled": "Activer la gestion de flotte des écrans (redémarrage nécessaire)",
|
||||
|
||||
"sysinfo_page_title": "Système",
|
||||
"sysinfo_panel_title": "Informations",
|
||||
"sysinfo_panel_th_attribute": "Attribut",
|
||||
"sysinfo_panel_th_value": "Valeur",
|
||||
"sysinfo_panel_td_ipaddr": "Adresse IP",
|
||||
|
||||
"settings_page_title": "Paramètres"
|
||||
"sysinfo_panel_td_ipaddr": "Adresse IP"
|
||||
}
|
||||
|
||||
29
obscreen.py
29
obscreen.py
@ -8,20 +8,28 @@ import sys
|
||||
|
||||
|
||||
from flask import Flask, send_from_directory
|
||||
from config import config
|
||||
from src.SlideManager import SlideManager
|
||||
from src.ScreenManager import ScreenManager
|
||||
from src.manager.SlideManager import SlideManager
|
||||
from src.manager.ScreenManager import ScreenManager
|
||||
from src.manager.VariableManager import VariableManager
|
||||
from src.controller.PlayerController import PlayerController
|
||||
from src.controller.SlideshowController import SlideshowController
|
||||
from src.controller.FleetController import FleetController
|
||||
from src.controller.SysinfoController import SysinfoController
|
||||
from src.controller.SettingsController import SettingsController
|
||||
from config import config
|
||||
|
||||
# <config>
|
||||
PLAYER_URL = 'http://localhost:{}'.format(config['port'])
|
||||
variable_manager = VariableManager()
|
||||
vars = variable_manager.get_variable_map()
|
||||
|
||||
screen_manager = ScreenManager()
|
||||
slide_manager = SlideManager()
|
||||
with open('./lang/{}.json'.format(config['lang']), 'r') as file:
|
||||
|
||||
PLAYER_URL = 'http://localhost:{}'.format(vars['port'].as_int())
|
||||
with open('./lang/{}.json'.format(vars['lang'].as_string()), 'r') as file:
|
||||
LANGDICT = json.load(file)
|
||||
|
||||
variable_manager.init(LANGDICT)
|
||||
# </config>
|
||||
|
||||
|
||||
@ -73,17 +81,18 @@ if config['lx_file']:
|
||||
@app.context_processor
|
||||
def inject_global_vars():
|
||||
return dict(
|
||||
FLEET_MODE=config['fleet_enabled'],
|
||||
LANG=config['lang'],
|
||||
FLEET_ENABLED=vars['fleet_enabled'].as_bool(),
|
||||
LANG=vars['lang'].as_string(),
|
||||
STATIC_PREFIX='/data/www/'
|
||||
)
|
||||
|
||||
|
||||
PlayerController(app, LANGDICT, slide_manager)
|
||||
SlideshowController(app, LANGDICT, slide_manager)
|
||||
SettingsController(app, LANGDICT, variable_manager)
|
||||
SysinfoController(app, LANGDICT)
|
||||
|
||||
if config['fleet_enabled']:
|
||||
if vars['fleet_enabled'].as_bool():
|
||||
FleetController(app, LANGDICT, screen_manager)
|
||||
|
||||
@app.errorhandler(404)
|
||||
@ -94,8 +103,8 @@ def not_found(e):
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(
|
||||
host=config['bind'] if 'bind' in config else '0.0.0.0',
|
||||
port=config['port'],
|
||||
host=vars['bind'].as_string(),
|
||||
port=vars['port'].as_int(),
|
||||
debug=config['debug']
|
||||
)
|
||||
|
||||
|
||||
@ -6,9 +6,9 @@ from src.model.Screen import Screen
|
||||
|
||||
class FleetController:
|
||||
|
||||
def __init__(self, app, l, screen_manager):
|
||||
def __init__(self, app, lang_dict, screen_manager):
|
||||
self._app = app
|
||||
self._l = l
|
||||
self._lang_dict = lang_dict
|
||||
self._screen_manager = screen_manager
|
||||
self.register()
|
||||
|
||||
@ -24,14 +24,13 @@ class FleetController:
|
||||
def fleet(self):
|
||||
return render_template(
|
||||
'fleet/fleet.jinja.html',
|
||||
l=self._l,
|
||||
screens=self._screen_manager.get_enabled_screens(),
|
||||
)
|
||||
|
||||
def fleet_screen_list(self):
|
||||
return render_template(
|
||||
'fleet/list.jinja.html',
|
||||
l=self._l,
|
||||
l=self._lang_dict,
|
||||
enabled_screens=self._screen_manager.get_enabled_screens(),
|
||||
disabled_screens=self._screen_manager.get_disabled_screens(),
|
||||
)
|
||||
|
||||
@ -6,9 +6,9 @@ from src.utils import get_ip_address
|
||||
|
||||
class PlayerController:
|
||||
|
||||
def __init__(self, app, l, slide_manager):
|
||||
def __init__(self, app, lang_dict, slide_manager):
|
||||
self._app = app
|
||||
self._l = l
|
||||
self._lang_dict = lang_dict
|
||||
self._slide_manager = slide_manager
|
||||
self.register()
|
||||
|
||||
|
||||
27
src/controller/SettingsController.py
Normal file
27
src/controller/SettingsController.py
Normal file
@ -0,0 +1,27 @@
|
||||
import json
|
||||
|
||||
from flask import Flask, render_template, redirect, request, url_for
|
||||
|
||||
|
||||
class SettingsController:
|
||||
|
||||
def __init__(self, app, lang_dict, variable_manager):
|
||||
self._app = app
|
||||
self._lang_dict = lang_dict
|
||||
self._variable_manager = variable_manager
|
||||
self.register()
|
||||
|
||||
def register(self):
|
||||
self._app.add_url_rule('/settings/variable/list', 'settings_variable_list', self.settings_variable_list, methods=['GET'])
|
||||
self._app.add_url_rule('/settings/variable/edit', 'settings_variable_edit', self.settings_variable_edit, methods=['POST'])
|
||||
|
||||
def settings_variable_list(self):
|
||||
return render_template(
|
||||
'settings/list.jinja.html',
|
||||
l=self._lang_dict,
|
||||
variables=self._variable_manager.get_all(),
|
||||
)
|
||||
|
||||
def settings_variable_edit(self):
|
||||
self._variable_manager.update_form(request.form['id'], request.form['value'])
|
||||
return redirect(url_for('settings_variable_list'))
|
||||
@ -10,9 +10,9 @@ from src.utils import str_to_enum
|
||||
|
||||
class SlideshowController:
|
||||
|
||||
def __init__(self, app, l, slide_manager):
|
||||
def __init__(self, app, lang_dict, slide_manager):
|
||||
self._app = app
|
||||
self._l = l
|
||||
self._lang_dict = lang_dict
|
||||
self._slide_manager = slide_manager
|
||||
self.register()
|
||||
|
||||
@ -27,7 +27,7 @@ class SlideshowController:
|
||||
def slideshow(self):
|
||||
return render_template(
|
||||
'slideshow/list.jinja.html',
|
||||
l=self._l,
|
||||
l=self._lang_dict,
|
||||
enabled_slides=self._slide_manager.get_enabled_slides(),
|
||||
disabled_slides=self._slide_manager.get_disabled_slides(),
|
||||
)
|
||||
|
||||
@ -1,14 +1,12 @@
|
||||
import json
|
||||
|
||||
from flask import Flask, render_template, redirect, request, url_for, send_from_directory, jsonify
|
||||
from flask import Flask, render_template
|
||||
from src.utils import get_ip_address
|
||||
|
||||
|
||||
class SysinfoController:
|
||||
|
||||
def __init__(self, app, l):
|
||||
def __init__(self, app, lang_dict):
|
||||
self._app = app
|
||||
self._l = l
|
||||
self._lang_dict = lang_dict
|
||||
self.register()
|
||||
|
||||
def register(self):
|
||||
@ -18,5 +16,5 @@ class SysinfoController:
|
||||
return render_template(
|
||||
'sysinfo/list.jinja.html',
|
||||
ipaddr=get_ip_address(),
|
||||
l=self._l,
|
||||
l=self._lang_dict,
|
||||
)
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
from typing import Dict, Optional, List, Tuple, Union
|
||||
from src.model.Screen import Screen
|
||||
from pysondb import PysonDB
|
||||
from pysondb.errors import IdDoesNotExistError
|
||||
|
||||
|
||||
class ScreenManager:
|
||||
@ -26,7 +27,21 @@ class ScreenManager:
|
||||
return [ScreenManager.hydrate_object(raw_screen) for raw_screen in raw_screens]
|
||||
|
||||
def get(self, id: str) -> Optional[Screen]:
|
||||
return self.hydrate_object(self._db.get_by_id(id), id)
|
||||
try:
|
||||
self.hydrate_object(self._db.get_by_id(id), id)
|
||||
except IdDoesNotExistError:
|
||||
return None
|
||||
|
||||
def get_by(self, query) -> List[Screen]:
|
||||
return self.hydrate_dict(self._db.get_by_query(query=query))
|
||||
|
||||
def get_one_by(self, query) -> Optional[Screen]:
|
||||
screens = self.hydrate_dict(self._db.get_by_query(query=query))
|
||||
if len(screens) == 1:
|
||||
return screens[0]
|
||||
elif len(screens) > 1:
|
||||
raise Error("More than one result for query")
|
||||
return None
|
||||
|
||||
def get_all(self, sort: bool = False) -> List[Screen]:
|
||||
raw_screens = self._db.get_all()
|
||||
@ -54,9 +69,13 @@ class ScreenManager:
|
||||
def update_form(self, id: str, name: str, host: str, port: int) -> None:
|
||||
self._db.update_by_id(id, {"name": name, "host": host, "port": port})
|
||||
|
||||
def add_form(self, screen: Screen) -> None:
|
||||
db_screen = screen.to_dict()
|
||||
del db_screen['id']
|
||||
def add_form(self, screen: Union[Screen, Dict]) -> None:
|
||||
db_screen = screen
|
||||
|
||||
if not isinstance(screen, dict):
|
||||
db_screen = screen.to_dict()
|
||||
del db_screen['id']
|
||||
|
||||
self._db.add(db_screen)
|
||||
|
||||
def delete(self, id: str) -> None:
|
||||
@ -4,6 +4,7 @@ from typing import Dict, Optional, List, Tuple, Union
|
||||
from src.model.Slide import Slide
|
||||
from src.utils import str_to_enum
|
||||
from pysondb import PysonDB
|
||||
from pysondb.errors import IdDoesNotExistError
|
||||
|
||||
|
||||
class SlideManager:
|
||||
@ -29,7 +30,21 @@ class SlideManager:
|
||||
return [SlideManager.hydrate_object(raw_slide) for raw_slide in raw_slides]
|
||||
|
||||
def get(self, id: str) -> Optional[Slide]:
|
||||
return self.hydrate_object(self._db.get_by_id(id), id)
|
||||
try:
|
||||
self.hydrate_object(self._db.get_by_id(id), id)
|
||||
except IdDoesNotExistError:
|
||||
return None
|
||||
|
||||
def get_by(self, query) -> List[Slide]:
|
||||
return self.hydrate_dict(self._db.get_by_query(query=query))
|
||||
|
||||
def get_one_by(self, query) -> Optional[Slide]:
|
||||
slides = self.hydrate_dict(self._db.get_by_query(query=query))
|
||||
if len(slides) == 1:
|
||||
return slides[0]
|
||||
elif len(slides) > 1:
|
||||
raise Error("More than one result for query")
|
||||
return None
|
||||
|
||||
def get_all(self, sort: bool = False) -> List[Slide]:
|
||||
raw_slides = self._db.get_all()
|
||||
@ -57,9 +72,13 @@ class SlideManager:
|
||||
def update_form(self, id: str, name: str, duration: int) -> None:
|
||||
self._db.update_by_id(id, {"name": name, "duration": duration})
|
||||
|
||||
def add_form(self, slide: Slide) -> None:
|
||||
db_slide = slide.to_dict()
|
||||
del db_slide['id']
|
||||
def add_form(self, slide: Union[Slide, Dict]) -> None:
|
||||
db_slide = slide
|
||||
|
||||
if not isinstance(slide, dict):
|
||||
db_slide = slide.to_dict()
|
||||
del db_slide['id']
|
||||
|
||||
self._db.add(db_slide)
|
||||
|
||||
def delete(self, id: str) -> None:
|
||||
95
src/manager/VariableManager.py
Normal file
95
src/manager/VariableManager.py
Normal file
@ -0,0 +1,95 @@
|
||||
from typing import Dict, Optional, List, Tuple, Union
|
||||
from src.model.Variable import Variable
|
||||
from pysondb import PysonDB
|
||||
from pysondb.errors import IdDoesNotExistError
|
||||
|
||||
|
||||
class VariableManager:
|
||||
|
||||
DB_FILE = "data/db/settings.json"
|
||||
|
||||
def __init__(self):
|
||||
self._db = PysonDB(self.DB_FILE)
|
||||
self.init()
|
||||
|
||||
def init(self, lang_dict: Optional[Dict] = None) -> None:
|
||||
default_vars = [
|
||||
{"name": "port", "value": 5000, "description": lang_dict['settings_variable_help_port'] if lang_dict else ""},
|
||||
{"name": "bind", "value": '0.0.0.0', "description": lang_dict['settings_variable_help_bind'] if lang_dict else ""},
|
||||
{"name": "lang", "value": "en", "description": lang_dict['settings_variable_help_lang'] if lang_dict else ""},
|
||||
{"name": "fleet_enabled", "value": "0", "description": lang_dict['settings_variable_help_fleet_enabled'] if lang_dict else ""},
|
||||
]
|
||||
|
||||
for default_var in default_vars:
|
||||
variable = self.get_one_by(query=lambda v: v['name'] == default_var['name'])
|
||||
|
||||
if not variable:
|
||||
self.add_form(default_var)
|
||||
elif variable.description != default_var['description']:
|
||||
self._db.update_by_id(variable.id, {"description": default_var['description']})
|
||||
|
||||
def get_variable_map(self) -> Dict[str, Variable]:
|
||||
var_map = {}
|
||||
|
||||
for var in self.get_all():
|
||||
var_map[var.name] = var
|
||||
|
||||
return var_map
|
||||
|
||||
@staticmethod
|
||||
def hydrate_object(raw_variable: dict, id: Optional[str] = None) -> Variable:
|
||||
if id:
|
||||
raw_variable['id'] = id
|
||||
|
||||
return Variable(**raw_variable)
|
||||
|
||||
@staticmethod
|
||||
def hydrate_dict(raw_variables: dict) -> List[Variable]:
|
||||
return [VariableManager.hydrate_object(raw_variable, raw_id) for raw_id, raw_variable in raw_variables.items()]
|
||||
|
||||
@staticmethod
|
||||
def hydrate_list(raw_variables: list) -> List[Variable]:
|
||||
return [VariableManager.hydrate_object(raw_variable) for raw_variable in raw_variables]
|
||||
|
||||
def get(self, id: str) -> Optional[Variable]:
|
||||
try:
|
||||
self.hydrate_object(self._db.get_by_id(id), id)
|
||||
except IdDoesNotExistError:
|
||||
return None
|
||||
|
||||
def get_by(self, query) -> List[Variable]:
|
||||
return self.hydrate_dict(self._db.get_by_query(query=query))
|
||||
|
||||
def get_one_by(self, query) -> Optional[Variable]:
|
||||
variables = self.hydrate_dict(self._db.get_by_query(query=query))
|
||||
if len(variables) == 1:
|
||||
return variables[0]
|
||||
elif len(variables) > 1:
|
||||
raise Error("More than one result for query")
|
||||
return None
|
||||
|
||||
def get_all(self) -> List[Variable]:
|
||||
raw_variables = self._db.get_all()
|
||||
|
||||
if isinstance(raw_variables, dict):
|
||||
return VariableManager.hydrate_dict(raw_variables)
|
||||
|
||||
return VariableManager.hydrate_list(raw_variables)
|
||||
|
||||
def update_form(self, id: str, value: Union[int, bool, str]) -> None:
|
||||
self._db.update_by_id(id, {"value": value})
|
||||
|
||||
def add_form(self, variable: Union[Variable, Dict]) -> None:
|
||||
db_variable = variable
|
||||
|
||||
if not isinstance(variable, dict):
|
||||
db_variable = variable.to_dict()
|
||||
del db_variable['id']
|
||||
|
||||
self._db.add(db_variable)
|
||||
|
||||
def delete(self, id: str) -> None:
|
||||
self._db.delete_by_id(id)
|
||||
|
||||
def to_dict(self, variables: List[Variable]) -> dict:
|
||||
return [variable.to_dict() for variable in variables]
|
||||
@ -58,7 +58,7 @@ class Screen:
|
||||
self._position = value
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"Slide(" \
|
||||
return f"Screen(" \
|
||||
f"id='{self.id}',\n" \
|
||||
f"name='{self.name}',\n" \
|
||||
f"enabled='{self.enabled}',\n" \
|
||||
@ -72,8 +72,8 @@ class Screen:
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
return {
|
||||
"name": self.name,
|
||||
"id": self.id,
|
||||
"name": self.name,
|
||||
"enabled": self.enabled,
|
||||
"position": self.position,
|
||||
"host": self.host,
|
||||
|
||||
@ -84,8 +84,8 @@ class Slide:
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
return {
|
||||
"name": self.name,
|
||||
"id": self.id,
|
||||
"name": self.name,
|
||||
"enabled": self.enabled,
|
||||
"position": self.position,
|
||||
"type": self.type.value,
|
||||
|
||||
68
src/model/Variable.py
Normal file
68
src/model/Variable.py
Normal file
@ -0,0 +1,68 @@
|
||||
import json
|
||||
|
||||
from typing import Optional, Union
|
||||
|
||||
|
||||
class Variable:
|
||||
|
||||
def __init__(self, name: str = '', description: str = '', value: Union[int, bool, str] = '', id: Optional[str] = None):
|
||||
self._id = id if id else None
|
||||
self._name = name
|
||||
self._description = description
|
||||
self._value = value
|
||||
|
||||
@property
|
||||
def id(self) -> Union[int, str]:
|
||||
return self._id
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
return self._name
|
||||
|
||||
@name.setter
|
||||
def name(self, value: str):
|
||||
self._name = value
|
||||
|
||||
@property
|
||||
def description(self) -> str:
|
||||
return self._description
|
||||
|
||||
@description.setter
|
||||
def description(self, value: str):
|
||||
self._description = value
|
||||
|
||||
@property
|
||||
def value(self) -> Union[int, bool, str]:
|
||||
return self._value
|
||||
|
||||
@value.setter
|
||||
def value(self, value: Union[int, bool, str]):
|
||||
self._value = value
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"Variable(" \
|
||||
f"id='{self.id}',\n" \
|
||||
f"name='{self.name}',\n" \
|
||||
f"value='{self.value}',\n" \
|
||||
f"description='{self.description}',\n" \
|
||||
f")"
|
||||
|
||||
def to_json(self) -> str:
|
||||
return json.dumps(self.to_dict())
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
return {
|
||||
"id": self.id,
|
||||
"name": self.name,
|
||||
"value": self.value,
|
||||
"description": self.description,
|
||||
}
|
||||
|
||||
def as_bool(self):
|
||||
return bool(int(self._value))
|
||||
|
||||
def as_string(self):
|
||||
return str(self._value)
|
||||
|
||||
def as_int(self):
|
||||
return int(self._value)
|
||||
@ -15,9 +15,10 @@
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
{% set fleet_mode = request.args.get('fleet_mode') == '1' %}
|
||||
|
||||
{% block header %}
|
||||
{% if request.args.get('fleet_mode') != '1' %}
|
||||
{% if not fleet_mode %}
|
||||
<header>
|
||||
<h1 class="logo">
|
||||
<img src="{{ STATIC_PREFIX }}img/logo.png" />
|
||||
@ -30,13 +31,18 @@
|
||||
<i class="fa-regular fa-clock"></i> {{ l.slideshow_page_title }}
|
||||
</a>
|
||||
</li>
|
||||
{% if FLEET_MODE %}
|
||||
{% if FLEET_ENABLED %}
|
||||
<li class="{{ 'active' if request.url_rule.endpoint == 'fleet_screen_list' }}">
|
||||
<a href="{{ url_for('fleet_screen_list') }}">
|
||||
<i class="fa fa-tv"></i> {{ l.fleet_page_title }}
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
<li class="{{ 'active' if request.url_rule.endpoint == 'settings_variable_list' }}">
|
||||
<a href="{{ url_for('settings_variable_list') }}">
|
||||
<i class="fa-solid fa-cogs"></i> {{ l.settings_page_title }}
|
||||
</a>
|
||||
</li>
|
||||
<li class="{{ 'active' if request.url_rule.endpoint == 'sysinfo_attribute_list' }}">
|
||||
<a href="{{ url_for('sysinfo_attribute_list') }}">
|
||||
<i class="fa-solid fa-list-check"></i> {{ l.sysinfo_page_title }}
|
||||
|
||||
33
views/settings/component/table.jinja.html
Normal file
33
views/settings/component/table.jinja.html
Normal file
@ -0,0 +1,33 @@
|
||||
<table class="variables">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ l.settings_variable_panel_th_name }}</th>
|
||||
<th>{{ l.settings_variable_panel_th_value }}</th>
|
||||
<th>{{ l.settings_variable_panel_th_description }}</th>
|
||||
<th class="tac">{{ l.settings_variable_panel_th_activity }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for variable in variables %}
|
||||
<tr class="variable-item" data-level="{{ variable.id }}" data-entity="{{ variable.to_json() }}">
|
||||
<td class="infos">
|
||||
<div class="inner">
|
||||
<i class="fa fa-cog icon-left"></i>
|
||||
{{ variable.name }}
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
{{ variable.value }}
|
||||
</td>
|
||||
<td>
|
||||
{{ variable.description }}
|
||||
</td>
|
||||
<td class="actions tac">
|
||||
<a href="javascript:void(0);" class="item-edit variable-edit">
|
||||
<i class="fa fa-pencil"></i>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
34
views/settings/list.jinja.html
Normal file
34
views/settings/list.jinja.html
Normal file
@ -0,0 +1,34 @@
|
||||
{% extends 'base.jinja.html' %}
|
||||
|
||||
|
||||
{% block page_title %}
|
||||
{{ l.settings_page_title }}
|
||||
{% endblock %}
|
||||
|
||||
{% block add_js %}
|
||||
<script src="{{ STATIC_PREFIX }}js/settings.js"></script>
|
||||
{% endblock %}
|
||||
|
||||
{% block page %}
|
||||
<div class="toolbar">
|
||||
<h2>{{ l.settings_page_title }}</h2>
|
||||
</div>
|
||||
<div class="panel">
|
||||
<div class="panel-body">
|
||||
<h3>{{ l.settings_variable_panel }}</h3>
|
||||
|
||||
{% include 'settings/component/table.jinja.html' %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modals hidden">
|
||||
<div class="modals-outer">
|
||||
<a href="javascript:void(0);" class="modal-close">
|
||||
<i class="fa fa-close"></i>
|
||||
</a>
|
||||
<div class="modals-inner">
|
||||
{% include 'settings/modal/edit.jinja.html' %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
32
views/settings/modal/edit.jinja.html
Normal file
32
views/settings/modal/edit.jinja.html
Normal file
@ -0,0 +1,32 @@
|
||||
<div class="modal modal-variable-edit hidden">
|
||||
<h2>
|
||||
{{ l.settings_variable_form_edit_submit }}
|
||||
</h2>
|
||||
|
||||
<form action="/settings/variable/edit" method="POST">
|
||||
<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"/>
|
||||
</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"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<button type="button" class="modal-close">
|
||||
{{ l.settings_variable_form_button_cancel }}
|
||||
</button>
|
||||
<button type="submit" class="green">
|
||||
<i class="fa fa-save icon-left"></i>{{ l.settings_variable_form_edit_submit }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@ -46,9 +46,11 @@
|
||||
<a href="javascript:void(0);" class="item-edit slide-edit">
|
||||
<i class="fa fa-pencil"></i>
|
||||
</a>
|
||||
<a href="{{ slide.location }}" class="item-download slide-download" target="_blank">
|
||||
<i class="fa fa-eye"></i>
|
||||
</a>
|
||||
{% if not fleet_mode %}
|
||||
<a href="{{ slide.location }}" class="item-download slide-download" target="_blank">
|
||||
<i class="fa fa-eye"></i>
|
||||
</a>
|
||||
{% endif %}
|
||||
<a href="javascript:void(0);" class="item-delete slide-delete">
|
||||
<i class="fa fa-trash"></i>
|
||||
</a>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user