feat(training): delete group button (admin only) on Training page

- Backend DELETE /api/groups/<gid> (admin, own-org enforced via _get_owned_group);
  cascades removal of the group's sessions. GroupStore.delete added.
- Training.vue: each group card gets a trash (Trash2 line icon) delete button shown only
  to admins (auth.isAdmin); confirm dialog; @click.stop so it doesn't navigate. Card
  restructured so the delete button is not inside the clickable router-link.
- test_user_journey: trainee cannot delete (403), admin deletes, group gone (404).
All suites pass. Rebuilt dist.
This commit is contained in:
Macky
2026-08-09 10:20:10 +07:00
parent 0b92430aab
commit 5b167b4546
30 changed files with 114 additions and 43 deletions

11
frontend/dist/assets/Login-BxCw0ggt.js vendored Normal file
View File

@@ -0,0 +1,11 @@
import{c as k,_ as x,a as y,b as e,t as l,u as a,i as n,w as h,v as M,d as w,e as B,f as _,g as E,r,h as f,j as S,k as V,o as s}from"./index-CvsGOA4u.js";/**
* @license lucide-vue-next v1.0.0 - ISC
*
* This source code is licensed under the ISC license.
* See the LICENSE file in the root directory of this source tree.
*/const z=k("eye-off",[["path",{d:"M10.733 5.076a10.744 10.744 0 0 1 11.205 6.575 1 1 0 0 1 0 .696 10.747 10.747 0 0 1-1.444 2.49",key:"ct8e1f"}],["path",{d:"M14.084 14.158a3 3 0 0 1-4.242-4.242",key:"151rxh"}],["path",{d:"M17.479 17.499a10.75 10.75 0 0 1-15.417-5.151 1 1 0 0 1 0-.696 10.75 10.75 0 0 1 4.446-5.143",key:"13bj9a"}],["path",{d:"m2 2 20 20",key:"1ooewy"}]]);/**
* @license lucide-vue-next v1.0.0 - ISC
*
* This source code is licensed under the ISC license.
* See the LICENSE file in the root directory of this source tree.
*/const C=k("eye",[["path",{d:"M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0",key:"1nclc0"}],["circle",{cx:"12",cy:"12",r:"3",key:"1v7zrd"}]]),D={class:"login-wrap"},K={class:"card login-card"},L={class:"pw-wrap"},j=["type"],I=["aria-label"],N={key:0,class:"error",role:"alert"},R=["disabled"],U={key:0,class:"spinner"},q={key:1},H={__name:"Login",setup(O){const g=V(),m=S(),u=r(""),i=r(""),o=r(!1),d=r(""),c=r(!1);async function v(){d.value="",c.value=!0;try{await f.login(u.value.trim(),i.value),f.mustSetup?m.push({path:"/setup"}):m.push(g.query.redirect||"/")}catch{d.value=n.t("loginError")}finally{c.value=!1}}return(b,t)=>(s(),y("div",D,[e("div",K,[e("h1",null,l(a(n).t("app")),1),t[3]||(t[3]=e("p",{class:"muted",style:{"margin-top":"-8px"}},"Sales training simulator",-1)),e("label",null,l(a(n).t("username")),1),h(e("input",{"onUpdate:modelValue":t[0]||(t[0]=p=>u.value=p),type:"text",autocomplete:"username",placeholder:"username",class:"wide",onKeyup:w(v,["enter"])},null,544),[[M,u.value]]),e("label",null,l(a(n).t("password")),1),e("div",L,[h(e("input",{"onUpdate:modelValue":t[1]||(t[1]=p=>i.value=p),type:o.value?"text":"password",autocomplete:"current-password",placeholder:"••••••••",class:"wide",onKeyup:w(v,["enter"])},null,40,j),[[B,i.value]]),e("button",{type:"button",class:"pw-toggle",onClick:t[2]||(t[2]=p=>o.value=!o.value),"aria-label":o.value?"Hide password":"Show password"},[o.value?(s(),_(a(z),{key:0,size:20,"stroke-width":1.8})):(s(),_(a(C),{key:1,size:20,"stroke-width":1.8}))],8,I)]),d.value?(s(),y("div",N,l(d.value),1)):E("",!0),e("button",{class:"primary",style:{width:"100%","margin-top":"18px"},disabled:c.value||!u.value||!i.value,onClick:v},[c.value?(s(),y("span",U)):(s(),y("span",q,l(a(n).t("login")),1))],8,R)])]))}},T=x(H,[["__scopeId","data-v-491f49d6"]]);export{T as default};