diff --git a/admin_panel/api/servers.py b/admin_panel/api/servers.py
index c145c1b..9068546 100644
--- a/admin_panel/api/servers.py
+++ b/admin_panel/api/servers.py
@@ -344,6 +344,20 @@ def get_setup_status():
timeout=5,
)
status["distrobuilder_installed"] = result.returncode == 0
+
+ if status["distrobuilder_installed"]:
+ # Get version
+ try:
+ ver_result = subprocess.run(
+ ["distrobuilder", "version"],
+ capture_output=True,
+ text=True,
+ timeout=5,
+ )
+ if ver_result.returncode == 0:
+ status["distrobuilder_version"] = ver_result.stdout.strip()
+ except Exception:
+ pass
except Exception:
pass
@@ -351,18 +365,15 @@ def get_setup_status():
@frappe.whitelist()
-def run_setup(doas_password):
+def run_setup(doas_password=None):
"""Run setup commands to install distrobuilder."""
_check_admin_permission()
- if not doas_password:
- return {"success": False, "error": "Password is required"}
-
logs = []
logs.append("=== Starting Distrobuilder Setup ===")
commands = [
- (["doas", "-S", "apk", "add", "distrobuilder"], "Installing distrobuilder"),
+ (["doas", "apk", "add", "distrobuilder"], "Installing distrobuilder"),
]
for cmd, description in commands:
@@ -370,7 +381,6 @@ def run_setup(doas_password):
try:
result = subprocess.run(
cmd,
- input=f"{doas_password}\n",
capture_output=True,
text=True,
timeout=120,
diff --git a/admin_panel/public/frontend/assets/AppDetail-d8b34acc.js b/admin_panel/public/frontend/assets/AppDetail-6620138c.js
similarity index 97%
rename from admin_panel/public/frontend/assets/AppDetail-d8b34acc.js
rename to admin_panel/public/frontend/assets/AppDetail-6620138c.js
index 103b86a..82c008a 100644
--- a/admin_panel/public/frontend/assets/AppDetail-d8b34acc.js
+++ b/admin_panel/public/frontend/assets/AppDetail-6620138c.js
@@ -1,2 +1,2 @@
-import{a as ce,y as Q,n as L,z as X,o as i,c as r,d as l,g as n,b as t,e as o,p as $,q as M,t as d,h as O,f as pe,J as ve,i as q,r as u,m as D,k as p,F as g,j as v,S as me,E as Y,G as fe,D as F,H as Z}from"./index-96d8d3bd.js";import{_ as ge}from"./LayoutHeader-a0707290.js";import{_ as U}from"./StatCard-a71614ae.js";import{_ as xe}from"./EmptyState-060c0be5.js";const ye={class:"flex flex-col h-full"},_e={class:"flex items-center gap-3"},be={class:"flex items-center gap-3"},ke={class:"w-10 h-10 rounded-lg bg-blue-100 flex items-center justify-center"},he={class:"text-xl font-semibold text-ink-gray-9"},we={class:"text-sm text-ink-gray-5"},Ve={class:"flex-1 overflow-auto"},Ce={key:0,class:"flex items-center justify-center h-64"},$e={class:"border-b px-5"},De={class:"flex gap-2"},Se=["onClick"],Be={class:"p-5"},Ie={key:0,class:"space-y-6"},ze={class:"grid gap-4 sm:grid-cols-2 lg:grid-cols-4"},Ne={class:"rounded-lg border p-5"},Ee={class:"flex items-center justify-between mb-4"},Fe={class:"text-sm text-ink-gray-5"},Ue={key:1},Re={key:0,class:"rounded-lg border overflow-hidden"},je={class:"min-w-full divide-y"},Te={class:"divide-y"},Ae={class:"px-6 py-4"},Le={class:"text-sm font-medium text-ink-gray-9"},Me={class:"px-6 py-4 text-sm text-ink-gray-7 font-mono"},Oe={class:"px-6 py-4 text-sm text-ink-gray-7 font-mono"},qe={class:"px-6 py-4 text-sm text-ink-gray-7"},Ge={class:"px-6 py-4 text-sm text-ink-gray-7"},He={class:"px-6 py-4"},Je={class:"px-6 py-4"},We={key:2},Ke={class:"rounded-lg border overflow-hidden"},Pe={class:"flex items-center justify-between p-4 border-b"},Qe={class:"flex gap-2"},Xe={class:"p-4"},Ye={key:0,class:"bg-gray-900 text-gray-100 p-4 rounded-lg text-sm overflow-x-auto font-mono max-h-[600px] overflow-y-auto"},Ze={class:"space-y-4"},et={key:0,class:"mt-4"},tt={class:"bg-gray-900 text-gray-100 p-4 rounded-lg text-xs font-mono max-h-64 overflow-y-auto"},rt={__name:"AppDetail",setup(at){const x=ce(),b=u("overview"),k=u(!1),h=u(""),R=u(!1),S=u(!1),B=u(""),I=u("edge"),y=u(""),j=u(!1),m=u(null),w=u(!1),z=u(""),T=u(!1),A=u(null),ee=[{id:"overview",label:"Overview"},{id:"versions",label:"Versions"},{id:"configuration",label:"Configuration"}],f=Q({url:"admin_panel.api.apps.get_app_detail",params:{app_name:x.params.appId},auto:!0}),te=Q({url:"admin_panel.api.servers.get_image_servers",auto:!0}),c=L(()=>f.data),N=L(()=>te.data||[]),ae=L(()=>N.value.map(e=>({label:`${e.name}${e.status==="online"?"":" ("+e.status+")"}`,value:e.name})));X(N,a=>{a.length&&!y.value&&(y.value=a[0].name)},{immediate:!0}),X(()=>{var a;return(a=c.value)==null?void 0:a.description},a=>{z.value=a||""});function se(){f.reload()}function le(){var a;h.value=((a=c.value)==null?void 0:a.yaml_content)||"",k.value=!0}function oe(){k.value=!1,h.value=""}async function ne(){R.value=!0;try{const a=await D("admin_panel.api.apps.save_app_config",{app_name:x.params.appId,yaml_content:h.value});a.success?(console.log(a.message),k.value=!1,f.reload()):console.error(a.error||"Failed to save configuration")}catch(a){console.error(a.message||"Failed to save configuration")}finally{R.value=!1}}async function ie(){j.value=!0,m.value=null;try{const a=await D("admin_panel.api.apps.build_image",{app_name:x.params.appId,version:B.value,target_server:y.value,release:I.value||"edge"});m.value=a,a.success?(console.log(a.message),f.reload()):console.error(a.error||"Build failed")}catch(a){m.value={success:!1,error:a.message,logs:[`Error: ${a.message}`]},console.error(a.message||"Build failed")}finally{j.value=!1}}function re(){S.value=!1,m.value=null,B.value="",I.value="edge",y.value=N.value.length?N.value[0].name:""}async function ue(){T.value=!0;try{const a=await D("admin_panel.api.apps.update_app_meta",{app_name:x.params.appId,description:z.value});a.success?(console.log(a.message),w.value=!1,f.reload()):console.error(a.error||"Failed to update description")}catch(a){console.error(a.message||"Failed to update description")}finally{T.value=!1}}async function de(a){if(!a.fingerprint||a.fingerprint==="-"){console.error("Cannot delete: invalid fingerprint");return}A.value=a.fingerprint;try{const V=(await D("admin_panel.api.apps.get_app_versions",{app_name:x.params.appId})).find(E=>E.fingerprint.startsWith(a.fingerprint));if(!V){console.error("Version not found");return}const C=await D("admin_panel.api.apps.delete_image",{fingerprint:V.fingerprint});C.success?(console.log("Image deleted successfully"),f.reload()):console.error(C.error||"Failed to delete image")}catch(e){console.error(e.message||"Failed to delete image")}finally{A.value=null}}return(a,e)=>{var V,C,E,G,H,J,W,K,P;return i(),r("div",ye,[l(ge,null,{left:n(()=>{var s,_;return[t("div",_e,[l(o(p),{variant:"ghost",onClick:e[0]||(e[0]=st=>a.$router.push({name:"Apps"}))},{default:n(()=>[l(o(g),{name:"arrow-left",class:"h-4 w-4"})]),_:1}),t("div",be,[t("div",ke,[l(o(g),{name:"package",class:"h-5 w-5 text-blue-600"})]),t("div",null,[t("h1",he,d(((s=c.value)==null?void 0:s.name)||o(x).params.appId),1),t("p",we,d(((_=c.value)==null?void 0:_.currentVersion)||"-"),1)])])])]}),right:n(()=>[l(o(p),{variant:"subtle",onClick:se,loading:o(f).loading},{prefix:n(()=>[l(o(g),{name:"refresh-cw",class:"h-4 w-4"})]),default:n(()=>[e[11]||(e[11]=v(" Refresh ",-1))]),_:1},8,["loading"]),l(o(p),{variant:"solid",onClick:e[1]||(e[1]=s=>S.value=!0)},{prefix:n(()=>[l(o(g),{name:"play",class:"h-4 w-4"})]),default:n(()=>[e[12]||(e[12]=v(" Build Image ",-1))]),_:1})]),_:1}),t("div",Ve,[o(f).loading?(i(),r("div",Ce,[l(o(me),{class:"h-8 w-8"})])):(i(),r($,{key:1},[t("div",$e,[t("nav",De,[(i(),r($,null,M(ee,s=>t("button",{key:s.id,class:Y(["px-4 py-2 text-sm font-medium transition-colors",b.value===s.id?"border-b-2 border-ink-gray-9 text-ink-gray-9":"text-ink-gray-5 hover:text-ink-gray-7"]),onClick:_=>b.value=s.id},d(s.label),11,Se)),64))])]),t("div",Be,[b.value==="overview"?(i(),r("div",Ie,[t("div",ze,[l(U,{label:"Versions",value:((C=(V=c.value)==null?void 0:V.versions)==null?void 0:C.length)||0,iconName:"tag",color:"blue"},null,8,["value"]),l(U,{label:"Latest Version",value:((E=c.value)==null?void 0:E.currentVersion)||"-",iconName:"git-branch",color:"green"},null,8,["value"]),l(U,{label:"Size",value:((G=c.value)==null?void 0:G.size)||"-",iconName:"hard-drive",color:"purple"},null,8,["value"]),l(U,{label:"Status",value:((H=c.value)==null?void 0:H.status)||"-",iconName:"activity",color:"gray"},null,8,["value"])]),t("div",Ne,[t("div",Ee,[e[14]||(e[14]=t("h3",{class:"text-base font-medium text-ink-gray-9"}," Description ",-1)),l(o(p),{variant:"subtle",size:"sm",onClick:e[2]||(e[2]=s=>w.value=!0)},{prefix:n(()=>[l(o(g),{name:"edit-2",class:"h-4 w-4"})]),default:n(()=>[e[13]||(e[13]=v(" Edit ",-1))]),_:1})]),t("p",Fe,d(((J=c.value)==null?void 0:J.description)||"No description available"),1)])])):b.value==="versions"?(i(),r("div",Ue,[(K=(W=c.value)==null?void 0:W.versions)!=null&&K.length?(i(),r("div",Re,[t("table",je,[e[15]||(e[15]=t("thead",{class:"bg-surface-gray-2"},[t("tr",null,[t("th",{class:"px-6 py-3 text-left text-xs font-medium text-ink-gray-5 uppercase"},"Version"),t("th",{class:"px-6 py-3 text-left text-xs font-medium text-ink-gray-5 uppercase"},"Alias"),t("th",{class:"px-6 py-3 text-left text-xs font-medium text-ink-gray-5 uppercase"},"Fingerprint"),t("th",{class:"px-6 py-3 text-left text-xs font-medium text-ink-gray-5 uppercase"},"Created"),t("th",{class:"px-6 py-3 text-left text-xs font-medium text-ink-gray-5 uppercase"},"Size"),t("th",{class:"px-6 py-3 text-left text-xs font-medium text-ink-gray-5 uppercase"},"Status"),t("th",{class:"px-6 py-3 text-left text-xs font-medium text-ink-gray-5 uppercase"},"Actions")])],-1)),t("tbody",Te,[(i(!0),r($,null,M(c.value.versions,s=>(i(),r("tr",{key:s.version},[t("td",Ae,[t("span",Le,d(s.version),1)]),t("td",Me,d(s.alias),1),t("td",Oe,d(s.fingerprint),1),t("td",qe,d(s.released),1),t("td",Ge,d(s.size),1),t("td",He,[l(o(fe),{variant:{current:"success",active:"info",deprecated:"warning"}[s.status]||"subtle",label:s.status},null,8,["variant","label"])]),t("td",Je,[l(o(p),{variant:"ghost",size:"sm",onClick:_=>de(s),loading:A.value===s.fingerprint},{default:n(()=>[l(o(g),{name:"trash-2",class:"h-4 w-4 text-red-500"})]),_:1},8,["onClick","loading"])])]))),128))])])])):(i(),O(xe,{key:1,icon:"tag",title:"No versions",description:"Build your first image version using the Build Image button."}))])):b.value==="configuration"?(i(),r("div",We,[t("div",Ke,[t("div",Pe,[e[19]||(e[19]=t("h3",{class:"text-base font-medium text-ink-gray-9"}," Distrobuilder Configuration ",-1)),t("div",Qe,[k.value?(i(),r($,{key:1},[l(o(p),{variant:"subtle",size:"sm",onClick:oe},{default:n(()=>[...e[17]||(e[17]=[v(" Cancel ",-1)])]),_:1}),l(o(p),{variant:"solid",size:"sm",onClick:ne,loading:R.value},{default:n(()=>[...e[18]||(e[18]=[v(" Save ",-1)])]),_:1},8,["loading"])],64)):(i(),O(o(p),{key:0,variant:"subtle",size:"sm",onClick:le},{prefix:n(()=>[l(o(g),{name:"edit-2",class:"h-4 w-4"})]),default:n(()=>[e[16]||(e[16]=v(" Edit ",-1))]),_:1}))])]),t("div",Xe,[k.value?pe((i(),r("textarea",{key:1,"onUpdate:modelValue":e[3]||(e[3]=s=>h.value=s),class:"w-full h-[600px] bg-gray-900 text-gray-100 p-4 rounded-lg text-sm font-mono focus:outline-none focus:ring-2 focus:ring-blue-500"},null,512)),[[ve,h.value]]):(i(),r("pre",Ye,d(((P=c.value)==null?void 0:P.yaml_content)||"# No configuration available"),1))])])])):q("",!0)])],64))]),l(o(Z),{modelValue:S.value,"onUpdate:modelValue":e[7]||(e[7]=s=>S.value=s),options:{title:"Build Image"}},{"body-content":n(()=>[t("div",Ze,[l(o(F),{modelValue:B.value,"onUpdate:modelValue":e[4]||(e[4]=s=>B.value=s),label:"Version Tag",type:"text",placeholder:"v1.0.0",description:"Leave empty for unversioned build"},null,8,["modelValue"]),l(o(F),{modelValue:I.value,"onUpdate:modelValue":e[5]||(e[5]=s=>I.value=s),label:"Release",type:"text",placeholder:"edge",description:"Distribution release (e.g. edge, 3.21, 3.23, 24.04)"},null,8,["modelValue"]),l(o(F),{modelValue:y.value,"onUpdate:modelValue":e[6]||(e[6]=s=>y.value=s),label:"Target Server",type:"select",options:ae.value,description:"Select the image server where the built image will be imported"},null,8,["modelValue","options"]),m.value?(i(),r("div",et,[e[20]||(e[20]=t("label",{class:"block text-sm font-medium text-ink-gray-7 mb-2"},"Build Output",-1)),t("div",tt,[(i(!0),r($,null,M(m.value.logs,(s,_)=>(i(),r("div",{key:_,class:Y({"text-green-400":s.includes("✓"),"text-red-400":s.includes("✗")||s.includes("Error"),"text-yellow-400":s.includes("===")})},d(s),3))),128))])])):q("",!0)])]),actions:n(()=>[l(o(p),{variant:"subtle",onClick:re},{default:n(()=>[v(d(m.value?"Close":a.$t("common.cancel")),1)]),_:1}),m.value?q("",!0):(i(),O(o(p),{key:0,variant:"solid",onClick:ie,loading:j.value},{prefix:n(()=>[l(o(g),{name:"play",class:"h-4 w-4"})]),default:n(()=>[e[21]||(e[21]=v(" Start Build ",-1))]),_:1},8,["loading"]))]),_:1},8,["modelValue"]),l(o(Z),{modelValue:w.value,"onUpdate:modelValue":e[10]||(e[10]=s=>w.value=s),options:{title:"Edit Description"}},{"body-content":n(()=>[l(o(F),{modelValue:z.value,"onUpdate:modelValue":e[8]||(e[8]=s=>z.value=s),label:"Description",type:"textarea",placeholder:"Describe this app template..."},null,8,["modelValue"])]),actions:n(()=>[l(o(p),{variant:"subtle",onClick:e[9]||(e[9]=s=>w.value=!1)},{default:n(()=>[v(d(a.$t("common.cancel")),1)]),_:1}),l(o(p),{variant:"solid",onClick:ue,loading:T.value},{default:n(()=>[...e[22]||(e[22]=[v(" Save ",-1)])]),_:1},8,["loading"])]),_:1},8,["modelValue"])])}}};export{rt as default};
-//# sourceMappingURL=AppDetail-d8b34acc.js.map
+import{a as ce,y as Q,n as L,z as X,o as i,c as r,d as l,g as n,b as t,e as o,p as $,q as M,t as d,h as O,f as pe,J as ve,i as q,r as u,m as D,k as p,F as g,j as v,S as me,E as Y,G as fe,D as F,H as Z}from"./index-236aaeb3.js";import{_ as ge}from"./LayoutHeader-46b723f4.js";import{_ as U}from"./StatCard-db6270fe.js";import{_ as xe}from"./EmptyState-7840fa22.js";const ye={class:"flex flex-col h-full"},_e={class:"flex items-center gap-3"},be={class:"flex items-center gap-3"},ke={class:"w-10 h-10 rounded-lg bg-blue-100 flex items-center justify-center"},he={class:"text-xl font-semibold text-ink-gray-9"},we={class:"text-sm text-ink-gray-5"},Ve={class:"flex-1 overflow-auto"},Ce={key:0,class:"flex items-center justify-center h-64"},$e={class:"border-b px-5"},De={class:"flex gap-2"},Se=["onClick"],Be={class:"p-5"},Ie={key:0,class:"space-y-6"},ze={class:"grid gap-4 sm:grid-cols-2 lg:grid-cols-4"},Ne={class:"rounded-lg border p-5"},Ee={class:"flex items-center justify-between mb-4"},Fe={class:"text-sm text-ink-gray-5"},Ue={key:1},Re={key:0,class:"rounded-lg border overflow-hidden"},je={class:"min-w-full divide-y"},Te={class:"divide-y"},Ae={class:"px-6 py-4"},Le={class:"text-sm font-medium text-ink-gray-9"},Me={class:"px-6 py-4 text-sm text-ink-gray-7 font-mono"},Oe={class:"px-6 py-4 text-sm text-ink-gray-7 font-mono"},qe={class:"px-6 py-4 text-sm text-ink-gray-7"},Ge={class:"px-6 py-4 text-sm text-ink-gray-7"},He={class:"px-6 py-4"},Je={class:"px-6 py-4"},We={key:2},Ke={class:"rounded-lg border overflow-hidden"},Pe={class:"flex items-center justify-between p-4 border-b"},Qe={class:"flex gap-2"},Xe={class:"p-4"},Ye={key:0,class:"bg-gray-900 text-gray-100 p-4 rounded-lg text-sm overflow-x-auto font-mono max-h-[600px] overflow-y-auto"},Ze={class:"space-y-4"},et={key:0,class:"mt-4"},tt={class:"bg-gray-900 text-gray-100 p-4 rounded-lg text-xs font-mono max-h-64 overflow-y-auto"},rt={__name:"AppDetail",setup(at){const x=ce(),b=u("overview"),k=u(!1),h=u(""),R=u(!1),S=u(!1),B=u(""),I=u("edge"),y=u(""),j=u(!1),m=u(null),w=u(!1),z=u(""),T=u(!1),A=u(null),ee=[{id:"overview",label:"Overview"},{id:"versions",label:"Versions"},{id:"configuration",label:"Configuration"}],f=Q({url:"admin_panel.api.apps.get_app_detail",params:{app_name:x.params.appId},auto:!0}),te=Q({url:"admin_panel.api.servers.get_image_servers",auto:!0}),c=L(()=>f.data),N=L(()=>te.data||[]),ae=L(()=>N.value.map(e=>({label:`${e.name}${e.status==="online"?"":" ("+e.status+")"}`,value:e.name})));X(N,a=>{a.length&&!y.value&&(y.value=a[0].name)},{immediate:!0}),X(()=>{var a;return(a=c.value)==null?void 0:a.description},a=>{z.value=a||""});function se(){f.reload()}function le(){var a;h.value=((a=c.value)==null?void 0:a.yaml_content)||"",k.value=!0}function oe(){k.value=!1,h.value=""}async function ne(){R.value=!0;try{const a=await D("admin_panel.api.apps.save_app_config",{app_name:x.params.appId,yaml_content:h.value});a.success?(console.log(a.message),k.value=!1,f.reload()):console.error(a.error||"Failed to save configuration")}catch(a){console.error(a.message||"Failed to save configuration")}finally{R.value=!1}}async function ie(){j.value=!0,m.value=null;try{const a=await D("admin_panel.api.apps.build_image",{app_name:x.params.appId,version:B.value,target_server:y.value,release:I.value||"edge"});m.value=a,a.success?(console.log(a.message),f.reload()):console.error(a.error||"Build failed")}catch(a){m.value={success:!1,error:a.message,logs:[`Error: ${a.message}`]},console.error(a.message||"Build failed")}finally{j.value=!1}}function re(){S.value=!1,m.value=null,B.value="",I.value="edge",y.value=N.value.length?N.value[0].name:""}async function ue(){T.value=!0;try{const a=await D("admin_panel.api.apps.update_app_meta",{app_name:x.params.appId,description:z.value});a.success?(console.log(a.message),w.value=!1,f.reload()):console.error(a.error||"Failed to update description")}catch(a){console.error(a.message||"Failed to update description")}finally{T.value=!1}}async function de(a){if(!a.fingerprint||a.fingerprint==="-"){console.error("Cannot delete: invalid fingerprint");return}A.value=a.fingerprint;try{const V=(await D("admin_panel.api.apps.get_app_versions",{app_name:x.params.appId})).find(E=>E.fingerprint.startsWith(a.fingerprint));if(!V){console.error("Version not found");return}const C=await D("admin_panel.api.apps.delete_image",{fingerprint:V.fingerprint});C.success?(console.log("Image deleted successfully"),f.reload()):console.error(C.error||"Failed to delete image")}catch(e){console.error(e.message||"Failed to delete image")}finally{A.value=null}}return(a,e)=>{var V,C,E,G,H,J,W,K,P;return i(),r("div",ye,[l(ge,null,{left:n(()=>{var s,_;return[t("div",_e,[l(o(p),{variant:"ghost",onClick:e[0]||(e[0]=st=>a.$router.push({name:"Apps"}))},{default:n(()=>[l(o(g),{name:"arrow-left",class:"h-4 w-4"})]),_:1}),t("div",be,[t("div",ke,[l(o(g),{name:"package",class:"h-5 w-5 text-blue-600"})]),t("div",null,[t("h1",he,d(((s=c.value)==null?void 0:s.name)||o(x).params.appId),1),t("p",we,d(((_=c.value)==null?void 0:_.currentVersion)||"-"),1)])])])]}),right:n(()=>[l(o(p),{variant:"subtle",onClick:se,loading:o(f).loading},{prefix:n(()=>[l(o(g),{name:"refresh-cw",class:"h-4 w-4"})]),default:n(()=>[e[11]||(e[11]=v(" Refresh ",-1))]),_:1},8,["loading"]),l(o(p),{variant:"solid",onClick:e[1]||(e[1]=s=>S.value=!0)},{prefix:n(()=>[l(o(g),{name:"play",class:"h-4 w-4"})]),default:n(()=>[e[12]||(e[12]=v(" Build Image ",-1))]),_:1})]),_:1}),t("div",Ve,[o(f).loading?(i(),r("div",Ce,[l(o(me),{class:"h-8 w-8"})])):(i(),r($,{key:1},[t("div",$e,[t("nav",De,[(i(),r($,null,M(ee,s=>t("button",{key:s.id,class:Y(["px-4 py-2 text-sm font-medium transition-colors",b.value===s.id?"border-b-2 border-ink-gray-9 text-ink-gray-9":"text-ink-gray-5 hover:text-ink-gray-7"]),onClick:_=>b.value=s.id},d(s.label),11,Se)),64))])]),t("div",Be,[b.value==="overview"?(i(),r("div",Ie,[t("div",ze,[l(U,{label:"Versions",value:((C=(V=c.value)==null?void 0:V.versions)==null?void 0:C.length)||0,iconName:"tag",color:"blue"},null,8,["value"]),l(U,{label:"Latest Version",value:((E=c.value)==null?void 0:E.currentVersion)||"-",iconName:"git-branch",color:"green"},null,8,["value"]),l(U,{label:"Size",value:((G=c.value)==null?void 0:G.size)||"-",iconName:"hard-drive",color:"purple"},null,8,["value"]),l(U,{label:"Status",value:((H=c.value)==null?void 0:H.status)||"-",iconName:"activity",color:"gray"},null,8,["value"])]),t("div",Ne,[t("div",Ee,[e[14]||(e[14]=t("h3",{class:"text-base font-medium text-ink-gray-9"}," Description ",-1)),l(o(p),{variant:"subtle",size:"sm",onClick:e[2]||(e[2]=s=>w.value=!0)},{prefix:n(()=>[l(o(g),{name:"edit-2",class:"h-4 w-4"})]),default:n(()=>[e[13]||(e[13]=v(" Edit ",-1))]),_:1})]),t("p",Fe,d(((J=c.value)==null?void 0:J.description)||"No description available"),1)])])):b.value==="versions"?(i(),r("div",Ue,[(K=(W=c.value)==null?void 0:W.versions)!=null&&K.length?(i(),r("div",Re,[t("table",je,[e[15]||(e[15]=t("thead",{class:"bg-surface-gray-2"},[t("tr",null,[t("th",{class:"px-6 py-3 text-left text-xs font-medium text-ink-gray-5 uppercase"},"Version"),t("th",{class:"px-6 py-3 text-left text-xs font-medium text-ink-gray-5 uppercase"},"Alias"),t("th",{class:"px-6 py-3 text-left text-xs font-medium text-ink-gray-5 uppercase"},"Fingerprint"),t("th",{class:"px-6 py-3 text-left text-xs font-medium text-ink-gray-5 uppercase"},"Created"),t("th",{class:"px-6 py-3 text-left text-xs font-medium text-ink-gray-5 uppercase"},"Size"),t("th",{class:"px-6 py-3 text-left text-xs font-medium text-ink-gray-5 uppercase"},"Status"),t("th",{class:"px-6 py-3 text-left text-xs font-medium text-ink-gray-5 uppercase"},"Actions")])],-1)),t("tbody",Te,[(i(!0),r($,null,M(c.value.versions,s=>(i(),r("tr",{key:s.version},[t("td",Ae,[t("span",Le,d(s.version),1)]),t("td",Me,d(s.alias),1),t("td",Oe,d(s.fingerprint),1),t("td",qe,d(s.released),1),t("td",Ge,d(s.size),1),t("td",He,[l(o(fe),{variant:{current:"success",active:"info",deprecated:"warning"}[s.status]||"subtle",label:s.status},null,8,["variant","label"])]),t("td",Je,[l(o(p),{variant:"ghost",size:"sm",onClick:_=>de(s),loading:A.value===s.fingerprint},{default:n(()=>[l(o(g),{name:"trash-2",class:"h-4 w-4 text-red-500"})]),_:1},8,["onClick","loading"])])]))),128))])])])):(i(),O(xe,{key:1,icon:"tag",title:"No versions",description:"Build your first image version using the Build Image button."}))])):b.value==="configuration"?(i(),r("div",We,[t("div",Ke,[t("div",Pe,[e[19]||(e[19]=t("h3",{class:"text-base font-medium text-ink-gray-9"}," Distrobuilder Configuration ",-1)),t("div",Qe,[k.value?(i(),r($,{key:1},[l(o(p),{variant:"subtle",size:"sm",onClick:oe},{default:n(()=>[...e[17]||(e[17]=[v(" Cancel ",-1)])]),_:1}),l(o(p),{variant:"solid",size:"sm",onClick:ne,loading:R.value},{default:n(()=>[...e[18]||(e[18]=[v(" Save ",-1)])]),_:1},8,["loading"])],64)):(i(),O(o(p),{key:0,variant:"subtle",size:"sm",onClick:le},{prefix:n(()=>[l(o(g),{name:"edit-2",class:"h-4 w-4"})]),default:n(()=>[e[16]||(e[16]=v(" Edit ",-1))]),_:1}))])]),t("div",Xe,[k.value?pe((i(),r("textarea",{key:1,"onUpdate:modelValue":e[3]||(e[3]=s=>h.value=s),class:"w-full h-[600px] bg-gray-900 text-gray-100 p-4 rounded-lg text-sm font-mono focus:outline-none focus:ring-2 focus:ring-blue-500"},null,512)),[[ve,h.value]]):(i(),r("pre",Ye,d(((P=c.value)==null?void 0:P.yaml_content)||"# No configuration available"),1))])])])):q("",!0)])],64))]),l(o(Z),{modelValue:S.value,"onUpdate:modelValue":e[7]||(e[7]=s=>S.value=s),options:{title:"Build Image"}},{"body-content":n(()=>[t("div",Ze,[l(o(F),{modelValue:B.value,"onUpdate:modelValue":e[4]||(e[4]=s=>B.value=s),label:"Version Tag",type:"text",placeholder:"v1.0.0",description:"Leave empty for unversioned build"},null,8,["modelValue"]),l(o(F),{modelValue:I.value,"onUpdate:modelValue":e[5]||(e[5]=s=>I.value=s),label:"Release",type:"text",placeholder:"edge",description:"Distribution release (e.g. edge, 3.21, 3.23, 24.04)"},null,8,["modelValue"]),l(o(F),{modelValue:y.value,"onUpdate:modelValue":e[6]||(e[6]=s=>y.value=s),label:"Target Server",type:"select",options:ae.value,description:"Select the image server where the built image will be imported"},null,8,["modelValue","options"]),m.value?(i(),r("div",et,[e[20]||(e[20]=t("label",{class:"block text-sm font-medium text-ink-gray-7 mb-2"},"Build Output",-1)),t("div",tt,[(i(!0),r($,null,M(m.value.logs,(s,_)=>(i(),r("div",{key:_,class:Y({"text-green-400":s.includes("✓"),"text-red-400":s.includes("✗")||s.includes("Error"),"text-yellow-400":s.includes("===")})},d(s),3))),128))])])):q("",!0)])]),actions:n(()=>[l(o(p),{variant:"subtle",onClick:re},{default:n(()=>[v(d(m.value?"Close":a.$t("common.cancel")),1)]),_:1}),m.value?q("",!0):(i(),O(o(p),{key:0,variant:"solid",onClick:ie,loading:j.value},{prefix:n(()=>[l(o(g),{name:"play",class:"h-4 w-4"})]),default:n(()=>[e[21]||(e[21]=v(" Start Build ",-1))]),_:1},8,["loading"]))]),_:1},8,["modelValue"]),l(o(Z),{modelValue:w.value,"onUpdate:modelValue":e[10]||(e[10]=s=>w.value=s),options:{title:"Edit Description"}},{"body-content":n(()=>[l(o(F),{modelValue:z.value,"onUpdate:modelValue":e[8]||(e[8]=s=>z.value=s),label:"Description",type:"textarea",placeholder:"Describe this app template..."},null,8,["modelValue"])]),actions:n(()=>[l(o(p),{variant:"subtle",onClick:e[9]||(e[9]=s=>w.value=!1)},{default:n(()=>[v(d(a.$t("common.cancel")),1)]),_:1}),l(o(p),{variant:"solid",onClick:ue,loading:T.value},{default:n(()=>[...e[22]||(e[22]=[v(" Save ",-1)])]),_:1},8,["loading"])]),_:1},8,["modelValue"])])}}};export{rt as default};
+//# sourceMappingURL=AppDetail-6620138c.js.map
diff --git a/admin_panel/public/frontend/assets/AppDetail-d8b34acc.js.map b/admin_panel/public/frontend/assets/AppDetail-6620138c.js.map
similarity index 99%
rename from admin_panel/public/frontend/assets/AppDetail-d8b34acc.js.map
rename to admin_panel/public/frontend/assets/AppDetail-6620138c.js.map
index 71d4f46..42c4d56 100644
--- a/admin_panel/public/frontend/assets/AppDetail-d8b34acc.js.map
+++ b/admin_panel/public/frontend/assets/AppDetail-6620138c.js.map
@@ -1 +1 @@
-{"version":3,"file":"AppDetail-d8b34acc.js","sources":["../../../../frontend/src/pages/admin/AppDetail.vue"],"sourcesContent":["\n \n {{ app?.currentVersion || '-' }}\n \n {{ app?.description || 'No description available' }}\n \n {{ app?.currentVersion || '-' }}\n \n {{ app?.description || 'No description available' }}\n \n {{ app.description }}\n {{ app.currentVersion || '-' }} {{ app.versions_count || 0 }} \n {{ app.description }}\n {{ app.currentVersion || '-' }} {{ app.versions_count || 0 }} \n {{ description }}\n \n {{ description }}\n \n {{ $t('auth.login') }}\n \n {{ $t('auth.login') }}\n \n The page you're looking for doesn't exist.\n \n The page you're looking for doesn't exist.\n \n {{ app?.name || route.params.appId }}\n
\n \n Description\n
\n \n \n \n
\n \n \n \n \n Version \n Alias \n Fingerprint \n Created \n Size \n Status \n Actions \n \n \n \n \n {{ version.version }}\n \n {{ version.alias }} \n {{ version.fingerprint }} \n {{ version.released }} \n {{ version.size }} \n \n \n \n \n \n \n Distrobuilder Configuration\n
\n {{ app?.yaml_content || '# No configuration available' }}\n \n \n {{ app?.name || route.params.appId }}\n
\n \n Description\n
\n \n \n \n
\n \n \n \n \n Version \n Alias \n Fingerprint \n Created \n Size \n Status \n Actions \n \n \n \n \n {{ version.version }}\n \n {{ version.alias }} \n {{ version.fingerprint }} \n {{ version.released }} \n {{ version.size }} \n \n \n \n \n \n \n Distrobuilder Configuration\n
\n {{ app?.yaml_content || '# No configuration available' }}\n \n \n {{ app.name }}\n
\n \n {{ app.name }}\n
\n \n {{ title }}\n
\n \n {{ title }}\n
\n \n \n
\n \n \n \n \n {{ $t('payments.customer.name') }} \n {{ $t('payments.customer.email') }} \n {{ $t('payments.connections') }} \n {{ $t('payments.customer.amount') }} \n {{ $t('payments.customer.status') }} \n Since \n {{ $t('common.actions') }} \n \n \n \n \n \n {{ customer.email }} \n {{ customer.connections }} \n \n {{ formatCurrency(customer.monthlyAmount) }}/mo\n \n \n \n {{ customer.since }} \n \n \n \n \n \n
\n \n \n \n \n {{ $t('payments.customer.name') }} \n {{ $t('payments.customer.email') }} \n {{ $t('payments.connections') }} \n {{ $t('payments.customer.amount') }} \n {{ $t('payments.customer.status') }} \n Since \n {{ $t('common.actions') }} \n \n \n \n \n \n {{ customer.email }} \n {{ customer.connections }} \n \n {{ formatCurrency(customer.monthlyAmount) }}/mo\n \n \n \n {{ customer.since }} \n \n \n \n \n {{ $t('dashboard.systemInfo') }}\n
\n \n {{ $t('dashboard.systemInfo') }}\n
\n \n {{ title }}\n
\n \n {{ title }}\n
\n \n {{ title }}\n
\n \n {{ title }}\n
\n \n Admin Panel\n
\n \n Admin Panel\n
\n 404
\n \n Page Not Found\n
\n 404
\n \n Page Not Found\n
\n \n Recent Payments\n
\n \n \n
\n \n \n \n \n Customer \n Amount \n Date \n Status \n Method \n \n \n \n {{ payment.customerName }} \n \n {{ formatCurrency(payment.amount) }}\n \n {{ payment.date }} \n \n \n {{ payment.method }} \n \n \n
\n \n \n \n \n {{ $t('payments.customer.name') }} \n {{ $t('payments.customer.email') }} \n {{ $t('payments.connections') }} \n {{ $t('payments.customer.amount') }} \n {{ $t('payments.customer.status') }} \n {{ $t('payments.customer.lastPayment') }} \n \n \n \n {{ customer.name }} \n {{ customer.email }} \n {{ customer.connections }} \n \n {{ formatCurrency(customer.monthlyAmount) }}/mo\n \n \n \n {{ customer.lastPayment }} \n \n \n
\n \n \n \n \n Customer \n Email \n Amount Due \n Reason \n Actions \n \n \n \n {{ account.name }} \n {{ account.email }} \n \n {{ formatCurrency(account.monthlyAmount) }}\n \n {{ account.frozenReason }} \n \n \n \n \n Generate Report\n
\n \n Recent Payments\n
\n \n \n
\n \n \n \n \n Customer \n Amount \n Date \n Status \n Method \n \n \n \n {{ payment.customerName }} \n \n {{ formatCurrency(payment.amount) }}\n \n {{ payment.date }} \n \n \n {{ payment.method }} \n \n \n
\n \n \n \n \n {{ $t('payments.customer.name') }} \n {{ $t('payments.customer.email') }} \n {{ $t('payments.connections') }} \n {{ $t('payments.customer.amount') }} \n {{ $t('payments.customer.status') }} \n {{ $t('payments.customer.lastPayment') }} \n \n \n \n {{ customer.name }} \n {{ customer.email }} \n {{ customer.connections }} \n \n {{ formatCurrency(customer.monthlyAmount) }}/mo\n \n \n \n {{ customer.lastPayment }} \n \n \n
\n \n \n \n \n Customer \n Email \n Amount Due \n Reason \n Actions \n \n \n \n {{ account.name }} \n {{ account.email }} \n \n {{ formatCurrency(account.monthlyAmount) }}\n \n {{ account.frozenReason }} \n \n \n \n \n Generate Report\n
\n
How to trust this certificate on Incus servers:
admin-panel.crt on your Incus serverincus config trust add-certificate admin-panel.crt\n Client certificate used to authenticate with Incus servers\n
\nCertificate configured
\n{{ certStatus.cert_path }}
\nHow to trust this certificate on Incus servers:
\nadmin-panel.crt on your Incus serverincus config trust add-certificate admin-panel.crtNo certificate
\nGenerate a client certificate to connect to Incus servers
\n\n {{ $t('servers.setup.description') }}\n
\n\n {{ setupStatus?.distrobuilder_installed ? $t('servers.setup.distrobuilderInstalled') : $t('servers.setup.distrobuilderNotInstalled') }}\n
\n\n {{ setupStatus?.distrobuilder_version || $t('servers.setup.distrobuilderDesc') }}\n
\n\n {{ $t('servers.roles.title') }}\n
\nHow to trust this certificate on Incus servers:
admin-panel.crt on your Incus serverincus config trust add-certificate admin-panel.crt\n Client certificate used to authenticate with Incus servers\n
\nCertificate configured
\n{{ certStatus.cert_path }}
\nHow to trust this certificate on Incus servers:
\nadmin-panel.crt on your Incus serverincus config trust add-certificate admin-panel.crtNo certificate
\nGenerate a client certificate to connect to Incus servers
\n\n Tools needed for building container images\n
\n\n {{ $t('servers.setup.distrobuilderInstalled') }}\n
\nFor building custom images
\n\n {{ $t('servers.roles.title') }}\n
\n| Name | \n{{ $t('settings.admin.role') }} | \n{{ $t('settings.admin.lastLogin') }} | \n{{ $t('common.actions') }} | \n|
|---|---|---|---|---|
| \n \n \n \n \n {{ user.name.charAt(0) }}\n \n \n {{ user.name }}\n | \n {{ user.email }} | \n\n | \n {{ user.lastLogin }} | \n\n \n \n \n \n | \n
\n Add an extra layer of security to your account\n
\n{{ session.device }}
\n{{ session.location }} - {{ session.lastActive }}
\n| Name | \n{{ $t('settings.admin.role') }} | \n{{ $t('settings.admin.lastLogin') }} | \n{{ $t('common.actions') }} | \n|
|---|---|---|---|---|
| \n \n \n \n \n {{ user.name.charAt(0) }}\n \n \n {{ user.name }}\n | \n {{ user.email }} | \n\n | \n {{ user.lastLogin }} | \n\n \n \n \n \n | \n
\n Add an extra layer of security to your account\n
\n{{ session.device }}
\n{{ session.location }} - {{ session.lastActive }}
\n\n {{ site?.container_name }}\n
\nFailed to load container details
\n \n\n {{ formatBytes(site?.memory_usage_bytes) }} / {{ formatBytes(site?.memory_total_bytes) }}\n
\n\n {{ formatBytes(site?.disk_usage_bytes) }} / {{ formatBytes(site?.disk_total_bytes) }}\n
\nNetwork RX
\n{{ formatBytes(site?.network_rx) }}
\nNetwork TX
\n{{ formatBytes(site?.network_tx) }}
\n{{ activity.message }}
\n\n {{ activity.timestamp }} - {{ activity.user }}\n
\n| Name | \nCreated | \nStateful | \nActions | \n
|---|---|---|---|
| {{ snap.name }} | \n{{ formatDate(snap.created_at) }} | \n\n | \n \n \n \n \n \n | \n
\n {{ site?.container_name }}\n
\nFailed to load container details
\n \n\n {{ formatBytes(site?.memory_usage_bytes) }} / {{ formatBytes(site?.memory_total_bytes) }}\n
\n\n {{ formatBytes(site?.disk_usage_bytes) }} / {{ formatBytes(site?.disk_total_bytes) }}\n
\nNetwork RX
\n{{ formatBytes(site?.network_rx) }}
\nNetwork TX
\n{{ formatBytes(site?.network_tx) }}
\n{{ activity.message }}
\n\n {{ activity.timestamp }} - {{ activity.user }}\n
\n| Name | \nCreated | \nStateful | \nActions | \n
|---|---|---|---|
| {{ snap.name }} | \n{{ formatDate(snap.created_at) }} | \n\n | \n \n \n \n \n \n | \n
No container servers configured
\nAdd a server with \"Container Server\" role in the Servers tab
\n \nFailed to load containers
\n{{ containers.error }}
\n \n{{ site.name }}
\n{{ site.image || site.type }}
\nIP
\n{{ site.ip_address || '-' }}
\n{{ $t('sites.siteOwner') }}
\n{{ site.owner || '-' }}
\nNo container servers configured
\nAdd a server with \"Container Server\" role in the Servers tab
\n \nFailed to load containers
\n{{ containers.error }}
\n \n{{ site.name }}
\n{{ site.image || site.type }}
\nIP
\n{{ site.ip_address || '-' }}
\n{{ $t('sites.siteOwner') }}
\n{{ site.owner || '-' }}
\n{{ label }}
\n\n {{ formattedValue }}\n
\n{{ label }}
\n\n {{ formattedValue }}\n
\n\n {{ props.description }}\n
\n