Files
seaweedfs/weed/admin/view/app/policies_templ.go
T
2026-09-16 20:29:14 -07:00

213 lines
36 KiB
Go

// 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 Policies(data dash.PoliciesData) 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=\"d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom\"><h1 class=\"h2\"><i class=\"bi bi-shield me-2\"></i>IAM Policies</h1><div class=\"btn-toolbar mb-2 mb-md-0\"><div class=\"btn-group me-2\"><button type=\"button\" class=\"btn btn-sm btn-primary\" data-bs-toggle=\"modal\" data-bs-target=\"#createPolicyModal\"><i class=\"bi bi-plus me-1\"></i>Create Policy</button></div></div></div><div id=\"policies-content\"><!-- Summary Cards --><div class=\"row mb-4\"><div class=\"col-xl-4 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 Policies</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.TotalPolicies))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/policies.templ`, Line: 34, 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=\"bi bi-shield icon-2x text-gray-300\"></i></div></div></div></div></div><div class=\"col-xl-4 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 Policies</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.TotalPolicies))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/policies.templ`, Line: 54, Col: 74}
}
_, 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=\"bi bi-check-circle icon-2x text-gray-300\"></i></div></div></div></div></div><div class=\"col-xl-4 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=\"h5 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/policies.templ`, Line: 74, 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=\"bi bi-clock icon-2x text-gray-300\"></i></div></div></div></div></div></div><!-- Policies 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=\"bi bi-shield me-2\"></i>IAM Policies</h6><div class=\"dropdown no-arrow\"><a class=\"dropdown-toggle\" href=\"#\" role=\"button\" data-bs-toggle=\"dropdown\"><i class=\"bi bi-three-dots-vertical icon-sm icon-fixed-width 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=\"#\"><i class=\"bi bi-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\"><thead><tr><th>Policy Name</th><th>Version</th><th>Statements</th><th>Created</th><th>Updated</th><th>Actions</th></tr></thead> <tbody>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
for _, policy := range data.Policies {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "<tr><td><strong>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var5 string
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(policy.Name)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/policies.templ`, Line: 123, Col: 68}
}
_, 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></td><td><span class=\"badge bg-info\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var6 string
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(policy.Document.Version)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/policies.templ`, Line: 126, Col: 100}
}
_, 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, "</span></td><td><span class=\"badge bg-secondary\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var7 string
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d statements", len(policy.Document.Statement)))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/policies.templ`, Line: 129, Col: 142}
}
_, 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, "</span></td><td><small class=\"text-muted\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var8 string
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(policy.CreatedAt.Format("2006-01-02 15:04"))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/policies.templ`, Line: 132, Col: 118}
}
_, 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, 9, "</small></td><td><small class=\"text-muted\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var9 string
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(policy.UpdatedAt.Format("2006-01-02 15:04"))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/policies.templ`, Line: 135, Col: 118}
}
_, 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, 10, "</small></td><td><div class=\"btn-group btn-group-sm\" role=\"group\"><button type=\"button\" class=\"btn btn-outline-info view-policy-btn\" title=\"View Policy\" data-policy-name=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var10 string
templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.ResolveAttributeValue(policy.Name)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/policies.templ`, Line: 139, Col: 168}
}
_, 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, 11, "\"><i class=\"bi bi-eye\"></i></button> <button type=\"button\" class=\"btn btn-outline-primary edit-policy-btn\" title=\"Edit Policy\" data-policy-name=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var11 string
templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.ResolveAttributeValue(policy.Name)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/policies.templ`, Line: 142, Col: 171}
}
_, 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, 12, "\"><i class=\"bi bi-pencil-square\"></i></button> <button type=\"button\" class=\"btn btn-outline-danger delete-policy-btn\" title=\"Delete Policy\" data-policy-name=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var12 string
templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.ResolveAttributeValue(policy.Name)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/policies.templ`, Line: 145, Col: 174}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var12)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "\"><i class=\"bi bi-trash\"></i></button></div></td></tr>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
if len(data.Policies) == 0 {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "<tr><td colspan=\"6\" class=\"text-center text-muted py-4\"><i class=\"bi bi-shield icon-3x mb-3 text-muted\"></i><div><h5>No IAM policies found</h5><p>Create your first policy to manage access permissions.</p><button type=\"button\" class=\"btn btn-primary\" data-bs-toggle=\"modal\" data-bs-target=\"#createPolicyModal\"><i class=\"bi bi-plus me-1\"></i>Create Policy</button></div></td></tr>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "</tbody></table></div></div></div></div></div></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = PolicyDatalists().Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "<!-- Create Policy Modal --><div class=\"modal fade\" id=\"createPolicyModal\" tabindex=\"-1\" aria-labelledby=\"createPolicyModalLabel\" aria-hidden=\"true\"><div class=\"modal-dialog modal-xl\"><div class=\"modal-content\"><div class=\"modal-header\"><h5 class=\"modal-title\" id=\"createPolicyModalLabel\"><i class=\"bi bi-shield me-2\"></i>Create IAM Policy</h5><button type=\"button\" class=\"btn-close\" data-bs-dismiss=\"modal\" aria-label=\"Close\"></button></div><div class=\"modal-body\"><form id=\"createPolicyForm\"><div class=\"mb-3\"><label for=\"policyName\" class=\"form-label\">Policy Name</label> <input type=\"text\" class=\"form-control\" id=\"policyName\" name=\"name\" required placeholder=\"e.g., S3ReadOnlyPolicy\"><div class=\"form-text\">Enter a unique name for this policy (alphanumeric and underscores only)</div></div><ul class=\"nav nav-tabs\" role=\"tablist\"><li class=\"nav-item\" role=\"presentation\"><button class=\"nav-link active\" id=\"createPolicyEditorTabBtn\" type=\"button\" data-bs-toggle=\"tab\" data-bs-target=\"#createPolicyEditorTab\">Editor</button></li><li class=\"nav-item\" role=\"presentation\"><button class=\"nav-link\" id=\"createPolicyJsonTabBtn\" type=\"button\" data-bs-toggle=\"tab\" data-bs-target=\"#createPolicyJsonTab\">JSON</button></li></ul><div class=\"tab-content border border-top-0 rounded-bottom p-3 mb-3\"><div class=\"tab-pane fade show active\" id=\"createPolicyEditorTab\"><div id=\"createPolicyEditorBody\"></div><button type=\"button\" class=\"btn btn-sm btn-outline-secondary\" id=\"createPolicyAddStatementBtn\"><i class=\"bi bi-plus me-1\"></i>Add statement</button></div><div class=\"tab-pane fade\" id=\"createPolicyJsonTab\"><textarea class=\"form-control\" id=\"policyDocument\" name=\"document\" rows=\"15\" placeholder=\"Enter IAM policy JSON document...\"></textarea><div class=\"form-text\">Enter the policy document in AWS IAM JSON format</div></div></div><div class=\"mb-3 d-flex justify-content-between\"><button type=\"button\" class=\"btn btn-outline-info btn-sm\" onclick=\"insertSamplePolicy('create')\"><i class=\"bi bi-file-earmark-text me-1\"></i>Use Sample Policy</button> <button type=\"button\" class=\"btn btn-outline-secondary btn-sm\" onclick=\"validatePolicyDocument('create')\"><i class=\"bi bi-check me-1\"></i>Validate</button></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=\"createPolicy()\"><i class=\"bi bi-plus me-1\"></i>Create Policy</button></div></div></div></div><!-- View Policy Modal --><div class=\"modal fade\" id=\"viewPolicyModal\" tabindex=\"-1\" aria-labelledby=\"viewPolicyModalLabel\" aria-hidden=\"true\"><div class=\"modal-dialog modal-lg\"><div class=\"modal-content\"><div class=\"modal-header\"><h5 class=\"modal-title\" id=\"viewPolicyModalLabel\"><i class=\"bi bi-eye me-2\"></i>View IAM Policy</h5><button type=\"button\" class=\"btn-close\" data-bs-dismiss=\"modal\" aria-label=\"Close\"></button></div><div class=\"modal-body\"><div id=\"viewPolicyContent\"><div class=\"text-center\"><div class=\"spinner-border\" role=\"status\"><span class=\"visually-hidden\">Loading...</span></div><p class=\"mt-2\">Loading policy...</p></div></div></div><div class=\"modal-footer\"><button type=\"button\" class=\"btn btn-secondary\" data-bs-dismiss=\"modal\">Close</button> <button type=\"button\" class=\"btn btn-primary\" id=\"editFromViewBtn\"><i class=\"bi bi-pencil-square me-1\"></i>Edit Policy</button></div></div></div></div><!-- Edit Policy Modal --><div class=\"modal fade\" id=\"editPolicyModal\" tabindex=\"-1\" aria-labelledby=\"editPolicyModalLabel\" aria-hidden=\"true\"><div class=\"modal-dialog modal-xl\"><div class=\"modal-content\"><div class=\"modal-header\"><h5 class=\"modal-title\" id=\"editPolicyModalLabel\"><i class=\"bi bi-pencil-square me-2\"></i>Edit IAM Policy</h5><button type=\"button\" class=\"btn-close\" data-bs-dismiss=\"modal\" aria-label=\"Close\"></button></div><div class=\"modal-body\"><form id=\"editPolicyForm\"><div class=\"mb-3\"><label for=\"editPolicyName\" class=\"form-label\">Policy Name</label> <input type=\"text\" class=\"form-control\" id=\"editPolicyName\" name=\"name\" readonly><div class=\"form-text\">Policy name cannot be changed</div></div><ul class=\"nav nav-tabs\" role=\"tablist\"><li class=\"nav-item\" role=\"presentation\"><button class=\"nav-link active\" id=\"editPolicyEditorTabBtn\" type=\"button\" data-bs-toggle=\"tab\" data-bs-target=\"#editPolicyEditorTab\">Editor</button></li><li class=\"nav-item\" role=\"presentation\"><button class=\"nav-link\" id=\"editPolicyJsonTabBtn\" type=\"button\" data-bs-toggle=\"tab\" data-bs-target=\"#editPolicyJsonTab\">JSON</button></li></ul><div class=\"tab-content border border-top-0 rounded-bottom p-3 mb-3\"><div class=\"tab-pane fade show active\" id=\"editPolicyEditorTab\"><div id=\"editPolicyEditorBody\"></div><button type=\"button\" class=\"btn btn-sm btn-outline-secondary\" id=\"editPolicyAddStatementBtn\"><i class=\"bi bi-plus me-1\"></i>Add statement</button></div><div class=\"tab-pane fade\" id=\"editPolicyJsonTab\"><textarea class=\"form-control\" id=\"editPolicyDocument\" name=\"document\" rows=\"15\"></textarea><div class=\"form-text\">Edit the policy document in AWS IAM JSON format</div></div></div><div class=\"mb-3 d-flex justify-content-between\"><button type=\"button\" class=\"btn btn-outline-info btn-sm\" onclick=\"insertSamplePolicy('edit')\"><i class=\"bi bi-file-earmark-text me-1\"></i>Reset to Sample</button> <button type=\"button\" class=\"btn btn-outline-secondary btn-sm\" onclick=\"validatePolicyDocument('edit')\"><i class=\"bi bi-check me-1\"></i>Validate</button></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=\"updatePolicy()\"><i class=\"bi bi-floppy me-1\"></i>Save Changes</button></div></div></div></div><!-- JavaScript for Policy Management --><script>\n // Current policy being viewed/edited\n let currentPolicy = null;\n // Drop edit-modal GET responses superseded by a later editPolicy call,\n // so a stalled load for one policy can't populate the editor while the\n // name field already says another. Same pattern as the bucket and\n // S3 Tables policy dialogs.\n let editPolicyRequestSeq = 0;\n\n // Event listeners for policy actions\n document.addEventListener('DOMContentLoaded', function() {\n // Register the two editor instances used on this page. Config\n // overrides here preserve the pre-extraction ids exactly, so this\n // page's markup did not need to change. This has to run after\n // DOMContentLoaded (not at the top of this script) because\n // policy_editor.js - which defines registerPolicyEditor - is\n // loaded by layout.templ's script bundle at the end of <body>,\n // i.e. after this page's own content (including this inline\n // script) has already been parsed and run.\n registerPolicyEditor('create', { textareaId: 'policyDocument' });\n registerPolicyEditor('edit', { textareaId: 'editPolicyDocument' });\n setupPolicyEditor('create');\n setupPolicyEditor('edit');\n\n // View policy buttons\n document.querySelectorAll('.view-policy-btn').forEach(button => {\n button.addEventListener('click', function() {\n const policyName = this.getAttribute('data-policy-name');\n viewPolicy(policyName);\n });\n });\n\n // Edit policy buttons\n document.querySelectorAll('.edit-policy-btn').forEach(button => {\n button.addEventListener('click', function() {\n const policyName = this.getAttribute('data-policy-name');\n editPolicy(policyName);\n });\n });\n\n // Delete policy buttons\n document.querySelectorAll('.delete-policy-btn').forEach(button => {\n button.addEventListener('click', function() {\n const policyName = this.getAttribute('data-policy-name');\n deletePolicy(policyName);\n });\n });\n\n // Edit from view button\n document.getElementById('editFromViewBtn').addEventListener('click', function() {\n if (currentPolicy) {\n const viewModal = bootstrap.Modal.getInstance(document.getElementById('viewPolicyModal'));\n if (viewModal) viewModal.hide();\n editPolicy(currentPolicy.name);\n }\n });\n\n // Reset the create modal's editor each time it's opened, so leftover\n // state from a previous (possibly cancelled) create doesn't leak in.\n document.getElementById('createPolicyModal').addEventListener('show.bs.modal', function() {\n document.getElementById('createPolicyForm').reset();\n policyEditors.create = { version: '2012-10-17', statements: [], otherFields: {} };\n renderPolicyEditor('create');\n const editorTab = bootstrap.Tab.getOrCreateInstance(document.getElementById('createPolicyEditorTabBtn'));\n editorTab.show();\n });\n });\n\n function createPolicy() {\n if (!commitPolicyActiveTab('create')) return;\n if (!confirmPolicyFieldDiscard('create')) return;\n\n const policyName = document.getElementById('policyName').value;\n const policyDocumentText = document.getElementById('policyDocument').value;\n\n if (!policyName || !policyDocumentText) {\n showAlert('Please fill in all required fields', 'warning');\n return;\n }\n\n let policyDocument;\n try {\n policyDocument = JSON.parse(policyDocumentText);\n } catch (e) {\n showAlert('Invalid JSON in policy document: ' + e.message, 'error');\n return;\n }\n\n const requestData = {\n name: policyName,\n document: policyDocument\n };\n\n validatePolicyJSON(policyDocumentText, true).then(valid => {\n if (!valid) return;\n\n fetch(basePath('/api/object-store/policies'), {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(requestData)\n })\n .then(response => response.json())\n .then(data => {\n if (data.success) {\n showAlert('Policy created successfully!', 'success');\n const modal = bootstrap.Modal.getInstance(document.getElementById('createPolicyModal'));\n if (modal) modal.hide();\n location.reload(); // Refresh the page to show the new policy\n } else {\n showAlert('Error creating policy: ' + (data.error || 'Unknown error'), 'error');\n }\n })\n .catch(error => {\n console.error('Error:', error);\n showAlert('Error creating policy: ' + error.message, 'error');\n });\n });\n }\n\n function viewPolicy(policyName) {\n // Show the modal first\n const modal = new bootstrap.Modal(document.getElementById('viewPolicyModal'));\n modal.show();\n\n // Reset content to loading state\n document.getElementById('viewPolicyContent').innerHTML = `\n <div class=\"text-center\">\n <div class=\"spinner-border\" role=\"status\">\n <span class=\"visually-hidden\">Loading...</span>\n </div>\n <p class=\"mt-2\">Loading policy...</p>\n </div>\n `;\n\n // Fetch policy data\n fetch(basePath('/api/object-store/policies/' + encodeURIComponent(policyName)))\n .then(response => {\n if (!response.ok) {\n throw new Error('Policy not found');\n }\n return response.json();\n })\n .then(policy => {\n currentPolicy = policy;\n displayPolicyDetails(policy);\n })\n .catch(error => {\n console.error('Error:', error);\n document.getElementById('viewPolicyContent').innerHTML = `\n <div class=\"alert alert-danger\" role=\"alert\">\n <i class=\"bi bi-exclamation-triangle me-2\"></i>\n Error loading policy: ${error.message}\n </div>\n `;\n });\n }\n\n function displayPolicyDetails(policy) {\n const content = document.getElementById('viewPolicyContent');\n\n // Escapes a policy value for display, whether it's carried as a\n // single value or a list, and whatever type it turns out to be.\n function escapedJoin(list) {\n if (list === undefined || list === null) return '';\n return (Array.isArray(list) ? list : [list]).map(function(v) { return escapeHtml(String(v)); }).join(', ');\n }\n\n // Summarizes a Principal/NotPrincipal value for read-only display,\n // regardless of shape (bare string/array, or a {\"Type\": ...} object -\n // possibly with several type keys), since the View modal must stay\n // correct even for forms the structured editor doesn't model.\n function principalSummary(value) {\n if (value === undefined || value === null) return '';\n if (Array.isArray(value)) return escapedJoin(value);\n if (typeof value === 'object') {\n return Object.keys(value).map(function(key) {\n const v = value[key];\n return escapeHtml(key) + ': ' + escapedJoin(v);\n }).join('; ');\n }\n return escapeHtml(String(value));\n }\n\n let statementsHtml = '';\n if (policy.document && policy.document.Statement) {\n statementsHtml = policy.document.Statement.map((stmt, index) => `\n <div class=\"card mb-2\">\n <div class=\"card-header py-2\">\n <h6 class=\"mb-0\">Statement ${index + 1}${stmt.Sid ? ' &mdash; ' + escapeHtml(stmt.Sid) : ''}</h6>\n </div>\n <div class=\"card-body py-2\">\n <div class=\"row\">\n <div class=\"col-md-6\">\n <strong>Effect:</strong>\n <span class=\"badge ${stmt.Effect === 'Allow' ? 'bg-success' : 'bg-danger'}\">${escapedJoin(stmt.Effect)}</span>\n </div>\n <div class=\"col-md-6\">\n <strong>Actions:</strong> ${escapedJoin(stmt.Action)}\n </div>\n </div>\n <div class=\"row mt-2\">\n <div class=\"col-12\">\n ${stmt.NotResource\n ? '<strong>NotResource (excluded):</strong> ' + escapedJoin(stmt.NotResource)\n : '<strong>Resource:</strong> ' + escapedJoin(stmt.Resource)}\n </div>\n </div>\n ${(stmt.Principal || stmt.NotPrincipal)\n ? '<div class=\"row mt-2\"><div class=\"col-12\">' +\n (stmt.NotPrincipal\n ? '<strong>NotPrincipal (excluded):</strong> ' + principalSummary(stmt.NotPrincipal)\n : '<strong>Principal:</strong> ' + principalSummary(stmt.Principal)) +\n '</div></div>'\n : ''}\n </div>\n </div>\n `).join('');\n }\n\n content.innerHTML = `\n <div class=\"row mb-3\">\n <div class=\"col-md-6\">\n <strong>Policy Name:</strong> ${escapedJoin(policy.name || 'Unknown')}\n </div>\n <div class=\"col-md-6\">\n <strong>Version:</strong> <span class=\"badge bg-info\">${escapedJoin(policy.document?.Version || 'Unknown')}</span>\n </div>\n </div>\n\n <div class=\"mb-3\">\n <strong>Statements:</strong>\n <div class=\"mt-2\">\n ${statementsHtml || '<p class=\"text-muted\">No statements found</p>'}\n </div>\n </div>\n\n <div class=\"mb-3\">\n <strong>Raw Policy Document:</strong>\n <pre class=\"bg-light p-3 border rounded mt-2\"><code>${escapeHtml(JSON.stringify(policy.document, null, 2))}</code></pre>\n </div>\n `;\n }\n\n function editPolicy(policyName) {\n // Show the modal first\n const modal = new bootstrap.Modal(document.getElementById('editPolicyModal'));\n modal.show();\n\n // Set policy name\n document.getElementById('editPolicyName').value = policyName;\n document.getElementById('editPolicyDocument').value = 'Loading...';\n policyEditors.edit = { version: '2012-10-17', statements: [], otherFields: {} };\n renderPolicyEditor('edit');\n\n // Fetch policy data; drop the response if another editPolicy call\n // superseded this one meanwhile.\n const requestSeq = ++editPolicyRequestSeq;\n fetch(basePath('/api/object-store/policies/' + encodeURIComponent(policyName)))\n .then(response => {\n if (!response.ok) {\n throw new Error('Policy not found');\n }\n return response.json();\n })\n .then(policy => {\n if (requestSeq !== editPolicyRequestSeq) return;\n currentPolicy = policy;\n document.getElementById('editPolicyDocument').value = JSON.stringify(policy.document, null, 2);\n let state;\n try {\n state = policyDocToEditorState('edit', policy.document);\n } catch (e) {\n // Valid JSON the structured editor can't model. The JSON tab\n // exists for exactly this, so hand the document over to it\n // rather than closing the modal on the only view of it.\n policyEditors.edit = { version: '2012-10-17', statements: [], otherFields: {}, unparsed: true };\n renderPolicyEditor('edit');\n showAlert(e.message + '. ' + POLICY_JSON_TAB_ONLY_MESSAGE, 'error');\n bootstrap.Tab.getOrCreateInstance(document.getElementById('editPolicyJsonTabBtn')).show();\n return;\n }\n policyEditors.edit = state;\n renderPolicyEditor('edit');\n const editorTab = bootstrap.Tab.getOrCreateInstance(document.getElementById('editPolicyEditorTabBtn'));\n editorTab.show();\n })\n .catch(error => {\n if (requestSeq !== editPolicyRequestSeq) return;\n console.error('Error:', error);\n showAlert('Error loading policy for editing: ' + error.message, 'error');\n const editModal = bootstrap.Modal.getInstance(document.getElementById('editPolicyModal'));\n if (editModal) editModal.hide();\n });\n }\n\n function updatePolicy() {\n if (!commitPolicyActiveTab('edit')) return;\n if (!confirmPolicyFieldDiscard('edit')) return;\n\n const policyName = document.getElementById('editPolicyName').value;\n const policyDocumentText = document.getElementById('editPolicyDocument').value;\n\n if (!policyName || !policyDocumentText) {\n showAlert('Please fill in all required fields', 'warning');\n return;\n }\n\n let policyDocument;\n try {\n policyDocument = JSON.parse(policyDocumentText);\n } catch (e) {\n showAlert('Invalid JSON in policy document: ' + e.message, 'error');\n return;\n }\n\n const requestData = {\n document: policyDocument\n };\n\n validatePolicyJSON(policyDocumentText, true).then(valid => {\n if (!valid) return;\n\n fetch(basePath('/api/object-store/policies/' + encodeURIComponent(policyName)), {\n method: 'PUT',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(requestData)\n })\n .then(response => response.json())\n .then(data => {\n if (data.success) {\n showAlert('Policy updated successfully!', 'success');\n const modal = bootstrap.Modal.getInstance(document.getElementById('editPolicyModal'));\n if (modal) modal.hide();\n location.reload(); // Refresh the page to show the updated policy\n } else {\n showAlert('Error updating policy: ' + (data.error || 'Unknown error'), 'error');\n }\n })\n .catch(error => {\n console.error('Error:', error);\n showAlert('Error updating policy: ' + error.message, 'error');\n });\n });\n }\n\n function validatePolicyDocument(which) {\n if (!commitPolicyActiveTab(which)) return;\n const policyText = document.getElementById(policyTextareaId(which)).value;\n validatePolicyJSON(policyText);\n }\n\n // Runs a policy document past the server's validator. Resolves to true\n // when it passes, and to false after alerting the user when it doesn't.\n // `quiet` suppresses the success alert for callers that go on to report\n // an outcome of their own.\n function validatePolicyJSON(policyText, quiet) {\n if (!policyText) {\n showAlert('Please enter a policy document first', 'warning');\n return Promise.resolve(false);\n }\n\n let policyDocument;\n try {\n policyDocument = JSON.parse(policyText);\n } catch (e) {\n showAlert('Invalid JSON: ' + e.message, 'error');\n return Promise.resolve(false);\n }\n\n return fetch(basePath('/api/object-store/policies/validate'), {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ document: policyDocument })\n })\n .then(response => response.json().then(data => ({ ok: response.ok, data })))\n .then(({ ok, data }) => {\n if (ok && data.valid) {\n if (!quiet) {\n showAlert(data.message || 'Policy document is valid!', 'success');\n }\n return true;\n }\n showAlert('Invalid policy: ' + (data.error || 'unknown error'), 'error');\n return false;\n })\n .catch(error => {\n console.error('Error:', error);\n showAlert('Error validating policy: ' + error.message, 'error');\n return false;\n });\n }\n\n function deletePolicy(policyName) {\n showDeleteConfirm(policyName, function() {\n fetch(basePath('/api/object-store/policies/' + encodeURIComponent(policyName)), {\n method: 'DELETE'\n })\n .then(response => response.json())\n .then(data => {\n if (data.success) {\n showAlert('Policy deleted successfully!', 'success');\n location.reload();\n } else {\n showAlert('Error deleting policy: ' + (data.error || 'Unknown error'), 'error');\n }\n })\n .catch(error => {\n console.error('Error:', error);\n showAlert('Error deleting policy: ' + error.message, 'error');\n });\n });\n }\n </script>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
}
var _ = templruntime.GeneratedTemplate