diff --git a/weed/admin/dash/admin_server.go b/weed/admin/dash/admin_server.go
index 4adbc2178..4f2489379 100644
--- a/weed/admin/dash/admin_server.go
+++ b/weed/admin/dash/admin_server.go
@@ -33,7 +33,10 @@ import (
"google.golang.org/grpc"
"github.com/seaweedfs/seaweedfs/weed/s3api"
+ "github.com/seaweedfs/seaweedfs/weed/s3api/lifecycle_xml"
"github.com/seaweedfs/seaweedfs/weed/s3api/s3_constants"
+ "github.com/seaweedfs/seaweedfs/weed/s3api/s3lifecycle"
+ "github.com/seaweedfs/seaweedfs/weed/s3api/s3lifecycle/scheduler"
"github.com/seaweedfs/seaweedfs/weed/s3api/s3tables"
"github.com/seaweedfs/seaweedfs/weed/worker/tasks"
@@ -797,20 +800,23 @@ func (s *AdminServer) GetS3Buckets() ([]S3Bucket, error) {
lastModified = time.Unix(resp.Entry.Attributes.Mtime, 0)
}
readOnly := fc.MatchStorageRule(filerConfig.BucketsPath + "/" + bucketName + "/").ReadOnly
+ lifecycleRuleCount, lifecycleEnabledCount := extractLifecycleCountsFromEntry(resp.Entry)
bucket := S3Bucket{
- Name: bucketName,
- CreatedAt: createdAt,
- LogicalSize: logicalSize,
- PhysicalSize: physicalSize,
- LastModified: lastModified,
- Quota: quota,
- QuotaEnabled: quotaEnabled,
- ReadOnly: readOnly,
- VersioningStatus: versioningStatus,
- ObjectLockEnabled: objectLockEnabled,
- ObjectLockMode: objectLockMode,
- ObjectLockDuration: objectLockDuration,
- Owner: owner,
+ Name: bucketName,
+ CreatedAt: createdAt,
+ LogicalSize: logicalSize,
+ PhysicalSize: physicalSize,
+ LastModified: lastModified,
+ Quota: quota,
+ QuotaEnabled: quotaEnabled,
+ ReadOnly: readOnly,
+ VersioningStatus: versioningStatus,
+ ObjectLockEnabled: objectLockEnabled,
+ ObjectLockMode: objectLockMode,
+ ObjectLockDuration: objectLockDuration,
+ Owner: owner,
+ LifecycleRuleCount: lifecycleRuleCount,
+ LifecycleEnabledCount: lifecycleEnabledCount,
}
buckets = append(buckets, bucket)
}
@@ -915,6 +921,7 @@ func (s *AdminServer) GetBucketDetails(bucketName string) (*BucketDetails, error
details.Bucket.ObjectLockMode = objectLockMode
details.Bucket.ObjectLockDuration = objectLockDuration
details.Bucket.Owner = owner
+ details.Bucket.LifecycleRuleCount, details.Bucket.LifecycleEnabledCount = extractLifecycleCountsFromEntry(bucketResp.Entry)
return nil
})
@@ -926,6 +933,68 @@ func (s *AdminServer) GetBucketDetails(bucketName string) (*BucketDetails, error
return details, nil
}
+// GetBucketLifecycle returns the lifecycle configuration stored on a bucket's filer entry
+func (s *AdminServer) GetBucketLifecycle(bucketName string) (*BucketLifecycle, error) {
+ filerConfig, err := s.getFilerConfig()
+ if err != nil {
+ glog.Warningf("Failed to get filer configuration, using defaults: %v", err)
+ }
+
+ lifecycle := &BucketLifecycle{
+ Bucket: bucketName,
+ Rules: []BucketLifecycleRule{},
+ }
+
+ err = s.WithFilerClient(func(client filer_pb.SeaweedFilerClient) error {
+ resp, err := client.LookupDirectoryEntry(context.Background(), &filer_pb.LookupDirectoryEntryRequest{
+ Directory: filerConfig.BucketsPath,
+ Name: bucketName,
+ })
+ if err != nil {
+ return fmt.Errorf("bucket not found: %w", err)
+ }
+
+ xmlBytes := resp.Entry.Extended[scheduler.BucketLifecycleConfigurationXMLKey]
+ if len(xmlBytes) == 0 {
+ return nil
+ }
+ rules, err := lifecycle_xml.ParseCanonical(xmlBytes)
+ if err != nil {
+ return fmt.Errorf("parse lifecycle configuration: %w", err)
+ }
+ lifecycle.XML = string(xmlBytes)
+ for _, rule := range rules {
+ lifecycle.Rules = append(lifecycle.Rules, toBucketLifecycleRule(rule))
+ }
+ return nil
+ })
+ if err != nil {
+ return nil, err
+ }
+
+ return lifecycle, nil
+}
+
+func toBucketLifecycleRule(rule *s3lifecycle.Rule) BucketLifecycleRule {
+ out := BucketLifecycleRule{
+ ID: rule.ID,
+ Status: rule.Status,
+ Prefix: rule.Prefix,
+ Tags: rule.FilterTags,
+ SizeGreaterThan: rule.FilterSizeGreaterThan,
+ SizeLessThan: rule.FilterSizeLessThan,
+ ExpirationDays: rule.ExpirationDays,
+ ExpiredObjectDeleteMarker: rule.ExpiredObjectDeleteMarker,
+ NoncurrentVersionExpirationDays: rule.NoncurrentVersionExpirationDays,
+ NewerNoncurrentVersions: rule.NewerNoncurrentVersions,
+ AbortMultipartDays: rule.AbortMPUDaysAfterInitiation,
+ }
+ if !rule.ExpirationDate.IsZero() {
+ out.ExpirationDate = rule.ExpirationDate.Format(time.DateOnly)
+ }
+ return out
+}
+
// CreateS3Bucket creates a new S3 bucket
func (s *AdminServer) CreateS3Bucket(bucketName string) error {
return s.CreateS3BucketWithQuota(bucketName, 0, false)
@@ -1812,6 +1881,24 @@ func extractVersioningFromEntry(entry *filer_pb.Entry) string {
return s3api.GetVersioningStatus(entry)
}
+func extractLifecycleCountsFromEntry(entry *filer_pb.Entry) (ruleCount, enabledCount int) {
+ xmlBytes := entry.Extended[scheduler.BucketLifecycleConfigurationXMLKey]
+ if len(xmlBytes) == 0 {
+ return
+ }
+ rules, err := lifecycle_xml.ParseCanonical(xmlBytes)
+ if err != nil {
+ return
+ }
+ for _, rule := range rules {
+ ruleCount++
+ if rule.Status == s3lifecycle.StatusEnabled {
+ enabledCount++
+ }
+ }
+ return
+}
+
// GetConfigPersistence returns the config persistence manager
func (as *AdminServer) GetConfigPersistence() *ConfigPersistence {
return as.configPersistence
diff --git a/weed/admin/dash/bucket_management.go b/weed/admin/dash/bucket_management.go
index 10e70e9dc..93d53331c 100644
--- a/weed/admin/dash/bucket_management.go
+++ b/weed/admin/dash/bucket_management.go
@@ -85,6 +85,23 @@ func (s *AdminServer) ShowBucketDetails(w http.ResponseWriter, r *http.Request)
writeJSON(w, http.StatusOK, details)
}
+// ShowBucketLifecycle returns the lifecycle configuration for a specific bucket
+func (s *AdminServer) ShowBucketLifecycle(w http.ResponseWriter, r *http.Request) {
+ bucketName := mux.Vars(r)["bucket"]
+ if bucketName == "" {
+ writeJSONError(w, http.StatusBadRequest, "Bucket name is required")
+ return
+ }
+
+ lifecycle, err := s.GetBucketLifecycle(bucketName)
+ if err != nil {
+ writeJSONError(w, http.StatusInternalServerError, "Failed to get bucket lifecycle: "+err.Error())
+ return
+ }
+
+ writeJSON(w, http.StatusOK, lifecycle)
+}
+
// CreateBucket creates a new S3 bucket
func (s *AdminServer) CreateBucket(w http.ResponseWriter, r *http.Request) {
var req CreateBucketRequest
diff --git a/weed/admin/dash/types.go b/weed/admin/dash/types.go
index e8fcacb53..322fa89dd 100644
--- a/weed/admin/dash/types.go
+++ b/weed/admin/dash/types.go
@@ -85,6 +85,9 @@ type S3Bucket struct {
ObjectLockMode string `json:"object_lock_mode"` // Object lock mode: "GOVERNANCE" or "COMPLIANCE"
ObjectLockDuration int32 `json:"object_lock_duration"` // Default retention duration in days
Owner string `json:"owner,omitempty"` // Bucket owner identity; empty means admin-only access
+
+ LifecycleRuleCount int `json:"lifecycle_rule_count"`
+ LifecycleEnabledCount int `json:"lifecycle_enabled_count"`
}
type S3Object struct {
@@ -100,6 +103,27 @@ type BucketDetails struct {
UpdatedAt time.Time `json:"updated_at"`
}
+type BucketLifecycleRule struct {
+ ID string `json:"id,omitempty"`
+ Status string `json:"status"`
+ Prefix string `json:"prefix,omitempty"`
+ Tags map[string]string `json:"tags,omitempty"`
+ SizeGreaterThan int64 `json:"size_greater_than,omitempty"`
+ SizeLessThan int64 `json:"size_less_than,omitempty"`
+ ExpirationDays int `json:"expiration_days,omitempty"`
+ ExpirationDate string `json:"expiration_date,omitempty"`
+ ExpiredObjectDeleteMarker bool `json:"expired_object_delete_marker,omitempty"`
+ NoncurrentVersionExpirationDays int `json:"noncurrent_version_expiration_days,omitempty"`
+ NewerNoncurrentVersions int `json:"newer_noncurrent_versions,omitempty"`
+ AbortMultipartDays int `json:"abort_multipart_days,omitempty"`
+}
+
+type BucketLifecycle struct {
+ Bucket string `json:"bucket"`
+ Rules []BucketLifecycleRule `json:"rules"`
+ XML string `json:"xml,omitempty"`
+}
+
// ObjectStoreUser is defined in admin_data.go
// Volume management structures
diff --git a/weed/admin/handlers/admin_handlers.go b/weed/admin/handlers/admin_handlers.go
index 1437d0c2d..842ba8b69 100644
--- a/weed/admin/handlers/admin_handlers.go
+++ b/weed/admin/handlers/admin_handlers.go
@@ -178,6 +178,7 @@ func (h *AdminHandlers) registerAPIRoutes(api *mux.Router, enforceWrite bool) {
s3Api.Handle("/buckets", wrapWrite(h.adminServer.CreateBucket)).Methods(http.MethodPost)
s3Api.Handle("/buckets/{bucket}", wrapWrite(h.adminServer.DeleteBucket)).Methods(http.MethodDelete)
s3Api.HandleFunc("/buckets/{bucket}", h.adminServer.ShowBucketDetails).Methods(http.MethodGet)
+ s3Api.HandleFunc("/buckets/{bucket}/lifecycle", h.adminServer.ShowBucketLifecycle).Methods(http.MethodGet)
s3Api.Handle("/buckets/{bucket}/quota", wrapWrite(h.adminServer.UpdateBucketQuota)).Methods(http.MethodPut)
s3Api.Handle("/buckets/{bucket}/owner", wrapWrite(h.adminServer.UpdateBucketOwner)).Methods(http.MethodPut)
diff --git a/weed/admin/view/app/s3_buckets.templ b/weed/admin/view/app/s3_buckets.templ
index 218f28787..224de2adc 100644
--- a/weed/admin/view/app/s3_buckets.templ
+++ b/weed/admin/view/app/s3_buckets.templ
@@ -150,6 +150,7 @@ templ S3Buckets(data dash.S3BucketsData) {
Quota |
Versioning |
Object Lock |
+ Lifecycle |
Actions |
@@ -232,6 +233,28 @@ templ S3Buckets(data dash.S3BucketsData) {
Not configured
}
+
+ if bucket.LifecycleRuleCount > 0 {
+
+
+ if bucket.LifecycleEnabledCount < bucket.LifecycleRuleCount {
+
+ {fmt.Sprintf("%d enabled", bucket.LifecycleEnabledCount)}
+
+ }
+
+ } else {
+ Not configured
+ }
+ |
+
+
+
@@ -659,6 +708,8 @@ templ S3Buckets(data dash.S3BucketsData) {
let quotaModalInstance = null;
let ownerModalInstance = null;
let detailsModalInstance = null;
+ let lifecycleModalInstance = null;
+ let lifecycleRequestSeq = 0;
let cachedUsers = null;
document.addEventListener('DOMContentLoaded', function() {
@@ -676,6 +727,7 @@ templ S3Buckets(data dash.S3BucketsData) {
quotaModalInstance = new bootstrap.Modal(document.getElementById('manageQuotaModal'));
ownerModalInstance = new bootstrap.Modal(document.getElementById('manageOwnerModal'));
detailsModalInstance = new bootstrap.Modal(document.getElementById('bucketDetailsModal'));
+ lifecycleModalInstance = new bootstrap.Modal(document.getElementById('bucketLifecycleModal'));
const quotaCheckbox = document.getElementById('enableQuota');
const quotaSettings = document.getElementById('quotaSettings');
@@ -1016,6 +1068,52 @@ templ S3Buckets(data dash.S3BucketsData) {
});
});
});
+
+ // Lifecycle buttons: column badge and action button
+ document.querySelectorAll('.lifecycle-btn').forEach(button => {
+ button.addEventListener('click', function() {
+ const bucketName = this.dataset.bucketName;
+
+ document.getElementById('bucketLifecycleModalLabel').innerHTML =
+ ' Lifecycle - ' + bucketName;
+
+ document.getElementById('bucketLifecycleContent').innerHTML =
+ ' ' +
+ ' ' +
+ ' Loading...' +
+ '<\/div>' +
+ ' Loading lifecycle rules... ' +
+ '<\/div>';
+
+ lifecycleModalInstance.show();
+
+ // Drop responses that arrive after another bucket was opened
+ const requestSeq = ++lifecycleRequestSeq;
+ fetch(basePath('/api/s3/buckets/' + bucketName + '/lifecycle'))
+ .then(response => response.json())
+ .then(data => {
+ if (requestSeq !== lifecycleRequestSeq) return;
+ if (data.error) {
+ document.getElementById('bucketLifecycleContent').innerHTML =
+ ' ' +
+ ' ' +
+ 'Error loading lifecycle rules: ' + data.error +
+ '<\/div>';
+ } else {
+ displayBucketLifecycle(data);
+ }
+ })
+ .catch(error => {
+ if (requestSeq !== lifecycleRequestSeq) return;
+ console.error('Error fetching bucket lifecycle:', error);
+ document.getElementById('bucketLifecycleContent').innerHTML =
+ ' ' +
+ ' ' +
+ 'Error loading lifecycle rules: ' + error.message +
+ '<\/div>';
+ });
+ });
+ });
});
function deleteBucket() {
@@ -1134,6 +1232,114 @@ function displayBucketDetails(data) {
document.getElementById('bucketDetailsContent').innerHTML = rows.join('');
}
+function displayBucketLifecycle(data) {
+ function escapeHtml(v) {
+ return String(v ?? '')
+ .replace(/&/g, '&')
+ .replace(//g, '>')
+ .replace(/"/g, '"')
+ .replace(/'/g, ''');
+ }
+
+ function formatBytes(bytes) {
+ if (bytes === 0) return '0 Bytes';
+ const k = 1024;
+ const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
+ }
+
+ function days(n) {
+ return n + (n === 1 ? ' day' : ' days');
+ }
+
+ const rules = data.rules || [];
+ if (rules.length === 0) {
+ document.getElementById('bucketLifecycleContent').innerHTML =
+ ' No lifecycle configuration<\/div>';
+ return;
+ }
+
+ function describeScope(rule) {
+ const parts = [];
+ if (rule.prefix) {
+ parts.push(' ' + escapeHtml(rule.prefix) + '<\/code>');
+ }
+ Object.entries(rule.tags || {}).forEach(([k, v]) => {
+ parts.push('' + escapeHtml(k) + '=' + escapeHtml(v) + '<\/span>');
+ });
+ if (rule.size_greater_than) {
+ parts.push('size > ' + formatBytes(rule.size_greater_than));
+ }
+ if (rule.size_less_than) {
+ parts.push('size < ' + formatBytes(rule.size_less_than));
+ }
+ return parts.length ? parts.join(' ') : 'Whole bucket<\/span>';
+ }
+
+ function describeActions(rule) {
+ const actions = [];
+ if (rule.expiration_days) {
+ actions.push('Expire after ' + days(rule.expiration_days));
+ }
+ if (rule.expiration_date) {
+ actions.push('Expire on ' + escapeHtml(rule.expiration_date));
+ }
+ if (rule.expired_object_delete_marker) {
+ actions.push('Remove expired object delete markers');
+ }
+ if (rule.noncurrent_version_expiration_days) {
+ let action = 'Expire noncurrent versions after ' + days(rule.noncurrent_version_expiration_days);
+ if (rule.newer_noncurrent_versions) {
+ action += ', keep ' + rule.newer_noncurrent_versions + ' newest';
+ }
+ actions.push(action);
+ }
+ if (rule.abort_multipart_days) {
+ actions.push('Abort incomplete multipart uploads after ' + days(rule.abort_multipart_days));
+ }
+ if (actions.length === 0) {
+ return 'None<\/span>';
+ }
+ return actions.join(' ');
+ }
+
+ const rows = [
+ '',
+ ' ',
+ '| Rule<\/th> | Status<\/th> | Scope<\/th> | Actions<\/th><\/tr><\/thead>',
+ ' | '
+ ];
+
+ rules.forEach(rule => {
+ const statusHtml = rule.status === 'Enabled'
+ ? 'Enabled<\/span>'
+ : '' + escapeHtml(rule.status) + '<\/span>';
+ rows.push(
+ '' +
+ '| ' + (rule.id ? escapeHtml(rule.id) : 'unnamed<\/span>') + '<\/td>' +
+ ' | ' + statusHtml + '<\/td>' +
+ ' | ' + describeScope(rule) + '<\/td>' +
+ ' | ' + describeActions(rule) + '<\/td>' +
+ '<\/tr>'
+ );
+ });
+
+ rows.push('<\/tbody>', '<\/table>', '<\/div>');
+
+ if (data.xml) {
+ rows.push(
+ '',
+ 'Raw XML<\/summary>',
+ '' + escapeHtml(data.xml) + '<\/pre>',
+ '<\/details>'
+ );
+ }
+
+ document.getElementById('bucketLifecycleContent').innerHTML = rows.join('');
+}
+
function goToPage(page) {
const url = new URL(window.location);
url.searchParams.set('page', page);
diff --git a/weed/admin/view/app/s3_buckets_templ.go b/weed/admin/view/app/s3_buckets_templ.go
index 7fc915c10..b570a700a 100644
--- a/weed/admin/view/app/s3_buckets_templ.go
+++ b/weed/admin/view/app/s3_buckets_templ.go
@@ -153,7 +153,7 @@ func S3Buckets(data dash.S3BucketsData) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "| Quota | Versioning | Object Lock | Actions | | ")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "Quota | Versioning | Object Lock | Lifecycle | Actions | ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@@ -165,7 +165,7 @@ func S3Buckets(data dash.S3BucketsData) templ.Component {
var templ_7745c5c3_Var5 templ.SafeURL
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinURLErrs(dash.PUrl(ctx, fmt.Sprintf("/files?path=/buckets/%s", bucket.Name)))
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/s3_buckets.templ`, Line: 160, Col: 124}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/s3_buckets.templ`, Line: 161, Col: 124}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
if templ_7745c5c3_Err != nil {
@@ -178,7 +178,7 @@ func S3Buckets(data dash.S3BucketsData) templ.Component {
var templ_7745c5c3_Var6 string
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(bucket.Name)
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/s3_buckets.templ`, Line: 163, Col: 64}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/s3_buckets.templ`, Line: 164, Col: 64}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))
if templ_7745c5c3_Err != nil {
@@ -206,7 +206,7 @@ func S3Buckets(data dash.S3BucketsData) templ.Component {
var templ_7745c5c3_Var7 string
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(bucket.Owner)
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/s3_buckets.templ`, Line: 174, Col: 101}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/s3_buckets.templ`, Line: 175, Col: 101}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
if templ_7745c5c3_Err != nil {
@@ -229,7 +229,7 @@ func S3Buckets(data dash.S3BucketsData) templ.Component {
var templ_7745c5c3_Var8 string
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(bucket.CreatedAt.Format("2006-01-02 15:04"))
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/s3_buckets.templ`, Line: 180, Col: 92}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/s3_buckets.templ`, Line: 181, Col: 92}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
if templ_7745c5c3_Err != nil {
@@ -242,7 +242,7 @@ func S3Buckets(data dash.S3BucketsData) templ.Component {
var templ_7745c5c3_Var9 string
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(formatBytes(bucket.LogicalSize))
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/s3_buckets.templ`, Line: 182, Col: 85}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/s3_buckets.templ`, Line: 183, Col: 85}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9))
if templ_7745c5c3_Err != nil {
@@ -260,7 +260,7 @@ func S3Buckets(data dash.S3BucketsData) templ.Component {
var templ_7745c5c3_Var10 string
templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%.1fx overhead", float64(bucket.PhysicalSize)/float64(bucket.LogicalSize)))
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/s3_buckets.templ`, Line: 185, Col: 144}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/s3_buckets.templ`, Line: 186, Col: 144}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10))
if templ_7745c5c3_Err != nil {
@@ -278,7 +278,7 @@ func S3Buckets(data dash.S3BucketsData) templ.Component {
var templ_7745c5c3_Var11 string
templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(formatBytes(bucket.PhysicalSize))
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/s3_buckets.templ`, Line: 189, Col: 81}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/s3_buckets.templ`, Line: 190, Col: 81}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11))
if templ_7745c5c3_Err != nil {
@@ -318,7 +318,7 @@ func S3Buckets(data dash.S3BucketsData) templ.Component {
var templ_7745c5c3_Var14 string
templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(formatBytes(bucket.Quota))
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/s3_buckets.templ`, Line: 194, Col: 86}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/s3_buckets.templ`, Line: 195, Col: 86}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14))
if templ_7745c5c3_Err != nil {
@@ -336,7 +336,7 @@ func S3Buckets(data dash.S3BucketsData) templ.Component {
var templ_7745c5c3_Var15 string
templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%.1f%% used", float64(bucket.LogicalSize)/float64(bucket.Quota)*100))
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/s3_buckets.templ`, Line: 198, Col: 146}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/s3_buckets.templ`, Line: 199, Col: 146}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var15))
if templ_7745c5c3_Err != nil {
@@ -394,7 +394,7 @@ func S3Buckets(data dash.S3BucketsData) templ.Component {
var templ_7745c5c3_Var16 string
templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinStringErrs(bucket.ObjectLockMode)
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/s3_buckets.templ`, Line: 228, Col: 82}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/s3_buckets.templ`, Line: 229, Col: 82}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16))
if templ_7745c5c3_Err != nil {
@@ -407,7 +407,7 @@ func S3Buckets(data dash.S3BucketsData) templ.Component {
var templ_7745c5c3_Var17 string
templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d days", bucket.ObjectLockDuration))
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/s3_buckets.templ`, Line: 228, Col: 138}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/s3_buckets.templ`, Line: 229, Col: 138}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var17))
if templ_7745c5c3_Err != nil {
@@ -423,296 +423,380 @@ func S3Buckets(data dash.S3BucketsData) templ.Component {
return templ_7745c5c3_Err
}
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 51, "")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- var templ_7745c5c3_Var18 templ.SafeURL
- templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.JoinURLErrs(dash.PUrl(ctx, fmt.Sprintf("/files?path=/buckets/%s", bucket.Name)))
- if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/s3_buckets.templ`, Line: 237, Col: 128}
+ if bucket.LifecycleRuleCount > 0 {
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 52, " ")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ if bucket.LifecycleEnabledCount < bucket.LifecycleRuleCount {
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 56, " ")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ var templ_7745c5c3_Var20 string
+ templ_7745c5c3_Var20, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d enabled", bucket.LifecycleEnabledCount))
+ if templ_7745c5c3_Err != nil {
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/s3_buckets.templ`, Line: 250, Col: 120}
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var20))
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 57, " ")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 58, " ")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ } else {
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 59, "Not configured")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
}
- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var18))
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 60, " | | ")
- if templ_7745c5c3_Err != nil {
- return templ_7745c5c3_Err
- }
- }
- if len(data.Buckets) == 0 {
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 60, " No Object Store buckets foundCreate your first bucket to get started with S3 storage. | ")
- if templ_7745c5c3_Err != nil {
- return templ_7745c5c3_Err
- }
- }
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 61, " | ")
- if templ_7745c5c3_Err != nil {
- return templ_7745c5c3_Err
- }
- if data.TotalPages > 1 {
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 62, "Showing ")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 65, "\" title=\"Manage Owner\"> | ")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ }
+ if len(data.Buckets) == 0 {
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 70, "No Object Store buckets foundCreate your first bucket to get started with S3 storage. |
")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 71, "")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ if data.TotalPages > 1 {
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 72, "Showing ")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ var templ_7745c5c3_Var30 string
+ templ_7745c5c3_Var30, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", (data.CurrentPage-1)*data.PageSize+1))
+ if templ_7745c5c3_Err != nil {
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/s3_buckets.templ`, Line: 326, Col: 101}
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var30))
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 73, " to ")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ var templ_7745c5c3_Var31 string
+ templ_7745c5c3_Var31, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", minInt(data.CurrentPage*data.PageSize, data.TotalBuckets)))
+ if templ_7745c5c3_Err != nil {
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/s3_buckets.templ`, Line: 326, Col: 185}
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var31))
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 74, " of ")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ var templ_7745c5c3_Var32 string
+ templ_7745c5c3_Var32, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", data.TotalBuckets))
+ if templ_7745c5c3_Err != nil {
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/s3_buckets.templ`, Line: 326, Col: 229}
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var32))
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 75, " buckets
")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 79, "")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ for i := maxInt(1, data.CurrentPage-2); i <= minInt(data.TotalPages, data.CurrentPage+2); i++ {
+ if i == data.CurrentPage {
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 80, "")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ var templ_7745c5c3_Var34 string
+ templ_7745c5c3_Var34, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", i))
+ if templ_7745c5c3_Err != nil {
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/s3_buckets.templ`, Line: 349, Col: 97}
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var34))
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 81, "")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ } else {
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 82, "")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ var templ_7745c5c3_Var36 string
+ templ_7745c5c3_Var36, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", i))
+ if templ_7745c5c3_Err != nil {
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/s3_buckets.templ`, Line: 353, Col: 152}
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var36))
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 84, "")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ }
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 85, "")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ if data.CurrentPage < data.TotalPages {
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 86, "")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ } else {
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 88, "")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 89, "")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 80, " Last updated: ")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 90, "
Last updated: ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- var templ_7745c5c3_Var34 string
- templ_7745c5c3_Var34, templ_7745c5c3_Err = templ.JoinStringErrs(data.LastUpdated.Format("2006-01-02 15:04:05"))
+ var templ_7745c5c3_Var38 string
+ templ_7745c5c3_Var38, 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/s3_buckets.templ`, Line: 357, Col: 81}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/s3_buckets.templ`, Line: 386, Col: 81}
}
- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var34))
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var38))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 81, "
Are you sure you want to delete the bucket ?
Warning: This action cannot be undone. All objects in the bucket will be permanently deleted.
Loading...
Loading bucket details...
")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 91, "Are you sure you want to delete the bucket ?
Warning: This action cannot be undone. All objects in the bucket will be permanently deleted.
Loading...
Loading bucket details...
")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}