You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
283 lines
35 KiB
283 lines
35 KiB
// Code generated by templ - DO NOT EDIT.
|
|
|
|
// templ: version: v0.3.960
|
|
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 ServiceAccounts(data dash.ServiceAccountsData) 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-robot me-2\"></i>Service Accounts</h1><p class=\"mb-0 text-muted\">Manage application credentials for automated processes</p></div><div class=\"d-flex gap-2\"><button type=\"button\" class=\"btn btn-primary\" data-bs-toggle=\"modal\" data-bs-target=\"#createServiceAccountModal\"><i class=\"fas fa-plus me-1\"></i>Create Service Account</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 Service Accounts</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.TotalAccounts))
|
|
if templ_7745c5c3_Err != nil {
|
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/service_accounts.templ`, Line: 38, Col: 74}
|
|
}
|
|
_, 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-id-card 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\">Active Accounts</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", data.ActiveAccounts))
|
|
if templ_7745c5c3_Err != nil {
|
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/service_accounts.templ`, Line: 58, Col: 75}
|
|
}
|
|
_, 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-check-circle 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/service_accounts.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><!-- Service Accounts 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-robot me-2\"></i>Service Accounts</h6></div><div class=\"card-body\"><div class=\"table-responsive\"><table class=\"table table-hover\" width=\"100%\" cellspacing=\"0\" id=\"serviceAccountsTable\"><thead><tr><th>ID</th><th>Parent User</th><th>Access Key</th><th>Status</th><th>Created</th><th>Actions</th></tr></thead> <tbody>")
|
|
if templ_7745c5c3_Err != nil {
|
|
return templ_7745c5c3_Err
|
|
}
|
|
for _, sa := range data.ServiceAccounts {
|
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "<tr><td><div class=\"d-flex align-items-center\"><i class=\"fas fa-robot me-2 text-muted\"></i> <code>")
|
|
if templ_7745c5c3_Err != nil {
|
|
return templ_7745c5c3_Err
|
|
}
|
|
var templ_7745c5c3_Var5 string
|
|
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(sa.ID)
|
|
if templ_7745c5c3_Err != nil {
|
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/service_accounts.templ`, Line: 118, Col: 64}
|
|
}
|
|
_, 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, "</code></div></td><td><i class=\"fas fa-user me-1 text-muted\"></i> ")
|
|
if templ_7745c5c3_Err != nil {
|
|
return templ_7745c5c3_Err
|
|
}
|
|
var templ_7745c5c3_Var6 string
|
|
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(sa.ParentUser)
|
|
if templ_7745c5c3_Err != nil {
|
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/service_accounts.templ`, Line: 123, Col: 62}
|
|
}
|
|
_, 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, 7, "</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(sa.AccessKeyId)
|
|
if templ_7745c5c3_Err != nil {
|
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/service_accounts.templ`, Line: 126, 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, 8, "</code></td><td>")
|
|
if templ_7745c5c3_Err != nil {
|
|
return templ_7745c5c3_Err
|
|
}
|
|
if sa.Status == "Active" {
|
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "<span class=\"badge bg-success\">Active</span>")
|
|
if templ_7745c5c3_Err != nil {
|
|
return templ_7745c5c3_Err
|
|
}
|
|
} else {
|
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "<span class=\"badge bg-secondary\">Inactive</span>")
|
|
if templ_7745c5c3_Err != nil {
|
|
return templ_7745c5c3_Err
|
|
}
|
|
}
|
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "</td><td>")
|
|
if templ_7745c5c3_Err != nil {
|
|
return templ_7745c5c3_Err
|
|
}
|
|
var templ_7745c5c3_Var8 string
|
|
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(sa.CreateDate.Format("2006-01-02"))
|
|
if templ_7745c5c3_Err != nil {
|
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/service_accounts.templ`, Line: 135, Col: 83}
|
|
}
|
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
|
|
if templ_7745c5c3_Err != nil {
|
|
return templ_7745c5c3_Err
|
|
}
|
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "</td><td><div class=\"btn-group btn-group-sm\" role=\"group\"><button type=\"button\" class=\"btn btn-outline-info\" data-action=\"show-sa-details\" data-sa-id=\"")
|
|
if templ_7745c5c3_Err != nil {
|
|
return templ_7745c5c3_Err
|
|
}
|
|
var templ_7745c5c3_Var9 string
|
|
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(sa.ID)
|
|
if templ_7745c5c3_Err != nil {
|
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/service_accounts.templ`, Line: 139, Col: 108}
|
|
}
|
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(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-info-circle\"></i></button> <button type=\"button\" class=\"btn btn-outline-primary\" data-action=\"toggle-sa-status\" data-sa-id=\"")
|
|
if templ_7745c5c3_Err != nil {
|
|
return templ_7745c5c3_Err
|
|
}
|
|
var templ_7745c5c3_Var10 string
|
|
templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(sa.ID)
|
|
if templ_7745c5c3_Err != nil {
|
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/service_accounts.templ`, Line: 143, Col: 109}
|
|
}
|
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10))
|
|
if templ_7745c5c3_Err != nil {
|
|
return templ_7745c5c3_Err
|
|
}
|
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "\" data-current-status=\"")
|
|
if templ_7745c5c3_Err != nil {
|
|
return templ_7745c5c3_Err
|
|
}
|
|
var templ_7745c5c3_Var11 string
|
|
templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(sa.Status)
|
|
if templ_7745c5c3_Err != nil {
|
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/service_accounts.templ`, Line: 143, Col: 143}
|
|
}
|
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11))
|
|
if templ_7745c5c3_Err != nil {
|
|
return templ_7745c5c3_Err
|
|
}
|
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "\">")
|
|
if templ_7745c5c3_Err != nil {
|
|
return templ_7745c5c3_Err
|
|
}
|
|
if sa.Status == "Active" {
|
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "<i class=\"fas fa-pause\"></i>")
|
|
if templ_7745c5c3_Err != nil {
|
|
return templ_7745c5c3_Err
|
|
}
|
|
} else {
|
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "<i class=\"fas fa-play\"></i>")
|
|
if templ_7745c5c3_Err != nil {
|
|
return templ_7745c5c3_Err
|
|
}
|
|
}
|
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "</button> <button type=\"button\" class=\"btn btn-outline-danger\" data-action=\"delete-sa\" data-sa-id=\"")
|
|
if templ_7745c5c3_Err != nil {
|
|
return templ_7745c5c3_Err
|
|
}
|
|
var templ_7745c5c3_Var12 string
|
|
templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(sa.ID)
|
|
if templ_7745c5c3_Err != nil {
|
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/service_accounts.templ`, Line: 151, Col: 102}
|
|
}
|
|
_, 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, 19, "\"><i class=\"fas fa-trash\"></i></button></div></td></tr>")
|
|
if templ_7745c5c3_Err != nil {
|
|
return templ_7745c5c3_Err
|
|
}
|
|
}
|
|
if len(data.ServiceAccounts) == 0 {
|
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "<tr><td colspan=\"6\" class=\"text-center text-muted py-4\"><i class=\"fas fa-robot fa-3x mb-3 text-muted\"></i><div><h5>No service accounts found</h5><p>Create your first service account for automated processes.</p></div></td></tr>")
|
|
if templ_7745c5c3_Err != nil {
|
|
return templ_7745c5c3_Err
|
|
}
|
|
}
|
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, "</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_Var13 string
|
|
templ_7745c5c3_Var13, 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/service_accounts.templ`, Line: 182, Col: 81}
|
|
}
|
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13))
|
|
if templ_7745c5c3_Err != nil {
|
|
return templ_7745c5c3_Err
|
|
}
|
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, "</small></div></div></div><!-- Create Service Account Modal --><div class=\"modal fade\" id=\"createServiceAccountModal\" 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-plus me-2\"></i>Create Service Account</h5><button type=\"button\" class=\"btn-close\" data-bs-dismiss=\"modal\"></button></div><div class=\"modal-body\"><form id=\"createSAForm\"><div class=\"mb-3\"><label for=\"parentUser\" class=\"form-label\">Parent User *</label> <select class=\"form-select\" id=\"parentUser\" name=\"parent_user\" required><option value=\"\">-- Select a user --</option> ")
|
|
if templ_7745c5c3_Err != nil {
|
|
return templ_7745c5c3_Err
|
|
}
|
|
for _, user := range data.AvailableUsers {
|
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, "<option value=\"")
|
|
if templ_7745c5c3_Err != nil {
|
|
return templ_7745c5c3_Err
|
|
}
|
|
var templ_7745c5c3_Var14 string
|
|
templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(user)
|
|
if templ_7745c5c3_Err != nil {
|
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/service_accounts.templ`, Line: 205, Col: 56}
|
|
}
|
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14))
|
|
if templ_7745c5c3_Err != nil {
|
|
return templ_7745c5c3_Err
|
|
}
|
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "\">")
|
|
if templ_7745c5c3_Err != nil {
|
|
return templ_7745c5c3_Err
|
|
}
|
|
var templ_7745c5c3_Var15 string
|
|
templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinStringErrs(user)
|
|
if templ_7745c5c3_Err != nil {
|
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/service_accounts.templ`, Line: 205, Col: 65}
|
|
}
|
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var15))
|
|
if templ_7745c5c3_Err != nil {
|
|
return templ_7745c5c3_Err
|
|
}
|
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, "</option>")
|
|
if templ_7745c5c3_Err != nil {
|
|
return templ_7745c5c3_Err
|
|
}
|
|
}
|
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, "</select> <small class=\"form-text text-muted\">The service account will inherit permissions from this user</small></div><div class=\"mb-3\"><label for=\"description\" class=\"form-label\">Description</label> <textarea class=\"form-control\" id=\"description\" name=\"description\" rows=\"2\" placeholder=\"What is this service account used for?\"></textarea></div><div class=\"mb-3\"><label for=\"expiration\" class=\"form-label\">Expiration (optional)</label> <input type=\"datetime-local\" class=\"form-control\" id=\"expiration\" name=\"expiration\"> <small class=\"form-text text-muted\">Leave empty for no expiration</small></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=\"handleCreateServiceAccount()\">Create</button></div></div></div></div><!-- Service Account Details Modal --><div class=\"modal fade\" id=\"saDetailsModal\" 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-robot me-2\"></i>Service Account Details</h5><button type=\"button\" class=\"btn-close\" data-bs-dismiss=\"modal\"></button></div><div class=\"modal-body\" id=\"saDetailsContent\"><!-- 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><!-- Credentials Display Modal --><div class=\"modal fade\" id=\"credentialsModal\" tabindex=\"-1\" role=\"dialog\" data-bs-backdrop=\"static\" data-bs-keyboard=\"false\"><div class=\"modal-dialog modal-lg\" role=\"document\"><div class=\"modal-content\"><div class=\"modal-header bg-success text-white\"><h5 class=\"modal-title\"><i class=\"fas fa-check-circle me-2\"></i>Service Account Created Successfully</h5></div><div class=\"modal-body\"><div class=\"alert alert-warning\"><i class=\"fas fa-exclamation-triangle me-2\"></i> <strong>Important:</strong> This is the only time you will see the secret access key. Please save it securely.</div><div class=\"mb-4\"><h6 class=\"text-muted mb-3\">AWS CLI Configuration</h6><p class=\"text-muted small\">Use these credentials to configure AWS CLI or SDKs:</p><div class=\"mb-3\"><label class=\"form-label fw-bold\">AWS_ACCESS_KEY_ID</label><div class=\"input-group\"><input type=\"text\" class=\"form-control font-monospace\" id=\"displayAccessKey\" readonly> <button class=\"btn btn-outline-secondary\" type=\"button\" onclick=\"copyCredentialToClipboard(this, 'displayAccessKey')\"><i class=\"fas fa-copy\"></i> Copy</button></div></div><div class=\"mb-3\"><label class=\"form-label fw-bold\">AWS_SECRET_ACCESS_KEY</label><div class=\"input-group\"><input type=\"text\" class=\"form-control font-monospace\" id=\"displaySecretKey\" readonly> <button class=\"btn btn-outline-secondary\" type=\"button\" onclick=\"copyCredentialToClipboard(this, 'displaySecretKey')\"><i class=\"fas fa-copy\"></i> Copy</button></div></div></div><div class=\"bg-light p-3 rounded\"><h6 class=\"text-muted mb-2\">Example AWS CLI Usage:</h6><div class=\"font-monospace small\"><div>export AWS_ACCESS_KEY_ID=<span id=\"exampleAccessKey\"></span></div><div>export AWS_SECRET_ACCESS_KEY=<span id=\"exampleSecretKey\"></span></div><div>export AWS_ENDPOINT_URL=http://localhost:8333</div><div class=\"mt-2\"># List buckets</div><div>aws s3 ls</div><div class=\"mt-2\"># Upload a file</div><div>aws s3 cp myfile.txt s3://mybucket/</div></div></div></div><div class=\"modal-footer\"><button type=\"button\" class=\"btn btn-primary\" onclick=\"closeCredentialsModal()\"><i class=\"fas fa-check me-1\"></i>I have saved the credentials</button></div></div></div></div><!-- JavaScript for service account management --><script>\n document.addEventListener('DOMContentLoaded', function() {\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 saId = button.getAttribute('data-sa-id');\n \n switch (action) {\n case 'show-sa-details':\n showSADetails(saId);\n break;\n case 'toggle-sa-status':\n toggleSAStatus(saId, button.getAttribute('data-current-status'));\n break;\n case 'delete-sa':\n deleteSA(saId);\n break;\n }\n });\n });\n\n async function showSADetails(id) {\n try {\n const response = await fetch(`/api/service-accounts/${id}`);\n if (response.ok) {\n const sa = await response.json();\n document.getElementById('saDetailsContent').innerHTML = createSADetailsContent(sa);\n const modal = new bootstrap.Modal(document.getElementById('saDetailsModal'));\n modal.show();\n } else {\n showErrorMessage('Failed to load service account details');\n }\n } catch (error) {\n console.error('Error loading service account details:', error);\n showErrorMessage('Failed to load service account details');\n }\n }\n\n async function toggleSAStatus(id, currentStatus) {\n const newStatus = currentStatus === 'Active' ? 'Inactive' : 'Active';\n try {\n const response = await fetch(`/api/service-accounts/${id}`, {\n method: 'PUT',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ status: newStatus })\n });\n \n if (response.ok) {\n showSuccessMessage(`Service account ${newStatus === 'Active' ? 'activated' : 'deactivated'}`);\n setTimeout(() => window.location.reload(), 1000);\n } else {\n const error = await response.json();\n showErrorMessage('Failed to update status: ' + (error.error || 'Unknown error'));\n }\n } catch (error) {\n console.error('Error updating status:', error);\n showErrorMessage('Failed to update status: ' + error.message);\n }\n }\n\n async function deleteSA(id) {\n if (confirm('Are you sure you want to delete this service account? This action cannot be undone.')) {\n try {\n const response = await fetch(`/api/service-accounts/${id}`, {\n method: 'DELETE'\n });\n \n if (response.ok) {\n showSuccessMessage('Service account deleted successfully');\n setTimeout(() => window.location.reload(), 1000);\n } else {\n const error = await response.json();\n showErrorMessage('Failed to delete: ' + (error.error || 'Unknown error'));\n }\n } catch (error) {\n console.error('Error deleting service account:', error);\n showErrorMessage('Failed to delete: ' + error.message);\n }\n }\n }\n\n async function handleCreateServiceAccount() {\n const form = document.getElementById('createSAForm');\n const formData = new FormData(form);\n \n const saData = {\n parent_user: formData.get('parent_user'),\n description: formData.get('description')\n };\n \n // Handle expiration if set\n const expiration = formData.get('expiration');\n if (expiration) {\n // Validate the date before using it\n const date = new Date(expiration);\n const now = new Date();\n \n if (isNaN(date.getTime())) {\n showErrorMessage('Invalid expiration date format');\n return;\n }\n \n // Ensure expiration is in the future\n if (date <= now) {\n showErrorMessage('Expiration date must be in the future');\n return;\n }\n \n saData.expiration = date.toISOString();\n }\n \n try {\n const response = await fetch('/api/service-accounts', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(saData)\n });\n \n if (response.ok) {\n const result = await response.json();\n \n // Hide create modal\n const createModal = bootstrap.Modal.getInstance(document.getElementById('createServiceAccountModal'));\n createModal.hide();\n form.reset();\n \n // Show credentials if returned\n if (result.service_account && result.service_account.secret_access_key) {\n showCredentials(result.service_account);\n } else {\n showSuccessMessage('Service account created successfully');\n setTimeout(() => window.location.reload(), 1000);\n }\n } else {\n const error = await response.json();\n showErrorMessage('Failed to create service account: ' + (error.error || 'Unknown error'));\n }\n } catch (error) {\n console.error('Error creating service account:', error);\n showErrorMessage('Failed to create service account: ' + error.message);\n }\n }\n\n function showCredentials(serviceAccount) {\n // Populate the credentials modal\n document.getElementById('displayAccessKey').value = serviceAccount.access_key_id;\n document.getElementById('displaySecretKey').value = serviceAccount.secret_access_key;\n document.getElementById('exampleAccessKey').textContent = serviceAccount.access_key_id;\n document.getElementById('exampleSecretKey').textContent = serviceAccount.secret_access_key;\n \n // Show the modal\n const credentialsModal = new bootstrap.Modal(document.getElementById('credentialsModal'));\n credentialsModal.show();\n }\n\n function closeCredentialsModal() {\n const modal = bootstrap.Modal.getInstance(document.getElementById('credentialsModal'));\n modal.hide();\n // Reload to show the new service account in the list\n setTimeout(() => window.location.reload(), 500);\n }\n\n function copyCredentialToClipboard(button, elementId) {\n const element = document.getElementById(elementId);\n const textToCopy = element.value;\n \n // Use modern Clipboard API if available\n if (navigator.clipboard && navigator.clipboard.writeText) {\n navigator.clipboard.writeText(textToCopy).then(() => {\n showSuccessMessage('Copied to clipboard!');\n }).catch(err => {\n console.warn('Clipboard API failed:', err);\n // Fallback\n fallbackCopyTextToClipboard(element);\n });\n } else {\n // Fallback for older browsers or non-secure contexts\n fallbackCopyTextToClipboard(element);\n }\n \n // Visual feedback\n const originalHTML = button.innerHTML;\n \n button.innerHTML = '<i class=\"fas fa-check\"></i>';\n button.classList.remove('btn-outline-secondary');\n button.classList.add('btn-success');\n \n setTimeout(() => {\n button.innerHTML = originalHTML;\n button.classList.remove('btn-success');\n button.classList.add('btn-outline-secondary');\n }, 1000);\n }\n\n function fallbackCopyTextToClipboard(element) {\n element.select();\n element.setSelectionRange(0, 99999); // For mobile devices\n \n try {\n const successful = document.execCommand('copy');\n if (successful) {\n showSuccessMessage('Copied to clipboard!');\n } else {\n showErrorMessage('Failed to copy to clipboard');\n }\n } catch (err) {\n console.error('Fallback copy failed:', err);\n showErrorMessage('Failed to copy to clipboard');\n }\n \n // Clear selection\n window.getSelection().removeAllRanges();\n }\n\n\n function createSADetailsContent(sa) {\n // Create DOM elements safely to prevent XSS\n const container = document.createElement('div');\n container.className = 'row';\n \n // Basic Information column\n const col1 = document.createElement('div');\n col1.className = 'col-md-6';\n \n const h6_1 = document.createElement('h6');\n h6_1.className = 'text-muted';\n h6_1.textContent = 'Basic Information';\n col1.appendChild(h6_1);\n \n const table1 = document.createElement('table');\n table1.className = 'table table-sm';\n \n // ID row\n const idRow = document.createElement('tr');\n idRow.innerHTML = '<td><strong>ID:</strong></td><td><code></code></td>';\n idRow.querySelector('code').textContent = sa.id || '';\n table1.appendChild(idRow);\n \n // Parent User row\n const parentRow = document.createElement('tr');\n parentRow.innerHTML = '<td><strong>Parent User:</strong></td><td></td>';\n parentRow.querySelectorAll('td')[1].textContent = sa.parent_user || '';\n table1.appendChild(parentRow);\n \n // Access Key row\n const keyRow = document.createElement('tr');\n keyRow.innerHTML = '<td><strong>Access Key:</strong></td><td><code></code></td>';\n keyRow.querySelector('code').textContent = sa.access_key_id || '';\n table1.appendChild(keyRow);\n \n // Status row\n const statusRow = document.createElement('tr');\n const statusTd1 = document.createElement('td');\n statusTd1.innerHTML = '<strong>Status:</strong>';\n const statusTd2 = document.createElement('td');\n const statusBadge = document.createElement('span');\n statusBadge.className = sa.status === 'Active' ? 'badge bg-success' : 'badge bg-secondary';\n statusBadge.textContent = sa.status || 'Unknown';\n statusTd2.appendChild(statusBadge);\n statusRow.appendChild(statusTd1);\n statusRow.appendChild(statusTd2);\n table1.appendChild(statusRow);\n \n col1.appendChild(table1);\n container.appendChild(col1);\n \n // Details column\n const col2 = document.createElement('div');\n col2.className = 'col-md-6';\n \n const h6_2 = document.createElement('h6');\n h6_2.className = 'text-muted';\n h6_2.textContent = 'Details';\n col2.appendChild(h6_2);\n \n const table2 = document.createElement('table');\n table2.className = 'table table-sm';\n \n // Description row\n const descRow = document.createElement('tr');\n descRow.innerHTML = '<td><strong>Description:</strong></td><td></td>';\n descRow.querySelectorAll('td')[1].textContent = sa.description || 'Not set';\n table2.appendChild(descRow);\n \n // Created row\n const createdRow = document.createElement('tr');\n createdRow.innerHTML = '<td><strong>Created:</strong></td><td></td>';\n try {\n createdRow.querySelectorAll('td')[1].textContent = new Date(sa.create_date).toLocaleString();\n } catch (e) {\n createdRow.querySelectorAll('td')[1].textContent = 'Invalid date';\n }\n table2.appendChild(createdRow);\n \n // Expiration row\n const expRow = document.createElement('tr');\n expRow.innerHTML = '<td><strong>Expires:</strong></td><td></td>';\n expRow.querySelectorAll('td')[1].textContent = sa.expiration || 'Never';\n table2.appendChild(expRow);\n \n col2.appendChild(table2);\n container.appendChild(col2);\n \n return container.outerHTML;\n }\n\n\n function showSuccessMessage(message) {\n showToast(message, 'success');\n }\n\n function showErrorMessage(message) {\n showToast(message, 'danger');\n }\n\n function showToast(message, type) {\n // Create toast container if it doesn't exist\n let toastContainer = document.getElementById('toastContainer');\n if (!toastContainer) {\n toastContainer = document.createElement('div');\n toastContainer.id = 'toastContainer';\n toastContainer.className = 'toast-container position-fixed top-0 end-0 p-3';\n toastContainer.style.zIndex = '9999';\n document.body.appendChild(toastContainer);\n }\n\n // Create toast element\n const toastId = 'toast-' + Date.now();\n const toastHTML = `\n <div id=\"${toastId}\" class=\"toast align-items-center text-white bg-${type} border-0\" role=\"alert\" aria-live=\"assertive\" aria-atomic=\"true\">\n <div class=\"d-flex\">\n <div class=\"toast-body\">\n ${escapeHtml(message)}\n </div>\n <button type=\"button\" class=\"btn-close btn-close-white me-2 m-auto\" data-bs-dismiss=\"toast\" aria-label=\"Close\"></button>\n </div>\n </div>\n `;\n \n toastContainer.insertAdjacentHTML('beforeend', toastHTML);\n const toastElement = document.getElementById(toastId);\n const toast = new bootstrap.Toast(toastElement, { autohide: true, delay: 5000 });\n toast.show();\n \n // Remove toast element after it's hidden\n toastElement.addEventListener('hidden.bs.toast', () => {\n toastElement.remove();\n });\n }\n\n function escapeHtml(text) {\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
|
|
})
|
|
}
|
|
|
|
var _ = templruntime.GeneratedTemplate
|