add instruction and srs

This commit is contained in:
Othman H. Suseno
2025-12-24 23:55:55 +07:00
commit 0537709576
31 changed files with 6611 additions and 0 deletions

View 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**.

View 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**.

View File

@@ -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

View File

@@ -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.

View File

@@ -0,0 +1,61 @@
# SRS-01 — AtlasOS Calypso Storage Component
Version: 1.0
Target Capacity: 3060 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.

View File

@@ -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 18 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.

View 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.

View 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.

View File

@@ -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.

View File

@@ -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 softwarespecific 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.
---

View 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 (18)
- 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.
---

View 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 (18)
- 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.
---

View 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
View 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 &amp; Logs</title>
<!-- Material Symbols -->
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&amp;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&amp;family=JetBrains+Mono:wght@400;500&amp;display=swap" rel="stylesheet"/>
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&amp;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 &amp; 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: &gt;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

Binary file not shown.

After

Width:  |  Height:  |  Size: 272 KiB

View 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&amp;display=swap" rel="stylesheet"/>
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&amp;display=swap" rel="stylesheet"/>
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&amp;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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 270 KiB

View 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&amp;display=swap" rel="stylesheet"/>
<!-- Material Symbols -->
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&amp;display=swap" rel="stylesheet"/>
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&amp;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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 KiB

View 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&amp;display=swap" rel="stylesheet"/>
<!-- Icons -->
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&amp;display=swap" rel="stylesheet"/>
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&amp;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 &amp; 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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 312 KiB

View 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&amp;display=swap" rel="stylesheet"/>
<!-- Material Icons -->
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&amp;display=swap" rel="stylesheet"/>
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&amp;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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 KiB

View 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&amp;display=swap" rel="stylesheet"/>
<!-- Material Symbols -->
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&amp;display=swap" rel="stylesheet"/>
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&amp;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 &amp; 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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 307 KiB

View 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 &amp; Logs</title>
<!-- Material Symbols -->
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&amp;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&amp;family=JetBrains+Mono:wght@400;500&amp;display=swap" rel="stylesheet"/>
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&amp;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 &amp; 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: &gt;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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 272 KiB

View 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 &amp; 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&amp;display=swap" rel="stylesheet"/>
<!-- Material Symbols -->
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&amp;display=swap" rel="stylesheet"/>
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&amp;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 &amp; 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 &amp; 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 &amp; 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 &amp; 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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 308 KiB

View 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&amp;display=swap" rel="stylesheet"/>
<!-- Material Symbols -->
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&amp;display=swap" rel="stylesheet"/>
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&amp;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

Binary file not shown.

After

Width:  |  Height:  |  Size: 292 KiB