first commit
This commit is contained in:
@@ -0,0 +1,225 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}Actions — JH Photomaton{% endblock %}
|
||||
|
||||
{% block nav_links %}
|
||||
<a href="/admin">Dashboard</a>
|
||||
<a href="/admin/gallery">Galerie admin</a>
|
||||
<a href="/admin/print">Impression</a>
|
||||
<a href="/admin/actions" class="active">Actions</a>
|
||||
<a href="/gallery">Galerie publique</a>
|
||||
<a href="/admin/logout" style="margin-left:auto;color:var(--text-dim)">Déconnexion</a>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container">
|
||||
<h1 class="page-title">Gestion des actions & mapping bouton</h1>
|
||||
|
||||
<!-- Mapping clics → actions -->
|
||||
<div class="section">
|
||||
<div class="card-title">Mapping bouton → actions photobooth-app</div>
|
||||
<div class="card">
|
||||
<p class="text-sm text-muted mb-2">Associe chaque nombre de clics à une action dans photobooth-app. L'index correspond à la position dans la liste des actions (0 = première action).</p>
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Clics</th>
|
||||
<th>Label affiché</th>
|
||||
<th>Index action (photobooth)</th>
|
||||
<th>Action correspondante</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for n in range(1, 5) %}
|
||||
{% set mapping = button_mapping.get(n) or button_mapping.get(n|string) or {} %}
|
||||
<tr>
|
||||
<td class="font-bold">
|
||||
{% if n == 1 %}1 clic{% else %}{{ n }} clics{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" id="label-{{ n }}" class="form-control" style="max-width:200px"
|
||||
value="{{ mapping.get('label', '') }}" placeholder="Label…">
|
||||
</td>
|
||||
<td>
|
||||
<select id="index-{{ n }}" class="form-control" style="max-width:80px">
|
||||
{% for i in range(pb_actions|length) %}
|
||||
<option value="{{ i }}" {% if mapping.get('photobooth_index') == i %}selected{% endif %}>{{ i }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</td>
|
||||
<td class="text-sm text-muted" id="action-name-{{ n }}">
|
||||
{% set idx = mapping.get('photobooth_index', 0) %}
|
||||
{% if pb_actions and idx < pb_actions|length %}
|
||||
{{ pb_actions[idx].name }}
|
||||
{% else %}—{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
<button class="btn btn-ghost btn-sm" onclick="testAction({{ n }})">▶ Test</button>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<button class="btn btn-primary mt-2" onclick="saveMapping()">💾 Sauvegarder le mapping</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Actions photobooth-app -->
|
||||
<div class="section">
|
||||
<div class="card-title">Actions image photobooth-app ({{ pb_actions|length }} au total)</div>
|
||||
<div id="actions-list">
|
||||
{% for action in pb_actions %}
|
||||
<div class="card mb-1" id="action-{{ loop.index0 }}" style="margin-bottom:0.75rem">
|
||||
<div class="flex items-center justify-between mb-1">
|
||||
<div>
|
||||
<span class="badge badge-muted text-xs">Action {{ loop.index0 }}</span>
|
||||
<span class="font-bold" style="margin-left:0.5rem">{{ action.name }}</span>
|
||||
</div>
|
||||
<div class="flex gap-1">
|
||||
<button class="btn btn-ghost btn-sm" onclick="toggleEdit({{ loop.index0 }})">✏ Modifier</button>
|
||||
<button class="btn btn-ghost btn-sm" onclick="triggerAction({{ loop.index0 }})">▶ Déclencher</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Infos résumées -->
|
||||
<div class="flex gap-2 text-sm text-muted" id="summary-{{ loop.index0 }}">
|
||||
<span>⏱ {{ action.jobcontrol.get('countdown_capture', '?') }}s</span>
|
||||
{% if action.processing.get('img_frame_file') %}
|
||||
<span>🖼 {{ action.processing.img_frame_file.split('/')[-1] }}</span>
|
||||
{% endif %}
|
||||
{% if action.processing.get('remove_background') %}
|
||||
<span class="badge badge-info">Remove BG</span>
|
||||
{% endif %}
|
||||
{% if action.processing.get('img_background_file') %}
|
||||
<span>🌄 {{ action.processing.img_background_file.split('/')[-1] }}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- Formulaire d'édition (masqué par défaut) -->
|
||||
<div class="edit-form mt-2" id="edit-{{ loop.index0 }}" style="display:none;border-top:1px solid var(--border);padding-top:1rem">
|
||||
<div class="grid-2">
|
||||
<div class="form-group">
|
||||
<label class="form-label">Nom de l'action</label>
|
||||
<input type="text" class="form-control" id="e-name-{{ loop.index0 }}" value="{{ action.name }}">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">Countdown (secondes)</label>
|
||||
<input type="number" class="form-control" id="e-countdown-{{ loop.index0 }}"
|
||||
value="{{ action.jobcontrol.get('countdown_capture', 5) }}" min="1" max="30" step="0.5">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">Cadre (img_frame_file)</label>
|
||||
<input type="text" class="form-control" id="e-frame-{{ loop.index0 }}"
|
||||
value="{{ action.processing.get('img_frame_file', '') or '' }}" placeholder="userdata/…/cadre.png">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">Fond (img_background_file)</label>
|
||||
<input type="text" class="form-control" id="e-bg-{{ loop.index0 }}"
|
||||
value="{{ action.processing.get('img_background_file', '') or '' }}" placeholder="userdata/…/fond.jpg">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">Filtre image</label>
|
||||
<select class="form-control" id="e-filter-{{ loop.index0 }}">
|
||||
<option value="original" {% if action.processing.get('image_filter','original') == 'original' %}selected{% endif %}>original</option>
|
||||
<option value="FilterPilgram2.earlybird" {% if 'earlybird' in (action.processing.get('image_filter','')) %}selected{% endif %}>Earlybird</option>
|
||||
<option value="FilterPilgram2.reyes" {% if 'reyes' in (action.processing.get('image_filter','')) %}selected{% endif %}>Reyes</option>
|
||||
<option value="FilterPilgram2.moon" {% if 'moon' in (action.processing.get('image_filter','')) %}selected{% endif %}>Moon</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label flex items-center gap-1">
|
||||
<input type="checkbox" id="e-rmbg-{{ loop.index0 }}" {% if action.processing.get('remove_background') %}checked{% endif %}>
|
||||
Remove Background (MODNet — ~400Mo RAM)
|
||||
</label>
|
||||
<label class="form-label flex items-center gap-1 mt-1">
|
||||
<input type="checkbox" id="e-bgena-{{ loop.index0 }}" {% if action.processing.get('img_background_enable') %}checked{% endif %}>
|
||||
Activer le fond
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex gap-1">
|
||||
<button class="btn btn-primary btn-sm" onclick="saveAction({{ loop.index0 }})">💾 Sauvegarder</button>
|
||||
<button class="btn btn-ghost btn-sm" onclick="toggleEdit({{ loop.index0 }})">Annuler</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="empty-state"><div class="icon">⚙️</div>Aucune action configurée dans photobooth-app</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script>
|
||||
// ── Formulaires d'édition ─────────────────────────────────────────────────────
|
||||
function toggleEdit(idx) {
|
||||
const el = document.getElementById('edit-' + idx);
|
||||
const sum = document.getElementById('summary-' + idx);
|
||||
const open = el.style.display === 'none';
|
||||
el.style.display = open ? 'block' : 'none';
|
||||
sum.style.display = open ? 'none' : 'flex';
|
||||
}
|
||||
|
||||
async function saveAction(idx) {
|
||||
const updates = {
|
||||
name: document.getElementById('e-name-' + idx).value,
|
||||
countdown_capture: parseFloat(document.getElementById('e-countdown-' + idx).value),
|
||||
img_frame_file: document.getElementById('e-frame-' + idx).value || null,
|
||||
img_background_file: document.getElementById('e-bg-' + idx).value || null,
|
||||
image_filter: document.getElementById('e-filter-' + idx).value,
|
||||
remove_background: document.getElementById('e-rmbg-' + idx).checked,
|
||||
img_background_enable: document.getElementById('e-bgena-' + idx).checked,
|
||||
};
|
||||
try {
|
||||
await api('PUT', `/api/actions/photobooth/${idx}`, updates);
|
||||
showToast('✅ Action sauvegardée — redémarrage photobooth-app requis', 'success', 6000);
|
||||
toggleEdit(idx);
|
||||
} catch(e) {
|
||||
showToast('❌ Erreur sauvegarde', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
async function triggerAction(idx) {
|
||||
if (!confirm(`Déclencher l'action ${idx} (prise de photo) ?`)) return;
|
||||
try {
|
||||
await api('POST', `/api/actions/trigger/${idx}`);
|
||||
showToast(`▶ Action ${idx} déclenchée`, 'info');
|
||||
} catch(e) { showToast('Erreur déclenchement', 'error'); }
|
||||
}
|
||||
|
||||
// ── Mapping bouton ─────────────────────────────────────────────────────────────
|
||||
async function saveMapping() {
|
||||
const mapping = {};
|
||||
for (let n = 1; n <= 4; n++) {
|
||||
mapping[n] = {
|
||||
label: document.getElementById('label-' + n).value,
|
||||
photobooth_index: parseInt(document.getElementById('index-' + n).value),
|
||||
};
|
||||
}
|
||||
try {
|
||||
await api('PUT', '/api/actions/mapping', mapping);
|
||||
showToast('✅ Mapping sauvegardé', 'success');
|
||||
} catch(e) { showToast('❌ Erreur sauvegarde mapping', 'error'); }
|
||||
}
|
||||
|
||||
async function testAction(n) {
|
||||
const idx = parseInt(document.getElementById('index-' + n).value);
|
||||
if (!confirm(`Déclencher l'action ${idx} pour tester le ${n} clic ?`)) return;
|
||||
try {
|
||||
await api('POST', `/api/actions/trigger/${idx}`);
|
||||
showToast(`▶ Test ${n} clic → action ${idx}`, 'info');
|
||||
} catch(e) { showToast('Erreur', 'error'); }
|
||||
}
|
||||
|
||||
// Mise à jour du nom de l'action quand on change l'index
|
||||
{% for n in range(1, 5) %}
|
||||
document.getElementById('index-{{ n }}').addEventListener('change', function() {
|
||||
const names = {{ pb_actions | map(attribute='name') | list | tojson }};
|
||||
document.getElementById('action-name-{{ n }}').textContent = names[this.value] || '—';
|
||||
});
|
||||
{% endfor %}
|
||||
</script>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user