Files
MediaCollectorLibary/resources/views/admin/sources.twig
Lars Behrends 73d8441787 i dont know
2025-10-20 23:40:55 +02:00

206 lines
11 KiB
Twig

{% extends 'admin/layout.twig' %}
{% block title %}Media Sources - Admin{% endblock %}
{% block content %}
<div class="d-flex justify-content-between align-items-center mb-4">
<h1 class="h3 mb-0">Media Sources</h1>
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addSourceModal">
<i class="bi bi-plus-circle me-2"></i>Add Source
</button>
</div>
{% if sources is not empty %}
<div class="card shadow mb-4">
<div class="card-body">
<div class="table-responsive">
<table class="table table-striped table-hover">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Path/URL</th>
<th>Status</th>
<th>Last Sync</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{% for source in sources %}
<tr>
<td>{{ source.name }}</td>
<td>
<span class="badge bg-{{ source.type == 'jellyfin' ? 'info' : 'success' }}">
{{ source.type|upper }}
</span>
</td>
<td>{{ source.path }}</td>
<td>
<span class="badge bg-{{ source.is_active ? 'success' : 'secondary' }}">
{{ source.is_active ? 'Active' : 'Inactive' }}
</span>
</td>
<td>{{ source.last_sync ? source.last_sync|date('Y-m-d H:i:s') : 'Never' }}</td>
<td>
<div class="btn-group btn-group-sm">
<button class="btn btn-outline-primary"
data-bs-toggle="tooltip"
title="Edit"
onclick="editSource({{ source|json_encode|e('js') }});">
<i class="bi bi-pencil"></i>
</button>
<a href="{{ path_for('admin.sync', {'id': source.id}) }}"
class="btn btn-outline-success"
data-bs-toggle="tooltip"
title="Sync Now">
<i class="bi bi-arrow-repeat"></i>
</a>
<button class="btn btn-outline-danger"
data-bs-toggle="tooltip"
title="Delete"
onclick="confirmDelete({{ source.id }}, '{{ source.name }}')">
<i class="bi bi-trash"></i>
</button>
</div>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
{% else %}
<div class="card shadow">
<div class="card-body text-center py-5">
<i class="bi bi-hdd-rack display-1 text-muted mb-4"></i>
<h3>No Media Sources Found</h3>
<p class="text-muted">Add your first media source to get started.</p>
<button type="button" class="btn btn-primary mt-3" data-bs-toggle="modal" data-bs-target="#addSourceModal">
<i class="bi bi-plus-circle me-2"></i>Add Media Source
</button>
</div>
</div>
{% endif %}
<!-- Add/Edit Source Modal -->
<div class="modal fade" id="sourceModal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<form id="sourceForm" method="post">
<div class="modal-header">
<h5 class="modal-title" id="modalTitle">Add Media Source</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<input type="hidden" name="id" id="sourceId">
<div class="mb-3">
<label for="name" class="form-label">Name</label>
<input type="text" class="form-control" id="name" name="name" required>
</div>
<div class="mb-3">
<label for="type" class="form-label">Type</label>
<select class="form-select" id="type" name="type" required>
<option value="jellyfin">Jellyfin</option>
<option value="local">Local Filesystem</option>
<option value="samba">Samba Share</option>
<option value="nfs">NFS Share</option>
</select>
</div>
<div class="mb-3">
<label for="path" class="form-label">Path/URL</label>
<input type="text" class="form-control" id="path" name="path" required>
<div class="form-text">
For Jellyfin: http(s)://server:port<br>
For local: /path/to/media<br>
For network shares: //server/share or nfs://server/path
</div>
</div>
<div class="mb-3">
<label for="username" class="form-label">Username (if required)</label>
<input type="text" class="form-control" id="username" name="username">
</div>
<div class="mb-3">
<label for="password" class="form-label">Password (if required)</label>
<input type="password" class="form-control" id="password" name="password">
</div>
<div class="form-check form-switch mb-3">
<input class="form-check-input" type="checkbox" id="isActive" name="is_active" checked>
<label class="form-check-label" for="isActive">Active</label>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
<button type="submit" class="btn btn-primary">Save</button>
</div>
</form>
</div>
</div>
</div>
<!-- Delete Confirmation Modal -->
<div class="modal fade" id="deleteModal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Confirm Deletion</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<p>Are you sure you want to delete <strong id="sourceName"></strong>?</p>
<p class="text-danger">This action cannot be undone and will remove all associated media data.</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
<form id="deleteForm" method="post" action="">
<button type="submit" class="btn btn-danger">Delete</button>
</form>
</div>
</div>
</div>
</div>
{% endblock %}
{% block scripts %}
<script>
// Initialize tooltips
var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'))
var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
return new bootstrap.Tooltip(tooltipTriggerEl)
});
// Handle add source button
document.getElementById('addSourceBtn').addEventListener('click', function() {
document.getElementById('modalTitle').textContent = 'Add Media Source';
document.getElementById('sourceForm').reset();
document.getElementById('sourceId').value = '';
document.getElementById('sourceForm').action = '{{ path_for("admin.sources.store") }}';
var modal = new bootstrap.Modal(document.getElementById('sourceModal'));
modal.show();
});
// Handle edit source
function editSource(source) {
document.getElementById('modalTitle').textContent = 'Edit Media Source';
document.getElementById('sourceId').value = source.id;
document.getElementById('name').value = source.name;
document.getElementById('type').value = source.type;
document.getElementById('path').value = source.path;
document.getElementById('username').value = source.username || '';
document.getElementById('isActive').checked = source.is_active;
document.getElementById('sourceForm').action = '{{ path_for("admin.sources.update", {id: 0}) }}'.replace('/0', '/' + source.id);
var modal = new bootstrap.Modal(document.getElementById('sourceModal'));
modal.show();
}
// Handle delete confirmation
function confirmDelete(id, name) {
document.getElementById('sourceName').textContent = name;
document.getElementById('deleteForm').action = '{{ path_for("admin.sources.destroy", {id: 0}) }}'.replace('/0', '/' + id);
var modal = new bootstrap.Modal(document.getElementById('deleteModal'));
modal.show();
}
</script>
{% endblock %}