PageSourceSearch

https://llapp.ai/assets/controllers/user_form_controller-210b4460.js

js llapp.ai collected 2026-10-05 14:38:46 UTC 3,532 bytes, 87 lines download raw bytes

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.