start new formatting

* start base instance page format
* start base plugins page format
This commit is contained in:
Jordan Blasenhauer 2024-08-11 21:20:37 +02:00
parent 74f9f33976
commit 4c0bf3edc4
12 changed files with 493 additions and 2174 deletions

File diff suppressed because it is too large Load diff

View file

@ -3,6 +3,7 @@
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 { useEqualStr } from "@utils/global.js";
/**
@ -62,6 +63,10 @@ const props = defineProps({
v-if="useEqualStr(widget.type, 'Instance')"
v-bind="widget.data"
/>
<Tabulator
v-else-if="useEqualStr(widget.type, 'Tabulator')"
v-bind="widget.data"
/>
</template>
</Grid>
</GridLayout>

View file

@ -57,7 +57,7 @@ const props = defineProps({
colMinWidth: {
type: Number,
required: false,
default: 100,
default: 150,
},
colMaxWidth: {
type: Number,
@ -101,7 +101,7 @@ const table = reactive({
reactiveData: true, //enable data reactivity
autoResize: true, // prevent auto resizing of table
resizableRows: true, // this option takes a boolean value (default = false)
layout: "fitDataFill",
layout: "fitColumns",
};
if (props.rowHeight) opts.rowHeight = props.rowHeight;

View file

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

View file

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

View file

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

View file

@ -1,7 +1,7 @@
from .utils.widgets import instance_widget
def instances_builder(instances: List[Instance]) -> str:
def instances_builder(instances) -> str:
"""
It returns the needed format from data to render the instances page in JSON format for the Vue.js builder
"""
@ -9,8 +9,8 @@ def instances_builder(instances: List[Instance]) -> str:
for instance in instances:
# setup actions buttons
actions = ["reload", "stop"] if instance.status == "up" else ["start"]
actions = ["reload", "stop"] if instance.status == "up" else ["start"]
buttons = [
{
"attrs": {

View file

@ -0,0 +1,82 @@
[
{
"type": "card",
"widgets": [
{
"type": "Tabulator",
"data": {
"id": "table-instances",
"columns": [
{ "title": "Name", "field": "name", "formatter": "text" },
{ "title": "Hostname", "field": "hostname", "formatter": "text" },
{ "title": "Type", "field": "type", "formatter": "text" },
{ "title": "Method", "field": "method", "formatter": "text" },
{
"title": "Creation date",
"field": "creation_date",
"formatter": "text"
},
{ "title": "Last seen", "field": "last_seen", "formatter": "text" },
{
"title": "Actions",
"field": "actions",
"formatter": "buttonGroup"
}
],
"items": [
{
"name": { "text": "Name" },
"hostname": { "text": "Hostname" },
"type": { "text": "Type" },
"method": { "text": "Method" },
"creation_date": { "text": "Creation date" },
"last_seen": { "text": "Last seen" }
}
],
"filters": [
{
"type": "like",
"fields": ["name", "hostname"],
"setting": {
"id": "input-search-host-name",
"name": "input-search-host-name",
"label": "Search (host)name",
"value": "",
"inpType": "input",
"columns": { "pc": 3, "tablet": 4, " mobile": 12 }
}
},
{
"type": "=",
"fields": ["type"],
"setting": {
"id": "select-type",
"name": "select-type",
"label": "Select type",
"value": "all",
"values": ["all", "type1", "type2"],
"inpType": "select",
"onlyDown": true,
"columns": { "pc": 3, "tablet": 4, " mobile": 12 }
}
},
{
"type": "=",
"fields": ["method"],
"setting": {
"id": "select-method",
"name": "select-method",
"label": "Select method",
"value": "all",
"values": ["all", "method1", "method2"],
"inpType": "select",
"onlyDown": true,
"columns": { "pc": 3, "tablet": 4, " mobile": 12 }
}
}
]
}
}
]
}
]

View file

@ -0,0 +1,209 @@
import json
import base64
from builder.utils.widgets import button, button_group, title, text, tabulator
columns = [
{"title": "Name", "field": "name", "formatter": "text"},
{"title": "Hostname", "field": "hostname", "formatter": "text"},
{"title": "Type", "field": "type", "formatter": "text"},
{"title": "Method", "field": "method", "formatter": "text"},
{"title": "Creation date", "field": "creation_date", "formatter": "text"},
{"title": "Last seen", "field": "last_seen", "formatter": "text"},
{
"title": "Actions",
"field": "actions",
"formatter": "buttonGroup",
},
]
# Because we are going to use built-in filters, we can't use the Filter component
# So we need this format in order to create under the hood fields that will be linked to the tabulator filter
# We need to pass on the setting key the same props as the Fields component. For example a "=" tabulator filter will be used with a select field, this one need "values" array to work.
# type : Choose between available tabulator built-in filters ("keywords", "like", "!=", ">", "<", ">=", "<=", "in", "regex", "!=")
filters = [
{
"type": "like",
"fields": ["name", "hostname"],
"setting": {
"id": "input-search-host-name",
"name": "input-search-host-name",
"label": "Search (host)name",
"value": "",
"inpType": "input",
"columns": {"pc": 3, "tablet": 4, " mobile": 12},
},
},
{
"type": "=",
"fields": ["type"],
"setting": {
"id": "select-type",
"name": "select-type",
"label": "Select type",
"value": "all",
"values": ["all", "type1", "type2"],
"inpType": "select",
"onlyDown": True,
"columns": {"pc": 3, "tablet": 4, " mobile": 12},
},
},
{
"type": "=",
"fields": ["method"],
"setting": {
"id": "select-method",
"name": "select-method",
"label": "Select method",
"value": "all",
"values": ["all", "method1", "method2"],
"inpType": "select",
"onlyDown": True,
"columns": {"pc": 3, "tablet": 4, " mobile": 12},
},
},
]
actions = (
{
"buttons": [
button(
id="ping-instance-INSTANCE_NAME",
text="action_ping",
color="success",
size="normal",
hideText=True,
iconName="globe",
iconColor="white",
modal={
"widgets": [
title(title="instances_ping_title"),
text(text="instances_ping_subtitle"),
text(bold=True, text="INSTANCE_NAME"),
button_group(
buttons=[
button(
id="close-ping-btn-INSTANCE_NAME",
text="action_close",
color="close",
size="normal",
attrs={"data-close-modal": ""},
)["data"],
button(
id="ping-btn-INSTANCE_NAME",
text="action_ping",
color="info",
size="normal",
attrs={"data-submit-form": '{"instance_name" : ", "instance_hostname" : "", "operation" : "ping" }'},
)["data"],
]
),
],
},
),
button(
id="delete-instance-INSTANCE_NAME",
text="action_delete",
color="success",
size="normal",
hideText=True,
iconName="globe",
iconColor="white",
modal={
"widgets": [
title(title="instances_delete_title"),
text(text="instances_delete_subtitle"),
text(bold=True, text="INSTANCE_NAME"),
button_group(
buttons=[
button(
id="close-delete-btn-INSTANCE_NAME",
text="action_close",
color="close",
size="normal",
attrs={"data-close-modal": ""},
)["data"],
button(
id="delete-btn-INSTANCE_NAME",
text="action_delete",
color="info",
size="normal",
attrs={"data-submit-form": '{"instance_name" : ", "instance_hostname" : "", "operation" : "delete" }'},
)["data"],
]
),
],
},
),
]
},
)
items = [
{
"name": text(text="Name")["data"],
"hostname": text(text="Hostname")["data"],
"type": text(text="Type")["data"],
"method": text(text="Method")["data"],
"creation_date": text(text="Creation date")["data"],
"last_seen": text(text="Last seen")["data"],
"actions": actions,
},
]
instance_create_form = {}
builder = [
{
"type": "card",
"display": ["main", 1],
"widgets": [
tabulator(
id="table-instances",
columns=columns,
items=items,
filters=filters,
)
],
},
{
"type": "card",
"display": ["main", 2],
"widgets": [
input(
id="instance-name",
name="instance-name",
label="instances_name",
value="",
columns={"pc": 3, "tablet": 4, " mobile": 12},
),
input(
id="instance-hostname",
name="instance-hostname",
label="instances_hostname",
value="",
columns={"pc": 3, "tablet": 4, " mobile": 12},
),
button(
id="create-instance",
text="action_create",
color="success",
size="normal",
),
],
},
]
with open("instances2.json", "w") as f:
f.write(json.dumps(builder))
output_base64_bytes = base64.b64encode(bytes(json.dumps(builder), "utf-8"))
output_base64_string = output_base64_bytes.decode("ascii")
with open("instances2.txt", "w") as f:
f.write(output_base64_string)

View file

@ -0,0 +1 @@
W3sidHlwZSI6ICJjYXJkIiwgIndpZGdldHMiOiBbeyJ0eXBlIjogIlRhYnVsYXRvciIsICJkYXRhIjogeyJpZCI6ICJ0YWJsZS1pbnN0YW5jZXMiLCAiY29sdW1ucyI6IFt7InRpdGxlIjogIk5hbWUiLCAiZmllbGQiOiAibmFtZSIsICJmb3JtYXR0ZXIiOiAidGV4dCJ9LCB7InRpdGxlIjogIkhvc3RuYW1lIiwgImZpZWxkIjogImhvc3RuYW1lIiwgImZvcm1hdHRlciI6ICJ0ZXh0In0sIHsidGl0bGUiOiAiVHlwZSIsICJmaWVsZCI6ICJ0eXBlIiwgImZvcm1hdHRlciI6ICJ0ZXh0In0sIHsidGl0bGUiOiAiTWV0aG9kIiwgImZpZWxkIjogIm1ldGhvZCIsICJmb3JtYXR0ZXIiOiAidGV4dCJ9LCB7InRpdGxlIjogIkNyZWF0aW9uIGRhdGUiLCAiZmllbGQiOiAiY3JlYXRpb25fZGF0ZSIsICJmb3JtYXR0ZXIiOiAidGV4dCJ9LCB7InRpdGxlIjogIkxhc3Qgc2VlbiIsICJmaWVsZCI6ICJsYXN0X3NlZW4iLCAiZm9ybWF0dGVyIjogInRleHQifSwgeyJ0aXRsZSI6ICJBY3Rpb25zIiwgImZpZWxkIjogImFjdGlvbnMiLCAiZm9ybWF0dGVyIjogImJ1dHRvbkdyb3VwIn1dLCAiaXRlbXMiOiBbeyJuYW1lIjogeyJ0ZXh0IjogIk5hbWUifSwgImhvc3RuYW1lIjogeyJ0ZXh0IjogIkhvc3RuYW1lIn0sICJ0eXBlIjogeyJ0ZXh0IjogIlR5cGUifSwgIm1ldGhvZCI6IHsidGV4dCI6ICJNZXRob2QifSwgImNyZWF0aW9uX2RhdGUiOiB7InRleHQiOiAiQ3JlYXRpb24gZGF0ZSJ9LCAibGFzdF9zZWVuIjogeyJ0ZXh0IjogIkxhc3Qgc2VlbiJ9fV0sICJmaWx0ZXJzIjogW3sidHlwZSI6ICJsaWtlIiwgImZpZWxkcyI6IFsibmFtZSIsICJob3N0bmFtZSJdLCAic2V0dGluZyI6IHsiaWQiOiAiaW5wdXQtc2VhcmNoLWhvc3QtbmFtZSIsICJuYW1lIjogImlucHV0LXNlYXJjaC1ob3N0LW5hbWUiLCAibGFiZWwiOiAiU2VhcmNoIChob3N0KW5hbWUiLCAidmFsdWUiOiAiIiwgImlucFR5cGUiOiAiaW5wdXQiLCAiY29sdW1ucyI6IHsicGMiOiAzLCAidGFibGV0IjogNCwgIiBtb2JpbGUiOiAxMn19fSwgeyJ0eXBlIjogIj0iLCAiZmllbGRzIjogWyJ0eXBlIl0sICJzZXR0aW5nIjogeyJpZCI6ICJzZWxlY3QtdHlwZSIsICJuYW1lIjogInNlbGVjdC10eXBlIiwgImxhYmVsIjogIlNlbGVjdCB0eXBlIiwgInZhbHVlIjogImFsbCIsICJ2YWx1ZXMiOiBbImFsbCIsICJ0eXBlMSIsICJ0eXBlMiJdLCAiaW5wVHlwZSI6ICJzZWxlY3QiLCAib25seURvd24iOiB0cnVlLCAiY29sdW1ucyI6IHsicGMiOiAzLCAidGFibGV0IjogNCwgIiBtb2JpbGUiOiAxMn19fSwgeyJ0eXBlIjogIj0iLCAiZmllbGRzIjogWyJtZXRob2QiXSwgInNldHRpbmciOiB7ImlkIjogInNlbGVjdC1tZXRob2QiLCAibmFtZSI6ICJzZWxlY3QtbWV0aG9kIiwgImxhYmVsIjogIlNlbGVjdCBtZXRob2QiLCAidmFsdWUiOiAiYWxsIiwgInZhbHVlcyI6IFsiYWxsIiwgIm1ldGhvZDEiLCAibWV0aG9kMiJdLCAiaW5wVHlwZSI6ICJzZWxlY3QiLCAib25seURvd24iOiB0cnVlLCAiY29sdW1ucyI6IHsicGMiOiAzLCAidGFibGV0IjogNCwgIiBtb2JpbGUiOiAxMn19fV19fV19XQ==

View file

@ -0,0 +1,91 @@
import json
import base64
from builder.utils.widgets import button, button_group, title, text, tabulator
core_columns = [
{"title": "Name", "field": "name", "formatter": "text"},
{"title": "Description", "field": "description", "formatter": "text"},
{"title": "Page", "field": "type", "formatter": "buttonGroup"},
]
# Because we are going to use built-in filters, we can't use the Filter component
# So we need this format in order to create under the hood fields that will be linked to the tabulator filter
# We need to pass on the setting key the same props as the Fields component. For example a "=" tabulator filter will be used with a select field, this one need "values" array to work.
# type : Choose between available tabulator built-in filters ("keywords", "like", "!=", ">", "<", ">=", "<=", "in", "regex", "!=")
core_filters = [
{
"type": "like",
"fields": ["name"],
"setting": {
"id": "input-search-core_name",
"name": "input-search-core_name",
"label": "Search name",
"value": "",
"inpType": "input",
"columns": {"pc": 3, "tablet": 4, " mobile": 12},
},
},
{
"type": "=",
"fields": ["page"],
"setting": {
"id": "select-core-page",
"name": "select-core-page",
"label": "Select core-page",
"value": "all",
"values": ["all", "plugin page", "no plugin page"],
"inpType": "select",
"onlyDown": True,
"columns": {"pc": 3, "tablet": 4, " mobile": 12},
},
},
]
core_items = [
{
"name": text(text="Name")["data"],
"description": text(text="Description")["data"],
"page": button_group(
buttons=[
button(
id="create-instance",
text="action_create",
color="success",
size="normal",
)["data"]
]
),
},
]
instance_create_form = {}
builder = [
{
"type": "card",
"display": ["main", 1],
"widgets": [
tabulator(
id="table-instances",
columns=core_columns,
items=core_items,
filters=core_filters,
)
],
},
]
with open("instances2.json", "w") as f:
f.write(json.dumps(builder))
output_base64_bytes = base64.b64encode(bytes(json.dumps(builder), "utf-8"))
output_base64_string = output_base64_bytes.decode("ascii")
with open("instances2.txt", "w") as f:
f.write(output_base64_string)

View file

@ -7,7 +7,7 @@ from typing import List
from shutil import rmtree
from re import search, sub
from typing import Union
from time import sleep
from utils import run_command
# We want to get path of the folder where our components are