automate builder and widgets dev to prod

* update widgets_generator.py in order to add widgets to client/builder
* update build.py : now run widgets_generatoy.py to get latests widgets state + copy ui/client/builder to ui/builder + add sys_path logic + update from path
This commit is contained in:
Jordan Blasenhauer 2024-08-09 18:44:03 +02:00
parent 29332ff7f3
commit 055e005b34
45 changed files with 46416 additions and 146 deletions

View file

@ -1,12 +1,4 @@
from os.path import join, sep
from sys import path as sys_path
for deps_path in [join(sep, "usr", "share", "bunkerweb", *paths) for paths in (("deps", "python"), ("utils",), ("api",), ("db",))]:
if deps_path not in sys_path:
sys_path.append(deps_path)
from builder.utils.form import get_forms
from .utils.form import get_forms
def global_config_builder(templates: list[dict], plugins: list, settings: dict) -> str:

View file

@ -1,11 +1,4 @@
from os.path import join, sep
from sys import path as sys_path
for deps_path in [join(sep, "usr", "share", "bunkerweb", *paths) for paths in (("deps", "python"), ("utils",), ("api",), ("db",))]:
if deps_path not in sys_path:
sys_path.append(deps_path)
from builder.utils.widgets import stat_widget
from .utils.widgets import stat_widget
def home_builder(data: dict) -> str:

View file

@ -1,14 +1,4 @@
from os.path import join, sep
from sys import path as sys_path
from typing import List
for deps_path in [join(sep, "usr", "share", "bunkerweb", *paths) for paths in (("deps", "python"), ("utils",), ("api",), ("db",))]:
if deps_path not in sys_path:
sys_path.append(deps_path)
from src.instance import Instance
from builder.utils.widgets import instance_widget
from .utils.widgets import instance_widget
def instances_builder(instances: List[Instance]) -> str:

View file

@ -1,11 +1,4 @@
from os.path import join, sep
from sys import path as sys_path
for deps_path in [join(sep, "usr", "share", "bunkerweb", *paths) for paths in (("deps", "python"), ("utils",), ("api",), ("db",))]:
if deps_path not in sys_path:
sys_path.append(deps_path)
from builder.utils.widgets import title_widget, table_widget
from .utils.widgets import title_widget, table_widget
def jobs_builder(jobs):

View file

@ -1,11 +1,4 @@
from os.path import join, sep
from sys import path as sys_path
for deps_path in [join(sep, "usr", "share", "bunkerweb", *paths) for paths in (("deps", "python"), ("utils",), ("api",), ("db",))]:
if deps_path not in sys_path:
sys_path.append(deps_path)
from builder.utils.widgets import title_widget
from .utils.widgets import title_widget
def logs_builder(files: list[str] = [], current_file: str = "", raw_data: str = "") -> str:

View file

@ -1,12 +1,4 @@
from os.path import join, sep
from sys import path as sys_path
for deps_path in [join(sep, "usr", "share", "bunkerweb", *paths) for paths in (("deps", "python"), ("utils",), ("api",), ("db",))]:
if deps_path not in sys_path:
sys_path.append(deps_path)
from builder.utils.form import get_forms, get_service_settings
from .utils.form import get_forms, get_service_settings
def raw_mode_builder(templates: list[dict], plugins: list, global_config: dict, total_config: dict, service_name: str, is_new: bool = False) -> str:

View file

