Fix UI/UX issues: lifecycle warnings, CORS tooltip, IAM overflow, config validation, JS maintenance
This commit is contained in:
@@ -374,6 +374,7 @@ def bucket_detail(bucket_name: str):
|
|||||||
kms_keys = kms_manager.list_keys() if kms_manager else []
|
kms_keys = kms_manager.list_keys() if kms_manager else []
|
||||||
kms_enabled = current_app.config.get("KMS_ENABLED", False)
|
kms_enabled = current_app.config.get("KMS_ENABLED", False)
|
||||||
encryption_enabled = current_app.config.get("ENCRYPTION_ENABLED", False)
|
encryption_enabled = current_app.config.get("ENCRYPTION_ENABLED", False)
|
||||||
|
lifecycle_enabled = current_app.config.get("LIFECYCLE_ENABLED", False)
|
||||||
can_manage_encryption = can_manage_versioning
|
can_manage_encryption = can_manage_versioning
|
||||||
|
|
||||||
bucket_quota = storage.get_bucket_quota(bucket_name)
|
bucket_quota = storage.get_bucket_quota(bucket_name)
|
||||||
@@ -418,6 +419,7 @@ def bucket_detail(bucket_name: str):
|
|||||||
kms_keys=kms_keys,
|
kms_keys=kms_keys,
|
||||||
kms_enabled=kms_enabled,
|
kms_enabled=kms_enabled,
|
||||||
encryption_enabled=encryption_enabled,
|
encryption_enabled=encryption_enabled,
|
||||||
|
lifecycle_enabled=lifecycle_enabled,
|
||||||
bucket_quota=bucket_quota,
|
bucket_quota=bucket_quota,
|
||||||
bucket_stats=bucket_stats,
|
bucket_stats=bucket_stats,
|
||||||
can_manage_quota=can_manage_quota,
|
can_manage_quota=can_manage_quota,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
APP_VERSION = "0.2.0"
|
APP_VERSION = "0.2.1"
|
||||||
|
|
||||||
|
|
||||||
def get_version() -> str:
|
def get_version() -> str:
|
||||||
|
|||||||
46
docs.md
46
docs.md
@@ -189,6 +189,52 @@ All configuration is done via environment variables. The table below lists every
|
|||||||
| `KMS_ENABLED` | `false` | Enable KMS key management for encryption. |
|
| `KMS_ENABLED` | `false` | Enable KMS key management for encryption. |
|
||||||
| `KMS_KEYS_PATH` | `data/.myfsio.sys/keys/kms_keys.json` | Path to store KMS key metadata. |
|
| `KMS_KEYS_PATH` | `data/.myfsio.sys/keys/kms_keys.json` | Path to store KMS key metadata. |
|
||||||
|
|
||||||
|
|
||||||
|
## Lifecycle Rules
|
||||||
|
|
||||||
|
Lifecycle rules automate object management by scheduling deletions based on object age.
|
||||||
|
|
||||||
|
### Enabling Lifecycle Enforcement
|
||||||
|
|
||||||
|
By default, lifecycle enforcement is disabled. Enable it by setting the environment variable:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
LIFECYCLE_ENABLED=true python run.py
|
||||||
|
```
|
||||||
|
|
||||||
|
Or in your `myfsio.env` file:
|
||||||
|
```
|
||||||
|
LIFECYCLE_ENABLED=true
|
||||||
|
LIFECYCLE_INTERVAL_SECONDS=3600 # Check interval (default: 1 hour)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Configuring Rules
|
||||||
|
|
||||||
|
Once enabled, configure lifecycle rules via:
|
||||||
|
- **Web UI:** Bucket Details → Lifecycle tab → Add Rule
|
||||||
|
- **S3 API:** `PUT /<bucket>?lifecycle` with XML configuration
|
||||||
|
|
||||||
|
### Available Actions
|
||||||
|
|
||||||
|
| Action | Description |
|
||||||
|
|--------|-------------|
|
||||||
|
| **Expiration** | Delete current version objects after N days |
|
||||||
|
| **NoncurrentVersionExpiration** | Delete old versions N days after becoming noncurrent (requires versioning) |
|
||||||
|
| **AbortIncompleteMultipartUpload** | Clean up incomplete multipart uploads after N days |
|
||||||
|
|
||||||
|
### Example Configuration (XML)
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<LifecycleConfiguration>
|
||||||
|
<Rule>
|
||||||
|
<ID>DeleteOldLogs</ID>
|
||||||
|
<Status>Enabled</Status>
|
||||||
|
<Filter><Prefix>logs/</Prefix></Filter>
|
||||||
|
<Expiration><Days>30</Days></Expiration>
|
||||||
|
</Rule>
|
||||||
|
</LifecycleConfiguration>
|
||||||
|
```
|
||||||
|
|
||||||
### Performance Tuning
|
### Performance Tuning
|
||||||
|
|
||||||
| Variable | Default | Notes |
|
| Variable | Default | Notes |
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ Flask>=3.1.2
|
|||||||
Flask-Limiter>=4.1.1
|
Flask-Limiter>=4.1.1
|
||||||
Flask-Cors>=6.0.2
|
Flask-Cors>=6.0.2
|
||||||
Flask-WTF>=1.2.2
|
Flask-WTF>=1.2.2
|
||||||
|
python-dotenv>=1.2.1
|
||||||
pytest>=9.0.2
|
pytest>=9.0.2
|
||||||
requests>=2.32.5
|
requests>=2.32.5
|
||||||
boto3>=1.42.14
|
boto3>=1.42.14
|
||||||
|
|||||||
11
run.py
11
run.py
@@ -6,6 +6,17 @@ import os
|
|||||||
import sys
|
import sys
|
||||||
import warnings
|
import warnings
|
||||||
from multiprocessing import Process
|
from multiprocessing import Process
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
|
for _env_file in [
|
||||||
|
Path("/opt/myfsio/myfsio.env"),
|
||||||
|
Path.cwd() / ".env",
|
||||||
|
Path.cwd() / "myfsio.env",
|
||||||
|
]:
|
||||||
|
if _env_file.exists():
|
||||||
|
load_dotenv(_env_file, override=True)
|
||||||
|
|
||||||
from app import create_api_app, create_ui_app
|
from app import create_api_app, create_ui_app
|
||||||
from app.config import AppConfig
|
from app.config import AppConfig
|
||||||
|
|||||||
3503
static/js/bucket-detail-main.js
Normal file
3503
static/js/bucket-detail-main.js
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -116,8 +116,8 @@
|
|||||||
<div class="card h-100 iam-user-card">
|
<div class="card h-100 iam-user-card">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="d-flex align-items-start justify-content-between mb-3">
|
<div class="d-flex align-items-start justify-content-between mb-3">
|
||||||
<div class="d-flex align-items-center gap-3">
|
<div class="d-flex align-items-center gap-3 min-width-0 overflow-hidden">
|
||||||
<div class="user-avatar user-avatar-lg">
|
<div class="user-avatar user-avatar-lg flex-shrink-0">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 16 16">
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 16 16">
|
||||||
<path d="M8 8a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm2-3a2 2 0 1 1-4 0 2 2 0 0 1 4 0zm4 8c0 1-1 1-1 1H3s-1 0-1-1 1-4 6-4 6 3 6 4zm-1-.004c-.001-.246-.154-.986-.832-1.664C11.516 10.68 10.289 10 8 10c-2.29 0-3.516.68-4.168 1.332-.678.678-.83 1.418-.832 1.664h10z"/>
|
<path d="M8 8a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm2-3a2 2 0 1 1-4 0 2 2 0 0 1 4 0zm4 8c0 1-1 1-1 1H3s-1 0-1-1 1-4 6-4 6 3 6 4zm-1-.004c-.001-.246-.154-.986-.832-1.664C11.516 10.68 10.289 10 8 10c-2.29 0-3.516.68-4.168 1.332-.678.678-.83 1.418-.832 1.664h10z"/>
|
||||||
</svg>
|
</svg>
|
||||||
@@ -127,7 +127,7 @@
|
|||||||
<code class="small text-muted d-block text-truncate" title="{{ user.access_key }}">{{ user.access_key }}</code>
|
<code class="small text-muted d-block text-truncate" title="{{ user.access_key }}">{{ user.access_key }}</code>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="dropdown">
|
<div class="dropdown flex-shrink-0">
|
||||||
<button class="btn btn-sm btn-icon" type="button" data-bs-toggle="dropdown" aria-expanded="false">
|
<button class="btn btn-sm btn-icon" type="button" data-bs-toggle="dropdown" aria-expanded="false">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
|
||||||
<path d="M9.5 13a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0zm0-5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0zm0-5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0z"/>
|
<path d="M9.5 13a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0zm0-5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0zm0-5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0z"/>
|
||||||
|
|||||||
@@ -184,5 +184,5 @@ class TestPaginatedObjectListing:
|
|||||||
assert resp.status_code == 200
|
assert resp.status_code == 200
|
||||||
|
|
||||||
html = resp.data.decode("utf-8")
|
html = resp.data.decode("utf-8")
|
||||||
# Should have the JavaScript loading infrastructure
|
# Should have the JavaScript loading infrastructure (external JS file)
|
||||||
assert "loadObjects" in html or "objectsApiUrl" in html
|
assert "bucket-detail-main.js" in html
|
||||||
|
|||||||
Reference in New Issue
Block a user