Implement custom health check endpoints, drag-and-drop reordering, collapsible service groups, theme management, and dashboard widgets; update documentation and configuration files
This commit is contained in:
437
FEATURES.md
Normal file
437
FEATURES.md
Normal file
@@ -0,0 +1,437 @@
|
||||
# Services Homepage - Features Documentation
|
||||
|
||||
## Overview
|
||||
|
||||
This services homepage provides a modern, feature-rich interface for managing and monitoring your self-hosted services. All features include persistent storage using browser localStorage.
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Core Features
|
||||
|
||||
### 1. **Custom Health Check Endpoints**
|
||||
|
||||
Health checks now support custom endpoints for services that don't respond on the root path.
|
||||
|
||||
#### Configuration
|
||||
|
||||
Add the `health-path` attribute to any service in `services.xml`:
|
||||
|
||||
```xml
|
||||
<service id="jellyfin"
|
||||
name="Jellyfin"
|
||||
proto="http"
|
||||
port="8096"
|
||||
health-path="/health"
|
||||
logo="jellyfin.svg" />
|
||||
```
|
||||
|
||||
**Supported attributes:**
|
||||
- `health-path`: Custom path to ping (e.g., `/api/health`, `/ping`, `/status`)
|
||||
- If not specified, defaults to root path (`/`)
|
||||
|
||||
#### How It Works
|
||||
|
||||
The health-proxy service:
|
||||
1. Parses `services.xml` and finds the service by `id`
|
||||
2. Uses `local-ip` > `tailscale-ip` > `host` for the target
|
||||
3. Appends the custom `health-path` to the URL
|
||||
4. Performs a HEAD request to check availability
|
||||
|
||||
---
|
||||
|
||||
### 2. **Drag-and-Drop Service Reordering** 🖱️
|
||||
|
||||
Reorganize your services within each group by dragging and dropping cards.
|
||||
|
||||
#### Usage
|
||||
|
||||
1. Click and hold any service card
|
||||
2. Drag it to the desired position within the same group
|
||||
3. Release to drop
|
||||
4. Order is automatically saved to localStorage
|
||||
|
||||
#### Features
|
||||
|
||||
- ✅ Reordering within groups only (maintains organization)
|
||||
- ✅ Visual feedback during drag (opacity, border highlight)
|
||||
- ✅ Persistent across browser sessions
|
||||
- ✅ Per-group order tracking
|
||||
|
||||
#### Reset Order
|
||||
|
||||
To reset to default XML order:
|
||||
```javascript
|
||||
localStorage.removeItem('services-order');
|
||||
location.reload();
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3. **Collapsible Service Groups** 📁
|
||||
|
||||
Collapse and expand service groups to focus on what matters.
|
||||
|
||||
#### Usage
|
||||
|
||||
1. Click on any group header (or the ▼ icon)
|
||||
2. The group will collapse/expand
|
||||
3. State is saved automatically
|
||||
|
||||
#### Features
|
||||
|
||||
- ✅ Animated collapse/expand
|
||||
- ✅ Persistent state per group
|
||||
- ✅ Visual indicator (rotating arrow)
|
||||
- ✅ Keyboard accessible
|
||||
|
||||
#### Reset State
|
||||
|
||||
```javascript
|
||||
localStorage.removeItem('collapsed-groups');
|
||||
location.reload();
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 4. **Theme System** 🎨
|
||||
|
||||
Choose from 5 built-in themes or customize your own.
|
||||
|
||||
#### Available Themes
|
||||
|
||||
1. **Dark** (Default) - Deep blue-gray tones
|
||||
2. **Light** - Clean white and blue
|
||||
3. **Ocean** - Deep teal and aqua
|
||||
4. **Sunset** - Purple and pink gradient
|
||||
5. **Forest** - Green and earth tones
|
||||
|
||||
#### Usage
|
||||
|
||||
1. Click the 🎨 icon in the top-right corner
|
||||
2. Select a theme from the menu
|
||||
3. Theme is applied immediately and saved
|
||||
|
||||
#### Custom Themes
|
||||
|
||||
Themes are defined in `js/themes.js`. To add a custom theme:
|
||||
|
||||
```javascript
|
||||
customTheme: {
|
||||
name: 'My Theme',
|
||||
primary: '#hexcolor',
|
||||
secondary: '#hexcolor',
|
||||
accent: '#hexcolor',
|
||||
text: '#hexcolor',
|
||||
textMuted: '#hexcolor',
|
||||
border: '#hexcolor',
|
||||
cardBg: 'rgba(...)',
|
||||
headerBg: 'rgba(...)',
|
||||
overlayBg: 'rgba(...)'
|
||||
}
|
||||
```
|
||||
|
||||
Add your theme to the `themes` object and rebuild.
|
||||
|
||||
---
|
||||
|
||||
### 5. **Export/Import Configuration** 💾
|
||||
|
||||
Backup and restore your service configurations with JSON export/import.
|
||||
|
||||
#### Export Configuration
|
||||
|
||||
1. Click **📥 Export** button in the top-left
|
||||
2. Downloads `services-config-YYYY-MM-DD.json` file
|
||||
3. Contains all services, groups, and settings
|
||||
|
||||
#### Import Configuration
|
||||
|
||||
1. Click **📤 Import** button
|
||||
2. Select a previously exported JSON file
|
||||
3. Downloads a new `services.xml` file
|
||||
4. Replace your existing `services.xml` and rebuild containers
|
||||
|
||||
#### Export Format
|
||||
|
||||
```json
|
||||
{
|
||||
"version": "1.0",
|
||||
"exportDate": "2025-11-24T...",
|
||||
"tailscaleIp": "100.124.17.41",
|
||||
"groups": [
|
||||
{
|
||||
"name": "Management",
|
||||
"services": [
|
||||
{
|
||||
"id": "portainer",
|
||||
"name": "Portainer",
|
||||
"proto": "https",
|
||||
"port": "9443",
|
||||
"logo": "portainer.svg"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 6. **Dashboard Widgets** 📊
|
||||
|
||||
Add live widgets to your homepage header.
|
||||
|
||||
#### Available Widgets
|
||||
|
||||
##### ⏰ Clock Widget
|
||||
- Real-time clock with date
|
||||
- Updates every second
|
||||
- Always enabled by default
|
||||
|
||||
##### 🌤️ Weather Widget
|
||||
- Current weather for your location
|
||||
- Temperature, conditions, wind, humidity
|
||||
- Requires **OpenWeatherMap API key** (free)
|
||||
- Auto-location or custom city
|
||||
|
||||
##### 💭 Daily Quote Widget
|
||||
- Random inspirational quotes
|
||||
- Fetched from quotable.io API
|
||||
- Changes on each page load
|
||||
|
||||
#### Configuration
|
||||
|
||||
1. Click **⚙️ Widgets** button
|
||||
2. Enable/disable widgets with checkboxes
|
||||
3. For weather:
|
||||
- Get API key from [OpenWeatherMap](https://openweathermap.org/api)
|
||||
- Enter API key
|
||||
- Set location to `auto` or city name (e.g., `Toronto`)
|
||||
4. Click **Save & Reload**
|
||||
|
||||
#### Settings Storage
|
||||
|
||||
All widget settings stored in localStorage:
|
||||
```javascript
|
||||
{
|
||||
"clock": {"enabled": true},
|
||||
"weather": {
|
||||
"enabled": true,
|
||||
"apiKey": "your-api-key",
|
||||
"location": "auto"
|
||||
},
|
||||
"quote": {"enabled": false}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ Technical Details
|
||||
|
||||
### Architecture
|
||||
|
||||
```
|
||||
┌─────────────────┐
|
||||
│ Browser │
|
||||
│ (HTTPS) │
|
||||
└────────┬────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────┐
|
||||
│ Nginx │◄── Serves static files
|
||||
│ (Port 8088) │◄── Reverse proxy /healthcheck
|
||||
└────────┬────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────┐
|
||||
│ Health Proxy │
|
||||
│ (Flask:8081) │◄── Server-side health checks
|
||||
│ │◄── Parses services.xml
|
||||
└─────────────────┘
|
||||
```
|
||||
|
||||
### Files Structure
|
||||
|
||||
```
|
||||
services-homepage/
|
||||
├── index.html # Main HTML
|
||||
├── styles.css # Styles with CSS variables
|
||||
├── services.xml # Service configuration
|
||||
├── nginx.conf # Nginx config with resolver
|
||||
├── docker-compose.yml # Multi-container setup
|
||||
├── backend/
|
||||
│ └── health-proxy.py # Flask health check service
|
||||
└── js/
|
||||
├── galaxy-background.js # 3D background
|
||||
├── services-loader.js # Core service rendering
|
||||
├── drag-drop.js # Drag-and-drop module
|
||||
├── collapsible-groups.js # Group collapse module
|
||||
├── themes.js # Theme system
|
||||
├── export-import.js # Config backup/restore
|
||||
├── widgets.js # Dashboard widgets
|
||||
├── search.js # Search functionality
|
||||
├── keyboard-nav.js # Arrow key navigation
|
||||
└── readme-loader.js # Markdown rendering
|
||||
```
|
||||
|
||||
### localStorage Keys
|
||||
|
||||
| Key | Purpose | Format |
|
||||
|-----|---------|--------|
|
||||
| `services-order` | Drag-drop order | `{"GroupName": ["id1", "id2"]}` |
|
||||
| `collapsed-groups` | Collapsed state | `{"GroupName": true/false}` |
|
||||
| `selected-theme` | Active theme | `"dark"/"light"/"ocean"/...` |
|
||||
| `enabled-widgets` | Widget settings | `{clock: {...}, weather: {...}}` |
|
||||
|
||||
---
|
||||
|
||||
## 📋 services.xml Reference
|
||||
|
||||
### Root Element
|
||||
|
||||
```xml
|
||||
<services tailscale-ip="100.124.17.41">
|
||||
```
|
||||
|
||||
**Attributes:**
|
||||
- `tailscale-ip`: Default IP for local services (optional)
|
||||
|
||||
### Service Element
|
||||
|
||||
```xml
|
||||
<service
|
||||
id="unique-id"
|
||||
name="Display Name"
|
||||
proto="http|https"
|
||||
port="8080"
|
||||
host="domain.com"
|
||||
logo="logo.svg"
|
||||
status="maintenance"
|
||||
check-health="true|false"
|
||||
health-path="/custom/path"
|
||||
local-ip="192.168.1.100"
|
||||
/>
|
||||
```
|
||||
|
||||
**Attributes:**
|
||||
|
||||
| Attribute | Required | Description | Example |
|
||||
|-----------|----------|-------------|---------|
|
||||
| `id` | Recommended | Unique identifier | `portainer` |
|
||||
| `name` | **Required** | Display name | `Portainer` |
|
||||
| `proto` | Optional | Protocol (default: `http`) | `https` |
|
||||
| `port` | Optional | Port number | `9443` |
|
||||
| `host` | Optional | Custom hostname/URL | `cloud.example.com` |
|
||||
| `logo` | Optional | Logo filename in `/logos/` | `portainer.svg` |
|
||||
| `status` | Optional | Manual status override | `maintenance` |
|
||||
| `check-health` | Optional | Enable health check (default: `true`) | `false` |
|
||||
| `health-path` | Optional | Custom health endpoint | `/api/health` |
|
||||
| `local-ip` | Optional | Override IP for health checks | `192.168.1.100` |
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Troubleshooting
|
||||
|
||||
### Health Checks Return 502
|
||||
|
||||
**Problem:** Nginx can't resolve the health-proxy container.
|
||||
|
||||
**Solution:** Ensure nginx.conf contains:
|
||||
```nginx
|
||||
resolver 127.0.0.11 valid=30s;
|
||||
```
|
||||
|
||||
### Widgets Not Appearing
|
||||
|
||||
**Problem:** Widgets enabled but not showing.
|
||||
|
||||
**Solutions:**
|
||||
1. Check browser console for errors
|
||||
2. For weather: Verify API key is correct
|
||||
3. Clear localStorage and reconfigure:
|
||||
```javascript
|
||||
localStorage.removeItem('enabled-widgets');
|
||||
location.reload();
|
||||
```
|
||||
|
||||
### Drag-and-Drop Not Working
|
||||
|
||||
**Problem:** Cards won't drag.
|
||||
|
||||
**Solutions:**
|
||||
1. Ensure JavaScript is enabled
|
||||
2. Check browser console for errors
|
||||
3. Verify cards have `draggable="true"` attribute
|
||||
4. Try different browser
|
||||
|
||||
### Theme Not Persisting
|
||||
|
||||
**Problem:** Theme resets after reload.
|
||||
|
||||
**Solutions:**
|
||||
1. Check browser allows localStorage
|
||||
2. Try incognito/private mode to test
|
||||
3. Clear site data and reconfigure
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Future Enhancement Ideas
|
||||
|
||||
- [ ] Custom widget creation API
|
||||
- [ ] Service groups reordering (drag groups)
|
||||
- [ ] Dark mode auto-switch (time-based)
|
||||
- [ ] Service uptime statistics
|
||||
- [ ] Notification system for service outages
|
||||
- [ ] Mobile app (PWA)
|
||||
- [ ] Multi-user configurations
|
||||
- [ ] Service tags and filtering
|
||||
- [ ] Global search across all services
|
||||
- [ ] Service dependencies visualization
|
||||
|
||||
---
|
||||
|
||||
## 📝 Changelog
|
||||
|
||||
### v2.0.0 - 2025-11-24
|
||||
|
||||
**Added:**
|
||||
- ✨ Custom health check endpoints support
|
||||
- ✨ Drag-and-drop service reordering
|
||||
- ✨ Collapsible service groups
|
||||
- ✨ Theme system (5 themes)
|
||||
- ✨ Export/import configuration
|
||||
- ✨ Dashboard widgets (clock, weather, quote)
|
||||
- 🐛 Fixed nginx DNS resolver for health-proxy
|
||||
- 🐛 Fixed services.xml mount in health-proxy container
|
||||
|
||||
### v1.0.0 - Previous
|
||||
|
||||
- ✅ Basic service listing from XML
|
||||
- ✅ Automatic health checks
|
||||
- ✅ Search functionality
|
||||
- ✅ Keyboard navigation
|
||||
- ✅ 3D galaxy background
|
||||
- ✅ README rendering
|
||||
|
||||
---
|
||||
|
||||
## 🤝 Contributing
|
||||
|
||||
To add features:
|
||||
|
||||
1. Create new module in `/js/`
|
||||
2. Export functions via `window.moduleName`
|
||||
3. Import in `index.html`
|
||||
4. Initialize in DOMContentLoaded listener
|
||||
5. Add styles to `styles.css`
|
||||
6. Document in this file
|
||||
|
||||
---
|
||||
|
||||
## 📄 License
|
||||
|
||||
This project is open source. See LICENSE file for details.
|
||||
|
||||
---
|
||||
|
||||
**Questions or Issues?** Check the README.md or open an issue.
|
||||
Reference in New Issue
Block a user