@ -1,13 +1,6 @@
from typing import Union
from os.path import join, sep
from sys import path as sys_path
for deps_path in [join(sep, "usr", "share", "bunkerweb", *paths) for paths in (("deps", "python"), ("utils",), ("api",), ("db",))]:
if deps_path not in sys_path:
sys_path.append(deps_path)
from builder.utils.widgets import title_widget, table_widget
from .utils.widgets import title_widget, table_widget
def services_builder(services):
@ -195,8 +188,7 @@ def services_action(
)
if operation == "draft":
# get reverse of current state for update
draft_value = "no" if is_draft else "yes"
draft_value = "yes" if is_draft else "no"
buttons.append(
{
"id": f"{operation}-service-btn-{server_name}",

View file

@ -120,37 +120,44 @@ def set_easy(template: list, plugins_base: list, settings: dict, is_new: bool) -
Prepare the easy form based on the template and plugins data.
We need to loop on each steps and prepare settings and configs for each step.
"""
template_settings = template.get("settings")
plugins = copy.deepcopy(plugins_base)
# Copy of the plugins base data
plugins = copy.deepcopy(plugins_base)
# Update settings with global config data
for plugin in plugins:
loop_id = 0
total_settings = len(plugin.get("settings"))
for setting, value in plugin.get("settings").items():
loop_id += 1
value = format_setting(setting, value, total_settings, loop_id, template_settings, settings, is_new)
set_multiples(template, plugins, settings)
steps = template.get("steps")
print(steps)
for step in steps:
step_settings = step.get("settings", {})
# Loop on step settings to set the settings value
loop_id = 0
step_settings_output = {}
for setting in step_settings:
loop_id += 1
# Get relate setting from plugins using setting name
plugin = next(
(plugin for plugin in plugins if setting in plugin.get("settings")),
None,
)
if not plugin:
continue
for plugin in plugins:
step_settings_output = {}
for setting, value in plugin.get("settings").items():
if setting not in step_settings:
continue
if not plugin.get("settings").get(setting):
continue
plugin_setting = copy.deepcopy(plugin.get("settings").get(setting))
plugin_setting = format_setting(setting, plugin_setting, len(step_settings), loop_id, template_settings, settings, is_new)
step_settings_output[setting] = plugin_setting
step["settings"] = step_settings_output
step_settings_output[setting] = value
# Case at least one key in step settings, we can add the plugin settings to the step
if len(step_settings_output) and not "plugins" in step:
step["plugins"] = []
if len(step_settings_output):
step_plugin = copy.deepcopy(plugin)
step_plugin["settings"] = step_settings_output
step["plugins"].append(step_plugin)
# remove settings key form step
step.pop("settings", None)
return steps
@ -243,7 +250,7 @@ def get_multiple_from_template(template, multiples):
# loop on settings of a multiple group
for mult_name, mult_settings in multiple_plugin.items():
# Check if at least one settign is matching a multiple setting
# Check if at least one setting is matching a multiple setting
if not format_setting in mult_settings:
continue
@ -307,7 +314,7 @@ def get_multiple_from_settings(settings, multiples):
# loop on settings of a multiple group
for mult_name, mult_settings in multiple_plugins.items():
# Check if at least one settign is matching a multiple setting
# Check if at least one setting is matching a multiple setting
if not format_setting in mult_settings:
continue
@ -473,7 +480,7 @@ def format_setting(
if "multiple" in value:
return value
# Else, we can add additionnal final data
# Else, we can add additional final data
value["method"] = settings.get(name, {}).get("method", "ui")
value["containerClass"] = f"z-{total_settings - loop_id}"

File diff suppressed because it is too large Load diff

View file

@ -18,6 +18,10 @@ ui_dir_static = current_directory.parent.joinpath("static")
ui_dir_templates = current_directory.parent.joinpath("templates")
legacy_dir_static = current_directory.joinpath("legacy", "static")
legacy_dir_templates = current_directory.joinpath("legacy", "templates")
builder_dir_pages = current_directory.joinpath("builder", "pages")
builder_dir_utils = current_directory.joinpath("builder", "utils")
ui_dir_builder = current_directory.parent.joinpath("builder")
ui_dir_builder_utils = current_directory.parent.joinpath("builder", "utils")
statics = ("assets", "css", "flags", "img", "js")
@ -29,6 +33,7 @@ def reset():
remove_dir(opt_dir_setup)
remove_dir(ui_dir_static)
remove_dir(ui_dir_templates)
remove_dir(ui_dir_builder)
def set_dashboard():
@ -146,6 +151,32 @@ def add_legacy():
copytree(legacy_dir_templates.as_posix(), ui_dir_templates.as_posix())
def add_builder_and_widgets():
# First we want to generate widgets by executing "widgets_generator.py" that is on same level
if run_command(["/usr/bin/python3", "widgets_generator.py"]):
if run_command(["python", "widgets_generator.py"]):
exit(1)
# Create output folders
copytree(builder_dir_pages.as_posix(), ui_dir_builder.as_posix())
# I want to loop on each file
for file in ui_dir_builder.glob("*.py"):
# I want to replace "from .utils." by "from builder.utils."
content = file.read_text()
content = content.replace("from .utils.", "from builder.utils.")
content = """from os.path import join, sep
from sys import path as sys_path
for deps_path in [join(sep, "usr", "share", "bunkerweb", *paths) for paths in (("deps", "python"), ("utils",), ("api",), ("db",))]:
if deps_path not in sys_path:
sys_path.append(deps_path)
""" + content
file.write_text(content)
copytree(builder_dir_utils.as_posix(), ui_dir_builder_utils.as_posix())
def build():
"""All steps to build the front end and set it to the flask app"""
reset()
@ -162,6 +193,7 @@ def build():
set_dashboard()
# run_command(["/usr/bin/npm", "run", "build-setup"])
# set_setup()
add_builder_and_widgets()
build()

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,38 @@
from .utils.form import get_forms, get_service_settings
def advanced_mode_builder(templates: list[dict], plugins: list, global_config: dict, total_config: dict, service_name: str, is_new: bool = False) -> str:
"""Render forms with global config data.
ATM we don't need templates but we need to pass at least one to the function (it will simply not override anything).
"""
settings = get_service_settings(service_name, global_config, total_config)
builder = [
{
"type": "card",
"containerColumns": {"pc": 12, "tablet": 12, "mobile": 12},
"widgets": [
{
"type": "Title",
"data": {
"title": service_name,
"type": "container",
"lowercase": True,
},
},
{
"type": "Subtitle",
"data": {"subtitle": "services_manage_subtitle", "type": "container"},
},
{
"type": "Templates",
"data": {
"templates": get_forms(templates, plugins, settings, ("advanced",), is_new, True),
"operation": "new" if is_new else "edit",
"oldServerName": service_name if service_name else "",
},
},
],
}
]
return builder

View file

@ -0,0 +1,669 @@
[
{
"type": "void",
"widgets": [
{
"type": "Button",
"data": {
"text": "bans_not_found"
}
}
]
},
{
"type": "card",
"containerColumns": {
"pc": 12,
"tablet": 12,
"mobile": 12
},
"widgets": [
{
"type": "Title",
"data": {
"title": "bans_title"
}
},
{
"type": "Table",
"data": {
"title": "bans_table_title",
"minWidth": "xl",
"header": [
"bans_table_select",
"bans_table_ip",
"bans_table_reason",
"bans_table_ban_start",
"bans_table_ban_end",
"bans_table_remain",
"bans_table_term"
],
"positions": [1, 1, 1, 3, 3, 2, 1],
"items": [
[
{
"select": false,
"type": "Fields",
"data": {
"setting": {
"columns": {
"pc": 12,
"tablet": 12,
"mobile": 12
},
"disabled": false,
"value": "no",
"inpType": "checkbox",
"id": "select-ban-1",
"name": "select-ban-1",
"label": "select-ban-1",
"hideLabel": true
}
}
},
{
"ip": "127.0.0.1",
"type": "Text",
"data": {
"text": "127.0.0.1"
}
},
{
"reason": "ui",
"type": "Text",
"data": {
"text": "ui"
}
},
{
"ban_start": "1719393920",
"type": "Fields",
"data": {
"setting": {
"columns": {
"pc": 12,
"tablet": 12,
"mobile": 12
},
"disabled": true,
"value": 1719393920,
"inpType": "datepicker",
"id": "datepicker-ban-ban-start-1",
"name": "datepicker-ban-ban-start-1",
"label": "datepicker-ban-ban-start-1",
"hideLabel": true
}
}
},
{
"ban_end": "1719393920",
"type": "Fields",
"data": {
"setting": {
"columns": {
"pc": 12,
"tablet": 12,
"mobile": 12
},
"disabled": true,
"value": 1719393920,
"inpType": "datepicker",
"id": "datepicker-ban-ban-end-1",
"name": "datepicker-ban-ban-end-1",
"label": "datepicker-ban-ban-end-1",
"hideLabel": true
}
}
},
{
"remain": "23 hours and 49 minutes",
"type": "Text",
"data": {
"text": "23 hours and 49 minutes"
}
},
{
"term": "hour(s)",
"type": "Text",
"data": {
"text": "hour(s)"
}
}
],
[
{
"select": false,
"type": "Fields",
"data": {
"setting": {
"columns": {
"pc": 12,
"tablet": 12,
"mobile": 12
},
"disabled": false,
"value": "no",
"inpType": "checkbox",
"id": "select-ban-2",
"name": "select-ban-2",
"label": "select-ban-2",
"hideLabel": true
}
}
},
{
"ip": "127.0.0.1",
"type": "Text",
"data": {
"text": "127.0.0.1"
}
},
{
"reason": "ui",
"type": "Text",
"data": {
"text": "ui"
}
},
{
"ban_start": "1719393920",
"type": "Fields",
"data": {
"setting": {
"columns": {
"pc": 12,
"tablet": 12,
"mobile": 12
},
"disabled": true,
"value": 1719393920,
"inpType": "datepicker",
"id": "datepicker-ban-ban-start-2",
"name": "datepicker-ban-ban-start-2",
"label": "datepicker-ban-ban-start-2",
"hideLabel": true
}
}
},
{
"ban_end": "1719393920",
"type": "Fields",
"data": {
"setting": {
"columns": {
"pc": 12,
"tablet": 12,
"mobile": 12
},
"disabled": true,
"value": 1719393920,
"inpType": "datepicker",
"id": "datepicker-ban-ban-end-2",
"name": "datepicker-ban-ban-end-2",
"label": "datepicker-ban-ban-end-2",
"hideLabel": true
}
}
},
{
"remain": "23 hours and 49 minutes",
"type": "Text",
"data": {
"text": "23 hours and 49 minutes"
}
},
{
"term": "day(s)",
"type": "Text",
"data": {
"text": "day(s)"
}
}
],
[
{
"select": false,
"type": "Fields",
"data": {
"setting": {
"columns": {
"pc": 12,
"tablet": 12,
"mobile": 12
},
"disabled": false,
"value": "no",
"inpType": "checkbox",
"id": "select-ban-3",
"name": "select-ban-3",
"label": "select-ban-3",
"hideLabel": true
}
}
},
{
"ip": "127.0.0.1",
"type": "Text",
"data": {
"text": "127.0.0.1"
}
},
{
"reason": "cor",
"type": "Text",
"data": {
"text": "cor"
}
},
{
"ban_start": "1719393920",
"type": "Fields",
"data": {
"setting": {
"columns": {
"pc": 12,
"tablet": 12,
"mobile": 12
},
"disabled": true,
"value": 1719393920,
"inpType": "datepicker",
"id": "datepicker-ban-ban-start-3",
"name": "datepicker-ban-ban-start-3",
"label": "datepicker-ban-ban-start-3",
"hideLabel": true
}
}
},
{
"ban_end": "1719393920",
"type": "Fields",
"data": {
"setting": {
"columns": {
"pc": 12,
"tablet": 12,
"mobile": 12
},
"disabled": true,
"value": 1719393920,
"inpType": "datepicker",
"id": "datepicker-ban-ban-end-3",
"name": "datepicker-ban-ban-end-3",
"label": "datepicker-ban-ban-end-3",
"hideLabel": true
}
}
},
{
"remain": "23 hours and 49 minutes",
"type": "Text",
"data": {
"text": "23 hours and 49 minutes"
}
},
{
"term": "hour(s)",
"type": "Text",
"data": {
"text": "hour(s)"
}
}
],
[
{
"select": false,
"type": "Fields",
"data": {
"setting": {
"columns": {
"pc": 12,
"tablet": 12,
"mobile": 12
},
"disabled": false,
"value": "no",
"inpType": "checkbox",
"id": "select-ban-4",
"name": "select-ban-4",
"label": "select-ban-4",
"hideLabel": true
}
}
},
{
"ip": "127.0.0.1",
"type": "Text",
"data": {
"text": "127.0.0.1"
}
},
{
"reason": "ui",
"type": "Text",
"data": {
"text": "ui"
}
},
{
"ban_start": "1719393920",
"type": "Fields",
"data": {
"setting": {
"columns": {
"pc": 12,
"tablet": 12,
"mobile": 12
},
"disabled": true,
"value": 1719393920,
"inpType": "datepicker",
"id": "datepicker-ban-ban-start-4",
"name": "datepicker-ban-ban-start-4",
"label": "datepicker-ban-ban-start-4",
"hideLabel": true
}
}
},
{
"ban_end": "1719393920",
"type": "Fields",
"data": {
"setting": {
"columns": {
"pc": 12,
"tablet": 12,
"mobile": 12
},
"disabled": true,
"value": 1719393920,
"inpType": "datepicker",
"id": "datepicker-ban-ban-end-4",
"name": "datepicker-ban-ban-end-4",
"label": "datepicker-ban-ban-end-4",
"hideLabel": true
}
}
},
{
"remain": "23 hours and 49 minutes",
"type": "Text",
"data": {
"text": "23 hours and 49 minutes"
}
},
{
"term": "hour(s)",
"type": "Text",
"data": {
"text": "hour(s)"
}
}
],
[
{
"select": false,
"type": "Fields",
"data": {
"setting": {
"columns": {
"pc": 12,
"tablet": 12,
"mobile": 12
},
"disabled": false,
"value": "no",
"inpType": "checkbox",
"id": "select-ban-5",
"name": "select-ban-5",
"label": "select-ban-5",
"hideLabel": true
}
}
},
{
"ip": "127.0.0.1",
"type": "Text",
"data": {
"text": "127.0.0.1"
}
},
{
"reason": "ui",
"type": "Text",
"data": {
"text": "ui"
}
},
{
"ban_start": "1719393920",
"type": "Fields",
"data": {
"setting": {
"columns": {
"pc": 12,
"tablet": 12,
"mobile": 12
},
"disabled": true,
"value": 1719393920,
"inpType": "datepicker",
"id": "datepicker-ban-ban-start-5",
"name": "datepicker-ban-ban-start-5",
"label": "datepicker-ban-ban-start-5",
"hideLabel": true
}
}
},
{
"ban_end": "1719393920",
"type": "Fields",
"data": {
"setting": {
"columns": {
"pc": 12,
"tablet": 12,
"mobile": 12
},
"disabled": true,
"value": 1719393920,
"inpType": "datepicker",
"id": "datepicker-ban-ban-end-5",
"name": "datepicker-ban-ban-end-5",
"label": "datepicker-ban-ban-end-5",
"hideLabel": true
}
}
},
{
"remain": "23 hours and 49 minutes",
"type": "Text",
"data": {
"text": "23 hours and 49 minutes"
}
},
{
"term": "hour(s)",
"type": "Text",
"data": {
"text": "hour(s)"
}
}
],
[
{
"select": false,
"type": "Fields",
"data": {
"setting": {
"columns": {
"pc": 12,
"tablet": 12,
"mobile": 12
},
"disabled": false,
"value": "no",
"inpType": "checkbox",
"id": "select-ban-6",
"name": "select-ban-6",
"label": "select-ban-6",
"hideLabel": true
}
}
},
{
"ip": "127.0.0.1",
"type": "Text",
"data": {
"text": "127.0.0.1"
}
},
{
"reason": "ui",
"type": "Text",
"data": {
"text": "ui"
}
},
{
"ban_start": "1719393920",
"type": "Fields",
"data": {
"setting": {
"columns": {
"pc": 12,
"tablet": 12,
"mobile": 12
},
"disabled": true,
"value": 1719393920,
"inpType": "datepicker",
"id": "datepicker-ban-ban-start-6",
"name": "datepicker-ban-ban-start-6",
"label": "datepicker-ban-ban-start-6",
"hideLabel": true
}
}
},
{
"ban_end": "1719393920",
"type": "Fields",
"data": {
"setting": {
"columns": {
"pc": 12,
"tablet": 12,
"mobile": 12
},
"disabled": true,
"value": 1719393920,
"inpType": "datepicker",
"id": "datepicker-ban-ban-end-6",
"name": "datepicker-ban-ban-end-6",
"label": "datepicker-ban-ban-end-6",
"hideLabel": true
}
}
},
{
"remain": "23 hours and 49 minutes",
"type": "Text",
"data": {
"text": "23 hours and 49 minutes"
}
},
{
"term": "hour(s)",
"type": "Text",
"data": {
"text": "hour(s)"
}
}
]
],
"filters": [
{
"filter": "table",
"filterName": "keyword",
"type": "keyword",
"value": "",
"keys": ["ip", "ban_start", "ban_end"],
"field": {
"id": "bans-keyword",
"value": "",
"type": "text",
"name": "bans-keyword",
"label": "bans_search",
"placeholder": "inp_keyword",
"isClipboard": false,
"popovers": [
{
"text": "bans_search_desc",
"iconName": "info"
}
],
"columns": {
"pc": 3,
"tablet": 4,
"mobile": 12
}
}
},
{
"filter": "table",
"filterName": "reason",
"type": "select",
"value": "all",
"keys": ["reason"],
"field": {
"id": "bans-reason",
"value": "all",
"values": ["all", "ui", "cor"],
"name": "bans-reason",
"onlyDown": true,
"label": "bans_reason",
"popovers": [
{
"text": "bans_reason_desc",
"iconName": "info"
}
],
"columns": {
"pc": 3,
"tablet": 4,
"mobile": 12
}
}
},
{
"filter": "table",
"filterName": "term",
"type": "select",
"value": "all",
"keys": ["term"],
"field": {
"id": "bans-terms",
"value": "all",
"values": ["all", "hour(s)", "day(s)"],
"name": "bans-terms",
"onlyDown": true,
"label": "bans_terms",
"popovers": [
{
"text": "bans_terms_desc",
"iconName": "info"
}
],
"columns": {
"pc": 3,
"tablet": 4,
"mobile": 12
}
}
}
]
}
}
]
}
]

View file

@ -0,0 +1,296 @@
import json
no_bans = []
bans = [
{
"reason": "ui",
"date": 1719393920,
"ip": "127.0.0.1",
"remain": "23 hours and 49 minutes",
"term": "hour(s)",
"ban_start": 1719393920,
"ban_end": 1719393920,
},
{
"reason": "ui",
"date": 1719393920,
"ip": "127.0.0.1",
"remain": "23 hours and 49 minutes",
"term": "day(s)",
"ban_start": 1719393920,
"ban_end": 1719393920,
},
{
"reason": "core",
"date": 1719393920,
"ip": "127.0.0.1",
"remain": "23 hours and 49 minutes",
"term": "hour(s)",
"ban_start": 1719393920,
"ban_end": 1719393920,
},
{
"reason": "ui",
"date": 1719393920,
"ip": "127.0.0.1",
"remain": "23 hours and 49 minutes",
"term": "hour(s)",
"ban_start": 1719393920,
"ban_end": 1719393920,
},
{
"reason": "ui",
"date": 1719393920,
"ip": "127.0.0.1",
"remain": "23 hours and 49 minutes",
"term": "hour(s)",
"ban_start": 1719393920,
"ban_end": 1719393920,
},
{
"reason": "ui",
"date": 1719393920,
"ip": "127.0.0.1",
"remain": "23 hours and 49 minutes",
"term": "hour(s)",
"ban_start": 1719393920,
"ban_end": 1719393920,
},
]
# Reorder bans dict
for ban in bans:
ban.pop("date")
ban["ip"] = ban.pop("ip")
ban["reason"] = ban.pop("reason")
ban["ban_start"] = ban.pop("ban_start")
ban["ban_end"] = ban.pop("ban_end")
ban["remain"] = ban.pop("remain")
ban["term"] = ban.pop("term")
def get_bans_filter(bans):
if len(bans) <= 5:
return []
total_reasons = ["all"]
total_terms = ["all"]
for ban in bans:
if ban.get("reason") and ban.get("reason") not in total_reasons:
total_reasons.append(ban.get("reason"))
if ban.get("term") and ban.get("term") not in total_terms:
total_terms.append(ban.get("term"))
filters = []
filters.append(
{
"filter": "table",
"filterName": "keyword",
"type": "keyword",
"value": "",
"keys": ["ip", "ban_start", "ban_end"],
"field": {
"id": "bans-keyword",
"value": "",
"type": "text",
"name": "bans-keyword",
"label": "bans_search",
"placeholder": "inp_keyword",
"isClipboard": False,
"popovers": [
{
"text": "bans_search_desc",
"iconName": "info",
},
],
"columns": {"pc": 3, "tablet": 4, "mobile": 12},
},
},
)
if len(total_reasons) > 2:
filters.append(
{
"filter": "table",
"filterName": "reason",
"type": "select",
"value": "all",
"keys": ["reason"],
"field": {
"id": "bans-reason",
"value": "all",
"values": total_reasons,
"name": "bans-reason",
"onlyDown": True,
"label": "bans_reason",
"popovers": [
{
"text": "bans_reason_desc",
"iconName": "info",
},
],
"columns": {"pc": 3, "tablet": 4, "mobile": 12},
},
},
)
if len(total_terms) > 2:
filters.append(
{
"filter": "table",
"filterName": "term",
"type": "select",
"value": "all",
"keys": ["term"],
"field": {
"id": "bans-terms",
"value": "all",
"values": total_terms,
"name": "bans-terms",
"onlyDown": True,
"label": "bans_terms",
"popovers": [
{
"text": "bans_terms_desc",
"iconName": "info",
},
],
"columns": {"pc": 3, "tablet": 4, "mobile": 12},
},
},
)
return filters
def get_bans_list(bans):
data = []
# loop on each dict
id = 0
for ban in bans:
id += 1
item = []
item.append(
{
"select": False,
"type": "Fields",
"data": {
"setting": {
"columns": {"pc": 12, "tablet": 12, "mobile": 12},
"disabled": False,
"value": "no",
"inpType": "checkbox",
"id": f"select-ban-{id}",
"name": f"select-ban-{id}",
"label": f"select-ban-{id}",
"hideLabel": True,
},
},
}
)
for k, v in ban.items():
if k in ("date", "ban_start", "ban_end"):
item.append(
{
k: json.dumps(v) if isinstance(v, dict) else str(v),
"type": "Fields",
"data": {
"setting": {
"columns": {"pc": 12, "tablet": 12, "mobile": 12},
"disabled": True,
"value": v,
"inpType": "datepicker",
"id": f"datepicker-ban-{k}-{id}".replace("_", "-"),
"name": f"datepicker-ban-{k}-{id}".replace("_", "-"),
"label": f"datepicker-ban-{k}-{id}".replace("_", "-"),
"hideLabel": True,
},
},
}
)
continue
item.append(
{
k: json.dumps(v) if isinstance(v, dict) else str(v),
"type": "Text",
"data": {
"text": json.dumps(v) if isinstance(v, dict) else str(v),
},
}
)
data.append(item)
return data
def bans_builder(bans):
builder = [
{
"type": "void",
"widgets": [{"type": "Button", "data": {"text": "bans_not_found"}}],
},
]
if not bans:
builder.append(
{
"type": "void",
"widgets": [
{"type": "MessageUnmatch", "data": {"text": "bans_not_found"}}
],
}
)
return builder
filters = get_bans_filter(bans)
bans_list = get_bans_list(bans)
bans_table = {
"type": "card",
"containerColumns": {"pc": 12, "tablet": 12, "mobile": 12},
"widgets": [
{
"type": "Title",
"data": {"title": "bans_title"},
},
{
"type": "Table",
"data": {
"title": "bans_table_title",
"minWidth": "xl",
"header": [
"bans_table_select",
"bans_table_ip",
"bans_table_reason",
"bans_table_ban_start",
"bans_table_ban_end",
"bans_table_remain",
"bans_table_term",
],
"positions": [1, 1, 1, 3, 3, 2, 1],
"items": bans_list,
"filters": filters,
},
},
],
}
builder.append(bans_table)
return builder
output = bans_builder(bans)
# output = bans_builder(no_bans)
# store on a file
with open("bans.json", "w") as f:
json.dump(output, f, indent=4)

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,39 @@
from .utils.form import get_forms, get_service_settings
def easy_mode_builder(templates: list[dict], plugins: list, global_config: dict, total_config: dict, service_name: str, is_new: bool = False) -> str:
"""Render forms with global config data.
ATM we don't need templates but we need to pass at least one to the function (it will simply not override anything).
"""
# We need
settings = get_service_settings(service_name, global_config, total_config)
builder = [
{
"type": "card",
"containerColumns": {"pc": 12, "tablet": 12, "mobile": 12},
"widgets": [
{
"type": "Title",
"data": {
"title": service_name,
"type": "container",
"lowercase": True,
},
},
{
"type": "Subtitle",
"data": {"subtitle": "services_manage_subtitle", "type": "container"},
},
{
"type": "Templates",
"data": {
"templates": get_forms(templates, plugins, settings, ("easy",), is_new, True),
"operation": "new" if is_new else "edit",
"oldServerName": service_name if service_name else "",
},
},
],
}
]
return builder

View file

@ -0,0 +1,31 @@
from .utils.form import get_forms
def global_config_builder(templates: list[dict], plugins: list, settings: dict) -> str:
"""Render forms with global config data.
ATM we don't need templates but we need to pass at least one to the function (it will simply not override anything).
"""
builder = [
{
"type": "card",
"containerColumns": {"pc": 12, "tablet": 12, "mobile": 12},
"widgets": [
{
"type": "Title",
"data": {"title": "global_config_title", "type": "container"},
},
{
"type": "Subtitle",
"data": {"subtitle": "global_config_subtitle", "type": "container"},
},
{
"type": "Templates",
"data": {
"templates": get_forms(templates, plugins, settings, ("advanced", "raw")),
},
},
],
}
]
return builder

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,107 @@
[
{
"type": "card",
"link": "https://panel.bunkerweb.io/?utm_campaign=self&utm_source=ui#pro",
"containerColumns": {
"pc": 4,
"tablet": 6,
"mobile": 12
},
"widgets": [
{
"type": "Stat",
"data": {
"title": "home_version",
"subtitle": "home_upgrade_to_pro",
"subtitleColor": "warning",
"stat": "home_free",
"iconName": "key"
}
}
]
},
{
"type": "card",
"link": "https://github.com/bunkerity/bunkerweb",
"containerColumns": {
"pc": 4,
"tablet": 6,
"mobile": 12
},
"widgets": [
{
"type": "Stat",
"data": {
"title": "home_version_number",
"subtitle": "home_update_available",
"subtitleColor": "warning",
"stat": "1.5.8",
"iconName": "wire"
}
}
]
},
{
"type": "card",
"link": "/instances",
"containerColumns": {
"pc": 4,
"tablet": 6,
"mobile": 12
},
"widgets": [
{
"type": "Stat",
"data": {
"title": "home_instances",
"subtitle": "home_total_number",
"subtitleColor": "info",
"stat": 1,
"iconName": "box"
}
}
]
},
{
"type": "card",
"link": "/services",
"containerColumns": {
"pc": 4,
"tablet": 6,
"mobile": 12
},
"widgets": [
{
"type": "Stat",
"data": {
"title": "home_services",
"subtitle": "home_all_methods_included",
"subtitleColor": "info",
"stat": 2,
"iconName": "disk"
}
}
]
},
{
"type": "card",
"link": "/plugins",
"containerColumns": {
"pc": 4,
"tablet": 6,
"mobile": 12
},
"widgets": [
{
"type": "Stat",
"data": {
"title": "home_plugins",
"subtitle": "home_no_error",
"subtitleColor": "success",
"stat": "42",
"iconName": "puzzle"
}
}
]
}
]

View file

@ -0,0 +1,84 @@
from .utils.widgets import stat_widget
def home_builder(data: dict) -> str:
"""
It returns the needed format from data to render the home page in JSON format for the Vue.js builder
"""
version_card = stat_widget(
link="https://panel.bunkerweb.io/?utm_campaign=self&utm_source=ui#pro",
containerColums={"pc": 4, "tablet": 6, "mobile": 12},
title="home_version",
subtitle=(
"home_all_features_available"
if data.get("is_pro_version")
else (
"home_awaiting_compliance"
if data.get("pro_status") == "active" and data.get("pro_overlapped")
else (
"home_renew_license"
if data.get("pro_status") == "expired"
else "home_talk_to_team" if data.get("pro_status") == "suspended" else "home_upgrade_to_pro"
)
)
),
subtitle_color="success" if data.get("is_pro_version") else "warning",
stat=(
"home_pro"
if data.get("is_pro_version")
else (
"home_pro_locked"
if data.get("pro_status") == "active" and data.get("pro_overlapped")
else "home_expired" if data.get("pro_status") == "expired" else "home_suspended" if data.get("pro_status") == "suspended" else "home_free"
)
),
icon_name="crown" if data.get("is_pro_version") else "key",
)
version_num_card = stat_widget(
link="https://github.com/bunkerity/bunkerweb",
containerColums={"pc": 4, "tablet": 6, "mobile": 12},
title="home_version_number",
subtitle=(
"home_couldnt_find_remote"
if not data.get("remote_version")
else "home_latest_version" if data.get("remote_version") and data.get("check_version") else "home_update_available"
),
subtitle_color=("error" if not data.get("remote_version") else "success" if data.get("remote_version") and data.get("check_version") else "warning"),
stat=data.get("version"),
icon_name="wire",
)
instances_card = stat_widget(
link="instances",
containerColums={"pc": 4, "tablet": 6, "mobile": 12},
title="home_instances",
subtitle="home_total_number",
subtitle_color="info",
stat=data.get("instances_number"),
icon_name="box",
)
services_card = stat_widget(
link="services",
containerColums={"pc": 4, "tablet": 6, "mobile": 12},
title="home_services",
subtitle="home_all_methods_included",
subtitle_color="info",
stat=data.get("services_number"),
icon_name="disk",
)
plugins_card = stat_widget(
link="plugins",
containerColums={"pc": 4, "tablet": 6, "mobile": 12},
title="home_plugins",
subtitle="home_errors_found" if data.get("plugins_errors") > 0 else "home_no_error",
subtitle_color="error" if data.get("plugins_errors") > 0 else "success",
stat=data.get("plugins_number"),
icon_name="puzzle",
)
builder = [version_card, version_num_card, instances_card, services_card, plugins_card]
return builder

View file

@ -0,0 +1,42 @@
from .utils.widgets import instance_widget
def instances_builder(instances: List[Instance]) -> str:
"""
It returns the needed format from data to render the instances page in JSON format for the Vue.js builder
"""
builder = []
for instance in instances:
# setup actions buttons
actions = ["reload", "stop"] if instance.status == "up" else ["start"]
buttons = [
{
"attrs": {
"data-submit-form": f"""{{"INSTANCE_ID" : "{instance.hostname}", "operation" : "{action}" }}""",
},
"text": f"action_{action}",
"color": "success" if action == "start" else "error" if action == "stop" else "warning",
}
for action in actions
]
instance = instance_widget(
containerColumns={"pc": 6, "tablet": 6, "mobile": 12},
pairs=[
{"key": "instances_name", "value": instance.name},
{"key": "instances_hostname", "value": instance.hostname},
{"key": "instances_type", "value": instance.type},
{"key": "instances_method", "value": instance.method},
{"key": "instances_creation_date", "value": instance.creation_date.strftime("%d-%m-%Y %H:%M:%S")},
{"key": "instances_last_seen", "value": instance.last_seen.strftime("%d-%m-%Y %H:%M:%S")},
],
status="success" if instance.status == "up" else "error",
title=instance.hostname,
buttons=buttons,
)
builder.append(instance)
return builder

View file

@ -0,0 +1,290 @@
from .utils.widgets import title_widget, table_widget
def jobs_builder(jobs):
jobs_list = get_jobs_list(jobs)
intervals = ["all"]
# loop on each job
for job in jobs_list:
# loop on each item
for item in job:
# get the interval if not already in intervals
if item.get("every") and item.get("every") not in intervals:
intervals.append(item.get("every"))
builder = [
{
"type": "card",
"containerColumns": {"pc": 12, "tablet": 12, "mobile": 12},
"widgets": [
title_widget("jobs_title"),
table_widget(
positions=[3, 2, 1, 1, 1, 1, 3],
header=[
"jobs_table_name",
"jobs_table_plugin_id",
"jobs_table_interval",
"jobs_table_reload",
"jobs_table_success",
"jobs_table_history",
"jobs_table_cache_downloadable",
],
items=jobs_list,
filters=[
{
"filter": "table",
"filterName": "keyword",
"type": "keyword",
"value": "",
"keys": ["name", "plugin_id"],
"field": {
"id": "jobs-keyword",
"value": "",
"type": "text",
"name": "jobs-keyword",
"label": "jobs_search",
"placeholder": "inp_keyword",
"isClipboard": False,
"popovers": [
{
"text": "jobs_search_desc",
"iconName": "info",
},
],
"columns": {"pc": 3, "tablet": 4, "mobile": 12},
},
},
{
"filter": "table",
"filterName": "every",
"type": "select",
"value": "all",
"keys": ["every"],
"field": {
"id": "jobs-every",
"value": "all",
"values": intervals,
"name": "jobs-every",
"onlyDown": True,
"label": "jobs_interval",
"popovers": [
{
"text": "jobs_interval_desc",
"iconName": "info",
},
],
"columns": {"pc": 3, "tablet": 4, "mobile": 12},
},
},
{
"filter": "table",
"filterName": "reload",
"type": "select",
"value": "all",
"keys": ["reload"],
"field": {
"id": "jobs-last-run",
"value": "all",
"values": ["all", "success", "failed"],
"name": "jobs-last-run",
"onlyDown": True,
"label": "jobs_reload",
"popovers": [
{
"text": "jobs_reload_desc",
"iconName": "info",
},
],
"columns": {"pc": 3, "tablet": 4, "mobile": 12},
},
},
{
"filter": "table",
"filterName": "success",
"type": "select",
"value": "all",
"keys": ["success"],
"field": {
"id": "jobs-success",
"value": "all",
"values": ["all", "success", "failed"],
"name": "jobs-success",
"onlyDown": True,
"label": "jobs_success",
"popovers": [
{
"text": "jobs_success_desc",
"iconName": "info",
},
],
"columns": {"pc": 3, "tablet": 4, "mobile": 12},
},
},
],
minWidth="lg",
title="jobs_table_title",
),
],
}
]
return builder
def get_jobs_list(jobs):
data = []
# loop on each dict
for key, value in jobs.items():
item = []
item.append({"name": key, "type": "Text", "data": {"text": key}})
# loop on each value
for k, v in value.items():
# override widget type for some keys
if k in ("reload", "history"):
is_success = v if k == "reload" else v[0].get("success")
item.append(
{
k: "success" if is_success else "failed",
"type": "Icons",
"data": {
"iconName": "check" if is_success else "cross",
},
}
)
if k not in ("history"):
continue
if k in ("plugin_id", "every"):
item.append({k: v, "type": "Text", "data": {"text": v}})
continue
if k in ("history"):
items = []
for hist in v:
items.append(
[
{
"type": "Text",
"data": {
"text": hist["start_date"],
},
},
{
"type": "Text",
"data": {
"text": hist["end_date"],
},
},
{
"type": "Icons",
"data": {
"iconName": "check" if hist["success"] else "cross",
},
},
]
)
item.append(
{
"type": "Button",
"data": {
"id": f"open-modal-history-{k}",
"text": "jobs_history",
"hideText": True,
"color": "blue",
"size": "normal",
"iconName": "document",
"iconColor": "white",
"modal": {
"widgets": [
{"type": "Title", "data": {"title": key}},
{"type": "Subtitle", "data": {"subtitle": "jobs_history_subtitle"}},
{
"type": "Table",
"data": {
"title": "jobs_history_table_title",
"minWidth": "",
"header": [
"jobs_table_start_run",
"jobs_table_end_run",
"jobs_table_success",
],
"positions": [5, 5, 2],
"items": items,
},
},
{
"type": "ButtonGroup",
"data": {
"buttons": [
{
"id": f"close-history-{k}",
"text": "action_close",
"color": "close",
"size": "normal",
"attrs": {"data-close-modal": ""},
}
]
},
},
]
},
},
}
)
if k in ("cache") and len(v) <= 0:
item.append({k: v, "type": "Text", "data": {"text": ""}})
continue
if k in ("cache") and len(v) > 0:
files = []
# loop on each cache item
for cache in v:
file_name = f"{cache['file_name']} [{cache['service_id']}]" if cache["service_id"] else f"{cache['file_name']}"
files.append(file_name)
item.append(
{
k: " ".join(files),
"type": "Fields",
"data": {
"setting": {
"attrs": {
"data-plugin-id": value.get("plugin_id", ""),
"data-job-name": key,
},
"id": f"{key}_cache",
"label": f"{key}_cache",
"hideLabel": True,
"inpType": "select",
"name": f"{key}_cache",
"value": "download file",
"values": files,
"columns": {
"pc": 12,
"tablet": 12,
"mobile": 12,
},
"overflowAttrEl": "data-table-body",
"containerClass": "table download-cache-file",
"maxBtnChars": 16,
"popovers": [
{
"iconName": "info",
"text": "jobs_download_cache_file",
},
],
}
},
}
)
continue
data.append(item)
return data

View file

@ -0,0 +1,83 @@
from .utils.widgets import title_widget
def logs_builder(files: list[str] = [], current_file: str = "", raw_data: str = "") -> str:
if not files:
builder = [
{
"type": "void",
"widgets": [{"type": "MessageUnmatch", "data": {"text": "logs_no_files_found"}}],
}
]
return builder
file_select = {
"type": "Fields",
"data": {
"setting": {
"id": "logs-select-file",
"label": "logs_log_file",
"inpType": "select",
"name": "logs-select-file",
"onlyDown": True,
"value": current_file or "Select a file",
"values": files,
"columns": {
"pc": 4,
"tablet": 6,
"mobile": 12,
},
"maxBtnChars": 20,
"attrs": {
"data-log": "true",
},
"popovers": [
{
"iconName": "info",
"text": "logs_select_file_info",
},
],
}
},
}
if not raw_data:
builder = [
{
"type": "card",
"containerColumns": {"pc": 12, "tablet": 12, "mobile": 12},
"widgets": [title_widget("logs_title"), file_select, {"type": "MessageUnmatch", "data": {"text": "logs_not_selected_or_not_found"}}],
}
]
return builder
editor = {
"type": "Fields",
"data": {
"setting": {
"containerClass": "mt-4",
"id": "logs-file-content",
"label": "logs_file_content",
"inpType": "editor",
"name": "logs-file-content",
"value": raw_data,
"columns": {
"pc": 12,
"tablet": 12,
"mobile": 12,
},
"editorClass" : "min-h-[500px]",
}
},
}
builder = [
{
"type": "card",
"containerColumns": {"pc": 12, "tablet": 12, "mobile": 12},
"widgets": [title_widget("logs_title"), file_select, editor],
}
]
return builder

View file

@ -0,0 +1,38 @@
from .utils.form import get_forms, get_service_settings
def advanced_mode_builder(templates: list[dict], plugins: list, global_config: dict, total_config: dict, service_name: str, is_new: bool = False) -> str:
"""Render forms with global config data.
ATM we don't need templates but we need to pass at least one to the function (it will simply not override anything).
"""
settings = get_service_settings(service_name, global_config, total_config)
builder = [
{
"type": "card",
"containerColumns": {"pc": 12, "tablet": 12, "mobile": 12},
"widgets": [
{
"type": "Title",
"data": {
"title": service_name,
"type": "container",
"lowercase": True,
},
},
{
"type": "Subtitle",
"data": {"subtitle": "services_manage_subtitle", "type": "container"},
},
{
"type": "Templates",
"data": {
"templates": get_forms(templates, plugins, settings, ("advanced",), is_new, True),
"operation": "new" if is_new else "edit",
"oldServerName": service_name if service_name else "",
},
},
],
}
]
return builder

View file

@ -0,0 +1,39 @@
from .utils.form import get_forms, get_service_settings
def easy_mode_builder(templates: list[dict], plugins: list, global_config: dict, total_config: dict, service_name: str, is_new: bool = False) -> str:
"""Render forms with global config data.
ATM we don't need templates but we need to pass at least one to the function (it will simply not override anything).
"""
# We need
settings = get_service_settings(service_name, global_config, total_config)
builder = [
{
"type": "card",
"containerColumns": {"pc": 12, "tablet": 12, "mobile": 12},
"widgets": [
{
"type": "Title",
"data": {
"title": service_name,
"type": "container",
"lowercase": True,
},
},
{
"type": "Subtitle",
"data": {"subtitle": "services_manage_subtitle", "type": "container"},
},
{
"type": "Templates",
"data": {
"templates": get_forms(templates, plugins, settings, ("easy",), is_new, True),
"operation": "new" if is_new else "edit",
"oldServerName": service_name if service_name else "",
},
},
],
}
]
return builder

View file

@ -0,0 +1,31 @@
from .utils.form import get_forms
def global_config_builder(templates: list[dict], plugins: list, settings: dict) -> str:
"""Render forms with global config data.
ATM we don't need templates but we need to pass at least one to the function (it will simply not override anything).
"""
builder = [
{
"type": "card",
"containerColumns": {"pc": 12, "tablet": 12, "mobile": 12},
"widgets": [
{
"type": "Title",
"data": {"title": "global_config_title", "type": "container"},
},
{
"type": "Subtitle",
"data": {"subtitle": "global_config_subtitle", "type": "container"},
},
{
"type": "Templates",
"data": {
"templates": get_forms(templates, plugins, settings, ("advanced", "raw")),
},
},
],
}
]
return builder

View file

@ -0,0 +1,84 @@
from .utils.widgets import stat_widget
def home_builder(data: dict) -> str:
"""
It returns the needed format from data to render the home page in JSON format for the Vue.js builder
"""
version_card = stat_widget(
link="https://panel.bunkerweb.io/?utm_campaign=self&utm_source=ui#pro",
containerColums={"pc": 4, "tablet": 6, "mobile": 12},
title="home_version",
subtitle=(
"home_all_features_available"
if data.get("is_pro_version")
else (
"home_awaiting_compliance"
if data.get("pro_status") == "active" and data.get("pro_overlapped")
else (
"home_renew_license"
if data.get("pro_status") == "expired"
else "home_talk_to_team" if data.get("pro_status") == "suspended" else "home_upgrade_to_pro"
)
)
),
subtitle_color="success" if data.get("is_pro_version") else "warning",
stat=(
"home_pro"
if data.get("is_pro_version")
else (
"home_pro_locked"
if data.get("pro_status") == "active" and data.get("pro_overlapped")
else "home_expired" if data.get("pro_status") == "expired" else "home_suspended" if data.get("pro_status") == "suspended" else "home_free"
)
),
icon_name="crown" if data.get("is_pro_version") else "key",
)
version_num_card = stat_widget(
link="https://github.com/bunkerity/bunkerweb",
containerColums={"pc": 4, "tablet": 6, "mobile": 12},
title="home_version_number",
subtitle=(
"home_couldnt_find_remote"
if not data.get("remote_version")
else "home_latest_version" if data.get("remote_version") and data.get("check_version") else "home_update_available"
),
subtitle_color=("error" if not data.get("remote_version") else "success" if data.get("remote_version") and data.get("check_version") else "warning"),
stat=data.get("version"),
icon_name="wire",
)
instances_card = stat_widget(
link="instances",
containerColums={"pc": 4, "tablet": 6, "mobile": 12},
title="home_instances",
subtitle="home_total_number",
subtitle_color="info",
stat=data.get("instances_number"),
icon_name="box",
)
services_card = stat_widget(
link="services",
containerColums={"pc": 4, "tablet": 6, "mobile": 12},
title="home_services",
subtitle="home_all_methods_included",
subtitle_color="info",
stat=data.get("services_number"),
icon_name="disk",
)
plugins_card = stat_widget(
link="plugins",
containerColums={"pc": 4, "tablet": 6, "mobile": 12},
title="home_plugins",
subtitle="home_errors_found" if data.get("plugins_errors") > 0 else "home_no_error",
subtitle_color="error" if data.get("plugins_errors") > 0 else "success",
stat=data.get("plugins_number"),
icon_name="puzzle",
)
builder = [version_card, version_num_card, instances_card, services_card, plugins_card]
return builder

View file

@ -0,0 +1,42 @@
from .utils.widgets import instance_widget
def instances_builder(instances: List[Instance]) -> str:
"""
It returns the needed format from data to render the instances page in JSON format for the Vue.js builder
"""
builder = []
for instance in instances:
# setup actions buttons
actions = ["reload", "stop"] if instance.status == "up" else ["start"]
buttons = [
{
"attrs": {
"data-submit-form": f"""{{"INSTANCE_ID" : "{instance.hostname}", "operation" : "{action}" }}""",
},
"text": f"action_{action}",
"color": "success" if action == "start" else "error" if action == "stop" else "warning",
}
for action in actions
]
instance = instance_widget(
containerColumns={"pc": 6, "tablet": 6, "mobile": 12},
pairs=[
{"key": "instances_name", "value": instance.name},
{"key": "instances_hostname", "value": instance.hostname},
{"key": "instances_type", "value": instance.type},
{"key": "instances_method", "value": instance.method},
{"key": "instances_creation_date", "value": instance.creation_date.strftime("%d-%m-%Y %H:%M:%S")},
{"key": "instances_last_seen", "value": instance.last_seen.strftime("%d-%m-%Y %H:%M:%S")},
],
status="success" if instance.status == "up" else "error",
title=instance.hostname,
buttons=buttons,
)
builder.append(instance)
return builder

View file

@ -0,0 +1,290 @@
from .utils.widgets import title_widget, table_widget
def jobs_builder(jobs):
jobs_list = get_jobs_list(jobs)
intervals = ["all"]
# loop on each job
for job in jobs_list:
# loop on each item
for item in job:
# get the interval if not already in intervals
if item.get("every") and item.get("every") not in intervals:
intervals.append(item.get("every"))
builder = [
{
"type": "card",
"containerColumns": {"pc": 12, "tablet": 12, "mobile": 12},
"widgets": [
title_widget("jobs_title"),
table_widget(
positions=[3, 2, 1, 1, 1, 1, 3],
header=[
"jobs_table_name",
"jobs_table_plugin_id",
"jobs_table_interval",
"jobs_table_reload",
"jobs_table_success",
"jobs_table_history",
"jobs_table_cache_downloadable",
],
items=jobs_list,
filters=[
{
"filter": "table",
"filterName": "keyword",
"type": "keyword",
"value": "",
"keys": ["name", "plugin_id"],
"field": {
"id": "jobs-keyword",
"value": "",
"type": "text",
"name": "jobs-keyword",
"label": "jobs_search",
"placeholder": "inp_keyword",
"isClipboard": False,
"popovers": [
{
"text": "jobs_search_desc",
"iconName": "info",
},
],
"columns": {"pc": 3, "tablet": 4, "mobile": 12},
},
},
{
"filter": "table",
"filterName": "every",
"type": "select",
"value": "all",
"keys": ["every"],
"field": {
"id": "jobs-every",
"value": "all",
"values": intervals,
"name": "jobs-every",
"onlyDown": True,
"label": "jobs_interval",
"popovers": [
{
"text": "jobs_interval_desc",
"iconName": "info",
},
],
"columns": {"pc": 3, "tablet": 4, "mobile": 12},
},
},
{
"filter": "table",
"filterName": "reload",
"type": "select",
"value": "all",
"keys": ["reload"],
"field": {
"id": "jobs-last-run",
"value": "all",
"values": ["all", "success", "failed"],
"name": "jobs-last-run",
"onlyDown": True,
"label": "jobs_reload",
"popovers": [
{
"text": "jobs_reload_desc",
"iconName": "info",
},
],
"columns": {"pc": 3, "tablet": 4, "mobile": 12},
},
},
{
"filter": "table",
"filterName": "success",
"type": "select",
"value": "all",
"keys": ["success"],
"field": {
"id": "jobs-success",
"value": "all",
"values": ["all", "success", "failed"],
"name": "jobs-success",
"onlyDown": True,
"label": "jobs_success",
"popovers": [
{
"text": "jobs_success_desc",
"iconName": "info",
},
],
"columns": {"pc": 3, "tablet": 4, "mobile": 12},
},
},
],
minWidth="lg",
title="jobs_table_title",
),
],
}
]
return builder
def get_jobs_list(jobs):
data = []
# loop on each dict
for key, value in jobs.items():
item = []
item.append({"name": key, "type": "Text", "data": {"text": key}})
# loop on each value
for k, v in value.items():
# override widget type for some keys
if k in ("reload", "history"):
is_success = v if k == "reload" else v[0].get("success")
item.append(
{
k: "success" if is_success else "failed",
"type": "Icons",
"data": {
"iconName": "check" if is_success else "cross",
},
}
)
if k not in ("history"):
continue
if k in ("plugin_id", "every"):
item.append({k: v, "type": "Text", "data": {"text": v}})
continue
if k in ("history"):
items = []
for hist in v:
items.append(
[
{
"type": "Text",
"data": {
"text": hist["start_date"],
},
},
{
"type": "Text",
"data": {
"text": hist["end_date"],
},
},
{
"type": "Icons",
"data": {
"iconName": "check" if hist["success"] else "cross",
},
},
]
)
item.append(
{
"type": "Button",
"data": {
"id": f"open-modal-history-{k}",
"text": "jobs_history",
"hideText": True,
"color": "blue",
"size": "normal",
"iconName": "document",
"iconColor": "white",
"modal": {
"widgets": [
{"type": "Title", "data": {"title": key}},
{"type": "Subtitle", "data": {"subtitle": "jobs_history_subtitle"}},
{
"type": "Table",
"data": {
"title": "jobs_history_table_title",
"minWidth": "",
"header": [
"jobs_table_start_run",
"jobs_table_end_run",
"jobs_table_success",
],
"positions": [5, 5, 2],
"items": items,
},
},
{
"type": "ButtonGroup",
"data": {
"buttons": [
{
"id": f"close-history-{k}",
"text": "action_close",
"color": "close",
"size": "normal",
"attrs": {"data-close-modal": ""},
}
]
},
},
]
},
},
}
)
if k in ("cache") and len(v) <= 0:
item.append({k: v, "type": "Text", "data": {"text": ""}})
continue
if k in ("cache") and len(v) > 0:
files = []
# loop on each cache item
for cache in v:
file_name = f"{cache['file_name']} [{cache['service_id']}]" if cache["service_id"] else f"{cache['file_name']}"
files.append(file_name)
item.append(
{
k: " ".join(files),
"type": "Fields",
"data": {
"setting": {
"attrs": {
"data-plugin-id": value.get("plugin_id", ""),
"data-job-name": key,
},
"id": f"{key}_cache",
"label": f"{key}_cache",
"hideLabel": True,
"inpType": "select",
"name": f"{key}_cache",
"value": "download file",
"values": files,
"columns": {
"pc": 12,
"tablet": 12,
"mobile": 12,
},
"overflowAttrEl": "data-table-body",
"containerClass": "table download-cache-file",
"maxBtnChars": 16,
"popovers": [
{
"iconName": "info",
"text": "jobs_download_cache_file",
},
],
}
},
}
)
continue
data.append(item)
return data

View file

@ -0,0 +1,83 @@
from .utils.widgets import title_widget
def logs_builder(files: list[str] = [], current_file: str = "", raw_data: str = "") -> str:
if not files:
builder = [
{
"type": "void",
"widgets": [{"type": "MessageUnmatch", "data": {"text": "logs_no_files_found"}}],
}
]
return builder
file_select = {
"type": "Fields",
"data": {
"setting": {
"id": "logs-select-file",
"label": "logs_log_file",
"inpType": "select",
"name": "logs-select-file",
"onlyDown": True,
"value": current_file or "Select a file",
"values": files,
"columns": {
"pc": 4,
"tablet": 6,
"mobile": 12,
},
"maxBtnChars": 20,
"attrs": {
"data-log": "true",
},
"popovers": [
{
"iconName": "info",
"text": "logs_select_file_info",
},
],
}
},
}
if not raw_data:
builder = [
{
"type": "card",
"containerColumns": {"pc": 12, "tablet": 12, "mobile": 12},
"widgets": [title_widget("logs_title"), file_select, {"type": "MessageUnmatch", "data": {"text": "logs_not_selected_or_not_found"}}],
}
]
return builder
editor = {
"type": "Fields",
"data": {
"setting": {
"containerClass": "mt-4",
"id": "logs-file-content",
"label": "logs_file_content",
"inpType": "editor",
"name": "logs-file-content",
"value": raw_data,
"columns": {
"pc": 12,
"tablet": 12,
"mobile": 12,
},
"editorClass" : "min-h-[500px]",
}
},
}
builder = [
{
"type": "card",
"containerColumns": {"pc": 12, "tablet": 12, "mobile": 12},
"widgets": [title_widget("logs_title"), file_select, editor],
}
]
return builder

View file

@ -0,0 +1,40 @@
from .utils.form import get_forms, get_service_settings
def raw_mode_builder(templates: list[dict], plugins: list, global_config: dict, total_config: dict, service_name: str, is_new: bool = False) -> str:
"""Render forms with global config data.
ATM we don't need templates but we need to pass at least one to the function (it will simply not override anything).
"""
# We need
settings = get_service_settings(service_name, global_config, total_config)
builder = [
{
"type": "card",
"containerColumns": {"pc": 12, "tablet": 12, "mobile": 12},
"widgets": [
{
"type": "Title",
"data": {
"title": service_name,
"type": "container",
"lowercase": True,
},
},
{
"type": "Subtitle",
"data": {"subtitle": "services_manage_subtitle", "type": "container"},
},
{
"type": "Templates",
"data": {
"templates": get_forms(templates, plugins, settings, ("raw",), is_new, True),
"operation": "new" if is_new else "edit",
"oldServerName": service_name if service_name else "",
},
},
],
}
]
return builder

View file

@ -0,0 +1,379 @@
from typing import Union
from .utils.widgets import title_widget, table_widget
def services_builder(services):
# get method for each service["SERVER_NAME"]["method"]
methods = list(set([service["SERVER_NAME"]["method"] for service in services]))
services_list = get_services_list(services)
builder = [
{
"type": "card",
"containerColumns": {"pc": 12, "tablet": 12, "mobile": 12},
"widgets": [
title_widget("services_title"),
{
"type": "Button",
"data": {
"id": "services-new",
"text": "services_new",
"color": "success",
"size": "normal",
"iconName": "plus",
"iconColor": "white",
"modal": services_action(server_name="new", operation="new", title="services_new_title", subtitle="services_new_subtitle"),
"containerClass": "col-span-12 flex justify-center",
},
},
table_widget(
positions=[4, 4, 4],
header=[
"services_table_name",
"services_table_method",
"services_table_actions",
],
items=services_list,
filters=[
{
"filter": "table",
"filterName": "keyword",
"type": "keyword",
"value": "",
"keys": ["name"],
"field": {
"id": "services-keyword",
"value": "",
"type": "text",
"name": "services-keyword",
"label": "services_search",
"placeholder": "inp_keyword",
"isClipboard": False,
"popovers": [
{
"text": "services_search_desc",
"iconName": "info",
},
],
"columns": {"pc": 3, "tablet": 4, "mobile": 12},
},
},
{
"filter": "table",
"filterName": "method",
"type": "select",
"value": "all",
"keys": ["method"],
"field": {
"id": "services-methods",
"value": "all",
"values": methods,
"name": "services-methods",
"onlyDown": True,
"label": "services_methods",
"popovers": [
{
"text": "services_methods_desc",
"iconName": "info",
},
],
"columns": {"pc": 3, "tablet": 4, "mobile": 12},
},
},
{
"filter": "table",
"filterName": "draft",
"type": "select",
"value": "all",
"keys": ["draft"],
"field": {
"id": "services-draft",
"value": "all",
"values": ["all", "online", "draft"],
"name": "services-draft",
"onlyDown": True,
"label": "services_draft",
"popovers": [
{
"text": "services_draft_desc",
"iconName": "info",
},
],
"columns": {"pc": 3, "tablet": 4, "mobile": 12},
},
},
],
minWidth="md",
title="services_table_title",
),
],
},
]
return builder
def services_settings(settings: dict) -> dict:
# deep copy settings dict
settings = settings.copy()
# remove "SERVER_NAME" and "IS_DRAFT" key
settings.pop("SERVER_NAME", None)
settings.pop("IS_DRAFT", None)
# Create table with settings remaining keys
settings_table_items = []
for key, value in settings.items():
format_key = key.replace("USE_", "").replace("_", " ")
settings_table_items.append(
[
{
"type": "Text",
"data": {"text": format_key},
},
{
"type": "Icons",
"data": {
"iconName": "check" if value.get("value") == "yes" else "cross",
},
},
]
)
table = table_widget(
positions=[8, 4],
header=["services_settings_table_name", "services_settings_table_status"],
items=settings_table_items,
filters=[],
minWidth="",
title="services_settings_table_title",
)
return table
def services_action(
server_name: str = "",
operation: str = "",
title: str = "",
subtitle: str = "",
additional: str = "",
is_draft: Union[bool, None] = None,
service: dict = None,
) -> dict:
buttons = [
{
"id": f"close-service-btn-{server_name}",
"text": "action_close",
"disabled": False,
"color": "close",
"size": "normal",
"attrs": {"data-close-modal": ""},
},
]
if operation == "delete":
buttons.append(
{
"id": f"{operation}-service-btn-{server_name}",
"text": f"action_{operation}",
"disabled": False,
"color": "delete",
"size": "normal",
"attrs": {
"data-submit-form": f"""{{"SERVER_NAME" : "{server_name}", "operation" : "{operation}" }}""",
},
},
)
if operation == "draft":
draft_value = "yes" if is_draft else "no"
buttons.append(
{
"id": f"{operation}-service-btn-{server_name}",
"text": "action_switch",
"disabled": False,
"color": "success",
"size": "normal",
"attrs": {
"data-submit-form": f"""{{"SERVER_NAME" : "{server_name}", "OLD_SERVER_NAME" : "{server_name}", "operation" : "edit", "IS_DRAFT" : "{draft_value}" }}""",
},
},
)
content = [
{
"type": "Title",
"data": {
"title": title,
},
},
]
if subtitle:
content.append(
{
"type": "Text",
"data": {
"text": subtitle,
},
},
)
if additional:
content.append(
{
"type": "Text",
"data": {
"bold": True,
"text": additional,
},
}
)
if operation == "plugins":
settings = services_settings(service)
content.append(settings)
if operation == "delete":
content.append(
{
"type": "Text",
"data": {
"text": "",
"bold": True,
"text": server_name,
},
}
)
if operation == "edit" or operation == "new":
modes = ("easy", "advanced", "raw")
mode_buttons = []
for mode in modes:
mode_buttons.append(
{
"id": f"{operation}-service-btn-{server_name}",
"text": f"services_mode_{mode}",
"disabled": False,
"color": "info",
"size": "normal",
"attrs": {
"role": "link",
"data-link": f"modes?service_name={server_name}&mode={mode}" if operation != "new" else f"modes?mode={mode}",
},
},
)
content.append(
{
"type": "ButtonGroup",
"data": {"buttons": mode_buttons},
}
)
content.append(
{
"type": "ButtonGroup",
"data": {"buttons": buttons},
},
)
modal = {
"widgets": content,
}
return modal
def get_services_list(services):
data = []
for index, service in enumerate(services):
server_name = service["SERVER_NAME"]["value"]
server_method = service["SERVER_NAME"]["method"]
is_draft = True if service["IS_DRAFT"]["value"] == "yes" else False
is_deletable = False if server_method in ("autoconf", "scheduler") else True
item = []
# Get name
item.append({"name": server_name, "type": "Text", "data": {"text": server_name}})
item.append({"method": server_method, "type": "Text", "data": {"text": server_method}})
item.append(
{
"type": "ButtonGroup",
"data": {
"buttons": [
{
"id": f"open-modal-plugins-{index}",
"text": "plugins",
"hideText": True,
"color": "success",
"size": "normal",
"iconName": "eye",
"iconColor": "white",
"modal": services_action(
server_name=server_name,
operation="plugins",
title="services_plugins_title",
subtitle="",
service=service,
),
},
{
"attrs": {"data-server-name": server_name},
"id": f"open-modal-manage-{index}",
"text": "manage",
"hideText": True,
"color": "edit",
"size": "normal",
"iconName": "pen",
"iconColor": "white",
"modal": services_action(
server_name=server_name,
operation="edit",
title="services_edit_title",
subtitle="services_edit_subtitle",
additional=server_name,
),
},
{
"attrs": {"data-server-name": server_name, "data-is-draft": "yes" if is_draft else "no"},
"id": f"open-modal-draft-{index}",
"text": "draft" if is_draft else "online",
"hideText": True,
"color": "blue",
"size": "normal",
"iconName": "document" if is_draft else "globe",
"iconColor": "white",
"modal": services_action(
server_name=server_name,
operation="draft",
title="services_draft_title",
subtitle="services_draft_subtitle" if is_draft else "services_online_subtitle",
additional="services_draft_switch_subtitle" if is_draft else "services_online_switch_subtitle",
is_draft=is_draft,
),
},
{
"attrs": {"data-server-name": server_name},
"id": f"open-modal-delete-{index}",
"text": "delete",
"disabled": not is_deletable,
"hideText": True,
"color": "red",
"size": "normal",
"iconName": "trash",
"iconColor": "white",
"modal": services_action(
server_name=server_name, operation="delete", title="services_delete_title", subtitle="services_delete_subtitle"
),
},
]
},
}
)
data.append(item)
return data

View file

@ -0,0 +1,40 @@
from .utils.form import get_forms, get_service_settings
def raw_mode_builder(templates: list[dict], plugins: list, global_config: dict, total_config: dict, service_name: str, is_new: bool = False) -> str:
"""Render forms with global config data.
ATM we don't need templates but we need to pass at least one to the function (it will simply not override anything).
"""
# We need
settings = get_service_settings(service_name, global_config, total_config)
builder = [
{
"type": "card",
"containerColumns": {"pc": 12, "tablet": 12, "mobile": 12},
"widgets": [
{
"type": "Title",
"data": {
"title": service_name,
"type": "container",
"lowercase": True,
},
},
{
"type": "Subtitle",
"data": {"subtitle": "services_manage_subtitle", "type": "container"},
},
{
"type": "Templates",
"data": {
"templates": get_forms(templates, plugins, settings, ("raw",), is_new, True),
"operation": "new" if is_new else "edit",
"oldServerName": service_name if service_name else "",
},
},
],
}
]
return builder

View file

@ -0,0 +1,379 @@
from typing import Union
from .utils.widgets import title_widget, table_widget
def services_builder(services):
# get method for each service["SERVER_NAME"]["method"]
methods = list(set([service["SERVER_NAME"]["method"] for service in services]))
services_list = get_services_list(services)
builder = [
{
"type": "card",
"containerColumns": {"pc": 12, "tablet": 12, "mobile": 12},
"widgets": [
title_widget("services_title"),
{
"type": "Button",
"data": {
"id": "services-new",
"text": "services_new",
"color": "success",
"size": "normal",
"iconName": "plus",
"iconColor": "white",
"modal": services_action(server_name="new", operation="new", title="services_new_title", subtitle="services_new_subtitle"),
"containerClass": "col-span-12 flex justify-center",
},
},
table_widget(
positions=[4, 4, 4],
header=[
"services_table_name",
"services_table_method",
"services_table_actions",
],
items=services_list,
filters=[
{
"filter": "table",
"filterName": "keyword",
"type": "keyword",
"value": "",
"keys": ["name"],
"field": {
"id": "services-keyword",
"value": "",
"type": "text",
"name": "services-keyword",
"label": "services_search",
"placeholder": "inp_keyword",
"isClipboard": False,
"popovers": [
{
"text": "services_search_desc",
"iconName": "info",
},
],
"columns": {"pc": 3, "tablet": 4, "mobile": 12},
},
},
{
"filter": "table",
"filterName": "method",
"type": "select",
"value": "all",
"keys": ["method"],
"field": {
"id": "services-methods",
"value": "all",
"values": methods,
"name": "services-methods",
"onlyDown": True,
"label": "services_methods",
"popovers": [
{
"text": "services_methods_desc",
"iconName": "info",
},
],
"columns": {"pc": 3, "tablet": 4, "mobile": 12},
},
},
{
"filter": "table",
"filterName": "draft",
"type": "select",
"value": "all",
"keys": ["draft"],
"field": {
"id": "services-draft",
"value": "all",
"values": ["all", "online", "draft"],
"name": "services-draft",
"onlyDown": True,
"label": "services_draft",
"popovers": [
{
"text": "services_draft_desc",
"iconName": "info",
},
],
"columns": {"pc": 3, "tablet": 4, "mobile": 12},
},
},
],
minWidth="md",
title="services_table_title",
),
],
},
]
return builder
def services_settings(settings: dict) -> dict:
# deep copy settings dict
settings = settings.copy()
# remove "SERVER_NAME" and "IS_DRAFT" key
settings.pop("SERVER_NAME", None)
settings.pop("IS_DRAFT", None)
# Create table with settings remaining keys
settings_table_items = []
for key, value in settings.items():
format_key = key.replace("USE_", "").replace("_", " ")
settings_table_items.append(
[
{
"type": "Text",
"data": {"text": format_key},
},
{
"type": "Icons",
"data": {
"iconName": "check" if value.get("value") == "yes" else "cross",
},
},
]
)
table = table_widget(
positions=[8, 4],
header=["services_settings_table_name", "services_settings_table_status"],
items=settings_table_items,
filters=[],
minWidth="",
title="services_settings_table_title",
)
return table
def services_action(
server_name: str = "",
operation: str = "",
title: str = "",
subtitle: str = "",
additional: str = "",
is_draft: Union[bool, None] = None,
service: dict = None,
) -> dict:
buttons = [
{
"id": f"close-service-btn-{server_name}",
"text": "action_close",
"disabled": False,
"color": "close",
"size": "normal",
"attrs": {"data-close-modal": ""},
},
]
if operation == "delete":
buttons.append(
{
"id": f"{operation}-service-btn-{server_name}",
"text": f"action_{operation}",
"disabled": False,
"color": "delete",
"size": "normal",
"attrs": {
"data-submit-form": f"""{{"SERVER_NAME" : "{server_name}", "operation" : "{operation}" }}""",
},
},
)
if operation == "draft":
draft_value = "yes" if is_draft else "no"
buttons.append(
{
"id": f"{operation}-service-btn-{server_name}",
"text": "action_switch",
"disabled": False,
"color": "success",
"size": "normal",
"attrs": {
"data-submit-form": f"""{{"SERVER_NAME" : "{server_name}", "OLD_SERVER_NAME" : "{server_name}", "operation" : "edit", "IS_DRAFT" : "{draft_value}" }}""",
},
},
)
content = [
{
"type": "Title",
"data": {
"title": title,
},
},
]
if subtitle:
content.append(
{
"type": "Text",
"data": {
"text": subtitle,
},
},
)
if additional:
content.append(
{
"type": "Text",
"data": {
"bold": True,
"text": additional,
},
}
)
if operation == "plugins":
settings = services_settings(service)
content.append(settings)
if operation == "delete":
content.append(
{
"type": "Text",
"data": {
"text": "",
"bold": True,
"text": server_name,
},
}
)
if operation == "edit" or operation == "new":
modes = ("easy", "advanced", "raw")
mode_buttons = []
for mode in modes:
mode_buttons.append(
{
"id": f"{operation}-service-btn-{server_name}",
"text": f"services_mode_{mode}",
"disabled": False,
"color": "info",
"size": "normal",
"attrs": {
"role": "link",
"data-link": f"modes?service_name={server_name}&mode={mode}" if operation != "new" else f"modes?mode={mode}",
},
},
)
content.append(
{
"type": "ButtonGroup",
"data": {"buttons": mode_buttons},
}
)
content.append(
{
"type": "ButtonGroup",
"data": {"buttons": buttons},
},
)
modal = {
"widgets": content,
}
return modal
def get_services_list(services):
data = []
for index, service in enumerate(services):
server_name = service["SERVER_NAME"]["value"]
server_method = service["SERVER_NAME"]["method"]
is_draft = True if service["IS_DRAFT"]["value"] == "yes" else False
is_deletable = False if server_method in ("autoconf", "scheduler") else True
item = []
# Get name
item.append({"name": server_name, "type": "Text", "data": {"text": server_name}})
item.append({"method": server_method, "type": "Text", "data": {"text": server_method}})
item.append(
{
"type": "ButtonGroup",
"data": {
"buttons": [
{
"id": f"open-modal-plugins-{index}",
"text": "plugins",
"hideText": True,
"color": "success",
"size": "normal",
"iconName": "eye",
"iconColor": "white",
"modal": services_action(
server_name=server_name,
operation="plugins",
title="services_plugins_title",
subtitle="",
service=service,
),
},
{
"attrs": {"data-server-name": server_name},
"id": f"open-modal-manage-{index}",
"text": "manage",
"hideText": True,
"color": "edit",
"size": "normal",
"iconName": "pen",
"iconColor": "white",
"modal": services_action(
server_name=server_name,
operation="edit",
title="services_edit_title",
subtitle="services_edit_subtitle",
additional=server_name,
),
},
{
"attrs": {"data-server-name": server_name, "data-is-draft": "yes" if is_draft else "no"},
"id": f"open-modal-draft-{index}",
"text": "draft" if is_draft else "online",
"hideText": True,
"color": "blue",
"size": "normal",
"iconName": "document" if is_draft else "globe",
"iconColor": "white",
"modal": services_action(
server_name=server_name,
operation="draft",
title="services_draft_title",
subtitle="services_draft_subtitle" if is_draft else "services_online_subtitle",
additional="services_draft_switch_subtitle" if is_draft else "services_online_switch_subtitle",
is_draft=is_draft,
),
},
{
"attrs": {"data-server-name": server_name},
"id": f"open-modal-delete-{index}",
"text": "delete",
"disabled": not is_deletable,
"hideText": True,
"color": "red",
"size": "normal",
"iconName": "trash",
"iconColor": "white",
"modal": services_action(
server_name=server_name, operation="delete", title="services_delete_title", subtitle="services_delete_subtitle"
),
},
]
},
}
)
data.append(item)
return data

View file

@ -0,0 +1,494 @@
import copy
from typing import Union
def get_setting_data(template_settings: dict, settings: dict, setting: str, value: dict, is_multiple_setting: bool = False, is_new: bool = False) -> tuple:
template_value = template_settings.get(setting, None)
current_value = settings[setting].get("value", None) if setting in settings else None
default_value = value.get("default")
is_disabled_method = (
True if settings.get(setting, {}).get("method", "ui") not in ("ui", "default", "manual") and not is_new and not is_multiple_setting else False
)
is_current_from_template = True if settings.get(setting, {}).get("template", None) is not None and template_value is not None else False
is_current_default = current_value is not None and current_value == default_value
setting_value = current_value if current_value is not None and not is_new and not is_multiple_setting else default_value
return template_value, current_value, default_value, is_disabled_method, is_current_from_template, is_current_default, setting_value
def get_service_settings(service_name: str, global_config: dict, total_config: dict) -> dict:
"""
total_config is a dict that contains global settings and services settings (format SERVICE_NAME_SETTING - www.example.com_USE_ANTIBOT for example -).
We will only keep settings that are related to the service_name (with prefix SERVICE_NAME_).
Then we will loop on global key and override value from global config by service config if exists.
"""
# Get service settings
service_settings = {}
for key, value in total_config.items():
if not key.startswith(f"{service_name}_"):
continue
service_settings[key.replace(f"{service_name}_", "")] = value
# Loop on global settings to override by service settings
for key, value in service_settings.items():
global_config[key] = value
return global_config
def get_plugins_multisite(plugins: list) -> list:
# loop on plugins with list index
plugins_multisite = []
for index, plugin in enumerate(plugins):
multisite_settings = {}
# loop on settings
for setting, value in plugin.get("settings").items():
# check if setting is multisite
if value.get("context") != "multisite":
continue
# add multisite key to plugin
multisite_settings[setting] = value
# add multisite settings to plugin
if len(multisite_settings):
plugin_multisite = copy.deepcopy(plugin)
plugin_multisite["settings"] = multisite_settings
plugins_multisite.append(plugin_multisite)
return plugins_multisite
def get_forms(
templates_ui: list = [],
plugins: list = [],
settings: dict = {},
render_forms: tuple = ("advanced", "easy", "raw"),
is_new: bool = False,
only_multisite: bool = False,
) -> dict:
"""
Will generate every needed form using templates, plugins and settings.
We will run on each plugins, set template value if one, and override by the custom settings value if exists.
We will format to fit each form type (easy, advanced, raw) in case
"""
# Copy of the plugins, and get the plugins by context if needed
# In services page, we want only multisite settings, but in global config we want both
plugins_base = get_plugins_multisite(plugins) if only_multisite else plugins
# This template will be used to show default value or value if exists
templates = [
{
"name": "default",
"steps": [],
"configs": {},
"settings": {},
}
]
for key, value in templates_ui.items():
value["label"] = value["name"]
value["name"] = key
templates.append(value)
# Update SERVER_NAME to be empty if new
if is_new and "SERVER_NAME" in settings:
settings["SERVER_NAME"]["value"] = ""
if is_new and not "SERVER_NAME" in settings:
settings["SERVER_NAME"] = {"value": "", "method": "ui", "global": False}
forms = {}
for form in render_forms:
forms[form] = {}
for template in templates:
if "advanced" in forms:
forms["advanced"][template.get("name")] = set_advanced(template, plugins_base, settings, is_new)
if "raw" in forms:
forms["raw"][template.get("name")] = set_raw(template, plugins_base, settings, is_new)
if "easy" in forms:
forms["easy"][template.get("name")] = set_easy(template, plugins_base, settings, is_new)
return forms
def set_easy(template: list, plugins_base: list, settings: dict, is_new: bool) -> dict:
"""
Prepare the easy form based on the template and plugins data.
We need to loop on each steps and prepare settings and configs for each step.
"""
template_settings = template.get("settings")
plugins = copy.deepcopy(plugins_base)
# Copy of the plugins base data
plugins = copy.deepcopy(plugins_base)
# Update settings with global config data
for plugin in plugins:
loop_id = 0
total_settings = len(plugin.get("settings"))
for setting, value in plugin.get("settings").items():
loop_id += 1
value = format_setting(setting, value, total_settings, loop_id, template_settings, settings, is_new)
set_multiples(template, plugins, settings)
steps = template.get("steps")
for step in steps:
step_settings = step.get("settings", {})
for plugin in plugins:
step_settings_output = {}
for setting, value in plugin.get("settings").items():
if setting not in step_settings:
continue
step_settings_output[setting] = value
# Case at least one key in step settings, we can add the plugin settings to the step
if len(step_settings_output) and not "plugins" in step:
step["plugins"] = []
if len(step_settings_output):
step_plugin = copy.deepcopy(plugin)
step_plugin["settings"] = step_settings_output
step["plugins"].append(step_plugin)
# remove settings key form step
step.pop("settings", None)
return steps
def set_raw(template: list, plugins_base: list, settings: dict, is_new: bool = False) -> dict:
"""
Set the raw form based on the template and plugins data.
It consists of keeping only the value or default value for each plugin settings.
"""
template_settings = template.get("settings")
raw_settings = {}
# Copy of the plugins base
plugins = copy.deepcopy(plugins_base)
# Update settings with global config data
for plugin in plugins:
for setting, value in plugin.get("settings").items():
is_multiple_setting = "multiple" in value
# By default, we will loop on one setting (not multiple)
total_settings = {setting: value}
# Case multiple, retrieve all settings that start with setting name
if is_multiple_setting:
# get all settings that start with setting name
total_settings = {k: v for k, v in settings.items() if k.startswith(f"{setting}")}
# Loop in a same way it is a multiple or regular setting
for mult_setting, mult_value in total_settings.items():
# Get setting data
# We need to send setting and not mult_setting because mult_setting is unknown on plugin side
template_value, current_value, default_value, is_disabled_method, is_current_from_template, is_current_default, setting_value = (
get_setting_data(template_settings, settings, mult_setting, mult_value)
)
if current_value is not None:
raw_settings[mult_setting] = current_value
continue
if template_value is not None:
raw_settings[mult_setting] = template_value
continue
return raw_settings
def set_advanced(template: list, plugins_base: list, settings: dict, is_new: bool) -> dict:
"""
Set the advanced form based on the template and plugins data.
It consists of formatting each plugin settings to be used in the advanced form.
"""
template_settings = template.get("settings")
# Copy of the plugins base data
plugins = copy.deepcopy(plugins_base)
# Update settings with global config data
for plugin in plugins:
loop_id = 0
total_settings = len(plugin.get("settings"))
for setting, value in plugin.get("settings").items():
loop_id += 1
value = format_setting(setting, value, total_settings, loop_id, template_settings, settings, is_new)
set_multiples(template, plugins, settings)
return plugins
def get_multiple_from_template(template, multiples):
"""
We are gonna loop on each plugins multiples group, in case a setting is matching a template setting,
we will create a group using the prefix as key (or "0" if no prefix) with default settings at first.
Then we will override by the template value in case there is one.
This will return something of this type :
{'0' : {'setting' : value, 'setting2': value2}, '1' : {'setting_1': value, 'setting2_1': value}} }
"""
# Loop on each plugin and loop on multiples key
# Check if the name us matching a template key
multiple_plugin = copy.deepcopy(multiples)
multiple_template = {}
for setting, value in template.get("settings").items():
# Sanitize setting name to remove prefix of type _1 if exists
# Slipt by _ and check if last element is a digit
format_setting = setting
setting_split = setting.split("_")
prefix = "0"
if setting_split[-1].isdigit():
prefix = setting_split[-1]
format_setting = "_".join(setting_split[:-1])
# loop on settings of a multiple group
for mult_name, mult_settings in multiple_plugin.items():
# Check if at least one setting is matching a multiple setting
if not format_setting in mult_settings:
continue
# Case we have at least one multiple setting, we can check if multiple name exists or create it
if not mult_name in multiple_template:
multiple_template[mult_name] = {}
# Case it is, we will check if already a group with the right prefix exists
# If not, we will create it
if not prefix in multiple_template[mult_name]:
# We want each settings to have the prefix if exists
# We will get the value of the setting without the prefix and create a prefix key with the same value
# And after that we can delete the original setting
new_multiple_group = {}
for multSett, multValue in mult_settings.items():
new_multiple_group[f"{multSett}{f'_{prefix}' if prefix != '0' else ''}"] = multValue
new_multiple_group = copy.deepcopy(new_multiple_group)
# Update id for each settings
for multSett, multValue in new_multiple_group.items():
multValue["id"] = f"{multValue['id']}{f'-{prefix}' if prefix != '0' else ''}"
multiple_template[mult_name][prefix] = new_multiple_group
# We can now add the template value to setting using the same setting name with prefix
multiple_template[mult_name][prefix][setting]["value"] = value
multiple_template[mult_name][prefix][setting]["prev_value"] = value
multiple_template[mult_name][prefix][setting]["method"] = "default"
# Sort key incrementally
for mult_name, mult_settings in multiple_template.items():
multiple_template[mult_name] = dict(sorted(mult_settings.items(), key=lambda item: int(item[0])))
return multiple_template
def get_multiple_from_settings(settings, multiples):
"""
We are gonna loop on each plugins multiples group, in case a setting is matching a service / global config setting,
we will create a group using the prefix as key (or "0" if no prefix) with default settings at first.
Then we will override by the service / global config value in case there is one.
This will return something of this type :
{'0' : {'setting' : value, 'setting2': value2}, '1' : {'setting_1': value, 'setting2_1': value}} }
"""
# Loop on each plugin and loop on multiples key
# Check if the name us matching a template key
multiple_plugins = copy.deepcopy(multiples)
multiple_settings = {}
for setting, value in settings.items():
# Sanitize setting name to remove prefix of type _1 if exists
# Slipt by _ and check if last element is a digit
format_setting = setting
setting_split = setting.split("_")
prefix = "0"
if setting_split[-1].isdigit():
prefix = setting_split[-1]
format_setting = "_".join(setting_split[:-1])
# loop on settings of a multiple group
for mult_name, mult_settings in multiple_plugins.items():
# Check if at least one setting is matching a multiple setting
if not format_setting in mult_settings:
continue
# Case we have at least one multiple setting, we can check if multiple name exists or create it
if not mult_name in multiple_settings:
multiple_settings[mult_name] = {}
# Now check if prefix exist for this mult
if not prefix in multiple_settings[mult_name]:
# We want each settings to have the prefix if exists
# We will get the value of the setting without the prefix and create a prefix key with the same value
# And after that we can delete the original setting
new_multiple_group = {}
for multSett, multValue in mult_settings.items():
new_multiple_group[f"{multSett}{f'_{prefix}' if prefix != '0' else ''}"] = multValue
new_multiple_group = copy.deepcopy(new_multiple_group)
# Update id for each settings
for multSett, multValue in new_multiple_group.items():
multValue["id"] = f"{multValue['id']}{f'-{prefix}' if prefix != '0' else ''}"
multiple_settings[mult_name][prefix] = new_multiple_group
# Update multiple template with real data
multiple_settings[mult_name][prefix][setting]["value"] = value.get("value", multiple_settings[mult_name][prefix][setting]["value"])
multiple_settings[mult_name][prefix][setting]["prev_value"] = value.get("value", multiple_settings[mult_name][prefix][setting]["value"])
multiple_settings[mult_name][prefix][setting]["method"] = value.get("method", "ui")
multiple_settings[mult_name][prefix][setting]["disabled"] = False if value.get("method", "ui") in ("ui", "default", "manual") else True
# Add popovers if setting is disabled else stop
if not multiple_settings[mult_name][prefix][setting].get("disabled", False):
continue
multiple_settings[mult_name][prefix][setting]["popovers"] = [
{
"iconName": "trespass",
"text": "inp_popover_method_disabled",
}
] + multiple_settings[
mult_name
][prefix][setting].get("popovers", [])
return multiple_settings
def set_multiples(template, format_plugins, settings):
"""
Set the multiples settings for each plugin.
"""
# copy of format plugins
for plugin in format_plugins:
# Get multiples
multiples = {}
settings_to_delete = []
total_settings = len(plugin.get("settings"))
zindex = 0
for setting, value in plugin.get("settings").items():
if not value.get("multiple"):
continue
zindex += 1
value["containerClass"] = f"z-{total_settings - zindex}"
mult_name = value.get("multiple")
# Get the multiple value and set it as key if not in multiples dict
if mult_name not in multiples:
multiples[mult_name] = {}
multiples[mult_name][setting] = value
settings_to_delete.append(setting)
# Delete multiple settings from regular settings
for setting in settings_to_delete:
del plugin["settings"][setting]
if len(multiples):
# Add multiple schema with default values to plugin
plugin["multiples_schema"] = multiples
# Now that we have for each plugin the multiples settings, we need to do the following
# Get all settings from template that are multiples
template_multiples = get_multiple_from_template(template, multiples)
# Get all settings from service settings / global config that are multiples
service_multiples = get_multiple_from_settings(settings, multiples)
# Get service multiples if at least one, else use template multiples
plugin["multiples"] = service_multiples if len(service_multiples) else template_multiples
return format_plugins
def format_setting(
name: str,
value: Union[str, int],
total_settings: Union[str, int],
loop_id: Union[str, int],
template_settings: dict,
settings: dict,
is_new: bool = False,
) -> dict:
"""
Format a setting in order to be used with form builder.
This will only set value for none multiple settings.
Additionnel set_multiples function will handle multiple settings.
"""
is_multiple_setting = value.get("multiple", False)
template_value, current_value, default_value, is_disabled_method, is_current_from_template, is_current_default, setting_value = get_setting_data(
template_settings, settings, name, value, is_multiple_setting, is_new
) # regex by pattern
value["pattern"] = value.get("regex", "")
# set inpType based on type define for each settings
inpType = (
"checkbox"
if value.get("type") == "check"
else ("select" if value.get("type") == "select" else "datepicker" if value.get("type") == "date" else "input")
)
value["inpType"] = inpType
if inpType == "select":
# replace "select" key by "values"
value["values"] = value.pop("select")
value["columns"] = {"pc": 4, "tablet": 6, "mobile": 12}
value["disabled"] = is_disabled_method
value["value"] = default_value
value["name"] = value.get("label")
value["prev_value"] = value.get("value")
# Prepare popover checking "help", "context"
popovers = []
if is_disabled_method:
popovers.append(
{
"iconName": "trespass",
"text": "inp_popover_method_disabled",
}
)
if value.get("context"):
popovers.append(
{
"iconName": ("disk" if value.get("context") == "multisite" else "globe"),
"text": ("inp_popover_multisite" if value.get("context") == "multisite" else "inp_popover_global"),
}
)
if value.get("help"):
popovers.append(
{
"iconName": "info",
"text": value.get("help"),
}
)
value["popovers"] = popovers
# Case multiple, stop here
if "multiple" in value:
return value
# Else, we can add additional final data
value["method"] = settings.get(name, {}).get("method", "ui")
value["containerClass"] = f"z-{total_settings - loop_id}"
if current_value is not None and not is_current_default:
value["value"] = current_value
elif template_value is not None:
value["value"] = template_value
else:
value["value"] = setting_value
return value

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

View file

@ -12,7 +12,7 @@ from typing import Union
inputFolder = abspath("../client/dashboard/components")
outputFolderMd = abspath("../client/.widgets-md")
outputFolderPy = abspath("../client/.widgets")
outputFolderWidgets = abspath("../client/widgets")
outputFolderWidgets = abspath("../client/builder/utils")
components_path_to_exclude = ("\components\Icons\\", "components\Forms\Error\\", "\components\Dashboard\\", "\components\Builder\\")
@ -51,8 +51,7 @@ def reset():
rmtree(outputFolderMd, ignore_errors=True)
# Remove all files from the output folder
rmtree(outputFolderPy, ignore_errors=True)
# remove outputfilename
rmtree(outputFolderWidgets, ignore_errors=True)
def vue2js():
@ -431,6 +430,10 @@ def add_key_value(data, key, value, default):
content += "\n"
# Utils function to add key value to data dict if not default value
# Remove previous file if exists
if Path(f"{outputFolderWidgets}/widgets.py").exists():
Path(f"{outputFolderWidgets}/widgets.py").unlink()
Path(f"{outputFolderWidgets}/widgets.py").write_text(content)
# Remove py folder