s3_buckets_templ.go 49 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  1. // Code generated by templ - DO NOT EDIT.
  2. // templ: version: v0.3.906
  3. package app
  4. //lint:file-ignore SA4006 This context is only used if a nested component is present.
  5. import "github.com/a-h/templ"
  6. import templruntime "github.com/a-h/templ/runtime"
  7. import (
  8. "fmt"
  9. "github.com/seaweedfs/seaweedfs/weed/admin/dash"
  10. )
  11. func S3Buckets(data dash.S3BucketsData) templ.Component {
  12. return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
  13. templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
  14. if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
  15. return templ_7745c5c3_CtxErr
  16. }
  17. templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
  18. if !templ_7745c5c3_IsBuffer {
  19. defer func() {
  20. templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
  21. if templ_7745c5c3_Err == nil {
  22. templ_7745c5c3_Err = templ_7745c5c3_BufErr
  23. }
  24. }()
  25. }
  26. ctx = templ.InitializeContext(ctx)
  27. templ_7745c5c3_Var1 := templ.GetChildren(ctx)
  28. if templ_7745c5c3_Var1 == nil {
  29. templ_7745c5c3_Var1 = templ.NopComponent
  30. }
  31. ctx = templ.ClearChildren(ctx)
  32. 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=\"fas fa-cube me-2\"></i>Object Store Buckets</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=\"#createBucketModal\"><i class=\"fas fa-plus me-1\"></i>Create Bucket</button></div></div></div><div id=\"s3-buckets-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 Buckets</div><div class=\"h5 mb-0 font-weight-bold text-gray-800\">")
  33. if templ_7745c5c3_Err != nil {
  34. return templ_7745c5c3_Err
  35. }
  36. var templ_7745c5c3_Var2 string
  37. templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", data.TotalBuckets))
  38. if templ_7745c5c3_Err != nil {
  39. return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/s3_buckets.templ`, Line: 37, Col: 73}
  40. }
  41. _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2))
  42. if templ_7745c5c3_Err != nil {
  43. return templ_7745c5c3_Err
  44. }
  45. templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "</div></div><div class=\"col-auto\"><i class=\"fas fa-cube fa-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\">Total Storage</div><div class=\"h5 mb-0 font-weight-bold text-gray-800\">")
  46. if templ_7745c5c3_Err != nil {
  47. return templ_7745c5c3_Err
  48. }
  49. var templ_7745c5c3_Var3 string
  50. templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(formatBytes(data.TotalSize))
  51. if templ_7745c5c3_Err != nil {
  52. return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/s3_buckets.templ`, Line: 57, Col: 64}
  53. }
  54. _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
  55. if templ_7745c5c3_Err != nil {
  56. return templ_7745c5c3_Err
  57. }
  58. templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "</div></div><div class=\"col-auto\"><i class=\"fas fa-hdd fa-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-warning 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-warning text-uppercase mb-1\">Last Updated</div><div class=\"h6 mb-0 font-weight-bold text-gray-800\">")
  59. if templ_7745c5c3_Err != nil {
  60. return templ_7745c5c3_Err
  61. }
  62. var templ_7745c5c3_Var4 string
  63. templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(data.LastUpdated.Format("15:04:05"))
  64. if templ_7745c5c3_Err != nil {
  65. return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/s3_buckets.templ`, Line: 78, Col: 72}
  66. }
  67. _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
  68. if templ_7745c5c3_Err != nil {
  69. return templ_7745c5c3_Err
  70. }
  71. 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><!-- Buckets 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-cube me-2\"></i>Object Store Buckets</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=\"exportBucketList()\"><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=\"bucketsTable\"><thead><tr><th>Name</th><th>Created</th><th>Objects</th><th>Size</th><th>Quota</th><th>Versioning</th><th>Object Lock</th><th>Actions</th></tr></thead> <tbody>")
  72. if templ_7745c5c3_Err != nil {
  73. return templ_7745c5c3_Err
  74. }
  75. for _, bucket := range data.Buckets {
  76. templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "<tr><td><a href=\"")
  77. if templ_7745c5c3_Err != nil {
  78. return templ_7745c5c3_Err
  79. }
  80. var templ_7745c5c3_Var5 templ.SafeURL
  81. templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(fmt.Sprintf("/s3/buckets/%s", bucket.Name)))
  82. if templ_7745c5c3_Err != nil {
  83. return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/s3_buckets.templ`, Line: 129, Col: 114}
  84. }
  85. _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
  86. if templ_7745c5c3_Err != nil {
  87. return templ_7745c5c3_Err
  88. }
  89. templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "\" class=\"text-decoration-none\"><i class=\"fas fa-cube me-2\"></i> ")
  90. if templ_7745c5c3_Err != nil {
  91. return templ_7745c5c3_Err
  92. }
  93. var templ_7745c5c3_Var6 string
  94. templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(bucket.Name)
  95. if templ_7745c5c3_Err != nil {
  96. return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/s3_buckets.templ`, Line: 132, Col: 64}
  97. }
  98. _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))
  99. if templ_7745c5c3_Err != nil {
  100. return templ_7745c5c3_Err
  101. }
  102. templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "</a></td><td>")
  103. if templ_7745c5c3_Err != nil {
  104. return templ_7745c5c3_Err
  105. }
  106. var templ_7745c5c3_Var7 string
  107. templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(bucket.CreatedAt.Format("2006-01-02 15:04"))
  108. if templ_7745c5c3_Err != nil {
  109. return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/s3_buckets.templ`, Line: 135, Col: 92}
  110. }
  111. _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
  112. if templ_7745c5c3_Err != nil {
  113. return templ_7745c5c3_Err
  114. }
  115. templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "</td><td>")
  116. if templ_7745c5c3_Err != nil {
  117. return templ_7745c5c3_Err
  118. }
  119. var templ_7745c5c3_Var8 string
  120. templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", bucket.ObjectCount))
  121. if templ_7745c5c3_Err != nil {
  122. return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/s3_buckets.templ`, Line: 136, Col: 86}
  123. }
  124. _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
  125. if templ_7745c5c3_Err != nil {
  126. return templ_7745c5c3_Err
  127. }
  128. templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "</td><td>")
  129. if templ_7745c5c3_Err != nil {
  130. return templ_7745c5c3_Err
  131. }
  132. var templ_7745c5c3_Var9 string
  133. templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(formatBytes(bucket.Size))
  134. if templ_7745c5c3_Err != nil {
  135. return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/s3_buckets.templ`, Line: 137, Col: 73}
  136. }
  137. _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9))
  138. if templ_7745c5c3_Err != nil {
  139. return templ_7745c5c3_Err
  140. }
  141. templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "</td><td>")
  142. if templ_7745c5c3_Err != nil {
  143. return templ_7745c5c3_Err
  144. }
  145. if bucket.Quota > 0 {
  146. templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "<div>")
  147. if templ_7745c5c3_Err != nil {
  148. return templ_7745c5c3_Err
  149. }
  150. var templ_7745c5c3_Var10 = []any{fmt.Sprintf("badge bg-%s", getQuotaStatusColor(bucket.Size, bucket.Quota, bucket.QuotaEnabled))}
  151. templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var10...)
  152. if templ_7745c5c3_Err != nil {
  153. return templ_7745c5c3_Err
  154. }
  155. templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "<span class=\"")
  156. if templ_7745c5c3_Err != nil {
  157. return templ_7745c5c3_Err
  158. }
  159. var templ_7745c5c3_Var11 string
  160. templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(templ.CSSClasses(templ_7745c5c3_Var10).String())
  161. if templ_7745c5c3_Err != nil {
  162. return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/s3_buckets.templ`, Line: 1, Col: 0}
  163. }
  164. _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11))
  165. if templ_7745c5c3_Err != nil {
  166. return templ_7745c5c3_Err
  167. }
  168. templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "\">")
  169. if templ_7745c5c3_Err != nil {
  170. return templ_7745c5c3_Err
  171. }
  172. var templ_7745c5c3_Var12 string
  173. templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(formatBytes(bucket.Quota))
  174. if templ_7745c5c3_Err != nil {
  175. return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/s3_buckets.templ`, Line: 142, Col: 86}
  176. }
  177. _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12))
  178. if templ_7745c5c3_Err != nil {
  179. return templ_7745c5c3_Err
  180. }
  181. templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "</span> ")
  182. if templ_7745c5c3_Err != nil {
  183. return templ_7745c5c3_Err
  184. }
  185. if bucket.QuotaEnabled {
  186. templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "<div class=\"small text-muted\">")
  187. if templ_7745c5c3_Err != nil {
  188. return templ_7745c5c3_Err
  189. }
  190. var templ_7745c5c3_Var13 string
  191. templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%.1f%% used", float64(bucket.Size)/float64(bucket.Quota)*100))
  192. if templ_7745c5c3_Err != nil {
  193. return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/s3_buckets.templ`, Line: 146, Col: 139}
  194. }
  195. _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13))
  196. if templ_7745c5c3_Err != nil {
  197. return templ_7745c5c3_Err
  198. }
  199. templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "</div>")
  200. if templ_7745c5c3_Err != nil {
  201. return templ_7745c5c3_Err
  202. }
  203. } else {
  204. templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "<div class=\"small text-muted\">Disabled</div>")
  205. if templ_7745c5c3_Err != nil {
  206. return templ_7745c5c3_Err
  207. }
  208. }
  209. templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "</div>")
  210. if templ_7745c5c3_Err != nil {
  211. return templ_7745c5c3_Err
  212. }
  213. } else {
  214. templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "<span class=\"text-muted\">No quota</span>")
  215. if templ_7745c5c3_Err != nil {
  216. return templ_7745c5c3_Err
  217. }
  218. }
  219. templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "</td><td>")
  220. if templ_7745c5c3_Err != nil {
  221. return templ_7745c5c3_Err
  222. }
  223. if bucket.VersioningEnabled {
  224. templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, "<span class=\"badge bg-success\"><i class=\"fas fa-check me-1\"></i>Enabled</span>")
  225. if templ_7745c5c3_Err != nil {
  226. return templ_7745c5c3_Err
  227. }
  228. } else {
  229. templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, "<span class=\"badge bg-secondary\"><i class=\"fas fa-times me-1\"></i>Disabled</span>")
  230. if templ_7745c5c3_Err != nil {
  231. return templ_7745c5c3_Err
  232. }
  233. }
  234. templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, "</td><td>")
  235. if templ_7745c5c3_Err != nil {
  236. return templ_7745c5c3_Err
  237. }
  238. if bucket.ObjectLockEnabled {
  239. templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "<div><span class=\"badge bg-warning\"><i class=\"fas fa-lock me-1\"></i>Enabled</span><div class=\"small text-muted\">")
  240. if templ_7745c5c3_Err != nil {
  241. return templ_7745c5c3_Err
  242. }
  243. var templ_7745c5c3_Var14 string
  244. templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(bucket.ObjectLockMode)
  245. if templ_7745c5c3_Err != nil {
  246. return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/s3_buckets.templ`, Line: 174, Col: 82}
  247. }
  248. _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14))
  249. if templ_7745c5c3_Err != nil {
  250. return templ_7745c5c3_Err
  251. }
  252. templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, " • ")
  253. if templ_7745c5c3_Err != nil {
  254. return templ_7745c5c3_Err
  255. }
  256. var templ_7745c5c3_Var15 string
  257. templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d days", bucket.ObjectLockDuration))
  258. if templ_7745c5c3_Err != nil {
  259. return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/s3_buckets.templ`, Line: 174, Col: 138}
  260. }
  261. _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var15))
  262. if templ_7745c5c3_Err != nil {
  263. return templ_7745c5c3_Err
  264. }
  265. templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, "</div></div>")
  266. if templ_7745c5c3_Err != nil {
  267. return templ_7745c5c3_Err
  268. }
  269. } else {
  270. templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 27, "<span class=\"badge bg-secondary\"><i class=\"fas fa-unlock me-1\"></i>Disabled</span>")
  271. if templ_7745c5c3_Err != nil {
  272. return templ_7745c5c3_Err
  273. }
  274. }
  275. templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 28, "</td><td><div class=\"btn-group btn-group-sm\" role=\"group\"><a href=\"")
  276. if templ_7745c5c3_Err != nil {
  277. return templ_7745c5c3_Err
  278. }
  279. var templ_7745c5c3_Var16 templ.SafeURL
  280. templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(fmt.Sprintf("/files?path=/buckets/%s", bucket.Name)))
  281. if templ_7745c5c3_Err != nil {
  282. return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/s3_buckets.templ`, Line: 185, Col: 127}
  283. }
  284. _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16))
  285. if templ_7745c5c3_Err != nil {
  286. return templ_7745c5c3_Err
  287. }
  288. templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 29, "\" class=\"btn btn-outline-success btn-sm\" title=\"Browse Files\"><i class=\"fas fa-folder-open\"></i></a> <button type=\"button\" class=\"btn btn-outline-primary btn-sm view-details-btn\" data-bucket-name=\"")
  289. if templ_7745c5c3_Err != nil {
  290. return templ_7745c5c3_Err
  291. }
  292. var templ_7745c5c3_Var17 string
  293. templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.JoinStringErrs(bucket.Name)
  294. if templ_7745c5c3_Err != nil {
  295. return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/s3_buckets.templ`, Line: 192, Col: 89}
  296. }
  297. _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var17))
  298. if templ_7745c5c3_Err != nil {
  299. return templ_7745c5c3_Err
  300. }
  301. templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 30, "\" title=\"View Details\"><i class=\"fas fa-eye\"></i></button> <button type=\"button\" class=\"btn btn-outline-warning btn-sm quota-btn\" data-bucket-name=\"")
  302. if templ_7745c5c3_Err != nil {
  303. return templ_7745c5c3_Err
  304. }
  305. var templ_7745c5c3_Var18 string
  306. templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.JoinStringErrs(bucket.Name)
  307. if templ_7745c5c3_Err != nil {
  308. return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/s3_buckets.templ`, Line: 198, Col: 89}
  309. }
  310. _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var18))
  311. if templ_7745c5c3_Err != nil {
  312. return templ_7745c5c3_Err
  313. }
  314. templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 31, "\" data-current-quota=\"")
  315. if templ_7745c5c3_Err != nil {
  316. return templ_7745c5c3_Err
  317. }
  318. var templ_7745c5c3_Var19 string
  319. templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", getQuotaInMB(bucket.Quota)))
  320. if templ_7745c5c3_Err != nil {
  321. return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/s3_buckets.templ`, Line: 199, Col: 125}
  322. }
  323. _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var19))
  324. if templ_7745c5c3_Err != nil {
  325. return templ_7745c5c3_Err
  326. }
  327. templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 32, "\" data-quota-enabled=\"")
  328. if templ_7745c5c3_Err != nil {
  329. return templ_7745c5c3_Err
  330. }
  331. var templ_7745c5c3_Var20 string
  332. templ_7745c5c3_Var20, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%t", bucket.QuotaEnabled))
  333. if templ_7745c5c3_Err != nil {
  334. return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/s3_buckets.templ`, Line: 200, Col: 118}
  335. }
  336. _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var20))
  337. if templ_7745c5c3_Err != nil {
  338. return templ_7745c5c3_Err
  339. }
  340. templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 33, "\" title=\"Manage Quota\"><i class=\"fas fa-tachometer-alt\"></i></button> <button type=\"button\" class=\"btn btn-outline-danger btn-sm delete-bucket-btn\" data-bucket-name=\"")
  341. if templ_7745c5c3_Err != nil {
  342. return templ_7745c5c3_Err
  343. }
  344. var templ_7745c5c3_Var21 string
  345. templ_7745c5c3_Var21, templ_7745c5c3_Err = templ.JoinStringErrs(bucket.Name)
  346. if templ_7745c5c3_Err != nil {
  347. return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/s3_buckets.templ`, Line: 206, Col: 89}
  348. }
  349. _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var21))
  350. if templ_7745c5c3_Err != nil {
  351. return templ_7745c5c3_Err
  352. }
  353. templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 34, "\" title=\"Delete Bucket\"><i class=\"fas fa-trash\"></i></button></div></td></tr>")
  354. if templ_7745c5c3_Err != nil {
  355. return templ_7745c5c3_Err
  356. }
  357. }
  358. if len(data.Buckets) == 0 {
  359. templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 35, "<tr><td colspan=\"8\" class=\"text-center text-muted py-4\"><i class=\"fas fa-cube fa-3x mb-3 text-muted\"></i><div><h5>No Object Store buckets found</h5><p>Create your first bucket to get started with S3 storage.</p><button type=\"button\" class=\"btn btn-primary\" data-bs-toggle=\"modal\" data-bs-target=\"#createBucketModal\"><i class=\"fas fa-plus me-1\"></i>Create Bucket</button></div></td></tr>")
  360. if templ_7745c5c3_Err != nil {
  361. return templ_7745c5c3_Err
  362. }
  363. }
  364. templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 36, "</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: ")
  365. if templ_7745c5c3_Err != nil {
  366. return templ_7745c5c3_Err
  367. }
  368. var templ_7745c5c3_Var22 string
  369. templ_7745c5c3_Var22, templ_7745c5c3_Err = templ.JoinStringErrs(data.LastUpdated.Format("2006-01-02 15:04:05"))
  370. if templ_7745c5c3_Err != nil {
  371. return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/s3_buckets.templ`, Line: 243, Col: 81}
  372. }
  373. _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var22))
  374. if templ_7745c5c3_Err != nil {
  375. return templ_7745c5c3_Err
  376. }
  377. templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 37, "</small></div></div></div><!-- Create Bucket Modal --><div class=\"modal fade\" id=\"createBucketModal\" tabindex=\"-1\" aria-labelledby=\"createBucketModalLabel\" aria-hidden=\"true\"><div class=\"modal-dialog\"><div class=\"modal-content\"><div class=\"modal-header\"><h5 class=\"modal-title\" id=\"createBucketModalLabel\"><i class=\"fas fa-plus me-2\"></i>Create New S3 Bucket</h5><button type=\"button\" class=\"btn-close\" data-bs-dismiss=\"modal\" aria-label=\"Close\"></button></div><form id=\"createBucketForm\"><div class=\"modal-body\"><div class=\"mb-3\"><label for=\"bucketName\" class=\"form-label\">Bucket Name</label> <input type=\"text\" class=\"form-control\" id=\"bucketName\" name=\"name\" placeholder=\"my-bucket-name\" required pattern=\"[a-z0-9.-]+\" title=\"Bucket name must contain only lowercase letters, numbers, dots, and hyphens\"><div class=\"form-text\">Bucket names must be between 3 and 63 characters, contain only lowercase letters, numbers, dots, and hyphens.</div></div><div class=\"mb-3\"><div class=\"form-check\"><input class=\"form-check-input\" type=\"checkbox\" id=\"enableQuota\" name=\"quota_enabled\"> <label class=\"form-check-label\" for=\"enableQuota\">Enable Storage Quota</label></div></div><div class=\"mb-3\" id=\"quotaSettings\" style=\"display: none;\"><div class=\"row\"><div class=\"col-md-8\"><label for=\"quotaSize\" class=\"form-label\">Quota Size</label> <input type=\"number\" class=\"form-control\" id=\"quotaSize\" name=\"quota_size\" placeholder=\"1024\" min=\"1\" step=\"1\"></div><div class=\"col-md-4\"><label for=\"quotaUnit\" class=\"form-label\">Unit</label> <select class=\"form-select\" id=\"quotaUnit\" name=\"quota_unit\"><option value=\"MB\" selected>MB</option> <option value=\"GB\">GB</option> <option value=\"TB\">TB</option></select></div></div><div class=\"form-text\">Set the maximum storage size for this bucket.</div></div><div class=\"mb-3\"><div class=\"form-check\"><input class=\"form-check-input\" type=\"checkbox\" id=\"enableVersioning\" name=\"versioning_enabled\"> <label class=\"form-check-label\" for=\"enableVersioning\">Enable Object Versioning</label></div><div class=\"form-text\">Keep multiple versions of objects in this bucket.</div></div><div class=\"mb-3\"><div class=\"form-check\"><input class=\"form-check-input\" type=\"checkbox\" id=\"enableObjectLock\" name=\"object_lock_enabled\"> <label class=\"form-check-label\" for=\"enableObjectLock\">Enable Object Lock</label></div><div class=\"form-text\">Prevent objects from being deleted or overwritten for a specified period. Automatically enables versioning.</div></div><div class=\"mb-3\" id=\"objectLockSettings\" style=\"display: none;\"><div class=\"row\"><div class=\"col-md-6\"><label for=\"objectLockMode\" class=\"form-label\">Object Lock Mode</label> <select class=\"form-select\" id=\"objectLockMode\" name=\"object_lock_mode\"><option value=\"GOVERNANCE\" selected>Governance</option> <option value=\"COMPLIANCE\">Compliance</option></select><div class=\"form-text\">Governance allows override with special permissions, Compliance is immutable.</div></div><div class=\"col-md-6\"><div class=\"form-check mb-3\"><input class=\"form-check-input\" type=\"checkbox\" id=\"setDefaultRetention\" name=\"set_default_retention\"> <label class=\"form-check-label\" for=\"setDefaultRetention\">Set Default Retention</label><div class=\"form-text\">Apply default retention to all new objects in this bucket.</div></div><div id=\"defaultRetentionSettings\" style=\"display: none;\"><label for=\"objectLockDuration\" class=\"form-label\">Default Retention (days)</label> <input type=\"number\" class=\"form-control\" id=\"objectLockDuration\" name=\"object_lock_duration\" placeholder=\"30\" min=\"1\" max=\"36500\" step=\"1\"><div class=\"form-text\">Default retention period for new objects (1-36500 days).</div></div></div></div></div></div><div class=\"modal-footer\"><button type=\"button\" class=\"btn btn-secondary\" data-bs-dismiss=\"modal\">Cancel</button> <button type=\"submit\" class=\"btn btn-primary\"><i class=\"fas fa-plus me-1\"></i>Create Bucket</button></div></form></div></div></div><!-- Delete Confirmation Modal --><div class=\"modal fade\" id=\"deleteBucketModal\" tabindex=\"-1\" aria-labelledby=\"deleteBucketModalLabel\" aria-hidden=\"true\"><div class=\"modal-dialog\"><div class=\"modal-content\"><div class=\"modal-header\"><h5 class=\"modal-title\" id=\"deleteBucketModalLabel\"><i class=\"fas fa-exclamation-triangle me-2 text-warning\"></i>Delete Bucket</h5><button type=\"button\" class=\"btn-close\" data-bs-dismiss=\"modal\" aria-label=\"Close\"></button></div><div class=\"modal-body\"><p>Are you sure you want to delete the bucket <strong id=\"deleteBucketName\"></strong>?</p><div class=\"alert alert-warning\"><i class=\"fas fa-exclamation-triangle me-2\"></i> <strong>Warning:</strong> This action cannot be undone. All objects in the bucket will be permanently deleted.</div></div><div class=\"modal-footer\"><button type=\"button\" class=\"btn btn-secondary\" data-bs-dismiss=\"modal\">Cancel</button> <button type=\"button\" class=\"btn btn-danger\" onclick=\"deleteBucket()\"><i class=\"fas fa-trash me-1\"></i>Delete Bucket</button></div></div></div></div><!-- Manage Quota Modal --><div class=\"modal fade\" id=\"manageQuotaModal\" tabindex=\"-1\" aria-labelledby=\"manageQuotaModalLabel\" aria-hidden=\"true\"><div class=\"modal-dialog\"><div class=\"modal-content\"><div class=\"modal-header\"><h5 class=\"modal-title\" id=\"manageQuotaModalLabel\"><i class=\"fas fa-tachometer-alt me-2\"></i>Manage Bucket Quota</h5><button type=\"button\" class=\"btn-close\" data-bs-dismiss=\"modal\" aria-label=\"Close\"></button></div><form id=\"quotaForm\"><div class=\"modal-body\"><div class=\"mb-3\"><label class=\"form-label\">Bucket Name</label> <input type=\"text\" class=\"form-control\" id=\"quotaBucketName\" readonly></div><div class=\"mb-3\"><div class=\"form-check\"><input class=\"form-check-input\" type=\"checkbox\" id=\"quotaEnabled\" name=\"quota_enabled\"> <label class=\"form-check-label\" for=\"quotaEnabled\">Enable Storage Quota</label></div></div><div class=\"mb-3\" id=\"quotaSizeSettings\"><div class=\"row\"><div class=\"col-md-8\"><label for=\"quotaSizeMB\" class=\"form-label\">Quota Size</label> <input type=\"number\" class=\"form-control\" id=\"quotaSizeMB\" name=\"quota_size\" placeholder=\"1024\" min=\"0\" step=\"1\"></div><div class=\"col-md-4\"><label for=\"quotaUnitMB\" class=\"form-label\">Unit</label> <select class=\"form-select\" id=\"quotaUnitMB\" name=\"quota_unit\"><option value=\"MB\" selected>MB</option> <option value=\"GB\">GB</option> <option value=\"TB\">TB</option></select></div></div><div class=\"form-text\">Set the maximum storage size for this bucket. Set to 0 to remove quota.</div></div></div><div class=\"modal-footer\"><button type=\"button\" class=\"btn btn-secondary\" data-bs-dismiss=\"modal\">Cancel</button> <button type=\"submit\" class=\"btn btn-warning\"><i class=\"fas fa-save me-1\"></i>Update Quota</button></div></form></div></div></div><!-- Bucket Details Modal --><div class=\"modal fade\" id=\"bucketDetailsModal\" tabindex=\"-1\" aria-labelledby=\"bucketDetailsModalLabel\" aria-hidden=\"true\"><div class=\"modal-dialog modal-lg\"><div class=\"modal-content\"><div class=\"modal-header\"><h5 class=\"modal-title\" id=\"bucketDetailsModalLabel\"><i class=\"fas fa-cube me-2\"></i>Bucket Details</h5><button type=\"button\" class=\"btn-close\" data-bs-dismiss=\"modal\" aria-label=\"Close\"></button></div><div class=\"modal-body\"><div id=\"bucketDetailsContent\"><div class=\"text-center py-4\"><div class=\"spinner-border text-primary\" role=\"status\"><span class=\"visually-hidden\">Loading...</span></div><div class=\"mt-2\">Loading bucket details...</div></div></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 bucket management --><script>\n document.addEventListener('DOMContentLoaded', function() {\n const quotaCheckbox = document.getElementById('enableQuota');\n const quotaSettings = document.getElementById('quotaSettings');\n const versioningCheckbox = document.getElementById('enableVersioning');\n const objectLockCheckbox = document.getElementById('enableObjectLock');\n const objectLockSettings = document.getElementById('objectLockSettings');\n const setDefaultRetentionCheckbox = document.getElementById('setDefaultRetention');\n const defaultRetentionSettings = document.getElementById('defaultRetentionSettings');\n const createBucketForm = document.getElementById('createBucketForm');\n\n // Toggle quota settings\n quotaCheckbox.addEventListener('change', function() {\n quotaSettings.style.display = this.checked ? 'block' : 'none';\n });\n\n // Toggle object lock settings and automatically enable versioning\n objectLockCheckbox.addEventListener('change', function() {\n objectLockSettings.style.display = this.checked ? 'block' : 'none';\n if (this.checked) {\n versioningCheckbox.checked = true;\n versioningCheckbox.disabled = true;\n } else {\n versioningCheckbox.disabled = false;\n // Reset default retention settings when object lock is disabled\n setDefaultRetentionCheckbox.checked = false;\n defaultRetentionSettings.style.display = 'none';\n }\n });\n\n // Toggle default retention settings\n setDefaultRetentionCheckbox.addEventListener('change', function() {\n defaultRetentionSettings.style.display = this.checked ? 'block' : 'none';\n });\n\n // Handle form submission\n createBucketForm.addEventListener('submit', function(e) {\n e.preventDefault();\n \n const formData = new FormData(this);\n const data = {\n name: formData.get('name'),\n region: formData.get('region') || '',\n quota_size: quotaCheckbox.checked ? parseInt(formData.get('quota_size')) || 0 : 0,\n quota_unit: formData.get('quota_unit') || 'MB',\n quota_enabled: quotaCheckbox.checked,\n versioning_enabled: versioningCheckbox.checked,\n object_lock_enabled: objectLockCheckbox.checked,\n object_lock_mode: formData.get('object_lock_mode') || 'GOVERNANCE',\n set_default_retention: setDefaultRetentionCheckbox.checked,\n object_lock_duration: setDefaultRetentionCheckbox.checked ? parseInt(formData.get('object_lock_duration')) || 30 : 0\n };\n\n // Validate object lock settings\n if (data.object_lock_enabled && data.set_default_retention && data.object_lock_duration <= 0) {\n alert('Please enter a valid retention duration for object lock.');\n return;\n }\n\n fetch('/api/s3/buckets', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(data)\n })\n .then(response => response.json())\n .then(data => {\n if (data.error) {\n alert('Error creating bucket: ' + data.error);\n } else {\n alert('Bucket created successfully!');\n // Properly close the modal before reloading\n const createModal = bootstrap.Modal.getInstance(document.getElementById('createBucketModal'));\n if (createModal) {\n createModal.hide();\n }\n setTimeout(() => location.reload(), 500);\n }\n })\n .catch(error => {\n console.error('Error:', error);\n alert('Error creating bucket: ' + error.message);\n });\n });\n\n // Handle delete bucket\n let deleteModalInstance = null;\n document.querySelectorAll('.delete-bucket-btn').forEach(button => {\n button.addEventListener('click', function() {\n const bucketName = this.dataset.bucketName;\n document.getElementById('deleteBucketName').textContent = bucketName;\n window.currentBucketToDelete = bucketName;\n \n // Dispose of existing modal instance if it exists\n if (deleteModalInstance) {\n deleteModalInstance.dispose();\n }\n \n // Create new modal instance\n deleteModalInstance = new bootstrap.Modal(document.getElementById('deleteBucketModal'));\n deleteModalInstance.show();\n });\n });\n\n // Add event listener to properly dispose of delete modal when hidden\n document.getElementById('deleteBucketModal').addEventListener('hidden.bs.modal', function() {\n if (deleteModalInstance) {\n deleteModalInstance.dispose();\n deleteModalInstance = null;\n }\n // Force remove any remaining backdrops\n document.querySelectorAll('.modal-backdrop').forEach(backdrop => {\n backdrop.remove();\n });\n // Ensure body classes are removed\n document.body.classList.remove('modal-open');\n document.body.style.removeProperty('padding-right');\n });\n\n // Handle quota management\n let quotaModalInstance = null;\n document.querySelectorAll('.quota-btn').forEach(button => {\n button.addEventListener('click', function() {\n const bucketName = this.dataset.bucketName;\n const currentQuota = parseInt(this.dataset.currentQuota);\n const quotaEnabled = this.dataset.quotaEnabled === 'true';\n \n document.getElementById('quotaBucketName').value = bucketName;\n document.getElementById('quotaEnabled').checked = quotaEnabled;\n document.getElementById('quotaSizeMB').value = currentQuota;\n \n // Toggle quota size settings\n document.getElementById('quotaSizeSettings').style.display = quotaEnabled ? 'block' : 'none';\n \n window.currentBucketToUpdate = bucketName;\n \n // Dispose of existing modal instance if it exists\n if (quotaModalInstance) {\n quotaModalInstance.dispose();\n }\n \n // Create new modal instance\n quotaModalInstance = new bootstrap.Modal(document.getElementById('manageQuotaModal'));\n quotaModalInstance.show();\n });\n });\n\n // Add event listener to properly dispose of quota modal when hidden\n document.getElementById('manageQuotaModal').addEventListener('hidden.bs.modal', function() {\n if (quotaModalInstance) {\n quotaModalInstance.dispose();\n quotaModalInstance = null;\n }\n // Force remove any remaining backdrops\n document.querySelectorAll('.modal-backdrop').forEach(backdrop => {\n backdrop.remove();\n });\n // Ensure body classes are removed\n document.body.classList.remove('modal-open');\n document.body.style.removeProperty('padding-right');\n });\n\n // Handle quota form submission\n document.getElementById('quotaForm').addEventListener('submit', function(e) {\n e.preventDefault();\n \n const formData = new FormData(this);\n const enabled = document.getElementById('quotaEnabled').checked;\n const data = {\n quota_size: enabled ? parseInt(formData.get('quota_size')) || 0 : 0,\n quota_unit: formData.get('quota_unit') || 'MB',\n quota_enabled: enabled\n };\n\n fetch(`/api/s3/buckets/${window.currentBucketToUpdate}/quota`, {\n method: 'PUT',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(data)\n })\n .then(response => response.json())\n .then(data => {\n if (data.error) {\n alert('Error updating quota: ' + data.error);\n } else {\n alert('Quota updated successfully!');\n // Properly close the modal before reloading\n if (quotaModalInstance) {\n quotaModalInstance.hide();\n }\n setTimeout(() => location.reload(), 500);\n }\n })\n .catch(error => {\n console.error('Error:', error);\n alert('Error updating quota: ' + error.message);\n });\n });\n\n // Handle quota enabled checkbox\n document.getElementById('quotaEnabled').addEventListener('change', function() {\n document.getElementById('quotaSizeSettings').style.display = this.checked ? 'block' : 'none';\n });\n\n // Handle view details button\n let detailsModalInstance = null;\n document.querySelectorAll('.view-details-btn').forEach(button => {\n button.addEventListener('click', function() {\n const bucketName = this.dataset.bucketName;\n \n // Update modal title\n document.getElementById('bucketDetailsModalLabel').innerHTML = \n '<i class=\"fas fa-cube me-2\"></i>Bucket Details - ' + bucketName;\n \n // Show loading spinner\n document.getElementById('bucketDetailsContent').innerHTML = \n '<div class=\"text-center py-4\">' +\n '<div class=\"spinner-border text-primary\" role=\"status\">' +\n '<span class=\"visually-hidden\">Loading...</span>' +\n '</div>' +\n '<div class=\"mt-2\">Loading bucket details...</div>' +\n '</div>';\n \n // Dispose of existing modal instance if it exists\n if (detailsModalInstance) {\n detailsModalInstance.dispose();\n }\n \n // Create new modal instance\n detailsModalInstance = new bootstrap.Modal(document.getElementById('bucketDetailsModal'));\n detailsModalInstance.show();\n \n // Fetch bucket details\n fetch('/api/s3/buckets/' + bucketName)\n .then(response => response.json())\n .then(data => {\n if (data.error) {\n document.getElementById('bucketDetailsContent').innerHTML = \n '<div class=\"alert alert-danger\">' +\n '<i class=\"fas fa-exclamation-triangle me-2\"></i>' +\n 'Error loading bucket details: ' + data.error +\n '</div>';\n } else {\n displayBucketDetails(data);\n }\n })\n .catch(error => {\n console.error('Error fetching bucket details:', error);\n document.getElementById('bucketDetailsContent').innerHTML = \n '<div class=\"alert alert-danger\">' +\n '<i class=\"fas fa-exclamation-triangle me-2\"></i>' +\n 'Error loading bucket details: ' + error.message +\n '</div>';\n });\n });\n });\n\n // Add event listener to properly dispose of details modal when hidden\n document.getElementById('bucketDetailsModal').addEventListener('hidden.bs.modal', function() {\n if (detailsModalInstance) {\n detailsModalInstance.dispose();\n detailsModalInstance = null;\n }\n // Force remove any remaining backdrops\n document.querySelectorAll('.modal-backdrop').forEach(backdrop => {\n backdrop.remove();\n });\n // Ensure body classes are removed\n document.body.classList.remove('modal-open');\n document.body.style.removeProperty('padding-right');\n });\n });\n\n function deleteBucket() {\n const bucketName = window.currentBucketToDelete;\n if (!bucketName) return;\n\n fetch(`/api/s3/buckets/${bucketName}`, {\n method: 'DELETE'\n })\n .then(response => response.json())\n .then(data => {\n if (data.error) {\n alert('Error deleting bucket: ' + data.error);\n } else {\n alert('Bucket deleted successfully!');\n // Properly close the modal before reloading\n if (deleteModalInstance) {\n deleteModalInstance.hide();\n }\n setTimeout(() => location.reload(), 500);\n }\n })\n .catch(error => {\n console.error('Error:', error);\n alert('Error deleting bucket: ' + error.message);\n });\n }\n\n function displayBucketDetails(data) {\n const bucket = data.bucket;\n const objects = data.objects || [];\n \n // Helper function to format bytes\n function formatBytes(bytes) {\n if (bytes === 0) return '0 Bytes';\n const k = 1024;\n const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];\n }\n \n // Helper function to format date\n function formatDate(dateString) {\n const date = new Date(dateString);\n return date.toLocaleString();\n }\n \n // Generate objects table\n let objectsTable = '';\n if (objects.length > 0) {\n objectsTable = '<div class=\"table-responsive\">' +\n '<table class=\"table table-sm table-striped\">' +\n '<thead>' +\n '<tr>' +\n '<th>Object Key</th>' +\n '<th>Size</th>' +\n '<th>Last Modified</th>' +\n '<th>Storage Class</th>' +\n '</tr>' +\n '</thead>' +\n '<tbody>' +\n objects.map(obj => \n '<tr>' +\n '<td><i class=\"fas fa-file me-1\"></i>' + obj.key + '</td>' +\n '<td>' + formatBytes(obj.size) + '</td>' +\n '<td>' + formatDate(obj.last_modified) + '</td>' +\n '<td><span class=\"badge bg-primary\">' + obj.storage_class + '</span></td>' +\n '</tr>'\n ).join('') +\n '</tbody>' +\n '</table>' +\n '</div>';\n } else {\n objectsTable = '<div class=\"text-center py-4 text-muted\">' +\n '<i class=\"fas fa-file fa-3x mb-3\"></i>' +\n '<div>No objects found in this bucket</div>' +\n '</div>';\n }\n \n const content = '<div class=\"row\">' +\n '<div class=\"col-md-6\">' +\n '<h6><i class=\"fas fa-info-circle me-2\"></i>Bucket Information</h6>' +\n '<table class=\"table table-sm\">' +\n '<tr>' +\n '<td><strong>Name:</strong></td>' +\n '<td>' + bucket.name + '</td>' +\n '</tr>' +\n '<tr>' +\n '<td><strong>Created:</strong></td>' +\n '<td>' + formatDate(bucket.created_at) + '</td>' +\n '</tr>' +\n '<tr>' +\n '<td><strong>Last Modified:</strong></td>' +\n '<td>' + formatDate(bucket.last_modified) + '</td>' +\n '</tr>' +\n '<tr>' +\n '<td><strong>Total Size:</strong></td>' +\n '<td>' + formatBytes(bucket.size) + '</td>' +\n '</tr>' +\n '<tr>' +\n '<td><strong>Object Count:</strong></td>' +\n '<td>' + bucket.object_count + '</td>' +\n '</tr>' +\n '</table>' +\n '</div>' +\n '<div class=\"col-md-6\">' +\n '<h6><i class=\"fas fa-cogs me-2\"></i>Configuration</h6>' +\n '<table class=\"table table-sm\">' +\n '<tr>' +\n '<td><strong>Quota:</strong></td>' +\n '<td>' +\n (bucket.quota_enabled ? \n '<span class=\"badge bg-success\">' + formatBytes(bucket.quota) + '</span>' : \n '<span class=\"badge bg-secondary\">Disabled</span>'\n ) +\n '</td>' +\n '</tr>' +\n '<tr>' +\n '<td><strong>Versioning:</strong></td>' +\n '<td>' +\n (bucket.versioning_enabled ? \n '<span class=\"badge bg-success\"><i class=\"fas fa-check me-1\"></i>Enabled</span>' : \n '<span class=\"badge bg-secondary\"><i class=\"fas fa-times me-1\"></i>Disabled</span>'\n ) +\n '</td>' +\n '</tr>' +\n '<tr>' +\n '<td><strong>Object Lock:</strong></td>' +\n '<td>' +\n (bucket.object_lock_enabled ? \n '<span class=\"badge bg-warning\"><i class=\"fas fa-lock me-1\"></i>Enabled</span>' +\n '<br><small class=\"text-muted\">' + bucket.object_lock_mode + ' • ' + bucket.object_lock_duration + ' days</small>' : \n '<span class=\"badge bg-secondary\"><i class=\"fas fa-unlock me-1\"></i>Disabled</span>'\n ) +\n '</td>' +\n '</tr>' +\n '</table>' +\n '</div>' +\n '</div>' +\n '<hr>' +\n '<div class=\"row\">' +\n '<div class=\"col-12\">' +\n '<h6><i class=\"fas fa-list me-2\"></i>Objects (' + objects.length + ')</h6>' +\n objectsTable +\n '</div>' +\n '</div>';\n \n document.getElementById('bucketDetailsContent').innerHTML = content;\n }\n\n function exportBucketList() {\n // Simple CSV export\n const buckets = Array.from(document.querySelectorAll('#bucketsTable tbody tr')).map(row => {\n const cells = row.querySelectorAll('td');\n if (cells.length > 1) {\n return {\n name: cells[0].textContent.trim(),\n created: cells[1].textContent.trim(),\n objects: cells[2].textContent.trim(),\n size: cells[3].textContent.trim(),\n quota: cells[4].textContent.trim(),\n versioning: cells[5].textContent.trim(),\n objectLock: cells[6].textContent.trim()\n };\n }\n return null;\n }).filter(bucket => bucket !== null);\n\n const csvContent = \"data:text/csv;charset=utf-8,\" + \n \"Name,Created,Objects,Size,Quota,Versioning,Object Lock\\n\" +\n buckets.map(b => '\"' + b.name + '\",\"' + b.created + '\",\"' + b.objects + '\",\"' + b.size + '\",\"' + b.quota + '\",\"' + b.versioning + '\",\"' + b.objectLock + '\"').join(\"\\n\");\n\n const encodedUri = encodeURI(csvContent);\n const link = document.createElement(\"a\");\n link.setAttribute(\"href\", encodedUri);\n link.setAttribute(\"download\", \"buckets.csv\");\n document.body.appendChild(link);\n link.click();\n document.body.removeChild(link);\n }\n </script>")
  378. if templ_7745c5c3_Err != nil {
  379. return templ_7745c5c3_Err
  380. }
  381. return nil
  382. })
  383. }
  384. // Helper functions for template
  385. func getQuotaStatusColor(used, quota int64, enabled bool) string {
  386. if !enabled || quota <= 0 {
  387. return "secondary"
  388. }
  389. percentage := float64(used) / float64(quota) * 100
  390. if percentage >= 90 {
  391. return "danger"
  392. } else if percentage >= 75 {
  393. return "warning"
  394. } else {
  395. return "success"
  396. }
  397. }
  398. func getQuotaInMB(quotaBytes int64) int64 {
  399. if quotaBytes < 0 {
  400. quotaBytes = -quotaBytes // Handle disabled quotas (negative values)
  401. }
  402. return quotaBytes / (1024 * 1024)
  403. }
  404. var _ = templruntime.GeneratedTemplate