// Code generated by templ - DO NOT EDIT.

// templ: version: v0.3.1020
package app

//lint:file-ignore SA4006 This context is only used if a nested component is present.

import "github.com/a-h/templ"
import templruntime "github.com/a-h/templ/runtime"

import (
	"fmt"
	"github.com/seaweedfs/seaweedfs/weed/admin/dash"
)

func ObjectStoreUsers(data dash.ObjectStoreUsersData) templ.Component {
	return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
		templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
		if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
			return templ_7745c5c3_CtxErr
		}
		templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
		if !templ_7745c5c3_IsBuffer {
			defer func() {
				templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
				if templ_7745c5c3_Err == nil {
					templ_7745c5c3_Err = templ_7745c5c3_BufErr
				}
			}()
		}
		ctx = templ.InitializeContext(ctx)
		templ_7745c5c3_Var1 := templ.GetChildren(ctx)
		if templ_7745c5c3_Var1 == nil {
			templ_7745c5c3_Var1 = templ.NopComponent
		}
		ctx = templ.ClearChildren(ctx)
		templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "<div class=\"container-fluid\"><!-- Page Header --><div class=\"d-sm-flex align-items-center justify-content-between mb-4\"><div><h1 class=\"h3 mb-0 text-gray-800\"><i class=\"fas fa-users me-2\"></i>Object Store Users</h1><p class=\"mb-0 text-muted\">Manage S3 API users and their access credentials</p></div><div class=\"d-flex gap-2\"><button type=\"button\" class=\"btn btn-primary\" data-bs-toggle=\"modal\" data-bs-target=\"#createUserModal\"><i class=\"fas fa-plus me-1\"></i>Create User</button></div></div><!-- Summary Cards --><div class=\"row mb-4\"><div class=\"col-xl-3 col-md-6 mb-4\"><div class=\"card border-left-primary shadow h-100 py-2\"><div class=\"card-body\"><div class=\"row no-gutters align-items-center\"><div class=\"col mr-2\"><div class=\"text-xs font-weight-bold text-primary text-uppercase mb-1\">Total Users</div><div class=\"h5 mb-0 font-weight-bold text-gray-800\">")
		if templ_7745c5c3_Err != nil {
			return templ_7745c5c3_Err
		}
		var templ_7745c5c3_Var2 string
		templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", data.TotalUsers))
		if templ_7745c5c3_Err != nil {
			return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/object_store_users.templ`, Line: 38, Col: 71}
		}
		_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2))
		if templ_7745c5c3_Err != nil {
			return templ_7745c5c3_Err
		}
		templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "</div></div><div class=\"col-auto\"><i class=\"fas fa-users fa-2x text-gray-300\"></i></div></div></div></div></div><div class=\"col-xl-3 col-md-6 mb-4\"><div class=\"card border-left-success shadow h-100 py-2\"><div class=\"card-body\"><div class=\"row no-gutters align-items-center\"><div class=\"col mr-2\"><div class=\"text-xs font-weight-bold text-success text-uppercase mb-1\">Total Users</div><div class=\"h5 mb-0 font-weight-bold text-gray-800\">")
		if templ_7745c5c3_Err != nil {
			return templ_7745c5c3_Err
		}
		var templ_7745c5c3_Var3 string
		templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", len(data.Users)))
		if templ_7745c5c3_Err != nil {
			return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/object_store_users.templ`, Line: 58, Col: 71}
		}
		_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
		if templ_7745c5c3_Err != nil {
			return templ_7745c5c3_Err
		}
		templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "</div></div><div class=\"col-auto\"><i class=\"fas fa-user-check fa-2x text-gray-300\"></i></div></div></div></div></div><div class=\"col-xl-3 col-md-6 mb-4\"><div class=\"card border-left-info shadow h-100 py-2\"><div class=\"card-body\"><div class=\"row no-gutters align-items-center\"><div class=\"col mr-2\"><div class=\"text-xs font-weight-bold text-info text-uppercase mb-1\">Last Updated</div><div class=\"h6 mb-0 font-weight-bold text-gray-800\">")
		if templ_7745c5c3_Err != nil {
			return templ_7745c5c3_Err
		}
		var templ_7745c5c3_Var4 string
		templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(data.LastUpdated.Format("15:04"))
		if templ_7745c5c3_Err != nil {
			return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/object_store_users.templ`, Line: 78, Col: 69}
		}
		_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
		if templ_7745c5c3_Err != nil {
			return templ_7745c5c3_Err
		}
		templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "</div></div><div class=\"col-auto\"><i class=\"fas fa-clock fa-2x text-gray-300\"></i></div></div></div></div></div></div><!-- Users Table --><div class=\"row\"><div class=\"col-12\"><div class=\"card shadow mb-4\"><div class=\"card-header py-3 d-flex flex-row align-items-center justify-content-between\"><h6 class=\"m-0 font-weight-bold text-primary\"><i class=\"fas fa-users me-2\"></i>Object Store Users</h6><div class=\"dropdown no-arrow\"><a class=\"dropdown-toggle\" href=\"#\" role=\"button\" data-bs-toggle=\"dropdown\"><i class=\"fas fa-ellipsis-v fa-sm fa-fw text-gray-400\"></i></a><div class=\"dropdown-menu dropdown-menu-right shadow animated--fade-in\"><div class=\"dropdown-header\">Actions:</div><a class=\"dropdown-item\" href=\"#\" onclick=\"exportUsers()\"><i class=\"fas fa-download me-2\"></i>Export List</a></div></div></div><div class=\"card-body\"><div class=\"table-responsive\"><table class=\"table table-hover\" width=\"100%\" cellspacing=\"0\" id=\"usersTable\"><thead><tr><th>Username</th><th>Email</th><th>Access Key</th><th>Actions</th></tr></thead> <tbody>")
		if templ_7745c5c3_Err != nil {
			return templ_7745c5c3_Err
		}
		for _, user := range data.Users {
			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "<tr><td><div class=\"d-flex align-items-center\"><i class=\"fas fa-user me-2 text-muted\"></i> <strong>")
			if templ_7745c5c3_Err != nil {
				return templ_7745c5c3_Err
			}
			var templ_7745c5c3_Var5 string
			templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(user.Username)
			if templ_7745c5c3_Err != nil {
				return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/object_store_users.templ`, Line: 127, Col: 74}
			}
			_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
			if templ_7745c5c3_Err != nil {
				return templ_7745c5c3_Err
			}
			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "</strong> ")
			if templ_7745c5c3_Err != nil {
				return templ_7745c5c3_Err
			}
			if user.IsStatic {
				templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "<span class=\"badge bg-secondary ms-2\" title=\"Loaded from config file (read-only)\">static</span>")
				if templ_7745c5c3_Err != nil {
					return templ_7745c5c3_Err
				}
			}
			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "</div></td><td>")
			if templ_7745c5c3_Err != nil {
				return templ_7745c5c3_Err
			}
			var templ_7745c5c3_Var6 string
			templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(user.Email)
			if templ_7745c5c3_Err != nil {
				return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/object_store_users.templ`, Line: 133, Col: 59}
			}
			_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))
			if templ_7745c5c3_Err != nil {
				return templ_7745c5c3_Err
			}
			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "</td><td><code class=\"text-muted\">")
			if templ_7745c5c3_Err != nil {
				return templ_7745c5c3_Err
			}
			var templ_7745c5c3_Var7 string
			templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(user.AccessKey)
			if templ_7745c5c3_Err != nil {
				return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/object_store_users.templ`, Line: 135, Col: 88}
			}
			_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
			if templ_7745c5c3_Err != nil {
				return templ_7745c5c3_Err
			}
			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "</code></td><td><div class=\"btn-group btn-group-sm\" role=\"group\"><button type=\"button\" class=\"btn btn-outline-info\" data-action=\"show-user-details\" data-username=\"")
			if templ_7745c5c3_Err != nil {
				return templ_7745c5c3_Err
			}
			var templ_7745c5c3_Var8 string
			templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.ResolveAttributeValue(user.Username)
			if templ_7745c5c3_Err != nil {
				return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/object_store_users.templ`, Line: 140, Col: 121}
			}
			_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var8)
			if templ_7745c5c3_Err != nil {
				return templ_7745c5c3_Err
			}
			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "\"><i class=\"fas fa-info-circle\"></i></button> ")
			if templ_7745c5c3_Err != nil {
				return templ_7745c5c3_Err
			}
			if !user.IsStatic {
				templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "<button type=\"button\" class=\"btn btn-outline-primary\" data-action=\"edit-user\" data-username=\"")
				if templ_7745c5c3_Err != nil {
					return templ_7745c5c3_Err
				}
				var templ_7745c5c3_Var9 string
				templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.ResolveAttributeValue(user.Username)
				if templ_7745c5c3_Err != nil {
					return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/object_store_users.templ`, Line: 145, Col: 117}
				}
				_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var9)
				if templ_7745c5c3_Err != nil {
					return templ_7745c5c3_Err
				}
				templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "\"><i class=\"fas fa-edit\"></i></button> ")
				if templ_7745c5c3_Err != nil {
					return templ_7745c5c3_Err
				}
			}
			if user.Username != "anonymous" && !user.IsStatic {
				templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "<button type=\"button\" class=\"btn btn-outline-secondary\" data-action=\"manage-access-keys\" data-username=\"")
				if templ_7745c5c3_Err != nil {
					return templ_7745c5c3_Err
				}
				var templ_7745c5c3_Var10 string
				templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.ResolveAttributeValue(user.Username)
				if templ_7745c5c3_Err != nil {
					return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/object_store_users.templ`, Line: 151, Col: 126}
				}
				_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var10)
				if templ_7745c5c3_Err != nil {
					return templ_7745c5c3_Err
				}
				templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "\"><i class=\"fas fa-key\"></i></button> ")
				if templ_7745c5c3_Err != nil {
					return templ_7745c5c3_Err
				}
			}
			if !user.IsStatic {
				templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "<button type=\"button\" class=\"btn btn-outline-danger\" data-action=\"delete-user\" data-username=\"")
				if templ_7745c5c3_Err != nil {
					return templ_7745c5c3_Err
				}
				var templ_7745c5c3_Var11 string
				templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.ResolveAttributeValue(user.Username)
				if templ_7745c5c3_Err != nil {
					return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/object_store_users.templ`, Line: 157, Col: 119}
				}
				_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var11)
				if templ_7745c5c3_Err != nil {
					return templ_7745c5c3_Err
				}
				templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "\"><i class=\"fas fa-trash\"></i></button>")
				if templ_7745c5c3_Err != nil {
					return templ_7745c5c3_Err
				}
			}
			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "</div></td></tr>")
			if templ_7745c5c3_Err != nil {
				return templ_7745c5c3_Err
			}
		}
		if len(data.Users) == 0 {
			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "<tr><td colspan=\"4\" class=\"text-center text-muted py-4\"><i class=\"fas fa-users fa-3x mb-3 text-muted\"></i><div><h5>No users found</h5><p>Create your first object store user to get started.</p></div></td></tr>")
			if templ_7745c5c3_Err != nil {
				return templ_7745c5c3_Err
			}
		}
		templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "</tbody></table></div></div></div></div></div><!-- Last Updated --><div class=\"row\"><div class=\"col-12\"><small class=\"text-muted\"><i class=\"fas fa-clock me-1\"></i> Last updated: ")
		if templ_7745c5c3_Err != nil {
			return templ_7745c5c3_Err
		}
		var templ_7745c5c3_Var12 string
		templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(data.LastUpdated.Format("2006-01-02 15:04:05"))
		if templ_7745c5c3_Err != nil {
			return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/object_store_users.templ`, Line: 189, Col: 81}
		}
		_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12))
		if templ_7745c5c3_Err != nil {
			return templ_7745c5c3_Err
		}
		templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, "</small></div></div></div><!-- Create User Modal --><div class=\"modal fade\" id=\"createUserModal\" tabindex=\"-1\" role=\"dialog\"><div class=\"modal-dialog\" role=\"document\"><div class=\"modal-content\"><div class=\"modal-header\"><h5 class=\"modal-title\"><i class=\"fas fa-user-plus me-2\"></i>Create New User</h5><button type=\"button\" class=\"btn-close\" data-bs-dismiss=\"modal\"></button></div><div class=\"modal-body\"><form id=\"createUserForm\"><div class=\"mb-3\"><label for=\"username\" class=\"form-label\">Username *</label> ")
		if templ_7745c5c3_Err != nil {
			return templ_7745c5c3_Err
		}
		if !data.HasAnonymousUser {
			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, "<div class=\"input-group\"><input type=\"text\" class=\"form-control\" id=\"username\" name=\"username\" required><div class=\"input-group-text\"><input class=\"form-check-input mt-0 me-1\" type=\"checkbox\" id=\"anonymousCheck\" onchange=\"toggleAnonymousUser()\"> <label class=\"form-check-label small\" for=\"anonymousCheck\">Anonymous</label></div></div>")
			if templ_7745c5c3_Err != nil {
				return templ_7745c5c3_Err
			}
		} else {
			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, "<input type=\"text\" class=\"form-control\" id=\"username\" name=\"username\" required>")
			if templ_7745c5c3_Err != nil {
				return templ_7745c5c3_Err
			}
		}
		templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "</div><div class=\"mb-3\"><label for=\"email\" class=\"form-label\">Email</label> <input type=\"email\" class=\"form-control\" id=\"email\" name=\"email\"></div><div class=\"mb-3\"><label for=\"actions\" class=\"form-label\">Permissions</label> <select multiple class=\"form-control\" id=\"actions\" name=\"actions\" size=\"10\"><option value=\"Admin\">Admin (Full Access)</option> <option value=\"Read\">Read</option> <option value=\"Write\">Write</option> <option value=\"List\">List</option> <option value=\"Tagging\">Tagging</option> <optgroup label=\"Object Lock Permissions\"><option value=\"BypassGovernanceRetention\">Bypass Governance Retention</option> <option value=\"GetObjectRetention\">Get Object Retention</option> <option value=\"PutObjectRetention\">Put Object Retention</option> <option value=\"GetObjectLegalHold\">Get Object Legal Hold</option> <option value=\"PutObjectLegalHold\">Put Object Legal Hold</option> <option value=\"GetBucketObjectLockConfiguration\">Get Bucket Object Lock Configuration</option> <option value=\"PutBucketObjectLockConfiguration\">Put Bucket Object Lock Configuration</option></optgroup> <optgroup label=\"Bucket Policy Permissions\"><option value=\"PutBucketPolicy\">Put Bucket Policy</option> <option value=\"DeleteBucketPolicy\">Delete Bucket Policy</option></optgroup> <optgroup label=\"S3 Tables Permissions\"><option value=\"S3TablesAdmin\">S3 Tables Admin (Full Access)</option> <option value=\"CreateTableBucket\">Create Table Bucket</option> <option value=\"GetTableBucket\">Get Table Bucket</option> <option value=\"ListTableBuckets\">List Table Buckets</option> <option value=\"DeleteTableBucket\">Delete Table Bucket</option> <option value=\"PutTableBucketPolicy\">Put Table Bucket Policy</option> <option value=\"GetTableBucketPolicy\">Get Table Bucket Policy</option> <option value=\"DeleteTableBucketPolicy\">Delete Table Bucket Policy</option> <option value=\"CreateNamespace\">Create Namespace</option> <option value=\"GetNamespace\">Get Namespace</option> <option value=\"ListNamespaces\">List Namespaces</option> <option value=\"DeleteNamespace\">Delete Namespace</option> <option value=\"CreateTable\">Create Table</option> <option value=\"GetTable\">Get Table</option> <option value=\"ListTables\">List Tables</option> <option value=\"DeleteTable\">Delete Table</option> <option value=\"PutTablePolicy\">Put Table Policy</option> <option value=\"GetTablePolicy\">Get Table Policy</option> <option value=\"DeleteTablePolicy\">Delete Table Policy</option> <option value=\"TagResource\">Tag Resource</option> <option value=\"ListTagsForResource\">List Tags</option> <option value=\"UntagResource\">Untag Resource</option></optgroup></select> <small class=\"form-text text-muted\">Hold Ctrl/Cmd to select multiple permissions</small></div><div class=\"mb-3\"><label class=\"form-label\">Bucket Scope</label> <small class=\"form-text text-muted d-block mb-2\">Apply selected permissions to specific buckets or all buckets</small><div class=\"form-check mb-2\"><input class=\"form-check-input\" type=\"radio\" name=\"bucketScope\" id=\"allBuckets\" value=\"all\" checked onchange=\"toggleBucketList()\"> <label class=\"form-check-label\" for=\"allBuckets\">All Buckets</label></div><div class=\"form-check mb-2\"><input class=\"form-check-input\" type=\"radio\" name=\"bucketScope\" id=\"specificBuckets\" value=\"specific\" onchange=\"toggleBucketList()\"> <label class=\"form-check-label\" for=\"specificBuckets\">Specific Buckets</label></div><div id=\"bucketSelectionList\" class=\"mt-2\" style=\"display: none;\"><select multiple class=\"form-select\" id=\"selectedBuckets\" size=\"5\"><!-- Options loaded dynamically --></select> <small class=\"form-text text-muted\">Hold Ctrl/Cmd to select multiple buckets</small></div></div><div class=\"mb-3\"><label for=\"policies\" class=\"form-label\">Attached Policies</label> <select multiple class=\"form-control\" id=\"policies\" name=\"policies\" size=\"5\"><!-- Options loaded dynamically --></select> <small class=\"form-text text-muted\">Hold Ctrl/Cmd to select multiple policies</small></div><div class=\"mb-3 form-check\"><input type=\"checkbox\" class=\"form-check-input\" id=\"generateKey\" name=\"generateKey\" checked> <label class=\"form-check-label\" for=\"generateKey\">Generate access key automatically</label></div></form></div><div class=\"modal-footer\"><button type=\"button\" class=\"btn btn-secondary\" data-bs-dismiss=\"modal\">Cancel</button> <button type=\"button\" class=\"btn btn-primary\" onclick=\"handleCreateUser()\">Create User</button></div></div></div></div><!-- Edit User Modal --><div class=\"modal fade\" id=\"editUserModal\" tabindex=\"-1\" role=\"dialog\"><div class=\"modal-dialog\" role=\"document\"><div class=\"modal-content\"><div class=\"modal-header\"><h5 class=\"modal-title\"><i class=\"fas fa-user-edit me-2\"></i>Edit User</h5><button type=\"button\" class=\"btn-close\" data-bs-dismiss=\"modal\"></button></div><div class=\"modal-body\"><form id=\"editUserForm\"><input type=\"hidden\" id=\"editUsername\" name=\"username\"><div class=\"mb-3\"><label for=\"editEmail\" class=\"form-label\">Email</label> <input type=\"email\" class=\"form-control\" id=\"editEmail\" name=\"email\"></div><div class=\"mb-3\"><label for=\"editActions\" class=\"form-label\">Permissions</label> <select multiple class=\"form-control\" id=\"editActions\" name=\"actions\" size=\"10\"><option value=\"Admin\">Admin (Full Access)</option> <option value=\"Read\">Read</option> <option value=\"Write\">Write</option> <option value=\"List\">List</option> <option value=\"Tagging\">Tagging</option> <optgroup label=\"Object Lock Permissions\"><option value=\"BypassGovernanceRetention\">Bypass Governance Retention</option> <option value=\"GetObjectRetention\">Get Object Retention</option> <option value=\"PutObjectRetention\">Put Object Retention</option> <option value=\"GetObjectLegalHold\">Get Object Legal Hold</option> <option value=\"PutObjectLegalHold\">Put Object Legal Hold</option> <option value=\"GetBucketObjectLockConfiguration\">Get Bucket Object Lock Configuration</option> <option value=\"PutBucketObjectLockConfiguration\">Put Bucket Object Lock Configuration</option></optgroup> <optgroup label=\"Bucket Policy Permissions\"><option value=\"PutBucketPolicy\">Put Bucket Policy</option> <option value=\"DeleteBucketPolicy\">Delete Bucket Policy</option></optgroup> <optgroup label=\"S3 Tables Permissions\"><option value=\"S3TablesAdmin\">S3 Tables Admin (Full Access)</option> <option value=\"CreateTableBucket\">Create Table Bucket</option> <option value=\"GetTableBucket\">Get Table Bucket</option> <option value=\"ListTableBuckets\">List Table Buckets</option> <option value=\"DeleteTableBucket\">Delete Table Bucket</option> <option value=\"PutTableBucketPolicy\">Put Table Bucket Policy</option> <option value=\"GetTableBucketPolicy\">Get Table Bucket Policy</option> <option value=\"DeleteTableBucketPolicy\">Delete Table Bucket Policy</option> <option value=\"CreateNamespace\">Create Namespace</option> <option value=\"GetNamespace\">Get Namespace</option> <option value=\"ListNamespaces\">List Namespaces</option> <option value=\"DeleteNamespace\">Delete Namespace</option> <option value=\"CreateTable\">Create Table</option> <option value=\"GetTable\">Get Table</option> <option value=\"ListTables\">List Tables</option> <option value=\"DeleteTable\">Delete Table</option> <option value=\"PutTablePolicy\">Put Table Policy</option> <option value=\"GetTablePolicy\">Get Table Policy</option> <option value=\"DeleteTablePolicy\">Delete Table Policy</option> <option value=\"TagResource\">Tag Resource</option> <option value=\"ListTagsForResource\">List Tags</option> <option value=\"UntagResource\">Untag Resource</option></optgroup></select></div><div class=\"mb-3\"><label class=\"form-label\">Bucket Scope</label> <small class=\"form-text text-muted d-block mb-2\">Apply selected permissions to specific buckets or all buckets</small><div class=\"form-check mb-2\"><input class=\"form-check-input\" type=\"radio\" name=\"editBucketScope\" id=\"editAllBuckets\" value=\"all\" checked onchange=\"toggleBucketList('edit')\"> <label class=\"form-check-label\" for=\"editAllBuckets\">All Buckets</label></div><div class=\"form-check mb-2\"><input class=\"form-check-input\" type=\"radio\" name=\"editBucketScope\" id=\"editSpecificBuckets\" value=\"specific\" onchange=\"toggleBucketList('edit')\"> <label class=\"form-check-label\" for=\"editSpecificBuckets\">Specific Buckets</label></div><div id=\"editBucketSelectionList\" class=\"mt-2\" style=\"display: none;\"><select multiple class=\"form-select\" id=\"editSelectedBuckets\" size=\"5\"><!-- Options loaded dynamically --></select> <small class=\"form-text text-muted\">Hold Ctrl/Cmd to select multiple buckets</small></div></div><div class=\"mb-3\"><label for=\"editPolicies\" class=\"form-label\">Attached Policies</label> <select multiple class=\"form-control\" id=\"editPolicies\" name=\"policies\" size=\"5\"><!-- Options loaded dynamically --></select></div><div class=\"mb-3\"><label class=\"form-label\">Groups</label><div id=\"editUserGroups\"><!-- Groups loaded dynamically --></div><div class=\"input-group mt-2\"><select class=\"form-select\" id=\"editGroupSelect\"><option value=\"\">Add to group...</option></select> <button class=\"btn btn-outline-primary\" type=\"button\" onclick=\"addUserToGroupFromEdit()\" aria-label=\"Add user to group\" title=\"Add user to group\"><i class=\"fas fa-plus\"></i></button></div></div></form></div><div class=\"modal-footer\"><button type=\"button\" class=\"btn btn-secondary\" data-bs-dismiss=\"modal\">Cancel</button> <button type=\"button\" class=\"btn btn-primary\" onclick=\"handleUpdateUser()\">Update User</button></div></div></div></div><!-- User Details Modal --><div class=\"modal fade\" id=\"userDetailsModal\" tabindex=\"-1\" role=\"dialog\"><div class=\"modal-dialog modal-lg\" role=\"document\"><div class=\"modal-content\"><div class=\"modal-header\"><h5 class=\"modal-title\"><i class=\"fas fa-user me-2\"></i>User Details</h5><button type=\"button\" class=\"btn-close\" data-bs-dismiss=\"modal\"></button></div><div class=\"modal-body\" id=\"userDetailsContent\"><!-- Content will be loaded dynamically --></div><div class=\"modal-footer\"><button type=\"button\" class=\"btn btn-secondary\" data-bs-dismiss=\"modal\">Close</button></div></div></div></div><!-- Access Keys Management Modal --><div class=\"modal fade\" id=\"accessKeysModal\" tabindex=\"-1\" role=\"dialog\"><div class=\"modal-dialog modal-lg\" role=\"document\"><div class=\"modal-content\"><div class=\"modal-header\"><h5 class=\"modal-title\"><i class=\"fas fa-key me-2\"></i>Manage Access Keys</h5><button type=\"button\" class=\"btn-close\" data-bs-dismiss=\"modal\"></button></div><div class=\"modal-body\"><div class=\"d-flex justify-content-between align-items-center mb-3\"><h6>Access Keys for <span id=\"accessKeysUsername\"></span></h6><button type=\"button\" class=\"btn btn-primary btn-sm\" onclick=\"toggleCreateKeyForm()\"><i class=\"fas fa-plus me-1\"></i>Create New Key</button></div><div id=\"createKeyForm\" class=\"card mb-3\" style=\"display: none;\"><div class=\"card-body\"><p class=\"text-muted small mb-2\">Leave blank to auto-generate.</p><div class=\"mb-2\"><label for=\"newAccessKeyInput\" class=\"form-label form-label-sm\">Access Key</label> <input type=\"text\" class=\"form-control form-control-sm\" id=\"newAccessKeyInput\" placeholder=\"Auto-generated if empty\" minlength=\"4\" maxlength=\"128\"></div><div class=\"mb-2\"><label for=\"newSecretKeyInput\" class=\"form-label form-label-sm\">Secret Key</label><div class=\"input-group input-group-sm\"><input type=\"password\" class=\"form-control form-control-sm\" id=\"newSecretKeyInput\" placeholder=\"Auto-generated if empty\" minlength=\"8\" maxlength=\"128\"> <button class=\"btn btn-outline-secondary\" type=\"button\" onclick=\"toggleSecretKeyVisibility()\" aria-label=\"Toggle secret key visibility\"><i class=\"fas fa-eye\" id=\"secretKeyToggleIcon\"></i></button></div></div><div class=\"d-flex gap-2\"><button type=\"button\" class=\"btn btn-primary btn-sm\" onclick=\"createAccessKey()\">Create</button> <button type=\"button\" class=\"btn btn-secondary btn-sm\" onclick=\"toggleCreateKeyForm()\">Cancel</button></div></div></div><div id=\"accessKeysContent\"><!-- Content will be loaded dynamically --></div></div><div class=\"modal-footer\"><button type=\"button\" class=\"btn btn-secondary\" data-bs-dismiss=\"modal\">Close</button></div></div></div></div><!-- JavaScript for user management --><script>\n        // Access key status constants\n        const STATUS_ACTIVE = 'Active';\n        const STATUS_INACTIVE = 'Inactive';\n\n        // Use basePath() from admin.js for -urlPrefix; it is loaded in the layout footer before DOMContentLoaded fires.\n        document.addEventListener('DOMContentLoaded', function() {\n\n            // Event delegation for user action buttons\n            document.addEventListener('click', function(e) {\n                const button = e.target.closest('[data-action]');\n                if (!button) return;\n\n                const action = button.getAttribute('data-action');\n                const username = button.getAttribute('data-username');\n\n                switch (action) {\n                    case 'show-user-details':\n                        showUserDetails(username);\n                        break;\n                    case 'edit-user':\n                        editUser(username);\n                        break;\n                    case 'manage-access-keys':\n                        manageAccessKeys(username);\n                        break;\n                    case 'delete-user':\n                        deleteUser(username);\n                        break;\n                }\n            });\n\n            // Event delegation for delete access key buttons\n            document.addEventListener('click', function(e) {\n                const deleteBtn = e.target.closest('.delete-access-key-btn');\n                if (deleteBtn) {\n                    const username = deleteBtn.getAttribute('data-username');\n                    const accessKey = deleteBtn.getAttribute('data-access-key');\n                    deleteAccessKey(username, accessKey);\n                }\n            });\n\n            // Event delegation for access key status changes\n            document.addEventListener('change', function(e) {\n                const statusSelect = e.target.closest('.access-key-status-select');\n                if (statusSelect) {\n                    const username = statusSelect.getAttribute('data-username');\n                    const accessKey = statusSelect.getAttribute('data-access-key');\n                    const newStatus = statusSelect.value;\n                    updateAccessKeyStatus(username, accessKey, newStatus);\n                }\n            });\n\n            // Load policies for dropdowns\n            loadPolicies();\n\n            // Load buckets for bucket permissions\n            loadBuckets();\n        });\n\n        // Global variable to store available buckets\n        var availableBuckets = [];\n        var bucketPermissionCounter = 0;\n        const s3TablesPermissions = new Set([\n            'CreateTableBucket',\n            'GetTableBucket',\n            'ListTableBuckets',\n            'DeleteTableBucket',\n            'PutTableBucketPolicy',\n            'GetTableBucketPolicy',\n            'DeleteTableBucketPolicy',\n            'CreateNamespace',\n            'GetNamespace',\n            'ListNamespaces',\n            'DeleteNamespace',\n            'CreateTable',\n            'GetTable',\n            'ListTables',\n            'DeleteTable',\n            'PutTablePolicy',\n            'GetTablePolicy',\n            'DeleteTablePolicy',\n            'TagResource',\n            'ListTagsForResource',\n            'UntagResource'\n        ]);\n        function isS3TablesPermission(permission) {\n            return permission === 'S3TablesAdmin' || s3TablesPermissions.has(permission);\n        }\n\n        // Load buckets\n        async function loadBuckets() {\n            try {\n                const response = await fetch(basePath('/api/s3/buckets'));\n                if (response.ok) {\n                    const data = await response.json();\n                    availableBuckets = (data.buckets || []).map(bucket => ({ name: bucket.name, type: 's3' }));\n                    console.log('Loaded', availableBuckets.length, 'buckets');\n                } else {\n                    console.warn('Failed to load buckets');\n                    availableBuckets = [];\n                }\n            } catch (error) {\n                console.error('Error loading buckets:', error);\n                availableBuckets = [];\n            }\n            try {\n                const response = await fetch(basePath('/api/s3tables/buckets'));\n                if (response.ok) {\n                    const data = await response.json();\n                    const tableBuckets = (data.buckets || data.tableBuckets || []).map(bucket => ({ name: bucket.name, type: 's3tables' }));\n                    availableBuckets = availableBuckets.concat(tableBuckets);\n                } else {\n                    console.warn('Failed to load table buckets');\n                }\n            } catch (error) {\n                console.warn('Error loading table buckets:', error);\n            }\n            // Populate bucket selection dropdowns\n            populateBucketSelections();\n        }\n\n        // Load policies\n        async function loadPolicies() {\n            try {\n                const response = await fetch(basePath('/api/object-store/policies'));\n                if (response.ok) {\n                    const data = await response.json();\n                    const policies = data.policies || [];\n\n                    const createSelect = document.getElementById('policies');\n                    const editSelect = document.getElementById('editPolicies');\n\n                    // Check if elements exist\n                    if (!createSelect || !editSelect) {\n                        console.warn('Policy select elements not found');\n                        return;\n                    }\n\n                    // Clear existing options\n                    createSelect.innerHTML = '';\n                    editSelect.innerHTML = '';\n\n                    if (policies && policies.length > 0) {\n                        policies.forEach(policy => {\n                            const option = document.createElement('option');\n                            option.value = policy.name;\n                            option.textContent = policy.name;\n                            createSelect.appendChild(option);\n                            editSelect.appendChild(option.cloneNode(true));\n                        });\n                    } else {\n                        const emptyOption = document.createElement('option');\n                        emptyOption.disabled = true;\n                        emptyOption.textContent = 'No policies available';\n                        createSelect.appendChild(emptyOption);\n                        editSelect.appendChild(emptyOption.cloneNode(true));\n                    }\n                } else {\n                    const error = await response.json().catch(() => ({}));\n                    showAlert('Failed to load policies: ' + (error.error || 'Unknown error'), 'error');\n                }\n            } catch (error) {\n                console.error('Error loading policies:', error);\n                showAlert('Failed to load policies: ' + error.message, 'error');\n            }\n        }\n\n        // Toggle bucket permission fields when Admin checkbox changes\n        function toggleBucketPermissionFields(mode) {\n            mode = mode || 'create';\n            const adminCheckbox = document.getElementById(mode === 'edit' ? 'editBucketAdmin' : 'bucketAdmin');\n            const permissionFields = document.getElementById(mode === 'edit' ? 'editBucketPermissionFields' : 'bucketPermissionFields');\n\n            if (adminCheckbox && permissionFields) {\n                permissionFields.style.display = adminCheckbox.checked ? 'none' : 'block';\n            }\n        }\n\n        // Toggle bucket list visibility when bucket scope changes\n        function toggleBucketList(mode) {\n            mode = mode || 'create';\n            const specificRadio = document.getElementById(mode === 'edit' ? 'editSpecificBuckets' : 'specificBuckets');\n            const bucketList = document.getElementById(mode === 'edit' ? 'editBucketSelectionList' : 'bucketSelectionList');\n\n            if (specificRadio && bucketList) {\n                bucketList.style.display = specificRadio.checked ? 'block' : 'none';\n            }\n        }\n\n        // Toggle anonymous user checkbox\n        function toggleAnonymousUser() {\n            const checkbox = document.getElementById('anonymousCheck');\n            const usernameInput = document.getElementById('username');\n            const generateKey = document.getElementById('generateKey');\n            if (checkbox.checked) {\n                usernameInput.value = 'anonymous';\n                usernameInput.readOnly = true;\n                generateKey.checked = false;\n                generateKey.disabled = true;\n            } else {\n                usernameInput.value = '';\n                usernameInput.readOnly = false;\n                generateKey.disabled = false;\n                generateKey.checked = true;\n            }\n        }\n\n        // Populate bucket selection dropdowns\n        function populateBucketSelections() {\n            const createSelect = document.getElementById('selectedBuckets');\n            const editSelect = document.getElementById('editSelectedBuckets');\n\n            [createSelect, editSelect].forEach(select => {\n                if (select) {\n                    select.innerHTML = '';\n                    availableBuckets.forEach(bucket => {\n                        const option = document.createElement('option');\n                        option.value = bucket.type + ':' + bucket.name;\n                        option.textContent = bucket.type === 's3tables' ? `Table: ${bucket.name}` : bucket.name;\n                        select.appendChild(option);\n                    });\n                }\n            });\n        }\n\n        // Parse bucket permissions from actions array for new UI\n        function parseBucketPermissions(actions) {\n            const result = {\n                isAdmin: false,\n                permissions: [],\n                applyToAll: false,\n                specificBuckets: []\n            };\n\n            // Check if user has Admin permission\n            if (actions.includes('Admin')) {\n                result.isAdmin = true;\n                return result;\n            }\n\n            // Separate bucket-scoped from global actions\n            const bucketActions = [];\n            const globalBucketPerms = [];\n\n            actions.forEach(action => {\n                if (action.startsWith('s3tables:')) {\n                    const actionValue = action.slice('s3tables:'.length);\n                    if (actionValue === '*') {\n                        globalBucketPerms.push('S3TablesAdmin');\n                        return;\n                    }\n                    const parts = actionValue.split(':');\n                    const perm = parts[0];\n                    const bucket = parts.length > 1 ? parts.slice(1).join(':').replace(/\\/\\*$/, '') : '';\n                    if (bucket) {\n                        bucketActions.push({ permission: perm, bucketId: 's3tables:' + bucket });\n                    } else {\n                        globalBucketPerms.push(perm);\n                    }\n                } else if (action.includes(':')) {\n                    const parts = action.split(':');\n                    const perm = parts[0];\n                    const bucket = parts.slice(1).join(':').replace(/\\/\\*$/, '');\n                    bucketActions.push({ permission: perm, bucketId: 's3:' + bucket });\n                } else {\n                    globalBucketPerms.push(action);\n                }\n            });\n\n            // If we have global bucket permissions (no colon), they apply to all buckets\n            if (globalBucketPerms.length > 0) {\n                result.permissions = globalBucketPerms;\n                result.applyToAll = true;\n            } else if (bucketActions.length > 0) {\n                // Get unique permissions and buckets\n                const perms = [...new Set(bucketActions.map(ba => ba.permission))];\n                const buckets = [...new Set(bucketActions.map(ba => ba.bucketId))];\n\n                result.permissions = perms;\n                result.applyToAll = false;\n                result.specificBuckets = buckets;\n            }\n\n            return result;\n        }\n\n        function parseBucketOptionValue(value) {\n            if (value.startsWith('s3tables:')) {\n                return { type: 's3tables', name: value.slice('s3tables:'.length) };\n            }\n            if (value.startsWith('s3:')) {\n                return { type: 's3', name: value.slice('s3:'.length) };\n            }\n            return { type: 's3', name: value };\n        }\n\n        // Build bucket permission action strings using original permissions dropdown\n        /**\n         * Builds bucket permission strings based on selected permissions and bucket scope.\n         * @param {string} mode - The operation mode, either 'create' or 'edit'.\n         * @returns {string[]|null} Array of permission strings (e.g., ['Read:bucket1']) or null if validation fails (specific scope selected but no buckets).\n         */\n        function buildBucketPermissions(mode) {\n            mode = mode || 'create';\n            const selectId = mode === 'edit' ? 'editActions' : 'actions';\n            const permSelect = document.getElementById(selectId);\n\n            if (!permSelect) return [];\n\n            // Get selected permissions from the original multi-select\n            const selectedPerms = Array.from(permSelect.selectedOptions).map(opt => opt.value);\n\n            const hasAdmin = selectedPerms.includes('Admin');\n            const hasS3TablesAdmin = selectedPerms.includes('S3TablesAdmin');\n\n            if (selectedPerms.length === 0) {\n                return [];\n            }\n\n            // Check if applying to all buckets or specific ones\n            // Use querySelector to find the checked radio button by name group\n            const scopeName = mode === 'edit' ? 'editBucketScope' : 'bucketScope';\n\n            // Try multiple methods to find the checked radio\n            let checkedRadio = document.querySelector(`input[name=\"${scopeName}\"]:checked`);\n\n            // Fallback: check both radio buttons explicitly\n            if (!checkedRadio) {\n                const allBucketsId = mode === 'edit' ? 'editAllBuckets' : 'allBuckets';\n                const specificBucketsId = mode === 'edit' ? 'editSpecificBuckets' : 'specificBuckets';\n\n                const allBucketsRadio = document.getElementById(allBucketsId);\n                const specificBucketsRadio = document.getElementById(specificBucketsId);\n\n                if (specificBucketsRadio && specificBucketsRadio.checked) {\n                    checkedRadio = specificBucketsRadio;\n                } else if (allBucketsRadio && allBucketsRadio.checked) {\n                    checkedRadio = allBucketsRadio;\n                }\n            }\n\n            // Default to 'all' if nothing is checked (shouldn't happen) or if 'all' is checked\n            const applyToAll = !checkedRadio || checkedRadio.value === 'all';\n\n            if (applyToAll) {\n                // Return global permissions (no bucket specification)\n                const actions = [];\n                if (hasAdmin) {\n                    actions.push('Admin');\n                }\n                if (hasS3TablesAdmin) {\n                    actions.push('s3tables:*');\n                }\n                selectedPerms.forEach(perm => {\n                    if (perm === 'Admin' || perm === 'S3TablesAdmin') {\n                        return;\n                    }\n                    if (isS3TablesPermission(perm)) {\n                        actions.push('s3tables:' + perm);\n                    } else {\n                        actions.push(perm);\n                    }\n                });\n                return actions;\n            } else {\n                // Get selected specific buckets\n                const bucketSelect = document.getElementById(mode === 'edit' ? 'editSelectedBuckets' : 'selectedBuckets');\n                if (!bucketSelect) return null;\n\n                const selectedBuckets = [...new Set(Array.from(bucketSelect.selectedOptions).map(opt => opt.value))];\n\n                // Return null to signal validation failure if no buckets selected\n                if (selectedBuckets.length === 0) {\n                    return null;\n                }\n\n                // Build bucket-scoped permissions\n                const actions = [];\n                if (hasAdmin) {\n                    selectedBuckets.forEach((bucket) => {\n                        const bucketInfo = parseBucketOptionValue(bucket);\n                        actions.push(\"Admin:\" + bucketInfo.name);\n                    });\n                }\n                if (hasS3TablesAdmin) {\n                    actions.push('s3tables:*');\n                }\n                selectedPerms.forEach(perm => {\n                    if (perm === 'Admin' || perm === 'S3TablesAdmin') {\n                        return;\n                    }\n                    selectedBuckets.forEach(bucket => {\n                        const bucketInfo = parseBucketOptionValue(bucket);\n                        if (isS3TablesPermission(perm)) {\n                            if (bucketInfo.type === 's3tables') {\n                                actions.push('s3tables:' + perm + ':' + bucketInfo.name);\n                            }\n                        } else if (bucketInfo.type === 's3') {\n                            actions.push(perm + ':' + bucketInfo.name);\n                        }\n                    });\n                });\n\n                return [...new Set(actions)];\n            }\n        }\n\n        // Show user details modal\n        async function showUserDetails(username) {\n            try {\n                const encodedUsername = encodeURIComponent(username);\n                const response = await fetch(basePath(`/api/users/${encodedUsername}`));\n                if (response.ok) {\n                    const user = await response.json();\n                    document.getElementById('userDetailsContent').innerHTML = createUserDetailsContent(user);\n                    const modal = new bootstrap.Modal(document.getElementById('userDetailsModal'));\n                    modal.show();\n                } else {\n                    showAlert('Failed to load user details', 'error');\n                }\n            } catch (error) {\n                console.error('Error loading user details:', error);\n                showAlert('Failed to load user details', 'error');\n            }\n        }\n\n        // Edit user function\n        async function editUser(username) {\n            try {\n                const encodedUsername = encodeURIComponent(username);\n                const response = await fetch(basePath(`/api/users/${encodedUsername}`));\n                if (response.ok) {\n                    const user = await response.json();\n\n                    // Populate edit form\n                    document.getElementById('editUsername').value = username;\n                    document.getElementById('editEmail').value = user.email || '';\n\n                    // Set selected actions\n                    const actionsSelect = document.getElementById('editActions');\n                    Array.from(actionsSelect.options).forEach(option => {\n                        option.selected = user.actions && user.actions.includes(option.value);\n                    });\n\n                    // Set selected policies\n                    const policiesSelect = document.getElementById('editPolicies');\n                    if (policiesSelect) {\n                        Array.from(policiesSelect.options).forEach(option => {\n                            option.selected = user.policy_names && user.policy_names.includes(option.value);\n                        });\n                    }\n\n                    // Populate bucket permissions using original permissions dropdown\n                    if (user.actions && user.actions.length > 0) {\n                        const bucketPerms = parseBucketPermissions(user.actions);\n\n                        // Set permissions in the original multi-select\n                        const actionsSelect = document.getElementById('editActions');\n                        if (actionsSelect) {\n                            Array.from(actionsSelect.options).forEach(option => {\n                                if (bucketPerms.isAdmin && option.value === 'Admin') {\n                                    option.selected = true;\n                                } else if (!bucketPerms.isAdmin && bucketPerms.permissions.includes(option.value)) {\n                                    option.selected = true;\n                                }\n                            });\n                        }\n\n                        // Set bucket scope (all or specific)\n                        const allBucketsRadio = document.getElementById('editAllBuckets');\n                        const specificBucketsRadio = document.getElementById('editSpecificBuckets');\n\n                        if (!bucketPerms.isAdmin) {\n                            if (bucketPerms.applyToAll) {\n                                if (allBucketsRadio) allBucketsRadio.checked = true;\n                            } else if (bucketPerms.specificBuckets.length > 0) {\n                                if (specificBucketsRadio) specificBucketsRadio.checked = true;\n                                toggleBucketList('edit');\n\n                                // Select specific buckets\n                                const bucketSelect = document.getElementById('editSelectedBuckets');\n                                if (bucketSelect) {\n                                    Array.from(bucketSelect.options).forEach(option => {\n                                        option.selected = bucketPerms.specificBuckets.includes(option.value);\n                                    });\n                                }\n                            }\n                        }\n                    }\n\n                    // Populate groups\n                    await populateEditUserGroups(username);\n\n                    // Show modal\n                    const modal = new bootstrap.Modal(document.getElementById('editUserModal'));\n                    modal.show();\n                } else {\n                    showAlert('Failed to load user details', 'error');\n                }\n            } catch (error) {\n                console.error('Error loading user:', error);\n                showAlert('Failed to load user details', 'error');\n            }\n        }\n\n        // Manage access keys function\n        async function manageAccessKeys(username) {\n            try {\n                const encodedUsername = encodeURIComponent(username);\n                const response = await fetch(basePath(`/api/users/${encodedUsername}`));\n                if (response.ok) {\n                    const user = await response.json();\n                    document.getElementById('accessKeysUsername').textContent = username;\n                    document.getElementById('accessKeysContent').innerHTML = createAccessKeysContent(user);\n                    const modal = new bootstrap.Modal(document.getElementById('accessKeysModal'));\n                    modal.show();\n                } else {\n                    showAlert('Failed to load access keys', 'error');\n                }\n            } catch (error) {\n                console.error('Error loading access keys:', error);\n                showAlert('Failed to load access keys', 'error');\n            }\n        }\n\n        // Delete user function\n        async function deleteUser(username) {\n            showDeleteConfirm(username, async function() {\n                try {\n                    const encodedUsername = encodeURIComponent(username);\n                    const response = await fetch(basePath(`/api/users/${encodedUsername}`), {\n                        method: 'DELETE'\n                    });\n\n                    if (response.ok) {\n                        showSuccessMessage('User deleted successfully');\n                        setTimeout(() => window.location.reload(), 1000);\n                    } else {\n                        const error = await response.json();\n                        showErrorMessage('Failed to delete user: ' + (error.error || 'Unknown error'));\n                    }\n                } catch (error) {\n                    console.error('Error deleting user:', error);\n                    showErrorMessage('Failed to delete user: ' + error.message);\n                }\n            }, 'Are you sure you want to delete this user? This action cannot be undone.');\n        }\n\n        // Handle create user form submission\n        async function handleCreateUser() {\n            const form = document.getElementById('createUserForm');\n            const formData = new FormData(form);\n\n            // Get permissions with bucket scope applied\n            const allActions = buildBucketPermissions('create');\n\n            if (allActions === null) {\n                showAlert('Please select at least one bucket when using specific bucket permissions', 'error');\n                return;\n            }\n\n            if (!allActions || allActions.length === 0) {\n                showAlert('At least one permission must be selected', 'error');\n                return;\n            }\n\n            const userData = {\n                username: formData.get('username'),\n                email: formData.get('email'),\n                actions: allActions,\n                policy_names: Array.from(document.getElementById('policies').selectedOptions).map(option => option.value),\n                generate_key: document.getElementById('generateKey').checked\n            };\n\n            try {\n                const response = await fetch(basePath('/api/users'), {\n                    method: 'POST',\n                    headers: {\n                        'Content-Type': 'application/json',\n                    },\n                    body: JSON.stringify(userData)\n                });\n\n                if (response.ok) {\n                    const result = await response.json();\n                    showSuccessMessage('User created successfully');\n\n                    // Show the created access key if generated\n                    if (result.user && result.user.access_key) {\n                        showNewAccessKeyModal(result.user);\n                    }\n\n                    // Close modal and refresh page\n                    const modal = bootstrap.Modal.getInstance(document.getElementById('createUserModal'));\n                    modal.hide();\n                    form.reset();\n                    document.getElementById('username').readOnly = false;\n                    document.getElementById('generateKey').disabled = false;\n                    setTimeout(() => window.location.reload(), 1000);\n                } else {\n                    const error = await response.json();\n                    showAlert('Failed to create user: ' + (error.error || 'Unknown error'), 'error');\n                }\n            } catch (error) {\n                console.error('Error creating user:', error);\n                showAlert('Failed to create user: ' + error.message, 'error');\n            }\n        }\n\n\n        // Populate groups in the edit user modal\n        async function populateEditUserGroups(username) {\n            const container = document.getElementById('editUserGroups');\n            const groupSelect = document.getElementById('editGroupSelect');\n            container.innerHTML = '';\n            groupSelect.innerHTML = '<option value=\"\">Add to group...</option>';\n\n            try {\n                // Fetch all groups\n                const groupsResp = await fetch(basePath('/api/groups'));\n                if (!groupsResp.ok) return;\n                const groupsData = await groupsResp.json();\n                const allGroups = groupsData.groups || [];\n\n                // Fetch user details to get current groups\n                const userResp = await fetch(basePath(`/api/users/${encodeURIComponent(username)}`));\n                if (!userResp.ok) return;\n                const user = await userResp.json();\n                const userGroups = user.groups || [];\n\n                // Show current group badges with remove button\n                if (userGroups.length > 0) {\n                    userGroups.forEach(function(group) {\n                        const badge = document.createElement('span');\n                        badge.className = 'badge bg-primary me-1 mb-1';\n                        badge.textContent = group + ' ';\n                        const removeIcon = document.createElement('i');\n                        removeIcon.className = 'fas fa-times ms-1';\n                        removeIcon.style.cursor = 'pointer';\n                        removeIcon.setAttribute('aria-label', 'Remove from group ' + group);\n                        removeIcon.setAttribute('title', 'Remove from group');\n                        removeIcon.addEventListener('click', function() {\n                            removeUserFromGroupInEdit(group);\n                        });\n                        badge.appendChild(removeIcon);\n                        container.appendChild(badge);\n                    });\n                } else {\n                    container.innerHTML = '<span class=\"text-muted\">No groups</span>';\n                }\n\n                // Populate dropdown with groups the user is NOT in\n                allGroups.forEach(function(g) {\n                    if (!userGroups.includes(g.name)) {\n                        const opt = document.createElement('option');\n                        opt.value = g.name;\n                        opt.textContent = g.name;\n                        groupSelect.appendChild(opt);\n                    }\n                });\n            } catch (error) {\n                console.error('Error loading groups:', error);\n            }\n        }\n\n        // Add user to group from edit modal\n        async function addUserToGroupFromEdit() {\n            const username = document.getElementById('editUsername').value;\n            const groupSelect = document.getElementById('editGroupSelect');\n            const groupName = groupSelect.value;\n            if (!groupName) return;\n\n            try {\n                const response = await fetch(basePath(`/api/groups/${encodeURIComponent(groupName)}/members`), {\n                    method: 'POST',\n                    headers: { 'Content-Type': 'application/json' },\n                    body: JSON.stringify({ username: username })\n                });\n                if (response.ok) {\n                    await populateEditUserGroups(username);\n                } else {\n                    const error = await response.json();\n                    showAlert('Failed to add to group: ' + (error.error || 'Unknown error'), 'error');\n                }\n            } catch (error) {\n                showAlert('Failed to add to group: ' + error.message, 'error');\n            }\n        }\n\n        // Remove user from group in edit modal\n        async function removeUserFromGroupInEdit(groupName) {\n            const username = document.getElementById('editUsername').value;\n            try {\n                const response = await fetch(basePath(`/api/groups/${encodeURIComponent(groupName)}/members/${encodeURIComponent(username)}`), {\n                    method: 'DELETE'\n                });\n                if (response.ok) {\n                    await populateEditUserGroups(username);\n                } else {\n                    const error = await response.json();\n                    showAlert('Failed to remove from group: ' + (error.error || 'Unknown error'), 'error');\n                }\n            } catch (error) {\n                showAlert('Failed to remove from group: ' + error.message, 'error');\n            }\n        }\n\n        // Handle update user form submission\n        async function handleUpdateUser() {\n            const username = document.getElementById('editUsername').value;\n            if (!username) {\n                showAlert('Username is required', 'error');\n                return;\n            }\n\n            // Get permissions with bucket scope applied\n            const allActions = buildBucketPermissions('edit');\n\n            // Check for null (validation failure from buildBucketPermissions)\n            if (allActions === null) {\n                showAlert('Please select at least one bucket when using specific bucket permissions', 'error');\n                return;\n            }\n\n            // Validate that permissions are not empty\n            if (!allActions || allActions.length === 0) {\n                showAlert('At least one permission must be selected', 'error');\n                return;\n            }\n\n            const userData = {\n                email: document.getElementById('editEmail').value,\n                actions: allActions,\n                policy_names: Array.from(document.getElementById('editPolicies').selectedOptions).map(option => option.value)\n            };\n\n            try {\n                const encodedUsername = encodeURIComponent(username);\n                const response = await fetch(basePath(`/api/users/${encodedUsername}`), {\n                    method: 'PUT',\n                    headers: {\n                        'Content-Type': 'application/json',\n                    },\n                    body: JSON.stringify(userData)\n                });\n\n                if (response.ok) {\n                    showSuccessMessage('User updated successfully');\n\n                    // Close modal and refresh page\n                    const modal = bootstrap.Modal.getInstance(document.getElementById('editUserModal'));\n                    modal.hide();\n                    setTimeout(() => window.location.reload(), 1000);\n                } else {\n                    const error = await response.json();\n                        showAlert('Failed to update user: ' + (error.error || 'Unknown error'), 'error');\n                }\n            } catch (error) {\n                console.error('Error updating user:', error);\n                showAlert('Failed to update user: ' + error.message, 'error');\n            }\n        }\n\n\n        // Create user details content\n        function createUserDetailsContent(user) {\n            var detailsHtml = '<div class=\"row\">';\n            detailsHtml += '<div class=\"col-md-6\">';\n            detailsHtml += '<h6 class=\"text-muted\">Basic Information</h6>';\n            detailsHtml += '<table class=\"table table-sm\">';\n            detailsHtml += '<tr><td><strong>Username:</strong></td><td>' + escapeHtml(user.username) + '</td></tr>';\n            detailsHtml += '<tr><td><strong>Email:</strong></td><td>' + escapeHtml(user.email || 'Not set') + '</td></tr>';\n            detailsHtml += '</table>';\n            detailsHtml += '</div>';\n            detailsHtml += '<div class=\"col-md-6\">';\n                         detailsHtml += '<h6 class=\"text-muted\">Permissions</h6>';\n             detailsHtml += '<div class=\"mb-3\">';\n             if (user.actions && user.actions.length > 0) {\n                 detailsHtml += user.actions.map(function(action) {\n                     return '<span class=\"badge bg-info me-1\">' + escapeHtml(action) + '</span>';\n                 }).join('');\n             } else {\n                 detailsHtml += '<span class=\"text-muted\">No permissions assigned</span>';\n             }\n              detailsHtml += '</div>';\n              detailsHtml += '<h6 class=\"text-muted\">Attached Policy Names</h6>';\n              detailsHtml += '<div class=\"mb-3\">';\n              if (user.policy_names && user.policy_names.length > 0) {\n                  detailsHtml += user.policy_names.map(function(policy) {\n                      return '<span class=\"badge bg-secondary me-1\">' + escapeHtml(policy) + '</span>';\n                  }).join('');\n              } else {\n                  detailsHtml += '<span class=\"text-muted\">No policies attached</span>';\n              }\n              detailsHtml += '</div>';\n              detailsHtml += '<h6 class=\"text-muted\">Groups</h6>';\n              detailsHtml += '<div class=\"mb-3\">';\n              if (user.groups && user.groups.length > 0) {\n                  detailsHtml += user.groups.map(function(group) {\n                      return '<span class=\"badge bg-primary me-1\">' + escapeHtml(group) + '</span>';\n                  }).join('');\n              } else {\n                  detailsHtml += '<span class=\"text-muted\">No groups</span>';\n              }\n              detailsHtml += '</div>';\n              detailsHtml += '<h6 class=\"text-muted\">Access Keys</h6>';\n             if (user.access_keys && user.access_keys.length > 0) {\n                 detailsHtml += '<div class=\"mb-2\">';\n                 user.access_keys.forEach(function(key) {\n                     detailsHtml += '<div><code class=\"text-muted\">' + escapeHtml(key.access_key) + '</code></div>';\n                 });\n                 detailsHtml += '</div>';\n             } else {\n                 detailsHtml += '<p class=\"text-muted\">No access keys</p>';\n             }\n            detailsHtml += '</div>';\n            detailsHtml += '</div>';\n            return detailsHtml;\n        }\n\n        // Create access keys content\n        function createAccessKeysContent(user) {\n            if (!user.access_keys || user.access_keys.length === 0) {\n                return '<p class=\"text-muted\">No access keys available</p>';\n            }\n\n            var keysHtml = '<div class=\"table-responsive\">';\n            keysHtml += '<table class=\"table table-sm\">';\n            keysHtml += '<thead><tr><th>Access Key</th><th>Status</th><th>Actions</th></tr></thead>';\n            keysHtml += '<tbody>';\n\n            user.access_keys.forEach(function(key) {\n                keysHtml += '<tr>';\n                keysHtml += '<td><code>' + escapeHtml(key.access_key) + '</code></td>';\n                keysHtml += '<td>';\n                keysHtml += '<select class=\"form-select form-select-sm access-key-status-select\" data-username=\"' + escapeHtml(user.username) + '\" data-access-key=\"' + escapeHtml(key.access_key) + '\" style=\"width: 110px;\">';\n                keysHtml += '<option value=\"' + STATUS_ACTIVE + '\" ' + (key.status === STATUS_ACTIVE || !key.status ? 'selected' : '') + '>' + STATUS_ACTIVE + '</option>';\n                keysHtml += '<option value=\"' + STATUS_INACTIVE + '\" ' + (key.status === STATUS_INACTIVE ? 'selected' : '') + '>' + STATUS_INACTIVE + '</option>';\n                keysHtml += '</select>';\n                keysHtml += '</td>';\n                keysHtml += '<td>';\n                // Add \"View Secret\" button with data attributes\n                keysHtml += '<button class=\"btn btn-outline-secondary btn-sm me-2 view-secret-btn\" data-access-key=\"' + escapeHtml(key.access_key) + '\" data-secret-key=\"' + escapeHtml(key.secret_key) + '\">';\n                keysHtml += '<i class=\"fas fa-eye\"></i> View Secret';\n                keysHtml += '</button>';\n                // Delete button\n                keysHtml += '<button class=\"btn btn-outline-danger btn-sm delete-access-key-btn\" data-username=\"' + escapeHtml(user.username) + '\" data-access-key=\"' + escapeHtml(key.access_key) + '\">';\n                keysHtml += '<i class=\"fas fa-trash\"></i> Delete';\n                keysHtml += '</button>';\n                keysHtml += '</td>';\n                keysHtml += '</tr>';\n            });\n\n            keysHtml += '</tbody>';\n            keysHtml += '</table>';\n            keysHtml += '</div>';\n\n            // Add delegated event listener for view secret buttons\n            setTimeout(() => {\n                document.querySelectorAll('.view-secret-btn').forEach(btn => {\n                    btn.addEventListener('click', function() {\n                        const accessKey = this.getAttribute('data-access-key');\n                        const secretKey = this.getAttribute('data-secret-key');\n                        showSecretKey(accessKey, secretKey);\n                    });\n                });\n            }, 100);\n\n            return keysHtml;\n        }\n\n        // Refresh access keys list content\n        async function refreshAccessKeysList(username) {\n            try {\n                const encodedUsername = encodeURIComponent(username);\n                const response = await fetch(basePath(`/api/users/${encodedUsername}`));\n                if (response.ok) {\n                    const user = await response.json();\n                    document.getElementById('accessKeysContent').innerHTML = createAccessKeysContent(user);\n                }\n            } catch (error) {\n                console.error('Error refreshing access keys:', error);\n            }\n        }\n\n        // Update access key status\n        async function updateAccessKeyStatus(username, accessKey, status) {\n            try {\n                const response = await fetch(basePath(`/api/users/${encodeURIComponent(username)}/access-keys/${encodeURIComponent(accessKey)}/status`), {\n                    method: 'PUT',\n                    headers: {\n                        'Content-Type': 'application/json',\n                    },\n                    body: JSON.stringify({ status: status })\n                });\n\n                if (response.ok) {\n                    showSuccessMessage('Access key status updated successfully');\n                    // Refresh access keys display without toggling modal\n                    refreshAccessKeysList(username);\n                } else {\n                    const error = await response.json();\n                        showAlert('Failed to update access key status: ' + (error.error || 'Unknown error'), 'error');\n                    refreshAccessKeysList(username);\n                }\n            } catch (error) {\n                console.error('Error updating access key status:', error);\n                showAlert('Failed to update access key status: ' + error.message, 'error');\n                refreshAccessKeysList(username);\n            }\n        }\n\n        // Reset and hide the create key form\n        function resetCreateKeyForm() {\n            document.getElementById('createKeyForm').style.display = 'none';\n            document.getElementById('newAccessKeyInput').value = '';\n            document.getElementById('newSecretKeyInput').value = '';\n            document.getElementById('newSecretKeyInput').type = 'password';\n            document.getElementById('secretKeyToggleIcon').className = 'fas fa-eye';\n        }\n\n        // Toggle create key form visibility\n        function toggleCreateKeyForm() {\n            const form = document.getElementById('createKeyForm');\n            if (form.style.display === 'none') {\n                form.style.display = 'block';\n            } else {\n                resetCreateKeyForm();\n            }\n        }\n\n        // Toggle secret key input visibility\n        function toggleSecretKeyVisibility() {\n            const input = document.getElementById('newSecretKeyInput');\n            const icon = document.getElementById('secretKeyToggleIcon');\n            if (input.type === 'password') {\n                input.type = 'text';\n                icon.className = 'fas fa-eye-slash';\n            } else {\n                input.type = 'password';\n                icon.className = 'fas fa-eye';\n            }\n        }\n\n        // Reset form when modal is dismissed\n        document.getElementById('accessKeysModal').addEventListener('hidden.bs.modal', resetCreateKeyForm);\n\n        // Create new access key\n        var isCreatingKey = false;\n        async function createAccessKey() {\n            if (isCreatingKey) return;\n\n            const username = document.getElementById('accessKeysUsername').textContent;\n            const accessKeyInput = document.getElementById('newAccessKeyInput');\n            const secretKeyInput = document.getElementById('newSecretKeyInput');\n            if ((accessKeyInput.value.trim() && !accessKeyInput.reportValidity()) ||\n                (secretKeyInput.value.trim() && !secretKeyInput.reportValidity())) {\n                return;\n            }\n            const accessKey = accessKeyInput.value.trim();\n            const secretKey = secretKeyInput.value.trim();\n\n            const body = {};\n            if (accessKey) body.access_key = accessKey;\n            if (secretKey) body.secret_key = secretKey;\n\n            isCreatingKey = true;\n            const createBtn = document.querySelector('#createKeyForm .btn-primary');\n            const cancelBtn = document.querySelector('#createKeyForm .btn-secondary');\n            if (createBtn) createBtn.disabled = true;\n            if (cancelBtn) cancelBtn.disabled = true;\n\n            try {\n                const encodedUsername = encodeURIComponent(username);\n                const response = await fetch(basePath(`/api/users/${encodedUsername}/access-keys`), {\n                    method: 'POST',\n                    headers: {\n                        'Content-Type': 'application/json',\n                    },\n                    body: JSON.stringify(body)\n                });\n\n                if (response.ok) {\n                    const result = await response.json();\n\n                    // Show the new access key details\n                    if (result.access_key) {\n                        showNewAccessKeyModal(result.access_key);\n                    }\n\n                    showSuccessMessage('Access key created successfully');\n                    resetCreateKeyForm();\n\n                    // Refresh access keys display\n                    refreshAccessKeysList(username);\n                } else {\n                    const error = await response.json();\n                        showAlert('Failed to create access key: ' + (error.error || 'Unknown error'), 'error');\n                }\n            } catch (error) {\n                console.error('Error creating access key:', error);\n                showAlert('Failed to create access key: ' + error.message, 'error');\n            } finally {\n                isCreatingKey = false;\n                if (createBtn) createBtn.disabled = false;\n                if (cancelBtn) cancelBtn.disabled = false;\n            }\n        }\n\n        // Delete access key\n        async function deleteAccessKey(username, accessKey) {\n            showDeleteConfirm(accessKey, async function() {\n                try {\n                    const encodedUsername = encodeURIComponent(username);\n                    const encodedAccessKey = encodeURIComponent(accessKey);\n                    const response = await fetch(basePath(`/api/users/${encodedUsername}/access-keys/${encodedAccessKey}`), {\n                        method: 'DELETE'\n                    });\n\n                    if (response.ok) {\n                        showSuccessMessage('Access key deleted successfully');\n\n                        // Refresh access keys display\n                        refreshAccessKeysList(username);\n                    } else {\n                        const error = await response.json();\n                        showErrorMessage('Failed to delete access key: ' + (error.error || 'Unknown error'));\n                    }\n                } catch (error) {\n                    console.error('Error deleting access key:', error);\n                    showErrorMessage('Failed to delete access key: ' + error.message);\n                }\n            }, 'Are you sure you want to delete this access key?');\n        }\n\n\n        // Utility functions\n        function showSuccessMessage(message) {\n            // Simple implementation - could be enhanced with toast notifications\n            alert('Success: ' + message);\n        }\n\n        function showErrorMessage(message) {\n            showAlert(message, 'error');\n        }\n\n        function escapeHtml(text) {\n            if (!text) return '';\n            const div = document.createElement('div');\n            div.textContent = text;\n            return div.innerHTML;\n        }\n    </script>")
		if templ_7745c5c3_Err != nil {
			return templ_7745c5c3_Err
		}
		return nil
	})
}

// Helper functions for template
var _ = templruntime.GeneratedTemplate
