add instruction and srs
339
src/srs-technical-spec-documents/AtlasOS-Calypso-Engineering.md
Normal file
@@ -0,0 +1,339 @@
|
||||
# AtlasOS – Calypso
|
||||
## Engineering & Architecture Master Document
|
||||
### (CURSOR.md – Single Source of Truth)
|
||||
|
||||
Version: 2.0
|
||||
Status: Baseline – Product Definition
|
||||
Target OS: Ubuntu Server 24.04 LTS
|
||||
Category: Backup Appliance / Tape & VTL Virtualization Platform
|
||||
Date: 2025
|
||||
|
||||
---
|
||||
|
||||
## 0. Project Definition
|
||||
|
||||
**AtlasOS – Calypso** adalah **generic backup appliance** yang menyediakan:
|
||||
|
||||
- Disk-based backup storage (iSCSI block)
|
||||
- Physical tape library bridging (SAS / FC → iSCSI)
|
||||
- Virtual Tape Library (VTL) menggunakan **MHVTL**
|
||||
- Unified web-based management GUI
|
||||
- Authentication, authorization, audit, dan monitoring terpusat
|
||||
|
||||
Calypso **tidak terikat pada backup software tertentu**.
|
||||
|
||||
Backup software yang didukung mencakup (namun tidak terbatas pada):
|
||||
- Bacula
|
||||
- Veeam
|
||||
- Dell NetWorker
|
||||
- Veritas NetBackup
|
||||
- Commvault
|
||||
- Arcserve
|
||||
- Custom / proprietary SCSI-compliant backup engines
|
||||
|
||||
Calypso berperan sebagai **storage & SCSI virtualization appliance**, bukan backup controller.
|
||||
|
||||
---
|
||||
|
||||
## 1. Non-Negotiable Design Rules
|
||||
|
||||
1. **SCST adalah satu-satunya iSCSI target framework**
|
||||
- Tidak menggunakan LIO / targetcli
|
||||
- Semua disk, physical tape, dan VTL diexport melalui SCST
|
||||
|
||||
2. **Mapping tape device wajib konsisten**
|
||||
- LUN 0 → Medium changer
|
||||
- LUN 1..N → Tape drives (maksimal 8)
|
||||
- Berlaku untuk:
|
||||
- Physical tape library
|
||||
- MHVTL virtual library
|
||||
|
||||
3. **Single initiator policy untuk tape**
|
||||
- Hanya satu IQN initiator boleh login ke tape target
|
||||
- Pelanggaran harus terdeteksi dan ditampilkan di UI
|
||||
|
||||
4. **Backup software agnostic**
|
||||
- Tidak ada logic Bacula / NetWorker / Veeam di core
|
||||
- Hanya SCSI semantics + optional compatibility profile
|
||||
|
||||
5. **Tidak ada shell/terminal di UI (v1)**
|
||||
- Semua aksi melalui API tervalidasi
|
||||
|
||||
6. **Least privilege backend**
|
||||
- Backend berjalan sebagai non-root
|
||||
- Aksi privileged via polkit atau sudoers allowlist ketat
|
||||
|
||||
7. **Audit wajib**
|
||||
- Setiap perubahan konfigurasi
|
||||
- Operasi tape
|
||||
- Apply iSCSI
|
||||
- Perubahan IAM
|
||||
|
||||
8. **Operasi berat bersifat async**
|
||||
- Inventory
|
||||
- Load / unload
|
||||
- Rescan
|
||||
- Apply SCST
|
||||
- Support bundle
|
||||
|
||||
---
|
||||
|
||||
## 2. Core Appliance Capabilities
|
||||
|
||||
### 2.1 Disk Storage
|
||||
- LVM-backed repository
|
||||
- Optional ZFS (advanced SKU)
|
||||
- Export sebagai iSCSI block device
|
||||
- Digunakan untuk:
|
||||
- Disk backup target
|
||||
- Backing store MHVTL
|
||||
|
||||
### 2.2 Physical Tape Bridge (SAS / FC)
|
||||
- Discovery changer & drive
|
||||
- Inventory slot & barcode
|
||||
- Load / unload tape
|
||||
- Bridge ke backup software via iSCSI
|
||||
|
||||
### 2.3 Virtual Tape Library (MHVTL)
|
||||
- Virtual changer, drive, slot, dan tape
|
||||
- Disk-backed tape image
|
||||
- Barcode emulation
|
||||
- Export via SCST iSCSI
|
||||
- Use case:
|
||||
- Backup staging
|
||||
- Copy-to-tape
|
||||
- Testing / development
|
||||
- Air-gap simulation
|
||||
|
||||
---
|
||||
|
||||
## 3. High-Level Architecture
|
||||
|
||||
Backup Software (Any Vendor)
|
||||
|
|
||||
iSCSI
|
||||
|
|
||||
+--------------------------------+
|
||||
| AtlasOS – Calypso |
|
||||
| |
|
||||
| Disk Repository (LUN) |
|
||||
| MHVTL (Virtual Tape) |
|
||||
| Physical Tape Bridge |
|
||||
| SCST iSCSI Core |
|
||||
| |
|
||||
+--------------------------------+
|
||||
|
|
||||
SAS / FC
|
||||
|
|
||||
Physical Tape Library
|
||||
|
||||
---
|
||||
|
||||
## 4. Component List (Authoritative)
|
||||
|
||||
### 4.1 Base Platform
|
||||
- Ubuntu Server 24.04 LTS
|
||||
- systemd, journald
|
||||
- udev persistent naming
|
||||
- chrony
|
||||
- ufw / nftables
|
||||
|
||||
### 4.2 Disk Storage Layer
|
||||
- LVM2
|
||||
- thin-provisioning-tools
|
||||
- XFS (primary)
|
||||
- ext4 (alternative)
|
||||
- Optional ZFS
|
||||
- smartmontools, nvme-cli
|
||||
- parted, gdisk
|
||||
|
||||
### 4.3 Physical Tape Subsystem
|
||||
- SAS / FC HBA drivers
|
||||
- multipath-tools (optional)
|
||||
- lsscsi
|
||||
- sg3_utils
|
||||
- mt-st
|
||||
- mtx
|
||||
|
||||
### 4.4 Virtual Tape Library
|
||||
- mhvtl
|
||||
- mhvtl-utils / vtlcmd
|
||||
- Disk-backed tape images
|
||||
|
||||
### 4.5 iSCSI Target Stack
|
||||
- scst
|
||||
- iscsi-scst
|
||||
- scstadmin
|
||||
|
||||
### 4.6 Calypso Core Application
|
||||
**Backend (Go):**
|
||||
- storage
|
||||
- tape_physical
|
||||
- tape_vtl
|
||||
- scst
|
||||
- iscsi
|
||||
- tasks
|
||||
- system
|
||||
- monitoring
|
||||
- audit
|
||||
- profile_engine
|
||||
|
||||
**Frontend (React + Vite):**
|
||||
- Dashboard
|
||||
- Disk Repository
|
||||
- Physical Tape
|
||||
- Virtual Tape Library
|
||||
- iSCSI Targets
|
||||
- Clients / Initiators
|
||||
- Tasks & Jobs
|
||||
- Alerts & Logs
|
||||
- System & IAM
|
||||
|
||||
### 4.7 Authentication & IAM
|
||||
- PostgreSQL
|
||||
- Local auth (Argon2id)
|
||||
- LDAP
|
||||
- OIDC SSO
|
||||
- RBAC
|
||||
- Audit log
|
||||
|
||||
### 4.8 Monitoring & Observability
|
||||
- Built-in health checks
|
||||
- Alerts engine
|
||||
- Event stream (WebSocket)
|
||||
- Optional Prometheus exporter
|
||||
- node_exporter
|
||||
|
||||
### 4.9 Web & Security Perimeter
|
||||
- Caddy (recommended) / Nginx
|
||||
- TLS
|
||||
- Security headers
|
||||
- Rate limiting
|
||||
|
||||
### 4.10 Packaging & Operations
|
||||
- Debian packages (.deb)
|
||||
- systemd services:
|
||||
- calypso-api
|
||||
- scst
|
||||
- mhvtl
|
||||
- postgresql
|
||||
- caddy/nginx
|
||||
- Installer & upgrade scripts
|
||||
- Support bundle generator
|
||||
|
||||
---
|
||||
|
||||
## 5. Repository Structure (Monorepo)
|
||||
|
||||
calypso/
|
||||
README.md
|
||||
CURSOR.md
|
||||
|
||||
docs/
|
||||
COMPONENT-LIST-AtlasOS-Calypso.md
|
||||
SRS-00-Main-AtlasOS-Calypso.md
|
||||
SRS-01-Storage-Component.md
|
||||
SRS-02-VTL-and-Tape-Bridge.md
|
||||
SRS-03-System-Management.md
|
||||
SRS-04-Auth-and-IAM.md
|
||||
SRS-05-Monitoring-and-Observability.md
|
||||
|
||||
frontend/
|
||||
backend/
|
||||
deploy/
|
||||
|
||||
---
|
||||
|
||||
## 6. API Design Rules
|
||||
|
||||
- Base path `/api/v1`
|
||||
- JSON only
|
||||
- RBAC + audit untuk endpoint mutating
|
||||
- Async → `task_id`
|
||||
- Task status → `/api/v1/tasks/{id}`
|
||||
- WebSocket `/ws`:
|
||||
- task progress
|
||||
- alerts
|
||||
- inventory
|
||||
- iSCSI session changes
|
||||
|
||||
---
|
||||
|
||||
## 7. Database Scope (PostgreSQL)
|
||||
|
||||
Digunakan untuk:
|
||||
- Users, roles, permissions
|
||||
- Sessions & tokens
|
||||
- Audit log
|
||||
- Appliance configuration
|
||||
- Async task state
|
||||
- Alerts
|
||||
|
||||
Tidak digunakan untuk:
|
||||
- Backup data
|
||||
- Tape data
|
||||
|
||||
---
|
||||
|
||||
## 8. Coding Standards
|
||||
|
||||
### Backend
|
||||
- Go ≥ 1.22
|
||||
- Context everywhere
|
||||
- No raw shell execution
|
||||
- Strict validation
|
||||
- Unit tests untuk:
|
||||
- SCST config
|
||||
- Tape discovery
|
||||
- Task state machine
|
||||
- RBAC
|
||||
|
||||
### Frontend
|
||||
- TypeScript strict
|
||||
- API via `src/api`
|
||||
- No business logic di component
|
||||
- Unified error handling
|
||||
- WebSocket reconnect handling
|
||||
|
||||
---
|
||||
|
||||
## 9. Safety & Guardrails
|
||||
|
||||
- Blok aksi berbahaya saat tape aktif
|
||||
- Cegah:
|
||||
- multi-initiator tape
|
||||
- remove active drive
|
||||
- reconfig SCST saat write
|
||||
- Konfirmasi wajib untuk destructive action
|
||||
|
||||
---
|
||||
|
||||
## 10. Implementation Phases
|
||||
|
||||
1. Foundation & Auth
|
||||
2. Disk Repository
|
||||
3. Physical Tape Bridge
|
||||
4. Virtual Tape Library (MHVTL)
|
||||
5. Monitoring & IAM extensions
|
||||
6. UI polish & hardening
|
||||
|
||||
---
|
||||
|
||||
## 11. Definition of Done (DoD)
|
||||
|
||||
Feature dianggap selesai jika:
|
||||
- API implemented
|
||||
- RBAC enforced
|
||||
- Audit logged
|
||||
- UI workflow complete
|
||||
- Error handled
|
||||
- Docs updated
|
||||
|
||||
---
|
||||
|
||||
## 12. Final Authority
|
||||
|
||||
Jika ada konflik antar dokumen:
|
||||
**FILE INI ADALAH SUMBER KEBENARAN.**
|
||||
|
||||
AtlasOS – Calypso adalah **tape & VTL appliance kelas enterprise**.
|
||||
339
src/srs-technical-spec-documents/CURSOR.md
Normal file
@@ -0,0 +1,339 @@
|
||||
# AtlasOS – Calypso
|
||||
## Engineering & Architecture Master Document
|
||||
### (CURSOR.md – Single Source of Truth)
|
||||
|
||||
Version: 2.0
|
||||
Status: Baseline – Product Definition
|
||||
Target OS: Ubuntu Server 24.04 LTS
|
||||
Category: Backup Appliance / Tape & VTL Virtualization Platform
|
||||
Date: 2025
|
||||
|
||||
---
|
||||
|
||||
## 0. Project Definition
|
||||
|
||||
**AtlasOS – Calypso** adalah **generic backup appliance** yang menyediakan:
|
||||
|
||||
- Disk-based backup storage (iSCSI block)
|
||||
- Physical tape library bridging (SAS / FC → iSCSI)
|
||||
- Virtual Tape Library (VTL) menggunakan **MHVTL**
|
||||
- Unified web-based management GUI
|
||||
- Authentication, authorization, audit, dan monitoring terpusat
|
||||
|
||||
Calypso **tidak terikat pada backup software tertentu**.
|
||||
|
||||
Backup software yang didukung mencakup (namun tidak terbatas pada):
|
||||
- Bacula
|
||||
- Veeam
|
||||
- Dell NetWorker
|
||||
- Veritas NetBackup
|
||||
- Commvault
|
||||
- Arcserve
|
||||
- Custom / proprietary SCSI-compliant backup engines
|
||||
|
||||
Calypso berperan sebagai **storage & SCSI virtualization appliance**, bukan backup controller.
|
||||
|
||||
---
|
||||
|
||||
## 1. Non-Negotiable Design Rules
|
||||
|
||||
1. **SCST adalah satu-satunya iSCSI target framework**
|
||||
- Tidak menggunakan LIO / targetcli
|
||||
- Semua disk, physical tape, dan VTL diexport melalui SCST
|
||||
|
||||
2. **Mapping tape device wajib konsisten**
|
||||
- LUN 0 → Medium changer
|
||||
- LUN 1..N → Tape drives (maksimal 8)
|
||||
- Berlaku untuk:
|
||||
- Physical tape library
|
||||
- MHVTL virtual library
|
||||
|
||||
3. **Single initiator policy untuk tape**
|
||||
- Hanya satu IQN initiator boleh login ke tape target
|
||||
- Pelanggaran harus terdeteksi dan ditampilkan di UI
|
||||
|
||||
4. **Backup software agnostic**
|
||||
- Tidak ada logic Bacula / NetWorker / Veeam di core
|
||||
- Hanya SCSI semantics + optional compatibility profile
|
||||
|
||||
5. **Tidak ada shell/terminal di UI (v1)**
|
||||
- Semua aksi melalui API tervalidasi
|
||||
|
||||
6. **Least privilege backend**
|
||||
- Backend berjalan sebagai non-root
|
||||
- Aksi privileged via polkit atau sudoers allowlist ketat
|
||||
|
||||
7. **Audit wajib**
|
||||
- Setiap perubahan konfigurasi
|
||||
- Operasi tape
|
||||
- Apply iSCSI
|
||||
- Perubahan IAM
|
||||
|
||||
8. **Operasi berat bersifat async**
|
||||
- Inventory
|
||||
- Load / unload
|
||||
- Rescan
|
||||
- Apply SCST
|
||||
- Support bundle
|
||||
|
||||
---
|
||||
|
||||
## 2. Core Appliance Capabilities
|
||||
|
||||
### 2.1 Disk Storage
|
||||
- LVM-backed repository
|
||||
- Optional ZFS (advanced SKU)
|
||||
- Export sebagai iSCSI block device
|
||||
- Digunakan untuk:
|
||||
- Disk backup target
|
||||
- Backing store MHVTL
|
||||
|
||||
### 2.2 Physical Tape Bridge (SAS / FC)
|
||||
- Discovery changer & drive
|
||||
- Inventory slot & barcode
|
||||
- Load / unload tape
|
||||
- Bridge ke backup software via iSCSI
|
||||
|
||||
### 2.3 Virtual Tape Library (MHVTL)
|
||||
- Virtual changer, drive, slot, dan tape
|
||||
- Disk-backed tape image
|
||||
- Barcode emulation
|
||||
- Export via SCST iSCSI
|
||||
- Use case:
|
||||
- Backup staging
|
||||
- Copy-to-tape
|
||||
- Testing / development
|
||||
- Air-gap simulation
|
||||
|
||||
---
|
||||
|
||||
## 3. High-Level Architecture
|
||||
|
||||
Backup Software (Any Vendor)
|
||||
|
|
||||
iSCSI
|
||||
|
|
||||
+--------------------------------+
|
||||
| AtlasOS – Calypso |
|
||||
| |
|
||||
| Disk Repository (LUN) |
|
||||
| MHVTL (Virtual Tape) |
|
||||
| Physical Tape Bridge |
|
||||
| SCST iSCSI Core |
|
||||
| |
|
||||
+--------------------------------+
|
||||
|
|
||||
SAS / FC
|
||||
|
|
||||
Physical Tape Library
|
||||
|
||||
---
|
||||
|
||||
## 4. Component List (Authoritative)
|
||||
|
||||
### 4.1 Base Platform
|
||||
- Ubuntu Server 24.04 LTS
|
||||
- systemd, journald
|
||||
- udev persistent naming
|
||||
- chrony
|
||||
- ufw / nftables
|
||||
|
||||
### 4.2 Disk Storage Layer
|
||||
- LVM2
|
||||
- thin-provisioning-tools
|
||||
- XFS (primary)
|
||||
- ext4 (alternative)
|
||||
- Optional ZFS
|
||||
- smartmontools, nvme-cli
|
||||
- parted, gdisk
|
||||
|
||||
### 4.3 Physical Tape Subsystem
|
||||
- SAS / FC HBA drivers
|
||||
- multipath-tools (optional)
|
||||
- lsscsi
|
||||
- sg3_utils
|
||||
- mt-st
|
||||
- mtx
|
||||
|
||||
### 4.4 Virtual Tape Library
|
||||
- mhvtl
|
||||
- mhvtl-utils / vtlcmd
|
||||
- Disk-backed tape images
|
||||
|
||||
### 4.5 iSCSI Target Stack
|
||||
- scst
|
||||
- iscsi-scst
|
||||
- scstadmin
|
||||
|
||||
### 4.6 Calypso Core Application
|
||||
**Backend (Go):**
|
||||
- storage
|
||||
- tape_physical
|
||||
- tape_vtl
|
||||
- scst
|
||||
- iscsi
|
||||
- tasks
|
||||
- system
|
||||
- monitoring
|
||||
- audit
|
||||
- profile_engine
|
||||
|
||||
**Frontend (React + Vite):**
|
||||
- Dashboard
|
||||
- Disk Repository
|
||||
- Physical Tape
|
||||
- Virtual Tape Library
|
||||
- iSCSI Targets
|
||||
- Clients / Initiators
|
||||
- Tasks & Jobs
|
||||
- Alerts & Logs
|
||||
- System & IAM
|
||||
|
||||
### 4.7 Authentication & IAM
|
||||
- PostgreSQL
|
||||
- Local auth (Argon2id)
|
||||
- LDAP
|
||||
- OIDC SSO
|
||||
- RBAC
|
||||
- Audit log
|
||||
|
||||
### 4.8 Monitoring & Observability
|
||||
- Built-in health checks
|
||||
- Alerts engine
|
||||
- Event stream (WebSocket)
|
||||
- Optional Prometheus exporter
|
||||
- node_exporter
|
||||
|
||||
### 4.9 Web & Security Perimeter
|
||||
- Caddy (recommended) / Nginx
|
||||
- TLS
|
||||
- Security headers
|
||||
- Rate limiting
|
||||
|
||||
### 4.10 Packaging & Operations
|
||||
- Debian packages (.deb)
|
||||
- systemd services:
|
||||
- calypso-api
|
||||
- scst
|
||||
- mhvtl
|
||||
- postgresql
|
||||
- caddy/nginx
|
||||
- Installer & upgrade scripts
|
||||
- Support bundle generator
|
||||
|
||||
---
|
||||
|
||||
## 5. Repository Structure (Monorepo)
|
||||
|
||||
calypso/
|
||||
README.md
|
||||
CURSOR.md
|
||||
|
||||
docs/
|
||||
COMPONENT-LIST-AtlasOS-Calypso.md
|
||||
SRS-00-Main-AtlasOS-Calypso.md
|
||||
SRS-01-Storage-Component.md
|
||||
SRS-02-VTL-and-Tape-Bridge.md
|
||||
SRS-03-System-Management.md
|
||||
SRS-04-Auth-and-IAM.md
|
||||
SRS-05-Monitoring-and-Observability.md
|
||||
|
||||
frontend/
|
||||
backend/
|
||||
deploy/
|
||||
|
||||
---
|
||||
|
||||
## 6. API Design Rules
|
||||
|
||||
- Base path `/api/v1`
|
||||
- JSON only
|
||||
- RBAC + audit untuk endpoint mutating
|
||||
- Async → `task_id`
|
||||
- Task status → `/api/v1/tasks/{id}`
|
||||
- WebSocket `/ws`:
|
||||
- task progress
|
||||
- alerts
|
||||
- inventory
|
||||
- iSCSI session changes
|
||||
|
||||
---
|
||||
|
||||
## 7. Database Scope (PostgreSQL)
|
||||
|
||||
Digunakan untuk:
|
||||
- Users, roles, permissions
|
||||
- Sessions & tokens
|
||||
- Audit log
|
||||
- Appliance configuration
|
||||
- Async task state
|
||||
- Alerts
|
||||
|
||||
Tidak digunakan untuk:
|
||||
- Backup data
|
||||
- Tape data
|
||||
|
||||
---
|
||||
|
||||
## 8. Coding Standards
|
||||
|
||||
### Backend
|
||||
- Go ≥ 1.22
|
||||
- Context everywhere
|
||||
- No raw shell execution
|
||||
- Strict validation
|
||||
- Unit tests untuk:
|
||||
- SCST config
|
||||
- Tape discovery
|
||||
- Task state machine
|
||||
- RBAC
|
||||
|
||||
### Frontend
|
||||
- TypeScript strict
|
||||
- API via `src/api`
|
||||
- No business logic di component
|
||||
- Unified error handling
|
||||
- WebSocket reconnect handling
|
||||
|
||||
---
|
||||
|
||||
## 9. Safety & Guardrails
|
||||
|
||||
- Blok aksi berbahaya saat tape aktif
|
||||
- Cegah:
|
||||
- multi-initiator tape
|
||||
- remove active drive
|
||||
- reconfig SCST saat write
|
||||
- Konfirmasi wajib untuk destructive action
|
||||
|
||||
---
|
||||
|
||||
## 10. Implementation Phases
|
||||
|
||||
1. Foundation & Auth
|
||||
2. Disk Repository
|
||||
3. Physical Tape Bridge
|
||||
4. Virtual Tape Library (MHVTL)
|
||||
5. Monitoring & IAM extensions
|
||||
6. UI polish & hardening
|
||||
|
||||
---
|
||||
|
||||
## 11. Definition of Done (DoD)
|
||||
|
||||
Feature dianggap selesai jika:
|
||||
- API implemented
|
||||
- RBAC enforced
|
||||
- Audit logged
|
||||
- UI workflow complete
|
||||
- Error handled
|
||||
- Docs updated
|
||||
|
||||
---
|
||||
|
||||
## 12. Final Authority
|
||||
|
||||
Jika ada konflik antar dokumen:
|
||||
**FILE INI ADALAH SUMBER KEBENARAN.**
|
||||
|
||||
AtlasOS – Calypso adalah **tape & VTL appliance kelas enterprise**.
|
||||
@@ -0,0 +1,164 @@
|
||||
# AtlasOS – Calypso Architecture Diagrams
|
||||
|
||||
## 1) System Context (High-Level)
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
subgraph Client["Backup Software Client (Any Vendor)"]
|
||||
C1["Backup Server / VM\n(Bacula / Veeam / NetWorker / NetBackup / etc)"]
|
||||
end
|
||||
|
||||
subgraph Net["Backup Network"]
|
||||
ISCSI["iSCSI (TCP/3260)\nInitiator Sessions"]
|
||||
HTTPS["HTTPS (TCP/443)\nAdmin GUI/API"]
|
||||
end
|
||||
|
||||
subgraph Calypso["AtlasOS – Calypso Appliance (Ubuntu 24.04)"]
|
||||
RP["Reverse Proxy\n(Caddy/Nginx)"]
|
||||
UI["Web GUI\n(React + Vite)"]
|
||||
API["Calypso Core API\n(Go REST + WebSocket)"]
|
||||
DB["PostgreSQL\n(IAM + Audit + Tasks + Alerts)"]
|
||||
SCST["SCST iSCSI Target Core\n(scst + iscsi-scst + scstadmin)"]
|
||||
DISK["Disk Storage Layer\n(LVM + XFS)\nBackup Repo + VTL Backing"]
|
||||
MHVTL["MHVTL Engine\n(Virtual Changer/Drives/Slots/Tapes)"]
|
||||
TOOLS["Tape Tools\n(lsscsi, sg3_utils, mtx, mt)"]
|
||||
end
|
||||
|
||||
subgraph Fabric["SAS/FC Fabric"]
|
||||
HBA["SAS/FC HBA"]
|
||||
end
|
||||
|
||||
subgraph Phys["Physical Tape Library"]
|
||||
CHG["Medium Changer"]
|
||||
DRV["Tape Drives (LTO-8)\nMax 8 presented"]
|
||||
SLOTS["Slots + Barcodes"]
|
||||
end
|
||||
|
||||
C1 --> ISCSI --> SCST
|
||||
C1 --> HTTPS --> RP
|
||||
RP --> UI
|
||||
RP --> API
|
||||
API --> DB
|
||||
API --> SCST
|
||||
API --> DISK
|
||||
API --> MHVTL
|
||||
API --> TOOLS
|
||||
|
||||
SCST --> DISK
|
||||
SCST --> MHVTL
|
||||
|
||||
TOOLS --> HBA --> CHG
|
||||
TOOLS --> HBA --> DRV
|
||||
HBA --> SLOTS
|
||||
|
||||
flowchart TB
|
||||
subgraph ControlPlane["Control Plane"]
|
||||
RP["Reverse Proxy\n(Caddy/Nginx)"]
|
||||
UI["Web GUI\nReact + Vite"]
|
||||
API["Calypso Core API (Go)\nREST + WS"]
|
||||
IAM["IAM Module\nLocal + LDAP + OIDC"]
|
||||
MON["Monitoring Module\nHealth + Alerts + Metrics"]
|
||||
TASKS["Task Engine\nAsync Ops + Progress"]
|
||||
AUDIT["Audit Engine\nAppend-only"]
|
||||
DB["PostgreSQL\nUsers/Roles/Sessions\nTasks/Alerts/Audit\nConfig State"]
|
||||
end
|
||||
|
||||
subgraph DataPlane["Data Plane (Storage/SCSI)"]
|
||||
SCST["SCST Target Core\niscsi-scst + scstadmin"]
|
||||
DISK["Disk Repo\nLVM + XFS"]
|
||||
MHVTL["MHVTL VTL\nVirtual Changer/Drives/Slots"]
|
||||
PHYS["Physical Tape\nSAS/FC Changer + Drives"]
|
||||
TOOLS["Tape Ops Tools\nlsscsi/sg3_utils/mtx/mt"]
|
||||
end
|
||||
|
||||
RP --> UI
|
||||
RP --> API
|
||||
|
||||
API --> IAM
|
||||
API --> MON
|
||||
API --> TASKS
|
||||
API --> AUDIT
|
||||
IAM --> DB
|
||||
MON --> DB
|
||||
TASKS --> DB
|
||||
AUDIT --> DB
|
||||
|
||||
API --> SCST
|
||||
API --> DISK
|
||||
API --> MHVTL
|
||||
API --> TOOLS
|
||||
|
||||
SCST --> DISK
|
||||
SCST --> MHVTL
|
||||
|
||||
TOOLS --> PHYS
|
||||
API --> PHYS
|
||||
|
||||
flowchart LR
|
||||
subgraph Initiator["Backup Software (Initiator)"]
|
||||
BSVR["Backup Server/VM\n(any vendor)"]
|
||||
end
|
||||
|
||||
subgraph Targets["Calypso iSCSI Targets (SCST)"]
|
||||
TDISK["Target: Disk Repository\nIQN: calypso.repo\nLUN 0: Disk LUN"]
|
||||
TPHYS["Target: Physical Tape Bridge\nIQN: calypso.tape.phys\nLUN 0: Changer\nLUN 1..8: Drives"]
|
||||
TVTL["Target: Virtual Tape Library\nIQN: calypso.tape.vtl\nLUN 0: VTL Changer\nLUN 1..N: VTL Drives"]
|
||||
end
|
||||
|
||||
subgraph Backing["Backing Devices"]
|
||||
DISK["LVM/XFS Repo LUN"]
|
||||
PHYCHG["Physical Changer (SAS/FC)"]
|
||||
PHYDRV["Physical Drives (LTO-8)"]
|
||||
VTLCHG["MHVTL Changer"]
|
||||
VTLDRV["MHVTL Drives"]
|
||||
VTLDATA["Disk-backed Tape Images\n(under repo/pool)"]
|
||||
end
|
||||
|
||||
BSVR --> TDISK
|
||||
BSVR --> TPHYS
|
||||
BSVR --> TVTL
|
||||
|
||||
TDISK --> DISK
|
||||
|
||||
TPHYS --> PHYCHG
|
||||
TPHYS --> PHYDRV
|
||||
|
||||
TVTL --> VTLCHG
|
||||
TVTL --> VTLDRV
|
||||
VTLDRV --> VTLDATA
|
||||
|
||||
sequenceDiagram
|
||||
autonumber
|
||||
participant UI as Web GUI
|
||||
participant API as Calypso API (Go)
|
||||
participant DB as PostgreSQL
|
||||
participant SCST as SCST (iSCSI Target)
|
||||
participant MHVTL as MHVTL
|
||||
participant TOOLS as Tape Tools (mtx/mt/sg3)
|
||||
participant WS as WebSocket Stream
|
||||
|
||||
UI->>API: POST /api/v1/tape/inventory (physical or vtl)
|
||||
API->>DB: create task (inventory)
|
||||
API-->>UI: 202 Accepted + task_id
|
||||
API->>WS: publish task_started(task_id)
|
||||
|
||||
alt Physical inventory
|
||||
API->>TOOLS: run inventory (mtx/sg3)
|
||||
TOOLS-->>API: inventory result
|
||||
else VTL inventory
|
||||
API->>MHVTL: vtlcmd inventory
|
||||
MHVTL-->>API: inventory result
|
||||
end
|
||||
|
||||
API->>DB: update task result + state=success
|
||||
API->>WS: publish task_progress + task_success
|
||||
UI->>WS: receive updates (realtime)
|
||||
|
||||
UI->>API: POST /api/v1/iscsi/apply
|
||||
API->>DB: audit + task (apply scst)
|
||||
API->>SCST: scstadmin apply config (validate/rollback)
|
||||
SCST-->>API: apply result
|
||||
API->>WS: publish iscsi_apply_result
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
# SRS-00 — AtlasOS – Calypso (Main)
|
||||
|
||||
Version: 1.0
|
||||
Status: Draft – Baseline
|
||||
Target OS: Ubuntu Server 24.04 LTS
|
||||
Primary Use Case: Backup Appliance (Disk + Tape) + iSCSI Bridge to VM (Bacula)
|
||||
Date: 2025
|
||||
|
||||
---
|
||||
|
||||
## 1. Purpose
|
||||
AtlasOS – Calypso is an enterprise-grade backup appliance platform designed to unify disk-based backup repositories and physical tape libraries under a single, auditable, and storage-centric management plane. The system is optimized for reliability, determinism, and operational safety in enterprise backup environments.
|
||||
|
||||
This document defines the **system-level software requirements** for AtlasOS – Calypso and acts as the parent SRS for all subsystem specifications.
|
||||
|
||||
---
|
||||
|
||||
## 2. Scope
|
||||
|
||||
### 2.1 In Scope
|
||||
- Disk-based backup repository provisioning and management
|
||||
- Physical tape library (LTO-8, SAS/FC) discovery and control
|
||||
- SCST-based iSCSI target orchestration
|
||||
- iSCSI bridge for tape library access by Bacula VM
|
||||
- Integration with Bacula Storage Daemon
|
||||
- System service management and diagnostics
|
||||
- Authentication, authorization, and auditing
|
||||
- Monitoring, alerting, and observability
|
||||
|
||||
### 2.2 Out of Scope (Version 1)
|
||||
- Bacula Director configuration and job scheduling
|
||||
- Multi-tenant isolation
|
||||
- High Availability (active-active) appliance clustering
|
||||
- Cloud object storage tiering
|
||||
- Tape encryption key lifecycle management
|
||||
|
||||
---
|
||||
|
||||
## 3. System Architecture
|
||||
|
||||
### 3.1 Logical Architecture
|
||||
|
||||
Browser (React + Vite UI)
|
||||
→ HTTPS (443)
|
||||
→ Reverse Proxy (Caddy / Nginx)
|
||||
→ Calypso Core API (Go)
|
||||
|
||||
Calypso Core integrates with:
|
||||
- SCST (Disk and Tape iSCSI targets)
|
||||
- Tape utilities (lsscsi, sg3_utils, mtx, mt)
|
||||
- Bacula Storage Daemon interfaces
|
||||
- PostgreSQL (IAM, audit, state)
|
||||
- systemd and journald
|
||||
|
||||
---
|
||||
|
||||
## 4. User Roles
|
||||
- Admin: Full system configuration and control
|
||||
- Operator: Day-to-day tape operations and monitoring
|
||||
- ReadOnly: Monitoring and reporting only
|
||||
|
||||
---
|
||||
|
||||
## 5. System-Level Requirements
|
||||
- Provide a web-based GUI for full appliance lifecycle management
|
||||
- Expose a versioned REST API and WebSocket event stream
|
||||
- Ensure deterministic SCSI behavior for disk and tape devices
|
||||
- Enforce strict RBAC and full auditability
|
||||
- Guarantee safe recovery after reboot or service restart
|
||||
|
||||
---
|
||||
|
||||
## 6. Non-Functional Requirements
|
||||
- UI response time < 300 ms for read operations
|
||||
- Configuration apply time < 5 seconds
|
||||
- All operations must be idempotent
|
||||
- Mandatory TLS for all access
|
||||
- Full compatibility with Ubuntu Server 24.04 LTS
|
||||
|
||||
---
|
||||
|
||||
## 7. Acceptance Criteria
|
||||
1. Bacula VM can access disk repository via iSCSI.
|
||||
2. Bacula VM can access tape changer and drives via iSCSI.
|
||||
3. Tape inventory, load/unload, and write operations succeed.
|
||||
4. All lifecycle operations are controllable from the GUI.
|
||||
5. System survives reboot without manual intervention.
|
||||
61
src/srs-technical-spec-documents/SRS-01-Storage-Component.md
Normal file
@@ -0,0 +1,61 @@
|
||||
# SRS-01 — AtlasOS – Calypso Storage Component
|
||||
|
||||
Version: 1.0
|
||||
Target Capacity: 30–60 TB
|
||||
Transport: iSCSI (SCST)
|
||||
Date: 2025
|
||||
|
||||
---
|
||||
|
||||
## 1. Purpose
|
||||
This document specifies requirements for the **Storage Repository Component**, which provides disk-based backup targets to Bacula through iSCSI.
|
||||
|
||||
---
|
||||
|
||||
## 2. Scope
|
||||
|
||||
### In Scope
|
||||
- Physical disk discovery
|
||||
- Backup repository provisioning
|
||||
- iSCSI LUN export
|
||||
- Capacity monitoring and alerts
|
||||
|
||||
### Out of Scope
|
||||
- Snapshot scheduling
|
||||
- Replication
|
||||
- Deduplication or compression engines
|
||||
|
||||
---
|
||||
|
||||
## 3. Functional Requirements
|
||||
|
||||
### 3.1 Disk Discovery
|
||||
- Detect block devices and volume groups
|
||||
- Display disk size, vendor, and health status
|
||||
|
||||
### 3.2 Repository Provisioning
|
||||
- Create repositories using LVM Logical Volumes
|
||||
- Optional support for ZFS zvol
|
||||
- Resize repositories with safety validation
|
||||
|
||||
### 3.3 iSCSI Export
|
||||
- Export repository as a dedicated iSCSI target
|
||||
- Map repository as LUN 0
|
||||
- Enforce initiator ACL
|
||||
|
||||
### 3.4 Capacity Monitoring
|
||||
- Display used and free capacity
|
||||
- Configurable warning and critical thresholds
|
||||
|
||||
---
|
||||
|
||||
## 4. Non-Functional Requirements
|
||||
- No data loss during resize operations
|
||||
- Minimal disruption to active iSCSI sessions
|
||||
|
||||
---
|
||||
|
||||
## 5. Acceptance Criteria
|
||||
1. Repository is visible as an iSCSI LUN.
|
||||
2. Bacula can mount and write to the disk target.
|
||||
3. Threshold alerts trigger correctly.
|
||||
@@ -0,0 +1,58 @@
|
||||
# SRS-02 — AtlasOS – Calypso VTL & Tape Bridge
|
||||
|
||||
Version: 1.0
|
||||
Target: Physical Tape Library LTO-8 (SAS / FC)
|
||||
Maximum Drives: 8
|
||||
Date: 2025
|
||||
|
||||
---
|
||||
|
||||
## 1. Purpose
|
||||
This document defines requirements for managing and exporting **physical tape libraries** through iSCSI, allowing Bacula to access tape hardware without direct attachment.
|
||||
|
||||
---
|
||||
|
||||
## 2. Scope
|
||||
|
||||
### In Scope
|
||||
- Tape changer and drive discovery
|
||||
- Slot inventory and barcode handling
|
||||
- Tape load and unload operations
|
||||
- iSCSI export of changer and drives
|
||||
|
||||
### Out of Scope
|
||||
- Virtual tape emulation
|
||||
- Tape encryption workflows
|
||||
- Tape duplication policies
|
||||
|
||||
---
|
||||
|
||||
## 3. Functional Requirements
|
||||
|
||||
### 3.1 Discovery
|
||||
- Detect tape changer and drives via SCSI inquiry
|
||||
- Group devices into a single logical library
|
||||
|
||||
### 3.2 Operations
|
||||
- Perform slot inventory
|
||||
- Load tape into drive
|
||||
- Unload tape to slot
|
||||
- Display drive state and errors
|
||||
|
||||
### 3.3 iSCSI Mapping
|
||||
- LUN 0 mapped to changer
|
||||
- LUN 1–8 mapped to tape drives
|
||||
- Enforce single-initiator access
|
||||
|
||||
---
|
||||
|
||||
## 4. Non-Functional Requirements
|
||||
- Operations must be asynchronous
|
||||
- Prevent conflicting concurrent actions
|
||||
|
||||
---
|
||||
|
||||
## 5. Acceptance Criteria
|
||||
1. Tape library is visible in Bacula.
|
||||
2. Inventory and load/unload succeed.
|
||||
3. No multi-initiator conflicts occur.
|
||||
31
src/srs-technical-spec-documents/SRS-03-System-Management.md
Normal file
@@ -0,0 +1,31 @@
|
||||
# SRS-03 — AtlasOS – Calypso System Management
|
||||
|
||||
Version: 1.0
|
||||
Target OS: Ubuntu Server 24.04
|
||||
Date: 2025
|
||||
|
||||
---
|
||||
|
||||
## 1. Purpose
|
||||
Defines requirements for managing system services, diagnostics, and appliance health.
|
||||
|
||||
---
|
||||
|
||||
## 2. Functional Requirements
|
||||
- Display systemd service status
|
||||
- Restart services with RBAC enforcement
|
||||
- View journald logs
|
||||
- Generate diagnostic support bundles
|
||||
|
||||
---
|
||||
|
||||
## 3. Constraints
|
||||
- No shell access from the UI
|
||||
- All actions must be audited
|
||||
|
||||
---
|
||||
|
||||
## 4. Acceptance Criteria
|
||||
1. Services are manageable from the UI.
|
||||
2. Logs are accessible for troubleshooting.
|
||||
3. Support bundles can be generated and downloaded.
|
||||
38
src/srs-technical-spec-documents/SRS-04-Auth-and-IAM.md
Normal file
@@ -0,0 +1,38 @@
|
||||
# SRS-04 — AtlasOS – Calypso Authentication & IAM
|
||||
|
||||
Version: 1.0
|
||||
Identity Sources: Local (PostgreSQL), LDAP, OIDC SSO
|
||||
Date: 2025
|
||||
|
||||
---
|
||||
|
||||
## 1. Purpose
|
||||
Defines authentication, authorization, and audit requirements for AtlasOS – Calypso.
|
||||
|
||||
---
|
||||
|
||||
## 2. Authentication Methods
|
||||
- Local authentication with Argon2id password hashing
|
||||
- LDAP bind authentication
|
||||
- OIDC-based SSO integration
|
||||
|
||||
---
|
||||
|
||||
## 3. Authorization
|
||||
- Role-Based Access Control (Admin, Operator, ReadOnly)
|
||||
- Permission enforcement per API endpoint
|
||||
|
||||
---
|
||||
|
||||
## 4. Audit Logging
|
||||
- Login success and failure
|
||||
- Configuration changes
|
||||
- Privileged system operations
|
||||
|
||||
---
|
||||
|
||||
## 5. Acceptance Criteria
|
||||
1. Local login works correctly.
|
||||
2. LDAP authentication functions as expected.
|
||||
3. OIDC login succeeds.
|
||||
4. Audit trail is complete and immutable.
|
||||
@@ -0,0 +1,36 @@
|
||||
# SRS-05 — AtlasOS – Calypso Monitoring & Observability
|
||||
|
||||
Version: 1.0
|
||||
Date: 2025
|
||||
|
||||
---
|
||||
|
||||
## 1. Purpose
|
||||
Defines monitoring, alerting, and observability requirements for the Calypso appliance.
|
||||
|
||||
---
|
||||
|
||||
## 2. Monitoring Scope
|
||||
- Disk capacity and health
|
||||
- Tape drive and changer status
|
||||
- iSCSI session stability
|
||||
- Service uptime
|
||||
|
||||
---
|
||||
|
||||
## 3. Alerts
|
||||
- Disk capacity thresholds
|
||||
- Tape errors and drive offline
|
||||
- Service failures
|
||||
|
||||
---
|
||||
|
||||
## 4. Event Streaming
|
||||
- Real-time UI updates via WebSocket
|
||||
|
||||
---
|
||||
|
||||
## 5. Acceptance Criteria
|
||||
1. Health states are visible in the UI.
|
||||
2. Alerts trigger correctly.
|
||||
3. Events stream to the UI in real time.
|
||||
@@ -0,0 +1,262 @@
|
||||
# AtlasOS – Calypso
|
||||
## Appliance Component List (Baseline v1)
|
||||
|
||||
Version: 1.0
|
||||
Status: Baseline – Product Definition
|
||||
Target OS: Ubuntu Server 24.04 LTS
|
||||
Date: 2025
|
||||
|
||||
---
|
||||
|
||||
## 1. Overview
|
||||
|
||||
AtlasOS – Calypso is a **generic backup appliance platform** that provides:
|
||||
|
||||
- Disk-based backup storage
|
||||
- Physical tape library bridging (SAS / FC)
|
||||
- Virtual Tape Library (VTL) services
|
||||
- iSCSI presentation for **any backup software**
|
||||
- Centralized management via web-based GUI
|
||||
- Strong security, auditability, and observability
|
||||
|
||||
This document enumerates **all required components** for building, operating, and packaging the appliance.
|
||||
|
||||
---
|
||||
|
||||
## 2. Base Platform Components
|
||||
|
||||
### 2.1 Operating System
|
||||
- Ubuntu Server 24.04 LTS
|
||||
- systemd
|
||||
- journald
|
||||
- udev (persistent device naming)
|
||||
- chrony (time synchronization)
|
||||
- ufw / nftables (firewall)
|
||||
|
||||
---
|
||||
|
||||
## 3. Disk Storage Layer
|
||||
|
||||
Used for:
|
||||
- Backup repository (disk target)
|
||||
- Virtual tape backing store (MHVTL)
|
||||
|
||||
Components:
|
||||
- LVM2
|
||||
- thin-provisioning-tools
|
||||
- XFS (primary filesystem)
|
||||
- ext4 (alternative)
|
||||
- (Optional) ZFS (advanced SKU)
|
||||
- smartmontools
|
||||
- nvme-cli
|
||||
- parted / gdisk
|
||||
|
||||
---
|
||||
|
||||
## 4. Physical Tape Subsystem (SAS / FC)
|
||||
|
||||
Used for:
|
||||
- Physical tape library discovery
|
||||
- Changer and drive operations
|
||||
- Slot inventory
|
||||
- Load / unload operations
|
||||
|
||||
Components:
|
||||
- SAS or FC HBA drivers (Broadcom / LSI / QLogic / Emulex)
|
||||
- multipath-tools (FC dual-path environments)
|
||||
- lsscsi
|
||||
- sg3_utils
|
||||
- mt-st
|
||||
- mtx
|
||||
|
||||
---
|
||||
|
||||
## 5. Virtual Tape Library (VTL)
|
||||
|
||||
Provides:
|
||||
- Disk-backed virtual tape services
|
||||
- Virtual medium changer
|
||||
- Virtual tape drives
|
||||
- Virtual slots and barcodes
|
||||
|
||||
Components:
|
||||
- mhvtl
|
||||
- mhvtl-utils / vtlcmd (depending on build)
|
||||
- VTL configuration and tape image storage
|
||||
|
||||
Use Cases:
|
||||
- Backup staging
|
||||
- Copy-to-tape workflows
|
||||
- Test / development environments
|
||||
- Air-gap logic simulation
|
||||
|
||||
---
|
||||
|
||||
## 6. iSCSI Target Stack (Core Appliance Function)
|
||||
|
||||
All storage and tape devices are presented using **SCST**.
|
||||
|
||||
Components:
|
||||
- scst (kernel modules)
|
||||
- iscsi-scst
|
||||
- scstadmin
|
||||
|
||||
Usage:
|
||||
- Disk repository iSCSI targets
|
||||
- Physical tape library bridge
|
||||
- Virtual tape library (MHVTL) export
|
||||
|
||||
Design Rules:
|
||||
- SCST is the **only** target framework
|
||||
- One device is owned by one framework only
|
||||
- Tape targets must use:
|
||||
- LUN 0 → Medium changer
|
||||
- LUN 1..N → Tape drives (max 8)
|
||||
- Single initiator policy enforced for tape targets
|
||||
|
||||
---
|
||||
|
||||
## 7. Calypso Core Application
|
||||
|
||||
### 7.1 Backend (Go)
|
||||
|
||||
Responsibilities:
|
||||
- Disk storage orchestration (LVM/ZFS)
|
||||
- Physical tape management
|
||||
- VTL (MHVTL) management
|
||||
- SCST iSCSI target orchestration
|
||||
- Async task execution
|
||||
- State and configuration management
|
||||
- Audit logging
|
||||
- Backup software compatibility profiles
|
||||
|
||||
Modules:
|
||||
- storage
|
||||
- tape-physical
|
||||
- tape-vtl
|
||||
- iscsi
|
||||
- scst
|
||||
- tasks
|
||||
- system
|
||||
- monitoring
|
||||
- audit
|
||||
- profile-engine
|
||||
|
||||
---
|
||||
|
||||
### 7.2 Frontend (Web GUI)
|
||||
|
||||
Technology:
|
||||
- React
|
||||
- Vite
|
||||
- TypeScript
|
||||
- TailwindCSS + shadcn/ui
|
||||
- TanStack Query
|
||||
- WebSocket client
|
||||
|
||||
Functional Areas:
|
||||
- Dashboard
|
||||
- Disk Repository Management
|
||||
- Physical Tape Library
|
||||
- Virtual Tape Library (VTL)
|
||||
- iSCSI Targets & Initiators
|
||||
- Tasks & Jobs
|
||||
- Alerts & Logs
|
||||
- System Settings
|
||||
- Authentication & Users
|
||||
|
||||
---
|
||||
|
||||
## 8. Authentication & IAM
|
||||
|
||||
Components:
|
||||
- PostgreSQL
|
||||
- Local user authentication (Argon2id)
|
||||
- LDAP authentication (AD / OpenLDAP)
|
||||
- SSO via OIDC (Keycloak, Azure AD, Okta)
|
||||
- RBAC (Admin / Operator / ReadOnly)
|
||||
- Audit logging
|
||||
|
||||
Database Entities:
|
||||
- users
|
||||
- roles
|
||||
- permissions
|
||||
- user_roles
|
||||
- external_identities
|
||||
- sessions
|
||||
- audit_log
|
||||
|
||||
---
|
||||
|
||||
## 9. Monitoring & Observability
|
||||
|
||||
### 9.1 Built-in Monitoring
|
||||
- Disk capacity and health
|
||||
- Tape library status (physical & VTL)
|
||||
- SCST and iSCSI sessions
|
||||
- System services health
|
||||
- Alert engine
|
||||
- Event stream (WebSocket)
|
||||
|
||||
### 9.2 Optional External Integration
|
||||
- Prometheus metrics endpoint
|
||||
- node_exporter
|
||||
- Log forwarding (rsyslog / Loki)
|
||||
|
||||
---
|
||||
|
||||
## 10. Web Access & Security Perimeter
|
||||
|
||||
Components:
|
||||
- Caddy (recommended) or Nginx
|
||||
- TLS certificates (ACME or internal CA)
|
||||
- HTTP security headers
|
||||
- Rate limiting
|
||||
- Reverse proxy to API and UI
|
||||
|
||||
---
|
||||
|
||||
## 11. Packaging & Appliance Operations
|
||||
|
||||
Components:
|
||||
- Debian packages (.deb)
|
||||
- systemd service units:
|
||||
- calypso-api.service
|
||||
- scst.service
|
||||
- mhvtl.service
|
||||
- postgresql.service
|
||||
- caddy.service / nginx.service
|
||||
- Installer scripts
|
||||
- Upgrade workflow
|
||||
- Support bundle generator (logs + configs + inventory)
|
||||
|
||||
---
|
||||
|
||||
## 12. Backup Software Compatibility
|
||||
|
||||
AtlasOS – Calypso is **backup software agnostic**.
|
||||
|
||||
Supported via iSCSI:
|
||||
- Bacula
|
||||
- Veeam
|
||||
- Dell NetWorker
|
||||
- Veritas NetBackup
|
||||
- Commvault
|
||||
- Arcserve
|
||||
- Any SCSI-compliant backup engine
|
||||
|
||||
No backup software–specific logic is embedded in the core appliance.
|
||||
|
||||
---
|
||||
|
||||
## 13. Status
|
||||
|
||||
This component list represents the **authoritative baseline** for:
|
||||
- Architecture decisions
|
||||
- SRS alignment
|
||||
- Implementation planning
|
||||
- Packaging and deployment
|
||||
|
||||
All other documents must conform to this component list.
|
||||
|
||||
---
|
||||
362
src/srs-technical-spec-documents/mhvtl-integration-blueprint
Normal file
@@ -0,0 +1,362 @@
|
||||
# AtlasOS – Calypso
|
||||
## SCST + MHVTL Integration Blueprint
|
||||
### (Single Source – Engineering Grade)
|
||||
|
||||
Version: 1.0
|
||||
Status: Baseline Blueprint
|
||||
Target OS: Ubuntu Server 24.04 LTS
|
||||
Scope: Virtual Tape Library (MHVTL) + Physical Tape Bridging via SCST iSCSI
|
||||
Date: 2025
|
||||
|
||||
---
|
||||
|
||||
## 1. Purpose
|
||||
|
||||
Dokumen ini mendefinisikan **blueprint integrasi resmi** antara:
|
||||
|
||||
- **MHVTL** sebagai Virtual Tape Library provider
|
||||
- **SCST** sebagai satu-satunya iSCSI target framework
|
||||
- **AtlasOS – Calypso** sebagai orchestration & control plane
|
||||
|
||||
Blueprint ini berlaku untuk:
|
||||
- Virtual Tape Library (VTL)
|
||||
- Bridging physical tape library (SAS / FC)
|
||||
- iSCSI presentation ke **backup software apa pun** (vendor-agnostic)
|
||||
|
||||
Dokumen ini bersifat **authoritative** untuk implementasi.
|
||||
|
||||
---
|
||||
|
||||
## 2. Fundamental Design Principles
|
||||
|
||||
### 2.1 Ownership Model
|
||||
- **MHVTL** → producer perangkat SCSI virtual
|
||||
- **Physical tape library** → producer perangkat SCSI fisik
|
||||
- **SCST** → exporter perangkat ke iSCSI
|
||||
- **Backup software** → iSCSI initiator (consumer)
|
||||
|
||||
Tidak boleh ada dua framework yang mengelola device yang sama.
|
||||
|
||||
---
|
||||
|
||||
### 2.2 Mandatory Rules
|
||||
|
||||
1. SCST adalah **satu-satunya iSCSI target framework**
|
||||
2. Semua tape (physical & virtual) wajib diexport via SCST
|
||||
3. Mapping tape device:
|
||||
- LUN 0 → Medium Changer
|
||||
- LUN 1..N → Tape Drives (maks 8)
|
||||
4. Tape target **single-initiator only**
|
||||
5. Tidak ada backup-software-specific logic di core
|
||||
6. Semua operasi destructive / privileged:
|
||||
- async
|
||||
- auditable
|
||||
- guarded
|
||||
|
||||
---
|
||||
|
||||
## 3. High-Level Integration Architecture
|
||||
|
||||
### 3.1 Data Plane
|
||||
|
||||
Backup Software
|
||||
|
|
||||
iSCSI
|
||||
|
|
||||
SCST
|
||||
|
|
||||
+------------------+
|
||||
| Backend Device |
|
||||
+------------------+
|
||||
| |
|
||||
MHVTL Physical Tape
|
||||
|
|
||||
Disk Backing Store
|
||||
|
||||
|
||||
### 3.2 Control Plane
|
||||
- Calypso API mengontrol:
|
||||
- lifecycle MHVTL
|
||||
- SCST config generation & apply
|
||||
- device discovery
|
||||
- state & policy enforcement
|
||||
- UI hanya berbicara ke API
|
||||
- Tidak ada direct shell access
|
||||
|
||||
---
|
||||
|
||||
## 4. Device Model
|
||||
|
||||
### 4.1 Virtual Tape Library (MHVTL)
|
||||
MHVTL menyediakan:
|
||||
- Medium changer device
|
||||
- Tape drive devices
|
||||
- Slot & barcode emulation
|
||||
- Tape image files (disk-backed)
|
||||
|
||||
Device yang dihasilkan:
|
||||
- `/dev/sgX` (generic SCSI)
|
||||
- `/dev/stX` / `/dev/nstX` (tape)
|
||||
- `/dev/schX` (changer)
|
||||
|
||||
---
|
||||
|
||||
### 4.2 Physical Tape Library
|
||||
Physical library menyediakan:
|
||||
- Medium changer (SAS / FC)
|
||||
- Tape drives (LTO-8)
|
||||
- Slots & barcodes
|
||||
|
||||
Device yang dihasilkan:
|
||||
- `/dev/sgX`
|
||||
- `/dev/stX` / `/dev/nstX`
|
||||
- `/dev/schX`
|
||||
|
||||
---
|
||||
|
||||
## 5. Stable Device Naming (Critical)
|
||||
|
||||
### Problem
|
||||
Nama `/dev/sg*`, `/dev/st*`, `/dev/sch*` **tidak stabil** antar reboot.
|
||||
|
||||
### Blueprint Solution
|
||||
1. Discover device via:
|
||||
- `lsscsi -g`
|
||||
- `sg_inq`
|
||||
2. Ambil:
|
||||
- vendor
|
||||
- model
|
||||
- serial
|
||||
- device type
|
||||
3. Generate udev rules → symlink stabil
|
||||
|
||||
### Recommended Symlink Layout
|
||||
|
||||
/dev/calypso/
|
||||
vtl/
|
||||
<library_name>/
|
||||
changer
|
||||
drive1
|
||||
drive2
|
||||
physical/
|
||||
<library_serial>/
|
||||
changer
|
||||
drive1
|
||||
drive2
|
||||
|
||||
|
||||
SCST **hanya** boleh mereferensikan path stabil ini.
|
||||
|
||||
---
|
||||
|
||||
## 6. SCST Backend Strategy
|
||||
|
||||
### 6.1 Handler Selection
|
||||
Karena variasi build SCST, Calypso wajib melakukan **capability detection**.
|
||||
|
||||
Supported modes:
|
||||
- Native tape handler (jika tersedia)
|
||||
- Generic SCSI passthrough (`sg` based)
|
||||
|
||||
### 6.2 Recommended Default
|
||||
- **Changer** → SCSI generic passthrough
|
||||
- **Drive** → tape char device (`nst`) atau sg fallback
|
||||
|
||||
Handler mode dipilih **per target**, disimpan di DB.
|
||||
|
||||
---
|
||||
|
||||
## 7. iSCSI Target Model
|
||||
|
||||
### 7.1 Target Naming
|
||||
|
||||
|
||||
iqn.<year>.atlasos.calypso:vtl.<name>
|
||||
iqn.<year>.atlasos.calypso:tape.physical.<name>
|
||||
|
||||
|
||||
|
||||
### 7.2 LUN Mapping (Mandatory)
|
||||
| LUN | Device |
|
||||
|----|-------|
|
||||
| 0 | Medium Changer |
|
||||
| 1 | Tape Drive 1 |
|
||||
| 2 | Tape Drive 2 |
|
||||
| … | … (max 8) |
|
||||
|
||||
### 7.3 ACL Policy
|
||||
- Allow only explicit initiator IQN
|
||||
- Tape targets: **single initiator enforced**
|
||||
|
||||
---
|
||||
|
||||
## 8. Workflow: Create & Export VTL
|
||||
|
||||
### Step 1 — Prepare Backing Store
|
||||
- Allocate disk path for tape images:
|
||||
|
||||
|
||||
/var/lib/calypso/vtl/<lib>/tapes
|
||||
|
||||
|
||||
### Step 2 — Create MHVTL Library
|
||||
Calypso invokes MHVTL tools to:
|
||||
- create changer
|
||||
- create drives (1–8)
|
||||
- define slots
|
||||
- enable barcode
|
||||
|
||||
Result:
|
||||
- Device nodes appear
|
||||
- MHVTL config persisted
|
||||
|
||||
---
|
||||
|
||||
### Step 3 — Device Discovery
|
||||
- Run `lsscsi -g`
|
||||
- Match new devices
|
||||
- Persist mapping in DB
|
||||
- Generate udev rules
|
||||
|
||||
---
|
||||
|
||||
### Step 4 — Generate SCST Config
|
||||
- Define target IQN
|
||||
- Define LUN mappings
|
||||
- Define ACL
|
||||
|
||||
Config generated to:
|
||||
|
||||
/etc/calypso/scst/generated.conf
|
||||
|
||||
|
||||
---
|
||||
|
||||
### Step 5 — Apply SCST (Safe Mode)
|
||||
1. Validate config
|
||||
2. Apply via `scstadmin`
|
||||
3. Verify target visibility
|
||||
4. On failure → rollback to last-known-good
|
||||
|
||||
---
|
||||
|
||||
### Step 6 — Initiator Validation
|
||||
Calypso provides validation profile:
|
||||
- Linux initiator test
|
||||
- Windows initiator hints
|
||||
- Confirm:
|
||||
- changer visible
|
||||
- drives visible
|
||||
- basic SCSI ops OK
|
||||
|
||||
---
|
||||
|
||||
## 9. Guardrails & Safety Rules
|
||||
|
||||
### Hard Blocks
|
||||
- No SCST apply while:
|
||||
- drive busy
|
||||
- tape loaded & writing
|
||||
- No delete library with:
|
||||
- active initiator
|
||||
- loaded tape
|
||||
|
||||
### Soft Alerts
|
||||
- Multiple initiators → CRITICAL alert
|
||||
- Backing store nearly full → WARNING / CRITICAL
|
||||
|
||||
---
|
||||
|
||||
## 10. Observability Requirements
|
||||
|
||||
Calypso must monitor:
|
||||
- SCST target state
|
||||
- iSCSI sessions
|
||||
- MHVTL status:
|
||||
- drives count
|
||||
- slots usage
|
||||
- error logs
|
||||
- Disk usage (tape images)
|
||||
|
||||
Events pushed via WebSocket to UI.
|
||||
|
||||
---
|
||||
|
||||
## 11. Persisted State
|
||||
|
||||
### PostgreSQL
|
||||
- vtl_libraries
|
||||
- vtl_drives
|
||||
- vtl_tapes
|
||||
- iscsi_targets
|
||||
- lun_mappings
|
||||
- tasks
|
||||
- audit_log
|
||||
- alerts
|
||||
|
||||
### Filesystem
|
||||
|
||||
/etc/calypso/
|
||||
scst/
|
||||
generated.conf
|
||||
last-known-good.conf
|
||||
udev/
|
||||
|
||||
/var/lib/calypso/
|
||||
vtl/
|
||||
state/
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 12. Example Mapping (Conceptual)
|
||||
|
||||
**Library:** `vtl01`
|
||||
**Target IQN:** `iqn.2025.atlasos.calypso:vtl.vtl01`
|
||||
|
||||
| LUN | Device Path |
|
||||
|----|------------|
|
||||
| 0 | /dev/calypso/vtl/vtl01/changer |
|
||||
| 1 | /dev/calypso/vtl/vtl01/drive1 |
|
||||
| 2 | /dev/calypso/vtl/vtl01/drive2 |
|
||||
|
||||
---
|
||||
|
||||
## 13. Required Adapters in Calypso
|
||||
|
||||
1. **MHVTL Adapter**
|
||||
- create/delete library
|
||||
- manage tapes
|
||||
- status & logs
|
||||
|
||||
2. **SCST Adapter**
|
||||
- config generation
|
||||
- apply / rollback
|
||||
- session listing
|
||||
|
||||
3. **Discovery Adapter**
|
||||
- lsscsi mapping
|
||||
- sg_inq identification
|
||||
- udev rule generation
|
||||
|
||||
4. **Policy Engine**
|
||||
- single-initiator enforcement
|
||||
- safe-apply checks
|
||||
|
||||
---
|
||||
|
||||
## 14. Final Authority
|
||||
|
||||
Dokumen ini adalah **blueprint resmi integrasi SCST + MHVTL**.
|
||||
|
||||
Jika ada konflik:
|
||||
- Blueprint ini
|
||||
- CURSOR.md
|
||||
- SRS
|
||||
|
||||
maka **Blueprint ini menang untuk domain SCST + MHVTL**.
|
||||
|
||||
AtlasOS – Calypso diperlakukan sebagai **enterprise tape & VTL appliance**, bukan sekadar lab tool.
|
||||
|
||||
---
|
||||
|
||||
362
src/srs-technical-spec-documents/mhvtl-integration-blueprint.md
Normal file
@@ -0,0 +1,362 @@
|
||||
# AtlasOS – Calypso
|
||||
## SCST + MHVTL Integration Blueprint
|
||||
### (Single Source – Engineering Grade)
|
||||
|
||||
Version: 1.0
|
||||
Status: Baseline Blueprint
|
||||
Target OS: Ubuntu Server 24.04 LTS
|
||||
Scope: Virtual Tape Library (MHVTL) + Physical Tape Bridging via SCST iSCSI
|
||||
Date: 2025
|
||||
|
||||
---
|
||||
|
||||
## 1. Purpose
|
||||
|
||||
Dokumen ini mendefinisikan **blueprint integrasi resmi** antara:
|
||||
|
||||
- **MHVTL** sebagai Virtual Tape Library provider
|
||||
- **SCST** sebagai satu-satunya iSCSI target framework
|
||||
- **AtlasOS – Calypso** sebagai orchestration & control plane
|
||||
|
||||
Blueprint ini berlaku untuk:
|
||||
- Virtual Tape Library (VTL)
|
||||
- Bridging physical tape library (SAS / FC)
|
||||
- iSCSI presentation ke **backup software apa pun** (vendor-agnostic)
|
||||
|
||||
Dokumen ini bersifat **authoritative** untuk implementasi.
|
||||
|
||||
---
|
||||
|
||||
## 2. Fundamental Design Principles
|
||||
|
||||
### 2.1 Ownership Model
|
||||
- **MHVTL** → producer perangkat SCSI virtual
|
||||
- **Physical tape library** → producer perangkat SCSI fisik
|
||||
- **SCST** → exporter perangkat ke iSCSI
|
||||
- **Backup software** → iSCSI initiator (consumer)
|
||||
|
||||
Tidak boleh ada dua framework yang mengelola device yang sama.
|
||||
|
||||
---
|
||||
|
||||
### 2.2 Mandatory Rules
|
||||
|
||||
1. SCST adalah **satu-satunya iSCSI target framework**
|
||||
2. Semua tape (physical & virtual) wajib diexport via SCST
|
||||
3. Mapping tape device:
|
||||
- LUN 0 → Medium Changer
|
||||
- LUN 1..N → Tape Drives (maks 8)
|
||||
4. Tape target **single-initiator only**
|
||||
5. Tidak ada backup-software-specific logic di core
|
||||
6. Semua operasi destructive / privileged:
|
||||
- async
|
||||
- auditable
|
||||
- guarded
|
||||
|
||||
---
|
||||
|
||||
## 3. High-Level Integration Architecture
|
||||
|
||||
### 3.1 Data Plane
|
||||
|
||||
Backup Software
|
||||
|
|
||||
iSCSI
|
||||
|
|
||||
SCST
|
||||
|
|
||||
+------------------+
|
||||
| Backend Device |
|
||||
+------------------+
|
||||
| |
|
||||
MHVTL Physical Tape
|
||||
|
|
||||
Disk Backing Store
|
||||
|
||||
|
||||
### 3.2 Control Plane
|
||||
- Calypso API mengontrol:
|
||||
- lifecycle MHVTL
|
||||
- SCST config generation & apply
|
||||
- device discovery
|
||||
- state & policy enforcement
|
||||
- UI hanya berbicara ke API
|
||||
- Tidak ada direct shell access
|
||||
|
||||
---
|
||||
|
||||
## 4. Device Model
|
||||
|
||||
### 4.1 Virtual Tape Library (MHVTL)
|
||||
MHVTL menyediakan:
|
||||
- Medium changer device
|
||||
- Tape drive devices
|
||||
- Slot & barcode emulation
|
||||
- Tape image files (disk-backed)
|
||||
|
||||
Device yang dihasilkan:
|
||||
- `/dev/sgX` (generic SCSI)
|
||||
- `/dev/stX` / `/dev/nstX` (tape)
|
||||
- `/dev/schX` (changer)
|
||||
|
||||
---
|
||||
|
||||
### 4.2 Physical Tape Library
|
||||
Physical library menyediakan:
|
||||
- Medium changer (SAS / FC)
|
||||
- Tape drives (LTO-8)
|
||||
- Slots & barcodes
|
||||
|
||||
Device yang dihasilkan:
|
||||
- `/dev/sgX`
|
||||
- `/dev/stX` / `/dev/nstX`
|
||||
- `/dev/schX`
|
||||
|
||||
---
|
||||
|
||||
## 5. Stable Device Naming (Critical)
|
||||
|
||||
### Problem
|
||||
Nama `/dev/sg*`, `/dev/st*`, `/dev/sch*` **tidak stabil** antar reboot.
|
||||
|
||||
### Blueprint Solution
|
||||
1. Discover device via:
|
||||
- `lsscsi -g`
|
||||
- `sg_inq`
|
||||
2. Ambil:
|
||||
- vendor
|
||||
- model
|
||||
- serial
|
||||
- device type
|
||||
3. Generate udev rules → symlink stabil
|
||||
|
||||
### Recommended Symlink Layout
|
||||
|
||||
/dev/calypso/
|
||||
vtl/
|
||||
<library_name>/
|
||||
changer
|
||||
drive1
|
||||
drive2
|
||||
physical/
|
||||
<library_serial>/
|
||||
changer
|
||||
drive1
|
||||
drive2
|
||||
|
||||
|
||||
SCST **hanya** boleh mereferensikan path stabil ini.
|
||||
|
||||
---
|
||||
|
||||
## 6. SCST Backend Strategy
|
||||
|
||||
### 6.1 Handler Selection
|
||||
Karena variasi build SCST, Calypso wajib melakukan **capability detection**.
|
||||
|
||||
Supported modes:
|
||||
- Native tape handler (jika tersedia)
|
||||
- Generic SCSI passthrough (`sg` based)
|
||||
|
||||
### 6.2 Recommended Default
|
||||
- **Changer** → SCSI generic passthrough
|
||||
- **Drive** → tape char device (`nst`) atau sg fallback
|
||||
|
||||
Handler mode dipilih **per target**, disimpan di DB.
|
||||
|
||||
---
|
||||
|
||||
## 7. iSCSI Target Model
|
||||
|
||||
### 7.1 Target Naming
|
||||
|
||||
|
||||
iqn.<year>.atlasos.calypso:vtl.<name>
|
||||
iqn.<year>.atlasos.calypso:tape.physical.<name>
|
||||
|
||||
|
||||
|
||||
### 7.2 LUN Mapping (Mandatory)
|
||||
| LUN | Device |
|
||||
|----|-------|
|
||||
| 0 | Medium Changer |
|
||||
| 1 | Tape Drive 1 |
|
||||
| 2 | Tape Drive 2 |
|
||||
| … | … (max 8) |
|
||||
|
||||
### 7.3 ACL Policy
|
||||
- Allow only explicit initiator IQN
|
||||
- Tape targets: **single initiator enforced**
|
||||
|
||||
---
|
||||
|
||||
## 8. Workflow: Create & Export VTL
|
||||
|
||||
### Step 1 — Prepare Backing Store
|
||||
- Allocate disk path for tape images:
|
||||
|
||||
|
||||
/var/lib/calypso/vtl/<lib>/tapes
|
||||
|
||||
|
||||
### Step 2 — Create MHVTL Library
|
||||
Calypso invokes MHVTL tools to:
|
||||
- create changer
|
||||
- create drives (1–8)
|
||||
- define slots
|
||||
- enable barcode
|
||||
|
||||
Result:
|
||||
- Device nodes appear
|
||||
- MHVTL config persisted
|
||||
|
||||
---
|
||||
|
||||
### Step 3 — Device Discovery
|
||||
- Run `lsscsi -g`
|
||||
- Match new devices
|
||||
- Persist mapping in DB
|
||||
- Generate udev rules
|
||||
|
||||
---
|
||||
|
||||
### Step 4 — Generate SCST Config
|
||||
- Define target IQN
|
||||
- Define LUN mappings
|
||||
- Define ACL
|
||||
|
||||
Config generated to:
|
||||
|
||||
/etc/calypso/scst/generated.conf
|
||||
|
||||
|
||||
---
|
||||
|
||||
### Step 5 — Apply SCST (Safe Mode)
|
||||
1. Validate config
|
||||
2. Apply via `scstadmin`
|
||||
3. Verify target visibility
|
||||
4. On failure → rollback to last-known-good
|
||||
|
||||
---
|
||||
|
||||
### Step 6 — Initiator Validation
|
||||
Calypso provides validation profile:
|
||||
- Linux initiator test
|
||||
- Windows initiator hints
|
||||
- Confirm:
|
||||
- changer visible
|
||||
- drives visible
|
||||
- basic SCSI ops OK
|
||||
|
||||
---
|
||||
|
||||
## 9. Guardrails & Safety Rules
|
||||
|
||||
### Hard Blocks
|
||||
- No SCST apply while:
|
||||
- drive busy
|
||||
- tape loaded & writing
|
||||
- No delete library with:
|
||||
- active initiator
|
||||
- loaded tape
|
||||
|
||||
### Soft Alerts
|
||||
- Multiple initiators → CRITICAL alert
|
||||
- Backing store nearly full → WARNING / CRITICAL
|
||||
|
||||
---
|
||||
|
||||
## 10. Observability Requirements
|
||||
|
||||
Calypso must monitor:
|
||||
- SCST target state
|
||||
- iSCSI sessions
|
||||
- MHVTL status:
|
||||
- drives count
|
||||
- slots usage
|
||||
- error logs
|
||||
- Disk usage (tape images)
|
||||
|
||||
Events pushed via WebSocket to UI.
|
||||
|
||||
---
|
||||
|
||||
## 11. Persisted State
|
||||
|
||||
### PostgreSQL
|
||||
- vtl_libraries
|
||||
- vtl_drives
|
||||
- vtl_tapes
|
||||
- iscsi_targets
|
||||
- lun_mappings
|
||||
- tasks
|
||||
- audit_log
|
||||
- alerts
|
||||
|
||||
### Filesystem
|
||||
|
||||
/etc/calypso/
|
||||
scst/
|
||||
generated.conf
|
||||
last-known-good.conf
|
||||
udev/
|
||||
|
||||
/var/lib/calypso/
|
||||
vtl/
|
||||
state/
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 12. Example Mapping (Conceptual)
|
||||
|
||||
**Library:** `vtl01`
|
||||
**Target IQN:** `iqn.2025.atlasos.calypso:vtl.vtl01`
|
||||
|
||||
| LUN | Device Path |
|
||||
|----|------------|
|
||||
| 0 | /dev/calypso/vtl/vtl01/changer |
|
||||
| 1 | /dev/calypso/vtl/vtl01/drive1 |
|
||||
| 2 | /dev/calypso/vtl/vtl01/drive2 |
|
||||
|
||||
---
|
||||
|
||||
## 13. Required Adapters in Calypso
|
||||
|
||||
1. **MHVTL Adapter**
|
||||
- create/delete library
|
||||
- manage tapes
|
||||
- status & logs
|
||||
|
||||
2. **SCST Adapter**
|
||||
- config generation
|
||||
- apply / rollback
|
||||
- session listing
|
||||
|
||||
3. **Discovery Adapter**
|
||||
- lsscsi mapping
|
||||
- sg_inq identification
|
||||
- udev rule generation
|
||||
|
||||
4. **Policy Engine**
|
||||
- single-initiator enforcement
|
||||
- safe-apply checks
|
||||
|
||||
---
|
||||
|
||||
## 14. Final Authority
|
||||
|
||||
Dokumen ini adalah **blueprint resmi integrasi SCST + MHVTL**.
|
||||
|
||||
Jika ada konflik:
|
||||
- Blueprint ini
|
||||
- CURSOR.md
|
||||
- SRS
|
||||
|
||||
maka **Blueprint ini menang untuk domain SCST + MHVTL**.
|
||||
|
||||
AtlasOS – Calypso diperlakukan sebagai **enterprise tape & VTL appliance**, bukan sekadar lab tool.
|
||||
|
||||
---
|
||||
|
||||
297
src/srs-technical-spec-documents/scst-sample-config.md
Normal file
@@ -0,0 +1,297 @@
|
||||
# AtlasOS – Calypso
|
||||
## SCST Sample Configuration Blueprint
|
||||
### (Disk + VTL (MHVTL) + Physical Tape Bridge)
|
||||
|
||||
Version: 1.0
|
||||
Status: Reference / Implementation Template
|
||||
Target OS: Ubuntu Server 24.04 LTS
|
||||
SCST Role: **Single iSCSI Target Framework**
|
||||
Date: 2025
|
||||
|
||||
---
|
||||
|
||||
## 1. Scope & Philosophy
|
||||
|
||||
Dokumen ini berisi **contoh konfigurasi SCST** yang digunakan oleh
|
||||
AtlasOS – Calypso untuk:
|
||||
|
||||
- Disk-based backup repository (iSCSI block)
|
||||
- Virtual Tape Library (MHVTL)
|
||||
- Physical tape library bridge (SAS / FC → iSCSI)
|
||||
|
||||
⚠️ Catatan penting:
|
||||
- **SCST tidak memiliki satu format config universal** antar distro/build.
|
||||
- Pendekatan paling aman adalah **scstadmin-based configuration**.
|
||||
- File ini adalah **template konseptual + praktis**, bukan hard-coded syntax
|
||||
yang dipaksakan ke semua environment.
|
||||
|
||||
Calypso akan **meng-generate dan meng-apply konfigurasi ini secara dinamis**.
|
||||
|
||||
---
|
||||
|
||||
## 2. Global Assumptions & Placeholders
|
||||
|
||||
Ganti placeholder berikut sesuai environment:
|
||||
|
||||
| Placeholder | Contoh |
|
||||
|------------|-------|
|
||||
| `<INITIATOR_IQN>` | `iqn.1993-08.org.debian:01:backupvm` |
|
||||
| `<IQN_REPO>` | `iqn.2025.atlasos.calypso:repo.main` |
|
||||
| `<IQN_VTL>` | `iqn.2025.atlasos.calypso:vtl.vtl01` |
|
||||
| `<IQN_PHYS>` | `iqn.2025.atlasos.calypso:tape.physical.lib01` |
|
||||
|
||||
### Stable Device Paths (via udev – recommended)
|
||||
|
||||
/dev/calypso/
|
||||
repo/
|
||||
lun0
|
||||
vtl/
|
||||
vtl01/
|
||||
changer
|
||||
drive1
|
||||
drive2
|
||||
physical/
|
||||
lib01/
|
||||
changer
|
||||
drive1
|
||||
drive2
|
||||
|
||||
|
||||
⚠️ SCST **HARUS** memakai path stabil ini, bukan `/dev/sgX` langsung.
|
||||
|
||||
---
|
||||
|
||||
## 3. Pre-flight Checks
|
||||
|
||||
```bash
|
||||
systemctl status scst --no-pager
|
||||
systemctl status iscsi-scst --no-pager
|
||||
|
||||
Capability detection:
|
||||
|
||||
scstadmin -list_handler
|
||||
scstadmin -list_driver
|
||||
scstadmin -list_target
|
||||
|
||||
Calypso WAJIB mendeteksi handler yang tersedia sebelum apply config.
|
||||
|
||||
4. Disk Repository Target (iSCSI Block)
|
||||
4.1 Create Backend Device
|
||||
|
||||
Biasanya menggunakan handler vdisk.
|
||||
|
||||
scstadmin -open_dev repo_lun0 \
|
||||
-handler vdisk \
|
||||
-attributes filename=/dev/calypso/repo/lun0
|
||||
|
||||
|
||||
4.2 Create iSCSI Target & LUN Mapping
|
||||
scstadmin -add_target <IQN_REPO> -driver iscsi
|
||||
|
||||
scstadmin -add_lun 0 \
|
||||
-target <IQN_REPO> \
|
||||
-driver iscsi \
|
||||
-device repo_lun0
|
||||
|
||||
4.3 Initiator ACL
|
||||
scstadmin -add_group repo_acl \
|
||||
-target <IQN_REPO> \
|
||||
-driver iscsi
|
||||
|
||||
scstadmin -add_init <INITIATOR_IQN> \
|
||||
-group repo_acl \
|
||||
-target <IQN_REPO> \
|
||||
-driver iscsi
|
||||
|
||||
(Opsional: CHAP bila diperlukan)
|
||||
|
||||
5. Virtual Tape Library (MHVTL → SCST)
|
||||
5.1 Handler Strategy
|
||||
|
||||
Karena variasi build SCST, mode default paling aman:
|
||||
|
||||
Changer → SCSI Generic (sg passthrough)
|
||||
|
||||
Drives → SCSI Generic (atau native tape handler jika tersedia)
|
||||
|
||||
Handler aktual ditentukan lewat:
|
||||
|
||||
scstadmin -list_handler
|
||||
|
||||
Gunakan placeholder <SG_HANDLER>.
|
||||
|
||||
5.2 Create Backend Devices (VTL)
|
||||
# Changer
|
||||
scstadmin -open_dev vtl01_changer \
|
||||
-handler <SG_HANDLER> \
|
||||
-attributes filename=/dev/calypso/vtl/vtl01/changer
|
||||
|
||||
# Drives
|
||||
scstadmin -open_dev vtl01_drive1 \
|
||||
-handler <SG_HANDLER> \
|
||||
-attributes filename=/dev/calypso/vtl/vtl01/drive1
|
||||
|
||||
scstadmin -open_dev vtl01_drive2 \
|
||||
-handler <SG_HANDLER> \
|
||||
-attributes filename=/dev/calypso/vtl/vtl01/drive2
|
||||
|
||||
|
||||
5.3 Create iSCSI Target & LUN Mapping
|
||||
scstadmin -add_target <IQN_VTL> -driver iscsi
|
||||
|
||||
# Mandatory LUN layout
|
||||
scstadmin -add_lun 0 \
|
||||
-target <IQN_VTL> \
|
||||
-driver iscsi \
|
||||
-device vtl01_changer
|
||||
|
||||
scstadmin -add_lun 1 \
|
||||
-target <IQN_VTL> \
|
||||
-driver iscsi \
|
||||
-device vtl01_drive1
|
||||
|
||||
scstadmin -add_lun 2 \
|
||||
-target <IQN_VTL> \
|
||||
-driver iscsi \
|
||||
-device vtl01_drive2
|
||||
|
||||
|
||||
5.4 ACL (Single Initiator)
|
||||
scstadmin -add_group vtl_acl \
|
||||
-target <IQN_VTL> \
|
||||
-driver iscsi
|
||||
|
||||
scstadmin -add_init <INITIATOR_IQN> \
|
||||
-group vtl_acl \
|
||||
-target <IQN_VTL> \
|
||||
-driver iscsi
|
||||
|
||||
|
||||
⚠️ Tape target WAJIB single initiator.
|
||||
|
||||
6. Physical Tape Library Bridge (SAS / FC)
|
||||
6.1 Backend Devices
|
||||
|
||||
# Changer
|
||||
scstadmin -open_dev phys_changer \
|
||||
-handler <SG_HANDLER> \
|
||||
-attributes filename=/dev/calypso/physical/lib01/changer
|
||||
|
||||
# Drives
|
||||
scstadmin -open_dev phys_drive1 \
|
||||
-handler <SG_HANDLER> \
|
||||
-attributes filename=/dev/calypso/physical/lib01/drive1
|
||||
|
||||
scstadmin -open_dev phys_drive2 \
|
||||
-handler <SG_HANDLER> \
|
||||
-attributes filename=/dev/calypso/physical/lib01/drive2
|
||||
|
||||
|
||||
6.2 Target & LUN Mapping
|
||||
scstadmin -add_target <IQN_PHYS> -driver iscsi
|
||||
|
||||
scstadmin -add_lun 0 \
|
||||
-target <IQN_PHYS> \
|
||||
-driver iscsi \
|
||||
-device phys_changer
|
||||
|
||||
scstadmin -add_lun 1 \
|
||||
-target <IQN_PHYS> \
|
||||
-driver iscsi \
|
||||
-device phys_drive1
|
||||
|
||||
scstadmin -add_lun 2 \
|
||||
-target <IQN_PHYS> \
|
||||
-driver iscsi \
|
||||
-device phys_drive2
|
||||
|
||||
|
||||
6.3 ACL (Single Initiator)
|
||||
scstadmin -add_group phys_acl \
|
||||
-target <IQN_PHYS> \
|
||||
-driver iscsi
|
||||
|
||||
scstadmin -add_init <INITIATOR_IQN> \
|
||||
-group phys_acl \
|
||||
-target <IQN_PHYS> \
|
||||
-driver iscsi
|
||||
|
||||
7. Persist Configuration
|
||||
|
||||
Tergantung packaging SCST:
|
||||
|
||||
Common Method
|
||||
scstadmin -write_config /etc/scst.conf
|
||||
|
||||
|
||||
Calypso Recommended Pattern
|
||||
/etc/calypso/scst/
|
||||
generated.conf
|
||||
last-known-good.conf
|
||||
|
||||
|
||||
Flow:
|
||||
|
||||
Generate → validate
|
||||
|
||||
Apply
|
||||
|
||||
Health check
|
||||
|
||||
Promote to last-known-good
|
||||
|
||||
8. Initiator Validation
|
||||
iscsiadm -m discovery -t sendtargets -p <CALYPSO_IP>
|
||||
iscsiadm -m node --login
|
||||
lsscsi -g
|
||||
|
||||
|
||||
Untuk tape:
|
||||
sg_inq /dev/sgX
|
||||
|
||||
|
||||
Backup software harus melihat:
|
||||
|
||||
1 medium changer
|
||||
N tape drives
|
||||
Slot inventory valid
|
||||
|
||||
9. Operational Guardrails
|
||||
Forbidden
|
||||
|
||||
Apply config saat drive busy
|
||||
|
||||
Delete tape target saat initiator login
|
||||
|
||||
Multiple initiators ke tape target
|
||||
|
||||
Mandatory
|
||||
|
||||
Audit semua perubahan
|
||||
|
||||
Async task execution
|
||||
|
||||
Rollback otomatis jika apply gagal
|
||||
|
||||
10. Authority
|
||||
|
||||
Dokumen ini adalah reference resmi untuk:
|
||||
|
||||
SCST config generation
|
||||
|
||||
VTL export
|
||||
|
||||
Physical tape bridge
|
||||
|
||||
Jika ada konflik:
|
||||
|
||||
Blueprint SCST + MHVTL
|
||||
|
||||
CURSOR.md
|
||||
|
||||
SRS
|
||||
|
||||
maka dokumen ini menang untuk domain SCST configuration.
|
||||
|
||||
AtlasOS – Calypso diperlakukan sebagai
|
||||
enterprise-grade tape & VTL appliance, bukan sekadar target iSCSI biasa.
|
||||
453
src/web/dashboard-code.html
Normal file
@@ -0,0 +1,453 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html class="dark" lang="en"><head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
|
||||
<title>Backup Appliance - Monitoring & Logs</title>
|
||||
<!-- Material Symbols -->
|
||||
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap" rel="stylesheet"/>
|
||||
<!-- Google Fonts: Manrope -->
|
||||
<link href="https://fonts.googleapis.com" rel="preconnect"/>
|
||||
<link crossorigin="" href="https://fonts.gstatic.com" rel="preconnect"/>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Manrope:wght@200..800&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet"/>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap" rel="stylesheet"/>
|
||||
<!-- Tailwind CSS -->
|
||||
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
|
||||
<script id="tailwind-config">
|
||||
tailwind.config = {
|
||||
darkMode: "class",
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
"primary": "#137fec",
|
||||
"background-light": "#f6f7f8",
|
||||
"background-dark": "#111a22", /* Matching the example code background */
|
||||
"card-dark": "#1a2632", /* Slightly lighter than bg */
|
||||
"border-dark": "#324d67",
|
||||
"text-secondary": "#92adc9",
|
||||
},
|
||||
fontFamily: {
|
||||
"display": ["Manrope", "sans-serif"],
|
||||
"mono": ["JetBrains Mono", "monospace"],
|
||||
},
|
||||
borderRadius: {"DEFAULT": "0.25rem", "lg": "0.5rem", "xl": "0.75rem", "full": "9999px"},
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
/* Custom scrollbar for log viewer */
|
||||
.custom-scrollbar::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
}
|
||||
.custom-scrollbar::-webkit-scrollbar-track {
|
||||
background: #111a22;
|
||||
}
|
||||
.custom-scrollbar::-webkit-scrollbar-thumb {
|
||||
background: #324d67;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.custom-scrollbar::-webkit-scrollbar-thumb:hover {
|
||||
background: #476685;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-background-light dark:bg-background-dark text-slate-900 dark:text-white font-display overflow-hidden">
|
||||
<div class="flex h-screen w-full">
|
||||
<!-- SIDEBAR -->
|
||||
<aside class="w-64 flex flex-col border-r border-border-dark bg-background-dark flex-shrink-0 z-20">
|
||||
<div class="p-6 flex flex-col gap-1">
|
||||
<h1 class="text-white text-lg font-bold leading-normal tracking-tight">Backup Appliance</h1>
|
||||
<p class="text-text-secondary text-xs font-mono">v4.2.0-stable</p>
|
||||
</div>
|
||||
<nav class="flex-1 overflow-y-auto px-4 space-y-2">
|
||||
<a class="flex items-center gap-3 px-3 py-2 rounded-lg text-text-secondary hover:bg-card-dark hover:text-white transition-colors" href="#">
|
||||
<span class="material-symbols-outlined text-[24px]">dashboard</span>
|
||||
<span class="text-sm font-medium">Dashboard</span>
|
||||
</a>
|
||||
<a class="flex items-center gap-3 px-3 py-2 rounded-lg text-text-secondary hover:bg-card-dark hover:text-white transition-colors" href="#">
|
||||
<span class="material-symbols-outlined text-[24px]">hard_drive</span>
|
||||
<span class="text-sm font-medium">Storage</span>
|
||||
</a>
|
||||
<a class="flex items-center gap-3 px-3 py-2 rounded-lg text-text-secondary hover:bg-card-dark hover:text-white transition-colors" href="#">
|
||||
<span class="material-symbols-outlined text-[24px]">network_check</span>
|
||||
<span class="text-sm font-medium">Network</span>
|
||||
</a>
|
||||
<!-- Active State -->
|
||||
<a class="flex items-center gap-3 px-3 py-2 rounded-lg bg-[#233648] text-primary border border-primary/20" href="#">
|
||||
<span class="material-symbols-outlined text-[24px] fill-current">monitoring</span>
|
||||
<span class="text-sm font-bold">Monitor & Logs</span>
|
||||
</a>
|
||||
<a class="flex items-center gap-3 px-3 py-2 rounded-lg text-text-secondary hover:bg-card-dark hover:text-white transition-colors" href="#">
|
||||
<span class="material-symbols-outlined text-[24px]">settings</span>
|
||||
<span class="text-sm font-medium">Settings</span>
|
||||
</a>
|
||||
</nav>
|
||||
<div class="p-4 border-t border-border-dark">
|
||||
<div class="flex items-center gap-3 p-2 rounded-lg bg-card-dark border border-border-dark">
|
||||
<div class="h-8 w-8 rounded-full bg-primary flex items-center justify-center text-white font-bold text-xs">AD</div>
|
||||
<div class="flex flex-col">
|
||||
<span class="text-xs font-bold text-white">Admin User</span>
|
||||
<span class="text-[10px] text-text-secondary">admin@local</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
<!-- MAIN CONTENT -->
|
||||
<main class="flex-1 flex flex-col min-w-0 bg-background-dark overflow-hidden relative">
|
||||
<!-- HEADER -->
|
||||
<header class="flex-none px-6 py-5 border-b border-border-dark bg-background-dark/95 backdrop-blur z-10">
|
||||
<div class="flex flex-wrap justify-between items-end gap-3 max-w-[1600px] mx-auto">
|
||||
<div class="flex flex-col gap-1">
|
||||
<h2 class="text-white text-3xl font-black tracking-tight">System Monitor</h2>
|
||||
<p class="text-text-secondary text-sm">Real-time telemetry, ZFS health, and system event logs</p>
|
||||
</div>
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="flex items-center gap-2 px-3 py-2 bg-card-dark rounded-lg border border-border-dark">
|
||||
<span class="relative flex h-2 w-2">
|
||||
<span class="animate-ping absolute inline-flex h-full w-full rounded-full bg-emerald-400 opacity-75"></span>
|
||||
<span class="relative inline-flex rounded-full h-2 w-2 bg-emerald-500"></span>
|
||||
</span>
|
||||
<span class="text-xs font-medium text-emerald-400">System Healthy</span>
|
||||
</div>
|
||||
<button class="flex items-center gap-2 h-10 px-4 bg-card-dark hover:bg-[#233648] border border-border-dark text-white text-sm font-bold rounded-lg transition-colors">
|
||||
<span class="material-symbols-outlined text-[18px]">refresh</span>
|
||||
<span>Refresh: 5s</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<!-- SCROLLABLE CONTENT AREA -->
|
||||
<div class="flex-1 overflow-y-auto custom-scrollbar p-6">
|
||||
<div class="flex flex-col gap-6 max-w-[1600px] mx-auto pb-10">
|
||||
<!-- TOP STATS ROW -->
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
|
||||
<!-- CPU -->
|
||||
<div class="flex flex-col gap-2 rounded-xl p-5 border border-border-dark bg-card-dark">
|
||||
<div class="flex justify-between items-start">
|
||||
<p class="text-text-secondary text-sm font-medium">CPU Load</p>
|
||||
<span class="material-symbols-outlined text-text-secondary text-[20px]">memory</span>
|
||||
</div>
|
||||
<div class="flex items-end gap-3 mt-1">
|
||||
<p class="text-white text-3xl font-bold">12%</p>
|
||||
<span class="text-emerald-500 text-sm font-medium mb-1 flex items-center">
|
||||
<span class="material-symbols-outlined text-[16px]">trending_down</span> 2%
|
||||
</span>
|
||||
</div>
|
||||
<!-- Mini Sparkline visualization -->
|
||||
<div class="h-1.5 w-full bg-[#233648] rounded-full mt-3 overflow-hidden">
|
||||
<div class="h-full bg-primary w-[12%] rounded-full"></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- RAM -->
|
||||
<div class="flex flex-col gap-2 rounded-xl p-5 border border-border-dark bg-card-dark">
|
||||
<div class="flex justify-between items-start">
|
||||
<p class="text-text-secondary text-sm font-medium">RAM Usage</p>
|
||||
<span class="material-symbols-outlined text-text-secondary text-[20px]">memory_alt</span>
|
||||
</div>
|
||||
<div class="flex items-end gap-3 mt-1">
|
||||
<p class="text-white text-3xl font-bold">8.4 <span class="text-lg text-text-secondary font-medium">GB</span></p>
|
||||
<span class="text-text-secondary text-xs mb-2">/ 32 GB</span>
|
||||
</div>
|
||||
<div class="h-1.5 w-full bg-[#233648] rounded-full mt-3 overflow-hidden">
|
||||
<div class="h-full bg-emerald-500 w-[26%] rounded-full"></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- ZFS Health -->
|
||||
<div class="flex flex-col gap-2 rounded-xl p-5 border border-border-dark bg-card-dark">
|
||||
<div class="flex justify-between items-start">
|
||||
<p class="text-text-secondary text-sm font-medium">ZFS Pool Status</p>
|
||||
<span class="material-symbols-outlined text-emerald-500 text-[20px]">check_circle</span>
|
||||
</div>
|
||||
<div class="flex items-end gap-3 mt-1">
|
||||
<p class="text-white text-3xl font-bold">Online</p>
|
||||
<span class="text-text-secondary text-sm font-medium mb-1">No Errors</span>
|
||||
</div>
|
||||
<div class="flex gap-1 mt-3">
|
||||
<div class="h-1.5 flex-1 bg-emerald-500 rounded-l-full"></div>
|
||||
<div class="h-1.5 flex-1 bg-emerald-500"></div>
|
||||
<div class="h-1.5 flex-1 bg-emerald-500"></div>
|
||||
<div class="h-1.5 flex-1 bg-emerald-500 rounded-r-full"></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Uptime -->
|
||||
<div class="flex flex-col gap-2 rounded-xl p-5 border border-border-dark bg-card-dark">
|
||||
<div class="flex justify-between items-start">
|
||||
<p class="text-text-secondary text-sm font-medium">System Uptime</p>
|
||||
<span class="material-symbols-outlined text-text-secondary text-[20px]">schedule</span>
|
||||
</div>
|
||||
<div class="mt-1">
|
||||
<p class="text-white text-3xl font-bold">14d 2h 12m</p>
|
||||
</div>
|
||||
<p class="text-text-secondary text-xs mt-3">Last reboot: Manual Patching</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- MIDDLE SECTION: CHARTS & DISKS -->
|
||||
<div class="grid grid-cols-1 xl:grid-cols-3 gap-6">
|
||||
<!-- CHARTS COLUMN (2/3) -->
|
||||
<div class="xl:col-span-2 flex flex-col gap-6">
|
||||
<!-- Network Chart -->
|
||||
<div class="bg-card-dark border border-border-dark rounded-xl p-6 shadow-sm">
|
||||
<div class="flex justify-between items-center mb-6">
|
||||
<div>
|
||||
<h3 class="text-white text-lg font-bold">Network Throughput</h3>
|
||||
<p class="text-text-secondary text-sm">Inbound vs Outbound (eth0)</p>
|
||||
</div>
|
||||
<div class="text-right">
|
||||
<p class="text-white text-2xl font-bold leading-tight">1.2 Gbps</p>
|
||||
<p class="text-emerald-500 text-sm">Peak: 2.1 Gbps</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="h-[200px] w-full relative">
|
||||
<!-- Simulated SVG Chart -->
|
||||
<svg class="w-full h-full" preserveaspectratio="none" viewbox="0 0 1000 200">
|
||||
<defs>
|
||||
<lineargradient id="gradientPrimary" x1="0" x2="0" y1="0" y2="1">
|
||||
<stop offset="0%" stop-color="#137fec" stop-opacity="0.2"></stop>
|
||||
<stop offset="100%" stop-color="#137fec" stop-opacity="0"></stop>
|
||||
</lineargradient>
|
||||
</defs>
|
||||
<!-- Outbound Line -->
|
||||
<path d="M0,150 Q100,140 200,100 T400,120 T600,80 T800,140 T1000,100" fill="none" stroke="#92adc9" stroke-dasharray="5,5" stroke-width="2"></path>
|
||||
<!-- Inbound Area -->
|
||||
<path d="M0,120 Q150,150 300,50 T600,80 T900,40 L1000,60 V200 H0 Z" fill="url(#gradientPrimary)"></path>
|
||||
<path d="M0,120 Q150,150 300,50 T600,80 T900,40 L1000,60" fill="none" stroke="#137fec" stroke-width="3"></path>
|
||||
</svg>
|
||||
<!-- X-Axis Labels -->
|
||||
<div class="flex justify-between text-text-secondary text-xs mt-2 font-mono">
|
||||
<span>10:00</span>
|
||||
<span>10:15</span>
|
||||
<span>10:30</span>
|
||||
<span>10:45</span>
|
||||
<span>11:00</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- ZFS ARC Chart -->
|
||||
<div class="bg-card-dark border border-border-dark rounded-xl p-6 shadow-sm">
|
||||
<div class="flex justify-between items-center mb-6">
|
||||
<div>
|
||||
<h3 class="text-white text-lg font-bold">ZFS ARC Hit Ratio</h3>
|
||||
<p class="text-text-secondary text-sm">Cache efficiency</p>
|
||||
</div>
|
||||
<div class="text-right">
|
||||
<p class="text-white text-2xl font-bold leading-tight">94%</p>
|
||||
<p class="text-text-secondary text-sm">Target: >90%</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="h-[150px] w-full relative">
|
||||
<!-- Simulated SVG Chart -->
|
||||
<svg class="w-full h-full" preserveaspectratio="none" viewbox="0 0 1000 150">
|
||||
<path d="M0,40 L100,40 L105,80 L110,40 L300,35 L305,90 L310,35 L600,30 L605,100 L610,30 L1000,25" fill="none" stroke="#10b981" stroke-width="2"></path>
|
||||
</svg>
|
||||
<div class="w-full h-[1px] bg-border-dark absolute top-[20%]"></div>
|
||||
<div class="absolute top-[20%] right-0 text-xs text-text-secondary -mt-5">95%</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- DISK HEATMAP COLUMN (1/3) -->
|
||||
<div class="flex flex-col gap-6">
|
||||
<div class="bg-card-dark border border-border-dark rounded-xl p-6 h-full shadow-sm flex flex-col">
|
||||
<div class="flex justify-between items-center mb-4">
|
||||
<h3 class="text-white text-lg font-bold">Disk Health</h3>
|
||||
<span class="bg-[#233648] text-white text-xs px-2 py-1 rounded border border-border-dark">Pool 1</span>
|
||||
</div>
|
||||
<div class="grid grid-cols-4 gap-3 flex-1 content-start">
|
||||
<!-- Healthy Disks -->
|
||||
<div class="aspect-square bg-[#1a2e22] border border-emerald-800 rounded flex flex-col items-center justify-center group relative cursor-help">
|
||||
<span class="material-symbols-outlined text-emerald-500">hard_drive</span>
|
||||
<span class="text-[10px] text-emerald-500 font-mono mt-1">da0</span>
|
||||
<div class="absolute bottom-full mb-2 hidden group-hover:block bg-black text-white text-xs p-2 rounded whitespace-nowrap z-10">Serial: Z802JKA</div>
|
||||
</div>
|
||||
<div class="aspect-square bg-[#1a2e22] border border-emerald-800 rounded flex flex-col items-center justify-center">
|
||||
<span class="material-symbols-outlined text-emerald-500">hard_drive</span>
|
||||
<span class="text-[10px] text-emerald-500 font-mono mt-1">da1</span>
|
||||
</div>
|
||||
<div class="aspect-square bg-[#1a2e22] border border-emerald-800 rounded flex flex-col items-center justify-center">
|
||||
<span class="material-symbols-outlined text-emerald-500">hard_drive</span>
|
||||
<span class="text-[10px] text-emerald-500 font-mono mt-1">da2</span>
|
||||
</div>
|
||||
<div class="aspect-square bg-[#1a2e22] border border-emerald-800 rounded flex flex-col items-center justify-center">
|
||||
<span class="material-symbols-outlined text-emerald-500">hard_drive</span>
|
||||
<span class="text-[10px] text-emerald-500 font-mono mt-1">da3</span>
|
||||
</div>
|
||||
<div class="aspect-square bg-[#1a2e22] border border-emerald-800 rounded flex flex-col items-center justify-center">
|
||||
<span class="material-symbols-outlined text-emerald-500">hard_drive</span>
|
||||
<span class="text-[10px] text-emerald-500 font-mono mt-1">da4</span>
|
||||
</div>
|
||||
<!-- Warning Disk -->
|
||||
<div class="aspect-square bg-[#332a18] border border-yellow-700/50 rounded flex flex-col items-center justify-center relative">
|
||||
<span class="absolute top-1 right-1 h-2 w-2 rounded-full bg-yellow-500 animate-pulse"></span>
|
||||
<span class="material-symbols-outlined text-yellow-500">warning</span>
|
||||
<span class="text-[10px] text-yellow-500 font-mono mt-1">da5</span>
|
||||
</div>
|
||||
<!-- Healthy Disks -->
|
||||
<div class="aspect-square bg-[#1a2e22] border border-emerald-800 rounded flex flex-col items-center justify-center">
|
||||
<span class="material-symbols-outlined text-emerald-500">hard_drive</span>
|
||||
<span class="text-[10px] text-emerald-500 font-mono mt-1">da6</span>
|
||||
</div>
|
||||
<div class="aspect-square bg-[#1a2e22] border border-emerald-800 rounded flex flex-col items-center justify-center">
|
||||
<span class="material-symbols-outlined text-emerald-500">hard_drive</span>
|
||||
<span class="text-[10px] text-emerald-500 font-mono mt-1">da7</span>
|
||||
</div>
|
||||
<!-- Empty/Spare Slots -->
|
||||
<div class="aspect-square bg-[#161f29] border border-border-dark border-dashed rounded flex flex-col items-center justify-center opacity-50">
|
||||
<span class="text-[10px] text-text-secondary font-mono">Empty</span>
|
||||
</div>
|
||||
<div class="aspect-square bg-[#161f29] border border-border-dark border-dashed rounded flex flex-col items-center justify-center opacity-50">
|
||||
<span class="text-[10px] text-text-secondary font-mono">Empty</span>
|
||||
</div>
|
||||
<div class="aspect-square bg-[#161f29] border border-border-dark border-dashed rounded flex flex-col items-center justify-center opacity-50">
|
||||
<span class="text-[10px] text-text-secondary font-mono">Empty</span>
|
||||
</div>
|
||||
<div class="aspect-square bg-[#161f29] border border-border-dark border-dashed rounded flex flex-col items-center justify-center opacity-50">
|
||||
<span class="text-[10px] text-text-secondary font-mono">Empty</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-4 pt-4 border-t border-border-dark">
|
||||
<div class="flex justify-between text-sm text-text-secondary">
|
||||
<span>Total Capacity</span>
|
||||
<span class="text-white font-bold">64 TB</span>
|
||||
</div>
|
||||
<div class="w-full bg-[#233648] h-2 rounded-full mt-2 overflow-hidden">
|
||||
<div class="bg-primary h-full w-[65%]"></div>
|
||||
</div>
|
||||
<div class="flex justify-between text-xs text-text-secondary mt-1">
|
||||
<span>Used: 41.6 TB</span>
|
||||
<span>Free: 22.4 TB</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- BOTTOM SECTION: TABS & LOGS -->
|
||||
<div class="bg-card-dark border border-border-dark rounded-xl shadow-sm overflow-hidden flex flex-col h-[400px]">
|
||||
<!-- Tabs Header -->
|
||||
<div class="flex border-b border-border-dark bg-[#161f29]">
|
||||
<button class="px-6 py-4 text-sm font-bold text-primary border-b-2 border-primary bg-card-dark">
|
||||
Active Jobs <span class="ml-2 bg-primary/20 text-primary px-1.5 py-0.5 rounded text-xs">2</span>
|
||||
</button>
|
||||
<button class="px-6 py-4 text-sm font-medium text-text-secondary hover:text-white transition-colors">
|
||||
System Logs
|
||||
</button>
|
||||
<button class="px-6 py-4 text-sm font-medium text-text-secondary hover:text-white transition-colors">
|
||||
Alerts History
|
||||
</button>
|
||||
<div class="flex-1 flex justify-end items-center px-4">
|
||||
<div class="relative">
|
||||
<span class="material-symbols-outlined absolute left-2 top-1.5 text-text-secondary text-[18px]">search</span>
|
||||
<input class="bg-[#111a22] border border-border-dark rounded-md py-1 pl-8 pr-3 text-sm text-white focus:outline-none focus:border-primary w-48 transition-all" placeholder="Search logs..." type="text"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Tab Content: Active Jobs + Logs Combined View for design -->
|
||||
<div class="flex-1 overflow-hidden flex flex-col">
|
||||
<!-- Jobs Section -->
|
||||
<div class="p-0">
|
||||
<table class="w-full text-left border-collapse">
|
||||
<thead class="bg-[#1a2632] text-xs uppercase text-text-secondary font-medium sticky top-0 z-10">
|
||||
<tr>
|
||||
<th class="px-6 py-3 border-b border-border-dark">Job Name</th>
|
||||
<th class="px-6 py-3 border-b border-border-dark">Type</th>
|
||||
<th class="px-6 py-3 border-b border-border-dark w-1/3">Progress</th>
|
||||
<th class="px-6 py-3 border-b border-border-dark">Speed</th>
|
||||
<th class="px-6 py-3 border-b border-border-dark">Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="text-sm divide-y divide-border-dark">
|
||||
<!-- Active Job 1 -->
|
||||
<tr class="group hover:bg-[#233648] transition-colors">
|
||||
<td class="px-6 py-4 font-medium text-white">Daily Backup: VM-Cluster-01</td>
|
||||
<td class="px-6 py-4 text-text-secondary">Replication</td>
|
||||
<td class="px-6 py-4">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-full bg-[#111a22] rounded-full h-2 overflow-hidden">
|
||||
<div class="bg-primary h-full rounded-full w-[45%] relative overflow-hidden">
|
||||
<div class="absolute inset-0 bg-white/20 animate-[pulse_2s_infinite]"></div>
|
||||
</div>
|
||||
</div>
|
||||
<span class="text-xs font-mono text-white">45%</span>
|
||||
</div>
|
||||
<p class="text-[10px] text-text-secondary mt-1">ETA: 1h 12m</p>
|
||||
</td>
|
||||
<td class="px-6 py-4 text-text-secondary font-mono">145 MB/s</td>
|
||||
<td class="px-6 py-4">
|
||||
<span class="inline-flex items-center px-2 py-1 rounded text-xs font-medium bg-primary/20 text-primary">
|
||||
Running
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- Active Job 2 -->
|
||||
<tr class="group hover:bg-[#233648] transition-colors">
|
||||
<td class="px-6 py-4 font-medium text-white">ZFS Scrub: Pool-01</td>
|
||||
<td class="px-6 py-4 text-text-secondary">Maintenance</td>
|
||||
<td class="px-6 py-4">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-full bg-[#111a22] rounded-full h-2 overflow-hidden">
|
||||
<div class="bg-primary h-full rounded-full w-[78%] relative overflow-hidden"></div>
|
||||
</div>
|
||||
<span class="text-xs font-mono text-white">78%</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-6 py-4 text-text-secondary font-mono">1.2 GB/s</td>
|
||||
<td class="px-6 py-4">
|
||||
<span class="inline-flex items-center px-2 py-1 rounded text-xs font-medium bg-primary/20 text-primary">
|
||||
Running
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<!-- Logs Section Header (Visual Separator) -->
|
||||
<div class="px-6 py-2 bg-[#161f29] border-y border-border-dark flex items-center justify-between">
|
||||
<h4 class="text-xs uppercase text-text-secondary font-bold tracking-wider">Recent System Events</h4>
|
||||
<button class="text-xs text-primary hover:text-white transition-colors">View All Logs</button>
|
||||
</div>
|
||||
<!-- Logs Table -->
|
||||
<div class="flex-1 overflow-y-auto custom-scrollbar bg-[#111a22]">
|
||||
<table class="w-full text-left border-collapse">
|
||||
<tbody class="text-sm font-mono divide-y divide-border-dark/50">
|
||||
<tr class="group hover:bg-[#233648] transition-colors">
|
||||
<td class="px-6 py-2 text-text-secondary w-32 whitespace-nowrap">10:45:22</td>
|
||||
<td class="px-6 py-2 w-24">
|
||||
<span class="text-emerald-500">INFO</span>
|
||||
</td>
|
||||
<td class="px-6 py-2 w-32 text-white">systemd</td>
|
||||
<td class="px-6 py-2 text-text-secondary truncate max-w-lg">Started User Manager for UID 1000.</td>
|
||||
</tr>
|
||||
<tr class="group hover:bg-[#233648] transition-colors">
|
||||
<td class="px-6 py-2 text-text-secondary w-32 whitespace-nowrap">10:45:15</td>
|
||||
<td class="px-6 py-2 w-24">
|
||||
<span class="text-yellow-500">WARN</span>
|
||||
</td>
|
||||
<td class="px-6 py-2 w-32 text-white">smartd</td>
|
||||
<td class="px-6 py-2 text-text-secondary truncate max-w-lg">Device: /dev/ada5, SMART Usage Attribute: 194 Temperature_Celsius changed from 38 to 41</td>
|
||||
</tr>
|
||||
<tr class="group hover:bg-[#233648] transition-colors">
|
||||
<td class="px-6 py-2 text-text-secondary w-32 whitespace-nowrap">10:44:58</td>
|
||||
<td class="px-6 py-2 w-24">
|
||||
<span class="text-emerald-500">INFO</span>
|
||||
</td>
|
||||
<td class="px-6 py-2 w-32 text-white">kernel</td>
|
||||
<td class="px-6 py-2 text-text-secondary truncate max-w-lg">ix0: link state changed to UP</td>
|
||||
</tr>
|
||||
<tr class="group hover:bg-[#233648] transition-colors">
|
||||
<td class="px-6 py-2 text-text-secondary w-32 whitespace-nowrap">10:42:10</td>
|
||||
<td class="px-6 py-2 w-24">
|
||||
<span class="text-emerald-500">INFO</span>
|
||||
</td>
|
||||
<td class="px-6 py-2 w-32 text-white">zfs</td>
|
||||
<td class="px-6 py-2 text-text-secondary truncate max-w-lg">zfs_arc_reclaim_thread: reclaiming 157286400 bytes ...</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</body></html>
|
||||
BIN
src/web/dashboard.png
Normal file
|
After Width: | Height: | Size: 272 KiB |
401
src/web/iscsi-management-code.html
Normal file
@@ -0,0 +1,401 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html class="dark" lang="en"><head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
|
||||
<title>iSCSI Management - Backup Appliance</title>
|
||||
<link href="https://fonts.googleapis.com" rel="preconnect"/>
|
||||
<link crossorigin="" href="https://fonts.gstatic.com" rel="preconnect"/>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Manrope:wght@200..800&display=swap" rel="stylesheet"/>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap" rel="stylesheet"/>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap" rel="stylesheet"/>
|
||||
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
|
||||
<script id="tailwind-config">
|
||||
tailwind.config = {
|
||||
darkMode: "class",
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
"primary": "#137fec",
|
||||
"background-light": "#f6f7f8",
|
||||
"background-dark": "#101922",
|
||||
"card-dark": "#16202a",
|
||||
"border-dark": "#2a3b4d",
|
||||
"text-secondary": "#92adc9"
|
||||
},
|
||||
fontFamily: {
|
||||
"display": ["Manrope", "sans-serif"],
|
||||
"mono": ["Noto Sans Mono", "monospace"]
|
||||
},
|
||||
borderRadius: {"DEFAULT": "0.25rem", "lg": "0.5rem", "xl": "0.75rem", "full": "9999px"},
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
/* Custom scrollbar for webkit */
|
||||
::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
}
|
||||
::-webkit-scrollbar-track {
|
||||
background: #111a22;
|
||||
}
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: #324d67;
|
||||
border-radius: 4px;
|
||||
}
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: #46607a;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-background-light dark:bg-background-dark font-display text-white overflow-hidden">
|
||||
<div class="flex h-screen w-full overflow-hidden">
|
||||
<!-- Side Navigation -->
|
||||
<div class="w-64 flex-shrink-0 flex flex-col bg-card-dark border-r border-border-dark h-full">
|
||||
<div class="flex flex-col h-full p-4">
|
||||
<!-- Header Profile -->
|
||||
<div class="flex gap-3 items-center mb-8 px-2">
|
||||
<div class="bg-center bg-no-repeat aspect-square bg-cover rounded-full size-10 border border-border-dark" data-alt="User avatar abstract pattern" style='background-image: url("https://lh3.googleusercontent.com/aida-public/AB6AXuCJzKcwFPccDv__mDYernJcx4x-1RaTn-w6K_hxr0iUUTE3xdGfUTI_hhfzMV2mhqO9cVPahE5gX6S4QuOr3teWZ1YH0wvsh1rSWwefN2m2PQEr8-51Z9mHsAlwkXnBK_LsLe7oXWMJT-HP55P30D8y_M1GeCJIFpEPpM9dkrJCB_lG9yx6MCCQsWKySuAKZCGuFnmHPXhyLqNjCzdfwtZfbiOHdvL7f39qstx3_MgW4D0QAvnp4_q0rksyLt6Iu9grimhngf42C_M");'></div>
|
||||
<div class="flex flex-col">
|
||||
<h1 class="text-white text-base font-bold leading-normal">Backup Appliance</h1>
|
||||
<p class="text-text-secondary text-xs font-normal leading-normal">Host: backup-z01</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Navigation Links -->
|
||||
<nav class="flex flex-col gap-2 flex-1">
|
||||
<a class="flex items-center gap-3 px-3 py-2.5 rounded-lg text-text-secondary hover:bg-white/5 hover:text-white transition-colors group" href="#">
|
||||
<span class="material-symbols-outlined text-text-secondary group-hover:text-white" style="font-size: 24px;">dashboard</span>
|
||||
<span class="text-sm font-medium leading-normal">Dashboard</span>
|
||||
</a>
|
||||
<a class="flex items-center gap-3 px-3 py-2.5 rounded-lg bg-primary/20 text-white border border-primary/20" href="#">
|
||||
<span class="material-symbols-outlined text-primary" style="font-size: 24px;">hard_drive</span>
|
||||
<span class="text-sm font-bold leading-normal">Storage</span>
|
||||
</a>
|
||||
<a class="flex items-center gap-3 px-3 py-2.5 rounded-lg text-text-secondary hover:bg-white/5 hover:text-white transition-colors group" href="#">
|
||||
<span class="material-symbols-outlined text-text-secondary group-hover:text-white" style="font-size: 24px;">share</span>
|
||||
<span class="text-sm font-medium leading-normal">Network</span>
|
||||
</a>
|
||||
<a class="flex items-center gap-3 px-3 py-2.5 rounded-lg text-text-secondary hover:bg-white/5 hover:text-white transition-colors group" href="#">
|
||||
<span class="material-symbols-outlined text-text-secondary group-hover:text-white" style="font-size: 24px;">settings</span>
|
||||
<span class="text-sm font-medium leading-normal">System</span>
|
||||
</a>
|
||||
<a class="flex items-center gap-3 px-3 py-2.5 rounded-lg text-text-secondary hover:bg-white/5 hover:text-white transition-colors group" href="#">
|
||||
<span class="material-symbols-outlined text-text-secondary group-hover:text-white" style="font-size: 24px;">description</span>
|
||||
<span class="text-sm font-medium leading-normal">Logs</span>
|
||||
</a>
|
||||
<a class="flex items-center gap-3 px-3 py-2.5 rounded-lg text-text-secondary hover:bg-white/5 hover:text-white transition-colors group" href="#">
|
||||
<span class="material-symbols-outlined text-text-secondary group-hover:text-white" style="font-size: 24px;">terminal</span>
|
||||
<span class="text-sm font-medium leading-normal">Terminal</span>
|
||||
</a>
|
||||
</nav>
|
||||
<div class="mt-auto pt-4 border-t border-border-dark">
|
||||
<a class="flex items-center gap-3 px-3 py-2 text-text-secondary hover:text-white transition-colors" href="#">
|
||||
<span class="material-symbols-outlined" style="font-size: 20px;">logout</span>
|
||||
<span class="text-sm font-medium">Logout</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Main Content Area -->
|
||||
<div class="flex-1 flex flex-col h-full overflow-hidden relative">
|
||||
<!-- Scrollable Container -->
|
||||
<div class="flex-1 overflow-y-auto p-8">
|
||||
<div class="max-w-[1200px] mx-auto flex flex-col gap-6">
|
||||
<!-- Breadcrumbs -->
|
||||
<div class="flex flex-wrap items-center gap-2">
|
||||
<a class="text-text-secondary text-sm font-medium hover:text-white transition-colors" href="#">Storage</a>
|
||||
<span class="material-symbols-outlined text-text-secondary" style="font-size: 16px;">chevron_right</span>
|
||||
<span class="text-white text-sm font-medium">iSCSI Management</span>
|
||||
</div>
|
||||
<!-- Page Heading -->
|
||||
<div class="flex flex-wrap justify-between items-end gap-4">
|
||||
<div class="flex flex-col gap-2">
|
||||
<h1 class="text-white text-3xl font-extrabold leading-tight tracking-tight">iSCSI Management</h1>
|
||||
<p class="text-text-secondary text-base font-normal">Manage targets, portals, and initiator access control lists.</p>
|
||||
</div>
|
||||
<div class="flex items-center gap-3">
|
||||
<button class="flex items-center gap-2 px-4 h-10 rounded-lg bg-card-dark border border-border-dark hover:bg-white/5 text-white text-sm font-semibold transition-colors">
|
||||
<span class="material-symbols-outlined" style="font-size: 20px;">settings</span>
|
||||
<span>Global Settings</span>
|
||||
</button>
|
||||
<button class="flex items-center gap-2 px-4 h-10 rounded-lg bg-primary hover:bg-blue-600 text-white text-sm font-bold shadow-lg shadow-blue-900/20 transition-colors">
|
||||
<span class="material-symbols-outlined" style="font-size: 20px;">add</span>
|
||||
<span>Create Target</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Stats Cards -->
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||
<div class="flex flex-col gap-1 rounded-xl p-5 bg-card-dark border border-border-dark shadow-sm">
|
||||
<div class="flex items-center justify-between mb-2">
|
||||
<p class="text-text-secondary text-sm font-medium uppercase tracking-wider">Service Status</p>
|
||||
<span class="material-symbols-outlined text-green-500" style="font-size: 24px;">check_circle</span>
|
||||
</div>
|
||||
<p class="text-white text-2xl font-bold">Running</p>
|
||||
<p class="text-green-500 text-xs font-medium mt-1">Uptime: 14d 2h</p>
|
||||
</div>
|
||||
<div class="flex flex-col gap-1 rounded-xl p-5 bg-card-dark border border-border-dark shadow-sm">
|
||||
<div class="flex items-center justify-between mb-2">
|
||||
<p class="text-text-secondary text-sm font-medium uppercase tracking-wider">Port Binding</p>
|
||||
<span class="material-symbols-outlined text-text-secondary" style="font-size: 24px;">dns</span>
|
||||
</div>
|
||||
<p class="text-white text-2xl font-bold">3260</p>
|
||||
<p class="text-text-secondary text-xs font-medium mt-1">Listening on 0.0.0.0</p>
|
||||
</div>
|
||||
<div class="flex flex-col gap-1 rounded-xl p-5 bg-card-dark border border-border-dark shadow-sm">
|
||||
<div class="flex items-center justify-between mb-2">
|
||||
<p class="text-text-secondary text-sm font-medium uppercase tracking-wider">Active Sessions</p>
|
||||
<span class="material-symbols-outlined text-primary" style="font-size: 24px;">swap_horiz</span>
|
||||
</div>
|
||||
<div class="flex items-baseline gap-2">
|
||||
<p class="text-white text-2xl font-bold">12</p>
|
||||
<span class="text-green-500 text-sm font-medium flex items-center">
|
||||
<span class="material-symbols-outlined" style="font-size: 16px;">arrow_upward</span> 2
|
||||
</span>
|
||||
</div>
|
||||
<p class="text-text-secondary text-xs font-medium mt-1">Total throughput: 450 MB/s</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Tabs & Filters -->
|
||||
<div class="flex flex-col bg-card-dark border border-border-dark rounded-xl overflow-hidden shadow-sm">
|
||||
<!-- Tabs Header -->
|
||||
<div class="border-b border-border-dark px-6">
|
||||
<div class="flex gap-8">
|
||||
<button class="relative py-4 text-primary font-bold text-sm tracking-wide">
|
||||
Targets
|
||||
<div class="absolute bottom-0 left-0 w-full h-0.5 bg-primary rounded-t-full"></div>
|
||||
</button>
|
||||
<button class="relative py-4 text-text-secondary hover:text-white font-medium text-sm tracking-wide transition-colors">
|
||||
Portals
|
||||
</button>
|
||||
<button class="relative py-4 text-text-secondary hover:text-white font-medium text-sm tracking-wide transition-colors">
|
||||
Initiators
|
||||
</button>
|
||||
<button class="relative py-4 text-text-secondary hover:text-white font-medium text-sm tracking-wide transition-colors">
|
||||
Extents
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Toolbar -->
|
||||
<div class="p-4 flex items-center justify-between gap-4 border-b border-border-dark/50 bg-[#141d26]">
|
||||
<div class="relative flex-1 max-w-md">
|
||||
<span class="absolute left-3 top-1/2 -translate-y-1/2 material-symbols-outlined text-text-secondary" style="font-size: 20px;">search</span>
|
||||
<input class="w-full bg-[#0f161d] border border-border-dark rounded-lg pl-10 pr-4 py-2 text-sm text-white focus:outline-none focus:border-primary focus:ring-1 focus:ring-primary transition-all placeholder-text-secondary/50" placeholder="Search targets by alias or IQN..." type="text"/>
|
||||
</div>
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="flex items-center gap-2 px-3 py-1.5 rounded-md bg-[#0f161d] border border-border-dark">
|
||||
<span class="text-xs text-text-secondary font-medium">Filter:</span>
|
||||
<select class="bg-transparent text-xs text-white font-medium focus:outline-none cursor-pointer">
|
||||
<option>All Status</option>
|
||||
<option>Online</option>
|
||||
<option>Offline</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Targets List -->
|
||||
<div class="flex flex-col">
|
||||
<!-- Row 1: Expanded -->
|
||||
<div class="group border-b border-border-dark bg-white/[0.02]">
|
||||
<!-- Main Row -->
|
||||
<div class="flex items-center p-4 gap-4 hover:bg-white/5 transition-colors cursor-pointer border-l-4 border-primary">
|
||||
<div class="p-2 rounded-md bg-primary/10 text-primary">
|
||||
<span class="material-symbols-outlined" style="font-size: 24px;">dns</span>
|
||||
</div>
|
||||
<div class="flex-1 min-w-0 flex flex-col gap-1">
|
||||
<div class="flex items-center gap-3">
|
||||
<span class="text-white font-bold text-sm">backup-target-01</span>
|
||||
<span class="px-2 py-0.5 rounded-full bg-green-500/20 text-green-400 text-[10px] font-bold uppercase tracking-wide border border-green-500/20">Online</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 group/iqn">
|
||||
<span class="text-text-secondary font-mono text-xs truncate">iqn.2023-10.lan.backup:target01</span>
|
||||
<button class="opacity-0 group-hover/iqn:opacity-100 text-text-secondary hover:text-white transition-opacity" title="Copy IQN">
|
||||
<span class="material-symbols-outlined" style="font-size: 14px;">content_copy</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hidden md:flex items-center gap-8 mr-4">
|
||||
<div class="flex flex-col items-end">
|
||||
<span class="text-[10px] uppercase text-text-secondary font-bold tracking-wider">LUNs</span>
|
||||
<div class="flex items-center gap-1">
|
||||
<span class="material-symbols-outlined text-text-secondary" style="font-size: 16px;">hard_drive</span>
|
||||
<span class="text-white text-sm font-bold">3</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col items-end">
|
||||
<span class="text-[10px] uppercase text-text-secondary font-bold tracking-wider">Auth</span>
|
||||
<span class="text-white text-sm font-medium">CHAP</span>
|
||||
</div>
|
||||
</div>
|
||||
<button class="p-2 hover:bg-white/10 rounded-full text-text-secondary hover:text-white transition-colors">
|
||||
<span class="material-symbols-outlined" style="font-size: 24px;">expand_less</span>
|
||||
</button>
|
||||
</div>
|
||||
<!-- Expanded Detail Panel -->
|
||||
<div class="px-4 pb-4 pt-0">
|
||||
<div class="bg-[#0f161d] border border-border-dark rounded-lg p-4 grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||||
<!-- Left: LUNs -->
|
||||
<div class="flex flex-col gap-3">
|
||||
<div class="flex items-center justify-between">
|
||||
<h4 class="text-xs font-bold text-text-secondary uppercase tracking-wider">Attached LUNs</h4>
|
||||
<button class="text-primary text-xs font-bold hover:underline">+ Add LUN</button>
|
||||
</div>
|
||||
<div class="flex flex-col gap-2">
|
||||
<!-- LUN Item -->
|
||||
<div class="flex items-center justify-between p-3 rounded bg-card-dark border border-border-dark hover:border-border-dark/80 transition-colors">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="bg-blue-500/10 text-blue-400 p-1.5 rounded">
|
||||
<span class="material-symbols-outlined" style="font-size: 18px;">pie_chart</span>
|
||||
</div>
|
||||
<div class="flex flex-col">
|
||||
<span class="text-white text-xs font-bold">LUN 0</span>
|
||||
<span class="text-text-secondary text-[10px]">zvol/tank/vm-backups/win-server</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-right">
|
||||
<span class="text-white text-xs font-mono">500 GB</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- LUN Item -->
|
||||
<div class="flex items-center justify-between p-3 rounded bg-card-dark border border-border-dark hover:border-border-dark/80 transition-colors">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="bg-blue-500/10 text-blue-400 p-1.5 rounded">
|
||||
<span class="material-symbols-outlined" style="font-size: 18px;">pie_chart</span>
|
||||
</div>
|
||||
<div class="flex flex-col">
|
||||
<span class="text-white text-xs font-bold">LUN 1</span>
|
||||
<span class="text-text-secondary text-[10px]">file/mnt/tank/iso-store</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-right">
|
||||
<span class="text-white text-xs font-mono">2.5 TB</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Right: ACLs & Config -->
|
||||
<div class="flex flex-col gap-3">
|
||||
<div class="flex items-center justify-between">
|
||||
<h4 class="text-xs font-bold text-text-secondary uppercase tracking-wider">Access Control</h4>
|
||||
<button class="text-primary text-xs font-bold hover:underline">Edit Policy</button>
|
||||
</div>
|
||||
<div class="flex flex-col gap-2 h-full">
|
||||
<div class="p-3 rounded bg-card-dark border border-border-dark flex flex-col gap-2">
|
||||
<div class="flex justify-between items-center pb-2 border-b border-border-dark/50">
|
||||
<span class="text-text-secondary text-xs">Auth Method</span>
|
||||
<span class="text-white text-xs font-bold">CHAP Mutual</span>
|
||||
</div>
|
||||
<div class="flex justify-between items-center py-1">
|
||||
<span class="text-text-secondary text-xs">Initiator Group</span>
|
||||
<span class="text-primary text-xs font-bold cursor-pointer hover:underline">group-esxi-cluster-01</span>
|
||||
</div>
|
||||
<div class="mt-2 bg-[#0f161d] p-2 rounded border border-border-dark/30">
|
||||
<p class="text-[10px] text-text-secondary mb-1">Allowed Initiators (3):</p>
|
||||
<p class="text-[10px] font-mono text-white/80">iqn.1998-01.com.vmware:esx01-4a2b...</p>
|
||||
<p class="text-[10px] font-mono text-white/80">iqn.1998-01.com.vmware:esx02-9c3d...</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Action Footer in Expanded View -->
|
||||
<div class="col-span-1 lg:col-span-2 flex justify-end gap-2 mt-2 pt-3 border-t border-border-dark/50">
|
||||
<button class="px-3 py-1.5 rounded text-xs font-bold text-red-400 hover:bg-red-400/10 transition-colors">Delete Target</button>
|
||||
<button class="px-3 py-1.5 rounded text-xs font-bold text-text-secondary hover:bg-white/10 transition-colors">View Metrics</button>
|
||||
<button class="px-3 py-1.5 rounded bg-primary text-white text-xs font-bold hover:bg-blue-600 transition-colors">Save Changes</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Row 2: Collapsed -->
|
||||
<div class="group border-b border-border-dark bg-transparent">
|
||||
<div class="flex items-center p-4 gap-4 hover:bg-white/5 transition-colors cursor-pointer border-l-4 border-transparent hover:border-border-dark">
|
||||
<div class="p-2 rounded-md bg-border-dark/50 text-text-secondary">
|
||||
<span class="material-symbols-outlined" style="font-size: 24px;">dns</span>
|
||||
</div>
|
||||
<div class="flex-1 min-w-0 flex flex-col gap-1">
|
||||
<div class="flex items-center gap-3">
|
||||
<span class="text-white font-bold text-sm">archive-cold-storage</span>
|
||||
<span class="px-2 py-0.5 rounded-full bg-yellow-500/20 text-yellow-500 text-[10px] font-bold uppercase tracking-wide border border-yellow-500/20">Idle</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 group/iqn">
|
||||
<span class="text-text-secondary font-mono text-xs truncate">iqn.2023-10.lan.backup:archive002</span>
|
||||
<button class="opacity-0 group-hover/iqn:opacity-100 text-text-secondary hover:text-white transition-opacity">
|
||||
<span class="material-symbols-outlined" style="font-size: 14px;">content_copy</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hidden md:flex items-center gap-8 mr-4">
|
||||
<div class="flex flex-col items-end">
|
||||
<span class="text-[10px] uppercase text-text-secondary font-bold tracking-wider">LUNs</span>
|
||||
<div class="flex items-center gap-1">
|
||||
<span class="material-symbols-outlined text-text-secondary" style="font-size: 16px;">hard_drive</span>
|
||||
<span class="text-white text-sm font-bold">1</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col items-end">
|
||||
<span class="text-[10px] uppercase text-text-secondary font-bold tracking-wider">Auth</span>
|
||||
<span class="text-white text-sm font-medium">None</span>
|
||||
</div>
|
||||
</div>
|
||||
<button class="p-2 hover:bg-white/10 rounded-full text-text-secondary hover:text-white transition-colors">
|
||||
<span class="material-symbols-outlined" style="font-size: 24px;">expand_more</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Row 3: Collapsed -->
|
||||
<div class="group border-b border-border-dark bg-transparent">
|
||||
<div class="flex items-center p-4 gap-4 hover:bg-white/5 transition-colors cursor-pointer border-l-4 border-transparent hover:border-border-dark">
|
||||
<div class="p-2 rounded-md bg-border-dark/50 text-text-secondary">
|
||||
<span class="material-symbols-outlined" style="font-size: 24px;">dns</span>
|
||||
</div>
|
||||
<div class="flex-1 min-w-0 flex flex-col gap-1">
|
||||
<div class="flex items-center gap-3">
|
||||
<span class="text-white font-bold text-sm">dev-sandbox-target</span>
|
||||
<span class="px-2 py-0.5 rounded-full bg-red-500/20 text-red-400 text-[10px] font-bold uppercase tracking-wide border border-red-500/20">Offline</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 group/iqn">
|
||||
<span class="text-text-secondary font-mono text-xs truncate">iqn.2023-10.lan.backup:sandbox-dev</span>
|
||||
<button class="opacity-0 group-hover/iqn:opacity-100 text-text-secondary hover:text-white transition-opacity">
|
||||
<span class="material-symbols-outlined" style="font-size: 14px;">content_copy</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hidden md:flex items-center gap-8 mr-4">
|
||||
<div class="flex flex-col items-end">
|
||||
<span class="text-[10px] uppercase text-text-secondary font-bold tracking-wider">LUNs</span>
|
||||
<div class="flex items-center gap-1">
|
||||
<span class="material-symbols-outlined text-text-secondary" style="font-size: 16px;">hard_drive</span>
|
||||
<span class="text-text-secondary text-sm font-bold">0</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col items-end">
|
||||
<span class="text-[10px] uppercase text-text-secondary font-bold tracking-wider">Auth</span>
|
||||
<span class="text-white text-sm font-medium">CHAP</span>
|
||||
</div>
|
||||
</div>
|
||||
<button class="p-2 hover:bg-white/10 rounded-full text-text-secondary hover:text-white transition-colors">
|
||||
<span class="material-symbols-outlined" style="font-size: 24px;">expand_more</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Pagination / Footer of table -->
|
||||
<div class="p-4 bg-[#141d26] border-t border-border-dark flex items-center justify-between">
|
||||
<p class="text-xs text-text-secondary">Showing 1-3 of 3 targets</p>
|
||||
<div class="flex gap-2">
|
||||
<button class="p-1 rounded text-text-secondary hover:text-white hover:bg-white/10 disabled:opacity-50">
|
||||
<span class="material-symbols-outlined" style="font-size: 20px;">chevron_left</span>
|
||||
</button>
|
||||
<button class="p-1 rounded text-text-secondary hover:text-white hover:bg-white/10">
|
||||
<span class="material-symbols-outlined" style="font-size: 20px;">chevron_right</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body></html>
|
||||
BIN
src/web/iscsi-management.png
Normal file
|
After Width: | Height: | Size: 270 KiB |
470
src/web/shares-management-code.html
Normal file
@@ -0,0 +1,470 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html class="dark" lang="en"><head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
|
||||
<title>Shares Management</title>
|
||||
<!-- Fonts -->
|
||||
<link href="https://fonts.googleapis.com" rel="preconnect"/>
|
||||
<link crossorigin="" href="https://fonts.gstatic.com" rel="preconnect"/>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Manrope:wght@200..800&display=swap" rel="stylesheet"/>
|
||||
<!-- Material Symbols -->
|
||||
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap" rel="stylesheet"/>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap" rel="stylesheet"/>
|
||||
<!-- Tailwind CSS -->
|
||||
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
|
||||
<!-- Theme Configuration -->
|
||||
<script>
|
||||
tailwind.config = {
|
||||
darkMode: "class",
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
"primary": "#137fec",
|
||||
"background-light": "#f6f7f8",
|
||||
"background-dark": "#111a22", /* Matched to component background for consistency */
|
||||
"surface-dark": "#192633",
|
||||
"border-dark": "#324d67",
|
||||
"text-secondary": "#92adc9",
|
||||
},
|
||||
fontFamily: {
|
||||
"display": ["Manrope", "sans-serif"]
|
||||
},
|
||||
borderRadius: {
|
||||
"DEFAULT": "0.25rem",
|
||||
"lg": "0.5rem",
|
||||
"xl": "0.75rem",
|
||||
"full": "9999px"
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Manrope', sans-serif;
|
||||
}
|
||||
/* Custom scrollbar for webkit */
|
||||
::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
}
|
||||
::-webkit-scrollbar-track {
|
||||
background: #111a22;
|
||||
}
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: #324d67;
|
||||
border-radius: 4px;
|
||||
}
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: #137fec;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-background-light dark:bg-background-dark text-slate-900 dark:text-white overflow-hidden">
|
||||
<div class="relative flex h-screen w-full flex-row overflow-hidden">
|
||||
<!-- SideNavBar -->
|
||||
<div class="hidden lg:flex w-72 flex-col border-r border-border-dark bg-background-dark flex-shrink-0">
|
||||
<div class="flex h-full flex-col justify-between p-4">
|
||||
<div class="flex flex-col gap-4">
|
||||
<div class="flex gap-3 px-2 py-2">
|
||||
<div class="bg-center bg-no-repeat aspect-square bg-cover rounded-full size-10 bg-primary/20 flex items-center justify-center text-primary" data-alt="System Logo">
|
||||
<span class="material-symbols-outlined">dns</span>
|
||||
</div>
|
||||
<div class="flex flex-col">
|
||||
<h1 class="text-white text-base font-medium leading-normal">Backup Appliance</h1>
|
||||
<p class="text-text-secondary text-sm font-normal leading-normal">System Admin</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="h-px bg-border-dark my-1"></div>
|
||||
<div class="flex flex-col gap-2">
|
||||
<div class="flex items-center gap-3 px-3 py-2 rounded-lg hover:bg-surface-dark cursor-pointer text-text-secondary hover:text-white transition-colors">
|
||||
<span class="material-symbols-outlined">dashboard</span>
|
||||
<p class="text-sm font-medium leading-normal">Dashboard</p>
|
||||
</div>
|
||||
<div class="flex items-center gap-3 px-3 py-2 rounded-lg hover:bg-surface-dark cursor-pointer text-text-secondary hover:text-white transition-colors">
|
||||
<span class="material-symbols-outlined">hard_drive</span>
|
||||
<p class="text-sm font-medium leading-normal">Storage</p>
|
||||
</div>
|
||||
<div class="flex items-center gap-3 px-3 py-2 rounded-lg hover:bg-surface-dark cursor-pointer text-text-secondary hover:text-white transition-colors">
|
||||
<span class="material-symbols-outlined">share</span>
|
||||
<p class="text-sm font-medium leading-normal">Networking</p>
|
||||
</div>
|
||||
<!-- Active State -->
|
||||
<div class="flex items-center gap-3 px-3 py-2 rounded-lg bg-primary text-white shadow-lg shadow-primary/20">
|
||||
<span class="material-symbols-outlined">folder_shared</span>
|
||||
<p class="text-sm font-medium leading-normal">Shares</p>
|
||||
</div>
|
||||
<div class="flex items-center gap-3 px-3 py-2 rounded-lg hover:bg-surface-dark cursor-pointer text-text-secondary hover:text-white transition-colors">
|
||||
<span class="material-symbols-outlined">desktop_windows</span>
|
||||
<p class="text-sm font-medium leading-normal">Virtualization</p>
|
||||
</div>
|
||||
<div class="flex items-center gap-3 px-3 py-2 rounded-lg hover:bg-surface-dark cursor-pointer text-text-secondary hover:text-white transition-colors">
|
||||
<span class="material-symbols-outlined">settings</span>
|
||||
<p class="text-sm font-medium leading-normal">System</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button class="flex w-full cursor-pointer items-center justify-center overflow-hidden rounded-lg h-10 px-4 bg-surface-dark hover:bg-border-dark text-white text-sm font-bold leading-normal tracking-[0.015em] transition-colors gap-2">
|
||||
<span class="material-symbols-outlined text-[20px]">logout</span>
|
||||
<span class="truncate">Logout</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Main Content -->
|
||||
<div class="flex flex-1 flex-col h-full overflow-hidden relative">
|
||||
<!-- Header Section -->
|
||||
<div class="flex-shrink-0 border-b border-border-dark bg-background-dark/95 backdrop-blur z-10">
|
||||
<div class="flex flex-col gap-4 p-6 pb-4">
|
||||
<div class="flex flex-wrap justify-between gap-3 items-center">
|
||||
<div class="flex flex-col gap-1">
|
||||
<h2 class="text-white text-3xl font-black leading-tight tracking-[-0.033em]">Shares Management</h2>
|
||||
<div class="flex items-center gap-2 text-text-secondary text-sm">
|
||||
<span>Storage</span>
|
||||
<span class="material-symbols-outlined text-[14px]">chevron_right</span>
|
||||
<span>Shares</span>
|
||||
<span class="material-symbols-outlined text-[14px]">chevron_right</span>
|
||||
<span class="text-white">Overview</span>
|
||||
</div>
|
||||
</div>
|
||||
<button class="flex cursor-pointer items-center justify-center overflow-hidden rounded-lg h-10 px-4 bg-primary hover:bg-blue-600 text-white text-sm font-bold leading-normal transition-colors gap-2">
|
||||
<span class="material-symbols-outlined">add</span>
|
||||
<span class="truncate">Create New Share</span>
|
||||
</button>
|
||||
</div>
|
||||
<!-- Status Stats -->
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 mt-2">
|
||||
<div class="flex flex-col gap-1 rounded-lg p-4 border border-border-dark bg-surface-dark/50">
|
||||
<div class="flex justify-between items-start">
|
||||
<p class="text-text-secondary text-xs font-bold uppercase tracking-wider">SMB Service</p>
|
||||
<div class="size-2 rounded-full bg-emerald-500 shadow-[0_0_8px_rgba(16,185,129,0.5)]"></div>
|
||||
</div>
|
||||
<p class="text-white text-xl font-bold leading-tight">Running</p>
|
||||
<p class="text-emerald-500 text-xs mt-1">Port 445 Active</p>
|
||||
</div>
|
||||
<div class="flex flex-col gap-1 rounded-lg p-4 border border-border-dark bg-surface-dark/50">
|
||||
<div class="flex justify-between items-start">
|
||||
<p class="text-text-secondary text-xs font-bold uppercase tracking-wider">NFS Service</p>
|
||||
<div class="size-2 rounded-full bg-emerald-500 shadow-[0_0_8px_rgba(16,185,129,0.5)]"></div>
|
||||
</div>
|
||||
<p class="text-white text-xl font-bold leading-tight">Running</p>
|
||||
<p class="text-emerald-500 text-xs mt-1">Port 2049 Active</p>
|
||||
</div>
|
||||
<div class="flex flex-col gap-1 rounded-lg p-4 border border-border-dark bg-surface-dark/50">
|
||||
<div class="flex justify-between items-start">
|
||||
<p class="text-text-secondary text-xs font-bold uppercase tracking-wider">Throughput</p>
|
||||
<span class="material-symbols-outlined text-text-secondary">speed</span>
|
||||
</div>
|
||||
<p class="text-white text-xl font-bold leading-tight">565 MB/s</p>
|
||||
<p class="text-text-secondary text-xs mt-1">14 Clients Connected</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Master-Detail Layout -->
|
||||
<div class="flex flex-1 overflow-hidden">
|
||||
<!-- Left Panel: Shares List (Master) -->
|
||||
<div class="w-full lg:w-[400px] flex flex-col border-r border-border-dark bg-background-dark flex-shrink-0">
|
||||
<!-- Search -->
|
||||
<div class="p-4 border-b border-border-dark bg-background-dark sticky top-0 z-10">
|
||||
<div class="relative">
|
||||
<input class="w-full bg-surface-dark border border-border-dark rounded-lg pl-10 pr-4 py-2.5 text-sm text-white focus:outline-none focus:border-primary focus:ring-1 focus:ring-primary placeholder-text-secondary" placeholder="Filter datasets..."/>
|
||||
<span class="material-symbols-outlined absolute left-3 top-2.5 text-text-secondary">search</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- List Items -->
|
||||
<div class="flex-1 overflow-y-auto">
|
||||
<!-- Tree Item 1 -->
|
||||
<div class="group flex flex-col border-b border-border-dark/50 cursor-pointer hover:bg-surface-dark transition-colors">
|
||||
<div class="px-4 py-3 flex items-start gap-3">
|
||||
<span class="material-symbols-outlined text-text-secondary mt-1">folder_open</span>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex justify-between items-center mb-1">
|
||||
<h3 class="text-sm font-medium text-white truncate">pool/tank/home</h3>
|
||||
</div>
|
||||
<p class="text-xs text-text-secondary truncate mb-2">/mnt/tank/home</p>
|
||||
<div class="flex gap-2">
|
||||
<span class="px-1.5 py-0.5 rounded text-[10px] font-bold bg-emerald-500/10 text-emerald-500 border border-emerald-500/20">SMB</span>
|
||||
<span class="px-1.5 py-0.5 rounded text-[10px] font-bold bg-emerald-500/10 text-emerald-500 border border-emerald-500/20">NFS</span>
|
||||
</div>
|
||||
</div>
|
||||
<span class="material-symbols-outlined text-text-secondary text-[18px]">chevron_right</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Tree Item 2 (Selected) -->
|
||||
<div class="group flex flex-col border-b border-border-dark/50 cursor-pointer bg-primary/10 border-l-4 border-l-primary relative">
|
||||
<div class="px-4 py-3 flex items-start gap-3 pl-3">
|
||||
<span class="material-symbols-outlined text-primary mt-1">dns</span>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex justify-between items-center mb-1">
|
||||
<h3 class="text-sm font-bold text-white truncate">pool/tank/vm_storage</h3>
|
||||
</div>
|
||||
<p class="text-xs text-primary/80 truncate mb-2">/mnt/tank/vm_storage</p>
|
||||
<div class="flex gap-2">
|
||||
<span class="px-1.5 py-0.5 rounded text-[10px] font-bold bg-surface-dark text-text-secondary border border-border-dark">SMB</span>
|
||||
<span class="px-1.5 py-0.5 rounded text-[10px] font-bold bg-emerald-500/10 text-emerald-500 border border-emerald-500/20">NFS</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Tree Item 3 -->
|
||||
<div class="group flex flex-col border-b border-border-dark/50 cursor-pointer hover:bg-surface-dark transition-colors">
|
||||
<div class="px-4 py-3 flex items-start gap-3">
|
||||
<span class="material-symbols-outlined text-text-secondary mt-1">folder_open</span>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex justify-between items-center mb-1">
|
||||
<h3 class="text-sm font-medium text-white truncate">pool/tank/backups</h3>
|
||||
</div>
|
||||
<p class="text-xs text-text-secondary truncate mb-2">/mnt/tank/backups</p>
|
||||
<div class="flex gap-2">
|
||||
<span class="px-1.5 py-0.5 rounded text-[10px] font-bold bg-emerald-500/10 text-emerald-500 border border-emerald-500/20">SMB</span>
|
||||
</div>
|
||||
</div>
|
||||
<span class="material-symbols-outlined text-text-secondary text-[18px]">chevron_right</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Tree Item 4 -->
|
||||
<div class="group flex flex-col border-b border-border-dark/50 cursor-pointer hover:bg-surface-dark transition-colors">
|
||||
<div class="px-4 py-3 flex items-start gap-3">
|
||||
<span class="material-symbols-outlined text-text-secondary mt-1">folder_open</span>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex justify-between items-center mb-1">
|
||||
<h3 class="text-sm font-medium text-white truncate">pool/tank/media</h3>
|
||||
</div>
|
||||
<p class="text-xs text-text-secondary truncate mb-2">/mnt/tank/media</p>
|
||||
<div class="flex gap-2">
|
||||
<span class="px-1.5 py-0.5 rounded text-[10px] font-bold bg-emerald-500/10 text-emerald-500 border border-emerald-500/20">SMB</span>
|
||||
<span class="px-1.5 py-0.5 rounded text-[10px] font-bold bg-emerald-500/10 text-emerald-500 border border-emerald-500/20">NFS</span>
|
||||
</div>
|
||||
</div>
|
||||
<span class="material-symbols-outlined text-text-secondary text-[18px]">chevron_right</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-4 border-t border-border-dark bg-background-dark text-center">
|
||||
<p class="text-xs text-text-secondary">Showing 4 of 12 datasets</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Right Panel: Details (Detail) -->
|
||||
<div class="flex-1 flex flex-col h-full overflow-hidden bg-background-light dark:bg-[#0d141c]">
|
||||
<!-- Detail Header -->
|
||||
<div class="p-6 pb-0 flex flex-col gap-6">
|
||||
<div class="flex justify-between items-start">
|
||||
<div>
|
||||
<div class="flex items-center gap-3 mb-2">
|
||||
<div class="bg-primary p-2 rounded-lg text-white">
|
||||
<span class="material-symbols-outlined block">dns</span>
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="text-2xl font-bold text-white">vm_storage</h2>
|
||||
<p class="text-text-secondary text-sm font-mono">pool/tank/vm_storage</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<button class="flex items-center justify-center rounded-lg h-9 px-4 border border-border-dark text-white text-sm font-medium hover:bg-surface-dark transition-colors">
|
||||
<span class="material-symbols-outlined text-[18px] mr-2">history</span>
|
||||
Revert
|
||||
</button>
|
||||
<button class="flex items-center justify-center rounded-lg h-9 px-4 bg-primary text-white text-sm font-bold shadow-lg shadow-primary/20 hover:bg-blue-600 transition-colors">
|
||||
<span class="material-symbols-outlined text-[18px] mr-2">save</span>
|
||||
Save Changes
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Toggles Panel -->
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-4">
|
||||
<!-- SMB Toggle -->
|
||||
<div class="flex items-center justify-between p-4 rounded-xl border border-border-dark bg-surface-dark/40">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="p-2 rounded-lg bg-surface-dark text-text-secondary">
|
||||
<span class="material-symbols-outlined">folder_shared</span>
|
||||
</div>
|
||||
<div class="flex flex-col">
|
||||
<span class="text-sm font-bold text-white">SMB Protocol</span>
|
||||
<span class="text-xs text-text-secondary">Windows File Sharing</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Switch OFF -->
|
||||
<div class="relative inline-flex h-6 w-11 shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out bg-slate-700 focus:outline-none focus:ring-2 focus:ring-primary focus:ring-offset-2 focus:ring-offset-background-dark">
|
||||
<span class="sr-only">Use setting</span>
|
||||
<span class="pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out translate-x-0"></span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- NFS Toggle -->
|
||||
<div class="flex items-center justify-between p-4 rounded-xl border border-primary/50 bg-primary/5">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="p-2 rounded-lg bg-primary/20 text-primary">
|
||||
<span class="material-symbols-outlined">cloud_queue</span>
|
||||
</div>
|
||||
<div class="flex flex-col">
|
||||
<span class="text-sm font-bold text-white">NFS Protocol</span>
|
||||
<span class="text-xs text-text-secondary">Unix/Linux File Sharing</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Switch ON -->
|
||||
<div class="relative inline-flex h-6 w-11 shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out bg-primary focus:outline-none focus:ring-2 focus:ring-primary focus:ring-offset-2 focus:ring-offset-background-dark">
|
||||
<span class="sr-only">Use setting</span>
|
||||
<span class="pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out translate-x-5"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Tabs -->
|
||||
<div class="border-b border-border-dark mt-2">
|
||||
<div class="flex gap-6">
|
||||
<button class="pb-3 border-b-2 border-primary text-primary text-sm font-bold flex items-center gap-2">
|
||||
<span class="material-symbols-outlined text-[18px]">tune</span>
|
||||
Configuration
|
||||
</button>
|
||||
<button class="pb-3 border-b-2 border-transparent text-text-secondary hover:text-white text-sm font-medium flex items-center gap-2 transition-colors">
|
||||
<span class="material-symbols-outlined text-[18px]">lock</span>
|
||||
Permissions (ACL)
|
||||
</button>
|
||||
<button class="pb-3 border-b-2 border-transparent text-text-secondary hover:text-white text-sm font-medium flex items-center gap-2 transition-colors">
|
||||
<span class="material-symbols-outlined text-[18px]">lan</span>
|
||||
Connected Clients
|
||||
<span class="bg-surface-dark text-white text-[10px] px-1.5 py-0.5 rounded-full ml-1">8</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Tab Content: Configuration -->
|
||||
<div class="flex-1 overflow-y-auto p-6">
|
||||
<div class="max-w-4xl flex flex-col gap-6">
|
||||
<!-- NFS Settings Card -->
|
||||
<div class="rounded-xl border border-border-dark bg-surface-dark overflow-hidden">
|
||||
<div class="px-5 py-4 border-b border-border-dark flex justify-between items-center bg-[#1c2a39]">
|
||||
<h3 class="text-sm font-bold text-white flex items-center gap-2">
|
||||
<span class="material-symbols-outlined text-primary text-[20px]">settings_ethernet</span>
|
||||
NFS Configuration
|
||||
</h3>
|
||||
<span class="text-xs text-emerald-500 font-medium px-2 py-1 bg-emerald-500/10 rounded border border-emerald-500/20">Active</span>
|
||||
</div>
|
||||
<div class="p-5 flex flex-col gap-5">
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-5">
|
||||
<div class="flex flex-col gap-2">
|
||||
<label class="text-xs font-semibold text-text-secondary uppercase">Allowed Subnets / IPs</label>
|
||||
<div class="flex gap-2">
|
||||
<input class="flex-1 bg-background-dark border border-border-dark rounded-lg px-3 py-2 text-sm text-white focus:border-primary focus:ring-1 focus:ring-primary font-mono" type="text" value="192.168.10.0/24"/>
|
||||
<button class="p-2 bg-surface-dark hover:bg-border-dark border border-border-dark rounded-lg text-white">
|
||||
<span class="material-symbols-outlined">add</span>
|
||||
</button>
|
||||
</div>
|
||||
<p class="text-xs text-text-secondary">CIDR notation supported. Use comma for multiple entries.</p>
|
||||
</div>
|
||||
<div class="flex flex-col gap-2">
|
||||
<label class="text-xs font-semibold text-text-secondary uppercase">Map Root User</label>
|
||||
<div class="relative">
|
||||
<select class="w-full bg-background-dark border border-border-dark rounded-lg px-3 py-2 text-sm text-white focus:border-primary focus:ring-1 focus:ring-primary appearance-none">
|
||||
<option>root (User ID 0)</option>
|
||||
<option>admin</option>
|
||||
<option>nobody</option>
|
||||
</select>
|
||||
<span class="material-symbols-outlined absolute right-3 top-2.5 text-text-secondary pointer-events-none">expand_more</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-5">
|
||||
<div class="flex flex-col gap-2">
|
||||
<label class="text-xs font-semibold text-text-secondary uppercase">Security Profile</label>
|
||||
<div class="flex gap-2">
|
||||
<label class="flex items-center gap-2 px-3 py-2 rounded-lg border border-border-dark bg-background-dark cursor-pointer flex-1">
|
||||
<input checked="" class="text-primary focus:ring-primary bg-surface-dark border-border-dark" name="sec" type="radio"/>
|
||||
<span class="text-sm text-white">sys (Default)</span>
|
||||
</label>
|
||||
<label class="flex items-center gap-2 px-3 py-2 rounded-lg border border-border-dark bg-background-dark cursor-pointer flex-1">
|
||||
<input class="text-primary focus:ring-primary bg-surface-dark border-border-dark" name="sec" type="radio"/>
|
||||
<span class="text-sm text-white">krb5</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col gap-2">
|
||||
<label class="text-xs font-semibold text-text-secondary uppercase">Sync Mode</label>
|
||||
<div class="relative">
|
||||
<select class="w-full bg-background-dark border border-border-dark rounded-lg px-3 py-2 text-sm text-white focus:border-primary focus:ring-1 focus:ring-primary appearance-none">
|
||||
<option>Standard</option>
|
||||
<option>Always Sync</option>
|
||||
<option>Disabled (Async)</option>
|
||||
</select>
|
||||
<span class="material-symbols-outlined absolute right-3 top-2.5 text-text-secondary pointer-events-none">expand_more</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Advanced Attributes -->
|
||||
<div class="rounded-xl border border-border-dark bg-surface-dark overflow-hidden">
|
||||
<button class="w-full px-5 py-4 flex justify-between items-center hover:bg-[#1c2a39] transition-colors text-left">
|
||||
<h3 class="text-sm font-bold text-white flex items-center gap-2">
|
||||
<span class="material-symbols-outlined text-text-secondary text-[20px]">tune</span>
|
||||
Advanced Attributes
|
||||
</h3>
|
||||
<span class="material-symbols-outlined text-text-secondary">expand_more</span>
|
||||
</button>
|
||||
<!-- Collapsed content placeholder (imagine this expands) -->
|
||||
<div class="p-5 border-t border-border-dark flex flex-wrap gap-4">
|
||||
<label class="flex items-center gap-2 cursor-pointer">
|
||||
<input class="rounded border-border-dark bg-background-dark text-primary focus:ring-primary h-4 w-4" type="checkbox"/>
|
||||
<span class="text-sm text-white">Read Only</span>
|
||||
</label>
|
||||
<label class="flex items-center gap-2 cursor-pointer">
|
||||
<input checked="" class="rounded border-border-dark bg-background-dark text-primary focus:ring-primary h-4 w-4" type="checkbox"/>
|
||||
<span class="text-sm text-white">Enable Compression (LZ4)</span>
|
||||
</label>
|
||||
<label class="flex items-center gap-2 cursor-pointer">
|
||||
<input class="rounded border-border-dark bg-background-dark text-primary focus:ring-primary h-4 w-4" type="checkbox"/>
|
||||
<span class="text-sm text-white">Enable Deduplication</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Connected Clients Preview -->
|
||||
<div class="flex flex-col gap-3">
|
||||
<div class="flex justify-between items-end">
|
||||
<h3 class="text-base font-bold text-white">Top Active Clients</h3>
|
||||
<a class="text-sm text-primary hover:text-blue-400 font-medium" href="#">View all clients</a>
|
||||
</div>
|
||||
<div class="rounded-lg border border-border-dark overflow-hidden bg-surface-dark">
|
||||
<table class="w-full text-sm text-left">
|
||||
<thead class="bg-background-dark text-text-secondary font-medium border-b border-border-dark">
|
||||
<tr>
|
||||
<th class="px-4 py-3">IP Address</th>
|
||||
<th class="px-4 py-3">User</th>
|
||||
<th class="px-4 py-3">Protocol</th>
|
||||
<th class="px-4 py-3 text-right">Throughput</th>
|
||||
<th class="px-4 py-3 text-right">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="text-white divide-y divide-border-dark">
|
||||
<tr>
|
||||
<td class="px-4 py-3 font-mono">192.168.10.105</td>
|
||||
<td class="px-4 py-3">esxi-host-01</td>
|
||||
<td class="px-4 py-3"><span class="bg-primary/20 text-primary px-1.5 py-0.5 rounded text-xs font-bold">NFS</span></td>
|
||||
<td class="px-4 py-3 text-right font-mono text-text-secondary">420 MB/s</td>
|
||||
<td class="px-4 py-3 text-right">
|
||||
<button class="text-text-secondary hover:text-red-400" title="Disconnect">
|
||||
<span class="material-symbols-outlined text-[18px]">block</span>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="px-4 py-3 font-mono">192.168.10.106</td>
|
||||
<td class="px-4 py-3">esxi-host-02</td>
|
||||
<td class="px-4 py-3"><span class="bg-primary/20 text-primary px-1.5 py-0.5 rounded text-xs font-bold">NFS</span></td>
|
||||
<td class="px-4 py-3 text-right font-mono text-text-secondary">105 MB/s</td>
|
||||
<td class="px-4 py-3 text-right">
|
||||
<button class="text-text-secondary hover:text-red-400" title="Disconnect">
|
||||
<span class="material-symbols-outlined text-[18px]">block</span>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body></html>
|
||||
BIN
src/web/shares-management.png
Normal file
|
After Width: | Height: | Size: 310 KiB |
454
src/web/snapshots-management-code.html
Normal file
@@ -0,0 +1,454 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html class="dark" lang="en"><head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
|
||||
<title>Data Protection - Snapshot Manager</title>
|
||||
<!-- Fonts -->
|
||||
<link href="https://fonts.googleapis.com" rel="preconnect"/>
|
||||
<link crossorigin="" href="https://fonts.gstatic.com" rel="preconnect"/>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;700&display=swap" rel="stylesheet"/>
|
||||
<!-- Icons -->
|
||||
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap" rel="stylesheet"/>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap" rel="stylesheet"/>
|
||||
<!-- Tailwind CSS -->
|
||||
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
|
||||
<!-- Theme Configuration -->
|
||||
<script id="tailwind-config">
|
||||
tailwind.config = {
|
||||
darkMode: "class",
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
"primary": "#137fec",
|
||||
"background-light": "#f6f7f8",
|
||||
"background-dark": "#101922",
|
||||
"surface-dark": "#16202a",
|
||||
"border-dark": "#324d67",
|
||||
"text-secondary": "#92adc9"
|
||||
},
|
||||
fontFamily: {
|
||||
"display": ["Manrope", "sans-serif"]
|
||||
},
|
||||
borderRadius: {
|
||||
"DEFAULT": "0.25rem",
|
||||
"lg": "0.5rem",
|
||||
"xl": "0.75rem",
|
||||
"full": "9999px"
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
/* Custom scrollbar for webkit browsers */
|
||||
::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
}
|
||||
::-webkit-scrollbar-track {
|
||||
background: #111a22;
|
||||
}
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: #324d67;
|
||||
border-radius: 4px;
|
||||
}
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: #4a6b8a;
|
||||
}
|
||||
|
||||
.material-symbols-outlined {
|
||||
font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 24;
|
||||
}
|
||||
.icon-filled {
|
||||
font-variation-settings: 'FILL' 1, 'wght' 400, 'GRAD' 0, 'opsz' 24;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-background-light dark:bg-background-dark text-white font-display overflow-hidden h-screen flex">
|
||||
<!-- Global Navigation Sidebar -->
|
||||
<aside class="w-64 bg-[#111a22] border-r border-border-dark flex flex-col h-full flex-shrink-0 z-20">
|
||||
<div class="flex items-center gap-3 p-4 border-b border-border-dark">
|
||||
<div class="bg-center bg-no-repeat bg-cover rounded-full h-10 w-10 shrink-0" data-alt="Abstract blue tech logo gradient" style='background-image: url("https://lh3.googleusercontent.com/aida-public/AB6AXuB3AJm6_-45EJVrywcu9Bfe2jgJC8qjm02SwZMeiJvN8_sR9UYfiwtNYebUlJFuP2X_D9_ppCQPe6xK-FAVaH4q8ObtjuWBNX73GsveMYbuBDyGctR1Fhu5jPiN_OcSBT4OAGPPDTBegjCgyZ2RTkV9GLzyiNeTZluUshePm7h1Rn4fdv1ZgXSWL7LAorhKLC6mrw6TdcdJfeNTBNzOs_8cvJHY_Vu-0Vi8xu_lWm2kjCjtSbGDRJRmxs1hzNOG5xQTNy2OfGm7luM");'></div>
|
||||
<div class="flex flex-col overflow-hidden">
|
||||
<h1 class="text-white text-base font-bold leading-normal truncate">Backup Appliance</h1>
|
||||
<p class="text-text-secondary text-xs font-normal leading-normal truncate">v24.04.1-SCALE</p>
|
||||
</div>
|
||||
</div>
|
||||
<nav class="flex flex-col gap-2 p-3 overflow-y-auto flex-1">
|
||||
<a class="flex items-center gap-3 px-3 py-2 rounded-lg hover:bg-white/5 transition-colors group" href="#">
|
||||
<span class="material-symbols-outlined text-text-secondary group-hover:text-white">dashboard</span>
|
||||
<p class="text-text-secondary group-hover:text-white text-sm font-medium">Dashboard</p>
|
||||
</a>
|
||||
<a class="flex items-center gap-3 px-3 py-2 rounded-lg hover:bg-white/5 transition-colors group" href="#">
|
||||
<span class="material-symbols-outlined text-text-secondary group-hover:text-white">hard_drive</span>
|
||||
<p class="text-text-secondary group-hover:text-white text-sm font-medium">Storage</p>
|
||||
</a>
|
||||
<a class="flex items-center gap-3 px-3 py-2 rounded-lg hover:bg-white/5 transition-colors group" href="#">
|
||||
<span class="material-symbols-outlined text-text-secondary group-hover:text-white">network_check</span>
|
||||
<p class="text-text-secondary group-hover:text-white text-sm font-medium">Network</p>
|
||||
</a>
|
||||
<!-- Active State -->
|
||||
<a class="flex items-center gap-3 px-3 py-2 rounded-lg bg-[#233648] text-white" href="#">
|
||||
<span class="material-symbols-outlined icon-filled text-primary">shield</span>
|
||||
<p class="text-white text-sm font-medium">Data Protection</p>
|
||||
</a>
|
||||
<a class="flex items-center gap-3 px-3 py-2 rounded-lg hover:bg-white/5 transition-colors group" href="#">
|
||||
<span class="material-symbols-outlined text-text-secondary group-hover:text-white">settings</span>
|
||||
<p class="text-text-secondary group-hover:text-white text-sm font-medium">System</p>
|
||||
</a>
|
||||
<a class="flex items-center gap-3 px-3 py-2 rounded-lg hover:bg-white/5 transition-colors group mt-auto" href="#">
|
||||
<span class="material-symbols-outlined text-text-secondary group-hover:text-white">logout</span>
|
||||
<p class="text-text-secondary group-hover:text-white text-sm font-medium">Logout</p>
|
||||
</a>
|
||||
</nav>
|
||||
</aside>
|
||||
<!-- Main Content Layout (Tree + Details) -->
|
||||
<div class="flex flex-1 h-full overflow-hidden">
|
||||
<!-- Dataset Tree View (Secondary Sidebar) -->
|
||||
<aside class="w-72 bg-surface-dark border-r border-border-dark flex flex-col h-full overflow-hidden hidden md:flex">
|
||||
<div class="p-4 border-b border-border-dark flex justify-between items-center">
|
||||
<h3 class="text-sm font-bold text-white uppercase tracking-wider">Datasets</h3>
|
||||
<button class="text-text-secondary hover:text-white">
|
||||
<span class="material-symbols-outlined text-lg">filter_list</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="flex-1 overflow-y-auto p-2">
|
||||
<!-- Tree Item: Root -->
|
||||
<div class="flex flex-col gap-1">
|
||||
<div class="flex items-center gap-2 px-2 py-1.5 rounded bg-primary/20 text-white cursor-pointer">
|
||||
<span class="material-symbols-outlined text-sm text-text-secondary">expand_more</span>
|
||||
<span class="material-symbols-outlined text-primary text-lg">dns</span>
|
||||
<span class="text-sm font-medium truncate">tank</span>
|
||||
</div>
|
||||
<!-- Children -->
|
||||
<div class="pl-4 flex flex-col gap-1 border-l border-border-dark ml-3 my-1">
|
||||
<!-- Item 1 (Active) -->
|
||||
<div class="flex items-center gap-2 px-2 py-1.5 rounded bg-[#324d67] text-white cursor-pointer relative">
|
||||
<div class="absolute w-1 h-full left-0 bg-primary rounded-l"></div>
|
||||
<span class="material-symbols-outlined text-sm text-text-secondary">expand_more</span>
|
||||
<span class="material-symbols-outlined text-yellow-500 text-lg">folder</span>
|
||||
<span class="text-sm font-medium truncate">data</span>
|
||||
<!-- Usage bar mini -->
|
||||
<div class="ml-auto w-12 h-1 bg-black/40 rounded-full overflow-hidden">
|
||||
<div class="h-full bg-green-500 w-[65%]"></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Nested Child -->
|
||||
<div class="pl-4 flex flex-col gap-1 border-l border-border-dark ml-3 my-1">
|
||||
<div class="flex items-center gap-2 px-2 py-1.5 rounded hover:bg-white/5 text-text-secondary hover:text-white cursor-pointer transition-colors">
|
||||
<span class="w-4"></span>
|
||||
<span class="material-symbols-outlined text-lg">folder</span>
|
||||
<span class="text-sm truncate">projects</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 px-2 py-1.5 rounded hover:bg-white/5 text-text-secondary hover:text-white cursor-pointer transition-colors">
|
||||
<span class="w-4"></span>
|
||||
<span class="material-symbols-outlined text-lg">folder</span>
|
||||
<span class="text-sm truncate">archives</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Item 2 -->
|
||||
<div class="flex items-center gap-2 px-2 py-1.5 rounded hover:bg-white/5 text-text-secondary hover:text-white cursor-pointer transition-colors">
|
||||
<span class="material-symbols-outlined text-sm text-text-secondary">chevron_right</span>
|
||||
<span class="material-symbols-outlined text-blue-400 text-lg">featured_play_list</span>
|
||||
<span class="text-sm font-medium truncate">vms-storage</span>
|
||||
</div>
|
||||
<!-- Item 3 -->
|
||||
<div class="flex items-center gap-2 px-2 py-1.5 rounded hover:bg-white/5 text-text-secondary hover:text-white cursor-pointer transition-colors">
|
||||
<span class="material-symbols-outlined text-sm text-text-secondary">chevron_right</span>
|
||||
<span class="material-symbols-outlined text-purple-400 text-lg">storage</span>
|
||||
<span class="text-sm font-medium truncate">iscsi-target-01</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Bottom Action in Sidebar -->
|
||||
<div class="p-3 border-t border-border-dark">
|
||||
<button class="w-full py-2 px-3 rounded border border-border-dark text-sm text-text-secondary hover:text-white hover:bg-white/5 flex items-center justify-center gap-2 transition-colors">
|
||||
<span class="material-symbols-outlined text-lg">add</span>
|
||||
Add Dataset
|
||||
</button>
|
||||
</div>
|
||||
</aside>
|
||||
<!-- Main Action Area -->
|
||||
<main class="flex-1 flex flex-col h-full bg-background-dark overflow-y-auto relative">
|
||||
<!-- Breadcrumbs -->
|
||||
<div class="px-8 pt-6 pb-2">
|
||||
<div class="flex flex-wrap gap-2 items-center">
|
||||
<a class="text-text-secondary text-sm font-medium hover:text-primary transition-colors flex items-center gap-1" href="#">
|
||||
<span class="material-symbols-outlined text-lg">hard_drive</span> Storage
|
||||
</a>
|
||||
<span class="text-text-secondary text-sm">/</span>
|
||||
<a class="text-text-secondary text-sm font-medium hover:text-primary transition-colors" href="#">ZFS Pools</a>
|
||||
<span class="text-text-secondary text-sm">/</span>
|
||||
<span class="text-white text-sm font-medium px-2 py-0.5 rounded bg-surface-dark border border-border-dark">tank/data</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Page Header -->
|
||||
<div class="px-8 py-4 flex flex-wrap justify-between gap-6 items-end">
|
||||
<div class="flex flex-col gap-2 max-w-2xl">
|
||||
<h1 class="text-white tracking-tight text-3xl font-bold">Snapshot Manager</h1>
|
||||
<p class="text-text-secondary text-sm leading-relaxed">Manage automated snapshots, retention policies, and replication tasks for the <span class="text-white font-mono bg-surface-dark px-1 rounded">tank/data</span> dataset.</p>
|
||||
</div>
|
||||
<div class="flex gap-3">
|
||||
<button class="flex items-center gap-2 px-4 py-2 bg-surface-dark border border-border-dark rounded-lg text-white text-sm font-medium hover:bg-[#1c2a35] transition-colors">
|
||||
<span class="material-symbols-outlined text-lg">settings</span>
|
||||
Settings
|
||||
</button>
|
||||
<button class="flex items-center gap-2 px-4 py-2 bg-primary text-white rounded-lg text-sm font-medium hover:bg-blue-600 transition-colors shadow-lg shadow-blue-900/20">
|
||||
<span class="material-symbols-outlined text-lg">add_a_photo</span>
|
||||
Create Snapshot
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Stats Cards -->
|
||||
<div class="px-8 pb-6">
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
|
||||
<!-- Stat 1 -->
|
||||
<div class="flex flex-col gap-1 p-5 rounded-xl border border-border-dark bg-surface-dark/50 hover:bg-surface-dark transition-colors">
|
||||
<div class="flex justify-between items-start">
|
||||
<p class="text-text-secondary text-xs font-bold uppercase tracking-wider">Total Snapshots</p>
|
||||
<span class="material-symbols-outlined text-primary text-xl">photo_library</span>
|
||||
</div>
|
||||
<p class="text-white text-2xl font-bold mt-1">1,245</p>
|
||||
<div class="flex items-center gap-1 mt-1 text-green-400 text-xs">
|
||||
<span class="material-symbols-outlined text-sm">trending_up</span>
|
||||
<span>+12 today</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Stat 2 -->
|
||||
<div class="flex flex-col gap-1 p-5 rounded-xl border border-border-dark bg-surface-dark/50 hover:bg-surface-dark transition-colors">
|
||||
<div class="flex justify-between items-start">
|
||||
<p class="text-text-secondary text-xs font-bold uppercase tracking-wider">Space Used</p>
|
||||
<span class="material-symbols-outlined text-yellow-500 text-xl">pie_chart</span>
|
||||
</div>
|
||||
<p class="text-white text-2xl font-bold mt-1">2.4 TB</p>
|
||||
<div class="w-full bg-[#111a22] rounded-full h-1.5 mt-2">
|
||||
<div class="bg-yellow-500 h-1.5 rounded-full" style="width: 45%"></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Stat 3 -->
|
||||
<div class="flex flex-col gap-1 p-5 rounded-xl border border-border-dark bg-surface-dark/50 hover:bg-surface-dark transition-colors">
|
||||
<div class="flex justify-between items-start">
|
||||
<p class="text-text-secondary text-xs font-bold uppercase tracking-wider">Reclaimable</p>
|
||||
<span class="material-symbols-outlined text-green-400 text-xl">recycling</span>
|
||||
</div>
|
||||
<p class="text-white text-2xl font-bold mt-1">420 GB</p>
|
||||
<p class="text-text-secondary text-xs mt-1">from expired policies</p>
|
||||
</div>
|
||||
<!-- Stat 4 -->
|
||||
<div class="flex flex-col gap-1 p-5 rounded-xl border border-border-dark bg-surface-dark/50 hover:bg-surface-dark transition-colors">
|
||||
<div class="flex justify-between items-start">
|
||||
<p class="text-text-secondary text-xs font-bold uppercase tracking-wider">Next Scheduled</p>
|
||||
<span class="material-symbols-outlined text-purple-400 text-xl">schedule</span>
|
||||
</div>
|
||||
<p class="text-white text-2xl font-bold mt-1">14:00</p>
|
||||
<p class="text-text-secondary text-xs mt-1">Today (Auto-Daily)</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Tabs -->
|
||||
<div class="px-8 border-b border-border-dark flex gap-8">
|
||||
<button class="pb-3 text-sm font-medium text-primary border-b-2 border-primary">Snapshots List</button>
|
||||
<button class="pb-3 text-sm font-medium text-text-secondary hover:text-white transition-colors">Schedule & Policies</button>
|
||||
<button class="pb-3 text-sm font-medium text-text-secondary hover:text-white transition-colors">Replication Tasks</button>
|
||||
</div>
|
||||
<!-- Toolbar & Filters -->
|
||||
<div class="px-8 py-4 flex flex-wrap gap-4 items-center justify-between bg-surface-dark/30">
|
||||
<div class="relative flex-1 min-w-[200px] max-w-md">
|
||||
<span class="absolute left-3 top-1/2 -translate-y-1/2 material-symbols-outlined text-text-secondary">search</span>
|
||||
<input class="w-full bg-[#111a22] border border-border-dark text-white text-sm rounded-lg pl-10 pr-4 py-2 focus:ring-1 focus:ring-primary focus:border-primary outline-none transition-all placeholder:text-text-secondary/50" placeholder="Filter snapshots..." type="text"/>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<button class="px-3 py-2 text-sm text-text-secondary hover:text-white border border-border-dark rounded bg-[#111a22] hover:bg-[#1c2a35] flex items-center gap-2">
|
||||
<span class="material-symbols-outlined text-lg">filter_alt</span> Filter
|
||||
</button>
|
||||
<button class="px-3 py-2 text-sm text-text-secondary hover:text-white border border-border-dark rounded bg-[#111a22] hover:bg-[#1c2a35] flex items-center gap-2">
|
||||
<span class="material-symbols-outlined text-lg">calendar_month</span> Date Range
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Data Table -->
|
||||
<div class="flex-1 px-8 pb-8 overflow-hidden flex flex-col">
|
||||
<div class="flex-1 overflow-auto rounded-lg border border-border-dark bg-[#111a22]">
|
||||
<table class="w-full text-left border-collapse">
|
||||
<thead class="sticky top-0 z-10 bg-surface-dark text-xs font-semibold text-text-secondary uppercase tracking-wider">
|
||||
<tr>
|
||||
<th class="p-4 border-b border-border-dark w-10">
|
||||
<input class="rounded border-border-dark bg-[#111a22] text-primary focus:ring-0 focus:ring-offset-0" type="checkbox"/>
|
||||
</th>
|
||||
<th class="p-4 border-b border-border-dark">Snapshot Name</th>
|
||||
<th class="p-4 border-b border-border-dark">Created</th>
|
||||
<th class="p-4 border-b border-border-dark text-right">Used</th>
|
||||
<th class="p-4 border-b border-border-dark text-right">Referenced</th>
|
||||
<th class="p-4 border-b border-border-dark">Policy</th>
|
||||
<th class="p-4 border-b border-border-dark text-right">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="text-sm divide-y divide-border-dark">
|
||||
<!-- Row 1 -->
|
||||
<tr class="hover:bg-white/5 transition-colors group">
|
||||
<td class="p-4">
|
||||
<input class="rounded border-border-dark bg-[#111a22] text-primary focus:ring-0 focus:ring-offset-0 opacity-50 group-hover:opacity-100" type="checkbox"/>
|
||||
</td>
|
||||
<td class="p-4">
|
||||
<div class="flex items-center gap-3">
|
||||
<span class="material-symbols-outlined text-text-secondary">camera_alt</span>
|
||||
<span class="font-medium text-white font-mono">auto-2023-10-27-1400</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="p-4 text-text-secondary">Oct 27, 2023 14:00</td>
|
||||
<td class="p-4 text-right text-white font-mono">1.2 GB</td>
|
||||
<td class="p-4 text-right text-text-secondary font-mono">14.5 TB</td>
|
||||
<td class="p-4">
|
||||
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-blue-500/10 text-blue-400 border border-blue-500/20">
|
||||
Hourly-Keep-24
|
||||
</span>
|
||||
</td>
|
||||
<td class="p-4 text-right">
|
||||
<button class="text-text-secondary hover:text-white p-1 rounded hover:bg-white/10">
|
||||
<span class="material-symbols-outlined text-lg">more_vert</span>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- Row 2 -->
|
||||
<tr class="hover:bg-white/5 transition-colors group">
|
||||
<td class="p-4">
|
||||
<input class="rounded border-border-dark bg-[#111a22] text-primary focus:ring-0 focus:ring-offset-0 opacity-50 group-hover:opacity-100" type="checkbox"/>
|
||||
</td>
|
||||
<td class="p-4">
|
||||
<div class="flex items-center gap-3">
|
||||
<span class="material-symbols-outlined text-text-secondary">camera_alt</span>
|
||||
<span class="font-medium text-white font-mono">auto-2023-10-27-1300</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="p-4 text-text-secondary">Oct 27, 2023 13:00</td>
|
||||
<td class="p-4 text-right text-white font-mono">850 MB</td>
|
||||
<td class="p-4 text-right text-text-secondary font-mono">14.5 TB</td>
|
||||
<td class="p-4">
|
||||
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-blue-500/10 text-blue-400 border border-blue-500/20">
|
||||
Hourly-Keep-24
|
||||
</span>
|
||||
</td>
|
||||
<td class="p-4 text-right">
|
||||
<button class="text-text-secondary hover:text-white p-1 rounded hover:bg-white/10">
|
||||
<span class="material-symbols-outlined text-lg">more_vert</span>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- Row 3: Manual Snapshot -->
|
||||
<tr class="hover:bg-white/5 transition-colors group">
|
||||
<td class="p-4">
|
||||
<input class="rounded border-border-dark bg-[#111a22] text-primary focus:ring-0 focus:ring-offset-0 opacity-50 group-hover:opacity-100" type="checkbox"/>
|
||||
</td>
|
||||
<td class="p-4">
|
||||
<div class="flex items-center gap-3">
|
||||
<span class="material-symbols-outlined text-primary">person</span>
|
||||
<span class="font-medium text-white font-mono">pre-upgrade-backup</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="p-4 text-text-secondary">Oct 27, 2023 12:45</td>
|
||||
<td class="p-4 text-right text-white font-mono">4.1 GB</td>
|
||||
<td class="p-4 text-right text-text-secondary font-mono">14.5 TB</td>
|
||||
<td class="p-4">
|
||||
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-purple-500/10 text-purple-400 border border-purple-500/20">
|
||||
Manual
|
||||
</span>
|
||||
</td>
|
||||
<td class="p-4 text-right">
|
||||
<div class="flex justify-end gap-2 opacity-0 group-hover:opacity-100 transition-opacity">
|
||||
<button class="text-text-secondary hover:text-white p-1 rounded hover:bg-white/10" title="Clone">
|
||||
<span class="material-symbols-outlined text-lg">content_copy</span>
|
||||
</button>
|
||||
<button class="text-text-secondary hover:text-red-400 p-1 rounded hover:bg-red-400/10" title="Rollback">
|
||||
<span class="material-symbols-outlined text-lg">history</span>
|
||||
</button>
|
||||
<button class="text-text-secondary hover:text-white p-1 rounded hover:bg-white/10">
|
||||
<span class="material-symbols-outlined text-lg">more_vert</span>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- Row 4 -->
|
||||
<tr class="hover:bg-white/5 transition-colors group">
|
||||
<td class="p-4">
|
||||
<input class="rounded border-border-dark bg-[#111a22] text-primary focus:ring-0 focus:ring-offset-0 opacity-50 group-hover:opacity-100" type="checkbox"/>
|
||||
</td>
|
||||
<td class="p-4">
|
||||
<div class="flex items-center gap-3">
|
||||
<span class="material-symbols-outlined text-text-secondary">camera_alt</span>
|
||||
<span class="font-medium text-white font-mono">auto-2023-10-27-1200</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="p-4 text-text-secondary">Oct 27, 2023 12:00</td>
|
||||
<td class="p-4 text-right text-white font-mono">920 MB</td>
|
||||
<td class="p-4 text-right text-text-secondary font-mono">14.5 TB</td>
|
||||
<td class="p-4">
|
||||
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-blue-500/10 text-blue-400 border border-blue-500/20">
|
||||
Hourly-Keep-24
|
||||
</span>
|
||||
</td>
|
||||
<td class="p-4 text-right">
|
||||
<button class="text-text-secondary hover:text-white p-1 rounded hover:bg-white/10">
|
||||
<span class="material-symbols-outlined text-lg">more_vert</span>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- Row 5: Locked -->
|
||||
<tr class="hover:bg-white/5 transition-colors group">
|
||||
<td class="p-4">
|
||||
<input class="rounded border-border-dark bg-[#111a22] text-text-secondary cursor-not-allowed opacity-50" disabled="" type="checkbox"/>
|
||||
</td>
|
||||
<td class="p-4">
|
||||
<div class="flex items-center gap-3">
|
||||
<span class="material-symbols-outlined text-yellow-500">lock</span>
|
||||
<span class="font-medium text-white font-mono">daily-2023-10-26</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="p-4 text-text-secondary">Oct 26, 2023 00:00</td>
|
||||
<td class="p-4 text-right text-white font-mono">12.5 GB</td>
|
||||
<td class="p-4 text-right text-text-secondary font-mono">14.4 TB</td>
|
||||
<td class="p-4">
|
||||
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-green-500/10 text-green-400 border border-green-500/20">
|
||||
Daily-Keep-30
|
||||
</span>
|
||||
</td>
|
||||
<td class="p-4 text-right">
|
||||
<button class="text-text-secondary hover:text-white p-1 rounded hover:bg-white/10">
|
||||
<span class="material-symbols-outlined text-lg">more_vert</span>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<!-- Pagination -->
|
||||
<div class="flex justify-between items-center py-4 border-t border-border-dark mt-2">
|
||||
<p class="text-xs text-text-secondary">Showing <span class="text-white font-medium">1-5</span> of <span class="text-white font-medium">1,245</span> snapshots</p>
|
||||
<div class="flex gap-2">
|
||||
<button class="px-3 py-1 text-xs font-medium text-text-secondary hover:text-white border border-border-dark rounded bg-surface-dark hover:bg-[#1c2a35] disabled:opacity-50">Previous</button>
|
||||
<button class="px-3 py-1 text-xs font-medium text-text-secondary hover:text-white border border-border-dark rounded bg-surface-dark hover:bg-[#1c2a35]">Next</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Floating Feedback/Status Toast (Bottom Right) -->
|
||||
<div class="absolute bottom-6 right-8 max-w-sm w-full animate-pulse">
|
||||
<div class="bg-surface-dark border border-border-dark rounded-lg shadow-2xl p-4 flex items-start gap-3">
|
||||
<div class="p-1 rounded-full bg-blue-500/20 text-blue-400 shrink-0">
|
||||
<span class="material-symbols-outlined text-xl">sync</span>
|
||||
</div>
|
||||
<div class="flex flex-col gap-1">
|
||||
<p class="text-sm font-medium text-white">Replication in progress</p>
|
||||
<p class="text-xs text-text-secondary">Sending 'auto-2023-10-27-1400' to backup-server (45%)</p>
|
||||
<div class="w-full bg-[#111a22] h-1 rounded-full mt-1">
|
||||
<div class="bg-blue-500 h-1 rounded-full w-[45%]"></div>
|
||||
</div>
|
||||
</div>
|
||||
<button class="text-text-secondary hover:text-white ml-auto">
|
||||
<span class="material-symbols-outlined text-sm">close</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</body></html>
|
||||
BIN
src/web/snapshots-management.png
Normal file
|
After Width: | Height: | Size: 312 KiB |
569
src/web/storage-management-code.html
Normal file
@@ -0,0 +1,569 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html class="dark" lang="en"><head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
|
||||
<title>Storage Management - Cockpit</title>
|
||||
<!-- Fonts -->
|
||||
<link href="https://fonts.googleapis.com" rel="preconnect"/>
|
||||
<link crossorigin="" href="https://fonts.gstatic.com" rel="preconnect"/>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Manrope:wght@200..800&display=swap" rel="stylesheet"/>
|
||||
<!-- Material Icons -->
|
||||
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap" rel="stylesheet"/>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap" rel="stylesheet"/>
|
||||
<!-- Tailwind CSS -->
|
||||
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
|
||||
<!-- Theme Configuration -->
|
||||
<script id="tailwind-config">
|
||||
tailwind.config = {
|
||||
darkMode: "class",
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
"primary": "#137fec",
|
||||
"background-light": "#f6f7f8",
|
||||
"background-dark": "#101922",
|
||||
"surface-dark": "#1a242f",
|
||||
"surface-darker": "#111a22",
|
||||
"border-dark": "#324d67",
|
||||
"text-secondary": "#92adc9",
|
||||
},
|
||||
fontFamily: {
|
||||
"display": ["Manrope", "sans-serif"]
|
||||
},
|
||||
borderRadius: {"DEFAULT": "0.375rem", "lg": "0.5rem", "xl": "0.75rem", "full": "9999px"},
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body class="bg-background-light dark:bg-background-dark font-display text-slate-900 dark:text-white antialiased overflow-hidden">
|
||||
<div class="flex h-screen w-full overflow-hidden">
|
||||
<!-- Sidebar -->
|
||||
<aside class="w-64 flex-shrink-0 border-r border-slate-200 dark:border-border-dark bg-white dark:bg-surface-darker flex flex-col justify-between p-4 z-20">
|
||||
<div class="flex flex-col gap-6">
|
||||
<!-- Brand -->
|
||||
<div class="flex flex-col px-2">
|
||||
<h1 class="text-slate-900 dark:text-white text-lg font-bold tracking-tight">Backup Appliance</h1>
|
||||
<p class="text-text-secondary text-xs font-medium">Cockpit Admin v2.4</p>
|
||||
</div>
|
||||
<!-- Navigation -->
|
||||
<nav class="flex flex-col gap-1">
|
||||
<a class="flex items-center gap-3 px-3 py-2.5 rounded-lg text-text-secondary hover:bg-slate-100 dark:hover:bg-slate-800 transition-colors group" href="#">
|
||||
<span class="material-symbols-outlined group-hover:text-primary transition-colors">speed</span>
|
||||
<span class="text-sm font-medium">Dashboard</span>
|
||||
</a>
|
||||
<a class="flex items-center gap-3 px-3 py-2.5 rounded-lg bg-primary/10 text-primary dark:text-white dark:bg-[#233648]" href="#">
|
||||
<span class="material-symbols-outlined text-primary dark:text-white fill-1">hard_drive</span>
|
||||
<span class="text-sm font-bold">Storage</span>
|
||||
</a>
|
||||
<a class="flex items-center gap-3 px-3 py-2.5 rounded-lg text-text-secondary hover:bg-slate-100 dark:hover:bg-slate-800 transition-colors group" href="#">
|
||||
<span class="material-symbols-outlined group-hover:text-primary transition-colors">network_check</span>
|
||||
<span class="text-sm font-medium">Networking</span>
|
||||
</a>
|
||||
<a class="flex items-center gap-3 px-3 py-2.5 rounded-lg text-text-secondary hover:bg-slate-100 dark:hover:bg-slate-800 transition-colors group" href="#">
|
||||
<span class="material-symbols-outlined group-hover:text-primary transition-colors">group</span>
|
||||
<span class="text-sm font-medium">Accounts</span>
|
||||
</a>
|
||||
<a class="flex items-center gap-3 px-3 py-2.5 rounded-lg text-text-secondary hover:bg-slate-100 dark:hover:bg-slate-800 transition-colors group" href="#">
|
||||
<span class="material-symbols-outlined group-hover:text-primary transition-colors">menu_book</span>
|
||||
<span class="text-sm font-medium">Logs</span>
|
||||
</a>
|
||||
<div class="my-2 border-t border-slate-200 dark:border-border-dark"></div>
|
||||
<a class="flex items-center gap-3 px-3 py-2.5 rounded-lg text-text-secondary hover:bg-slate-100 dark:hover:bg-slate-800 transition-colors group" href="#">
|
||||
<span class="material-symbols-outlined group-hover:text-primary transition-colors">terminal</span>
|
||||
<span class="text-sm font-medium">Terminal</span>
|
||||
</a>
|
||||
</nav>
|
||||
</div>
|
||||
<!-- User -->
|
||||
<div class="px-2 py-2 flex items-center gap-3 border-t border-slate-200 dark:border-border-dark pt-4">
|
||||
<div class="h-8 w-8 rounded-full bg-primary flex items-center justify-center text-white font-bold text-xs">AD</div>
|
||||
<div class="flex flex-col">
|
||||
<span class="text-sm font-bold dark:text-white">Admin User</span>
|
||||
<span class="text-xs text-text-secondary">System Administrator</span>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
<!-- Main Content Area -->
|
||||
<main class="flex-1 flex flex-col h-full overflow-hidden relative bg-background-light dark:bg-background-dark">
|
||||
<!-- Header & Breadcrumbs -->
|
||||
<header class="flex-shrink-0 px-8 py-6 border-b border-slate-200 dark:border-border-dark bg-white/50 dark:bg-surface-darker/50 backdrop-blur-sm z-10">
|
||||
<div class="max-w-[1400px] mx-auto w-full flex flex-col gap-4">
|
||||
<!-- Breadcrumbs -->
|
||||
<nav class="flex items-center text-sm font-medium text-text-secondary">
|
||||
<a class="hover:text-primary transition-colors" href="#">Home</a>
|
||||
<span class="mx-2">/</span>
|
||||
<span class="text-slate-900 dark:text-white">Storage Management</span>
|
||||
</nav>
|
||||
<div class="flex flex-wrap items-end justify-between gap-4">
|
||||
<div class="flex flex-col gap-1">
|
||||
<h1 class="text-3xl font-extrabold text-slate-900 dark:text-white tracking-tight">Storage Pools</h1>
|
||||
<p class="text-text-secondary">Manage ZFS pools, datasets, and physical disks topology.</p>
|
||||
</div>
|
||||
<div class="flex items-center gap-3">
|
||||
<button class="flex items-center gap-2 px-4 py-2 rounded-lg border border-slate-300 dark:border-border-dark bg-white dark:bg-surface-dark text-slate-700 dark:text-white text-sm font-bold hover:bg-slate-50 dark:hover:bg-slate-800 transition-colors">
|
||||
<span class="material-symbols-outlined text-[20px]">refresh</span>
|
||||
Rescan Disks
|
||||
</button>
|
||||
<button class="flex items-center gap-2 px-4 py-2 rounded-lg bg-primary text-white text-sm font-bold hover:bg-primary/90 transition-colors shadow-lg shadow-primary/20">
|
||||
<span class="material-symbols-outlined text-[20px]">add_circle</span>
|
||||
Create Pool
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<!-- Scrollable Content -->
|
||||
<div class="flex-1 overflow-y-auto p-8">
|
||||
<div class="max-w-[1400px] mx-auto w-full flex flex-col gap-8 pb-10">
|
||||
<!-- Stats Overview -->
|
||||
<section class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
|
||||
<!-- Total Capacity -->
|
||||
<div class="bg-white dark:bg-surface-dark p-5 rounded-xl border border-slate-200 dark:border-border-dark shadow-sm">
|
||||
<div class="flex justify-between items-start mb-2">
|
||||
<p class="text-text-secondary text-sm font-semibold uppercase tracking-wider">Total Capacity</p>
|
||||
<span class="material-symbols-outlined text-text-secondary">database</span>
|
||||
</div>
|
||||
<div class="flex items-baseline gap-2">
|
||||
<h3 class="text-2xl font-bold dark:text-white">120.5 TB</h3>
|
||||
<span class="text-xs text-text-secondary">Raw</span>
|
||||
</div>
|
||||
<div class="mt-3 w-full bg-slate-100 dark:bg-slate-800 rounded-full h-1.5 overflow-hidden">
|
||||
<div class="bg-primary h-1.5 rounded-full" style="width: 38%"></div>
|
||||
</div>
|
||||
<p class="mt-2 text-xs text-text-secondary">38% Used (45 TB)</p>
|
||||
</div>
|
||||
<!-- Health Status -->
|
||||
<div class="bg-white dark:bg-surface-dark p-5 rounded-xl border border-slate-200 dark:border-border-dark shadow-sm">
|
||||
<div class="flex justify-between items-start mb-2">
|
||||
<p class="text-text-secondary text-sm font-semibold uppercase tracking-wider">Health Status</p>
|
||||
<span class="material-symbols-outlined text-emerald-500">check_circle</span>
|
||||
</div>
|
||||
<div class="flex items-baseline gap-2">
|
||||
<h3 class="text-2xl font-bold dark:text-white text-emerald-500">Optimal</h3>
|
||||
</div>
|
||||
<p class="mt-2 text-xs text-text-secondary">All pools are online</p>
|
||||
<p class="text-xs text-emerald-500 mt-1 font-medium">Last scrub: 2 hours ago</p>
|
||||
</div>
|
||||
<!-- Efficiency -->
|
||||
<div class="bg-white dark:bg-surface-dark p-5 rounded-xl border border-slate-200 dark:border-border-dark shadow-sm">
|
||||
<div class="flex justify-between items-start mb-2">
|
||||
<p class="text-text-secondary text-sm font-semibold uppercase tracking-wider">Efficiency</p>
|
||||
<span class="material-symbols-outlined text-text-secondary">compress</span>
|
||||
</div>
|
||||
<div class="flex items-baseline gap-2">
|
||||
<h3 class="text-2xl font-bold dark:text-white">1.45x</h3>
|
||||
<span class="text-xs text-text-secondary">Ratio</span>
|
||||
</div>
|
||||
<div class="flex gap-2 mt-3">
|
||||
<span class="px-2 py-0.5 rounded bg-blue-500/10 text-blue-500 text-[10px] font-bold">LZ4</span>
|
||||
<span class="px-2 py-0.5 rounded bg-purple-500/10 text-purple-500 text-[10px] font-bold">DEDUP ON</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Performance -->
|
||||
<div class="bg-white dark:bg-surface-dark p-5 rounded-xl border border-slate-200 dark:border-border-dark shadow-sm">
|
||||
<div class="flex justify-between items-start mb-2">
|
||||
<p class="text-text-secondary text-sm font-semibold uppercase tracking-wider">ARC Hit Ratio</p>
|
||||
<span class="material-symbols-outlined text-text-secondary">memory</span>
|
||||
</div>
|
||||
<div class="flex items-baseline gap-2">
|
||||
<h3 class="text-2xl font-bold dark:text-white">98.2%</h3>
|
||||
</div>
|
||||
<p class="mt-2 text-xs text-text-secondary">Cache Usage: 58GB / 64GB</p>
|
||||
<div class="mt-2 flex gap-1">
|
||||
<div class="h-1 flex-1 bg-emerald-500 rounded-full"></div>
|
||||
<div class="h-1 flex-1 bg-emerald-500 rounded-full"></div>
|
||||
<div class="h-1 flex-1 bg-emerald-500 rounded-full"></div>
|
||||
<div class="h-1 flex-1 bg-emerald-500/30 rounded-full"></div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<!-- Active Pools Table -->
|
||||
<section class="flex flex-col gap-4">
|
||||
<div class="flex items-center justify-between">
|
||||
<h2 class="text-xl font-bold text-slate-900 dark:text-white">Active Pools</h2>
|
||||
<div class="flex gap-2">
|
||||
<div class="relative">
|
||||
<span class="material-symbols-outlined absolute left-2.5 top-1/2 -translate-y-1/2 text-text-secondary text-[20px]">search</span>
|
||||
<input class="pl-10 pr-4 py-1.5 bg-white dark:bg-surface-dark border border-slate-300 dark:border-border-dark rounded-lg text-sm text-slate-900 dark:text-white focus:ring-2 focus:ring-primary focus:border-transparent outline-none w-64 placeholder-text-secondary" placeholder="Search datasets..." type="text"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-white dark:bg-surface-dark rounded-xl border border-slate-200 dark:border-border-dark overflow-hidden shadow-sm">
|
||||
<div class="overflow-x-auto">
|
||||
<table class="w-full text-left border-collapse">
|
||||
<thead>
|
||||
<tr class="bg-slate-50 dark:bg-[#1e2832] border-b border-slate-200 dark:border-border-dark">
|
||||
<th class="py-3 px-5 text-xs font-semibold uppercase tracking-wider text-text-secondary w-10"></th>
|
||||
<th class="py-3 px-5 text-xs font-semibold uppercase tracking-wider text-text-secondary">Name</th>
|
||||
<th class="py-3 px-5 text-xs font-semibold uppercase tracking-wider text-text-secondary">Status</th>
|
||||
<th class="py-3 px-5 text-xs font-semibold uppercase tracking-wider text-text-secondary">Used / Avail</th>
|
||||
<th class="py-3 px-5 text-xs font-semibold uppercase tracking-wider text-text-secondary">Topology</th>
|
||||
<th class="py-3 px-5 text-xs font-semibold uppercase tracking-wider text-text-secondary">Compression</th>
|
||||
<th class="py-3 px-5 text-xs font-semibold uppercase tracking-wider text-text-secondary text-right">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-slate-200 dark:divide-border-dark text-sm">
|
||||
<!-- Row 1: Parent Pool -->
|
||||
<tr class="group hover:bg-slate-50 dark:hover:bg-white/5 transition-colors cursor-pointer">
|
||||
<td class="py-4 px-5 text-text-secondary">
|
||||
<span class="material-symbols-outlined text-[20px] transition-transform rotate-90">arrow_right</span>
|
||||
</td>
|
||||
<td class="py-4 px-5">
|
||||
<div class="flex items-center gap-3">
|
||||
<span class="material-symbols-outlined text-primary">dns</span>
|
||||
<div>
|
||||
<span class="font-bold text-slate-900 dark:text-white block">tank0</span>
|
||||
<span class="text-xs text-text-secondary">/mnt/tank0</span>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td class="py-4 px-5">
|
||||
<span class="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-xs font-bold bg-emerald-500/10 text-emerald-600 dark:text-emerald-400 border border-emerald-500/20">
|
||||
<span class="w-1.5 h-1.5 rounded-full bg-emerald-500"></span>
|
||||
ONLINE
|
||||
</span>
|
||||
</td>
|
||||
<td class="py-4 px-5">
|
||||
<div class="flex flex-col gap-1 w-32">
|
||||
<div class="flex justify-between text-xs">
|
||||
<span class="text-slate-900 dark:text-white font-medium">18.5 TB</span>
|
||||
<span class="text-text-secondary">42 TB</span>
|
||||
</div>
|
||||
<div class="w-full bg-slate-200 dark:bg-slate-700 rounded-full h-1.5">
|
||||
<div class="bg-primary h-1.5 rounded-full" style="width: 44%"></div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td class="py-4 px-5 text-text-secondary">RAIDZ2 (6 disks)</td>
|
||||
<td class="py-4 px-5 text-text-secondary">LZ4</td>
|
||||
<td class="py-4 px-5 text-right">
|
||||
<button class="p-1.5 rounded-md hover:bg-slate-200 dark:hover:bg-slate-700 text-text-secondary transition-colors">
|
||||
<span class="material-symbols-outlined text-[20px]">more_vert</span>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- Child Dataset 1 -->
|
||||
<tr class="bg-slate-50/50 dark:bg-[#151d26] hover:bg-slate-100 dark:hover:bg-[#1a242f] transition-colors">
|
||||
<td class="py-3 px-5"></td>
|
||||
<td class="py-3 px-5 pl-10">
|
||||
<div class="flex items-center gap-3 relative before:content-[''] before:absolute before:-left-4 before:top-1/2 before:-translate-y-1/2 before:w-3 before:h-px before:bg-border-dark before:opacity-50">
|
||||
<span class="material-symbols-outlined text-text-secondary text-[18px]">folder</span>
|
||||
<span class="font-medium text-slate-700 dark:text-slate-200">projects_vol</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="py-3 px-5 text-text-secondary text-xs">Mounted</td>
|
||||
<td class="py-3 px-5">
|
||||
<div class="flex flex-col gap-1 w-32">
|
||||
<div class="flex justify-between text-xs">
|
||||
<span class="text-slate-700 dark:text-slate-300 font-medium">12 TB</span>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td class="py-3 px-5 text-text-secondary text-xs">—</td>
|
||||
<td class="py-3 px-5 text-text-secondary text-xs">ZSTD-3</td>
|
||||
<td class="py-3 px-5 text-right">
|
||||
<button class="p-1 rounded-md hover:bg-slate-200 dark:hover:bg-slate-700 text-text-secondary transition-colors">
|
||||
<span class="material-symbols-outlined text-[18px]">settings</span>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- Child Dataset 2 -->
|
||||
<tr class="bg-slate-50/50 dark:bg-[#151d26] hover:bg-slate-100 dark:hover:bg-[#1a242f] transition-colors border-b border-slate-200 dark:border-border-dark/50">
|
||||
<td class="py-3 px-5"></td>
|
||||
<td class="py-3 px-5 pl-10">
|
||||
<div class="flex items-center gap-3 relative before:content-[''] before:absolute before:-left-4 before:top-1/2 before:-translate-y-1/2 before:w-3 before:h-px before:bg-border-dark before:opacity-50">
|
||||
<span class="material-symbols-outlined text-text-secondary text-[18px]">folder_shared</span>
|
||||
<span class="font-medium text-slate-700 dark:text-slate-200">backups_smb</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="py-3 px-5 text-text-secondary text-xs">Shared (SMB)</td>
|
||||
<td class="py-3 px-5">
|
||||
<div class="flex flex-col gap-1 w-32">
|
||||
<div class="flex justify-between text-xs">
|
||||
<span class="text-slate-700 dark:text-slate-300 font-medium">6.5 TB</span>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td class="py-3 px-5 text-text-secondary text-xs">—</td>
|
||||
<td class="py-3 px-5 text-text-secondary text-xs">GZIP-9</td>
|
||||
<td class="py-3 px-5 text-right">
|
||||
<button class="p-1 rounded-md hover:bg-slate-200 dark:hover:bg-slate-700 text-text-secondary transition-colors">
|
||||
<span class="material-symbols-outlined text-[18px]">settings</span>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- Row 2: Secondary Pool -->
|
||||
<tr class="group hover:bg-slate-50 dark:hover:bg-white/5 transition-colors cursor-pointer">
|
||||
<td class="py-4 px-5 text-text-secondary">
|
||||
<span class="material-symbols-outlined text-[20px] transition-transform">arrow_right</span>
|
||||
</td>
|
||||
<td class="py-4 px-5">
|
||||
<div class="flex items-center gap-3">
|
||||
<span class="material-symbols-outlined text-orange-500">warning</span>
|
||||
<div>
|
||||
<span class="font-bold text-slate-900 dark:text-white block">archive_legacy</span>
|
||||
<span class="text-xs text-text-secondary">/mnt/archive</span>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td class="py-4 px-5">
|
||||
<span class="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-xs font-bold bg-orange-500/10 text-orange-600 dark:text-orange-400 border border-orange-500/20">
|
||||
<span class="w-1.5 h-1.5 rounded-full bg-orange-500 animate-pulse"></span>
|
||||
DEGRADED
|
||||
</span>
|
||||
</td>
|
||||
<td class="py-4 px-5">
|
||||
<div class="flex flex-col gap-1 w-32">
|
||||
<div class="flex justify-between text-xs">
|
||||
<span class="text-slate-900 dark:text-white font-medium">8.2 TB</span>
|
||||
<span class="text-text-secondary">10 TB</span>
|
||||
</div>
|
||||
<div class="w-full bg-slate-200 dark:bg-slate-700 rounded-full h-1.5">
|
||||
<div class="bg-orange-500 h-1.5 rounded-full" style="width: 82%"></div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td class="py-4 px-5 text-text-secondary">MIRROR (2 disks)</td>
|
||||
<td class="py-4 px-5 text-text-secondary">LZ4</td>
|
||||
<td class="py-4 px-5 text-right">
|
||||
<button class="p-1.5 rounded-md hover:bg-slate-200 dark:hover:bg-slate-700 text-text-secondary transition-colors">
|
||||
<span class="material-symbols-outlined text-[20px]">more_vert</span>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<!-- Table Footer -->
|
||||
<div class="bg-slate-50 dark:bg-[#1e2832] px-5 py-3 border-t border-slate-200 dark:border-border-dark flex justify-between items-center text-xs text-text-secondary">
|
||||
<span>Showing 2 active pools</span>
|
||||
<a class="hover:text-primary font-medium" href="#">View Archived Pools</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<!-- Physical Disks Grid -->
|
||||
<section class="flex flex-col gap-4">
|
||||
<div class="flex items-center justify-between">
|
||||
<h2 class="text-xl font-bold text-slate-900 dark:text-white">Physical Disks</h2>
|
||||
<button class="text-primary text-sm font-bold hover:underline">View All Disks</button>
|
||||
</div>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 xl:grid-cols-6 gap-4">
|
||||
<!-- Disk 1 -->
|
||||
<div class="bg-white dark:bg-surface-dark rounded-lg p-4 border border-slate-200 dark:border-border-dark flex flex-col gap-3 hover:border-primary/50 transition-colors group cursor-pointer relative overflow-hidden">
|
||||
<div class="absolute top-0 right-0 p-2">
|
||||
<div class="w-2 h-2 rounded-full bg-emerald-500"></div>
|
||||
</div>
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-10 h-10 rounded bg-slate-100 dark:bg-slate-800 flex items-center justify-center">
|
||||
<span class="material-symbols-outlined text-text-secondary group-hover:text-primary transition-colors">hard_drive</span>
|
||||
</div>
|
||||
<div class="flex flex-col">
|
||||
<span class="text-sm font-bold text-slate-900 dark:text-white">sda</span>
|
||||
<span class="text-xs text-text-secondary">Slot 1</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col gap-1">
|
||||
<div class="flex justify-between text-xs text-text-secondary">
|
||||
<span>HGST-7200</span>
|
||||
<span>4 TB</span>
|
||||
</div>
|
||||
<div class="flex gap-0.5 h-1.5 w-full rounded-full overflow-hidden bg-slate-200 dark:bg-slate-700">
|
||||
<div class="bg-primary w-2/3"></div>
|
||||
<div class="bg-transparent w-1/3"></div>
|
||||
</div>
|
||||
<span class="text-[10px] text-text-secondary mt-1">Pool: tank0</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Disk 2 -->
|
||||
<div class="bg-white dark:bg-surface-dark rounded-lg p-4 border border-slate-200 dark:border-border-dark flex flex-col gap-3 hover:border-primary/50 transition-colors group cursor-pointer relative overflow-hidden">
|
||||
<div class="absolute top-0 right-0 p-2">
|
||||
<div class="w-2 h-2 rounded-full bg-emerald-500"></div>
|
||||
</div>
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-10 h-10 rounded bg-slate-100 dark:bg-slate-800 flex items-center justify-center">
|
||||
<span class="material-symbols-outlined text-text-secondary group-hover:text-primary transition-colors">hard_drive</span>
|
||||
</div>
|
||||
<div class="flex flex-col">
|
||||
<span class="text-sm font-bold text-slate-900 dark:text-white">sdb</span>
|
||||
<span class="text-xs text-text-secondary">Slot 2</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col gap-1">
|
||||
<div class="flex justify-between text-xs text-text-secondary">
|
||||
<span>HGST-7200</span>
|
||||
<span>4 TB</span>
|
||||
</div>
|
||||
<div class="flex gap-0.5 h-1.5 w-full rounded-full overflow-hidden bg-slate-200 dark:bg-slate-700">
|
||||
<div class="bg-primary w-2/3"></div>
|
||||
<div class="bg-transparent w-1/3"></div>
|
||||
</div>
|
||||
<span class="text-[10px] text-text-secondary mt-1">Pool: tank0</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Disk 3 -->
|
||||
<div class="bg-white dark:bg-surface-dark rounded-lg p-4 border border-slate-200 dark:border-border-dark flex flex-col gap-3 hover:border-primary/50 transition-colors group cursor-pointer relative overflow-hidden">
|
||||
<div class="absolute top-0 right-0 p-2">
|
||||
<div class="w-2 h-2 rounded-full bg-emerald-500"></div>
|
||||
</div>
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-10 h-10 rounded bg-slate-100 dark:bg-slate-800 flex items-center justify-center">
|
||||
<span class="material-symbols-outlined text-text-secondary group-hover:text-primary transition-colors">hard_drive</span>
|
||||
</div>
|
||||
<div class="flex flex-col">
|
||||
<span class="text-sm font-bold text-slate-900 dark:text-white">sdc</span>
|
||||
<span class="text-xs text-text-secondary">Slot 3</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col gap-1">
|
||||
<div class="flex justify-between text-xs text-text-secondary">
|
||||
<span>HGST-7200</span>
|
||||
<span>4 TB</span>
|
||||
</div>
|
||||
<div class="flex gap-0.5 h-1.5 w-full rounded-full overflow-hidden bg-slate-200 dark:bg-slate-700">
|
||||
<div class="bg-primary w-2/3"></div>
|
||||
<div class="bg-transparent w-1/3"></div>
|
||||
</div>
|
||||
<span class="text-[10px] text-text-secondary mt-1">Pool: tank0</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Disk 4 (Faulted) -->
|
||||
<div class="bg-red-50 dark:bg-red-900/10 rounded-lg p-4 border border-red-200 dark:border-red-900/30 flex flex-col gap-3 hover:border-red-500 transition-colors group cursor-pointer relative overflow-hidden">
|
||||
<div class="absolute top-0 right-0 p-2">
|
||||
<div class="w-2 h-2 rounded-full bg-red-500 animate-pulse"></div>
|
||||
</div>
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-10 h-10 rounded bg-red-100 dark:bg-red-900/20 flex items-center justify-center">
|
||||
<span class="material-symbols-outlined text-red-500 group-hover:text-red-400 transition-colors">error</span>
|
||||
</div>
|
||||
<div class="flex flex-col">
|
||||
<span class="text-sm font-bold text-slate-900 dark:text-white">sdd</span>
|
||||
<span class="text-xs text-red-500 font-bold">FAULTED</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col gap-1">
|
||||
<div class="flex justify-between text-xs text-text-secondary">
|
||||
<span>HGST-7200</span>
|
||||
<span>4 TB</span>
|
||||
</div>
|
||||
<div class="flex gap-0.5 h-1.5 w-full rounded-full overflow-hidden bg-slate-200 dark:bg-slate-700">
|
||||
<!-- Error state for bar -->
|
||||
<div class="bg-red-500 w-full opacity-50"></div>
|
||||
</div>
|
||||
<span class="text-[10px] text-red-400 mt-1">Pool: archive_legacy</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Disk 5 (Spare) -->
|
||||
<div class="bg-white dark:bg-surface-dark rounded-lg p-4 border border-slate-200 dark:border-border-dark flex flex-col gap-3 hover:border-primary/50 transition-colors group cursor-pointer relative overflow-hidden">
|
||||
<div class="absolute top-0 right-0 p-2">
|
||||
<div class="w-2 h-2 rounded-full bg-blue-500"></div>
|
||||
</div>
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-10 h-10 rounded bg-slate-100 dark:bg-slate-800 flex items-center justify-center">
|
||||
<span class="material-symbols-outlined text-text-secondary group-hover:text-primary transition-colors">medical_services</span>
|
||||
</div>
|
||||
<div class="flex flex-col">
|
||||
<span class="text-sm font-bold text-slate-900 dark:text-white">sde</span>
|
||||
<span class="text-xs text-text-secondary">Slot 5</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col gap-1">
|
||||
<div class="flex justify-between text-xs text-text-secondary">
|
||||
<span>Samsung SSD</span>
|
||||
<span>4 TB</span>
|
||||
</div>
|
||||
<div class="flex gap-0.5 h-1.5 w-full rounded-full overflow-hidden bg-slate-200 dark:bg-slate-700">
|
||||
<div class="bg-blue-500 w-0"></div>
|
||||
</div>
|
||||
<span class="text-[10px] text-blue-400 mt-1 font-bold">HOT SPARE</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Add Disk -->
|
||||
<div class="bg-slate-50 dark:bg-surface-dark/50 rounded-lg p-4 border border-dashed border-slate-300 dark:border-border-dark flex flex-col gap-3 hover:border-primary hover:bg-primary/5 transition-all group cursor-pointer items-center justify-center h-[134px]">
|
||||
<span class="material-symbols-outlined text-text-secondary group-hover:text-primary text-[32px]">add</span>
|
||||
<span class="text-sm font-medium text-text-secondary group-hover:text-primary">Add New Disk</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
<!-- Slide-over Panel (Simulated) -->
|
||||
<div class="fixed inset-y-0 right-0 w-96 bg-white dark:bg-surface-darker border-l border-slate-200 dark:border-border-dark shadow-2xl z-30 transform translate-x-full lg:translate-x-0 transition-transform duration-300 flex flex-col">
|
||||
<!-- Header -->
|
||||
<div class="flex items-center justify-between p-6 border-b border-slate-200 dark:border-border-dark bg-slate-50 dark:bg-surface-dark">
|
||||
<h3 class="text-lg font-bold text-slate-900 dark:text-white">tank0 Properties</h3>
|
||||
<button class="text-text-secondary hover:text-slate-900 dark:hover:text-white transition-colors">
|
||||
<span class="material-symbols-outlined">close</span>
|
||||
</button>
|
||||
</div>
|
||||
<!-- Content -->
|
||||
<div class="flex-1 overflow-y-auto p-6 flex flex-col gap-6">
|
||||
<!-- Quick Info -->
|
||||
<div class="p-4 rounded-lg bg-primary/10 border border-primary/20">
|
||||
<div class="flex items-center gap-3 mb-2">
|
||||
<span class="material-symbols-outlined text-primary">info</span>
|
||||
<span class="text-sm font-bold text-primary">Healthy</span>
|
||||
</div>
|
||||
<p class="text-xs text-slate-600 dark:text-slate-300 leading-relaxed">
|
||||
This pool is operating normally. Scrub completed successfully on Oct 24, 2023.
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex flex-col gap-4">
|
||||
<!-- Setting -->
|
||||
<div class="flex flex-col gap-2">
|
||||
<label class="text-sm font-medium text-slate-900 dark:text-white">Compression Level</label>
|
||||
<select class="w-full bg-white dark:bg-surface-dark border border-slate-300 dark:border-border-dark rounded-lg px-3 py-2 text-sm text-slate-700 dark:text-white focus:ring-2 focus:ring-primary outline-none">
|
||||
<option value="off">Off</option>
|
||||
<option selected="" value="lz4">LZ4 (Recommended)</option>
|
||||
<option value="zstd">ZSTD</option>
|
||||
<option value="gzip">GZIP</option>
|
||||
</select>
|
||||
<p class="text-xs text-text-secondary">Balances performance and storage efficiency.</p>
|
||||
</div>
|
||||
<!-- Setting -->
|
||||
<div class="flex flex-col gap-2 border-t border-slate-200 dark:border-border-dark pt-4">
|
||||
<div class="flex items-center justify-between">
|
||||
<label class="text-sm font-medium text-slate-900 dark:text-white">Deduplication</label>
|
||||
<!-- Toggle Switch -->
|
||||
<button aria-checked="false" class="w-11 h-6 bg-slate-200 dark:bg-slate-700 rounded-full relative transition-colors focus:outline-none focus:ring-2 focus:ring-primary">
|
||||
<span class="absolute left-1 top-1 bg-white w-4 h-4 rounded-full transition-transform transform translate-x-0"></span>
|
||||
</button>
|
||||
</div>
|
||||
<p class="text-xs text-text-secondary">Requires significant RAM. Use with caution.</p>
|
||||
</div>
|
||||
<!-- Setting -->
|
||||
<div class="flex flex-col gap-2 border-t border-slate-200 dark:border-border-dark pt-4">
|
||||
<div class="flex items-center justify-between">
|
||||
<label class="text-sm font-medium text-slate-900 dark:text-white">Auto-Expand</label>
|
||||
<button aria-checked="true" class="w-11 h-6 bg-primary rounded-full relative transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-surface-darker focus:ring-primary">
|
||||
<span class="absolute left-1 top-1 bg-white w-4 h-4 rounded-full transition-transform transform translate-x-5"></span>
|
||||
</button>
|
||||
</div>
|
||||
<p class="text-xs text-text-secondary">Automatically grow pool when larger disks are added.</p>
|
||||
</div>
|
||||
<!-- Setting -->
|
||||
<div class="flex flex-col gap-2 border-t border-slate-200 dark:border-border-dark pt-4">
|
||||
<label class="text-sm font-medium text-slate-900 dark:text-white">Scrub Interval</label>
|
||||
<div class="flex items-center gap-2">
|
||||
<input class="w-20 bg-white dark:bg-surface-dark border border-slate-300 dark:border-border-dark rounded-lg px-3 py-2 text-sm text-slate-700 dark:text-white focus:ring-2 focus:ring-primary outline-none" type="number" value="30"/>
|
||||
<span class="text-sm text-text-secondary">days</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Footer Actions -->
|
||||
<div class="p-6 border-t border-slate-200 dark:border-border-dark bg-slate-50 dark:bg-surface-dark flex gap-3">
|
||||
<button class="flex-1 px-4 py-2 bg-primary text-white text-sm font-bold rounded-lg hover:bg-primary/90 transition-colors">Save Changes</button>
|
||||
<button class="px-4 py-2 bg-white dark:bg-surface-darker border border-slate-300 dark:border-border-dark text-slate-700 dark:text-white text-sm font-bold rounded-lg hover:bg-slate-50 dark:hover:bg-slate-800 transition-colors">Cancel</button>
|
||||
</div>
|
||||
<div class="p-6 pt-0 bg-slate-50 dark:bg-surface-dark">
|
||||
<button class="w-full px-4 py-2 border border-red-500/30 text-red-500 hover:bg-red-500/10 text-sm font-bold rounded-lg transition-colors flex items-center justify-center gap-2">
|
||||
<span class="material-symbols-outlined text-[18px]">delete</span>
|
||||
Export / Destroy Pool
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body></html>
|
||||
BIN
src/web/storage-management.png
Normal file
|
After Width: | Height: | Size: 310 KiB |
459
src/web/system-management-code.html
Normal file
@@ -0,0 +1,459 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html class="dark" lang="en"><head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
|
||||
<title>System Settings - Backup Appliance</title>
|
||||
<!-- Google Fonts -->
|
||||
<link href="https://fonts.googleapis.com" rel="preconnect"/>
|
||||
<link crossorigin="" href="https://fonts.gstatic.com" rel="preconnect"/>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Manrope:wght@200..800&display=swap" rel="stylesheet"/>
|
||||
<!-- Material Symbols -->
|
||||
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap" rel="stylesheet"/>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap" rel="stylesheet"/>
|
||||
<!-- Tailwind CSS -->
|
||||
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
|
||||
<!-- Tailwind Config -->
|
||||
<script id="tailwind-config">
|
||||
tailwind.config = {
|
||||
darkMode: "class",
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
"primary": "#137fec",
|
||||
"background-light": "#f6f7f8",
|
||||
"background-dark": "#101922",
|
||||
"card-dark": "#192633",
|
||||
"border-dark": "#233648",
|
||||
"text-secondary": "#92adc9",
|
||||
},
|
||||
fontFamily: {
|
||||
"display": ["Manrope", "sans-serif"]
|
||||
},
|
||||
borderRadius: {"DEFAULT": "0.25rem", "lg": "0.5rem", "xl": "0.75rem", "full": "9999px"},
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
/* Custom Toggle Switch */
|
||||
.toggle-checkbox:checked {
|
||||
right: 0;
|
||||
border-color: #137fec;
|
||||
}
|
||||
.toggle-checkbox:checked + .toggle-label {
|
||||
background-color: #137fec;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Manrope', sans-serif;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-background-light dark:bg-background-dark text-slate-900 dark:text-white overflow-hidden">
|
||||
<div class="flex h-screen w-full">
|
||||
<!-- Side Navigation -->
|
||||
<aside class="hidden w-64 flex-col border-r border-border-dark bg-background-dark md:flex">
|
||||
<div class="flex h-16 items-center px-6 border-b border-border-dark">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="material-symbols-outlined text-primary" style="font-size: 28px;">dns</span>
|
||||
<h1 class="text-lg font-bold tracking-tight">BackupNode</h1>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-1 flex-col justify-between p-4 overflow-y-auto">
|
||||
<div class="flex flex-col gap-4">
|
||||
<div class="px-2">
|
||||
<p class="text-xs font-bold uppercase tracking-wider text-text-secondary mb-2">Main</p>
|
||||
<div class="flex flex-col gap-1">
|
||||
<a class="flex items-center gap-3 rounded-lg px-3 py-2 text-text-secondary hover:bg-border-dark hover:text-white transition-colors" href="#">
|
||||
<span class="material-symbols-outlined">dashboard</span>
|
||||
<span class="text-sm font-medium">Dashboard</span>
|
||||
</a>
|
||||
<a class="flex items-center gap-3 rounded-lg px-3 py-2 text-text-secondary hover:bg-border-dark hover:text-white transition-colors" href="#">
|
||||
<span class="material-symbols-outlined">hard_drive</span>
|
||||
<span class="text-sm font-medium">Storage Pools</span>
|
||||
</a>
|
||||
<a class="flex items-center gap-3 rounded-lg px-3 py-2 text-text-secondary hover:bg-border-dark hover:text-white transition-colors" href="#">
|
||||
<span class="material-symbols-outlined">cloud_upload</span>
|
||||
<span class="text-sm font-medium">Cloud Sync</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="px-2">
|
||||
<p class="text-xs font-bold uppercase tracking-wider text-text-secondary mb-2">System</p>
|
||||
<div class="flex flex-col gap-1">
|
||||
<a class="flex items-center gap-3 rounded-lg bg-primary/20 px-3 py-2 text-primary transition-colors" href="#">
|
||||
<span class="material-symbols-outlined fill-1">settings</span>
|
||||
<span class="text-sm font-bold">Settings</span>
|
||||
</a>
|
||||
<a class="flex items-center gap-3 rounded-lg px-3 py-2 text-text-secondary hover:bg-border-dark hover:text-white transition-colors" href="#">
|
||||
<span class="material-symbols-outlined">security</span>
|
||||
<span class="text-sm font-medium">Access Control</span>
|
||||
</a>
|
||||
<a class="flex items-center gap-3 rounded-lg px-3 py-2 text-text-secondary hover:bg-border-dark hover:text-white transition-colors" href="#">
|
||||
<span class="material-symbols-outlined">description</span>
|
||||
<span class="text-sm font-medium">System Logs</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-auto border-t border-border-dark pt-4">
|
||||
<div class="flex items-center gap-3 px-2 py-2">
|
||||
<div class="relative">
|
||||
<div class="h-2 w-2 rounded-full bg-green-500 absolute -right-0.5 -bottom-0.5 border border-background-dark"></div>
|
||||
<div class="h-8 w-8 rounded-full bg-border-dark flex items-center justify-center text-text-secondary">
|
||||
<span class="material-symbols-outlined text-sm">person</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col">
|
||||
<p class="text-sm font-bold text-white">Administrator</p>
|
||||
<p class="text-xs text-text-secondary">root</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
<!-- Main Content -->
|
||||
<main class="flex flex-1 flex-col bg-background-light dark:bg-background-dark overflow-hidden relative">
|
||||
<!-- Top Navigation -->
|
||||
<header class="flex h-16 items-center justify-between border-b border-border-dark bg-background-dark px-6 lg:px-10 shrink-0 z-10">
|
||||
<div class="flex items-center gap-4">
|
||||
<button class="text-text-secondary md:hidden hover:text-white">
|
||||
<span class="material-symbols-outlined">menu</span>
|
||||
</button>
|
||||
<!-- Breadcrumbs -->
|
||||
<div class="flex items-center gap-2 text-sm">
|
||||
<a class="text-text-secondary hover:text-white transition-colors" href="#">System</a>
|
||||
<span class="text-text-secondary">/</span>
|
||||
<span class="text-white font-medium">Configuration</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="hidden md:flex items-center gap-2 px-3 py-1.5 rounded-full bg-green-500/10 border border-green-500/20">
|
||||
<div class="h-2 w-2 rounded-full bg-green-500 animate-pulse"></div>
|
||||
<span class="text-xs font-medium text-green-500">System Healthy</span>
|
||||
</div>
|
||||
<div class="h-6 w-px bg-border-dark mx-2"></div>
|
||||
<button class="flex items-center justify-center gap-2 rounded-lg bg-border-dark px-4 py-2 text-sm font-bold text-white hover:bg-[#2f455a] transition-colors">
|
||||
<span class="material-symbols-outlined text-[18px]">restart_alt</span>
|
||||
<span class="hidden sm:inline">Reboot</span>
|
||||
</button>
|
||||
<button class="flex items-center justify-center gap-2 rounded-lg bg-red-500/10 px-4 py-2 text-sm font-bold text-red-500 hover:bg-red-500/20 transition-colors border border-red-500/20">
|
||||
<span class="material-symbols-outlined text-[18px]">power_settings_new</span>
|
||||
<span class="hidden sm:inline">Shutdown</span>
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
<!-- Scrollable Content -->
|
||||
<div class="flex-1 overflow-y-auto p-4 md:p-8 lg:px-12 scroll-smooth">
|
||||
<div class="mx-auto max-w-7xl">
|
||||
<!-- Page Header -->
|
||||
<div class="mb-8 flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
|
||||
<div>
|
||||
<h1 class="text-3xl font-bold tracking-tight text-white mb-2">System Configuration</h1>
|
||||
<p class="text-text-secondary text-sm max-w-2xl">
|
||||
Manage network interfaces, time synchronization, service states, and remote management protocols.
|
||||
</p>
|
||||
</div>
|
||||
<button class="flex items-center justify-center gap-2 rounded-lg bg-primary px-5 py-2.5 text-sm font-bold text-white hover:bg-blue-600 transition-all shadow-lg shadow-blue-500/20">
|
||||
<span class="material-symbols-outlined text-[20px]">save</span>
|
||||
Save Changes
|
||||
</button>
|
||||
</div>
|
||||
<!-- Grid Layout -->
|
||||
<div class="grid grid-cols-1 gap-6 xl:grid-cols-2">
|
||||
<!-- Network Card -->
|
||||
<div class="flex flex-col rounded-xl border border-border-dark bg-card-dark shadow-sm">
|
||||
<div class="flex items-center justify-between border-b border-border-dark px-6 py-4">
|
||||
<div class="flex items-center gap-3">
|
||||
<span class="material-symbols-outlined text-primary">lan</span>
|
||||
<h2 class="text-lg font-bold text-white">Network Interfaces</h2>
|
||||
</div>
|
||||
<button class="text-xs font-bold text-primary hover:text-blue-400">CONFIGURE DNS</button>
|
||||
</div>
|
||||
<div class="p-2">
|
||||
<!-- Interface Item 1 -->
|
||||
<div class="group flex items-center justify-between rounded-lg p-3 hover:bg-border-dark/50 transition-colors">
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="flex h-10 w-10 items-center justify-center rounded-lg bg-border-dark text-white">
|
||||
<span class="material-symbols-outlined">settings_ethernet</span>
|
||||
</div>
|
||||
<div>
|
||||
<div class="flex items-center gap-2">
|
||||
<p class="font-bold text-white">eth0</p>
|
||||
<span class="rounded bg-primary/20 px-1.5 py-0.5 text-[10px] font-bold text-primary uppercase">Management</span>
|
||||
</div>
|
||||
<p class="font-mono text-xs text-text-secondary">192.168.1.50 <span class="opacity-50 mx-1">/</span> 24</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="hidden sm:flex flex-col items-end">
|
||||
<div class="flex items-center gap-1.5">
|
||||
<div class="h-2 w-2 rounded-full bg-green-500"></div>
|
||||
<span class="text-xs font-medium text-white">Connected</span>
|
||||
</div>
|
||||
<span class="text-xs text-text-secondary">10 Gbps</span>
|
||||
</div>
|
||||
<button class="h-8 w-8 rounded-full hover:bg-border-dark flex items-center justify-center text-text-secondary hover:text-white transition-colors">
|
||||
<span class="material-symbols-outlined">more_vert</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Interface Item 2 -->
|
||||
<div class="group flex items-center justify-between rounded-lg p-3 hover:bg-border-dark/50 transition-colors">
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="flex h-10 w-10 items-center justify-center rounded-lg bg-border-dark text-white">
|
||||
<span class="material-symbols-outlined">settings_ethernet</span>
|
||||
</div>
|
||||
<div>
|
||||
<div class="flex items-center gap-2">
|
||||
<p class="font-bold text-white">eth1</p>
|
||||
<span class="rounded bg-purple-500/20 px-1.5 py-0.5 text-[10px] font-bold text-purple-400 uppercase">iSCSI</span>
|
||||
</div>
|
||||
<p class="font-mono text-xs text-text-secondary">10.0.50.10 <span class="opacity-50 mx-1">/</span> 24</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="hidden sm:flex flex-col items-end">
|
||||
<div class="flex items-center gap-1.5">
|
||||
<div class="h-2 w-2 rounded-full bg-green-500"></div>
|
||||
<span class="text-xs font-medium text-white">Connected</span>
|
||||
</div>
|
||||
<span class="text-xs text-text-secondary">10 Gbps</span>
|
||||
</div>
|
||||
<button class="h-8 w-8 rounded-full hover:bg-border-dark flex items-center justify-center text-text-secondary hover:text-white transition-colors">
|
||||
<span class="material-symbols-outlined">more_vert</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Interface Item 3 -->
|
||||
<div class="group flex items-center justify-between rounded-lg p-3 hover:bg-border-dark/50 transition-colors opacity-70">
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="flex h-10 w-10 items-center justify-center rounded-lg bg-border-dark text-text-secondary">
|
||||
<span class="material-symbols-outlined">settings_ethernet</span>
|
||||
</div>
|
||||
<div>
|
||||
<div class="flex items-center gap-2">
|
||||
<p class="font-bold text-text-secondary">eth2</p>
|
||||
</div>
|
||||
<p class="font-mono text-xs text-text-secondary">No Carrier</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="hidden sm:flex flex-col items-end">
|
||||
<div class="flex items-center gap-1.5">
|
||||
<div class="h-2 w-2 rounded-full bg-red-500"></div>
|
||||
<span class="text-xs font-medium text-text-secondary">Down</span>
|
||||
</div>
|
||||
</div>
|
||||
<button class="h-8 w-8 rounded-full hover:bg-border-dark flex items-center justify-center text-text-secondary hover:text-white transition-colors">
|
||||
<span class="material-symbols-outlined">more_vert</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Services Card -->
|
||||
<div class="flex flex-col rounded-xl border border-border-dark bg-card-dark shadow-sm">
|
||||
<div class="flex items-center justify-between border-b border-border-dark px-6 py-4">
|
||||
<div class="flex items-center gap-3">
|
||||
<span class="material-symbols-outlined text-primary">memory</span>
|
||||
<h2 class="text-lg font-bold text-white">Service Control</h2>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="h-2 w-2 rounded-full bg-green-500"></span>
|
||||
<span class="text-xs text-text-secondary">All Systems Normal</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-4 flex flex-col gap-1">
|
||||
<!-- Service Row -->
|
||||
<div class="flex items-center justify-between rounded-lg bg-[#111a22] p-3 border border-transparent hover:border-border-dark transition-colors">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="p-2 rounded bg-border-dark/50 text-white">
|
||||
<span class="material-symbols-outlined text-[20px]">terminal</span>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-sm font-bold text-white">SSH Service</p>
|
||||
<p class="text-xs text-text-secondary">Remote command line access</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<span class="px-2 py-0.5 rounded text-[10px] font-bold bg-green-500/20 text-green-500 border border-green-500/20">RUNNING</span>
|
||||
<div class="relative inline-block w-10 mr-2 align-middle select-none transition duration-200 ease-in">
|
||||
<input checked="" class="toggle-checkbox absolute block w-5 h-5 rounded-full bg-white border-4 appearance-none cursor-pointer checked:right-0 checked:border-primary transition-all duration-300" id="ssh-toggle" name="toggle" type="checkbox"/>
|
||||
<label class="toggle-label block overflow-hidden h-5 rounded-full bg-border-dark cursor-pointer transition-colors duration-300" for="ssh-toggle"></label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Service Row -->
|
||||
<div class="flex items-center justify-between rounded-lg bg-[#111a22] p-3 border border-transparent hover:border-border-dark transition-colors">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="p-2 rounded bg-border-dark/50 text-white">
|
||||
<span class="material-symbols-outlined text-[20px]">folder_shared</span>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-sm font-bold text-white">SMB / CIFS</p>
|
||||
<p class="text-xs text-text-secondary">Windows file sharing</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<span class="px-2 py-0.5 rounded text-[10px] font-bold bg-green-500/20 text-green-500 border border-green-500/20">RUNNING</span>
|
||||
<div class="relative inline-block w-10 mr-2 align-middle select-none transition duration-200 ease-in">
|
||||
<input checked="" class="toggle-checkbox absolute block w-5 h-5 rounded-full bg-white border-4 appearance-none cursor-pointer checked:right-0 checked:border-primary transition-all duration-300" id="smb-toggle" name="toggle" type="checkbox"/>
|
||||
<label class="toggle-label block overflow-hidden h-5 rounded-full bg-border-dark cursor-pointer transition-colors duration-300" for="smb-toggle"></label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Service Row -->
|
||||
<div class="flex items-center justify-between rounded-lg bg-[#111a22] p-3 border border-transparent hover:border-border-dark transition-colors">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="p-2 rounded bg-border-dark/50 text-white">
|
||||
<span class="material-symbols-outlined text-[20px]">storage</span>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-sm font-bold text-white">iSCSI Target</p>
|
||||
<p class="text-xs text-text-secondary">Block storage sharing</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<span class="px-2 py-0.5 rounded text-[10px] font-bold bg-yellow-500/20 text-yellow-500 border border-yellow-500/20">STOPPED</span>
|
||||
<div class="relative inline-block w-10 mr-2 align-middle select-none transition duration-200 ease-in">
|
||||
<input class="toggle-checkbox absolute block w-5 h-5 rounded-full bg-white border-4 appearance-none cursor-pointer checked:right-0 checked:border-primary transition-all duration-300" id="iscsi-toggle" name="toggle" type="checkbox"/>
|
||||
<label class="toggle-label block overflow-hidden h-5 rounded-full bg-border-dark cursor-pointer transition-colors duration-300" for="iscsi-toggle"></label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Service Row -->
|
||||
<div class="flex items-center justify-between rounded-lg bg-[#111a22] p-3 border border-transparent hover:border-border-dark transition-colors">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="p-2 rounded bg-border-dark/50 text-white">
|
||||
<span class="material-symbols-outlined text-[20px]">share</span>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-sm font-bold text-white">NFS Service</p>
|
||||
<p class="text-xs text-text-secondary">Unix file sharing</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<span class="px-2 py-0.5 rounded text-[10px] font-bold bg-green-500/20 text-green-500 border border-green-500/20">RUNNING</span>
|
||||
<div class="relative inline-block w-10 mr-2 align-middle select-none transition duration-200 ease-in">
|
||||
<input checked="" class="toggle-checkbox absolute block w-5 h-5 rounded-full bg-white border-4 appearance-none cursor-pointer checked:right-0 checked:border-primary transition-all duration-300" id="nfs-toggle" name="toggle" type="checkbox"/>
|
||||
<label class="toggle-label block overflow-hidden h-5 rounded-full bg-border-dark cursor-pointer transition-colors duration-300" for="nfs-toggle"></label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Date & Time Card -->
|
||||
<div class="flex flex-col rounded-xl border border-border-dark bg-card-dark shadow-sm">
|
||||
<div class="flex items-center justify-between border-b border-border-dark px-6 py-4">
|
||||
<div class="flex items-center gap-3">
|
||||
<span class="material-symbols-outlined text-primary">schedule</span>
|
||||
<h2 class="text-lg font-bold text-white">Date & Time</h2>
|
||||
</div>
|
||||
<span class="text-xs font-mono text-text-secondary bg-border-dark px-2 py-1 rounded">UTC</span>
|
||||
</div>
|
||||
<div class="p-6 flex flex-col gap-6">
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<div class="col-span-2">
|
||||
<label class="mb-2 block text-xs font-medium text-text-secondary uppercase">System Timezone</label>
|
||||
<div class="relative">
|
||||
<select class="block w-full rounded-lg border-border-dark bg-[#111a22] py-2.5 pl-3 pr-10 text-sm text-white focus:border-primary focus:ring-1 focus:ring-primary appearance-none">
|
||||
<option>Etc/UTC</option>
|
||||
<option>America/New_York</option>
|
||||
<option>Europe/London</option>
|
||||
<option>Asia/Tokyo</option>
|
||||
</select>
|
||||
<div class="pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-white">
|
||||
<span class="material-symbols-outlined text-sm">expand_more</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="flex items-center justify-between mb-2">
|
||||
<label class="block text-xs font-medium text-text-secondary uppercase">NTP Servers</label>
|
||||
<button class="text-xs text-primary font-bold hover:text-white flex items-center gap-1">
|
||||
<span class="material-symbols-outlined text-[14px]">add</span> Add Server
|
||||
</button>
|
||||
</div>
|
||||
<div class="flex flex-col gap-2">
|
||||
<div class="flex items-center justify-between rounded-lg bg-[#111a22] p-3 border border-border-dark">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="h-2 w-2 rounded-full bg-green-500 animate-pulse"></div>
|
||||
<span class="text-sm font-mono text-white">pool.ntp.org</span>
|
||||
</div>
|
||||
<span class="text-xs text-text-secondary">Stratum 2 • 12ms</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between rounded-lg bg-[#111a22] p-3 border border-border-dark">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="h-2 w-2 rounded-full bg-green-500"></div>
|
||||
<span class="text-sm font-mono text-white">time.google.com</span>
|
||||
</div>
|
||||
<span class="text-xs text-text-secondary">Stratum 1 • 45ms</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Management & SNMP Card -->
|
||||
<div class="flex flex-col rounded-xl border border-border-dark bg-card-dark shadow-sm">
|
||||
<div class="flex items-center justify-between border-b border-border-dark px-6 py-4">
|
||||
<div class="flex items-center gap-3">
|
||||
<span class="material-symbols-outlined text-primary">hub</span>
|
||||
<h2 class="text-lg font-bold text-white">Management</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-6 flex flex-col gap-6">
|
||||
<div>
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<div>
|
||||
<h3 class="text-sm font-bold text-white">SNMP Monitoring</h3>
|
||||
<p class="text-xs text-text-secondary">Enable Simple Network Management Protocol</p>
|
||||
</div>
|
||||
<div class="relative inline-block w-10 align-middle select-none transition duration-200 ease-in">
|
||||
<input class="toggle-checkbox absolute block w-5 h-5 rounded-full bg-white border-4 appearance-none cursor-pointer checked:right-0 checked:border-primary transition-all duration-300" id="snmp-toggle" name="toggle" type="checkbox"/>
|
||||
<label class="toggle-label block overflow-hidden h-5 rounded-full bg-border-dark cursor-pointer transition-colors duration-300" for="snmp-toggle"></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-1 gap-4 opacity-50 pointer-events-none" id="snmp-settings">
|
||||
<div>
|
||||
<label class="mb-1.5 block text-xs font-medium text-text-secondary uppercase">Community String</label>
|
||||
<input class="block w-full rounded-lg border-border-dark bg-[#111a22] p-2.5 text-sm text-white placeholder-gray-500 focus:border-primary focus:ring-1 focus:ring-primary" placeholder="e.g. public" type="text" value="public"/>
|
||||
</div>
|
||||
<div>
|
||||
<label class="mb-1.5 block text-xs font-medium text-text-secondary uppercase">Trap Receiver IP</label>
|
||||
<input class="block w-full rounded-lg border-border-dark bg-[#111a22] p-2.5 text-sm text-white placeholder-gray-500 focus:border-primary focus:ring-1 focus:ring-primary" placeholder="e.g. 192.168.1.100" type="text"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="border-t border-border-dark pt-4">
|
||||
<h3 class="text-sm font-bold text-white mb-3">Syslog Forwarding</h3>
|
||||
<div class="flex gap-2">
|
||||
<input class="flex-1 rounded-lg border-border-dark bg-[#111a22] p-2.5 text-sm text-white placeholder-gray-500 focus:border-primary focus:ring-1 focus:ring-primary" placeholder="Syslog Server Address (UDP:514)" type="text"/>
|
||||
<button class="rounded-lg bg-border-dark px-4 py-2 text-sm font-bold text-white hover:bg-[#2f455a] transition-colors">Test</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Bottom Spacer -->
|
||||
<div class="h-10"></div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
<script>
|
||||
// Simple script to toggle opacity of SNMP settings for visual feedback
|
||||
const snmpToggle = document.getElementById('snmp-toggle');
|
||||
const snmpSettings = document.getElementById('snmp-settings');
|
||||
|
||||
snmpToggle.addEventListener('change', function() {
|
||||
if(this.checked) {
|
||||
snmpSettings.classList.remove('opacity-50', 'pointer-events-none');
|
||||
} else {
|
||||
snmpSettings.classList.add('opacity-50', 'pointer-events-none');
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body></html>
|
||||
BIN
src/web/system-management.png
Normal file
|
After Width: | Height: | Size: 307 KiB |
453
src/web/system-monitoring-code.html
Normal file
@@ -0,0 +1,453 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html class="dark" lang="en"><head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
|
||||
<title>Backup Appliance - Monitoring & Logs</title>
|
||||
<!-- Material Symbols -->
|
||||
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap" rel="stylesheet"/>
|
||||
<!-- Google Fonts: Manrope -->
|
||||
<link href="https://fonts.googleapis.com" rel="preconnect"/>
|
||||
<link crossorigin="" href="https://fonts.gstatic.com" rel="preconnect"/>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Manrope:wght@200..800&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet"/>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap" rel="stylesheet"/>
|
||||
<!-- Tailwind CSS -->
|
||||
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
|
||||
<script id="tailwind-config">
|
||||
tailwind.config = {
|
||||
darkMode: "class",
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
"primary": "#137fec",
|
||||
"background-light": "#f6f7f8",
|
||||
"background-dark": "#111a22", /* Matching the example code background */
|
||||
"card-dark": "#1a2632", /* Slightly lighter than bg */
|
||||
"border-dark": "#324d67",
|
||||
"text-secondary": "#92adc9",
|
||||
},
|
||||
fontFamily: {
|
||||
"display": ["Manrope", "sans-serif"],
|
||||
"mono": ["JetBrains Mono", "monospace"],
|
||||
},
|
||||
borderRadius: {"DEFAULT": "0.25rem", "lg": "0.5rem", "xl": "0.75rem", "full": "9999px"},
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
/* Custom scrollbar for log viewer */
|
||||
.custom-scrollbar::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
}
|
||||
.custom-scrollbar::-webkit-scrollbar-track {
|
||||
background: #111a22;
|
||||
}
|
||||
.custom-scrollbar::-webkit-scrollbar-thumb {
|
||||
background: #324d67;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.custom-scrollbar::-webkit-scrollbar-thumb:hover {
|
||||
background: #476685;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-background-light dark:bg-background-dark text-slate-900 dark:text-white font-display overflow-hidden">
|
||||
<div class="flex h-screen w-full">
|
||||
<!-- SIDEBAR -->
|
||||
<aside class="w-64 flex flex-col border-r border-border-dark bg-background-dark flex-shrink-0 z-20">
|
||||
<div class="p-6 flex flex-col gap-1">
|
||||
<h1 class="text-white text-lg font-bold leading-normal tracking-tight">Backup Appliance</h1>
|
||||
<p class="text-text-secondary text-xs font-mono">v4.2.0-stable</p>
|
||||
</div>
|
||||
<nav class="flex-1 overflow-y-auto px-4 space-y-2">
|
||||
<a class="flex items-center gap-3 px-3 py-2 rounded-lg text-text-secondary hover:bg-card-dark hover:text-white transition-colors" href="#">
|
||||
<span class="material-symbols-outlined text-[24px]">dashboard</span>
|
||||
<span class="text-sm font-medium">Dashboard</span>
|
||||
</a>
|
||||
<a class="flex items-center gap-3 px-3 py-2 rounded-lg text-text-secondary hover:bg-card-dark hover:text-white transition-colors" href="#">
|
||||
<span class="material-symbols-outlined text-[24px]">hard_drive</span>
|
||||
<span class="text-sm font-medium">Storage</span>
|
||||
</a>
|
||||
<a class="flex items-center gap-3 px-3 py-2 rounded-lg text-text-secondary hover:bg-card-dark hover:text-white transition-colors" href="#">
|
||||
<span class="material-symbols-outlined text-[24px]">network_check</span>
|
||||
<span class="text-sm font-medium">Network</span>
|
||||
</a>
|
||||
<!-- Active State -->
|
||||
<a class="flex items-center gap-3 px-3 py-2 rounded-lg bg-[#233648] text-primary border border-primary/20" href="#">
|
||||
<span class="material-symbols-outlined text-[24px] fill-current">monitoring</span>
|
||||
<span class="text-sm font-bold">Monitor & Logs</span>
|
||||
</a>
|
||||
<a class="flex items-center gap-3 px-3 py-2 rounded-lg text-text-secondary hover:bg-card-dark hover:text-white transition-colors" href="#">
|
||||
<span class="material-symbols-outlined text-[24px]">settings</span>
|
||||
<span class="text-sm font-medium">Settings</span>
|
||||
</a>
|
||||
</nav>
|
||||
<div class="p-4 border-t border-border-dark">
|
||||
<div class="flex items-center gap-3 p-2 rounded-lg bg-card-dark border border-border-dark">
|
||||
<div class="h-8 w-8 rounded-full bg-primary flex items-center justify-center text-white font-bold text-xs">AD</div>
|
||||
<div class="flex flex-col">
|
||||
<span class="text-xs font-bold text-white">Admin User</span>
|
||||
<span class="text-[10px] text-text-secondary">admin@local</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
<!-- MAIN CONTENT -->
|
||||
<main class="flex-1 flex flex-col min-w-0 bg-background-dark overflow-hidden relative">
|
||||
<!-- HEADER -->
|
||||
<header class="flex-none px-6 py-5 border-b border-border-dark bg-background-dark/95 backdrop-blur z-10">
|
||||
<div class="flex flex-wrap justify-between items-end gap-3 max-w-[1600px] mx-auto">
|
||||
<div class="flex flex-col gap-1">
|
||||
<h2 class="text-white text-3xl font-black tracking-tight">System Monitor</h2>
|
||||
<p class="text-text-secondary text-sm">Real-time telemetry, ZFS health, and system event logs</p>
|
||||
</div>
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="flex items-center gap-2 px-3 py-2 bg-card-dark rounded-lg border border-border-dark">
|
||||
<span class="relative flex h-2 w-2">
|
||||
<span class="animate-ping absolute inline-flex h-full w-full rounded-full bg-emerald-400 opacity-75"></span>
|
||||
<span class="relative inline-flex rounded-full h-2 w-2 bg-emerald-500"></span>
|
||||
</span>
|
||||
<span class="text-xs font-medium text-emerald-400">System Healthy</span>
|
||||
</div>
|
||||
<button class="flex items-center gap-2 h-10 px-4 bg-card-dark hover:bg-[#233648] border border-border-dark text-white text-sm font-bold rounded-lg transition-colors">
|
||||
<span class="material-symbols-outlined text-[18px]">refresh</span>
|
||||
<span>Refresh: 5s</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<!-- SCROLLABLE CONTENT AREA -->
|
||||
<div class="flex-1 overflow-y-auto custom-scrollbar p-6">
|
||||
<div class="flex flex-col gap-6 max-w-[1600px] mx-auto pb-10">
|
||||
<!-- TOP STATS ROW -->
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
|
||||
<!-- CPU -->
|
||||
<div class="flex flex-col gap-2 rounded-xl p-5 border border-border-dark bg-card-dark">
|
||||
<div class="flex justify-between items-start">
|
||||
<p class="text-text-secondary text-sm font-medium">CPU Load</p>
|
||||
<span class="material-symbols-outlined text-text-secondary text-[20px]">memory</span>
|
||||
</div>
|
||||
<div class="flex items-end gap-3 mt-1">
|
||||
<p class="text-white text-3xl font-bold">12%</p>
|
||||
<span class="text-emerald-500 text-sm font-medium mb-1 flex items-center">
|
||||
<span class="material-symbols-outlined text-[16px]">trending_down</span> 2%
|
||||
</span>
|
||||
</div>
|
||||
<!-- Mini Sparkline visualization -->
|
||||
<div class="h-1.5 w-full bg-[#233648] rounded-full mt-3 overflow-hidden">
|
||||
<div class="h-full bg-primary w-[12%] rounded-full"></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- RAM -->
|
||||
<div class="flex flex-col gap-2 rounded-xl p-5 border border-border-dark bg-card-dark">
|
||||
<div class="flex justify-between items-start">
|
||||
<p class="text-text-secondary text-sm font-medium">RAM Usage</p>
|
||||
<span class="material-symbols-outlined text-text-secondary text-[20px]">memory_alt</span>
|
||||
</div>
|
||||
<div class="flex items-end gap-3 mt-1">
|
||||
<p class="text-white text-3xl font-bold">8.4 <span class="text-lg text-text-secondary font-medium">GB</span></p>
|
||||
<span class="text-text-secondary text-xs mb-2">/ 32 GB</span>
|
||||
</div>
|
||||
<div class="h-1.5 w-full bg-[#233648] rounded-full mt-3 overflow-hidden">
|
||||
<div class="h-full bg-emerald-500 w-[26%] rounded-full"></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- ZFS Health -->
|
||||
<div class="flex flex-col gap-2 rounded-xl p-5 border border-border-dark bg-card-dark">
|
||||
<div class="flex justify-between items-start">
|
||||
<p class="text-text-secondary text-sm font-medium">ZFS Pool Status</p>
|
||||
<span class="material-symbols-outlined text-emerald-500 text-[20px]">check_circle</span>
|
||||
</div>
|
||||
<div class="flex items-end gap-3 mt-1">
|
||||
<p class="text-white text-3xl font-bold">Online</p>
|
||||
<span class="text-text-secondary text-sm font-medium mb-1">No Errors</span>
|
||||
</div>
|
||||
<div class="flex gap-1 mt-3">
|
||||
<div class="h-1.5 flex-1 bg-emerald-500 rounded-l-full"></div>
|
||||
<div class="h-1.5 flex-1 bg-emerald-500"></div>
|
||||
<div class="h-1.5 flex-1 bg-emerald-500"></div>
|
||||
<div class="h-1.5 flex-1 bg-emerald-500 rounded-r-full"></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Uptime -->
|
||||
<div class="flex flex-col gap-2 rounded-xl p-5 border border-border-dark bg-card-dark">
|
||||
<div class="flex justify-between items-start">
|
||||
<p class="text-text-secondary text-sm font-medium">System Uptime</p>
|
||||
<span class="material-symbols-outlined text-text-secondary text-[20px]">schedule</span>
|
||||
</div>
|
||||
<div class="mt-1">
|
||||
<p class="text-white text-3xl font-bold">14d 2h 12m</p>
|
||||
</div>
|
||||
<p class="text-text-secondary text-xs mt-3">Last reboot: Manual Patching</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- MIDDLE SECTION: CHARTS & DISKS -->
|
||||
<div class="grid grid-cols-1 xl:grid-cols-3 gap-6">
|
||||
<!-- CHARTS COLUMN (2/3) -->
|
||||
<div class="xl:col-span-2 flex flex-col gap-6">
|
||||
<!-- Network Chart -->
|
||||
<div class="bg-card-dark border border-border-dark rounded-xl p-6 shadow-sm">
|
||||
<div class="flex justify-between items-center mb-6">
|
||||
<div>
|
||||
<h3 class="text-white text-lg font-bold">Network Throughput</h3>
|
||||
<p class="text-text-secondary text-sm">Inbound vs Outbound (eth0)</p>
|
||||
</div>
|
||||
<div class="text-right">
|
||||
<p class="text-white text-2xl font-bold leading-tight">1.2 Gbps</p>
|
||||
<p class="text-emerald-500 text-sm">Peak: 2.1 Gbps</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="h-[200px] w-full relative">
|
||||
<!-- Simulated SVG Chart -->
|
||||
<svg class="w-full h-full" preserveaspectratio="none" viewbox="0 0 1000 200">
|
||||
<defs>
|
||||
<lineargradient id="gradientPrimary" x1="0" x2="0" y1="0" y2="1">
|
||||
<stop offset="0%" stop-color="#137fec" stop-opacity="0.2"></stop>
|
||||
<stop offset="100%" stop-color="#137fec" stop-opacity="0"></stop>
|
||||
</lineargradient>
|
||||
</defs>
|
||||
<!-- Outbound Line -->
|
||||
<path d="M0,150 Q100,140 200,100 T400,120 T600,80 T800,140 T1000,100" fill="none" stroke="#92adc9" stroke-dasharray="5,5" stroke-width="2"></path>
|
||||
<!-- Inbound Area -->
|
||||
<path d="M0,120 Q150,150 300,50 T600,80 T900,40 L1000,60 V200 H0 Z" fill="url(#gradientPrimary)"></path>
|
||||
<path d="M0,120 Q150,150 300,50 T600,80 T900,40 L1000,60" fill="none" stroke="#137fec" stroke-width="3"></path>
|
||||
</svg>
|
||||
<!-- X-Axis Labels -->
|
||||
<div class="flex justify-between text-text-secondary text-xs mt-2 font-mono">
|
||||
<span>10:00</span>
|
||||
<span>10:15</span>
|
||||
<span>10:30</span>
|
||||
<span>10:45</span>
|
||||
<span>11:00</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- ZFS ARC Chart -->
|
||||
<div class="bg-card-dark border border-border-dark rounded-xl p-6 shadow-sm">
|
||||
<div class="flex justify-between items-center mb-6">
|
||||
<div>
|
||||
<h3 class="text-white text-lg font-bold">ZFS ARC Hit Ratio</h3>
|
||||
<p class="text-text-secondary text-sm">Cache efficiency</p>
|
||||
</div>
|
||||
<div class="text-right">
|
||||
<p class="text-white text-2xl font-bold leading-tight">94%</p>
|
||||
<p class="text-text-secondary text-sm">Target: >90%</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="h-[150px] w-full relative">
|
||||
<!-- Simulated SVG Chart -->
|
||||
<svg class="w-full h-full" preserveaspectratio="none" viewbox="0 0 1000 150">
|
||||
<path d="M0,40 L100,40 L105,80 L110,40 L300,35 L305,90 L310,35 L600,30 L605,100 L610,30 L1000,25" fill="none" stroke="#10b981" stroke-width="2"></path>
|
||||
</svg>
|
||||
<div class="w-full h-[1px] bg-border-dark absolute top-[20%]"></div>
|
||||
<div class="absolute top-[20%] right-0 text-xs text-text-secondary -mt-5">95%</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- DISK HEATMAP COLUMN (1/3) -->
|
||||
<div class="flex flex-col gap-6">
|
||||
<div class="bg-card-dark border border-border-dark rounded-xl p-6 h-full shadow-sm flex flex-col">
|
||||
<div class="flex justify-between items-center mb-4">
|
||||
<h3 class="text-white text-lg font-bold">Disk Health</h3>
|
||||
<span class="bg-[#233648] text-white text-xs px-2 py-1 rounded border border-border-dark">Pool 1</span>
|
||||
</div>
|
||||
<div class="grid grid-cols-4 gap-3 flex-1 content-start">
|
||||
<!-- Healthy Disks -->
|
||||
<div class="aspect-square bg-[#1a2e22] border border-emerald-800 rounded flex flex-col items-center justify-center group relative cursor-help">
|
||||
<span class="material-symbols-outlined text-emerald-500">hard_drive</span>
|
||||
<span class="text-[10px] text-emerald-500 font-mono mt-1">da0</span>
|
||||
<div class="absolute bottom-full mb-2 hidden group-hover:block bg-black text-white text-xs p-2 rounded whitespace-nowrap z-10">Serial: Z802JKA</div>
|
||||
</div>
|
||||
<div class="aspect-square bg-[#1a2e22] border border-emerald-800 rounded flex flex-col items-center justify-center">
|
||||
<span class="material-symbols-outlined text-emerald-500">hard_drive</span>
|
||||
<span class="text-[10px] text-emerald-500 font-mono mt-1">da1</span>
|
||||
</div>
|
||||
<div class="aspect-square bg-[#1a2e22] border border-emerald-800 rounded flex flex-col items-center justify-center">
|
||||
<span class="material-symbols-outlined text-emerald-500">hard_drive</span>
|
||||
<span class="text-[10px] text-emerald-500 font-mono mt-1">da2</span>
|
||||
</div>
|
||||
<div class="aspect-square bg-[#1a2e22] border border-emerald-800 rounded flex flex-col items-center justify-center">
|
||||
<span class="material-symbols-outlined text-emerald-500">hard_drive</span>
|
||||
<span class="text-[10px] text-emerald-500 font-mono mt-1">da3</span>
|
||||
</div>
|
||||
<div class="aspect-square bg-[#1a2e22] border border-emerald-800 rounded flex flex-col items-center justify-center">
|
||||
<span class="material-symbols-outlined text-emerald-500">hard_drive</span>
|
||||
<span class="text-[10px] text-emerald-500 font-mono mt-1">da4</span>
|
||||
</div>
|
||||
<!-- Warning Disk -->
|
||||
<div class="aspect-square bg-[#332a18] border border-yellow-700/50 rounded flex flex-col items-center justify-center relative">
|
||||
<span class="absolute top-1 right-1 h-2 w-2 rounded-full bg-yellow-500 animate-pulse"></span>
|
||||
<span class="material-symbols-outlined text-yellow-500">warning</span>
|
||||
<span class="text-[10px] text-yellow-500 font-mono mt-1">da5</span>
|
||||
</div>
|
||||
<!-- Healthy Disks -->
|
||||
<div class="aspect-square bg-[#1a2e22] border border-emerald-800 rounded flex flex-col items-center justify-center">
|
||||
<span class="material-symbols-outlined text-emerald-500">hard_drive</span>
|
||||
<span class="text-[10px] text-emerald-500 font-mono mt-1">da6</span>
|
||||
</div>
|
||||
<div class="aspect-square bg-[#1a2e22] border border-emerald-800 rounded flex flex-col items-center justify-center">
|
||||
<span class="material-symbols-outlined text-emerald-500">hard_drive</span>
|
||||
<span class="text-[10px] text-emerald-500 font-mono mt-1">da7</span>
|
||||
</div>
|
||||
<!-- Empty/Spare Slots -->
|
||||
<div class="aspect-square bg-[#161f29] border border-border-dark border-dashed rounded flex flex-col items-center justify-center opacity-50">
|
||||
<span class="text-[10px] text-text-secondary font-mono">Empty</span>
|
||||
</div>
|
||||
<div class="aspect-square bg-[#161f29] border border-border-dark border-dashed rounded flex flex-col items-center justify-center opacity-50">
|
||||
<span class="text-[10px] text-text-secondary font-mono">Empty</span>
|
||||
</div>
|
||||
<div class="aspect-square bg-[#161f29] border border-border-dark border-dashed rounded flex flex-col items-center justify-center opacity-50">
|
||||
<span class="text-[10px] text-text-secondary font-mono">Empty</span>
|
||||
</div>
|
||||
<div class="aspect-square bg-[#161f29] border border-border-dark border-dashed rounded flex flex-col items-center justify-center opacity-50">
|
||||
<span class="text-[10px] text-text-secondary font-mono">Empty</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-4 pt-4 border-t border-border-dark">
|
||||
<div class="flex justify-between text-sm text-text-secondary">
|
||||
<span>Total Capacity</span>
|
||||
<span class="text-white font-bold">64 TB</span>
|
||||
</div>
|
||||
<div class="w-full bg-[#233648] h-2 rounded-full mt-2 overflow-hidden">
|
||||
<div class="bg-primary h-full w-[65%]"></div>
|
||||
</div>
|
||||
<div class="flex justify-between text-xs text-text-secondary mt-1">
|
||||
<span>Used: 41.6 TB</span>
|
||||
<span>Free: 22.4 TB</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- BOTTOM SECTION: TABS & LOGS -->
|
||||
<div class="bg-card-dark border border-border-dark rounded-xl shadow-sm overflow-hidden flex flex-col h-[400px]">
|
||||
<!-- Tabs Header -->
|
||||
<div class="flex border-b border-border-dark bg-[#161f29]">
|
||||
<button class="px-6 py-4 text-sm font-bold text-primary border-b-2 border-primary bg-card-dark">
|
||||
Active Jobs <span class="ml-2 bg-primary/20 text-primary px-1.5 py-0.5 rounded text-xs">2</span>
|
||||
</button>
|
||||
<button class="px-6 py-4 text-sm font-medium text-text-secondary hover:text-white transition-colors">
|
||||
System Logs
|
||||
</button>
|
||||
<button class="px-6 py-4 text-sm font-medium text-text-secondary hover:text-white transition-colors">
|
||||
Alerts History
|
||||
</button>
|
||||
<div class="flex-1 flex justify-end items-center px-4">
|
||||
<div class="relative">
|
||||
<span class="material-symbols-outlined absolute left-2 top-1.5 text-text-secondary text-[18px]">search</span>
|
||||
<input class="bg-[#111a22] border border-border-dark rounded-md py-1 pl-8 pr-3 text-sm text-white focus:outline-none focus:border-primary w-48 transition-all" placeholder="Search logs..." type="text"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Tab Content: Active Jobs + Logs Combined View for design -->
|
||||
<div class="flex-1 overflow-hidden flex flex-col">
|
||||
<!-- Jobs Section -->
|
||||
<div class="p-0">
|
||||
<table class="w-full text-left border-collapse">
|
||||
<thead class="bg-[#1a2632] text-xs uppercase text-text-secondary font-medium sticky top-0 z-10">
|
||||
<tr>
|
||||
<th class="px-6 py-3 border-b border-border-dark">Job Name</th>
|
||||
<th class="px-6 py-3 border-b border-border-dark">Type</th>
|
||||
<th class="px-6 py-3 border-b border-border-dark w-1/3">Progress</th>
|
||||
<th class="px-6 py-3 border-b border-border-dark">Speed</th>
|
||||
<th class="px-6 py-3 border-b border-border-dark">Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="text-sm divide-y divide-border-dark">
|
||||
<!-- Active Job 1 -->
|
||||
<tr class="group hover:bg-[#233648] transition-colors">
|
||||
<td class="px-6 py-4 font-medium text-white">Daily Backup: VM-Cluster-01</td>
|
||||
<td class="px-6 py-4 text-text-secondary">Replication</td>
|
||||
<td class="px-6 py-4">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-full bg-[#111a22] rounded-full h-2 overflow-hidden">
|
||||
<div class="bg-primary h-full rounded-full w-[45%] relative overflow-hidden">
|
||||
<div class="absolute inset-0 bg-white/20 animate-[pulse_2s_infinite]"></div>
|
||||
</div>
|
||||
</div>
|
||||
<span class="text-xs font-mono text-white">45%</span>
|
||||
</div>
|
||||
<p class="text-[10px] text-text-secondary mt-1">ETA: 1h 12m</p>
|
||||
</td>
|
||||
<td class="px-6 py-4 text-text-secondary font-mono">145 MB/s</td>
|
||||
<td class="px-6 py-4">
|
||||
<span class="inline-flex items-center px-2 py-1 rounded text-xs font-medium bg-primary/20 text-primary">
|
||||
Running
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- Active Job 2 -->
|
||||
<tr class="group hover:bg-[#233648] transition-colors">
|
||||
<td class="px-6 py-4 font-medium text-white">ZFS Scrub: Pool-01</td>
|
||||
<td class="px-6 py-4 text-text-secondary">Maintenance</td>
|
||||
<td class="px-6 py-4">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-full bg-[#111a22] rounded-full h-2 overflow-hidden">
|
||||
<div class="bg-primary h-full rounded-full w-[78%] relative overflow-hidden"></div>
|
||||
</div>
|
||||
<span class="text-xs font-mono text-white">78%</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-6 py-4 text-text-secondary font-mono">1.2 GB/s</td>
|
||||
<td class="px-6 py-4">
|
||||
<span class="inline-flex items-center px-2 py-1 rounded text-xs font-medium bg-primary/20 text-primary">
|
||||
Running
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<!-- Logs Section Header (Visual Separator) -->
|
||||
<div class="px-6 py-2 bg-[#161f29] border-y border-border-dark flex items-center justify-between">
|
||||
<h4 class="text-xs uppercase text-text-secondary font-bold tracking-wider">Recent System Events</h4>
|
||||
<button class="text-xs text-primary hover:text-white transition-colors">View All Logs</button>
|
||||
</div>
|
||||
<!-- Logs Table -->
|
||||
<div class="flex-1 overflow-y-auto custom-scrollbar bg-[#111a22]">
|
||||
<table class="w-full text-left border-collapse">
|
||||
<tbody class="text-sm font-mono divide-y divide-border-dark/50">
|
||||
<tr class="group hover:bg-[#233648] transition-colors">
|
||||
<td class="px-6 py-2 text-text-secondary w-32 whitespace-nowrap">10:45:22</td>
|
||||
<td class="px-6 py-2 w-24">
|
||||
<span class="text-emerald-500">INFO</span>
|
||||
</td>
|
||||
<td class="px-6 py-2 w-32 text-white">systemd</td>
|
||||
<td class="px-6 py-2 text-text-secondary truncate max-w-lg">Started User Manager for UID 1000.</td>
|
||||
</tr>
|
||||
<tr class="group hover:bg-[#233648] transition-colors">
|
||||
<td class="px-6 py-2 text-text-secondary w-32 whitespace-nowrap">10:45:15</td>
|
||||
<td class="px-6 py-2 w-24">
|
||||
<span class="text-yellow-500">WARN</span>
|
||||
</td>
|
||||
<td class="px-6 py-2 w-32 text-white">smartd</td>
|
||||
<td class="px-6 py-2 text-text-secondary truncate max-w-lg">Device: /dev/ada5, SMART Usage Attribute: 194 Temperature_Celsius changed from 38 to 41</td>
|
||||
</tr>
|
||||
<tr class="group hover:bg-[#233648] transition-colors">
|
||||
<td class="px-6 py-2 text-text-secondary w-32 whitespace-nowrap">10:44:58</td>
|
||||
<td class="px-6 py-2 w-24">
|
||||
<span class="text-emerald-500">INFO</span>
|
||||
</td>
|
||||
<td class="px-6 py-2 w-32 text-white">kernel</td>
|
||||
<td class="px-6 py-2 text-text-secondary truncate max-w-lg">ix0: link state changed to UP</td>
|
||||
</tr>
|
||||
<tr class="group hover:bg-[#233648] transition-colors">
|
||||
<td class="px-6 py-2 text-text-secondary w-32 whitespace-nowrap">10:42:10</td>
|
||||
<td class="px-6 py-2 w-24">
|
||||
<span class="text-emerald-500">INFO</span>
|
||||
</td>
|
||||
<td class="px-6 py-2 w-32 text-white">zfs</td>
|
||||
<td class="px-6 py-2 text-text-secondary truncate max-w-lg">zfs_arc_reclaim_thread: reclaiming 157286400 bytes ...</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</body></html>
|
||||
BIN
src/web/system-monitoring.png
Normal file
|
After Width: | Height: | Size: 272 KiB |
400
src/web/user-access-management-code.html
Normal file
@@ -0,0 +1,400 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html class="dark" lang="en"><head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
|
||||
<title>User & Access Management - Backup Appliance</title>
|
||||
<!-- Google Fonts: Manrope -->
|
||||
<link href="https://fonts.googleapis.com" rel="preconnect"/>
|
||||
<link crossorigin="" href="https://fonts.gstatic.com" rel="preconnect"/>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Manrope:wght@200..800&display=swap" rel="stylesheet"/>
|
||||
<!-- Material Symbols -->
|
||||
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap" rel="stylesheet"/>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap" rel="stylesheet"/>
|
||||
<!-- Tailwind CSS -->
|
||||
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
|
||||
<!-- Theme Configuration -->
|
||||
<script id="tailwind-config">
|
||||
tailwind.config = {
|
||||
darkMode: "class",
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
"primary": "#137fec",
|
||||
"background-light": "#f6f7f8",
|
||||
"background-dark": "#101922",
|
||||
"surface-dark": "#1c2630",
|
||||
"surface-darker": "#111a22",
|
||||
"border-dark": "#324d67",
|
||||
},
|
||||
fontFamily: {
|
||||
"display": ["Manrope", "sans-serif"]
|
||||
},
|
||||
borderRadius: { "DEFAULT": "0.25rem", "lg": "0.5rem", "xl": "0.75rem", "full": "9999px" },
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
/* Custom scrollbar for dark mode cockpit feel */
|
||||
::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
}
|
||||
::-webkit-scrollbar-track {
|
||||
background: #101922;
|
||||
}
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: #324d67;
|
||||
border-radius: 4px;
|
||||
}
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: #137fec;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-background-light dark:bg-background-dark text-slate-900 dark:text-white font-display overflow-hidden h-screen w-full flex">
|
||||
<!-- Sidebar -->
|
||||
<aside class="w-64 h-full bg-surface-darker flex flex-col border-r border-border-dark flex-shrink-0 z-20">
|
||||
<div class="p-6 flex flex-col gap-6">
|
||||
<!-- Appliance Identity -->
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="bg-primary/20 p-2 rounded-lg">
|
||||
<span class="material-symbols-outlined text-primary text-3xl">dns</span>
|
||||
</div>
|
||||
<div class="flex flex-col">
|
||||
<h1 class="text-white text-base font-bold leading-tight">Backup Appliance</h1>
|
||||
<p class="text-slate-400 text-xs font-medium">Host: node-01.local</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Navigation -->
|
||||
<nav class="flex flex-col gap-2">
|
||||
<a class="flex items-center gap-3 px-3 py-2.5 rounded-lg text-slate-300 hover:bg-surface-dark hover:text-white transition-colors group" href="#">
|
||||
<span class="material-symbols-outlined group-hover:text-primary transition-colors">dashboard</span>
|
||||
<span class="text-sm font-medium">Dashboard</span>
|
||||
</a>
|
||||
<a class="flex items-center gap-3 px-3 py-2.5 rounded-lg text-slate-300 hover:bg-surface-dark hover:text-white transition-colors group" href="#">
|
||||
<span class="material-symbols-outlined group-hover:text-primary transition-colors">hard_drive</span>
|
||||
<span class="text-sm font-medium">Storage</span>
|
||||
</a>
|
||||
<a class="flex items-center gap-3 px-3 py-2.5 rounded-lg text-slate-300 hover:bg-surface-dark hover:text-white transition-colors group" href="#">
|
||||
<span class="material-symbols-outlined group-hover:text-primary transition-colors">lan</span>
|
||||
<span class="text-sm font-medium">Network</span>
|
||||
</a>
|
||||
<!-- Active State -->
|
||||
<a class="flex items-center gap-3 px-3 py-2.5 rounded-lg bg-primary/10 text-primary border border-primary/20" href="#">
|
||||
<span class="material-symbols-outlined fill-1">manage_accounts</span>
|
||||
<span class="text-sm font-bold">User & Access</span>
|
||||
</a>
|
||||
<a class="flex items-center gap-3 px-3 py-2.5 rounded-lg text-slate-300 hover:bg-surface-dark hover:text-white transition-colors group" href="#">
|
||||
<span class="material-symbols-outlined group-hover:text-primary transition-colors">security</span>
|
||||
<span class="text-sm font-medium">Data Protection</span>
|
||||
</a>
|
||||
<a class="flex items-center gap-3 px-3 py-2.5 rounded-lg text-slate-300 hover:bg-surface-dark hover:text-white transition-colors group" href="#">
|
||||
<span class="material-symbols-outlined group-hover:text-primary transition-colors">settings</span>
|
||||
<span class="text-sm font-medium">System</span>
|
||||
</a>
|
||||
</nav>
|
||||
</div>
|
||||
<!-- User Profile (Bottom Sidebar) -->
|
||||
<div class="mt-auto p-4 border-t border-border-dark">
|
||||
<div class="flex items-center gap-3 px-2 py-2 rounded-lg hover:bg-surface-dark cursor-pointer transition-colors">
|
||||
<div class="h-8 w-8 rounded-full bg-cover bg-center ring-2 ring-border-dark" data-alt="Administrator profile picture" style="background-image: url('https://lh3.googleusercontent.com/aida-public/AB6AXuDzrQIWpC-TosfbyD0BB4efX7Qu00RduKrfteJ7r7YTjzmO5t98e3qOPYXvr-Zjxa_fzls8Vqy3Hl1Pfh01M45iBNGvfTswlOkJk9PDvJVHmngkOauGp61DKXrkfvVOymrFoPmFYGfx1o5Lxv1H078E95PFapYKZVO9Dh_0319rQLN4KFjOhjY4VDWOARbEKkbjGfT2reaOHVXhkc9A3XRRhd4opmYGmUrR68VVk0SOQ_2eFoZd69WnYjLTa44FoyzvpOE7Mps_JLg');"></div>
|
||||
<div class="flex flex-col min-w-0">
|
||||
<span class="text-sm font-semibold text-white truncate">Admin User</span>
|
||||
<span class="text-xs text-slate-400 truncate">System Administrator</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
<!-- Main Content Area -->
|
||||
<main class="flex-1 flex flex-col h-full overflow-hidden bg-background-dark">
|
||||
<!-- Scrollable content -->
|
||||
<div class="flex-1 overflow-y-auto">
|
||||
<div class="max-w-[1200px] mx-auto w-full p-8 flex flex-col gap-6">
|
||||
<!-- Page Header -->
|
||||
<header class="flex flex-wrap justify-between items-end gap-4 border-b border-border-dark pb-6">
|
||||
<div class="flex flex-col gap-2">
|
||||
<nav class="flex items-center gap-2 text-sm text-slate-400 mb-1">
|
||||
<span>System</span>
|
||||
<span class="material-symbols-outlined text-[16px]">chevron_right</span>
|
||||
<span class="text-white">Access Control</span>
|
||||
</nav>
|
||||
<h1 class="text-3xl font-black text-white leading-tight">User & Access Management</h1>
|
||||
<p class="text-slate-400 text-base max-w-2xl">Manage local accounts, define RBAC roles, and configure directory services (LDAP/AD) integration.</p>
|
||||
</div>
|
||||
<div class="flex gap-3">
|
||||
<button class="flex items-center justify-center gap-2 px-4 py-2 bg-surface-dark border border-border-dark rounded-lg text-white hover:bg-border-dark transition-colors font-semibold">
|
||||
<span class="material-symbols-outlined text-[20px]">history</span>
|
||||
Audit Log
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
<!-- Content Container -->
|
||||
<div class="flex flex-col gap-6">
|
||||
<!-- Tabs -->
|
||||
<div class="flex border-b border-border-dark gap-8">
|
||||
<button class="flex items-center gap-2 pb-3 border-b-[3px] border-primary text-white hover:text-white transition-colors">
|
||||
<span class="material-symbols-outlined text-[20px]">group</span>
|
||||
<span class="text-sm font-bold">Local Users & Groups</span>
|
||||
</button>
|
||||
<button class="flex items-center gap-2 pb-3 border-b-[3px] border-transparent text-slate-400 hover:text-white hover:border-slate-600 transition-colors">
|
||||
<span class="material-symbols-outlined text-[20px]">badge</span>
|
||||
<span class="text-sm font-bold">Directory Services</span>
|
||||
</button>
|
||||
<button class="flex items-center gap-2 pb-3 border-b-[3px] border-transparent text-slate-400 hover:text-white hover:border-slate-600 transition-colors">
|
||||
<span class="material-symbols-outlined text-[20px]">lock</span>
|
||||
<span class="text-sm font-bold">Authentication & SSO</span>
|
||||
</button>
|
||||
</div>
|
||||
<!-- Toolbar Area -->
|
||||
<div class="flex flex-wrap gap-4 items-center justify-between">
|
||||
<!-- Search & Filter -->
|
||||
<div class="flex flex-1 max-w-xl gap-3">
|
||||
<div class="relative flex-1">
|
||||
<span class="material-symbols-outlined absolute left-3 top-1/2 -translate-y-1/2 text-slate-400">search</span>
|
||||
<input class="w-full bg-surface-dark border border-border-dark rounded-lg pl-10 pr-4 py-2.5 text-white placeholder-slate-400 focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent text-sm" placeholder="Search users by name, role, or group..." type="text"/>
|
||||
</div>
|
||||
<button class="flex items-center gap-2 px-4 py-2.5 bg-surface-dark border border-border-dark rounded-lg text-slate-300 hover:text-white hover:border-slate-500 transition-colors">
|
||||
<span class="material-symbols-outlined text-[20px]">filter_list</span>
|
||||
<span class="text-sm font-medium">Filter</span>
|
||||
</button>
|
||||
</div>
|
||||
<!-- Primary Action -->
|
||||
<button class="flex items-center gap-2 bg-primary hover:bg-blue-600 text-white px-5 py-2.5 rounded-lg font-bold shadow-lg shadow-blue-500/20 transition-all">
|
||||
<span class="material-symbols-outlined text-[20px]">person_add</span>
|
||||
Create User
|
||||
</button>
|
||||
</div>
|
||||
<!-- Users Table -->
|
||||
<div class="rounded-xl border border-border-dark bg-surface-darker overflow-hidden shadow-sm">
|
||||
<div class="overflow-x-auto">
|
||||
<table class="w-full">
|
||||
<thead>
|
||||
<tr class="bg-surface-dark border-b border-border-dark text-left">
|
||||
<th class="px-6 py-4 text-xs font-bold text-slate-400 uppercase tracking-wider w-24">Status</th>
|
||||
<th class="px-6 py-4 text-xs font-bold text-slate-400 uppercase tracking-wider">Username</th>
|
||||
<th class="px-6 py-4 text-xs font-bold text-slate-400 uppercase tracking-wider">Full Name</th>
|
||||
<th class="px-6 py-4 text-xs font-bold text-slate-400 uppercase tracking-wider">Role</th>
|
||||
<th class="px-6 py-4 text-xs font-bold text-slate-400 uppercase tracking-wider">Groups</th>
|
||||
<th class="px-6 py-4 text-xs font-bold text-slate-400 uppercase tracking-wider">Last Login</th>
|
||||
<th class="px-6 py-4 text-xs font-bold text-slate-400 uppercase tracking-wider text-right">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-border-dark">
|
||||
<!-- Row 1: Active Admin -->
|
||||
<tr class="group hover:bg-surface-dark transition-colors">
|
||||
<td class="px-6 py-4">
|
||||
<div class="inline-flex items-center gap-2 px-2.5 py-1 rounded-full bg-green-500/10 text-green-500 text-xs font-bold border border-green-500/20">
|
||||
<span class="w-1.5 h-1.5 rounded-full bg-green-500 animate-pulse"></span>
|
||||
Active
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-6 py-4">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-8 h-8 rounded-full bg-gradient-to-br from-blue-500 to-indigo-600 flex items-center justify-center text-white text-xs font-bold" data-alt="Avatar gradient">AD</div>
|
||||
<span class="text-white font-medium">admin</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-6 py-4 text-slate-300 text-sm">System Administrator</td>
|
||||
<td class="px-6 py-4">
|
||||
<span class="inline-flex items-center gap-1.5 text-xs font-medium px-2.5 py-1 rounded-md bg-purple-500/10 text-purple-400 border border-purple-500/20">
|
||||
<span class="material-symbols-outlined text-[14px]">verified_user</span>
|
||||
Superuser
|
||||
</span>
|
||||
</td>
|
||||
<td class="px-6 py-4 text-slate-400 text-sm">wheel, system</td>
|
||||
<td class="px-6 py-4 text-slate-400 text-sm">Just now</td>
|
||||
<td class="px-6 py-4 text-right">
|
||||
<button class="p-2 text-slate-400 hover:text-white hover:bg-border-dark rounded-lg transition-colors">
|
||||
<span class="material-symbols-outlined text-[20px]">more_vert</span>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- Row 2: Operator -->
|
||||
<tr class="group hover:bg-surface-dark transition-colors">
|
||||
<td class="px-6 py-4">
|
||||
<div class="inline-flex items-center gap-2 px-2.5 py-1 rounded-full bg-green-500/10 text-green-500 text-xs font-bold border border-green-500/20">
|
||||
<span class="w-1.5 h-1.5 rounded-full bg-green-500"></span>
|
||||
Active
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-6 py-4">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-8 h-8 rounded-full bg-slate-700 flex items-center justify-center text-slate-300 text-xs font-bold" data-alt="Avatar placeholder">JD</div>
|
||||
<span class="text-white font-medium">jdoe</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-6 py-4 text-slate-300 text-sm">John Doe</td>
|
||||
<td class="px-6 py-4">
|
||||
<span class="inline-flex items-center gap-1.5 text-xs font-medium px-2.5 py-1 rounded-md bg-blue-500/10 text-blue-400 border border-blue-500/20">
|
||||
<span class="material-symbols-outlined text-[14px]">engineering</span>
|
||||
Operator
|
||||
</span>
|
||||
</td>
|
||||
<td class="px-6 py-4 text-slate-400 text-sm">operators, backup</td>
|
||||
<td class="px-6 py-4 text-slate-400 text-sm">2 days ago</td>
|
||||
<td class="px-6 py-4 text-right">
|
||||
<button class="p-2 text-slate-400 hover:text-white hover:bg-border-dark rounded-lg transition-colors">
|
||||
<span class="material-symbols-outlined text-[20px]">more_vert</span>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- Row 3: Service Account (Locked) -->
|
||||
<tr class="group hover:bg-surface-dark transition-colors">
|
||||
<td class="px-6 py-4">
|
||||
<div class="inline-flex items-center gap-2 px-2.5 py-1 rounded-full bg-red-500/10 text-red-500 text-xs font-bold border border-red-500/20">
|
||||
<span class="material-symbols-outlined text-[14px]">lock</span>
|
||||
Locked
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-6 py-4">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-8 h-8 rounded-full bg-slate-700 flex items-center justify-center text-slate-300 text-xs font-bold" data-alt="Avatar placeholder">BS</div>
|
||||
<span class="text-white font-medium">backup_svc</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-6 py-4 text-slate-300 text-sm">Backup Service Account</td>
|
||||
<td class="px-6 py-4">
|
||||
<span class="inline-flex items-center gap-1.5 text-xs font-medium px-2.5 py-1 rounded-md bg-slate-700 text-slate-300 border border-slate-600">
|
||||
<span class="material-symbols-outlined text-[14px]">smart_toy</span>
|
||||
Service
|
||||
</span>
|
||||
</td>
|
||||
<td class="px-6 py-4 text-slate-400 text-sm">services</td>
|
||||
<td class="px-6 py-4 text-slate-400 text-sm">Never</td>
|
||||
<td class="px-6 py-4 text-right">
|
||||
<button class="p-2 text-slate-400 hover:text-white hover:bg-border-dark rounded-lg transition-colors">
|
||||
<span class="material-symbols-outlined text-[20px]">more_vert</span>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- Row 4: Auditor -->
|
||||
<tr class="group hover:bg-surface-dark transition-colors">
|
||||
<td class="px-6 py-4">
|
||||
<div class="inline-flex items-center gap-2 px-2.5 py-1 rounded-full bg-green-500/10 text-green-500 text-xs font-bold border border-green-500/20">
|
||||
<span class="w-1.5 h-1.5 rounded-full bg-green-500"></span>
|
||||
Active
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-6 py-4">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-8 h-8 rounded-full bg-slate-700 flex items-center justify-center text-slate-300 text-xs font-bold" data-alt="Avatar placeholder">AS</div>
|
||||
<span class="text-white font-medium">asmith</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-6 py-4 text-slate-300 text-sm">Alice Smith</td>
|
||||
<td class="px-6 py-4">
|
||||
<span class="inline-flex items-center gap-1.5 text-xs font-medium px-2.5 py-1 rounded-md bg-yellow-500/10 text-yellow-500 border border-yellow-500/20">
|
||||
<span class="material-symbols-outlined text-[14px]">visibility</span>
|
||||
Auditor
|
||||
</span>
|
||||
</td>
|
||||
<td class="px-6 py-4 text-slate-400 text-sm">auditors</td>
|
||||
<td class="px-6 py-4 text-slate-400 text-sm">1 week ago</td>
|
||||
<td class="px-6 py-4 text-right">
|
||||
<button class="p-2 text-slate-400 hover:text-white hover:bg-border-dark rounded-lg transition-colors">
|
||||
<span class="material-symbols-outlined text-[20px]">more_vert</span>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- Row 5: Storage Admin -->
|
||||
<tr class="group hover:bg-surface-dark transition-colors">
|
||||
<td class="px-6 py-4">
|
||||
<div class="inline-flex items-center gap-2 px-2.5 py-1 rounded-full bg-green-500/10 text-green-500 text-xs font-bold border border-green-500/20">
|
||||
<span class="w-1.5 h-1.5 rounded-full bg-green-500"></span>
|
||||
Active
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-6 py-4">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-8 h-8 rounded-full bg-slate-700 flex items-center justify-center text-slate-300 text-xs font-bold" data-alt="Avatar placeholder">RR</div>
|
||||
<span class="text-white font-medium">rroe</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-6 py-4 text-slate-300 text-sm">Richard Roe</td>
|
||||
<td class="px-6 py-4">
|
||||
<span class="inline-flex items-center gap-1.5 text-xs font-medium px-2.5 py-1 rounded-md bg-teal-500/10 text-teal-500 border border-teal-500/20">
|
||||
<span class="material-symbols-outlined text-[14px]">storage</span>
|
||||
Storage Admin
|
||||
</span>
|
||||
</td>
|
||||
<td class="px-6 py-4 text-slate-400 text-sm">storage_admins</td>
|
||||
<td class="px-6 py-4 text-slate-400 text-sm">5 hours ago</td>
|
||||
<td class="px-6 py-4 text-right">
|
||||
<button class="p-2 text-slate-400 hover:text-white hover:bg-border-dark rounded-lg transition-colors">
|
||||
<span class="material-symbols-outlined text-[20px]">more_vert</span>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<!-- Pagination -->
|
||||
<div class="px-6 py-4 border-t border-border-dark flex items-center justify-between bg-surface-dark">
|
||||
<span class="text-sm text-slate-400">Showing <span class="font-bold text-white">1-5</span> of <span class="font-bold text-white">24</span> users</span>
|
||||
<div class="flex gap-2">
|
||||
<button class="p-2 rounded-lg text-slate-400 hover:bg-border-dark hover:text-white disabled:opacity-50 disabled:cursor-not-allowed">
|
||||
<span class="material-symbols-outlined text-[20px]">chevron_left</span>
|
||||
</button>
|
||||
<button class="p-2 rounded-lg text-slate-400 hover:bg-border-dark hover:text-white">
|
||||
<span class="material-symbols-outlined text-[20px]">chevron_right</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Info Cards (Simulating Dashboard widgets) -->
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mt-2">
|
||||
<!-- Directory Status -->
|
||||
<div class="bg-surface-darker p-5 rounded-xl border border-border-dark flex flex-col gap-4">
|
||||
<div class="flex justify-between items-start">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="p-2 bg-slate-800 rounded-lg text-slate-300">
|
||||
<span class="material-symbols-outlined">domain</span>
|
||||
</div>
|
||||
<h3 class="text-white font-bold">Directory Service</h3>
|
||||
</div>
|
||||
<span class="px-2 py-1 rounded text-xs font-bold bg-slate-800 text-slate-400 border border-slate-700">Inactive</span>
|
||||
</div>
|
||||
<p class="text-sm text-slate-400">No LDAP or Active Directory server is currently connected. Local authentication is being used.</p>
|
||||
<div class="mt-auto pt-2">
|
||||
<a class="text-primary text-sm font-bold hover:underline flex items-center gap-1" href="#">
|
||||
Configure Directory
|
||||
<span class="material-symbols-outlined text-[16px]">arrow_forward</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<!-- MFA Status -->
|
||||
<div class="bg-surface-darker p-5 rounded-xl border border-border-dark flex flex-col gap-4">
|
||||
<div class="flex justify-between items-start">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="p-2 bg-orange-500/10 rounded-lg text-orange-500">
|
||||
<span class="material-symbols-outlined">shield</span>
|
||||
</div>
|
||||
<h3 class="text-white font-bold">Security Policy</h3>
|
||||
</div>
|
||||
<span class="px-2 py-1 rounded text-xs font-bold bg-green-500/10 text-green-500 border border-green-500/20">Good</span>
|
||||
</div>
|
||||
<div class="flex flex-col gap-2">
|
||||
<div class="flex justify-between items-center text-sm">
|
||||
<span class="text-slate-400">Multi-Factor Auth</span>
|
||||
<span class="text-green-500 font-medium">Enforced</span>
|
||||
</div>
|
||||
<div class="flex justify-between items-center text-sm">
|
||||
<span class="text-slate-400">Password Rotation</span>
|
||||
<span class="text-white font-medium">90 Days</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-auto pt-2">
|
||||
<a class="text-primary text-sm font-bold hover:underline flex items-center gap-1" href="#">
|
||||
Manage Policies
|
||||
<span class="material-symbols-outlined text-[16px]">arrow_forward</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</body></html>
|
||||
BIN
src/web/user-access-management.png
Normal file
|
After Width: | Height: | Size: 308 KiB |
516
src/web/vtl-management-code.html
Normal file
@@ -0,0 +1,516 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html class="dark" lang="en"><head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
|
||||
<title>Virtual Tape Library Management</title>
|
||||
<!-- Tailwind CSS -->
|
||||
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
|
||||
<!-- Google Fonts -->
|
||||
<link href="https://fonts.googleapis.com" rel="preconnect"/>
|
||||
<link crossorigin="" href="https://fonts.gstatic.com" rel="preconnect"/>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&display=swap" rel="stylesheet"/>
|
||||
<!-- Material Symbols -->
|
||||
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap" rel="stylesheet"/>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap" rel="stylesheet"/>
|
||||
<!-- Theme Configuration -->
|
||||
<script id="tailwind-config">
|
||||
tailwind.config = {
|
||||
darkMode: "class",
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
"primary": "#137fec",
|
||||
"background-light": "#f6f7f8",
|
||||
"background-dark": "#101922",
|
||||
"surface-dark": "#1c2834",
|
||||
"border-dark": "#324d67",
|
||||
"text-secondary": "#92adc9",
|
||||
},
|
||||
fontFamily: {
|
||||
"display": ["Manrope", "Noto Sans", "sans-serif"]
|
||||
},
|
||||
borderRadius: {"DEFAULT": "0.25rem", "lg": "0.5rem", "xl": "0.75rem", "full": "9999px"},
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.material-symbols-outlined {
|
||||
font-variation-settings:
|
||||
'FILL' 0,
|
||||
'wght' 400,
|
||||
'GRAD' 0,
|
||||
'opsz' 24;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.material-symbols-filled {
|
||||
font-variation-settings:
|
||||
'FILL' 1,
|
||||
'wght' 400,
|
||||
'GRAD' 0,
|
||||
'opsz' 24;
|
||||
}
|
||||
|
||||
/* Custom scrollbar for dark theme */
|
||||
::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
}
|
||||
::-webkit-scrollbar-track {
|
||||
background: #101922;
|
||||
}
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: #324d67;
|
||||
border-radius: 4px;
|
||||
}
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: #4a6b8c;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-background-light dark:bg-background-dark font-display text-slate-900 dark:text-white overflow-hidden">
|
||||
<div class="flex h-screen w-full">
|
||||
<!-- Sidebar Navigation -->
|
||||
<aside class="flex w-72 flex-col border-r border-border-dark bg-[#111a22] hidden lg:flex shrink-0 z-20">
|
||||
<div class="flex h-full flex-col justify-between p-4">
|
||||
<div class="flex flex-col gap-6">
|
||||
<!-- Appliance Header -->
|
||||
<div class="flex gap-3 items-center px-2">
|
||||
<div class="bg-center bg-no-repeat bg-cover rounded-full size-10 shadow-lg relative overflow-hidden bg-gradient-to-br from-blue-600 to-indigo-900" data-alt="Abstract blue gradient circle representing appliance logo">
|
||||
<div class="absolute inset-0 flex items-center justify-center text-white opacity-80">
|
||||
<span class="material-symbols-outlined text-xl">dns</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col">
|
||||
<h1 class="text-white text-base font-bold leading-tight">Cockpit Appliance</h1>
|
||||
<p class="text-text-secondary text-xs font-medium">v4.2.0 • <span class="text-green-400">Online</span></p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Navigation Links -->
|
||||
<nav class="flex flex-col gap-2">
|
||||
<a class="flex items-center gap-3 px-3 py-2.5 rounded-lg text-text-secondary hover:bg-surface-dark hover:text-white transition-colors group" href="#">
|
||||
<span class="material-symbols-outlined group-hover:text-primary transition-colors">hard_drive</span>
|
||||
<span class="text-sm font-medium">Storage</span>
|
||||
</a>
|
||||
<a class="flex items-center gap-3 px-3 py-2.5 rounded-lg text-text-secondary hover:bg-surface-dark hover:text-white transition-colors group" href="#">
|
||||
<span class="material-symbols-outlined group-hover:text-primary transition-colors">hub</span>
|
||||
<span class="text-sm font-medium">Networking</span>
|
||||
</a>
|
||||
<!-- Active State -->
|
||||
<a class="flex items-center gap-3 px-3 py-2.5 rounded-lg bg-primary/20 text-white border-l-4 border-primary" href="#">
|
||||
<span class="material-symbols-outlined text-primary fill-current material-symbols-filled">database</span>
|
||||
<span class="text-sm font-bold">VTL</span>
|
||||
</a>
|
||||
<a class="flex items-center gap-3 px-3 py-2.5 rounded-lg text-text-secondary hover:bg-surface-dark hover:text-white transition-colors group" href="#">
|
||||
<span class="material-symbols-outlined group-hover:text-primary transition-colors">settings</span>
|
||||
<span class="text-sm font-medium">System</span>
|
||||
</a>
|
||||
<a class="flex items-center gap-3 px-3 py-2.5 rounded-lg text-text-secondary hover:bg-surface-dark hover:text-white transition-colors group" href="#">
|
||||
<span class="material-symbols-outlined group-hover:text-primary transition-colors">description</span>
|
||||
<span class="text-sm font-medium">Logs</span>
|
||||
</a>
|
||||
</nav>
|
||||
</div>
|
||||
<!-- Footer User Profile -->
|
||||
<div class="flex items-center gap-3 px-3 py-3 border-t border-border-dark mt-auto">
|
||||
<div class="size-8 rounded-full bg-surface-dark flex items-center justify-center text-text-secondary">
|
||||
<span class="material-symbols-outlined text-sm">person</span>
|
||||
</div>
|
||||
<div class="flex flex-col">
|
||||
<p class="text-white text-sm font-medium">Admin User</p>
|
||||
<p class="text-text-secondary text-xs">admin@local</p>
|
||||
</div>
|
||||
<button class="ml-auto text-text-secondary hover:text-white">
|
||||
<span class="material-symbols-outlined text-lg">logout</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
<!-- Main Content Area -->
|
||||
<main class="flex-1 flex flex-col h-full overflow-hidden relative">
|
||||
<!-- Top Header & Breadcrumbs -->
|
||||
<header class="flex-none px-6 py-5 border-b border-border-dark bg-[#111a22]/95 backdrop-blur z-10">
|
||||
<div class="max-w-[1400px] mx-auto w-full flex flex-col gap-4">
|
||||
<!-- Breadcrumbs -->
|
||||
<div class="flex flex-wrap gap-2 items-center">
|
||||
<a class="text-text-secondary text-sm font-medium hover:text-primary transition-colors" href="#">Home</a>
|
||||
<span class="text-text-secondary text-xs">/</span>
|
||||
<a class="text-text-secondary text-sm font-medium hover:text-primary transition-colors" href="#">Storage</a>
|
||||
<span class="text-text-secondary text-xs">/</span>
|
||||
<span class="text-white text-sm font-medium">Virtual Tape Libraries</span>
|
||||
</div>
|
||||
<!-- Page Heading & Actions -->
|
||||
<div class="flex flex-wrap justify-between items-end gap-4">
|
||||
<div class="flex flex-col gap-1">
|
||||
<h2 class="text-white text-3xl font-bold tracking-tight">Virtual Tape Libraries</h2>
|
||||
<p class="text-text-secondary text-base max-w-2xl">Manage virtual tape devices, emulation profiles, and storage targets.</p>
|
||||
</div>
|
||||
<div class="flex gap-3">
|
||||
<button class="px-4 py-2 bg-surface-dark hover:bg-[#2a3b4d] border border-border-dark rounded-lg text-white text-sm font-medium flex items-center gap-2 transition-all">
|
||||
<span class="material-symbols-outlined text-lg">refresh</span>
|
||||
Refresh
|
||||
</button>
|
||||
<button class="px-4 py-2 bg-primary hover:bg-blue-600 rounded-lg text-white text-sm font-bold shadow-lg shadow-blue-900/20 flex items-center gap-2 transition-all">
|
||||
<span class="material-symbols-outlined text-lg">add</span>
|
||||
Create VTL
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<!-- Scrollable Content -->
|
||||
<div class="flex-1 overflow-y-auto bg-background-dark">
|
||||
<div class="max-w-[1400px] mx-auto p-6 flex flex-col gap-6 pb-20">
|
||||
<!-- Stats Grid -->
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
|
||||
<!-- Stat Card 1 -->
|
||||
<div class="flex flex-col gap-1 p-5 rounded-xl border border-border-dark bg-surface-dark relative overflow-hidden group">
|
||||
<div class="absolute right-0 top-0 p-4 opacity-10 group-hover:opacity-20 transition-opacity">
|
||||
<span class="material-symbols-outlined text-6xl text-white">dns</span>
|
||||
</div>
|
||||
<p class="text-text-secondary text-sm font-medium">Total Libraries</p>
|
||||
<div class="flex items-end gap-2">
|
||||
<p class="text-white text-3xl font-bold tracking-tight">3</p>
|
||||
<span class="text-green-500 text-xs font-medium mb-1.5 flex items-center">
|
||||
<span class="material-symbols-outlined text-sm mr-0.5">check_circle</span> All Online
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Stat Card 2 -->
|
||||
<div class="flex flex-col gap-1 p-5 rounded-xl border border-border-dark bg-surface-dark relative overflow-hidden group">
|
||||
<div class="absolute right-0 top-0 p-4 opacity-10 group-hover:opacity-20 transition-opacity">
|
||||
<span class="material-symbols-outlined text-6xl text-white">database</span>
|
||||
</div>
|
||||
<p class="text-text-secondary text-sm font-medium">Total Capacity</p>
|
||||
<div class="flex items-end gap-2">
|
||||
<p class="text-white text-3xl font-bold tracking-tight">120 <span class="text-lg text-text-secondary font-medium">TB</span></p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Stat Card 3 -->
|
||||
<div class="flex flex-col gap-1 p-5 rounded-xl border border-border-dark bg-surface-dark relative overflow-hidden group">
|
||||
<div class="absolute right-0 top-0 p-4 opacity-10 group-hover:opacity-20 transition-opacity">
|
||||
<span class="material-symbols-outlined text-6xl text-white">album</span>
|
||||
</div>
|
||||
<p class="text-text-secondary text-sm font-medium">Tapes Online</p>
|
||||
<div class="flex items-end gap-2">
|
||||
<p class="text-white text-3xl font-bold tracking-tight">45</p>
|
||||
<span class="text-text-secondary text-xs font-medium mb-1.5">/ 200 Slots</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Stat Card 4 -->
|
||||
<div class="flex flex-col gap-1 p-5 rounded-xl border border-border-dark bg-surface-dark relative overflow-hidden group">
|
||||
<div class="absolute right-0 top-0 p-4 opacity-10 group-hover:opacity-20 transition-opacity">
|
||||
<span class="material-symbols-outlined text-6xl text-white">swap_horiz</span>
|
||||
</div>
|
||||
<p class="text-text-secondary text-sm font-medium">Active Sessions</p>
|
||||
<div class="flex items-end gap-2">
|
||||
<p class="text-white text-3xl font-bold tracking-tight">2</p>
|
||||
<span class="text-blue-400 text-xs font-medium mb-1.5">Writing</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Usage Progress Section -->
|
||||
<div class="p-5 rounded-xl bg-surface-dark border border-border-dark flex flex-col gap-3">
|
||||
<div class="flex justify-between items-center">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="material-symbols-outlined text-text-secondary">pie_chart</span>
|
||||
<h3 class="text-white text-sm font-semibold">VTL Partition Usage (ZFS Pool)</h3>
|
||||
</div>
|
||||
<p class="text-white text-sm font-medium">14.5 TB / 50 TB Used</p>
|
||||
</div>
|
||||
<div class="w-full bg-[#111a22] rounded-full h-3 overflow-hidden">
|
||||
<div class="bg-gradient-to-r from-blue-600 to-primary h-3 rounded-full" style="width: 29%"></div>
|
||||
</div>
|
||||
<div class="flex justify-between items-center text-xs text-text-secondary">
|
||||
<span>Compression Ratio: <span class="text-white font-mono">1.5x</span></span>
|
||||
<span class="flex items-center gap-1 text-green-400"><span class="w-2 h-2 rounded-full bg-green-500"></span> Pool Healthy</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Main Data Table Section -->
|
||||
<div class="flex flex-col rounded-xl border border-border-dark bg-surface-dark overflow-hidden">
|
||||
<!-- Toolbar -->
|
||||
<div class="p-4 border-b border-border-dark flex flex-col sm:flex-row gap-4 justify-between items-center bg-[#1c2834]">
|
||||
<div class="relative w-full sm:w-96">
|
||||
<span class="material-symbols-outlined absolute left-3 top-1/2 -translate-y-1/2 text-text-secondary text-lg">search</span>
|
||||
<input class="w-full bg-[#111a22] border border-border-dark text-white text-sm rounded-lg pl-10 pr-4 py-2 focus:ring-1 focus:ring-primary focus:border-primary placeholder-gray-600 outline-none transition-all" placeholder="Search libraries by name or ID..." type="text"/>
|
||||
</div>
|
||||
<div class="flex gap-2 w-full sm:w-auto">
|
||||
<button class="px-3 py-2 bg-[#111a22] hover:bg-[#1a2632] border border-border-dark rounded-lg text-text-secondary text-sm font-medium flex items-center gap-2 transition-colors">
|
||||
<span class="material-symbols-outlined text-lg">filter_list</span>
|
||||
Filter
|
||||
</button>
|
||||
<button class="px-3 py-2 bg-[#111a22] hover:bg-[#1a2632] border border-border-dark rounded-lg text-text-secondary text-sm font-medium flex items-center gap-2 transition-colors">
|
||||
<span class="material-symbols-outlined text-lg">settings</span>
|
||||
Columns
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Table -->
|
||||
<div class="overflow-x-auto">
|
||||
<table class="w-full text-left border-collapse">
|
||||
<thead>
|
||||
<tr class="bg-[#151e29] border-b border-border-dark">
|
||||
<th class="py-4 px-6 text-xs font-semibold uppercase tracking-wider text-text-secondary w-12">
|
||||
<input class="rounded border-border-dark bg-[#111a22] text-primary focus:ring-offset-background-dark focus:ring-primary h-4 w-4" type="checkbox"/>
|
||||
</th>
|
||||
<th class="py-4 px-6 text-xs font-semibold uppercase tracking-wider text-text-secondary">Library Name</th>
|
||||
<th class="py-4 px-6 text-xs font-semibold uppercase tracking-wider text-text-secondary">Status</th>
|
||||
<th class="py-4 px-6 text-xs font-semibold uppercase tracking-wider text-text-secondary">Emulation</th>
|
||||
<th class="py-4 px-6 text-xs font-semibold uppercase tracking-wider text-text-secondary">Tapes / Slots</th>
|
||||
<th class="py-4 px-6 text-xs font-semibold uppercase tracking-wider text-text-secondary">iSCSI Target</th>
|
||||
<th class="py-4 px-6 text-xs font-semibold uppercase tracking-wider text-text-secondary text-right">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-border-dark">
|
||||
<!-- Row 1 -->
|
||||
<tr class="group hover:bg-[#233342] transition-colors">
|
||||
<td class="py-4 px-6">
|
||||
<input class="rounded border-border-dark bg-[#111a22] text-primary focus:ring-offset-background-dark focus:ring-primary h-4 w-4" type="checkbox"/>
|
||||
</td>
|
||||
<td class="py-4 px-6">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="size-8 rounded bg-blue-900/30 flex items-center justify-center text-primary">
|
||||
<span class="material-symbols-outlined text-lg">shelves</span>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-white text-sm font-bold">VTL_Arch_01</p>
|
||||
<p class="text-text-secondary text-xs">ID: 001</p>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td class="py-4 px-6">
|
||||
<span class="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-xs font-medium bg-green-500/10 text-green-400 border border-green-500/20">
|
||||
<span class="w-1.5 h-1.5 rounded-full bg-green-500 animate-pulse"></span>
|
||||
Ready
|
||||
</span>
|
||||
</td>
|
||||
<td class="py-4 px-6">
|
||||
<p class="text-white text-sm font-medium">HP MSL2024</p>
|
||||
<p class="text-text-secondary text-xs">LTO-7 • 2 Drives</p>
|
||||
</td>
|
||||
<td class="py-4 px-6">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="material-symbols-outlined text-text-secondary text-lg">album</span>
|
||||
<span class="text-white text-sm">24 / 24</span>
|
||||
</div>
|
||||
<div class="w-24 bg-[#111a22] rounded-full h-1 mt-1.5">
|
||||
<div class="bg-primary h-1 rounded-full" style="width: 100%"></div>
|
||||
</div>
|
||||
</td>
|
||||
<td class="py-4 px-6">
|
||||
<div class="flex items-center gap-2 group/copy cursor-pointer">
|
||||
<code class="text-xs text-text-secondary font-mono bg-[#111a22] px-2 py-1 rounded border border-border-dark group-hover/copy:text-white transition-colors">iqn.2023-10.com.vtl:arch01</code>
|
||||
<span class="material-symbols-outlined text-text-secondary text-sm opacity-0 group-hover/copy:opacity-100 transition-opacity">content_copy</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="py-4 px-6 text-right">
|
||||
<div class="flex items-center justify-end gap-1">
|
||||
<button class="p-2 text-text-secondary hover:text-white hover:bg-[#324d67] rounded-lg transition-colors" title="Manage Tapes">
|
||||
<span class="material-symbols-outlined text-xl">cable</span>
|
||||
</button>
|
||||
<button class="p-2 text-text-secondary hover:text-primary hover:bg-primary/10 rounded-lg transition-colors" title="Edit Configuration">
|
||||
<span class="material-symbols-outlined text-xl">edit</span>
|
||||
</button>
|
||||
<button class="p-2 text-text-secondary hover:text-red-400 hover:bg-red-400/10 rounded-lg transition-colors" title="Delete Library">
|
||||
<span class="material-symbols-outlined text-xl">delete</span>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- Row 2 -->
|
||||
<tr class="group hover:bg-[#233342] transition-colors">
|
||||
<td class="py-4 px-6">
|
||||
<input class="rounded border-border-dark bg-[#111a22] text-primary focus:ring-offset-background-dark focus:ring-primary h-4 w-4" type="checkbox"/>
|
||||
</td>
|
||||
<td class="py-4 px-6">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="size-8 rounded bg-blue-900/30 flex items-center justify-center text-primary">
|
||||
<span class="material-symbols-outlined text-lg">shelves</span>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-white text-sm font-bold">VTL_Prod_Daily</p>
|
||||
<p class="text-text-secondary text-xs">ID: 002</p>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td class="py-4 px-6">
|
||||
<span class="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-xs font-medium bg-blue-500/10 text-blue-400 border border-blue-500/20">
|
||||
<span class="material-symbols-outlined text-[10px] animate-spin">refresh</span>
|
||||
Writing
|
||||
</span>
|
||||
</td>
|
||||
<td class="py-4 px-6">
|
||||
<p class="text-white text-sm font-medium">Quantum i3</p>
|
||||
<p class="text-text-secondary text-xs">LTO-8 • 4 Drives</p>
|
||||
</td>
|
||||
<td class="py-4 px-6">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="material-symbols-outlined text-text-secondary text-lg">album</span>
|
||||
<span class="text-white text-sm">12 / 50</span>
|
||||
</div>
|
||||
<div class="w-24 bg-[#111a22] rounded-full h-1 mt-1.5">
|
||||
<div class="bg-blue-500 h-1 rounded-full" style="width: 24%"></div>
|
||||
</div>
|
||||
</td>
|
||||
<td class="py-4 px-6">
|
||||
<div class="flex items-center gap-2 group/copy cursor-pointer">
|
||||
<code class="text-xs text-text-secondary font-mono bg-[#111a22] px-2 py-1 rounded border border-border-dark group-hover/copy:text-white transition-colors">iqn.2023-10.com.vtl:prod02</code>
|
||||
<span class="material-symbols-outlined text-text-secondary text-sm opacity-0 group-hover/copy:opacity-100 transition-opacity">content_copy</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="py-4 px-6 text-right">
|
||||
<div class="flex items-center justify-end gap-1">
|
||||
<button class="p-2 text-text-secondary hover:text-white hover:bg-[#324d67] rounded-lg transition-colors" title="Manage Tapes">
|
||||
<span class="material-symbols-outlined text-xl">cable</span>
|
||||
</button>
|
||||
<button class="p-2 text-text-secondary hover:text-primary hover:bg-primary/10 rounded-lg transition-colors" title="Edit Configuration">
|
||||
<span class="material-symbols-outlined text-xl">edit</span>
|
||||
</button>
|
||||
<button class="p-2 text-text-secondary hover:text-red-400 hover:bg-red-400/10 rounded-lg transition-colors" title="Delete Library">
|
||||
<span class="material-symbols-outlined text-xl">delete</span>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- Row 3 -->
|
||||
<tr class="group hover:bg-[#233342] transition-colors">
|
||||
<td class="py-4 px-6">
|
||||
<input class="rounded border-border-dark bg-[#111a22] text-primary focus:ring-offset-background-dark focus:ring-primary h-4 w-4" type="checkbox"/>
|
||||
</td>
|
||||
<td class="py-4 px-6">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="size-8 rounded bg-gray-700/30 flex items-center justify-center text-gray-400">
|
||||
<span class="material-symbols-outlined text-lg">shelves</span>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-white text-sm font-bold">VTL_Legacy_03</p>
|
||||
<p class="text-text-secondary text-xs">ID: 003</p>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td class="py-4 px-6">
|
||||
<span class="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-xs font-medium bg-gray-500/10 text-gray-400 border border-gray-500/20">
|
||||
<span class="w-1.5 h-1.5 rounded-full bg-gray-500"></span>
|
||||
Offline
|
||||
</span>
|
||||
</td>
|
||||
<td class="py-4 px-6">
|
||||
<p class="text-white text-sm font-medium">IBM TS3100</p>
|
||||
<p class="text-text-secondary text-xs">LTO-5 • 1 Drive</p>
|
||||
</td>
|
||||
<td class="py-4 px-6">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="material-symbols-outlined text-text-secondary text-lg">album</span>
|
||||
<span class="text-white text-sm">9 / 10</span>
|
||||
</div>
|
||||
<div class="w-24 bg-[#111a22] rounded-full h-1 mt-1.5">
|
||||
<div class="bg-gray-500 h-1 rounded-full" style="width: 90%"></div>
|
||||
</div>
|
||||
</td>
|
||||
<td class="py-4 px-6">
|
||||
<div class="flex items-center gap-2 group/copy cursor-pointer">
|
||||
<code class="text-xs text-text-secondary font-mono bg-[#111a22] px-2 py-1 rounded border border-border-dark group-hover/copy:text-white transition-colors">iqn.2023-10.com.vtl:leg03</code>
|
||||
<span class="material-symbols-outlined text-text-secondary text-sm opacity-0 group-hover/copy:opacity-100 transition-opacity">content_copy</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="py-4 px-6 text-right">
|
||||
<div class="flex items-center justify-end gap-1">
|
||||
<button class="p-2 text-text-secondary hover:text-white hover:bg-[#324d67] rounded-lg transition-colors" title="Power On">
|
||||
<span class="material-symbols-outlined text-xl">power_settings_new</span>
|
||||
</button>
|
||||
<button class="p-2 text-text-secondary hover:text-primary hover:bg-primary/10 rounded-lg transition-colors" title="Edit Configuration">
|
||||
<span class="material-symbols-outlined text-xl">edit</span>
|
||||
</button>
|
||||
<button class="p-2 text-text-secondary hover:text-red-400 hover:bg-red-400/10 rounded-lg transition-colors" title="Delete Library">
|
||||
<span class="material-symbols-outlined text-xl">delete</span>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<!-- Pagination -->
|
||||
<div class="px-6 py-4 border-t border-border-dark flex items-center justify-between bg-[#1c2834]">
|
||||
<p class="text-text-secondary text-sm">Showing <span class="text-white font-medium">1-3</span> of <span class="text-white font-medium">3</span> libraries</p>
|
||||
<div class="flex gap-2">
|
||||
<button class="px-3 py-1.5 rounded-lg border border-border-dark bg-[#111a22] text-text-secondary text-sm hover:text-white disabled:opacity-50">Previous</button>
|
||||
<button class="px-3 py-1.5 rounded-lg border border-border-dark bg-[#111a22] text-text-secondary text-sm hover:text-white disabled:opacity-50">Next</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- "Tape Detail" Drawer Simulation (Showing detailed context for selected item) -->
|
||||
<!-- Positioned absolute to simulate a slide-up panel or just a section on the page. Using a bottom panel style here. -->
|
||||
<div class="bg-surface-dark border-t border-border-dark p-6 absolute bottom-0 w-full transform translate-y-full transition-transform lg:relative lg:translate-y-0 lg:border-t lg:border-border-dark lg:h-auto z-30 shadow-2xl shadow-black">
|
||||
<div class="max-w-[1400px] mx-auto">
|
||||
<div class="flex justify-between items-center mb-4">
|
||||
<div class="flex items-center gap-3">
|
||||
<span class="material-symbols-outlined text-primary text-2xl">cable</span>
|
||||
<div>
|
||||
<h3 class="text-white text-lg font-bold">Tape Management: VTL_Arch_01</h3>
|
||||
<p class="text-text-secondary text-sm">Manage virtual cartridges, import/export slots, and barcodes.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex gap-3">
|
||||
<button class="px-3 py-2 bg-[#111a22] border border-border-dark rounded-lg text-text-secondary hover:text-white text-sm font-medium transition-colors">
|
||||
Bulk Format
|
||||
</button>
|
||||
<button class="px-3 py-2 bg-primary hover:bg-blue-600 rounded-lg text-white text-sm font-bold transition-colors flex items-center gap-2">
|
||||
<span class="material-symbols-outlined text-lg">add</span>
|
||||
Add Tapes
|
||||
</button>
|
||||
<button class="lg:hidden p-2 text-text-secondary hover:text-white">
|
||||
<span class="material-symbols-outlined">close</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 md:grid-cols-4 lg:grid-cols-6 gap-3">
|
||||
<!-- Tape Item (Loaded) -->
|
||||
<div class="p-3 bg-[#111a22] rounded border border-green-500/30 flex flex-col gap-2 relative group hover:border-green-500 transition-colors cursor-pointer">
|
||||
<div class="flex justify-between items-start">
|
||||
<span class="material-symbols-outlined text-green-500 text-xl">album</span>
|
||||
<span class="text-[10px] uppercase font-bold text-text-secondary bg-[#1c2834] px-1 rounded">Slot 1</span>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-white text-xs font-mono font-bold">ARC001L7</p>
|
||||
<p class="text-text-secondary text-[10px]">12.0 TB / 12.0 TB</p>
|
||||
</div>
|
||||
<div class="absolute inset-0 bg-black/60 hidden group-hover:flex items-center justify-center gap-2 backdrop-blur-[1px] rounded">
|
||||
<span class="material-symbols-outlined text-white hover:text-primary text-lg">eject</span>
|
||||
<span class="material-symbols-outlined text-white hover:text-red-400 text-lg">delete</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Tape Item (Loaded) -->
|
||||
<div class="p-3 bg-[#111a22] rounded border border-border-dark flex flex-col gap-2 relative group hover:border-primary transition-colors cursor-pointer">
|
||||
<div class="flex justify-between items-start">
|
||||
<span class="material-symbols-outlined text-text-secondary text-xl">album</span>
|
||||
<span class="text-[10px] uppercase font-bold text-text-secondary bg-[#1c2834] px-1 rounded">Slot 2</span>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-white text-xs font-mono font-bold">ARC002L7</p>
|
||||
<p class="text-text-secondary text-[10px]">Empty / 12.0 TB</p>
|
||||
</div>
|
||||
<div class="absolute inset-0 bg-black/60 hidden group-hover:flex items-center justify-center gap-2 backdrop-blur-[1px] rounded">
|
||||
<span class="material-symbols-outlined text-white hover:text-primary text-lg">upload</span>
|
||||
<span class="material-symbols-outlined text-white hover:text-red-400 text-lg">delete</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Tape Item (Empty Slot) -->
|
||||
<div class="p-3 bg-[#111a22] rounded border border-dashed border-border-dark flex flex-col gap-2 justify-center items-center h-20 opacity-60 hover:opacity-100 hover:bg-[#1c2834] transition-all cursor-pointer">
|
||||
<span class="material-symbols-outlined text-text-secondary">add_circle</span>
|
||||
<span class="text-[10px] text-text-secondary uppercase font-bold">Empty Slot 3</span>
|
||||
</div>
|
||||
<!-- Tape Item (Empty Slot) -->
|
||||
<div class="p-3 bg-[#111a22] rounded border border-dashed border-border-dark flex flex-col gap-2 justify-center items-center h-20 opacity-60 hover:opacity-100 hover:bg-[#1c2834] transition-all cursor-pointer">
|
||||
<span class="material-symbols-outlined text-text-secondary">add_circle</span>
|
||||
<span class="text-[10px] text-text-secondary uppercase font-bold">Empty Slot 4</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</body></html>
|
||||
BIN
src/web/vtl-management.png
Normal file
|
After Width: | Height: | Size: 292 KiB |