Files
digiserver-v2/app/templates/players/manage_player.html
ske087 498c03ef00 Replace emoji icons with local SVG files for consistent rendering
- Created 10 SVG icon files in app/static/icons/ (Feather Icons style)
- Updated base.html with SVG icons in navigation and dark mode toggle
- Updated dashboard.html with icons in stats cards and quick actions
- Updated content_list_new.html (playlist management) with SVG icons
- Updated upload_media.html with upload-related icons
- Updated manage_player.html with player management icons
- Icons use currentColor for automatic theme adaptation
- Removed emoji dependency for better Raspberry Pi compatibility
- Added ICON_INTEGRATION.md documentation
2025-11-13 21:00:07 +02:00

253 lines
14 KiB
HTML
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{% extends "base.html" %}
{% block title %}Manage Player - {{ player.name }}{% endblock %}
{% block content %}
<div style="margin-bottom: 2rem;">
<h1 style="display: inline-block; margin-right: 1rem; display: flex; align-items: center; gap: 0.5rem;">
<img src="{{ url_for('static', filename='icons/monitor.svg') }}" alt="" style="width: 32px; height: 32px;">
Manage Player: {{ player.name }}
</h1>
<a href="{{ url_for('players.list') }}" class="btn" style="float: right; display: inline-flex; align-items: center; gap: 0.5rem;">
<img src="{{ url_for('static', filename='icons/monitor.svg') }}" alt="" style="width: 18px; height: 18px; filter: brightness(0) invert(1);">
Back to Players
</a>
</div>
<!-- Player Status Overview -->
<div class="card" style="margin-bottom: 2rem; background: {% if player.status == 'online' %}#d4edda{% elif player.status == 'offline' %}#f8d7da{% else %}#fff3cd{% endif %};">
<h3 style="display: flex; align-items: center; gap: 0.5rem;">
Status:
{% if player.status == 'online' %}
<span style="color: #28a745; display: flex; align-items: center; gap: 0.3rem;">
<img src="{{ url_for('static', filename='icons/info.svg') }}" alt="" style="width: 20px; height: 20px; color: #28a745;">
Online
</span>
{% elif player.status == 'offline' %}
<span style="color: #dc3545; display: flex; align-items: center; gap: 0.3rem;">
<img src="{{ url_for('static', filename='icons/warning.svg') }}" alt="" style="width: 20px; height: 20px; color: #dc3545;">
Offline
</span>
{% else %}
<span style="color: #ffc107; display: flex; align-items: center; gap: 0.3rem;">
<img src="{{ url_for('static', filename='icons/info.svg') }}" alt="" style="width: 20px; height: 20px; color: #ffc107;">
{{ player.status|title }}
</span>
{% endif %}
</h3>
<p><strong>Hostname:</strong> {{ player.hostname }}</p>
<p><strong>Last Seen:</strong>
{% if player.last_seen %}
{{ player.last_seen.strftime('%Y-%m-%d %H:%M:%S') }}
{% else %}
Never
{% endif %}
</p>
<p><strong>Assigned Playlist:</strong>
{% if current_playlist %}
<span style="color: #28a745; font-weight: bold;">{{ current_playlist.name }} (v{{ current_playlist.version }})</span>
{% else %}
<span style="color: #dc3545;">No playlist assigned</span>
{% endif %}
</p>
</div>
<!-- Three Column Layout -->
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(350px, 1fr)); gap: 1.5rem;">
<!-- Card 1: Edit Credentials -->
<div class="card">
<h2 style="display: flex; align-items: center; gap: 0.5rem;">
<img src="{{ url_for('static', filename='icons/edit.svg') }}" alt="" style="width: 24px; height: 24px;">
Edit Credentials
</h2>
<form method="POST" style="margin-top: 1rem;">
<input type="hidden" name="action" value="update_credentials">
<div style="margin-bottom: 1rem;">
<label for="name" style="display: block; margin-bottom: 0.5rem; font-weight: bold;">Player Name *</label>
<input type="text" id="name" name="name" value="{{ player.name }}"
required minlength="3"
style="width: 100%; padding: 0.5rem; border: 1px solid #ddd; border-radius: 4px;">
</div>
<div style="margin-bottom: 1rem;">
<label for="location" style="display: block; margin-bottom: 0.5rem; font-weight: bold;">Location</label>
<input type="text" id="location" name="location" value="{{ player.location or '' }}"
placeholder="e.g., Main Lobby"
style="width: 100%; padding: 0.5rem; border: 1px solid #ddd; border-radius: 4px;">
</div>
<div style="margin-bottom: 1rem;">
<label for="orientation" style="display: block; margin-bottom: 0.5rem; font-weight: bold;">Orientation</label>
<select id="orientation" name="orientation"
style="width: 100%; padding: 0.5rem; border: 1px solid #ddd; border-radius: 4px;">
<option value="Landscape" {% if player.orientation == 'Landscape' %}selected{% endif %}>Landscape</option>
<option value="Portrait" {% if player.orientation == 'Portrait' %}selected{% endif %}>Portrait</option>
</select>
</div>
<div style="padding: 1rem; background: #f8f9fa; border-radius: 4px; margin-bottom: 1rem;">
<p style="margin: 0; font-size: 0.9rem;"><strong>Hostname:</strong> {{ player.hostname }}</p>
<p style="margin: 0.5rem 0 0 0; font-size: 0.9rem;"><strong>Auth Code:</strong> <code>{{ player.auth_code }}</code></p>
<p style="margin: 0.5rem 0 0 0; font-size: 0.9rem;"><strong>Quick Connect:</strong> {{ player.quickconnect_code or 'Not set' }}</p>
</div>
<button type="submit" class="btn btn-success" style="width: 100%; display: flex; align-items: center; justify-content: center; gap: 0.5rem;">
<img src="{{ url_for('static', filename='icons/edit.svg') }}" alt="" style="width: 18px; height: 18px; filter: brightness(0) invert(1);">
Save Changes
</button>
</form>
</div>
<!-- Card 2: Assign Playlist -->
<div class="card">
<h2 style="display: flex; align-items: center; gap: 0.5rem;">
<img src="{{ url_for('static', filename='icons/playlist.svg') }}" alt="" style="width: 24px; height: 24px;">
Assign Playlist
</h2>
<form method="POST" style="margin-top: 1rem;">
<input type="hidden" name="action" value="assign_playlist">
<div style="margin-bottom: 1rem;">
<label for="playlist_id" style="display: block; margin-bottom: 0.5rem; font-weight: bold;">Select Playlist</label>
<select id="playlist_id" name="playlist_id"
style="width: 100%; padding: 0.5rem; border: 1px solid #ddd; border-radius: 4px;">
<option value="">-- No Playlist (Unassign) --</option>
{% for playlist in playlists %}
<option value="{{ playlist.id }}"
{% if player.playlist_id == playlist.id %}selected{% endif %}>
{{ playlist.name }} (v{{ playlist.version }}) - {{ playlist.contents.count() }} items
</option>
{% endfor %}
</select>
</div>
{% if current_playlist %}
<div style="padding: 1rem; background: #d4edda; border-radius: 4px; margin-bottom: 1rem;">
<h4 style="margin: 0 0 0.5rem 0; color: #155724;">Currently Assigned:</h4>
<p style="margin: 0;"><strong>{{ current_playlist.name }}</strong></p>
<p style="margin: 0.25rem 0 0 0; font-size: 0.9rem;">Version: {{ current_playlist.version }}</p>
<p style="margin: 0.25rem 0 0 0; font-size: 0.9rem;">Content Items: {{ current_playlist.contents.count() }}</p>
<p style="margin: 0.25rem 0 0 0; font-size: 0.9rem; color: #6c757d;">
Updated: {{ current_playlist.updated_at.strftime('%Y-%m-%d %H:%M') }}
</p>
</div>
{% else %}
<div style="padding: 1rem; background: #fff3cd; border-radius: 4px; margin-bottom: 1rem;">
<p style="margin: 0; color: #856404; display: flex; align-items: center; gap: 0.5rem;">
<img src="{{ url_for('static', filename='icons/warning.svg') }}" alt="" style="width: 18px; height: 18px;">
No playlist currently assigned to this player.
</p>
</div>
{% endif %}
<button type="submit" class="btn btn-success" style="width: 100%; display: flex; align-items: center; justify-content: center; gap: 0.5rem;">
<img src="{{ url_for('static', filename='icons/playlist.svg') }}" alt="" style="width: 18px; height: 18px; filter: brightness(0) invert(1);">
Assign Playlist
</button>
</form>
<div style="margin-top: 1.5rem; padding-top: 1.5rem; border-top: 1px solid #ddd;">
<h4>Quick Actions:</h4>
<a href="{{ url_for('content.content_list') }}" class="btn" style="width: 100%; margin-top: 0.5rem; display: flex; align-items: center; justify-content: center; gap: 0.5rem;">
<img src="{{ url_for('static', filename='icons/playlist.svg') }}" alt="" style="width: 18px; height: 18px; filter: brightness(0) invert(1);">
Create New Playlist
</a>
{% if current_playlist %}
<a href="{{ url_for('content.manage_playlist_content', playlist_id=current_playlist.id) }}"
class="btn" style="width: 100%; margin-top: 0.5rem; display: flex; align-items: center; justify-content: center; gap: 0.5rem;">
<img src="{{ url_for('static', filename='icons/edit.svg') }}" alt="" style="width: 18px; height: 18px; filter: brightness(0) invert(1);">
Edit Current Playlist
</a>
{% endif %}
</div>
</div>
<!-- Card 3: Player Logs -->
<div class="card">
<h2 style="display: flex; align-items: center; gap: 0.5rem;">
<img src="{{ url_for('static', filename='icons/info.svg') }}" alt="" style="width: 24px; height: 24px;">
Player Logs
</h2>
<p style="color: #6c757d; font-size: 0.9rem;">Recent feedback from the player device</p>
<div style="max-height: 500px; overflow-y: auto; margin-top: 1rem;">
{% if recent_logs %}
{% for log in recent_logs %}
<div style="padding: 0.75rem; margin-bottom: 0.5rem; border-left: 4px solid
{% if log.status == 'error' %}#dc3545
{% elif log.status == 'warning' %}#ffc107
{% elif log.status == 'playing' %}#28a745
{% else %}#17a2b8{% endif %};
background: #f8f9fa; border-radius: 4px;">
<div style="display: flex; justify-content: space-between; align-items: start;">
<div style="flex: 1;">
<strong style="color:
{% if log.status == 'error' %}#dc3545
{% elif log.status == 'warning' %}#ffc107
{% elif log.status == 'playing' %}#28a745
{% else %}#17a2b8{% endif %};">
{% if log.status == 'error' %}❌
{% elif log.status == 'warning' %}⚠️
{% elif log.status == 'playing' %}▶️
{% elif log.status == 'restarting' %}🔄
{% else %}{% endif %}
{{ log.status|upper }}
</strong>
<p style="margin: 0.25rem 0 0 0; font-size: 0.9rem;">{{ log.message }}</p>
{% if log.playlist_version %}
<p style="margin: 0.25rem 0 0 0; font-size: 0.85rem; color: #6c757d;">
Playlist v{{ log.playlist_version }}
</p>
{% endif %}
{% if log.error_details %}
<details style="margin-top: 0.5rem;">
<summary style="cursor: pointer; font-size: 0.85rem; color: #dc3545;">Error Details</summary>
<pre style="margin: 0.5rem 0 0 0; padding: 0.5rem; background: #fff; border: 1px solid #ddd; border-radius: 4px; font-size: 0.8rem; overflow-x: auto;">{{ log.error_details }}</pre>
</details>
{% endif %}
</div>
<small style="color: #6c757d; white-space: nowrap; margin-left: 1rem;">
{{ log.timestamp.strftime('%m/%d %H:%M') }}
</small>
</div>
</div>
{% endfor %}
{% else %}
<div style="text-align: center; padding: 2rem; color: #6c757d;">
<p>📭 No logs received yet</p>
<p style="font-size: 0.9rem;">Logs will appear here once the player starts sending feedback</p>
</div>
{% endif %}
</div>
</div>
</div>
<!-- Additional Info Section -->
<div class="card" style="margin-top: 2rem;">
<h2> Player Information</h2>
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 1rem; margin-top: 1rem;">
<div>
<p><strong>Player ID:</strong> {{ player.id }}</p>
<p><strong>Created:</strong> {{ player.created_at.strftime('%Y-%m-%d %H:%M') if player.created_at else 'N/A' }}</p>
</div>
<div>
<p><strong>Orientation:</strong> {{ player.orientation }}</p>
<p><strong>Location:</strong> {{ player.location or 'Not set' }}</p>
</div>
<div>
<p><strong>Last Heartbeat:</strong>
{% if player.last_heartbeat %}
{{ player.last_heartbeat.strftime('%Y-%m-%d %H:%M:%S') }}
{% else %}
Never
{% endif %}
</p>
</div>
</div>
</div>
{% endblock %}