instances page + update components, builder, ...

* widgets_generator.py now update jsdoc array or dict with empty value in params to Optional python param
*  add utils to get fields component right format from a specific field
* add missing display prop for layout
* created a regular form component with advacned settings
* set mawWidth screen for regular form and layout component for better style
* fix displayStore toggle value making components crashing if toggle too quickly
* add i18n instances
* add absolute url for data-submit-endpoint and regular endpoint param
* enhance table style
* update and enhance instance format : handle no instances case, fix button group rendering on tabulator, better handling of filters to display base on values,  add list and form card title and subtitle, don't send delete option if instance is not right method
* update vite and builder to render new instances page
This commit is contained in:
Jordan Blasenhauer 2024-08-13 15:24:25 +02:00
parent b9e0e55ea5
commit 27920db4dd
46 changed files with 871 additions and 737 deletions

View file

@ -1,33 +0,0 @@
import json
import base64
from builder.instances import instances_builder
# Create instance class using keys from the instances list
class Instance:
def __init__(self, _type, health, _id, hostname, name):
self._type = _type
self.health = health
self._id = _id
self.hostname = hostname
self.name = name
instances = [
Instance("manual", True, "bunkerweb", "bunkerweb", "bunkerweb"),
Instance("manual", True, "bunkerweb", "bunkerweb", "bunkerweb"),
]
builder = instances_builder(instances)
# store on a file
with open("instances.json", "w") as f:
json.dump(builder, f)
output_base64_bytes = base64.b64encode(bytes(json.dumps(builder), "utf-8"))
output_base64_string = output_base64_bytes.decode("ascii")
with open("instances.txt", "w") as f:
f.write(output_base64_string)

View file

