1 line
16 KiB
JavaScript
1 line
16 KiB
JavaScript
import{a as o,j as e}from"./vendor-react-BHG7lGYR.js";import{a as C,d as N,g as O,B as L,D as $,p as k,l as ne,L as ie,E as Y,C as B,b as H,c as G,e as J,y as Q}from"./index-BWcMVITa.js";import{r as q}from"./features-6vY6zDlz.js";import{q as S}from"./vendor-IYr-MHu4.js";import{B as P}from"./badge-CPAgRIoX.js";import{I as _}from"./input-BGBI2Wze.js";import{L as y}from"./label-N1Bsuay_.js";import{T as V}from"./textarea-If6sHLPh.js";import{ah as le,i as W,_ as ce,aJ as de,T as me,aI as K}from"./vendor-icons-DaGlTw4_.js";import{S as ue}from"./select-laDQECdR.js";import"./vendor-router-D-s5vIeO.js";import"./vendor-tanstack-BzWBL1hV.js";import"./vendor-utils-CgOSfOkx.js";import"./dropdown-BYn_8IId.js";async function he(){try{const r=await C.get("/roles");return Array.isArray(r.data)?r.data:[]}catch(r){if(r instanceof S){if(r.response?.status===401)throw new Error("Unauthorized: Please log in to access roles");if(r.response?.status===403)throw new Error("Forbidden: You do not have permission to view roles");const s=r.response?.data?.error||r.message||"Failed to fetch roles";throw new Error(s)}throw r}}async function pe(r){try{return(await C.get(`/roles/${r}`)).data}catch(s){if(s instanceof S){if(s.response?.status===401)throw new Error("Unauthorized: Please log in to access role");if(s.response?.status===403)throw new Error("Forbidden: You do not have permission to view this role");if(s.response?.status===404)throw new Error("Role not found");const t=s.response?.data?.error||s.message||"Failed to fetch role";throw new Error(t)}throw s}}async function xe(r){try{return(await C.get(`/users/${r}/roles`)).data.roles||[]}catch(s){if(s instanceof S){if(s.response?.status===401)throw new Error("Unauthorized: Please log in to access user roles");if(s.response?.status===403)throw new Error("Forbidden: You do not have permission to view user roles");if(s.response?.status===404)throw new Error("User not found");const t=s.response?.data?.error||s.message||"Failed to fetch user roles";throw new Error(t)}throw s}}async function fe(r,s){q("ROLE_MANAGEMENT");try{await C.post(`/users/${r}/roles`,s)}catch(t){if(t instanceof S){if(t.response?.status===400){const m=t.response?.data?.error||"Invalid request data";throw new Error(m)}if(t.response?.status===401)throw new Error("Unauthorized: Please log in to assign roles");if(t.response?.status===403)throw new Error("Forbidden: You do not have permission to assign roles");if(t.response?.status===404)throw new Error("User or role not found");const l=t.response?.data?.error||t.message||"Failed to assign role";throw new Error(l)}throw t}}async function ge(r){try{return(await C.post("/roles",r)).data.role}catch(s){if(s instanceof S){if(s.response?.status===400){const l=s.response?.data?.error||"Invalid role data";throw new Error(l)}if(s.response?.status===401)throw new Error("Unauthorized: Please log in to create roles");if(s.response?.status===403)throw new Error("Forbidden: You do not have permission to create roles");const t=s.response?.data?.error||s.message||"Failed to create role";throw new Error(t)}throw s}}async function X(r,s){q("ROLE_MANAGEMENT");try{await C.put(`/roles/${r}`,s)}catch(t){if(t instanceof S){if(t.response?.status===400){const m=t.response?.data?.error||"Invalid role data";throw new Error(m)}if(t.response?.status===401)throw new Error("Unauthorized: Please log in to update roles");if(t.response?.status===403)throw new Error("Forbidden: You do not have permission to update roles");if(t.response?.status===404)throw new Error("Role not found or is a system role");const l=t.response?.data?.error||t.message||"Failed to update role";throw new Error(l)}throw t}}async function ye(r){q("ROLE_MANAGEMENT");try{await C.delete(`/roles/${r}`)}catch(s){if(s instanceof S){if(s.response?.status===400){const l=s.response?.data?.error||"Cannot delete system role";throw new Error(l)}if(s.response?.status===401)throw new Error("Unauthorized: Please log in to delete roles");if(s.response?.status===403)throw new Error("Forbidden: You do not have permission to delete roles");if(s.response?.status===404)throw new Error("Role not found");const t=s.response?.data?.error||s.message||"Failed to delete role";throw new Error(t)}throw s}}const Z=o.forwardRef(({className:r,"aria-label":s,"aria-labelledby":t,...l},m)=>e.jsx("div",{className:"relative w-full overflow-auto",children:e.jsx("table",{ref:m,className:N("w-full caption-bottom text-sm",r),"aria-label":s,"aria-labelledby":t,...l})}));Z.displayName="Table";const ee=o.forwardRef(({className:r,...s},t)=>e.jsx("thead",{ref:t,className:N("[&_tr]:border-b border-kodo-steel",r),...s}));ee.displayName="TableHeader";const se=o.forwardRef(({className:r,...s},t)=>e.jsx("tbody",{ref:t,className:N("[&_tr:last-child]:border-0",r),...s}));se.displayName="TableBody";const je=o.forwardRef(({className:r,...s},t)=>e.jsx("tfoot",{ref:t,className:N("border-t border-kodo-steel bg-kodo-steel/30 font-medium [&>tr]:last:border-b-0",r),...s}));je.displayName="TableFooter";const z=o.forwardRef(({className:r,...s},t)=>e.jsx("tr",{ref:t,className:N("border-b border-kodo-steel transition-colors hover:bg-white/5 data-[state=selected]:bg-white/10",r),...s}));z.displayName="TableRow";const v=o.forwardRef(({className:r,...s},t)=>e.jsx("th",{ref:t,className:N("h-12 px-4 text-left align-middle font-bold text-kodo-content-dim uppercase tracking-wider [&:has([role=checkbox])]:pr-0",r),...s}));v.displayName="TableHead";const b=o.forwardRef(({className:r,...s},t)=>e.jsx("td",{ref:t,className:N("p-4 align-middle [&:has([role=checkbox])]:pr-0 text-kodo-text-main",r),...s}));b.displayName="TableCell";const we=o.forwardRef(({className:r,...s},t)=>e.jsx("caption",{ref:t,className:N("mt-4 text-sm text-kodo-content-dim",r),...s}));we.displayName="TableCaption";function ve({onRoleCreated:r}){const[s,t]=o.useState(!1),[l,m]=o.useState(!1),[d,x]=o.useState({name:"",display_name:"",description:"",is_active:!0}),{success:u,error:h}=O(),p=async()=>{m(!0);try{await ge(d),u("Role created successfully"),t(!1),x({name:"",display_name:"",description:"",is_active:!0}),r(),x({name:"",display_name:"",description:"",is_active:!0}),r()}catch(c){const f=k(c);h(f.message)}finally{m(!1)}};return e.jsxs(e.Fragment,{children:[e.jsxs(L,{onClick:()=>t(!0),children:[e.jsx(le,{className:"h-4 w-4 mr-2"}),"Create Role"]}),e.jsx($,{open:s,onClose:()=>t(!1),title:"Create New Role",onConfirm:p,confirmLabel:l?"Creating...":"Create Role",cancelLabel:"Cancel",children:e.jsxs("form",{onSubmit:c=>{c.preventDefault(),p()},className:"space-y-4",children:[e.jsxs("div",{children:[e.jsx(y,{htmlFor:"name",children:"Name *"}),e.jsx(_,{id:"name",value:d.name,onChange:c=>x({...d,name:c.target.value}),placeholder:"e.g., content_moderator",required:!0})]}),e.jsxs("div",{children:[e.jsx(y,{htmlFor:"display_name",children:"Display Name *"}),e.jsx(_,{id:"display_name",value:d.display_name,onChange:c=>x({...d,display_name:c.target.value}),placeholder:"e.g., Content Moderator",required:!0})]}),e.jsxs("div",{children:[e.jsx(y,{htmlFor:"description",children:"Description"}),e.jsx(V,{id:"description",value:d.description,onChange:c=>x({...d,description:c.target.value}),placeholder:"Role description...",rows:3})]}),e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx("input",{type:"checkbox",id:"is_active",checked:d.is_active,onChange:c=>x({...d,is_active:c.target.checked}),className:"rounded"}),e.jsx(y,{htmlFor:"is_active",children:"Active"})]})]})})]})}function be({role:r,open:s,onClose:t,onRoleUpdated:l}){const[m,d]=o.useState(!1),[x,u]=o.useState(!1),[h,p]=o.useState({name:r.name,display_name:r.display_name,description:r.description,is_active:r.is_active}),{success:c,error:f}=O();o.useEffect(()=>{s&&r.id&&(u(!0),pe(r.id).then(i=>{p({name:i.name,display_name:i.display_name,description:i.description,is_active:i.is_active})}).catch(i=>{const j=k(i);f(j.message)}).finally(()=>{u(!1)}))},[s,r.id,f]);const g=async()=>{d(!0);try{await X(r.id,h),c("Role updated successfully"),t(),l()}catch(i){const j=k(i);f(j.message)}finally{d(!1)}};return e.jsx($,{open:s,onClose:t,title:"Edit Role",onConfirm:g,confirmLabel:m?"Updating...":"Update Role",cancelLabel:"Cancel",children:x?e.jsx("div",{className:"flex justify-center py-8",children:e.jsx(W,{className:"h-8 w-8 animate-spin"})}):e.jsxs("form",{onSubmit:i=>{i.preventDefault(),g()},className:"space-y-4",children:[e.jsxs("div",{children:[e.jsx(y,{htmlFor:"edit-name",children:"Name *"}),e.jsx(_,{id:"edit-name",value:h.name,onChange:i=>p({...h,name:i.target.value}),required:!0,disabled:r.is_system}),r.is_system&&e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:"System roles cannot be renamed"})]}),e.jsxs("div",{children:[e.jsx(y,{htmlFor:"edit-display_name",children:"Display Name *"}),e.jsx(_,{id:"edit-display_name",value:h.display_name,onChange:i=>p({...h,display_name:i.target.value}),required:!0})]}),e.jsxs("div",{children:[e.jsx(y,{htmlFor:"edit-description",children:"Description"}),e.jsx(V,{id:"edit-description",value:h.description,onChange:i=>p({...h,description:i.target.value}),rows:3})]}),e.jsxs("div",{className:"flex items-center space-x-2",children:[e.jsx("input",{type:"checkbox",id:"edit-is_active",checked:h.is_active,onChange:i=>p({...h,is_active:i.target.checked}),className:"rounded",disabled:r.is_system}),e.jsx(y,{htmlFor:"edit-is_active",children:"Active"}),r.is_system&&e.jsx("p",{className:"text-xs text-muted-foreground ml-2",children:"System roles are always active"})]})]})})}function Ne({userId:r,userName:s,availableRoles:t,open:l,onClose:m,onRoleAssigned:d}){const[x,u]=o.useState(!1),[h,p]=o.useState(!1),[c,f]=o.useState(""),[g,i]=o.useState(""),[j,D]=o.useState([]),{success:U,error:E}=O();o.useEffect(()=>{l&&r&&(p(!0),xe(r).then(n=>{D(n)}).catch(n=>{const R=k(n);ne.error("Failed to load user roles",{error:R.message,stack:n instanceof Error?n.stack:void 0,userId:r})}).finally(()=>{p(!1)}))},[l,r]);const F=async()=>{if(!c){E("Please select a role");return}u(!0);try{await fe(r,{role_id:c,expires_at:g||void 0}),U("Role assigned successfully"),m(),f(""),i(""),d(),i(""),d()}catch(n){const R=k(n);E(R.message)}finally{u(!1)}},M=t.filter(n=>!j.some(R=>R.id===n.id)),A=M.map(n=>({value:n.id,label:`${n.display_name} (${n.name})`}));return e.jsx($,{open:l,onClose:m,title:`Assign Role${s?` to ${s}`:""}`,onConfirm:F,confirmLabel:x?"Assigning...":"Assign Role",cancelLabel:"Cancel",children:h?e.jsx("div",{className:"flex justify-center py-8",children:e.jsx(W,{className:"h-8 w-8 animate-spin"})}):e.jsxs("form",{onSubmit:F,className:"space-y-4",children:[e.jsxs("div",{children:[e.jsx(y,{htmlFor:"role-select",children:"Role *"}),M.length===0?e.jsx("div",{className:"p-2 text-sm text-muted-foreground border rounded",children:"No available roles to assign"}):e.jsx(ue,{options:A,value:c,onChange:n=>f(Array.isArray(n)?n[0]:n),placeholder:"Select a role"})]}),e.jsxs("div",{children:[e.jsx(y,{htmlFor:"expires-at",children:"Expires At (optional)"}),e.jsx(_,{id:"expires-at",type:"datetime-local",value:g,onChange:n=>i(n.target.value)}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:"Leave empty for permanent assignment"})]}),j.length>0&&e.jsxs("div",{children:[e.jsx(y,{children:"Current Roles"}),e.jsx("div",{className:"mt-2 space-y-1",children:j.map(n=>e.jsxs("div",{className:"text-sm text-muted-foreground",children:["• ",n.display_name]},n.id))})]})]})})}function Pe(){const[r,s]=o.useState([]),[t,l]=o.useState(!0),[m,d]=o.useState(null),[x,u]=o.useState(null),[h,p]=o.useState(null),[c,f]=o.useState(0),g=o.useRef(null),[i,j]=o.useState(!1),[D,U]=o.useState(!1),[E,F]=o.useState(""),[M,A]=o.useState(""),n=async()=>{try{l(!0),d(null);const a=await he();s(a)}catch(a){const w=a instanceof Error?a.message:"Failed to load roles";d(new Error(w))}finally{l(!1)}};o.useEffect(()=>{n()},[]);const R=async a=>{const w=async()=>{await X(a.id,{is_active:!a.is_active}),Q.success(`Role ${a.is_active?"deactivated":"activated"} successfully`),n(),u(null),f(0),g.current=null};g.current=w,u(null);try{await w()}catch(T){const I=T instanceof Error?T.message:"Failed to update role";u(new Error(I))}},re=async a=>{if(a.is_system){u(new Error("Cannot delete system roles"));return}const w=async()=>{await ye(a.id),Q.success("Role deleted successfully"),n(),u(null),f(0),g.current=null};g.current=w,u(null);try{await w()}catch(T){const I=T instanceof Error?T.message:"Failed to delete role";u(new Error(I))}},te=async()=>{if(!(!g.current||c>=3)){f(a=>a+1);try{await g.current()}catch{}}},ae=a=>{p(a),j(!0)},oe=(a,w)=>{F(a),A(w||""),U(!0)};return t?e.jsx("div",{className:"container mx-auto px-4 py-8",children:e.jsx("div",{className:"flex items-center justify-center min-h-[400px]",children:e.jsx(ie,{})})}):m&&r.length===0?e.jsx("div",{className:"container mx-auto px-4 py-8",children:e.jsx(Y,{error:m,variant:"card",severity:"error",context:{action:"fetching roles",resource:"roles"},onRetry:n})}):e.jsxs("div",{className:"container mx-auto px-4 py-8",children:[x&&e.jsx(Y,{error:x,variant:"banner",severity:"error",context:{action:"updating role",resource:"roles"},onRetry:c<3?te:void 0,onDismiss:()=>{u(null),f(0),g.current=null}}),e.jsxs("div",{className:"mb-6 flex items-center justify-between",children:[e.jsxs("div",{children:[e.jsx("h1",{className:"text-3xl font-bold mb-2",children:"Roles Management"}),e.jsx("p",{className:"text-muted-foreground",children:"Manage user roles and permissions"})]}),e.jsx(ve,{onRoleCreated:n})]}),e.jsxs(B,{children:[e.jsx(H,{children:e.jsxs(G,{className:"flex items-center gap-2",children:[e.jsx(ce,{className:"h-5 w-5"}),"Roles"]})}),e.jsx(J,{children:r.length===0?e.jsx("div",{className:"text-center py-8",children:e.jsx("p",{className:"text-muted-foreground",children:"No roles found"})}):e.jsxs(Z,{children:[e.jsx(ee,{children:e.jsxs(z,{children:[e.jsx(v,{children:"Name"}),e.jsx(v,{children:"Display Name"}),e.jsx(v,{children:"Description"}),e.jsx(v,{children:"Status"}),e.jsx(v,{children:"Type"}),e.jsx(v,{children:"Permissions"}),e.jsx(v,{className:"text-right",children:"Actions"})]})}),e.jsx(se,{children:r.map(a=>e.jsxs(z,{children:[e.jsx(b,{className:"font-medium",children:a.name}),e.jsx(b,{children:a.display_name}),e.jsx(b,{className:"max-w-md truncate",children:a.description}),e.jsx(b,{children:e.jsx(P,{variant:a.is_active?"success":"warning",children:a.is_active?"Active":"Inactive"})}),e.jsx(b,{children:a.is_system?e.jsx(P,{variant:"primary",children:"System"}):e.jsx(P,{variant:"default",children:"Custom"})}),e.jsxs(b,{children:[a.permissions?.length||0," permissions"]}),e.jsx(b,{className:"text-right",children:e.jsxs("div",{className:"flex items-center justify-end gap-2",children:[e.jsx(L,{variant:"ghost",size:"sm",onClick:()=>R(a),disabled:a.is_system,children:a.is_active?"Deactivate":"Activate"}),e.jsx(L,{variant:"ghost",size:"sm",onClick:()=>ae(a),disabled:a.is_system,children:e.jsx(de,{className:"h-4 w-4"})}),e.jsx(L,{variant:"ghost",size:"sm",onClick:()=>re(a),disabled:a.is_system,children:e.jsx(me,{className:"h-4 w-4 text-destructive"})})]})})]},a.id))})]})})]}),e.jsxs(B,{className:"mt-6",children:[e.jsx(H,{children:e.jsxs(G,{className:"flex items-center gap-2",children:[e.jsx(K,{className:"h-5 w-5"}),"Assign Role to User"]})}),e.jsx(J,{children:e.jsxs("div",{className:"flex gap-2",children:[e.jsx(_,{placeholder:"User ID",value:E,onChange:a=>F(a.target.value),className:"flex-1"}),e.jsx(_,{placeholder:"User Name (optional)",value:M,onChange:a=>A(a.target.value),className:"flex-1"}),e.jsxs(L,{onClick:()=>oe(E,M),disabled:!E,children:[e.jsx(K,{className:"h-4 w-4 mr-2"}),"Assign Role"]})]})})]}),h&&e.jsx(be,{role:h,open:i,onClose:()=>{j(!1),p(null)},onRoleUpdated:n}),e.jsx(Ne,{userId:E,userName:M,availableRoles:r.filter(a=>a.is_active),open:D,onClose:()=>{U(!1),F(""),A("")},onRoleAssigned:()=>{}})]})}export{Pe as RolesPage};
|