1import { Controller } from "@hotwired/stimulus" 2 3export default class extends Controller { 4 static targets = ["rolesSection", "accountRoles", "globalRoles"] 5 6 static USER_TYPE_IDS = [ "user_system", "user_root", "user_owner" ] 7 8 connect() { 9 this.updateUserTypeGate() 10 this.toggleRoles() 11 } 12 13 // System, Root, and Account Owner are mutually exclusive: checking one clears the other two. 14 toggleUserType(event) { 15 if (event.target.checked) { 16 this.constructor.USER_TYPE_IDS.forEach(id => { 17 if (id === event.target.id) return 18 const checkbox = document.getElementById(id) 19 if (checkbox) checkbox.checked = false 20 }) 21 } 22 23 this.resetRoleSelections() 24 this.updateUserTypeGate() 25 this.toggleRoles() 26 } 27 28 // Reverts any in-session role picks to whatever the server actually persisted for this 29 // user (`defaultChecked`, set from the initial `checked` attribute at render time) as 30 // long as roles still apply under the new type. Only System excludes roles entirely â 31 // both sections are force-cleared so a hidden, still-checked box can't sneak a role onto 32 // a System user on submit. 33 resetRoleSelections() { 34 const rolesApply = this.rolesApply() 35 36 this.element.querySelectorAll('input[name="user[role_ids][]"], input[name="user[global_role_ids][]"]').forEach(checkbox => { 37 checkbox.checked = rolesApply && checkbox.defaultChecked 38 }) 39 } 40 41 rolesApply() { 42 return !(document.getElementById("user_system")?.checked || false) 43 } 44 45 // Locks whichever of System/Root/Owner isn't currently selected. This is a UX affordance 46 // only â it does not use the `disabled` attribute, since disabled checkboxes don't submit 47 // their value at all (only the hidden "0" fallback would), which would silently reset an 48 // existing user's flag on save if left unattended. 49 updateUserTypeGate() { 50 const ids = this.constructor.USER_TYPE_IDS 51 const checkedId = ids.find(id => document.getElementById(id)?.checked) 52 53 ids.forEach(id => { 54 const checkbox = document.getElementById(id) 55 if (!checkbox || checkbox.disabled) return 56 57 const locked = !!checkedId && checkedId !== id 58 const container = checkbox.closest(".form-check") 59 container?.classList.toggle("pe-none", locked) 60 container?.classList.toggle("opacity-50", locked) 61 checkbox.tabIndex = locked ? -1 : 0 62 checkbox.setAttribute("aria-disabled", locked.toString()) 63 }) 64 } 65 66 // Local (account-scoped) Roles show for Owners, and Global Roles show for Owners and 67 // Root users â same as before. New: when no User Type at all is selected (a plain 68 // user), both sections are now shown too, so plain users can still be given Roles. 69 // System is the one type that excludes roles entirely (see rolesApply above). 70 toggleRoles() { 71 const ownerChecked = document.getElementById("user_owner")?.checked || false 72 const rootChecked = document.getElementById("user_root")?.checked || false 73 const noTypeSelected = this.rolesApply() && !ownerChecked && !rootChecked 74 75 const showAccountRoles = noTypeSelected || ownerChecked 76 const showGlobalRoles = noTypeSelected || rootChecked || ownerChecked 77 78 this.rolesSectionTarget.style.display = (showAccountRoles || showGlobalRoles) ? "" : "none" 79 80 if (this.hasAccountRolesTarget) { 81 this.accountRolesTarget.style.display = showAccountRoles ? "" : "none" 82 } 83 if (this.hasGlobalRolesTarget) { 84 this.globalRolesTarget.style.display = showGlobalRoles ? "" : "none" 85 } 86 } 87}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.