@ -1,5 +1,7 @@
from .utils.widgets import button_widget, button_group_widget, title_widget, text_widget, tabulator_widget, datepicker_widget
from .utils.table import add_column, format_field
from .utils.table import add_column
from .utils.format import get_fields_from_field
from typing import Optional
bans_columns = [
add_column(title="IP", field="ip", formatter="text"),
@ -10,7 +12,7 @@ bans_columns = [
]
def bans_filters(reasons: list = [], remains: list = []) -> list:
def bans_filters(reasons: Optional[list] = None, remains: Optional[list] = None) -> list:
filters = [
{
@ -28,7 +30,7 @@ def bans_filters(reasons: list = [], remains: list = []) -> list:
]
# Case "all" ans
if len(reasons) >= 2:
if reasons is not None and len(reasons) >= 2:
filters.append(
{
"type": "=",
@ -46,7 +48,7 @@ def bans_filters(reasons: list = [], remains: list = []) -> list:
},
)
if len(reasons) >= 2:
if remains is not None and len(remains) >= 2:
filters.append(
{
"type": "=",
@ -72,7 +74,7 @@ def ban_item(id: str, ip: str, reason: str, ban_start_date: int, ban_end_date: i
{
"ip": text_widget(text=ip)["data"],
"reason": text_widget(text=reason)["data"],
"ban_start_date": format_field(
"ban_start_date": get_fields_from_field(
datepicker_widget(
id=f"datepicker-ban-start-{id}",
name=f"datepicker-ban-start-{id}",
@ -83,7 +85,7 @@ def ban_item(id: str, ip: str, reason: str, ban_start_date: int, ban_end_date: i
columns={"pc": 12, "tablet": 12, " mobile": 12},
)
),
"ban_end_date": format_field(
"ban_end_date": get_fields_from_field(
datepicker_widget(
id=f"datepicker-ban-end-{id}",
name=f"datepicker-ban-end-{id}",
@ -124,7 +126,7 @@ bans_add_columns = [
default_add_ban = [
{
"id": 1,
"ip": format_field(
"ip": get_fields_from_field(
datepicker_widget(
id="datepicker-add-ban-ip-1",
name="datepicker-add-ban-ip-1",
@ -134,7 +136,7 @@ default_add_ban = [
columns={"pc": 12, "tablet": 12, " mobile": 12},
)
),
"ban_end": format_field(
"ban_end": get_fields_from_field(
datepicker_widget(
id="datepicker-add-ban-end-1",
name="datepicker-add-ban-end-1",

View file

@ -11,7 +11,7 @@ from .utils.widgets import (
tabulator_widget,
icons_widget,
)
from typing import Optional
from .utils.table import add_column
@ -32,8 +32,8 @@ def config_form(
is_global: str, # "yes" or "no"
filename: str = "",
config_type: str = "",
types: list = [],
services: list = [],
types: Optional[list] = None,
services: Optional[list] = None,
config_value: str = "",
is_new: bool = False,
display_index: int = 1,
@ -64,7 +64,7 @@ def config_form(
name="select-type",
label="configs_types", # keep it (a18n)
value="" if is_new else config_type,
values=types, # set all available types like ["http", "modsec"]
values=types or [], # set all available types like ["http", "modsec"]
columns={"pc": 3, "tablet": 4, " mobile": 12},
onlyDown=True,
),
@ -86,7 +86,7 @@ def config_form(
name="combo-services",
label="configs_types", # keep it (a18n)
value="",
values=services, # set services list ATM, we will update by a checklist with [{value : "service1", is_check : bool}, ...]
values=services or [], # set services list ATM, we will update by a checklist with [{value : "service1", is_check : bool}, ...]
onlyDown=True,
columns={"pc": 3, "tablet": 4, " mobile": 12},
),

View file

@ -1,45 +1,366 @@
from .utils.widgets import instance_widget
from .utils.widgets import (
button_widget,
button_group_widget,
title_widget,
subtitle_widget,
text_widget,
tabulator_widget,
input_widget,
icons_widget,
regular_widget,
unmatch_widget,
)
from .utils.table import add_column
from .utils.format import get_fields_from_field
from typing import Optional
from typing import List
# from src.instance import Instance
columns = [
add_column(title="Name", field="name", formatter="text"),
add_column(title="Hostname", field="hostname", formatter="text"),
add_column(title="Type", field="type", formatter="text"),
add_column(title="Method", field="method", formatter="text"),
add_column(title="Creation date", field="creation_date", formatter="text"),
add_column(title="Last seen", field="last_seen", formatter="text"),
add_column(title="health", field="health", formatter="icons"),
add_column(title="Actions", field="actions", formatter="buttongroup"),
]
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 = []
def instances_filter(healths: str, types: Optional[list] = None, methods: Optional[list] = None) -> list: # healths = "up", "down", "loading"
filters = [
{
"type": "like",
"fields": ["name", "hostname"],
"setting": {
"id": "input-search-host-name",
"name": "input-search-host-name",
"label": "instances_search", # keep it (a18n)
"value": "",
"inpType": "input",
"columns": {"pc": 3, "tablet": 4, "mobile": 12},
"popovers": [
{
"iconName": "info",
"text": "instances_search_popover",
}
],
},
}
]
for instance in instances:
# setup actions buttons
actions = ["reload", "stop"] if instance.status == "up" else ["start"]
buttons = [
if types is not None and len(types) >= 2:
filters.append(
{
"attrs": {
"data-submit-form": f"""{{"INSTANCE_ID" : "{instance.hostname}", "operation" : "{action}" }}""",
"type": "=",
"fields": ["type"],
"setting": {
"id": "select-type",
"name": "select-type",
"label": "instances_type", # keep it (a18n)
"value": "all", # keep "all"
"values": ["all"] + types,
"inpType": "select",
"onlyDown": True,
"columns": {"pc": 3, "tablet": 4, "mobile": 12},
"popovers": [
{
"iconName": "info",
"text": "instances_type_popover",
}
],
},
"text": f"action_{action}",
"color": "success" if action == "start" else "error" if action == "stop" else "warning",
}
for action in actions
]
instance = instance_widget(
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)
if methods is not None and len(methods) >= 2:
filters.append(
{
"type": "=",
"fields": ["method"],
"setting": {
"id": "select-method",
"name": "select-method",
"label": "instances_method", # keep it (a18n)
"value": "all", # keep "all"
"values": ["all"] + methods,
"inpType": "select",
"onlyDown": True,
"columns": {"pc": 3, "tablet": 4, "mobile": 12},
"popovers": [
{
"iconName": "info",
"text": "instances_method_popover",
}
],
},
},
)
return builder
if healths is not None and len(healths) >= 2:
filters.append(
{
"type": "=",
"fields": ["health"],
"setting": {
"id": "select-health",
"name": "select-health",
"label": "instances_health", # keep it (a18n)
"value": "all", # keep "all"
"values": ["all"] + healths,
"inpType": "select",
"onlyDown": True,
"columns": {"pc": 3, "tablet": 4, "mobile": 12},
"popovers": [
{
"iconName": "info",
"text": "instances_health_popover",
}
],
},
},
)
return filters
def instance_item(
instance_name: str,
hostname: str,
instance_type: str,
method: str,
health: str,
creation_date: str,
last_seen: str,
):
# Always ping action, but delete only if ui, manual or default
actions = [
button_widget(
id=f"ping-instance-{instance_name}",
text="action_ping", # keep it (a18n)
color="info",
size="normal",
hideText=True,
iconName="globe",
iconColor="white",
modal={
"widgets": [
title_widget(title="instances_ping_title"), # keep it (a18n)
text_widget(text="instances_ping_subtitle"), # keep it (a18n)
text_widget(bold=True, text=instance_name),
button_group_widget(
buttons=[
button_widget(
id=f"close-ping-btn-{instance_name}",
text="action_close", # keep it (a18n)
color="close",
size="normal",
attrs={"data-close-modal": ""}, # a11y
),
button_widget(
id=f"ping-btn-{instance_name}",
text="action_ping", # keep it (a18n)
color="info",
size="normal",
attrs={
"data-submit-form": f"""{{"instance_name" : "{instance_name}", "instance_hostname" : "{hostname}" }}""",
"data-submit-endpoint": "/ping",
},
),
]
),
],
},
)
]
if method.strip() in ("ui", "manual", "default"):
actions.append(
button_widget(
id=f"delete-instance-{instance_name}",
text="action_delete", # keep it (a18n)
color="error",
size="normal",
hideText=True,
iconName="trash",
iconColor="white",
modal={
"widgets": [
title_widget(title="instances_delete_title"), # keep it (a18n)
text_widget(text="instances_delete_subtitle"), # keep it (a18n)
text_widget(bold=True, text=instance_name),
button_group_widget(
buttons=[
button_widget(
id=f"close-delete-btn-{instance_name}",
text="action_close", # keep it (a18n)
color="close",
size="normal",
attrs={"data-close-modal": ""}, # a11y
),
button_widget(
id=f"delete-btn-{instance_name}",
text="action_delete", # keep it (a18n)
color="delete",
size="normal",
attrs={
"data-submit-form": f"""{{ "instance_name" : "{instance_name}", "instance_hostname" : "{hostname}" }}""",
"data-submit-endpoint": "/delete",
},
),
]
),
],
},
),
)
return {
"name": text_widget(text=instance_name)["data"],
"hostname": text_widget(text=hostname)["data"],
"type": text_widget(text=instance_type)["data"],
"method": text_widget(text=method)["data"],
"creation_date": text_widget(text=creation_date)["data"],
"last_seen": text_widget(text=last_seen)["data"],
"health": icons_widget(
iconName="check" if health == "up" else "cross" if health == "down" else "search",
value=health,
)["data"],
"actions": {"buttons": actions},
}
def instances_new_form() -> dict:
return {
"type": "card",
"maxWidthScreen": "md",
"display": ["main", 2],
"widgets": [
title_widget(
title="instances_create_title", # keep it (a18n)
),
subtitle_widget(
subtitle="instances_create_subtitle", # keep it (a18n)
),
regular_widget(
maxWidthScreen="xs",
endpoint="/add",
fields=[
get_fields_from_field(
input_widget(
id="instance-name",
name="instance-name",
label="instances_name", # keep it (a18n)
value="",
pattern="", # add your pattern if needed
columns={"pc": 12, "tablet": 12, "mobile": 12},
)
),
get_fields_from_field(
input_widget(
id="instance-hostname",
name="instance-hostname",
label="instances_hostname", # keep it (a18n)
value="",
pattern="", # add your pattern if needed
columns={"pc": 12, "tablet": 12, "mobile": 12},
)
),
],
buttons=[
button_widget(
id="create-instance-submit",
text="action_save",
color="success",
size="normal",
type="submit",
containerClass="flex justify-center",
)
],
),
],
}
def instances_tabs():
return {
"type": "tabs",
"widgets": [
button_group_widget(
buttons=[
button_widget(
text="instances_tab_list",
display=["main", 1],
size="tab",
color="info",
iconColor="white",
iconName="list",
),
button_widget(
text="instances_tab_add",
color="success",
display=["main", 2],
size="tab",
iconColor="white",
iconName="plus",
),
]
)
],
}
def instances_list(instances: Optional[list] = None, types: Optional[list] = None, methods: Optional[list] = None, healths: Optional[list] = None) -> dict:
if instances is None or len(instances) == 0:
return {
"type": "card",
"gridLayoutClass": "transparent",
"widgets": [
unmatch_widget(text="instances_not_found"),
],
}
items = []
for instance in instances:
items.append(
instance_item(
instance_name=instance.get("name", ""),
hostname=instance.get("hostname", ""),
instance_type=instance.get("type", ""),
method=instance.get("method", ""),
health=instance.get("health", ""),
creation_date=instance.get("creation_date", ""),
last_seen=instance.get("last_seen", ""),
)
)
return {
"type": "card",
"display": ["main", 1],
"widgets": [
title_widget(
title="instances_list_title", # keep it (a18n)
),
subtitle_widget(
subtitle="instances_list_subtitle", # keep it (a18n)
),
tabulator_widget(
id="table-instances",
columns=columns,
items=items,
filters=instances_filter(types=types, methods=methods, healths=healths),
),
],
}
def instances_builder(instances: Optional[list] = None, types: Optional[list] = None, methods: Optional[list] = None, healths: Optional[list] = None) -> list:
items = []
return [
# Tabs is button group with display value and a size tab inside a tabs container
instances_tabs(),
instances_list(instances=instances, types=types, methods=methods, healths=healths),
instances_new_form(),
]

View file

@ -1,275 +0,0 @@
from .utils.widgets import button_widget, button_group_widget, title_widget, text_widget, tabulator_widget, input_widget, icons_widget
from .utils.table import add_column
columns = [
add_column(title="Name", field="name", formatter="text"),
add_column(title="Hostname", field="hostname", formatter="text"),
add_column(title="Type", field="type", formatter="text"),
add_column(title="Method", field="method", formatter="text"),
add_column(title="Creation date", field="creation_date", formatter="text"),
add_column(title="Last seen", field="last_seen", formatter="text"),
add_column(title="health", field="health", formatter="icons"),
add_column(title="Actions", field="actions", formatter="buttonGroup"),
]
def instances_filter(healths: str, types: list = [], methods: list = []) -> list: # healths = "up", "down", "loading"
filters = [
{
"type": "like",
"fields": ["name", "hostname"],
"setting": {
"id": "input-search-host-name",
"name": "input-search-host-name",
"label": "instances_search_host_name", # keep it (a18n)
"value": "",
"inpType": "input",
"columns": {"pc": 3, "tablet": 4, " mobile": 12},
},
}
]
if len(types) >= 2:
filters.append(
{
"type": "=",
"fields": ["type"],
"setting": {
"id": "select-type",
"name": "select-type",
"label": "instances_select_type", # keep it (a18n)
"value": "all", # keep "all"
"values": ["all"] + types,
"inpType": "select",
"onlyDown": True,
"columns": {"pc": 3, "tablet": 4, " mobile": 12},
},
}
)
if len(methods) >= 2:
filters.append(
{
"type": "=",
"fields": ["method"],
"setting": {
"id": "select-method",
"name": "select-method",
"label": "instances_select_method", # keep it (a18n)
"value": "all", # keep "all"
"values": ["all"] + methods,
"inpType": "select",
"onlyDown": True,
"columns": {"pc": 3, "tablet": 4, " mobile": 12},
},
},
)
if len(healths) >= 2:
filters.append(
{
"type": "=",
"fields": ["health"],
"setting": {
"id": "select-health",
"name": "select-health",
"label": "instances_select_health", # keep it (a18n)
"value": "all", # keep "all"
"values": ["all"] + healths,
"inpType": "select",
"onlyDown": True,
"columns": {"pc": 3, "tablet": 4, " mobile": 12},
},
},
)
return filters
def instance_item(
instance_name: str,
hostname: str,
instance_type: str,
method: str,
health: str,
creation_date: str,
last_seen: str,
):
{
"name": text_widget(text=instance_name)["data"],
"hostname": text_widget(text=hostname)["data"],
"type": text_widget(text=instance_type)["data"],
"method": text_widget(text=method)["data"],
"creation_date": text_widget(text=creation_date)["data"],
"last_seen": text_widget(text=last_seen)["data"],
"health": icons_widget(
iconName="check" if health == "up" else "cross" if health == "down" else "search",
value=health,
),
"actions": {
"buttons": [
button_widget(
id=f"ping-instance-{instance_name}",
text="action_ping", # keep it (a18n)
color="success",
size="normal",
hideText=True,
iconName="globe",
iconColor="white",
modal={
"widgets": [
title_widget(title="instances_ping_title"), # keep it (a18n)
text_widget(text="instances_ping_subtitle"), # keep it (a18n)
text_widget(bold=True, text=instance_name),
button_group_widget(
buttons=[
button_widget(
id=f"close-ping-btn-{instance_name}",
text="action_close", # keep it (a18n)
color="close",
size="normal",
attrs={"data-close-modal": ""}, # a11y
)["data"],
button_widget(
id=f"ping-btn-{instance_name}",
text="action_ping", # keep it (a18n)
color="info",
size="normal",
attrs={
"data-submit-form": f"""{{"instance_name" : "{instance_name}", "instance_hostname" : "{hostname}" }}""",
"data-submit-endpoint": "/ping",
},
)["data"],
]
),
],
},
),
button_widget(
id=f"delete-instance-{instance_name}",
text="action_delete", # keep it (a18n)
color="success",
size="normal",
hideText=True,
iconName="globe",
iconColor="white",
modal={
"widgets": [
title_widget(title="instances_delete_title"), # keep it (a18n)
text_widget(text="instances_delete_subtitle"), # keep it (a18n)
text_widget(bold=True, text=instance_name),
button_group_widget(
buttons=[
button_widget(
id=f"close-delete-btn-{instance_name}",
text="action_close", # keep it (a18n)
color="close",
size="normal",
attrs={"data-close-modal": ""}, # a11y
)["data"],
button_widget(
id=f"delete-btn-{instance_name}",
text="action_delete", # keep it (a18n)
color="delete",
size="normal",
attrs={
"data-submit-form": f"""{{ "instance_name" : "{instance_name}", "instance_hostname" : "{hostname}" }}""",
"data-submit-endpoint": "/delete",
},
)["data"],
]
),
],
},
),
]
},
},
def instance_new_form() -> list:
return [
input_widget(
id="instance-name",
name="instance-name",
label="instances_name", # keep it (a18n)
value="",
pattern="", # add your pattern if needed
columns={"pc": 3, "tablet": 4, " mobile": 12},
),
input_widget(
id="instance-hostname",
name="instance-hostname",
label="instances_hostname", # keep it (a18n)
value="",
pattern="", # add your pattern if needed
columns={"pc": 3, "tablet": 4, " mobile": 12},
),
button_widget(
id="create-instance",
text="action_create", # keep it (a18n)
color="success",
size="normal",
),
]
def instances_tabs():
return [
button_widget(
text="instances_tab_list",
display=["main", 1],
size="tab",
iconColor="white",
iconName="list",
),
button_widget(
text="instances_tab_add",
display=["main", 2],
size="tab",
iconColor="white",
iconName="plus",
),
]
def instances_builder(instances: list, types: list = [], methods: list = [], healths: list = []) -> list:
items = []
for instance in instances:
items.append(
instance_item(
instance_name=instance.get("name"),
hostname=instance.get("hostname"),
instance_type=instance.get("type"),
method=instance.get("method"),
health=instance.get("health"),
creation_date=instance.get("creation_date"),
last_seen=instance.get("last_seen"),
)
)
return [
# Tabs is button group with display value and a size tab inside a tabs container
{
"type": "tabs",
"widgets": [button_group_widget(buttons=instances_tabs())],
},
{
"type": "card",
"display": ["main", 1],
"widgets": [
tabulator_widget(
id="table-instances",
columns=columns,
items=items,
filters=instances_filter(types=types, methods=methods, healths=healths),
)
],
},
{
"type": "card",
"display": ["main", 2],
"widgets": instance_new_form(),
},
]

View file

@ -1,5 +1,7 @@
from .utils.table import add_column, format_field
from .utils.table import add_column
from .utils.format import get_fields_from_field
from .utils.widgets import datepicker_widget, text_widget, tabulator_widget
from typing import Optional
reports_columns = [
add_column(title="Date", field="date", formatter="fields"),
@ -15,7 +17,7 @@ reports_columns = [
]
def reports_filters(reasons: list = [], countries: list = [], methods: list = [], codes: list = []) -> list:
def reports_filters(reasons: Optional[list] = None, countries: Optional[list] = None, methods: Optional[list] = None, codes: Optional[list] = None) -> list:
reports_filters = [
{
"type": "like",
@ -55,7 +57,7 @@ def reports_filters(reasons: list = [], countries: list = [], methods: list = []
},
]
if len(reasons) >= 2:
if reasons is not None and len(reasons) >= 2:
reports_filters.append(
{
"type": "=",
@ -73,7 +75,7 @@ def reports_filters(reasons: list = [], countries: list = [], methods: list = []
}
)
if len(countries) >= 2:
if countries is not None and len(countries) >= 2:
reports_filters.append(
{
"type": "=",
@ -91,7 +93,7 @@ def reports_filters(reasons: list = [], countries: list = [], methods: list = []
}
)
if len(methods) >= 2:
if methods is not None and len(methods) >= 2:
reports_filters.append(
{
"type": "=",
@ -109,7 +111,7 @@ def reports_filters(reasons: list = [], countries: list = [], methods: list = []
}
)
if len(codes) >= 2:
if codes is not None and len(codes) >= 2:
reports_filters.append(
{
"type": "=",
@ -134,7 +136,7 @@ def reports_filters(reasons: list = [], countries: list = [], methods: list = []
def report_item(id: int, date: int, ip: str, country: str, method: str, url: str, code: str, user_agent: str, reason: str, data: str) -> dict:
return (
{
"date": format_field(
"date": get_fields_from_field(
datepicker_widget(
id=f"datepicker-date-{id}",
name=f"datepicker-date-{id}",
@ -156,7 +158,9 @@ def report_item(id: int, date: int, ip: str, country: str, method: str, url: str
)
def reports_builder(reports: list, reasons: list = [], countries: list = [], methods: list = [], codes: list = []) -> str:
def reports_builder(
reports: list, reasons: Optional[list] = None, countries: Optional[list] = None, methods: Optional[list] = None, codes: Optional[list] = None
) -> str:
reports_items = [report_item(**report, id=index) for index, report in enumerate(reports)]
return [
{

View file

@ -1,5 +1,5 @@
import copy
from typing import Union
from typing import Union, Optional
def get_setting_data(template_settings: dict, settings: dict, setting: str, value: dict, is_multiple_setting: bool = False, is_new: bool = False) -> tuple:
@ -60,9 +60,9 @@ def get_plugins_multisite(plugins: list) -> list:
def get_forms(
templates_ui: list = [],
plugins: list = [],
settings: dict = {},
templates_ui: Optional[list] = None,
plugins: Optional[list] = None,
settings: Optional[dict] = None,
render_forms: tuple = ("advanced", "easy", "raw"),
is_new: bool = False,
only_multisite: bool = False,

View file

@ -0,0 +1,3 @@
def get_fields_from_field(field):
# get field["data"] and add inpType
return {"setting": {**field["data"], "inpType": field["type"].lower()}}

View file

@ -4,7 +4,3 @@ def add_column(title, field, formatter=""):
return {"title": title, "field": field, "formatter": formatter}
return {"title": title, "field": field}
def format_field(field):
return {"setting": field["data"]}

View file

@ -1,5 +1,5 @@
from typing import Union
from typing import Union, Optional
# Add params to data dict only if value is not the default one
def add_key_value(data, key, value, default):
@ -9,10 +9,10 @@ def add_key_value(data, key, value, default):
def advanced_widget(
template: dict,
containerClass: str,
columns: dict,
containerClass: str = "",
operation: str = "edit",
oldServerName: str = ""
oldServerName: str = "",
columns: dict = {"pc":"12","tablet":"12","mobile":"12"}
):
"""
This component is used to create a complete advanced form with plugin selection.
@ -20,10 +20,10 @@ def advanced_widget(
PARAMETERS
- `template` **Object** Template object with plugin and settings data.
- `containerClass` **string** Container
- `containerClass` **string** Container additional class (optional, default `""`)
- `operation` **string** Operation type (edit, new, delete). (optional, default `"edit"`)
- `oldServerName` **string** Old server name. This is a server name before any changes. (optional, default `""`)
- `columns` **Object** Columns object.
- `columns` **Object** Columns object. (optional, default `{"pc":"12","tablet":"12","mobile":"12"}`)
EXAMPLE
@ -58,13 +58,11 @@ def advanced_widget(
data = {
"template" : template,
"containerClass" : containerClass,
"columns" : columns,
}
# List of params that will be add only if not default value
list_params = [("operation", operation, "edit"),("oldServerName", oldServerName, "")]
list_params = [("containerClass", containerClass, ""),("operation", operation, "edit"),("oldServerName", oldServerName, ""),("columns", columns, {"pc":"12","tablet":"12","mobile":"12"})]
for param in list_params:
add_key_value(data, param[0], param[1], param[2])
@ -74,7 +72,7 @@ def advanced_widget(
def button_widget(
text: str,
id: str = "",
display: list = [],
display: Optional[list] = None,
type: str = "button",
disabled: bool = False,
hideText: bool = False,
@ -82,7 +80,7 @@ def button_widget(
iconColor: str = "",
size: str = "normal",
iconName: str = "",
attrs: dict = {},
attrs: Optional[dict] = None,
modal: Union[dict, bool] = False,
tabId: Union[str, int] = "",
containerClass: str = ""
@ -128,7 +126,7 @@ def button_widget(
# List of params that will be add only if not default value
list_params = [("id", id, ""),("display", display, []),("type", type, "button"),("disabled", disabled, False),("hideText", hideText, False),("color", color, "primary"),("iconColor", iconColor, ""),("size", size, "normal"),("iconName", iconName, ""),("attrs", attrs, {}),("modal", modal, False),("tabId", tabId, ""),("containerClass", containerClass, "")]
list_params = [("id", id, ""),("display", display, None),("type", type, "button"),("disabled", disabled, False),("hideText", hideText, False),("color", color, "primary"),("iconColor", iconColor, ""),("size", size, "normal"),("iconName", iconName, ""),("attrs", attrs, None),("modal", modal, False),("tabId", tabId, ""),("containerClass", containerClass, "")]
for param in list_params:
add_key_value(data, param[0], param[1], param[2])
@ -237,8 +235,8 @@ def checkbox_widget(
name: str,
value: str,
id: str = "",
attrs: dict = {},
popovers: list = [],
attrs: Optional[dict] = None,
popovers: Optional[list] = None,
inpType: str = "checkbox",
disabled: bool = False,
required: bool = False,
@ -302,7 +300,7 @@ def checkbox_widget(
# List of params that will be add only if not default value
list_params = [("id", id, ""),("attrs", attrs, {}),("popovers", popovers, []),("inpType", inpType, "checkbox"),("disabled", disabled, False),("required", required, False),("columns", columns, {"pc":"12","tablet":"12","mobile":"12"}),("hideLabel", hideLabel, False),("containerClass", containerClass, ""),("headerClass", headerClass, ""),("inpClass", inpClass, ""),("tabId", tabId, "")]
list_params = [("id", id, ""),("attrs", attrs, None),("popovers", popovers, None),("inpType", inpType, "checkbox"),("disabled", disabled, False),("required", required, False),("columns", columns, {"pc":"12","tablet":"12","mobile":"12"}),("hideLabel", hideLabel, False),("containerClass", containerClass, ""),("headerClass", headerClass, ""),("inpClass", inpClass, ""),("tabId", tabId, "")]
for param in list_params:
add_key_value(data, param[0], param[1], param[2])
@ -358,13 +356,13 @@ def combobox_widget(
value: str,
values: list,
id: str = "",
attrs: dict = {},
attrs: Optional[dict] = None,
maxBtnChars: str = "",
popovers: list = [],
popovers: Optional[list] = None,
inpType: str = "select",
disabled: bool = False,
required: bool = False,
requiredValues: list = [],
requiredValues: Optional[list] = None,
columns: dict = {"pc":"12","tablet":"12","mobile":"12"},
hideLabel: bool = False,
onlyDown: bool = False,
@ -433,7 +431,7 @@ def combobox_widget(
# List of params that will be add only if not default value
list_params = [("id", id, ""),("attrs", attrs, {}),("maxBtnChars", maxBtnChars, ""),("popovers", popovers, []),("inpType", inpType, "select"),("disabled", disabled, False),("required", required, False),("requiredValues", requiredValues, []),("columns", columns, {"pc":"12","tablet":"12","mobile":"12"}),("hideLabel", hideLabel, False),("onlyDown", onlyDown, False),("overflowAttrEl", overflowAttrEl, ""),("containerClass", containerClass, ""),("inpClass", inpClass, ""),("headerClass", headerClass, ""),("tabId", tabId, "")]
list_params = [("id", id, ""),("attrs", attrs, None),("maxBtnChars", maxBtnChars, ""),("popovers", popovers, None),("inpType", inpType, "select"),("disabled", disabled, False),("required", required, False),("requiredValues", requiredValues, None),("columns", columns, {"pc":"12","tablet":"12","mobile":"12"}),("hideLabel", hideLabel, False),("onlyDown", onlyDown, False),("overflowAttrEl", overflowAttrEl, ""),("containerClass", containerClass, ""),("inpClass", inpClass, ""),("headerClass", headerClass, ""),("tabId", tabId, "")]
for param in list_params:
add_key_value(data, param[0], param[1], param[2])
@ -442,9 +440,9 @@ def combobox_widget(
def container_widget(
containerClass: str = "",
columns: Union[dict, bool] = False,
columns: Union[dict, bool] = {"pc":"12","tablet":"12","mobile":"12"},
tag: str = "div",
display: list = []
display: Optional[list] = None
):
"""
This component is a basic container that can be used to wrap other components.
@ -455,7 +453,7 @@ def container_widget(
PARAMETERS
- `containerClass` **String** Additional class (optional, default `""`)
- `columns` **(Object | boolean)** Work with grid system { pc: 12, tablet: 12, mobile: 12} (optional, default `false`)
- `columns` **(Object | boolean)** Work with grid system { pc: 12, tablet: 12, mobile: 12} (optional, default `{"pc":"12","tablet":"12","mobile":"12"}`)
- `tag` **String** The tag for the container (optional, default `"div"`)
- `display` **Array** Array need two values : "groupName" in index 0 and "compId" in index 1 in order to be displayed using the display store. More info on the display store itslef. (optional, default `[]`)
@ -473,7 +471,7 @@ def container_widget(
# List of params that will be add only if not default value
list_params = [("containerClass", containerClass, ""),("columns", columns, False),("tag", tag, "div"),("display", display, [])]
list_params = [("containerClass", containerClass, ""),("columns", columns, {"pc":"12","tablet":"12","mobile":"12"}),("tag", tag, "div"),("display", display, None)]
for param in list_params:
add_key_value(data, param[0], param[1], param[2])
@ -484,8 +482,8 @@ def datepicker_widget(
label: str,
name: str,
id: str = "",
popovers: list = [],
attrs: dict = {},
popovers: Optional[list] = None,
attrs: Optional[dict] = None,
inpType: str = "datepicker",
value: int = "",
minDate: int = "",
@ -554,7 +552,7 @@ def datepicker_widget(
# List of params that will be add only if not default value
list_params = [("id", id, ""),("popovers", popovers, []),("attrs", attrs, {}),("inpType", inpType, "datepicker"),("value", value, ""),("minDate", minDate, ""),("maxDate", maxDate, ""),("isClipboard", isClipboard, True),("hideLabel", hideLabel, False),("columns", columns, {"pc":"12","tablet":"12","mobile":"12"}),("disabled", disabled, False),("required", required, False),("headerClass", headerClass, ""),("containerClass", containerClass, ""),("tabId", tabId, "")]
list_params = [("id", id, ""),("popovers", popovers, None),("attrs", attrs, None),("inpType", inpType, "datepicker"),("value", value, ""),("minDate", minDate, ""),("maxDate", maxDate, ""),("isClipboard", isClipboard, True),("hideLabel", hideLabel, False),("columns", columns, {"pc":"12","tablet":"12","mobile":"12"}),("disabled", disabled, False),("required", required, False),("headerClass", headerClass, ""),("containerClass", containerClass, ""),("tabId", tabId, "")]
for param in list_params:
add_key_value(data, param[0], param[1], param[2])
@ -564,7 +562,7 @@ def datepicker_widget(
def details_widget(
columns,
details: str,
filters: list = []
filters: Optional[list] = None
):
"""
This component is a list of items separate on two columns : one for the title, and other for a list of popovers related to the plugin (type, link...)
@ -605,7 +603,7 @@ def details_widget(
# List of params that will be add only if not default value
list_params = [("columns", columns, {"pc":"4","tablet":"6","mobile":"12"}),("filters", filters, [])]
list_params = [("columns", columns, {"pc":"4","tablet":"6","mobile":"12"}),("filters", filters, None)]
for param in list_params:
add_key_value(data, param[0], param[1], param[2])
@ -614,10 +612,10 @@ def details_widget(
def easy_widget(
template: dict,
containerClass: str,
columns: dict,
containerClass: str = "",
operation: str = "edit",
oldServerName: str = ""
oldServerName: str = "",
columns: dict = {"pc":"12","tablet":"12","mobile":"12"}
):
"""
This component is used to create a complete easy form with plugin selection.
@ -625,10 +623,10 @@ def easy_widget(
PARAMETERS
- `template` **Object** Template object with plugin and settings data.
- `containerClass` **string** Container
- `containerClass` **string** Container additional class (optional, default `""`)
- `operation` **string** Operation type (edit, new, delete). (optional, default `"edit"`)
- `oldServerName` **string** Old server name. This is a server name before any changes. (optional, default `""`)
- `columns` **Object** Columns object.
- `columns` **Object** Columns object. (optional, default `{"pc":"12","tablet":"12","mobile":"12"}`)
EXAMPLE
@ -663,13 +661,11 @@ def easy_widget(
data = {
"template" : template,
"containerClass" : containerClass,
"columns" : columns,
}
# List of params that will be add only if not default value
list_params = [("operation", operation, "edit"),("oldServerName", oldServerName, "")]
list_params = [("containerClass", containerClass, ""),("operation", operation, "edit"),("oldServerName", oldServerName, ""),("columns", columns, {"pc":"12","tablet":"12","mobile":"12"})]
for param in list_params:
add_key_value(data, param[0], param[1], param[2])
@ -681,8 +677,8 @@ def editor_widget(
name: str,
value: str,
id: str = "",
attrs: dict = {},
popovers: list = [],
attrs: Optional[dict] = None,
popovers: Optional[list] = None,
inpType: str = "editor",
columns: dict = {"pc":"12","tablet":"12","mobile":"12"},
pattern: str = "",
@ -744,7 +740,7 @@ def editor_widget(
# List of params that will be add only if not default value
list_params = [("id", id, ""),("attrs", attrs, {}),("popovers", popovers, []),("inpType", inpType, "editor"),("columns", columns, {"pc":"12","tablet":"12","mobile":"12"}),("pattern", pattern, ""),("disabled", disabled, False),("required", required, False),("isClipboard", isClipboard, True),("hideLabel", hideLabel, False),("containerClass", containerClass, ""),("editorClass", editorClass, ""),("headerClass", headerClass, ""),("tabId", tabId, "")]
list_params = [("id", id, ""),("attrs", attrs, None),("popovers", popovers, None),("inpType", inpType, "editor"),("columns", columns, {"pc":"12","tablet":"12","mobile":"12"}),("pattern", pattern, ""),("disabled", disabled, False),("required", required, False),("isClipboard", isClipboard, True),("hideLabel", hideLabel, False),("containerClass", containerClass, ""),("editorClass", editorClass, ""),("headerClass", headerClass, ""),("tabId", tabId, "")]
for param in list_params:
add_key_value(data, param[0], param[1], param[2])
@ -755,7 +751,7 @@ def field_widget(
label: str,
id: str,
name: str,
popovers: list = [],
popovers: Optional[list] = None,
required: bool = False,
hideLabel: bool = False,
headerClass: str = ""
@ -800,7 +796,7 @@ def field_widget(
# List of params that will be add only if not default value
list_params = [("popovers", popovers, []),("required", required, False),("hideLabel", hideLabel, False),("headerClass", headerClass, "")]
list_params = [("popovers", popovers, None),("required", required, False),("hideLabel", hideLabel, False),("headerClass", headerClass, "")]
for param in list_params:
add_key_value(data, param[0], param[1], param[2])
@ -848,7 +844,7 @@ def fields_widget(
def filter_widget(
filters: list = [],
filters: Optional[list] = None,
data: Union[dict, list] = {},
containerClass: str = ""
):
@ -904,7 +900,7 @@ def filter_widget(
# List of params that will be add only if not default value
list_params = [("filters", filters, []),("data", data, {}),("containerClass", containerClass, "")]
list_params = [("filters", filters, None),("data", data, {}),("containerClass", containerClass, "")]
for param in list_params:
add_key_value(data, param[0], param[1], param[2])
@ -913,7 +909,7 @@ def filter_widget(
def grid_widget(
gridClass: str = "items-start",
display: list = []
display: Optional[list] = None
):
"""
This component is a basic container that can be used to wrap other components.
@ -940,7 +936,7 @@ def grid_widget(
# List of params that will be add only if not default value
list_params = [("gridClass", gridClass, "items-start"),("display", display, [])]
list_params = [("gridClass", gridClass, "items-start"),("display", display, None)]
for param in list_params:
add_key_value(data, param[0], param[1], param[2])
@ -954,8 +950,9 @@ def grid_layout_widget(
link: str = "",
columns: dict = {"pc":12,"tablet":12,"mobile":12},
gridLayoutClass: str = "items-start",
display: list = [],
tabId: str = ""
display: Optional[list] = None,
tabId: str = "",
maxWidthScreen: str = "lg"
):
"""
This component is used for top level page layout.
@ -973,6 +970,7 @@ def grid_layout_widget(
- `gridLayoutClass` **String** Additional class (optional, default `"items-start"`)
- `display` **Array** Array need two values : "groupName" in index 0 and "compId" in index 1 in order to be displayed using the display store. More info on the display store itslef. (optional, default `[]`)
- `tabId` **String** Case the container is converted to an anchor with a link, we can define the tabId, by default it is the contentIndex (optional, default `contentIndex`)
- `maxWidthScreen` **string** Max screen width for the settings based on the breakpoint (xs, sm, md, lg, xl, 2xl) (optional, default `"lg"`)
EXAMPLE
@ -991,7 +989,7 @@ def grid_layout_widget(
# List of params that will be add only if not default value
list_params = [("type", type, "card"),("id", id, ""),("title", title, ""),("link", link, ""),("columns", columns, {"pc":12,"tablet":12,"mobile":12}),("gridLayoutClass", gridLayoutClass, "items-start"),("display", display, []),("tabId", tabId, "")]
list_params = [("type", type, "card"),("id", id, ""),("title", title, ""),("link", link, ""),("columns", columns, {"pc":12,"tablet":12,"mobile":12}),("gridLayoutClass", gridLayoutClass, "items-start"),("display", display, None),("tabId", tabId, ""),("maxWidthScreen", maxWidthScreen, "lg")]
for param in list_params:
add_key_value(data, param[0], param[1], param[2])
@ -1049,8 +1047,8 @@ def input_widget(
value: str,
id: str = "",
type: str = "text",
attrs: dict = {},
popovers: list = [],
attrs: Optional[dict] = None,
popovers: Optional[list] = None,
inpType: str = "input",
columns: dict = {"pc":"12","tablet":"12","mobile":"12"},
disabled: bool = False,
@ -1125,76 +1123,22 @@ def input_widget(
# List of params that will be add only if not default value
list_params = [("id", id, ""),("type", type, "text"),("attrs", attrs, {}),("popovers", popovers, []),("inpType", inpType, "input"),("columns", columns, {"pc":"12","tablet":"12","mobile":"12"}),("disabled", disabled, False),("required", required, False),("placeholder", placeholder, ""),("pattern", pattern, "(?.*)"),("isClipboard", isClipboard, True),("readonly", readonly, False),("hideLabel", hideLabel, False),("containerClass", containerClass, ""),("inpClass", inpClass, ""),("headerClass", headerClass, ""),("tabId", tabId, "")]
list_params = [("id", id, ""),("type", type, "text"),("attrs", attrs, None),("popovers", popovers, None),("inpType", inpType, "input"),("columns", columns, {"pc":"12","tablet":"12","mobile":"12"}),("disabled", disabled, False),("required", required, False),("placeholder", placeholder, ""),("pattern", pattern, "(?.*)"),("isClipboard", isClipboard, True),("readonly", readonly, False),("hideLabel", hideLabel, False),("containerClass", containerClass, ""),("inpClass", inpClass, ""),("headerClass", headerClass, ""),("tabId", tabId, "")]
for param in list_params:
add_key_value(data, param[0], param[1], param[2])
return { "type" : "Input", "data" : data }
def instance_widget(
title: str,
status: str,
details: list,
buttons: list
):
"""
This component is an instance widget.
This component is using the Container, TitleCard, IconStatus, ListPairs and ButtonGroup components.
PARAMETERS
- `title` **String**;
- `status` **String**;
- `details` **Array** List of details to display
- `buttons` **Array** List of buttons to display
EXAMPLE
{
id: "instance-1",
title: "Instance 1",
status: "success",
details: [
{ key: "Version", value: "1.0.0" },
{ key: "Status", value: "Running" },
{ key: "Created", value: "2021-01-01" },
],
buttons : [
{
id: "open-modal-btn",
text: "Open modal",
disabled: false,
hideText: true,
color: "green",
size: "normal",
iconName: "modal",
},
]
}
"""
data = {
"title" : title,
"status" : status,
"details" : details,
"buttons" : buttons,
}
return { "type" : "Instance", "data" : data }
def list_widget(
label: str,
name: str,
value: str,
id: str = "",
attrs: dict = {},
attrs: Optional[dict] = None,
separator: str = " ",
maxBtnChars: str = "",
popovers: list = [],
popovers: Optional[list] = None,
inpType: str = "list",
disabled: bool = False,
required: bool = False,
@ -1259,7 +1203,7 @@ def list_widget(
# List of params that will be add only if not default value
list_params = [("id", id, ""),("attrs", attrs, {}),("separator", separator, " "),("maxBtnChars", maxBtnChars, ""),("popovers", popovers, []),("inpType", inpType, "list"),("disabled", disabled, False),("required", required, False),("columns", columns, {"pc":"12","tablet":"12","mobile":"12"}),("hideLabel", hideLabel, False),("onlyDown", onlyDown, False),("overflowAttrEl", overflowAttrEl, ""),("containerClass", containerClass, ""),("inpClass", inpClass, ""),("headerClass", headerClass, ""),("tabId", tabId, "")]
list_params = [("id", id, ""),("attrs", attrs, None),("separator", separator, " "),("maxBtnChars", maxBtnChars, ""),("popovers", popovers, None),("inpType", inpType, "list"),("disabled", disabled, False),("required", required, False),("columns", columns, {"pc":"12","tablet":"12","mobile":"12"}),("hideLabel", hideLabel, False),("onlyDown", onlyDown, False),("overflowAttrEl", overflowAttrEl, ""),("containerClass", containerClass, ""),("inpClass", inpClass, ""),("headerClass", headerClass, ""),("tabId", tabId, "")]
for param in list_params:
add_key_value(data, param[0], param[1], param[2])
@ -1494,7 +1438,7 @@ def popover_widget(
text: str,
color: str,
href: str = "#",
attrs: dict = {},
attrs: Optional[dict] = None,
tag: str = "a",
iconClass: str = "icon-default",
tabId: Union[str, int] = ""
@ -1530,7 +1474,7 @@ def popover_widget(
# List of params that will be add only if not default value
list_params = [("href", href, "#"),("attrs", attrs, {}),("tag", tag, "a"),("iconClass", iconClass, "icon-default"),("tabId", tabId, "")]
list_params = [("href", href, "#"),("attrs", attrs, None),("tag", tag, "a"),("iconClass", iconClass, "icon-default"),("tabId", tabId, "")]
for param in list_params:
add_key_value(data, param[0], param[1], param[2])
@ -1584,10 +1528,10 @@ def popover_group_widget(
def raw_widget(
template: dict,
containerClass: str,
columns: dict,
operation: str = "edit",
oldServerName: str = ""
oldServerName: str = "",
containerClass: str = "",
columns: dict = {"pc":"12","tablet":"12","mobile":"12"}
):
"""
This component is used to create a complete raw form with settings as JSON format.
@ -1597,8 +1541,8 @@ def raw_widget(
- `template` **Object** Template object with plugin and settings data.
- `operation` **String** Operation type (edit, new, delete). (optional, default `"edit"`)
- `oldServerName` **String** Old server name. This is a server name before any changes. (optional, default `""`)
- `containerClass` **String** Container
- `columns` **Object** Columns object.
- `containerClass` **string** Container additional class (optional, default `""`)
- `columns` **Object** Columns object. (optional, default `{"pc":"12","tablet":"12","mobile":"12"}`)
EXAMPLE
@ -1614,32 +1558,93 @@ def raw_widget(
data = {
"template" : template,
"containerClass" : containerClass,
"columns" : columns,
}
# List of params that will be add only if not default value
list_params = [("operation", operation, "edit"),("oldServerName", oldServerName, "")]
list_params = [("operation", operation, "edit"),("oldServerName", oldServerName, ""),("containerClass", containerClass, ""),("columns", columns, {"pc":"12","tablet":"12","mobile":"12"})]
for param in list_params:
add_key_value(data, param[0], param[1], param[2])
return { "type" : "Raw", "data" : data }
def regular_widget(
fields: dict,
buttons: dict,
containerClass: str = "",
endpoint: str = "",
maxWidthScreen: str = "lg",
columns: dict = {"pc":"12","tablet":"12","mobile":"12"}
):
"""
This component is used to create a basic form with fields.
PARAMETERS
- `fields` **Object** List of Fields component to display
- `buttons` **Object** We need to send a regular ButtonGroup buttons prop
- `containerClass` **string** Container additional class (optional, default `""`)
- `endpoint` **string** Form endpoint. Case none, will be ignored. (optional, default `""`)
- `maxWidthScreen` **string** Max screen width for the settings based on the breakpoint (xs, sm, md, lg, xl, 2xl) (optional, default `"lg"`)
- `columns` **Object** Columns object. (optional, default `{"pc":"12","tablet":"12","mobile":"12"}`)
EXAMPLE
fields : [
{
columns: { pc: 6, tablet: 12, mobile: 12 },
id: "test-check",
value: "yes",
label: "Checkbox",
name: "checkbox",
required: true,
hideLabel: false,
headerClass: "text-red-500",
inpType: "checkbox",
},
{
id: "test-input",
value: "yes",
type: "text",
name: "test-input",
disabled: false,
required: true,
label: "Test input",
pattern: "(test)",
inpType: "input",
},
],
"""
data = {
"fields" : fields,
"buttons" : buttons,
}
# List of params that will be add only if not default value
list_params = [("containerClass", containerClass, ""),("endpoint", endpoint, ""),("maxWidthScreen", maxWidthScreen, "lg"),("columns", columns, {"pc":"12","tablet":"12","mobile":"12"})]
for param in list_params:
add_key_value(data, param[0], param[1], param[2])
return { "type" : "Regular", "data" : data }
def select_widget(
label: str,
name: str,
value: str,
values: list,
id: str = "",
attrs: dict = {},
popovers: list = [],
attrs: Optional[dict] = None,
popovers: Optional[list] = None,
inpType: str = "select",
maxBtnChars: str = "",
disabled: bool = False,
required: bool = False,
requiredValues: list = [],
requiredValues: Optional[list] = None,
columns: dict = {"pc":"12","tablet":"12","mobile":"12"},
hideLabel: bool = False,
onlyDown: bool = False,
@ -1709,7 +1714,7 @@ def select_widget(
# List of params that will be add only if not default value
list_params = [("id", id, ""),("attrs", attrs, {}),("popovers", popovers, []),("inpType", inpType, "select"),("maxBtnChars", maxBtnChars, ""),("disabled", disabled, False),("required", required, False),("requiredValues", requiredValues, []),("columns", columns, {"pc":"12","tablet":"12","mobile":"12"}),("hideLabel", hideLabel, False),("onlyDown", onlyDown, False),("overflowAttrEl", overflowAttrEl, ""),("containerClass", containerClass, ""),("inpClass", inpClass, ""),("headerClass", headerClass, ""),("tabId", tabId, "")]
list_params = [("id", id, ""),("attrs", attrs, None),("popovers", popovers, None),("inpType", inpType, "select"),("maxBtnChars", maxBtnChars, ""),("disabled", disabled, False),("required", required, False),("requiredValues", requiredValues, None),("columns", columns, {"pc":"12","tablet":"12","mobile":"12"}),("hideLabel", hideLabel, False),("onlyDown", onlyDown, False),("overflowAttrEl", overflowAttrEl, ""),("containerClass", containerClass, ""),("inpClass", inpClass, ""),("headerClass", headerClass, ""),("tabId", tabId, "")]
for param in list_params:
add_key_value(data, param[0], param[1], param[2])
@ -1854,7 +1859,7 @@ def table_widget(
header: list,
positions: list,
items: list,
filters: list = [],
filters: Optional[list] = None,
minWidth: str = "base",
containerClass: str = "",
containerWrapClass: str = "",
@ -1936,7 +1941,7 @@ def table_widget(
# List of params that will be add only if not default value
list_params = [("filters", filters, []),("minWidth", minWidth, "base"),("containerClass", containerClass, ""),("containerWrapClass", containerWrapClass, ""),("tableClass", tableClass, "")]
list_params = [("filters", filters, None),("minWidth", minWidth, "base"),("containerClass", containerClass, ""),("containerWrapClass", containerWrapClass, ""),("tableClass", tableClass, "")]
for param in list_params:
add_key_value(data, param[0], param[1], param[2])
@ -1948,7 +1953,7 @@ def tabulator_widget(
columns: list,
items: list,
isStriped: bool = True,
filters: list = [],
filters: Optional[list] = None,
rowHeight: int = 0,
colMinWidth: int = 150,
colMaxWidth: int = 0,
@ -2010,7 +2015,7 @@ def tabulator_widget(
# List of params that will be add only if not default value
list_params = [("isStriped", isStriped, True),("filters", filters, []),("rowHeight", rowHeight, 0),("colMinWidth", colMinWidth, 150),("colMaxWidth", colMaxWidth, 0),("isPagination", isPagination, True),("paginationSize", paginationSize, 10),("paginationInitialPage", paginationInitialPage, 1),("paginationSizeSelector", paginationSizeSelector, [10,25,50,100])]
list_params = [("isStriped", isStriped, True),("filters", filters, None),("rowHeight", rowHeight, 0),("colMinWidth", colMinWidth, 150),("colMaxWidth", colMaxWidth, 0),("isPagination", isPagination, True),("paginationSize", paginationSize, 10),("paginationInitialPage", paginationInitialPage, 1),("paginationSizeSelector", paginationSizeSelector, [10,25,50,100])]
for param in list_params:
add_key_value(data, param[0], param[1], param[2])
@ -2067,7 +2072,7 @@ def text_widget(
uppercase: bool = False,
tag: str = "p",
icon: Union[bool, dict] = False,
attrs: dict = {}
attrs: Optional[dict] = None
):
"""
This component is used for regular paragraph.
@ -2099,7 +2104,7 @@ def text_widget(
# List of params that will be add only if not default value
list_params = [("textClass", textClass, ""),("color", color, ""),("bold", bold, False),("uppercase", uppercase, False),("tag", tag, "p"),("icon", icon, False),("attrs", attrs, {})]
list_params = [("textClass", textClass, ""),("color", color, ""),("bold", bold, False),("uppercase", uppercase, False),("tag", tag, "p"),("icon", icon, False),("attrs", attrs, None)]
for param in list_params:
add_key_value(data, param[0], param[1], param[2])

View file

@ -1,6 +1,6 @@
from utils import save_builder
from pages.instances2 import instances_builder
from pages.instances import instances_builder
# Create instance class using keys from the instances list
@ -14,8 +14,17 @@ class Instance:
instances = [
{"name": "instance1", "hostname": "hostname1", "type": "static", "health": "up", "id": 1},
{"name": "instance2", "hostname": "hostname2", "type": "container", "health": "down", "id": 2},
{"name": "instance1", "hostname": "hostname1", "type": "static", "health": "up", "last_seen": "yyyy", "method": "method", "creation_date": "yyyy", "id": 1},
{
"name": "instance2",
"hostname": "hostname2",
"type": "container",
"health": "down",
"last_seen": "yyyy",
"method": "ui",
"creation_date": "yyyy",
"id": 2,
},
]
types = ["static", "container"]
@ -25,4 +34,4 @@ healths = ["up", "down", "loading"]
builder = instances_builder(instances)
save_builder("instances2", builder, update_page=False)
save_builder(page_name="instances", output=builder, script_name="instances")

View file

@ -3,11 +3,14 @@ import json
import base64
def save_builder(page_name: str, output: str, store_json: bool = True, update_page: bool = True):
def save_builder(page_name: str, output: str, store_json: bool = True, update_page: bool = True, script_name: str = ""):
if store_json:
with open(f"test_{page_name.lower()}.json", "w") as f:
json.dump(output, f, indent=4)
if not update_page:
return
data = base64.b64encode(bytes(json.dumps(output), "utf-8"))
data = data.decode("ascii")
# get current directory
@ -39,7 +42,7 @@ def save_builder(page_name: str, output: str, store_json: bool = True, update_pa
data-server-builder='{data}'
></div>
<div id="app"></div>
<script type="module" src="{page_name.lower()}.js"></script>
<script type="module" src="{script_name or page_name.lower()}.js"></script>
</body>
</html>
"""

View file

@ -41,11 +41,13 @@ const props = defineProps({
v-for="(container, index) in props.builder"
:key="index"
:gridLayoutClass="container.containerClass"
:maxWidthScreen="container.maxWidthScreen"
:type="container.type"
:title="container.title"
:link="container.link"
:columns="container.containerColumns"
:id="container.id"
:display="container.display"
>
<!-- widget grid -->
<Grid>

View file

@ -53,11 +53,13 @@ const props = defineProps({
v-for="(container, index) in props.builder"
:key="index"
:gridLayoutClass="container.containerClass"
:maxWidthScreen="container.maxWidthScreen"
:type="container.type"
:title="container.title"
:link="container.link"
:columns="container.containerColumns"
:id="container.id"
:display="container.display"
>
<!-- widget grid -->
<Grid>

View file

@ -45,11 +45,13 @@ const props = defineProps({
v-for="(container, index) in props.builder"
:key="index"
:gridLayoutClass="container.containerClass"
:maxWidthScreen="container.maxWidthScreen"
:type="container.type"
:title="container.title"
:link="container.link"
:columns="container.containerColumns"
:id="container.id"
:display="container.display"
>
<!-- widget grid -->
<Grid>

View file

@ -2,8 +2,12 @@
// Containers
import Grid from "@components/Widget/Grid.vue";
import GridLayout from "@components/Widget/GridLayout.vue";
import Instance from "@components/Widget/Instance.vue";
import Tabulator from "@components/Widget/Tabulator.vue";
import Button from "@components/Widget/Button.vue";
import ButtonGroup from "@components/Widget/ButtonGroup.vue";
import Regular from "@components/Form/Regular.vue";
import Title from "@components/Widget/Title.vue";
import Subtitle from "@components/Widget/Subtitle.vue";
import { useEqualStr } from "@utils/global.js";
/**
@ -49,22 +53,37 @@ const props = defineProps({
v-for="(container, index) in props.builder"
:key="index"
:gridLayoutClass="container.containerClass"
:maxWidthScreen="container.maxWidthScreen"
:type="container.type"
:title="container.title"
:link="container.link"
:columns="container.containerColumns"
:id="container.id"
:display="container.display"
>
<!-- widget grid -->
<Grid>
<!-- widget element -->
<template v-for="(widget, index) in container.widgets" :key="index">
<Instance
v-if="useEqualStr(widget.type, 'Instance')"
<Tabulator
v-if="useEqualStr(widget.type, 'Tabulator')"
v-bind="widget.data"
/>
<Tabulator
v-else-if="useEqualStr(widget.type, 'Tabulator')"
<Button
v-if="useEqualStr(widget.type, 'Button')"
v-bind="widget.data"
/>
<Regular
v-if="useEqualStr(widget.type, 'Regular')"
v-bind="widget.data"
/>
<ButtonGroup
v-if="useEqualStr(widget.type, 'ButtonGroup')"
v-bind="widget.data"
/>
<Title v-if="useEqualStr(widget.type, 'Title')" v-bind="widget.data" />
<Subtitle
v-if="useEqualStr(widget.type, 'Subtitle')"
v-bind="widget.data"
/>
</template>

View file

@ -75,11 +75,13 @@ const props = defineProps({
v-for="(container, index) in props.builder"
:key="index"
:gridLayoutClass="container.containerClass"
:maxWidthScreen="container.maxWidthScreen"
:type="container.type"
:title="container.title"
:link="container.link"
:columns="container.containerColumns"
:id="container.id"
:display="container.display"
>
<!-- widget grid -->
<Grid>

View file

@ -27,11 +27,13 @@ const props = defineProps({
v-for="(container, index) in props.builder"
:key="index"
:gridLayoutClass="container.containerClass"
:maxWidthScreen="container.maxWidthScreen"
:type="container.type"
:title="container.title"
:link="container.link"
:columns="container.containerColumns"
:id="container.id"
:display="container.display"
>
<!-- widget grid -->
<Grid>

View file

@ -50,11 +50,13 @@ const props = defineProps({
v-for="(container, index) in props.builder"
:key="index"
:gridLayoutClass="container.containerClass"
:maxWidthScreen="container.maxWidthScreen"
:type="container.type"
:title="container.title"
:link="container.link"
:columns="container.containerColumns"
:id="container.id"
:display="container.display"
>
<!-- widget grid -->
<Grid>

View file

@ -60,11 +60,13 @@ const props = defineProps({
v-for="(container, index) in props.builder"
:key="index"
:gridLayoutClass="container.containerClass"
:maxWidthScreen="container.maxWidthScreen"
:type="container.type"
:title="container.title"
:link="container.link"
:columns="container.containerColumns"
:id="container.id"
:display="container.display"
>
<!-- widget grid -->
<Grid>

View file

@ -42,11 +42,13 @@ const props = defineProps({
v-for="(container, index) in props.builder"
:key="index"
:gridLayoutClass="container.containerClass"
:maxWidthScreen="container.maxWidthScreen"
:type="container.type"
:title="container.title"
:link="container.link"
:columns="container.containerColumns"
:id="container.id"
:display="container.display"
>
<!-- widget grid -->
<Grid>

View file

@ -306,11 +306,13 @@ const props = defineProps({
v-for="(container, index) in props.builder"
:key="index"
:gridLayoutClass="container.containerClass"
:maxWidthScreen="container.maxWidthScreen"
:type="container.type"
:title="container.title"
:link="container.link"
:columns="container.containerColumns"
:id="container.id"
:display="container.display"
>
<!-- widget grid -->
<Grid>

View file

@ -28,11 +28,13 @@ const props = defineProps({
v-for="(container, index) in props.builder"
:key="index"
:gridLayoutClass="container.containerClass"
:maxWidthScreen="container.maxWidthScreen"
:type="container.type"
:title="container.title"
:link="container.link"
:columns="container.containerColumns"
:id="container.id"
:display="container.display"
>
<!-- widget grid -->
<Grid>

View file

@ -46,10 +46,10 @@ import { v4 as uuidv4 } from "uuid";
* ],
* }
* @param {Object} template - Template object with plugin and settings data.
* @param {string} containerClass - Container
* @param {string} [containerClass=""] - Container additional class
* @param {string} [operation="edit"] - Operation type (edit, new, delete).
* @param {string} [oldServerName=""] - Old server name. This is a server name before any changes.
* @param {Object} columns - Columns object.
* @param {Object} [columns={ "pc": "12", "tablet": "12", "mobile": "12" }] - Columns object.
*/
const advancedForm = useAdvancedForm();

View file

@ -50,10 +50,10 @@ import { useEasyForm } from "@store/form.js";
* ],
* }
* @param {Object} template - Template object with plugin and settings data.
* @param {string} containerClass - Container
* @param {string} [containerClass=""] - Container additional class
* @param {string} [operation="edit"] - Operation type (edit, new, delete).
* @param {string} [oldServerName=""] - Old server name. This is a server name before any changes.
* @param {Object} columns - Columns object.
* @param {Object} [columns={ "pc": "12", "tablet": "12", "mobile": "12" }] - Columns object.
*/
const easyForm = useEasyForm();

View file

@ -48,7 +48,7 @@ const emit = defineEmits(["inp"]);
@inp="(value) => $emit('inp', value)"
v-if="props.setting.inpType === 'checkbox'"
:id="props.setting.id || ''"
:columns="props.setting.columns || false"
:columns="props.setting.columns || { pc: '12', tablet: '12', mobile: '12' }"
:value="props.setting.value"
:popovers="props.setting.popovers || []"
:inpType="props.setting.inpType || 'checkbox'"
@ -67,7 +67,7 @@ const emit = defineEmits(["inp"]);
@inp="(value) => $emit('inp', value)"
v-if="props.setting.inpType === 'select'"
:id="props.setting.id || ''"
:columns="props.setting.columns || false"
:columns="props.setting.columns || { pc: '12', tablet: '12', mobile: '12' }"
:value="props.setting.value"
:values="props.setting.values"
:inpType="props.setting.inpType || 'select'"
@ -91,7 +91,7 @@ const emit = defineEmits(["inp"]);
@inp="(value) => $emit('inp', value)"
v-if="props.setting.inpType === 'datepicker'"
:id="props.setting.id || ''"
:columns="props.setting.columns || false"
:columns="props.setting.columns || { pc: '12', tablet: '12', mobile: '12' }"
:value="props.setting.value || ''"
:minDate="props.setting.minDate || ''"
:maxDate="props.setting.maxDate || ''"
@ -113,7 +113,7 @@ const emit = defineEmits(["inp"]);
@inp="(value) => $emit('inp', value)"
v-if="props.setting.inpType === 'input'"
:id="props.setting.id || ''"
:columns="props.setting.columns || false"
:columns="props.setting.columns || { pc: '12', tablet: '12', mobile: '12' }"
:name="props.setting.name"
:type="props.setting.type"
:inpType="props.setting.inpType || 'input'"
@ -137,7 +137,7 @@ const emit = defineEmits(["inp"]);
@inp="(value) => $emit('inp', value)"
v-if="props.setting.inpType === 'editor'"
:id="props.setting.id || ''"
:columns="props.setting.columns || false"
:columns="props.setting.columns || { pc: '12', tablet: '12', mobile: '12' }"
:name="props.setting.name"
:inpType="props.setting.inpType || 'editor'"
:required="props.setting.required || false"

View file

@ -23,8 +23,8 @@ import { useRawForm } from "@store/form.js";
* @param {Object} template - Template object with plugin and settings data.
* @param {String} [operation="edit"] - Operation type (edit, new, delete).
* @param {String} [oldServerName=""] - Old server name. This is a server name before any changes.
* @param {String} containerClass - Container
* @param {Object} columns - Columns object.
* @param {string} [containerClass=""] - Container additional class
* @param {Object} [columns={ "pc": "12", "tablet": "12", "mobile": "12" }] - Columns object.
*/
const rawForm = useRawForm();

View file

@ -0,0 +1,127 @@
<script setup>
import { defineProps, reactive, onMounted } from "vue";
import Container from "@components/Widget/Container.vue";
import Fields from "@components/Form/Fields.vue";
import ButtonGroup from "@components/Widget/ButtonGroup.vue";
import Text from "@components/Widget/Text.vue";
/**
* @name Form/Regular.vue
* @description This component is used to create a basic form with fields.
* @example
* fields : [
* {
* columns: { pc: 6, tablet: 12, mobile: 12 },
* id: "test-check",
* value: "yes",
* label: "Checkbox",
* name: "checkbox",
* required: true,
* hideLabel: false,
* headerClass: "text-red-500",
* inpType: "checkbox",
* },
* {
* id: "test-input",
* value: "yes",
* type: "text",
* name: "test-input",
* disabled: false,
* required: true,
* label: "Test input",
* pattern: "(test)",
* inpType: "input",
* },
* ],
* @param {Object} fields - List of Fields component to display
* @param {Object} buttons - We need to send a regular ButtonGroup buttons prop
* @param {string} [containerClass=""] - Container additional class
* @param {string} [endpoint=""] - Form endpoint. Case none, will be ignored.
* @param {string} [maxWidthScreen="lg"] - Max screen width for the settings based on the breakpoint (xs, sm, md, lg, xl, 2xl)
* @param {Object} [columns={ "pc": "12", "tablet": "12", "mobile": "12" }] - Columns object.
*/
const props = defineProps({
// id && value && method
fields: {
type: Array,
required: true,
default: [],
},
buttons: {
type: Array,
required: false,
default: {},
},
maxWidthScreen: {
type: String,
required: false,
default: "lg",
},
endpoint: {
type: String,
required: false,
default: "",
},
containerClass: {
type: String,
required: false,
default: "",
},
columns: {
type: Object,
required: false,
default: { pc: 12, tablet: 12, mobile: 12 },
},
});
const data = reactive({
base: props.fields,
endpoint: props.endpoint,
isRegErr: false,
isReqErr: false,
settingErr: "",
pluginErr: "",
isUpdateData: false,
});
onMounted(() => {
data.endpoint =
window.location.origin + window.location.pathname + props.endpoint;
});
</script>
<template>
<Container
data-is="form"
:tag="'form'"
method="POST"
:action="data.endpoint"
:columns="props.columns"
:containerClass="`form-regular-container`"
>
<div class="form-regular-wrap">
<div :class="['layout-settings', `max-w-screen-${props.maxWidthScreen}`]">
<template v-for="(field, key) in props.fields">
<Fields :setting="field.setting" />
</template>
</div>
<ButtonGroup :buttons="props.buttons" />
<div class="flex justify-center items-center" data-is="form-error">
<Text
v-if="data.isRegErr || data.isReqErr"
:text="
data.isReqErr
? $t('dashboard_regular_required', {
setting: data.settingErr,
})
: $t('dashboard_regular_invalid', {
setting: data.settingErr,
})
"
/>
</div>
</div>
</Container>
</template>

View file

@ -71,7 +71,7 @@ const props = defineProps({
columns: {
type: [Object, Boolean],
required: false,
default: false,
default: { pc: "12", tablet: "12", mobile: "12" },
},
name: {
type: String,

View file

@ -157,21 +157,31 @@ function handleClick(e) {
btn.openModal = true;
}
if (props.display.length) {
console.log("update", btn.isActive);
displayStore.setDisplay(props.display[0], props.display[1]);
}
}
/**
* @name checkDisplay
* @description Check if the current display value is matching the display store value.
* @returns {Void}
*/
function checkDisplay() {
if (!props.display.length) return;
const isCurrent = displayStore.isCurrentDisplay(
props.display[0],
props.display[1]
);
btnEl.value.setAttribute("aria-controls", btn.modalId);
btnEl.value.setAttribute("aria-expanded", isCurrent ? "true" : "false");
btn.isActive = isCurrent ? true : false;
}
// Add a11y attributs and update when needed in case the button is related to a display group
if (props.display.length) {
watch(displayStore.display, (val) => {
const isCurrent = displayStore.isCurrentDisplay(
props.display[0],
props.display[1]
);
btnEl.value.setAttribute("aria-controls", btn.modalId);
btnEl.value.setAttribute("aria-expanded", isCurrent ? "true" : "false");
btn.isActive = isCurrent ? true : false;
checkDisplay();
});
}

View file

@ -59,7 +59,7 @@ const groupEl = ref(null);
onMounted(() => {
group.class =
props.boutonGroupClass || groupEl?.value.closest("[data-is]")
props.boutonGroupClass || groupEl?.value?.closest("[data-is]")
? `button-group-${groupEl.value
.closest("[data-is]")
.getAttribute("data-is")}`
@ -85,7 +85,7 @@ onMounted(() => {
<Button
v-for="(button, id) in props.buttons"
:key="button"
v-bind="button"
v-bind="button.data"
:class="[id === props.buttons.length - 1 ? '' : 'mr-2']"
/>
</div>

View file

@ -1,6 +1,6 @@
<script setup>
import { useDisplayStore } from "@store/global.js";
import { defineProps, watch, computed, reactive } from "vue";
import { defineProps, watch, computed, reactive, onMounted } from "vue";
/**
* @name Widget/Container.vue
* @description This component is a basic container that can be used to wrap other components.
@ -13,7 +13,7 @@ import { defineProps, watch, computed, reactive } from "vue";
* columns: { pc: 12, tablet: 12, mobile: 12}
* }
* @param {String} [containerClass=""] - Additional class
* @param {Object|boolean} [columns=false] - Work with grid system { pc: 12, tablet: 12, mobile: 12}
* @param {Object|boolean} [columns={"pc": "12", "tablet": "12", "mobile": "12"}] - Work with grid system { pc: 12, tablet: 12, mobile: 12}
* @param {String} [tag="div"] - The tag for the container
* @param {Array} [display=[]] - Array need two values : "groupName" in index 0 and "compId" in index 1 in order to be displayed using the display store. More info on the display store itslef.
*/
@ -25,9 +25,9 @@ const props = defineProps({
default: "",
},
columns: {
type: [Object, Boolean],
type: Object,
required: false,
default: false,
default: { pc: "12", tablet: "12", mobile: "12" },
},
tag: {
type: String,
@ -50,13 +50,23 @@ const container = reactive({
: true,
});
/**
* @name checkDisplay
* @description Check if the current display value is matching the display store value.
* @returns {Void}
*/
function checkDisplay() {
if (!props.display.length) return;
container.isDisplay = displayStore.isCurrentDisplay(
props.display[0],
props.display[1]
);
}
// Case we have set a display group name and component id, the component id must match the current display id for the same group name to be displayed.
if (props.display.length) {
watch(displayStore.display, (val) => {
container.isDisplay = displayStore.isCurrentDisplay(
props.display[0],
props.display[1]
);
checkDisplay();
});
}
@ -69,7 +79,8 @@ const gridClass = computed(() => {
<template>
<component
v-if="container.isDisplay"
v-show="container.isDisplay"
:aria-hidden="container.isDisplay ? 'false' : 'true'"
:is="props.tag"
data-container
:class="[props.containerClass ? props.containerClass : '', gridClass]"

View file

@ -1,6 +1,6 @@
<script setup>
import { useDisplayStore } from "@store/global.js";
import { defineProps, watch, reactive } from "vue";
import { defineProps, watch, reactive, onMounted } from "vue";
/**
* @name Widget/Grid.vue
* @description This component is a basic container that can be used to wrap other components.
@ -38,20 +38,31 @@ const container = reactive({
: true,
});
/**
* @name checkDisplay
* @description Check if the current display value is matching the display store value.
* @returns {Void}
*/
function checkDisplay() {
if (!props.display.length) return;
container.isDisplay = displayStore.isCurrentDisplay(
props.display[0],
props.display[1]
);
}
// Case we have set a display group name and component id, the component id must match the current display id for the same group name to be displayed.
if (props.display.length) {
watch(displayStore.display, (val) => {
container.isDisplay = displayStore.isCurrentDisplay(
props.display[0],
props.display[1]
);
checkDisplay();
});
}
</script>
<template>
<div
v-if="container.isDisplay"
v-show="container.isDisplay"
:aria-hidden="container.isDisplay ? 'false' : 'true'"
data-grid
:class="[props.gridClass, 'layout-grid']"
>

View file

@ -26,6 +26,7 @@ import { useDisplayStore } from "@store/global.js";
* @param {String} [gridLayoutClass="items-start"] - Additional class
* @param {Array} [display=[]] - Array need two values : "groupName" in index 0 and "compId" in index 1 in order to be displayed using the display store. More info on the display store itslef.
* @param {String} [tabId=contentIndex] - Case the container is converted to an anchor with a link, we can define the tabId, by default it is the contentIndex
* @param {string} [maxWidthScreen="lg"] - Max screen width for the settings based on the breakpoint (xs, sm, md, lg, xl, 2xl)
*/
const props = defineProps({
@ -73,6 +74,11 @@ const props = defineProps({
required: false,
default: [],
},
maxWidthScreen: {
type: String,
required: false,
default: "2xl",
},
});
const displayStore = useDisplayStore();
@ -85,13 +91,23 @@ const container = reactive({
: true,
});
/**
* @name checkDisplay
* @description Check if the current display value is matching the display store value.
* @returns {Void}
*/
function checkDisplay() {
if (!props.display.length) return;
container.isDisplay = displayStore.isCurrentDisplay(
props.display[0],
props.display[1]
);
}
// Case we have set a display group name and component id, the component id must match the current display id for the same group name to be displayed.
if (props.display.length) {
watch(displayStore.display, (val) => {
container.isDisplay = displayStore.isCurrentDisplay(
props.display[0],
props.display[1]
);
checkDisplay();
});
}
@ -125,12 +141,18 @@ onMounted(() => {
<template>
<component
v-if="container.isDisplay"
v-show="container.isDisplay"
:aria-hidden="container.isDisplay ? 'false' : 'true'"
ref="flowEl"
:id="container.id"
:is="props.link ? 'a' : 'div'"
:data-is="`${props.type}`"
:class="[containerClass, gridClass, props.gridLayoutClass]"
:class="[
containerClass,
gridClass,
props.gridLayoutClass,
`max-w-screen-${props.maxWidthScreen}`,
]"
>
<slot></slot>
</component>

View file

@ -1,70 +0,0 @@
<script setup>
import { defineProps } from "vue";
import Container from "@components/Widget/Container.vue";
import Title from "@components/Widget/Title.vue";
import Status from "@components/Widget/Status.vue";
import ListPairs from "@components/List/Pairs.vue";
import ButtonGroup from "@components/Widget/ButtonGroup.vue";
/**
* @name Widget/Instance.vue
* @description This component is an instance widget.
* This component is using the Container, TitleCard, IconStatus, ListPairs and ButtonGroup components.
* @example
* {
* id: "instance-1",
* title: "Instance 1",
* status: "success",
* details: [
* { key: "Version", value: "1.0.0" },
* { key: "Status", value: "Running" },
* { key: "Created", value: "2021-01-01" },
* ],
* buttons : [
* {
* id: "open-modal-btn",
* text: "Open modal",
* disabled: false,
* hideText: true,
* color: "green",
* size: "normal",
* iconName: "modal",
* },
* ]
* }
* @param {String} title
* @param {String} status
* @param {Array} details - List of details to display
* @param {Array} buttons - List of buttons to display
*/
const props = defineProps({
title: {
type: String,
required: true,
},
status: {
type: String,
required: true,
default: "",
},
pairs: {
type: Array,
required: true,
default: [],
},
buttons: {
type: Array,
required: true,
default: [],
},
});
</script>
<template>
<Container data-is="instance" :columns="{ pc: 12, tablet: 12, mobile: 12 }">
<Status :id="props.title" :status="props.status" />
<Title type="card" :title="props.title" />
<ListPairs :pairs="props.pairs" />
<ButtonGroup v-if="props.buttons.length > 0" :buttons="props.buttons" />
</Container>
</template>

View file

@ -191,12 +191,25 @@
"home_errors_found": "errors found",
"instances_name": "name",
"instances_hostname": "hostname",
"instances_search": "search",
"instances_search_popover": "Search by hostname or name keyword.",
"instances_type": "type",
"instances_status": "status",
"instances_active": "active",
"instances_inactive": "inactive",
"instances_creation_date": "creation date",
"instances_last_seen": "last seen",
"instances_type_popover": "Select the instance type.",
"instances_method": "method",
"instances_method_popover": "Select the instance method.",
"instances_health": "health",
"instances_health_popover": "Select the instance health. Health is based on the last seen date.",
"instances_ping_title": "Ping instance",
"instances_ping_subtitle": "Ping will check instance health of the following instance.",
"instances_delete_title": "Delete instance",
"instances_delete_subtitle": "Are you sure to delete the following instance ?",
"instances_create_title": "Create instance",
"instances_create_subtitle": "Notice that port and server name will be set by scheduler.",
"instances_tab_list": "Instances",
"instances_tab_add": "Add instance",
"instances_list_title": "Instances",
"instances_list_subtitle": "List of instances related to BunkerWeb.",
"instances_not_found": "No instances found",
"global_config_title": "Global configuration",
"global_config_subtitle": "Manage your global settings.",
"jobs_title": "Jobs list",

View file

@ -2,14 +2,20 @@
import { reactive, onBeforeMount, onMounted } from "vue";
import DashboardLayout from "@components/Dashboard/Layout.vue";
import BuilderInstances from "@components/Builder/Instances.vue";
import { useGlobal } from "@utils/global";
import { useGlobal } from "@utils/global.js";
import { useDisplayStore } from "@store/global.js";
/**
* @name Page/Instances.vue
* @description This component is the instances page.
This page displays current instances and allows to manage them.
We are using displayStore and setting ["main", 1] to display the instances list first.
*/
// Set default store
const displayStore = useDisplayStore();
displayStore.setDisplay("main", 1);
const instances = reactive({
builder: "",
});

File diff suppressed because one or more lines are too long

View file

@ -1,60 +0,0 @@
<script setup>
import { reactive, onBeforeMount, onMounted } from "vue";
import DashboardLayout from "@components/Dashboard/Layout.vue";
import BuilderInstances from "@components/Builder/Instances.vue";
import { useGlobal } from "@utils/global";
/**
* @name Page/Instances.vue
* @description This component is the instances page.
This page displays current instances and allows to manage them.
*/
const instances = reactive({
builder: "",
});
onBeforeMount(() => {
// Get builder data
const dataAtt = "data-server-builder";
const dataEl = document.querySelector(`[${dataAtt}]`);
const data =
dataEl && !dataEl.getAttribute(dataAtt).includes(dataAtt)
? JSON.parse(atob(dataEl.getAttribute(dataAtt)))
: {};
instances.builder = data;
});
onMounted(() => {
// Set the page title
useGlobal();
});
// const data = [
// {
// type: "Instance",
// data: {
// details: [
// { key: <instances_hostname="hostname">, value: "www.example.com" },
// { key: <instances_method="method">, value: <dashboard_ui> or <dashboard_scheduler>...},
// { key: <instances_port="port">, value: "1084" },
// { key: <instances_status="status">, value: <instances_active="active"> or <instances_inactive="inactive"> },
// ],
// status: "success",
// title: "www.example.com",
// buttons: [
// {
// text: <action_*>,
// color: "edit",
// size: "normal",
// },
// ],
// },
// },
// ];
</script>
<template>
<DashboardLayout>
<BuilderInstances v-if="instances.builder" :builder="instances.builder" />
</DashboardLayout>
</template>

View file

@ -1,27 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/x-icon" href="/img/favicon.ico" />
<link rel="stylesheet" href="/css/style.css" />
<link rel="stylesheet" href="/css/flag-icons.min.css" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>BunkerWeb | Instances</title>
</head>
<body>
<div
class="hidden"
data-server-global='{"username" : "admin", "plugins_page": [{"id" : "antibot", "name": "Antibot"}, {"id": "backup", "name" : "backup"}]}'
></div>
<div
class="hidden"
data-server-flash='[{"type" : "success", "title" : "title", "message" : "Success feedback"}, {"type" : "error", "title" : "title", "message" : "Error feedback"}, {"type" : "warning", "title" : "title", "message" : "Warning feedback"}, {"type" : "info", "title" : "title", "message" : "Info feedback"}]'
></div>
<div
class="hidden"
data-server-builder="W3sidHlwZSI6ICJjYXJkIiwgIndpZGdldHMiOiBbeyJ0eXBlIjogIlRhYnVsYXRvciIsICJkYXRhIjogeyJpZCI6ICJ0YWJsZS1pbnN0YW5jZXMiLCAiY29sdW1ucyI6IFt7InRpdGxlIjogIk5hbWUiLCAiZmllbGQiOiAibmFtZSIsICJmb3JtYXR0ZXIiOiAidGV4dCJ9LCB7InRpdGxlIjogIkhvc3RuYW1lIiwgImZpZWxkIjogImhvc3RuYW1lIiwgImZvcm1hdHRlciI6ICJ0ZXh0In0sIHsidGl0bGUiOiAiVHlwZSIsICJmaWVsZCI6ICJ0eXBlIiwgImZvcm1hdHRlciI6ICJ0ZXh0In0sIHsidGl0bGUiOiAiTWV0aG9kIiwgImZpZWxkIjogIm1ldGhvZCIsICJmb3JtYXR0ZXIiOiAidGV4dCJ9LCB7InRpdGxlIjogIkNyZWF0aW9uIGRhdGUiLCAiZmllbGQiOiAiY3JlYXRpb25fZGF0ZSIsICJmb3JtYXR0ZXIiOiAidGV4dCJ9LCB7InRpdGxlIjogIkxhc3Qgc2VlbiIsICJmaWVsZCI6ICJsYXN0X3NlZW4iLCAiZm9ybWF0dGVyIjogInRleHQifSwgeyJ0aXRsZSI6ICJBY3Rpb25zIiwgImZpZWxkIjogImFjdGlvbnMiLCAiZm9ybWF0dGVyIjogImJ1dHRvbkdyb3VwIn1dLCAiaXRlbXMiOiBbeyJuYW1lIjogeyJ0ZXh0IjogIk5hbWUifSwgImhvc3RuYW1lIjogeyJ0ZXh0IjogIkhvc3RuYW1lIn0sICJ0eXBlIjogeyJ0ZXh0IjogIlR5cGUifSwgIm1ldGhvZCI6IHsidGV4dCI6ICJNZXRob2QifSwgImNyZWF0aW9uX2RhdGUiOiB7InRleHQiOiAiQ3JlYXRpb24gZGF0ZSJ9LCAibGFzdF9zZWVuIjogeyJ0ZXh0IjogIkxhc3Qgc2VlbiJ9fV0sICJmaWx0ZXJzIjogW3sidHlwZSI6ICJsaWtlIiwgImZpZWxkcyI6IFsibmFtZSIsICJob3N0bmFtZSJdLCAic2V0dGluZyI6IHsiaWQiOiAiaW5wdXQtc2VhcmNoLWhvc3QtbmFtZSIsICJuYW1lIjogImlucHV0LXNlYXJjaC1ob3N0LW5hbWUiLCAibGFiZWwiOiAiU2VhcmNoIChob3N0KW5hbWUiLCAidmFsdWUiOiAiIiwgImlucFR5cGUiOiAiaW5wdXQiLCAiY29sdW1ucyI6IHsicGMiOiAzLCAidGFibGV0IjogNCwgIiBtb2JpbGUiOiAxMn19fSwgeyJ0eXBlIjogIj0iLCAiZmllbGRzIjogWyJ0eXBlIl0sICJzZXR0aW5nIjogeyJpZCI6ICJzZWxlY3QtdHlwZSIsICJuYW1lIjogInNlbGVjdC10eXBlIiwgImxhYmVsIjogIlNlbGVjdCB0eXBlIiwgInZhbHVlIjogImFsbCIsICJ2YWx1ZXMiOiBbImFsbCIsICJ0eXBlMSIsICJ0eXBlMiJdLCAiaW5wVHlwZSI6ICJzZWxlY3QiLCAib25seURvd24iOiB0cnVlLCAiY29sdW1ucyI6IHsicGMiOiAzLCAidGFibGV0IjogNCwgIiBtb2JpbGUiOiAxMn19fSwgeyJ0eXBlIjogIj0iLCAiZmllbGRzIjogWyJtZXRob2QiXSwgInNldHRpbmciOiB7ImlkIjogInNlbGVjdC1tZXRob2QiLCAibmFtZSI6ICJzZWxlY3QtbWV0aG9kIiwgImxhYmVsIjogIlNlbGVjdCBtZXRob2QiLCAidmFsdWUiOiAiYWxsIiwgInZhbHVlcyI6IFsiYWxsIiwgIm1ldGhvZDEiLCAibWV0aG9kMiJdLCAiaW5wVHlwZSI6ICJzZWxlY3QiLCAib25seURvd24iOiB0cnVlLCAiY29sdW1ucyI6IHsicGMiOiAzLCAidGFibGV0IjogNCwgIiBtb2JpbGUiOiAxMn19fV19fV19XQ"
></div>
<div id="app"></div>
<script type="module" src="instances.js"></script>
</body>
</html>

View file

@ -1,11 +0,0 @@
import { createApp } from "vue";
import { createPinia } from "pinia";
import { getI18n } from "@utils/lang.js";
import Instances from "./Instances.vue";
const pinia = createPinia();
createApp(Instances)
.use(pinia)
.use(getI18n(["dashboard", "action", "inp", "icons", "instances"]))
.mount("#app");

View file

@ -29,7 +29,9 @@ function useSubmitAttr(e) {
try {
const data = JSON.parse(e.target.getAttribute("data-submit-form"));
const submitEndpoint = e.target.hasAttribute("data-submit-endpoint")
? e.target.getAttribute("data-submit-endpoint")
? `${window.location.origin}${
window.location.pathname
}${e.target.getAttribute("data-submit-endpoint")}`
: "";
useSubmitForm(data, submitEndpoint);
} catch (e) {

View file

@ -123,7 +123,7 @@ body {
}
.content-wrap {
@apply grid gap-y-4 gap-3 sm:gap-4 lg:gap-4 grid-cols-12 w-full max-w-[1920px];
@apply grid gap-y-4 gap-3 sm:gap-4 lg:gap-4 grid-cols-12 w-full max-w-[1920px] justify-items-center;
}
/* HEADER */
@ -1150,6 +1150,10 @@ body {
@apply flex justify-center items-center mx-4;
}
.button-group-form {
@apply col-span-12 flex justify-center items-center;
}
.button-group-tabs {
@apply col-span-12 flex justify-center items-center;
}
@ -1334,6 +1338,14 @@ body {
/* FORM */
.form-regular-container {
@apply col-span-12 w-full mt-3 mb-2;
}
.form-regular-wrap {
@apply flex flex-col justify-center items-center;
}
.form-advanced-container {
@apply col-span-12 w-full;
}
@ -3344,7 +3356,6 @@ body {
}
.tabulator .tabulator-footer {
border-top: 1px solid #999;
background-color: #f9fafb;
color: #555;
font-weight: bold;
@ -3680,6 +3691,7 @@ body {
overflow: hidden;
text-overflow: ellipsis;
outline: none;
height: unset !important;
}
.tabulator-row .tabulator-cell.tabulator-row-header {
@ -4468,7 +4480,6 @@ body.tabulator-print-fullscreen-hide > *:not(.tabulator-print-fullscreen) {
.tabulator .tabulator-footer {
padding: 0.78571em 0.78571em;
border-top: 1px solid rgba(34, 36, 38, 0.15);
box-shadow: none;
background: #f9fafbc7;
text-align: right;

File diff suppressed because one or more lines are too long

View file

@ -8,6 +8,12 @@ export default {
"../setup/src/*.{js,vue,ts,jsx,tsx,mdx}",
],
safelist: [
"max-w-screen-xs",
"max-w-screen-sm",
"max-w-screen-md",
"max-w-screen-lg",
"max-w-screen-xl",
"max-w-screen-2xl",
"col-span-1",
"col-span-2",
"col-span-3",

View file

@ -316,7 +316,6 @@ def convert_params(params: List[dict]) -> List[dict]:
# Case we have multiple types
if param_type and param_type and "(" in param_type and "|" in param_type:
is_union = True
# We need to remove parenthesis
param_type = param_type.replace("(", "").replace(")", "")
# We need to split by |
@ -334,6 +333,15 @@ def convert_params(params: List[dict]) -> List[dict]:
if default and default in convert_values:
default = convert_values[default]
# When matching specific param and default
if param.get("type").lower().strip() == "array" and param.get("default") == "[]":
convert_type = "Optional[list]"
default = "None"
if param.get("type").lower().strip() == "object" and param.get("default") == "{}":
convert_type = "Optional[dict]"
default = "None"
convert_params.append({"name": param.get("name"), "type": convert_type, "default": default})
# remove None values
@ -428,7 +436,7 @@ def merge_widgets():
Path(f"{outputFolderWidgets}/widgets.py").write_text("")
content = """
from typing import Union
from typing import Union, Optional
# Add params to data dict only if value is not the default one
def add_key_value(data, key, value, default):