feat: Open Site button opens containername.host.jeyerp.az, add Login as Administrator
- Open Site button now uses containername.host_domain URL format - Login button generates one-time session inside container via incus exec and opens site with sid for auto-login as Administrator to Setup Wizard - host_domain is configurable via site_config (default: host.jeyerp.az) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
d2791d3db7
commit
c104cc330c
|
|
@ -1103,3 +1103,55 @@ def deploy_container_full(container_name, image="erp", pool_name="default", volu
|
||||||
"logs": logs,
|
"logs": logs,
|
||||||
"message": f"Deploy failed at step {current_step}: {str(e)}",
|
"message": f"Deploy failed at step {current_step}: {str(e)}",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@frappe.whitelist()
|
||||||
|
def get_login_url(container_name, target_server=None):
|
||||||
|
"""Generate a one-time login URL for a container site (login as Administrator)."""
|
||||||
|
_check_admin_permission()
|
||||||
|
|
||||||
|
if not target_server:
|
||||||
|
frappe.throw("Server name is required")
|
||||||
|
|
||||||
|
# Generate sid inside the container via bench execute
|
||||||
|
# This Python snippet creates a session for Administrator and prints the sid
|
||||||
|
python_cmd = (
|
||||||
|
"import frappe;"
|
||||||
|
"frappe.init(site='frontend');"
|
||||||
|
"frappe.connect();"
|
||||||
|
"sid = frappe.generate_hash();"
|
||||||
|
"frappe.db.sql("
|
||||||
|
"\"INSERT INTO `tabSessions` (`sid`, `user`, `data`, `lastused`, `status`) "
|
||||||
|
"VALUES (%s, 'Administrator', '{}', NOW(), 'Active')\", (sid,));"
|
||||||
|
"frappe.db.commit();"
|
||||||
|
"print(sid)"
|
||||||
|
)
|
||||||
|
|
||||||
|
cmd = f"su frappe -c \"cd /home/frappe/frappe-bench && bench --site frontend execute 'frappe.utils.execute_in_shell' 2>/dev/null\" 2>/dev/null || python3 -c \"{python_cmd}\""
|
||||||
|
|
||||||
|
# Simpler approach: run python3 directly
|
||||||
|
result = _exec_in_container(target_server, container_name,
|
||||||
|
["python3", "-c", python_cmd],
|
||||||
|
timeout=30,
|
||||||
|
)
|
||||||
|
|
||||||
|
if result.get("return_code") != 0:
|
||||||
|
return {
|
||||||
|
"success": False,
|
||||||
|
"error": result.get("output") or "Failed to generate login token",
|
||||||
|
}
|
||||||
|
|
||||||
|
sid = result.get("output", "").strip().split("\n")[-1].strip()
|
||||||
|
if not sid:
|
||||||
|
return {"success": False, "error": "Empty sid returned"}
|
||||||
|
|
||||||
|
# Build the site URL
|
||||||
|
host_domain = frappe.conf.get("host_domain", "host.jeyerp.az")
|
||||||
|
site_url = f"http://{container_name}.{host_domain}"
|
||||||
|
|
||||||
|
return {
|
||||||
|
"success": True,
|
||||||
|
"url": site_url,
|
||||||
|
"sid": sid,
|
||||||
|
"login_url": f"{site_url}/api/method/login?sid={sid}",
|
||||||
|
}
|
||||||
|
|
|
||||||
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,2 +1,2 @@
|
||||||
import{o as a,c as r,b as e,t as i,P as s}from"./index-5e93ecd0.js";const n={class:"rounded-lg border p-4 shadow-sm"},c={class:"flex items-center justify-between mb-4"},d={class:"text-base font-medium text-ink-gray-9"},l={class:"h-[200px]"},p={__name:"ChartCard",props:{title:{type:String,required:!0}},setup(o){return(t,_)=>(a(),r("div",n,[e("div",c,[e("h3",d,i(o.title),1),s(t.$slots,"actions")]),e("div",l,[s(t.$slots,"default")])]))}};export{p as _};
|
import{o as a,c as r,b as e,t as i,P as s}from"./index-0ce49f30.js";const n={class:"rounded-lg border p-4 shadow-sm"},c={class:"flex items-center justify-between mb-4"},d={class:"text-base font-medium text-ink-gray-9"},l={class:"h-[200px]"},p={__name:"ChartCard",props:{title:{type:String,required:!0}},setup(o){return(t,_)=>(a(),r("div",n,[e("div",c,[e("h3",d,i(o.title),1),s(t.$slots,"actions")]),e("div",l,[s(t.$slots,"default")])]))}};export{p as _};
|
||||||
//# sourceMappingURL=ChartCard-98ba0e20.js.map
|
//# sourceMappingURL=ChartCard-14decb58.js.map
|
||||||
|
|
@ -1 +1 @@
|
||||||
{"version":3,"file":"ChartCard-98ba0e20.js","sources":["../../../../frontend/src/components/Common/ChartCard.vue"],"sourcesContent":["<template>\n <div class=\"rounded-lg border p-4 shadow-sm\">\n <div class=\"flex items-center justify-between mb-4\">\n <h3 class=\"text-base font-medium text-ink-gray-9\">\n {{ title }}\n </h3>\n <slot name=\"actions\" />\n </div>\n <div class=\"h-[200px]\">\n <slot />\n </div>\n </div>\n</template>\n\n<script setup>\ndefineProps({\n title: {\n type: String,\n required: true,\n },\n})\n</script>\n"],"names":["_openBlock","_createElementBlock","_hoisted_1","_createElementVNode","_hoisted_2","_hoisted_3","_toDisplayString","__props","_renderSlot","_ctx","_hoisted_4"],"mappings":"sUACEA,EAAA,EAAAC,EAUM,MAVNC,EAUM,CATJC,EAKM,MALNC,EAKM,CAJJD,EAEK,KAFLE,EAEKC,EADAC,EAAK,KAAA,EAAA,CAAA,EAEVC,EAAuBC,EAAA,OAAA,SAAA,IAEzBN,EAEM,MAFNO,EAEM,CADJF,EAAQC,EAAA,OAAA,SAAA"}
|
{"version":3,"file":"ChartCard-14decb58.js","sources":["../../../../frontend/src/components/Common/ChartCard.vue"],"sourcesContent":["<template>\n <div class=\"rounded-lg border p-4 shadow-sm\">\n <div class=\"flex items-center justify-between mb-4\">\n <h3 class=\"text-base font-medium text-ink-gray-9\">\n {{ title }}\n </h3>\n <slot name=\"actions\" />\n </div>\n <div class=\"h-[200px]\">\n <slot />\n </div>\n </div>\n</template>\n\n<script setup>\ndefineProps({\n title: {\n type: String,\n required: true,\n },\n})\n</script>\n"],"names":["_openBlock","_createElementBlock","_hoisted_1","_createElementVNode","_hoisted_2","_hoisted_3","_toDisplayString","__props","_renderSlot","_ctx","_hoisted_4"],"mappings":"sUACEA,EAAA,EAAAC,EAUM,MAVNC,EAUM,CATJC,EAKM,MALNC,EAKM,CAJJD,EAEK,KAFLE,EAEKC,EADAC,EAAK,KAAA,EAAA,CAAA,EAEVC,EAAuBC,EAAA,OAAA,SAAA,IAEzBN,EAEM,MAFNO,EAEM,CADJF,EAAQC,EAAA,OAAA,SAAA"}
|
||||||
|
|
@ -1,2 +1,2 @@
|
||||||
import{_ as g}from"./LayoutHeader-596b102d.js";import{c as v}from"./payments-4b7e79ca.js";import{n as k,o as c,c as m,d as n,g as r,b as t,t as s,p as w,q as $,e as i,_ as C,F as d,k as p,j as b,G as V,r as x}from"./index-5e93ecd0.js";const F={class:"flex flex-col h-full"},B={class:"flex-1 overflow-auto p-5"},L={class:"rounded-lg border overflow-hidden"},N={class:"min-w-full divide-y"},U={class:"bg-surface-gray-2"},j={class:"px-6 py-3 text-left text-xs font-medium text-ink-gray-5 uppercase"},q={class:"px-6 py-3 text-left text-xs font-medium text-ink-gray-5 uppercase"},A={class:"px-6 py-3 text-left text-xs font-medium text-ink-gray-5 uppercase"},D={class:"px-6 py-3 text-left text-xs font-medium text-ink-gray-5 uppercase"},E={class:"px-6 py-3 text-left text-xs font-medium text-ink-gray-5 uppercase"},I={class:"px-6 py-3 text-right text-xs font-medium text-ink-gray-5 uppercase"},R={class:"divide-y"},S={class:"px-6 py-4"},z={class:"flex items-center gap-3"},G={class:"w-8 h-8 rounded-full bg-surface-gray-2 flex items-center justify-center"},Q={class:"text-sm font-medium text-ink-gray-5"},T={class:"text-sm font-medium text-ink-gray-9"},H={class:"px-6 py-4 text-sm text-ink-gray-7"},J={class:"px-6 py-4 text-sm text-ink-gray-7"},K={class:"px-6 py-4 text-sm font-medium text-ink-gray-9"},M={class:"px-6 py-4"},O={class:"px-6 py-4 text-sm text-ink-gray-7"},P={class:"px-6 py-4 text-right"},et={__name:"Customers",setup(W){const l=x(""),u=x(v),_=k(()=>{if(!l.value)return u.value;const e=l.value.toLowerCase();return u.value.filter(o=>o.name.toLowerCase().includes(e)||o.email.toLowerCase().includes(e))});function f(e){return new Intl.NumberFormat("ru-RU",{style:"currency",currency:"RUB",minimumFractionDigits:0}).format(e)}function y(){console.log("Exporting customers...")}function h(e){console.log("Viewing customer:",e.name)}return(e,o)=>(c(),m("div",F,[n(g,{title:e.$t("payments.customers")},{right:r(()=>[n(i(C),{modelValue:l.value,"onUpdate:modelValue":o[0]||(o[0]=a=>l.value=a),type:"text",placeholder:e.$t("common.search"),class:"w-64"},{prefix:r(()=>[n(i(d),{name:"search",class:"h-4 w-4 text-ink-gray-4"})]),_:1},8,["modelValue","placeholder"]),n(i(p),{variant:"subtle",onClick:y},{prefix:r(()=>[n(i(d),{name:"download",class:"h-4 w-4"})]),default:r(()=>[b(" "+s(e.$t("common.export")),1)]),_:1})]),_:1},8,["title"]),t("div",B,[t("div",L,[t("table",N,[t("thead",U,[t("tr",null,[t("th",j,s(e.$t("payments.customer.name")),1),t("th",q,s(e.$t("payments.customer.email")),1),t("th",A,s(e.$t("payments.connections")),1),t("th",D,s(e.$t("payments.customer.amount")),1),t("th",E,s(e.$t("payments.customer.status")),1),o[1]||(o[1]=t("th",{class:"px-6 py-3 text-left text-xs font-medium text-ink-gray-5 uppercase"},"Since",-1)),t("th",I,s(e.$t("common.actions")),1)])]),t("tbody",R,[(c(!0),m(w,null,$(_.value,a=>(c(),m("tr",{key:a.id},[t("td",S,[t("div",z,[t("div",G,[t("span",Q,s(a.name.charAt(0)),1)]),t("span",T,s(a.name),1)])]),t("td",H,s(a.email),1),t("td",J,s(a.connections),1),t("td",K,s(f(a.monthlyAmount))+"/mo ",1),t("td",M,[n(i(V),{variant:a.status==="active"?"success":"info",label:a.status},null,8,["variant","label"])]),t("td",O,s(a.since),1),t("td",P,[n(i(p),{variant:"ghost",size:"sm",onClick:X=>h(a)},{default:r(()=>[n(i(d),{name:"eye",class:"h-4 w-4"})]),_:1},8,["onClick"])])]))),128))])])])])]))}};export{et as default};
|
import{_ as g}from"./LayoutHeader-15280106.js";import{c as v}from"./payments-4b7e79ca.js";import{n as k,o as c,c as m,d as n,g as r,b as t,t as s,p as w,q as $,e as i,_ as C,F as d,k as p,j as b,G as V,r as x}from"./index-0ce49f30.js";const F={class:"flex flex-col h-full"},B={class:"flex-1 overflow-auto p-5"},L={class:"rounded-lg border overflow-hidden"},N={class:"min-w-full divide-y"},U={class:"bg-surface-gray-2"},j={class:"px-6 py-3 text-left text-xs font-medium text-ink-gray-5 uppercase"},q={class:"px-6 py-3 text-left text-xs font-medium text-ink-gray-5 uppercase"},A={class:"px-6 py-3 text-left text-xs font-medium text-ink-gray-5 uppercase"},D={class:"px-6 py-3 text-left text-xs font-medium text-ink-gray-5 uppercase"},E={class:"px-6 py-3 text-left text-xs font-medium text-ink-gray-5 uppercase"},I={class:"px-6 py-3 text-right text-xs font-medium text-ink-gray-5 uppercase"},R={class:"divide-y"},S={class:"px-6 py-4"},z={class:"flex items-center gap-3"},G={class:"w-8 h-8 rounded-full bg-surface-gray-2 flex items-center justify-center"},Q={class:"text-sm font-medium text-ink-gray-5"},T={class:"text-sm font-medium text-ink-gray-9"},H={class:"px-6 py-4 text-sm text-ink-gray-7"},J={class:"px-6 py-4 text-sm text-ink-gray-7"},K={class:"px-6 py-4 text-sm font-medium text-ink-gray-9"},M={class:"px-6 py-4"},O={class:"px-6 py-4 text-sm text-ink-gray-7"},P={class:"px-6 py-4 text-right"},et={__name:"Customers",setup(W){const l=x(""),u=x(v),_=k(()=>{if(!l.value)return u.value;const e=l.value.toLowerCase();return u.value.filter(o=>o.name.toLowerCase().includes(e)||o.email.toLowerCase().includes(e))});function f(e){return new Intl.NumberFormat("ru-RU",{style:"currency",currency:"RUB",minimumFractionDigits:0}).format(e)}function y(){console.log("Exporting customers...")}function h(e){console.log("Viewing customer:",e.name)}return(e,o)=>(c(),m("div",F,[n(g,{title:e.$t("payments.customers")},{right:r(()=>[n(i(C),{modelValue:l.value,"onUpdate:modelValue":o[0]||(o[0]=a=>l.value=a),type:"text",placeholder:e.$t("common.search"),class:"w-64"},{prefix:r(()=>[n(i(d),{name:"search",class:"h-4 w-4 text-ink-gray-4"})]),_:1},8,["modelValue","placeholder"]),n(i(p),{variant:"subtle",onClick:y},{prefix:r(()=>[n(i(d),{name:"download",class:"h-4 w-4"})]),default:r(()=>[b(" "+s(e.$t("common.export")),1)]),_:1})]),_:1},8,["title"]),t("div",B,[t("div",L,[t("table",N,[t("thead",U,[t("tr",null,[t("th",j,s(e.$t("payments.customer.name")),1),t("th",q,s(e.$t("payments.customer.email")),1),t("th",A,s(e.$t("payments.connections")),1),t("th",D,s(e.$t("payments.customer.amount")),1),t("th",E,s(e.$t("payments.customer.status")),1),o[1]||(o[1]=t("th",{class:"px-6 py-3 text-left text-xs font-medium text-ink-gray-5 uppercase"},"Since",-1)),t("th",I,s(e.$t("common.actions")),1)])]),t("tbody",R,[(c(!0),m(w,null,$(_.value,a=>(c(),m("tr",{key:a.id},[t("td",S,[t("div",z,[t("div",G,[t("span",Q,s(a.name.charAt(0)),1)]),t("span",T,s(a.name),1)])]),t("td",H,s(a.email),1),t("td",J,s(a.connections),1),t("td",K,s(f(a.monthlyAmount))+"/mo ",1),t("td",M,[n(i(V),{variant:a.status==="active"?"success":"info",label:a.status},null,8,["variant","label"])]),t("td",O,s(a.since),1),t("td",P,[n(i(p),{variant:"ghost",size:"sm",onClick:X=>h(a)},{default:r(()=>[n(i(d),{name:"eye",class:"h-4 w-4"})]),_:1},8,["onClick"])])]))),128))])])])])]))}};export{et as default};
|
||||||
//# sourceMappingURL=Customers-efeef313.js.map
|
//# sourceMappingURL=Customers-ffd5b37c.js.map
|
||||||
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,2 +1,2 @@
|
||||||
import{o as t,c as s,b as n,d as r,e as c,F as o,t as a,i as l,P as d}from"./index-5e93ecd0.js";const m={class:"flex flex-col items-center justify-center py-12 text-center"},u={class:"mb-4 flex h-16 w-16 items-center justify-center rounded-full bg-surface-gray-2"},f={class:"mb-2 text-lg font-medium text-ink-gray-9"},y={key:0,class:"mb-4 max-w-sm text-sm text-ink-gray-5"},p={__name:"EmptyState",props:{icon:{type:String,default:"inbox"},title:{type:String,required:!0},description:{type:String,default:""}},setup(e){return(i,x)=>(t(),s("div",m,[n("div",u,[r(c(o),{name:e.icon,class:"h-8 w-8 text-ink-gray-4"},null,8,["name"])]),n("h3",f,a(e.title),1),e.description?(t(),s("p",y,a(e.description),1)):l("",!0),d(i.$slots,"action")]))}};export{p as _};
|
import{o as t,c as s,b as n,d as r,e as c,F as o,t as a,i as l,P as d}from"./index-0ce49f30.js";const m={class:"flex flex-col items-center justify-center py-12 text-center"},u={class:"mb-4 flex h-16 w-16 items-center justify-center rounded-full bg-surface-gray-2"},f={class:"mb-2 text-lg font-medium text-ink-gray-9"},y={key:0,class:"mb-4 max-w-sm text-sm text-ink-gray-5"},p={__name:"EmptyState",props:{icon:{type:String,default:"inbox"},title:{type:String,required:!0},description:{type:String,default:""}},setup(e){return(i,x)=>(t(),s("div",m,[n("div",u,[r(c(o),{name:e.icon,class:"h-8 w-8 text-ink-gray-4"},null,8,["name"])]),n("h3",f,a(e.title),1),e.description?(t(),s("p",y,a(e.description),1)):l("",!0),d(i.$slots,"action")]))}};export{p as _};
|
||||||
//# sourceMappingURL=EmptyState-1ecba3e9.js.map
|
//# sourceMappingURL=EmptyState-a30cc5b3.js.map
|
||||||
|
|
@ -1 +1 @@
|
||||||
{"version":3,"file":"EmptyState-1ecba3e9.js","sources":["../../../../frontend/src/components/Common/EmptyState.vue"],"sourcesContent":["<template>\n <div class=\"flex flex-col items-center justify-center py-12 text-center\">\n <div\n class=\"mb-4 flex h-16 w-16 items-center justify-center rounded-full bg-surface-gray-2\"\n >\n <FeatherIcon :name=\"icon\" class=\"h-8 w-8 text-ink-gray-4\" />\n </div>\n <h3 class=\"mb-2 text-lg font-medium text-ink-gray-9\">\n {{ title }}\n </h3>\n <p v-if=\"description\" class=\"mb-4 max-w-sm text-sm text-ink-gray-5\">\n {{ description }}\n </p>\n <slot name=\"action\" />\n </div>\n</template>\n\n<script setup>\nimport { FeatherIcon } from 'frappe-ui'\n\ndefineProps({\n icon: {\n type: String,\n default: 'inbox',\n },\n title: {\n type: String,\n required: true,\n },\n description: {\n type: String,\n default: '',\n },\n})\n</script>\n"],"names":["_openBlock","_createElementBlock","_hoisted_1","_createElementVNode","_hoisted_2","_createVNode","_unref","FeatherIcon","__props","_hoisted_3","_toDisplayString","_hoisted_4","_renderSlot","_ctx"],"mappings":"ohBACEA,EAAA,EAAAC,EAaM,MAbNC,EAaM,CAZJC,EAIM,MAJNC,EAIM,CADJC,EAA4DC,EAAAC,CAAA,EAAA,CAA9C,KAAMC,EAAI,KAAE,MAAM,8CAElCL,EAEK,KAFLM,EAEKC,EADAF,EAAK,KAAA,EAAA,CAAA,EAEDA,EAAW,iBAApBP,EAEI,IAFJU,EAEID,EADCF,EAAW,WAAA,EAAA,CAAA,YAEhBI,EAAsBC,EAAA,OAAA,QAAA"}
|
{"version":3,"file":"EmptyState-a30cc5b3.js","sources":["../../../../frontend/src/components/Common/EmptyState.vue"],"sourcesContent":["<template>\n <div class=\"flex flex-col items-center justify-center py-12 text-center\">\n <div\n class=\"mb-4 flex h-16 w-16 items-center justify-center rounded-full bg-surface-gray-2\"\n >\n <FeatherIcon :name=\"icon\" class=\"h-8 w-8 text-ink-gray-4\" />\n </div>\n <h3 class=\"mb-2 text-lg font-medium text-ink-gray-9\">\n {{ title }}\n </h3>\n <p v-if=\"description\" class=\"mb-4 max-w-sm text-sm text-ink-gray-5\">\n {{ description }}\n </p>\n <slot name=\"action\" />\n </div>\n</template>\n\n<script setup>\nimport { FeatherIcon } from 'frappe-ui'\n\ndefineProps({\n icon: {\n type: String,\n default: 'inbox',\n },\n title: {\n type: String,\n required: true,\n },\n description: {\n type: String,\n default: '',\n },\n})\n</script>\n"],"names":["_openBlock","_createElementBlock","_hoisted_1","_createElementVNode","_hoisted_2","_createVNode","_unref","FeatherIcon","__props","_hoisted_3","_toDisplayString","_hoisted_4","_renderSlot","_ctx"],"mappings":"ohBACEA,EAAA,EAAAC,EAaM,MAbNC,EAaM,CAZJC,EAIM,MAJNC,EAIM,CADJC,EAA4DC,EAAAC,CAAA,EAAA,CAA9C,KAAMC,EAAI,KAAE,MAAM,8CAElCL,EAEK,KAFLM,EAEKC,EADAF,EAAK,KAAA,EAAA,CAAA,EAEDA,EAAW,iBAApBP,EAEI,IAFJU,EAEID,EADCF,EAAW,WAAA,EAAA,CAAA,YAEhBI,EAAsBC,EAAA,OAAA,QAAA"}
|
||||||
|
|
@ -1,2 +1,2 @@
|
||||||
import{o as a,c as r,b as e,P as s,t as i}from"./index-5e93ecd0.js";const c={class:"flex items-center justify-between border-b bg-surface-white px-5 py-2.5"},l={class:"flex items-center gap-2"},n={class:"text-xl font-semibold text-ink-gray-9"},d={class:"flex items-center gap-2"},f={__name:"LayoutHeader",props:{title:{type:String,default:""}},setup(o){return(t,_)=>(a(),r("header",c,[e("div",l,[s(t.$slots,"left",{},()=>[e("h1",n,i(o.title),1)])]),e("div",d,[s(t.$slots,"right")])]))}};export{f as _};
|
import{o as a,c as r,b as e,P as s,t as i}from"./index-0ce49f30.js";const c={class:"flex items-center justify-between border-b bg-surface-white px-5 py-2.5"},l={class:"flex items-center gap-2"},n={class:"text-xl font-semibold text-ink-gray-9"},d={class:"flex items-center gap-2"},f={__name:"LayoutHeader",props:{title:{type:String,default:""}},setup(o){return(t,_)=>(a(),r("header",c,[e("div",l,[s(t.$slots,"left",{},()=>[e("h1",n,i(o.title),1)])]),e("div",d,[s(t.$slots,"right")])]))}};export{f as _};
|
||||||
//# sourceMappingURL=LayoutHeader-596b102d.js.map
|
//# sourceMappingURL=LayoutHeader-15280106.js.map
|
||||||
|
|
@ -1 +1 @@
|
||||||
{"version":3,"file":"LayoutHeader-596b102d.js","sources":["../../../../frontend/src/components/Common/LayoutHeader.vue"],"sourcesContent":["<template>\n <header class=\"flex items-center justify-between border-b bg-surface-white px-5 py-2.5\">\n <div class=\"flex items-center gap-2\">\n <slot name=\"left\">\n <h1 class=\"text-xl font-semibold text-ink-gray-9\">\n {{ title }}\n </h1>\n </slot>\n </div>\n <div class=\"flex items-center gap-2\">\n <slot name=\"right\" />\n </div>\n </header>\n</template>\n\n<script setup>\ndefineProps({\n title: {\n type: String,\n default: '',\n },\n})\n</script>\n"],"names":["_openBlock","_createElementBlock","_hoisted_1","_createElementVNode","_hoisted_2","_renderSlot","_ctx","_hoisted_3","_toDisplayString","__props","_hoisted_4"],"mappings":"+WACEA,EAAA,EAAAC,EAWS,SAXTC,EAWS,CAVPC,EAMM,MANNC,EAMM,CALJC,EAIOC,mBAJP,IAIO,CAHLH,EAEK,KAFLI,EAEKC,EADAC,EAAK,KAAA,EAAA,CAAA,MAIdN,EAEM,MAFNO,EAEM,CADJL,EAAqBC,EAAA,OAAA,OAAA"}
|
{"version":3,"file":"LayoutHeader-15280106.js","sources":["../../../../frontend/src/components/Common/LayoutHeader.vue"],"sourcesContent":["<template>\n <header class=\"flex items-center justify-between border-b bg-surface-white px-5 py-2.5\">\n <div class=\"flex items-center gap-2\">\n <slot name=\"left\">\n <h1 class=\"text-xl font-semibold text-ink-gray-9\">\n {{ title }}\n </h1>\n </slot>\n </div>\n <div class=\"flex items-center gap-2\">\n <slot name=\"right\" />\n </div>\n </header>\n</template>\n\n<script setup>\ndefineProps({\n title: {\n type: String,\n default: '',\n },\n})\n</script>\n"],"names":["_openBlock","_createElementBlock","_hoisted_1","_createElementVNode","_hoisted_2","_renderSlot","_ctx","_hoisted_3","_toDisplayString","__props","_hoisted_4"],"mappings":"+WACEA,EAAA,EAAAC,EAWS,SAXTC,EAWS,CAVPC,EAMM,MANNC,EAMM,CALJC,EAIOC,mBAJP,IAIO,CAHLH,EAEK,KAFLI,EAEKC,EADAC,EAAK,KAAA,EAAA,CAAA,MAIdN,EAEM,MAFNO,EAEM,CADJL,EAAqBC,EAAA,OAAA,OAAA"}
|
||||||
|
|
@ -1,2 +1,2 @@
|
||||||
import{u as b,a as _,o as f,c as y,b as e,d as r,t as a,w as x,e as n,f as w,v as k,g as V,h as $,i as B,r as o,A as L,_ as p,j as M,k as N,l as j,m as q,s as A}from"./index-5e93ecd0.js";const C={class:"min-h-screen flex items-center justify-center bg-surface-gray-2 py-12 px-4 sm:px-6 lg:px-8"},U={class:"max-w-md w-full space-y-8"},D={class:"text-center"},P={class:"mt-2 text-sm text-ink-gray-5"},R={class:"space-y-4"},S={for:"email",class:"block text-sm font-medium text-ink-gray-7"},E={for:"password",class:"block text-sm font-medium text-ink-gray-7"},T={class:"flex items-center justify-between"},z={class:"flex items-center"},F={for:"remember-me",class:"ml-2 block text-sm text-ink-gray-7"},G={class:"text-sm"},H={href:"#",class:"font-medium text-blue-600 hover:text-blue-500"},K={__name:"Login",setup(I){const h=b(),v=_(),d=o(""),u=o(""),c=o(!1),m=o(!1),i=o("");async function g(){m.value=!0,i.value="";try{await q("login",{usr:d.value,pwd:u.value}),await A.init();const s=v.query.redirect||"/dashboard";h.push(s)}catch(s){i.value=s.message||"Login failed"}finally{m.value=!1}}return(s,t)=>(f(),y("div",C,[e("div",U,[e("div",D,[r(L,{class:"mx-auto h-16 w-16"}),t[3]||(t[3]=e("h2",{class:"mt-6 text-3xl font-bold text-ink-gray-9"}," Admin Panel ",-1)),e("p",P,a(s.$t("auth.login")),1)]),e("form",{class:"mt-8 space-y-6",onSubmit:x(g,["prevent"])},[e("div",R,[e("div",null,[e("label",S,a(s.$t("auth.email")),1),r(n(p),{id:"email",modelValue:d.value,"onUpdate:modelValue":t[0]||(t[0]=l=>d.value=l),type:"email",required:"",class:"mt-1",placeholder:s.$t("auth.email")},null,8,["modelValue","placeholder"])]),e("div",null,[e("label",E,a(s.$t("auth.password")),1),r(n(p),{id:"password",modelValue:u.value,"onUpdate:modelValue":t[1]||(t[1]=l=>u.value=l),type:"password",required:"",class:"mt-1",placeholder:s.$t("auth.password")},null,8,["modelValue","placeholder"])])]),e("div",T,[e("div",z,[w(e("input",{id:"remember-me","onUpdate:modelValue":t[2]||(t[2]=l=>c.value=l),type:"checkbox",class:"h-4 w-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500"},null,512),[[k,c.value]]),e("label",F,a(s.$t("auth.rememberMe")),1)]),e("div",G,[e("a",H,a(s.$t("auth.forgotPassword")),1)])]),e("div",null,[r(n(N),{type:"submit",variant:"solid",class:"w-full",loading:m.value},{default:V(()=>[M(a(s.$t("auth.loginButton")),1)]),_:1},8,["loading"])]),i.value?(f(),$(n(j),{key:0,message:i.value},null,8,["message"])):B("",!0)],32)])]))}};export{K as default};
|
import{u as b,a as _,o as f,c as y,b as e,d as r,t as a,w as x,e as n,f as w,v as k,g as V,h as $,i as B,r as o,A as L,_ as p,j as M,k as N,l as j,m as q,s as A}from"./index-0ce49f30.js";const C={class:"min-h-screen flex items-center justify-center bg-surface-gray-2 py-12 px-4 sm:px-6 lg:px-8"},U={class:"max-w-md w-full space-y-8"},D={class:"text-center"},P={class:"mt-2 text-sm text-ink-gray-5"},R={class:"space-y-4"},S={for:"email",class:"block text-sm font-medium text-ink-gray-7"},E={for:"password",class:"block text-sm font-medium text-ink-gray-7"},T={class:"flex items-center justify-between"},z={class:"flex items-center"},F={for:"remember-me",class:"ml-2 block text-sm text-ink-gray-7"},G={class:"text-sm"},H={href:"#",class:"font-medium text-blue-600 hover:text-blue-500"},K={__name:"Login",setup(I){const h=b(),v=_(),d=o(""),u=o(""),c=o(!1),m=o(!1),i=o("");async function g(){m.value=!0,i.value="";try{await q("login",{usr:d.value,pwd:u.value}),await A.init();const s=v.query.redirect||"/dashboard";h.push(s)}catch(s){i.value=s.message||"Login failed"}finally{m.value=!1}}return(s,t)=>(f(),y("div",C,[e("div",U,[e("div",D,[r(L,{class:"mx-auto h-16 w-16"}),t[3]||(t[3]=e("h2",{class:"mt-6 text-3xl font-bold text-ink-gray-9"}," Admin Panel ",-1)),e("p",P,a(s.$t("auth.login")),1)]),e("form",{class:"mt-8 space-y-6",onSubmit:x(g,["prevent"])},[e("div",R,[e("div",null,[e("label",S,a(s.$t("auth.email")),1),r(n(p),{id:"email",modelValue:d.value,"onUpdate:modelValue":t[0]||(t[0]=l=>d.value=l),type:"email",required:"",class:"mt-1",placeholder:s.$t("auth.email")},null,8,["modelValue","placeholder"])]),e("div",null,[e("label",E,a(s.$t("auth.password")),1),r(n(p),{id:"password",modelValue:u.value,"onUpdate:modelValue":t[1]||(t[1]=l=>u.value=l),type:"password",required:"",class:"mt-1",placeholder:s.$t("auth.password")},null,8,["modelValue","placeholder"])])]),e("div",T,[e("div",z,[w(e("input",{id:"remember-me","onUpdate:modelValue":t[2]||(t[2]=l=>c.value=l),type:"checkbox",class:"h-4 w-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500"},null,512),[[k,c.value]]),e("label",F,a(s.$t("auth.rememberMe")),1)]),e("div",G,[e("a",H,a(s.$t("auth.forgotPassword")),1)])]),e("div",null,[r(n(N),{type:"submit",variant:"solid",class:"w-full",loading:m.value},{default:V(()=>[M(a(s.$t("auth.loginButton")),1)]),_:1},8,["loading"])]),i.value?(f(),$(n(j),{key:0,message:i.value},null,8,["message"])):B("",!0)],32)])]))}};export{K as default};
|
||||||
//# sourceMappingURL=Login-3b5a2007.js.map
|
//# sourceMappingURL=Login-47accf47.js.map
|
||||||
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,2 +1,2 @@
|
||||||
import{o,c as a,b as e,d as r,g as n,e as i,j as d,k as l}from"./index-5e93ecd0.js";const x={class:"min-h-screen flex items-center justify-center bg-surface-gray-2 py-12 px-4"},u={class:"text-center"},g={__name:"NotFound",setup(f){return(s,t)=>(o(),a("div",x,[e("div",u,[t[2]||(t[2]=e("h1",{class:"text-9xl font-bold text-ink-gray-2"},"404",-1)),t[3]||(t[3]=e("h2",{class:"mt-4 text-2xl font-semibold text-ink-gray-9"}," Page Not Found ",-1)),t[4]||(t[4]=e("p",{class:"mt-2 text-ink-gray-5"}," The page you're looking for doesn't exist. ",-1)),r(i(l),{variant:"solid",class:"mt-6",onClick:t[0]||(t[0]=m=>s.$router.push("/dashboard"))},{default:n(()=>[...t[1]||(t[1]=[d(" Go to Dashboard ",-1)])]),_:1})])]))}};export{g as default};
|
import{o,c as a,b as e,d as r,g as n,e as i,j as d,k as l}from"./index-0ce49f30.js";const x={class:"min-h-screen flex items-center justify-center bg-surface-gray-2 py-12 px-4"},u={class:"text-center"},g={__name:"NotFound",setup(f){return(s,t)=>(o(),a("div",x,[e("div",u,[t[2]||(t[2]=e("h1",{class:"text-9xl font-bold text-ink-gray-2"},"404",-1)),t[3]||(t[3]=e("h2",{class:"mt-4 text-2xl font-semibold text-ink-gray-9"}," Page Not Found ",-1)),t[4]||(t[4]=e("p",{class:"mt-2 text-ink-gray-5"}," The page you're looking for doesn't exist. ",-1)),r(i(l),{variant:"solid",class:"mt-6",onClick:t[0]||(t[0]=m=>s.$router.push("/dashboard"))},{default:n(()=>[...t[1]||(t[1]=[d(" Go to Dashboard ",-1)])]),_:1})])]))}};export{g as default};
|
||||||
//# sourceMappingURL=NotFound-62e4f85b.js.map
|
//# sourceMappingURL=NotFound-21e4d5b3.js.map
|
||||||
|
|
@ -1 +1 @@
|
||||||
{"version":3,"file":"NotFound-62e4f85b.js","sources":["../../../../frontend/src/pages/admin/NotFound.vue"],"sourcesContent":["<template>\n <div class=\"min-h-screen flex items-center justify-center bg-surface-gray-2 py-12 px-4\">\n <div class=\"text-center\">\n <h1 class=\"text-9xl font-bold text-ink-gray-2\">404</h1>\n <h2 class=\"mt-4 text-2xl font-semibold text-ink-gray-9\">\n Page Not Found\n </h2>\n <p class=\"mt-2 text-ink-gray-5\">\n The page you're looking for doesn't exist.\n </p>\n <Button\n variant=\"solid\"\n class=\"mt-6\"\n @click=\"$router.push('/dashboard')\"\n >\n Go to Dashboard\n </Button>\n </div>\n </div>\n</template>\n\n<script setup>\nimport { Button } from 'frappe-ui'\n</script>\n"],"names":["_openBlock","_createElementBlock","_hoisted_1","_createElementVNode","_hoisted_2","_cache","_createVNode","_unref","Button","$event","$router"],"mappings":"qPACEA,EAAA,EAAAC,EAiBM,MAjBNC,EAiBM,CAhBJC,EAeM,MAfNC,EAeM,CAdJC,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAAF,EAAuD,KAAnD,CAAA,MAAM,oCAAoC,EAAC,MAAG,EAAA,GAClDE,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAAF,EAEK,KAFD,CAAA,MAAM,6CAA6C,EAAC,mBAExD,EAAA,GACAE,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAAF,EAEI,IAFD,CAAA,MAAM,sBAAsB,EAAC,+CAEhC,EAAA,GACAG,EAMSC,EAAAC,CAAA,EAAA,CALP,QAAQ,QACR,MAAM,OACL,QAAKH,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAAI,GAAEC,EAAO,QAAC,KAAI,YAAA,eACrB,IAED,CAAA,GAAAL,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAA,GAFC,oBAED,EAAA"}
|
{"version":3,"file":"NotFound-21e4d5b3.js","sources":["../../../../frontend/src/pages/admin/NotFound.vue"],"sourcesContent":["<template>\n <div class=\"min-h-screen flex items-center justify-center bg-surface-gray-2 py-12 px-4\">\n <div class=\"text-center\">\n <h1 class=\"text-9xl font-bold text-ink-gray-2\">404</h1>\n <h2 class=\"mt-4 text-2xl font-semibold text-ink-gray-9\">\n Page Not Found\n </h2>\n <p class=\"mt-2 text-ink-gray-5\">\n The page you're looking for doesn't exist.\n </p>\n <Button\n variant=\"solid\"\n class=\"mt-6\"\n @click=\"$router.push('/dashboard')\"\n >\n Go to Dashboard\n </Button>\n </div>\n </div>\n</template>\n\n<script setup>\nimport { Button } from 'frappe-ui'\n</script>\n"],"names":["_openBlock","_createElementBlock","_hoisted_1","_createElementVNode","_hoisted_2","_cache","_createVNode","_unref","Button","$event","$router"],"mappings":"qPACEA,EAAA,EAAAC,EAiBM,MAjBNC,EAiBM,CAhBJC,EAeM,MAfNC,EAeM,CAdJC,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAAF,EAAuD,KAAnD,CAAA,MAAM,oCAAoC,EAAC,MAAG,EAAA,GAClDE,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAAF,EAEK,KAFD,CAAA,MAAM,6CAA6C,EAAC,mBAExD,EAAA,GACAE,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAAF,EAEI,IAFD,CAAA,MAAM,sBAAsB,EAAC,+CAEhC,EAAA,GACAG,EAMSC,EAAAC,CAAA,EAAA,CALP,QAAQ,QACR,MAAM,OACL,QAAKH,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAAI,GAAEC,EAAO,QAAC,KAAI,YAAA,eACrB,IAED,CAAA,GAAAL,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAA,GAFC,oBAED,EAAA"}
|
||||||
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 +0,0 @@
|
||||||
.migrate-progress[data-v-1d4c10fc]{animation:migrate-bar-1d4c10fc 3s ease-in-out infinite}@keyframes migrate-bar-1d4c10fc{0%{width:5%}50%{width:70%}to{width:95%}}
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
.migrate-progress[data-v-f33d4570]{animation:migrate-bar-f33d4570 3s ease-in-out infinite}@keyframes migrate-bar-f33d4570{0%{width:5%}50%{width:70%}to{width:95%}}
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -1,2 +1,2 @@
|
||||||
import{n as s,o as c,c as u,b as r,E as i,d as o,e as d,F as g,t as l,i as m}from"./index-5e93ecd0.js";const p={class:"rounded-lg border p-4 shadow-sm"},v={class:"flex items-center justify-between"},h={class:"flex items-center gap-3"},w={class:"text-sm text-ink-gray-5"},N={class:"text-2xl font-semibold text-ink-gray-9"},k={class:"text-sm font-medium"},S={key:0,class:"mt-2 text-xs text-ink-gray-5"},F={__name:"StatCard",props:{label:{type:String,required:!0},value:{type:[Number,String],required:!0},iconName:{type:String,default:"activity"},color:{type:String,default:"blue",validator:e=>["blue","green","red","yellow","purple","gray"].includes(e)},trend:{type:Number,default:void 0},subtitle:{type:String,default:""},format:{type:String,default:"number",validator:e=>["number","currency","percent"].includes(e)}},setup(e){const n=e,a={blue:{bg:"bg-blue-100",icon:"text-blue-600"},green:{bg:"bg-green-100",icon:"text-green-600"},red:{bg:"bg-red-100",icon:"text-red-600"},yellow:{bg:"bg-orange-100",icon:"text-orange-600"},purple:{bg:"bg-purple-100",icon:"text-purple-600"},gray:{bg:"bg-surface-gray-2",icon:"text-ink-gray-5"}},b=s(()=>{var t;return((t=a[n.color])==null?void 0:t.bg)||a.blue.bg}),f=s(()=>{var t;return((t=a[n.color])==null?void 0:t.icon)||a.blue.icon}),y=s(()=>n.trend>0?"text-green-600":n.trend<0?"text-red-600":"text-ink-gray-5"),x=s(()=>{const t=typeof n.value=="number"?n.value:parseFloat(n.value);if(isNaN(t))return n.value;switch(n.format){case"currency":return new Intl.NumberFormat("ru-RU",{style:"currency",currency:"RUB",minimumFractionDigits:0}).format(t);case"percent":return`${t}%`;default:return new Intl.NumberFormat("ru-RU").format(t)}});return(t,C)=>(c(),u("div",p,[r("div",v,[r("div",h,[r("div",{class:i(["flex h-10 w-10 items-center justify-center rounded-lg",b.value])},[o(d(g),{name:e.iconName,class:i(["h-5 w-5",f.value])},null,8,["name","class"])],2),r("div",null,[r("p",w,l(e.label),1),r("p",N,l(x.value),1)])]),e.trend!==void 0?(c(),u("div",{key:0,class:i(["flex items-center gap-1",y.value])},[o(d(g),{name:e.trend>0?"trending-up":"trending-down",class:"h-4 w-4"},null,8,["name"]),r("span",k,l(Math.abs(e.trend))+"%",1)],2)):m("",!0)]),e.subtitle?(c(),u("div",S,l(e.subtitle),1)):m("",!0)]))}};export{F as _};
|
import{n as s,o as c,c as u,b as r,E as i,d as o,e as d,F as g,t as l,i as m}from"./index-0ce49f30.js";const p={class:"rounded-lg border p-4 shadow-sm"},v={class:"flex items-center justify-between"},h={class:"flex items-center gap-3"},w={class:"text-sm text-ink-gray-5"},N={class:"text-2xl font-semibold text-ink-gray-9"},k={class:"text-sm font-medium"},S={key:0,class:"mt-2 text-xs text-ink-gray-5"},F={__name:"StatCard",props:{label:{type:String,required:!0},value:{type:[Number,String],required:!0},iconName:{type:String,default:"activity"},color:{type:String,default:"blue",validator:e=>["blue","green","red","yellow","purple","gray"].includes(e)},trend:{type:Number,default:void 0},subtitle:{type:String,default:""},format:{type:String,default:"number",validator:e=>["number","currency","percent"].includes(e)}},setup(e){const n=e,a={blue:{bg:"bg-blue-100",icon:"text-blue-600"},green:{bg:"bg-green-100",icon:"text-green-600"},red:{bg:"bg-red-100",icon:"text-red-600"},yellow:{bg:"bg-orange-100",icon:"text-orange-600"},purple:{bg:"bg-purple-100",icon:"text-purple-600"},gray:{bg:"bg-surface-gray-2",icon:"text-ink-gray-5"}},b=s(()=>{var t;return((t=a[n.color])==null?void 0:t.bg)||a.blue.bg}),f=s(()=>{var t;return((t=a[n.color])==null?void 0:t.icon)||a.blue.icon}),y=s(()=>n.trend>0?"text-green-600":n.trend<0?"text-red-600":"text-ink-gray-5"),x=s(()=>{const t=typeof n.value=="number"?n.value:parseFloat(n.value);if(isNaN(t))return n.value;switch(n.format){case"currency":return new Intl.NumberFormat("ru-RU",{style:"currency",currency:"RUB",minimumFractionDigits:0}).format(t);case"percent":return`${t}%`;default:return new Intl.NumberFormat("ru-RU").format(t)}});return(t,C)=>(c(),u("div",p,[r("div",v,[r("div",h,[r("div",{class:i(["flex h-10 w-10 items-center justify-center rounded-lg",b.value])},[o(d(g),{name:e.iconName,class:i(["h-5 w-5",f.value])},null,8,["name","class"])],2),r("div",null,[r("p",w,l(e.label),1),r("p",N,l(x.value),1)])]),e.trend!==void 0?(c(),u("div",{key:0,class:i(["flex items-center gap-1",y.value])},[o(d(g),{name:e.trend>0?"trending-up":"trending-down",class:"h-4 w-4"},null,8,["name"]),r("span",k,l(Math.abs(e.trend))+"%",1)],2)):m("",!0)]),e.subtitle?(c(),u("div",S,l(e.subtitle),1)):m("",!0)]))}};export{F as _};
|
||||||
//# sourceMappingURL=StatCard-9cdf9951.js.map
|
//# sourceMappingURL=StatCard-1a7c512e.js.map
|
||||||
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
|
|
@ -15,7 +15,7 @@
|
||||||
document.documentElement.setAttribute('data-theme', isDark ? 'dark' : 'light');
|
document.documentElement.setAttribute('data-theme', isDark ? 'dark' : 'light');
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
<script type="module" crossorigin src="/assets/admin_panel/frontend/assets/index-5e93ecd0.js"></script>
|
<script type="module" crossorigin src="/assets/admin_panel/frontend/assets/index-0ce49f30.js"></script>
|
||||||
<link rel="stylesheet" href="/assets/admin_panel/frontend/assets/index-a640712b.css">
|
<link rel="stylesheet" href="/assets/admin_panel/frontend/assets/index-a640712b.css">
|
||||||
</head>
|
</head>
|
||||||
<body class="h-full">
|
<body class="h-full">
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@
|
||||||
document.documentElement.setAttribute('data-theme', isDark ? 'dark' : 'light');
|
document.documentElement.setAttribute('data-theme', isDark ? 'dark' : 'light');
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
<script type="module" crossorigin src="/assets/admin_panel/frontend/assets/index-5e93ecd0.js"></script>
|
<script type="module" crossorigin src="/assets/admin_panel/frontend/assets/index-0ce49f30.js"></script>
|
||||||
<link rel="stylesheet" href="/assets/admin_panel/frontend/assets/index-a640712b.css">
|
<link rel="stylesheet" href="/assets/admin_panel/frontend/assets/index-a640712b.css">
|
||||||
</head>
|
</head>
|
||||||
<body class="h-full">
|
<body class="h-full">
|
||||||
|
|
|
||||||
|
|
@ -21,4 +21,5 @@ def get_boot():
|
||||||
return {
|
return {
|
||||||
"csrf_token": frappe.sessions.get_csrf_token(),
|
"csrf_token": frappe.sessions.get_csrf_token(),
|
||||||
"user": frappe.session.user,
|
"user": frappe.session.user,
|
||||||
|
"host_domain": frappe.conf.get("host_domain", "host.jeyerp.az"),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -85,12 +85,18 @@
|
||||||
</template>
|
</template>
|
||||||
{{ $t('common.delete') }}
|
{{ $t('common.delete') }}
|
||||||
</Button>
|
</Button>
|
||||||
<Button variant="solid" @click="openSite">
|
<Button variant="subtle" @click="openSite">
|
||||||
<template #prefix>
|
<template #prefix>
|
||||||
<FeatherIcon name="external-link" class="h-4 w-4" />
|
<FeatherIcon name="external-link" class="h-4 w-4" />
|
||||||
</template>
|
</template>
|
||||||
{{ $t('sites.actions.openSite') }}
|
{{ $t('sites.actions.openSite') }}
|
||||||
</Button>
|
</Button>
|
||||||
|
<Button variant="solid" @click="loginAsAdmin" :loading="actionLoading === 'login'">
|
||||||
|
<template #prefix>
|
||||||
|
<FeatherIcon name="log-in" class="h-4 w-4" />
|
||||||
|
</template>
|
||||||
|
Login
|
||||||
|
</Button>
|
||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
</LayoutHeader>
|
</LayoutHeader>
|
||||||
|
|
@ -967,9 +973,35 @@ async function runBenchMigrate() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getSiteUrl() {
|
||||||
|
const hostDomain = window.host_domain || 'host.jeyerp.az'
|
||||||
|
const containerName = route.params.siteId
|
||||||
|
return `http://${containerName}.${hostDomain}`
|
||||||
|
}
|
||||||
|
|
||||||
function openSite() {
|
function openSite() {
|
||||||
if (site.value?.ip_address) {
|
window.open(getSiteUrl(), '_blank')
|
||||||
window.open(`http://${site.value.ip_address}`, '_blank')
|
}
|
||||||
|
|
||||||
|
async function loginAsAdmin() {
|
||||||
|
actionLoading.value = 'login'
|
||||||
|
try {
|
||||||
|
const result = await call('admin_panel.api.sites.get_login_url', {
|
||||||
|
container_name: route.params.siteId,
|
||||||
|
target_server: site.value?.server,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (result.success) {
|
||||||
|
// Frappe reads sid from query params (frappe.form_dict) before cookies
|
||||||
|
const siteUrl = getSiteUrl()
|
||||||
|
window.open(`${siteUrl}/app/setup-wizard?sid=${result.sid}`, '_blank')
|
||||||
|
} else {
|
||||||
|
actionError.value = result.error || 'Failed to generate login URL'
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
actionError.value = error.message || 'Failed to login'
|
||||||
|
} finally {
|
||||||
|
actionLoading.value = ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue