mirror of
https://github.com/bunkerity/bunkerweb
synced 2026-05-24 09:28:37 +00:00
enhance build + add instances vue.js page
* remove previous useless assets for every build * reproduce instances data to easily test it on Vite * add instances page to build * update instances builder to fit new components : list pairs and form data * form submit working on instances actions
This commit is contained in:
parent
0c3b66899f
commit
a3514d2bb2
34 changed files with 161 additions and 411 deletions
|
|
@ -97,7 +97,7 @@ async function setBuildTempToUI() {
|
|||
fs.readdir(resolve("./templates"), (err, files) => {
|
||||
// Read content
|
||||
files.forEach((file) => {
|
||||
const data = fs.readFile(
|
||||
fs.readFile(
|
||||
resolve(`./templates/${file}`),
|
||||
{
|
||||
encoding: "utf8",
|
||||
|
|
@ -109,7 +109,8 @@ async function setBuildTempToUI() {
|
|||
}
|
||||
let updateData = data;
|
||||
// I want to remove the first "/" for href="/css", href="/js", href="/img", href="/favicon", src="/assets" or src="/js"
|
||||
const regexPaths = /href="\/(css|js|img|favicon)|src="\/(assets|js)/g;
|
||||
const regexPaths =
|
||||
/href="\/(css|js|img|favicon|assets|js)|src="\/(assets|js)/g;
|
||||
updateData = data.replace(regexPaths, (match) => {
|
||||
return match.replace("/", "");
|
||||
});
|
||||
|
|
@ -163,8 +164,17 @@ async function moveBuildStaticToUI() {
|
|||
});
|
||||
}
|
||||
|
||||
async function delPrevDirs() {
|
||||
// Delete prev existing dir
|
||||
delElRecursive(`${appStaticDir}/css`);
|
||||
delElRecursive(`${appStaticDir}/assets`);
|
||||
delElRecursive(`${appStaticDir}/flags`);
|
||||
delElRecursive(`${appStaticDir}/img`);
|
||||
}
|
||||
|
||||
async function build() {
|
||||
// Build client and setup
|
||||
await delPrevDirs();
|
||||
await buildVite();
|
||||
await updateClientDir();
|
||||
await setBuildTempToUI();
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
stats = [
|
||||
import json
|
||||
|
||||
home = [
|
||||
{
|
||||
"type": "card",
|
||||
"link": "https://panel.bunkerweb.io/?utm_campaign=self&utm_source=ui#pro",
|
||||
|
|
@ -85,3 +87,7 @@ stats = [
|
|||
],
|
||||
},
|
||||
]
|
||||
|
||||
# store on a file
|
||||
with open("home.json", "w") as f:
|
||||
json.dump(home, f, indent=4)
|
||||
|
|
|
|||
1
src/client/tests/instances.json
Normal file
1
src/client/tests/instances.json
Normal file
|
|
@ -0,0 +1 @@
|
|||
[{"type": "card", "containerColumns": {"pc": 6, "tablet": 6, "mobile": 12}, "widgets": [{"type": "Instance", "data": {"pairs": [{"key": "instances_hostname", "value": "bunkerweb"}, {"key": "instances_type", "value": "manual"}, {"key": "instances_status", "value": "instances_active"}], "status": "success", "title": "bunkerweb", "buttons": [{"attrs": {"data-submit-form": "{\"INSTANCE_ID\" : \"bunkerweb\", \"operation\" : \"reload\" }"}, "text": "action_reload", "color": "warning"}, {"attrs": {"data-submit-form": "{\"INSTANCE_ID\" : \"bunkerweb\", \"operation\" : \"stop\" }"}, "text": "action_stop", "color": "error"}]}}]}, {"type": "card", "containerColumns": {"pc": 6, "tablet": 6, "mobile": 12}, "widgets": [{"type": "Instance", "data": {"pairs": [{"key": "instances_hostname", "value": "bunkerweb"}, {"key": "instances_type", "value": "manual"}, {"key": "instances_status", "value": "instances_active"}], "status": "success", "title": "bunkerweb", "buttons": [{"attrs": {"data-submit-form": "{\"INSTANCE_ID\" : \"bunkerweb\", \"operation\" : \"reload\" }"}, "text": "action_reload", "color": "warning"}, {"attrs": {"data-submit-form": "{\"INSTANCE_ID\" : \"bunkerweb\", \"operation\" : \"stop\" }"}, "text": "action_stop", "color": "error"}]}}]}]
|
||||
77
src/client/tests/instances.py
Normal file
77
src/client/tests/instances.py
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
import json
|
||||
|
||||
|
||||
# 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"),
|
||||
]
|
||||
|
||||
|
||||
def instances_builder(instances: list):
|
||||
"""
|
||||
It returns the home page in JSON format for the Vue.js builder
|
||||
"""
|
||||
builder = []
|
||||
|
||||
for instance in instances:
|
||||
# setup actions buttons
|
||||
actions = (
|
||||
["restart", "stop"]
|
||||
if instance._type == "local" and instance.health
|
||||
else (
|
||||
["reload", "stop"]
|
||||
if not instance._type == "local" and instance.health
|
||||
else ["start"] if instance._type == "local" and not instance.health else []
|
||||
)
|
||||
)
|
||||
buttons = [
|
||||
{
|
||||
"attrs": {
|
||||
"data-submit-form": f"""{{"INSTANCE_ID" : "{instance._id}", "operation" : "{action}" }}""",
|
||||
},
|
||||
"text": f"action_{action}",
|
||||
"color": "success" if action == "start" else "error" if action == "stop" else "warning",
|
||||
}
|
||||
for action in actions
|
||||
]
|
||||
|
||||
component = {
|
||||
"type": "card",
|
||||
"containerColumns": {"pc": 6, "tablet": 6, "mobile": 12},
|
||||
"widgets": [
|
||||
{
|
||||
"type": "Instance",
|
||||
"data": {
|
||||
"pairs": [
|
||||
{"key": "instances_hostname", "value": instance.hostname},
|
||||
{"key": "instances_type", "value": instance._type},
|
||||
{"key": "instances_status", "value": "instances_active" if instance.health else "instances_inactive"},
|
||||
],
|
||||
"status": "success" if instance.health else "error",
|
||||
"title": instance.name,
|
||||
"buttons": buttons,
|
||||
},
|
||||
}
|
||||
],
|
||||
}
|
||||
|
||||
builder.append(component)
|
||||
|
||||
return builder
|
||||
|
||||
|
||||
builder = instances_builder(instances)
|
||||
|
||||
# store on a file
|
||||
with open("instances.json", "w") as f:
|
||||
json.dump(builder, f)
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
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='[{"type":"card","containerColumns":{"pc":6,"tablet":6,"mobile":12},"widgets":[{"type":"Instance","data":{"pairs":[{"key":"instances_hostname","value":"bunkerweb"},{"key":"instances_type","value":"manual"},{"key":"instances_status","value":"instances_active"}],"status":"success","title":"bunkerweb","buttons":[{"attrs":{"data-submit-form": {"operation" : "reload", "INSTANCE_ID" : "bunkerweb"} },"text":"action_reload","color":"warning","size":"normal"},{"attrs":{"data-submit-form": { "operation" : "stop", "INSTANCE_ID" : "bunkerweb"} },"text":"action_stop","color":"error","size":"normal"}]}}]}]'>
|
||||
data-server-builder='[{"type": "card", "containerColumns": {"pc": 6, "tablet": 6, "mobile": 12}, "widgets": [{"type": "Instance", "data": {"pairs": [{"key": "instances_hostname", "value": "bunkerweb"}, {"key": "instances_type", "value": "manual"}, {"key": "instances_status", "value": "instances_active"}], "status": "success", "title": "bunkerweb", "buttons": [{"attrs": {"data-submit-form": "{\"INSTANCE_ID\" : \"bunkerweb\", \"operation\" : \"reload\" }"}, "text": "action_reload", "color": "warning"}, {"attrs": {"data-submit-form": "{\"INSTANCE_ID\" : \"bunkerweb\", \"operation\" : \"stop\" }"}, "text": "action_stop", "color": "error"}]}}]}, {"type": "card", "containerColumns": {"pc": 6, "tablet": 6, "mobile": 12}, "widgets": [{"type": "Instance", "data": {"pairs": [{"key": "instances_hostname", "value": "bunkerweb"}, {"key": "instances_type", "value": "manual"}, {"key": "instances_status", "value": "instances_active"}], "status": "success", "title": "bunkerweb", "buttons": [{"attrs": {"data-submit-form": "{\"INSTANCE_ID\" : \"bunkerweb\", \"operation\" : \"reload\" }"}, "text": "action_reload", "color": "warning"}, {"attrs": {"data-submit-form": "{\"INSTANCE_ID\" : \"bunkerweb\", \"operation\" : \"stop\" }"}, "text": "action_stop", "color": "error"}]}}]}]'>
|
||||
</div>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="instances.js"></script>
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ function useSubmitForm(data) {
|
|||
input.value = data[key];
|
||||
form.appendChild(input);
|
||||
}
|
||||
// Append the form to the body and submit it
|
||||
// Append to be able to submit
|
||||
document.querySelector("body").appendChild(form);
|
||||
form.submit();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ export default defineConfig({
|
|||
rollupOptions: {
|
||||
input: {
|
||||
home: resolve(__dirname, "./src/pages/home/index.html"),
|
||||
instances: resolve(__dirname, "./src/pages/instances/index.html"),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1043,10 +1043,11 @@ def instances_builder(instances: list):
|
|||
)
|
||||
buttons = [
|
||||
{
|
||||
"attrs": {"data-form-INSTANCE_ID": instance._id, "data-form-operation": action, "data-submit-form": "true"},
|
||||
"attrs": {
|
||||
"data-submit-form": f"""{{"INSTANCE_ID" : "{instance._id}", "operation" : "{action}" }}""",
|
||||
},
|
||||
"text": f"action_{action}",
|
||||
"color": "success" if action == "start" else "error" if action == "stop" else "warning",
|
||||
"size": "normal",
|
||||
}
|
||||
for action in actions
|
||||
]
|
||||
|
|
@ -1058,7 +1059,7 @@ def instances_builder(instances: list):
|
|||
{
|
||||
"type": "Instance",
|
||||
"data": {
|
||||
"details": [
|
||||
"pairs": [
|
||||
{"key": "instances_hostname", "value": instance.hostname},
|
||||
{"key": "instances_type", "value": instance._type},
|
||||
{"key": "instances_status", "value": "instances_active" if instance.health else "instances_inactive"},
|
||||
|
|
@ -1116,8 +1117,9 @@ def instances():
|
|||
|
||||
# Display instances
|
||||
instances = app.config["INSTANCES"].get_instances()
|
||||
|
||||
data_server_builder = instances_builder(instances)
|
||||
return render_template("instances.html", title="Instances", data_server_builder=data_server_builder, instances=instances, username=current_user.get_id())
|
||||
return render_template("instances.html", title="Instances", data_server_builder=json.dumps(data_server_builder))
|
||||
|
||||
|
||||
@app.route("/services", methods=["GET", "POST"])
|
||||
|
|
|
|||
25
src/ui/static/assets/Title-9ae7a316.js
Normal file
25
src/ui/static/assets/Title-9ae7a316.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
src/ui/static/assets/home-ef55bffd.js
Normal file
1
src/ui/static/assets/home-ef55bffd.js
Normal file
|
|
@ -0,0 +1 @@
|
|||
import{c as v,r as q,a as _,o as x,b as a,d as u,w as n,e as b,t as m,n as S,f as y,g as o,h as d,m as p,i as $,_ as h,F as f,j as N,k as g,l as B,p as E,q as k,s as A,u as V,v as j,x as z,y as I,z as L,A as O,B as P}from"./Title-9ae7a316.js";const w={__name:"Subtitle",props:{subtitle:{type:String,required:!0},type:{type:String,required:!1,default:"card"},tag:{type:String,required:!1,default:""},color:{type:String,required:!1,default:""},bold:{type:Boolean,required:!1,default:!1},uppercase:{type:Boolean,required:!1,default:!1},subtitleClass:{type:String,required:!1,default:""}},setup(i){const e=i,s=v(()=>e.tag?e.tag:"p"),r=q({class:""}),t=_(null);return x(()=>{r.class=e.subtitleClass||t.value.closest("[data-is]")?`subtitle-${t.value.closest("[data-is]").getAttribute("data-is")}`:"subtitle-card"}),(l,c)=>e.subtitle?(a(),u(y(s.value),{key:0,ref_key:"subtitleEl",ref:t,"data-subtitle":"",class:S([r.class,e.color,"text-el",e.bold?"bold":"",e.uppercase?"uppercase":""])},{default:n(()=>[b(m(l.$t(e.subtitle,l.$t("dashboard_placeholder",e.subtitle))),1)]),_:1},8,["class"])):o("",!0)}},D={key:1,class:S(["flex justify-center items-center"])},F={__name:"Text",props:{text:{type:[String,Number],required:!0},textClass:{type:String,required:!1,default:""},color:{type:String,required:!1,default:""},bold:{type:Boolean,required:!1,default:!1},uppercase:{type:Boolean,required:!1,default:!1},tag:{type:String,required:!1,default:"p"},icon:{type:[Boolean,Object],required:!1,default:!1},attrs:{type:Object,required:!1,default:{}}},setup(i){const e=i,s=q({class:""}),r=_(null),t=_(null);return x(()=>{const l=r.value||t.value||null,c=l.closest('[data-is="void"]')?"void":"";s.class=e.textClass||l.closest("[data-is]")?`text-${c||l.closest("[data-is]").getAttribute("data-is")}`:"text-card"}),(l,c)=>(a(),d(f,null,[e.icon?o("",!0):(a(),u(y(e.tag),p({key:0},e.attrs,{ref_key:"textEl",ref:r,class:[s.class,e.color,"text-el",e.bold?"bold":"",e.uppercase?"uppercase":""]}),{default:n(()=>[b(m(l.$t(e.text,l.$t("dashboard_placeholder",e.text))),1)]),_:1},16,["class"])),e.icon?(a(),d("div",D,[e.icon?(a(),u(h,$(p({key:0},e.icon)),null,16)):o("",!0),(a(),u(y(e.tag),p({ref_key:"textIconEl",ref:t},e.attrs,{class:[s.class,e.color,"text-el","ml-2"]}),{default:n(()=>[b(m(l.$t(e.text,l.$t("dashboard_placeholder",e.text))),1)]),_:1},16,["class"]))])):o("",!0)],64))}},H={__name:"Stat",props:{title:{type:String,required:!0},stat:{type:[String,Number],required:!0},subtitle:{type:String,required:!1,default:""},iconName:{type:String,required:!1,default:""},color:{type:String,required:!1,default:""},subtitleColor:{type:String,required:!1,default:"info"},statClass:{type:String,required:!1,default:""}},setup(i){const e=i;return(s,r)=>(a(),u(E,{"data-is":"stat",columns:{pc:12,tablet:12,mobile:12}},{default:n(()=>[N("div",{class:S(["stat-content-container",e.iconName?"is-icon":"no-icon"])},[g(B,{tag:"h3",title:e.title},null,8,["title"]),g(F,{text:e.stat},null,8,["text"]),e.subtitle?(a(),u(w,{key:0,subtitle:e.subtitle,color:e.subtitleColor},null,8,["subtitle","color"])):o("",!0)],2),e.iconName?(a(),u(h,{key:0,iconName:e.iconName,isStick:!0},null,8,["iconName"])):o("",!0)]),_:1}))}},M={__name:"Home",props:{builder:{type:Array,required:!0}},setup(i){const e=i;return(s,r)=>(a(!0),d(f,null,k(e.builder,(t,l)=>(a(),u(V,{key:l,gridLayoutClass:t.containerClass,type:t.type,title:t.title,link:t.link,columns:t.containerColumns,id:t.id},{default:n(()=>[g(A,null,{default:n(()=>[(a(!0),d(f,null,k(t.widgets,(c,C)=>(a(),d(f,{key:C},[c.type==="Stat"?(a(),u(H,$(p({key:0},c.data)),null,16)):o("",!0)],64))),128))]),_:2},1024)]),_:2},1032,["gridLayoutClass","type","title","link","columns","id"]))),128))}},T={__name:"Home",setup(i){const e=q({builder:""});return j(()=>{const s="data-server-builder",r=document.querySelector(`[${s}]`),t=r&&!r.getAttribute(s).includes(s)?JSON.parse(r.getAttribute(s)):{};e.builder=t}),x(()=>{z()}),(s,r)=>(a(),u(I,null,{default:n(()=>[e.builder?(a(),u(M,{key:0,builder:e.builder},null,8,["builder"])):o("",!0)]),_:1}))}},G=L();O(T).use(G).use(P(["dashboard","action","inp","icons","home"])).mount("#app");
|
||||
1
src/ui/static/assets/instances-67da6d8b.js
Normal file
1
src/ui/static/assets/instances-67da6d8b.js
Normal file
|
|
@ -0,0 +1 @@
|
|||
import{r as h,c as $,v as k,C as v,b as r,h as n,j as _,n as p,t as g,F as d,q as m,g as b,a as S,o as q,d as i,m as C,D as A,w as f,k as c,l as B,p as E,s as w,i as I,u as N,x as P,y as D,z as F,A as L,B as O}from"./Title-9ae7a316.js";const x=["aria-labelledby"],z=["id"],V={__name:"Status",props:{id:{type:String,required:!1,default:""},status:{type:String,required:!0,default:"info"},statusClass:{type:String,required:!1,default:""}},setup(a){const t=a,s=h({id:""}),e=$(()=>{if(t.status==="success")return"dashboard_status_success";if(t.status==="error")return"dashboard_status_error";if(t.status==="warning")return"dashboard_status_warning";if(t.status==="info")return"dashboard_status_info"});return k(()=>{s.id=v(t.id)}),(u,l)=>(r(),n("div",{class:p([t.statusClass,"status-svg-container"])},[_("div",{role:"img","aria-labelledby":`status-${s.id}`,class:p([t.status,"status-icon"])},null,10,x),_("p",{id:`status-${s.id}`,class:"sr-only"},g(u.$t(e.value)),9,z)],2))}},j={key:0,"data-is":"list-pairs",class:p(["list-pairs-container"])},G={class:"list-pairs-title"},J={class:"list-pairs-subtitle"},M={__name:"Pairs",props:{pairs:{type:Array,required:!0},columns:{type:Object,required:!1,default:{pc:12,tablet:12,mobile:12}}},setup(a){const t=a,s=$(()=>`col-span-${t.columns.mobile} md:col-span-${t.columns.tablet} lg:col-span-${t.columns.pc}`);return(e,u)=>t.pairs?(r(),n("ul",j,[(r(!0),n(d,null,m(t.pairs,l=>(r(),n("li",{class:p(["list-pairs-item",s.value])},[_("span",G,g(e.$t(l.key,e.$t("dashboard_placeholder",l.key))),1),_("span",J,g(e.$t(l.value,e.$t("dashboard_placeholder",l.value))),1)],2))),256))])):b("",!0)}},T={__name:"ButtonGroup",props:{buttons:{type:Array,required:!0,default:[]},groupClass:{type:String,required:!1,default:""}},setup(a){const t=a,s=h({class:""}),e=S(null);return q(()=>{s.class=t.groupClass||e.value.closest("[data-is]")?`button-group-${e.value.closest("[data-is]").getAttribute("data-is")}`:"button-group-default"}),(u,l)=>t.buttons.length>0?(r(),n("div",{key:0,ref_key:"groupEl",ref:e,class:p([s.class,t.groupClass])},[(r(!0),n(d,null,m(t.buttons,(o,y)=>(r(),i(A,C({key:o},o,{class:[y===t.buttons.length-1?"":"mr-2"]}),null,16,["class"]))),128))],2)):b("",!0)}},U={__name:"Instance",props:{title:{type:String,required:!0},status:{type:String,required:!0,default:""},pairs:{type:Array,required:!0,default:[]},buttons:{type:Array,required:!0,default:[]}},setup(a){const t=a;return(s,e)=>(r(),i(E,{"data-is":"instance",columns:{pc:12,tablet:12,mobile:12}},{default:f(()=>[c(V,{id:t.title,status:t.status},null,8,["id","status"]),c(B,{type:"card",title:t.title},null,8,["title"]),c(M,{pairs:t.pairs},null,8,["pairs"]),c(T,{buttons:t.buttons},null,8,["buttons"])]),_:1}))}},H={__name:"Instances",props:{builder:{type:Array,required:!0}},setup(a){const t=a;return(s,e)=>(r(!0),n(d,null,m(t.builder,(u,l)=>(r(),i(N,{key:l,gridLayoutClass:u.containerClass,type:u.type,title:u.title,link:u.link,columns:u.containerColumns,id:u.id},{default:f(()=>[c(w,null,{default:f(()=>[(r(!0),n(d,null,m(u.widgets,(o,y)=>(r(),n(d,{key:y},[o.type==="Instance"?(r(),i(U,I(C({key:0},o.data)),null,16)):b("",!0)],64))),128))]),_:2},1024)]),_:2},1032,["gridLayoutClass","type","title","link","columns","id"]))),128))}};function K(){window.addEventListener("click",a=>{if(a.target.hasAttribute("data-submit-form"))try{const t=JSON.parse(a.target.getAttribute("data-submit-form"));Q(t)}catch(t){console.log(t)}})}function Q(a){const t=document.createElement("form");t.style.display="none",t.method="POST";try{const s=document.querySelector("[data-csrf-token]");s&&(a.csrf_token=s.getAttribute("data-csrf-token"))}catch{}for(const s in a){const e=document.createElement("input");e.type="hidden",e.name=s,e.value=a[s],t.appendChild(e)}document.querySelector("body").appendChild(t),t.submit()}const R={__name:"Instances",setup(a){const t=h({builder:""});return k(()=>{const s="data-server-builder",e=document.querySelector(`[${s}]`),u=e&&!e.getAttribute(s).includes(s)?JSON.parse(e.getAttribute(s)):{};t.builder=u}),q(()=>{P(),K()}),(s,e)=>(r(),i(D,null,{default:f(()=>[t.builder?(r(),i(H,{key:0,builder:t.builder},null,8,["builder"])):b("",!0)]),_:1}))}},W=F();L(R).use(W).use(O(["dashboard","action","inp","icons","instances"])).mount("#app");
|
||||
File diff suppressed because one or more lines are too long
Binary file not shown.
|
Before Width: | Height: | Size: 48 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 53 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 9.5 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 4.5 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 4.7 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 1.2 KiB |
3
src/ui/templates/home.html
vendored
3
src/ui/templates/home.html
vendored
|
|
@ -7,7 +7,8 @@
|
|||
<link rel="stylesheet" href="css/flag-icons.min.css" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>BunkerWeb | DASHBOARD</title>
|
||||
<script nonce="{{ script_nonce }}" type="module" crossorigin src="assets/home-7b366ea2.js"></script>
|
||||
<script nonce="{{ script_nonce }}" type="module" crossorigin src="assets/home-ef55bffd.js"></script>
|
||||
<link rel="modulepreload" crossorigin href="assets/Title-9ae7a316.js">
|
||||
</head>
|
||||
<body>
|
||||
<div class="hidden" data-csrf-token="{{ csrf_token() }}"></div>
|
||||
|
|
|
|||
98
src/ui/templates/instances.html
vendored
98
src/ui/templates/instances.html
vendored
|
|
@ -1,74 +1,24 @@
|
|||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
{% set attribute_name = "instances" %}
|
||||
{% if instances|length == 0 %}
|
||||
<div class="col-span-12 sm:col-span-4 sm:col-start-5">
|
||||
<div class="text-center relative w-full p-4 text-white bg-blue-500 rounded-lg">No instance to show</div>
|
||||
</div>
|
||||
{% else %}
|
||||
{% for instances_batched in instances|batch(2) %}
|
||||
{% for instance in
|
||||
instances_batched %}
|
||||
<!-- instance card -->
|
||||
<div class="overflow-hidden max-h-none sm:max-h- hover:scale-102 transition col-span-12 lg:col-span-6 3xl:col-span-4 flex p-4 justify-between w-full shadow-md break-words bg-white dark:bg-slate-850 dark:brightness-110 dark:shadow-dark-xl rounded-2xl bg-clip-border">
|
||||
<form class="w-full" id="form-instance-{{ instance._id }}" method="POST">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
|
||||
<input type="hidden" name="INSTANCE_ID" value="{{ instance._id }}" />
|
||||
<!-- state and title-->
|
||||
<div class="flex justify-start items-start overflow-hidden">
|
||||
{% if instance.health %}<div class="min-w-4 mr-2 mt-2 h-4 w-4 rounded-full bg-green-500"></div>{% endif %}
|
||||
{% if not instance.health %}<div class="min-w-4 mr-2 mt-2 h-4 w-4 rounded-full bg-red-500"></div>{% endif %}
|
||||
<h5 class="break-words font-bold dark:text-white/90 transition duration-300 ease-in-out">{{ instance.name }}</h5>
|
||||
</div>
|
||||
<!-- end state and title-->
|
||||
<!-- detail list -->
|
||||
<div role="grid" class="card-detail-container">
|
||||
{% set instance_details = [{"name" : "TYPE", "value" : instance['_type']},{"name" : "HOSTNAME", "value" : instance['hostname']}] %}
|
||||
<!-- detail -->
|
||||
{% for detail in instance_details %}
|
||||
<div role="row" class="card-detail-item">
|
||||
<p role="gridcell" class="card-detail-item-title">{{ detail['name'] }}</p>
|
||||
<p role="gridcell" class="card-detail-item-subtitle">{{ detail['value'] }}</p>
|
||||
</div>
|
||||
{% endfor %}
|
||||
<!-- end detail -->
|
||||
</div>
|
||||
<!-- end detail list-->
|
||||
<!-- button list-->
|
||||
<div class="relative w-full flex justify-center sm:justify-end">
|
||||
{% if instance._type == "local" and instance.health %}
|
||||
<button type="submit"
|
||||
name="operation"
|
||||
value="restart"
|
||||
class="edit-btn mx-1 text-xs">Restart</button>
|
||||
<button type="submit"
|
||||
name="operation"
|
||||
value="stop"
|
||||
class="delete-btn mx-1 text-xs">Stop</button>
|
||||
{% endif %}
|
||||
{% if not instance._type == "local" and instance.health %}
|
||||
<button type="submit"
|
||||
name="operation"
|
||||
value="reload"
|
||||
class="edit-btn mx-1 text-xs">Reload</button>
|
||||
<button type="submit"
|
||||
name="operation"
|
||||
value="stop"
|
||||
class="delete-btn mx-1 text-xs">Stop</button>
|
||||
{% endif %}
|
||||
{% if instance._type == "local" and not instance.health or not
|
||||
instance._type == "local" and not instance.health %}
|
||||
<button type="submit"
|
||||
name="operation"
|
||||
value="start"
|
||||
class="valid-btn mx-1 text-xs">Start</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
<!-- end button list-->
|
||||
</form>
|
||||
</div>
|
||||
<!-- end instance card -->
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endblock content %}
|
||||
<!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 | DASHBOARD</title>
|
||||
<script nonce="{{ script_nonce }}" type="module" crossorigin src="assets/instances-67da6d8b.js"></script>
|
||||
<link rel="modulepreload" crossorigin href="assets/Title-9ae7a316.js">
|
||||
</head>
|
||||
<body>
|
||||
<div class="hidden" data-csrf-token="{{ csrf_token() }}"></div>
|
||||
|
||||
<div class="hidden" data-server-global="{{data_server_global if data_server_global else {}}}"></div>
|
||||
|
||||
<div class="hidden" data-server-flash="{{data_server_flash if data_server_flash else []}}"></div>
|
||||
|
||||
<div class="hidden" data-server-builder="{{data_server_builder}}"></div>
|
||||
|
||||
<div id="app"></div>
|
||||
</body>
|
||||
</html>
|
||||
2
src/ui/templates/loading.html
vendored
2
src/ui/templates/loading.html
vendored
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue