mirror of
https://github.com/bunkerity/bunkerweb
synced 2026-05-24 09:28:37 +00:00
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:
parent
b9e0e55ea5
commit
27920db4dd
46 changed files with 871 additions and 737 deletions
|
|
@ -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)
|
||||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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},
|
||||
),
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
]
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
},
|
||||
]
|
||||
|
|
@ -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 [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
3
src/ui/client/builder/pages/utils/format.py
Normal file
3
src/ui/client/builder/pages/utils/format.py
Normal 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()}}
|
||||
|
|
@ -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"]}
|
||||
|
|
|
|||
|
|
@ -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])
|
||||
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
@ -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>
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
127
src/ui/client/dashboard/components/Form/Regular.vue
Normal file
127
src/ui/client/dashboard/components/Form/Regular.vue
Normal 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>
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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]"
|
||||
|
|
|
|||
|
|
@ -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']"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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");
|
||||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
Loading…
Reference in a new issue