Permet de vérifier en un clic que le serveur et le topic ntfy
renseignés fonctionnent, avant d'attendre un vrai rappel. Le bouton
envoie une notification de test via la même chaîne que les rappels
réels (donc tracée dans /logs), et affiche le résultat inline.
La fonction send_ntfy retourne désormais un booléen de succès pour
permettre ce retour utilisateur.
💘 Generated with Crush
Assisted-by: Crush:glm-5.2
240 lines
8.4 KiB
HTML
240 lines
8.4 KiB
HTML
{% extends "base.html" %}
|
|
{% block content %}
|
|
<div class="stats-head">
|
|
<div>
|
|
<span class="stats-title">Réglages</span>
|
|
<div class="stats-meta">Rappels de pointage sur ton téléphone</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="settings-card">
|
|
<span class="hist-label">Plages horaires</span>
|
|
<p class="settings-p">
|
|
Bornes de présence obligatoire matin/après-midi et heure de reprise par défaut de
|
|
l'après-midi, utilisées pour les avertissements de saisie et les préconisations de
|
|
fin de demi-journée. Les heures visées (arrivée le matin, départ le soir) guident
|
|
les préconisations : le matin est planifié depuis ton arrivée visée, et le rattrapage
|
|
est casé avant ton départ visé tant que c'est possible. Propres à ton compte —
|
|
ne change rien pour les autres.
|
|
</p>
|
|
|
|
{% if plages_saved %}
|
|
<div class="settings-saved">Enregistré.</div>
|
|
{% endif %}
|
|
{% if plages_error %}
|
|
<div class="settings-error">Horaires invalides (format HH:MM, matin_debut < matin_fin < aprem_debut < aprem_fin).</div>
|
|
{% endif %}
|
|
|
|
<form method="post" action="/settings/plages" class="settings-form">
|
|
<label class="login-label" for="matin_debut">Présence matin</label>
|
|
<div class="settings-range">
|
|
<input id="matin_debut" class="login-input time-range-input" type="time" name="matin_debut" value="{{ plages.matin_debut }}">
|
|
<span class="settings-range-sep">→</span>
|
|
<input id="matin_fin" class="login-input time-range-input" type="time" name="matin_fin" value="{{ plages.matin_fin }}">
|
|
</div>
|
|
<label class="login-label" for="aprem_debut">Présence après-midi</label>
|
|
<div class="settings-range">
|
|
<input id="aprem_debut" class="login-input time-range-input" type="time" name="aprem_debut" value="{{ plages.aprem_debut }}">
|
|
<span class="settings-range-sep">→</span>
|
|
<input id="aprem_fin" class="login-input time-range-input" type="time" name="aprem_fin" value="{{ plages.aprem_fin }}">
|
|
</div>
|
|
<label class="login-label" for="pause_dejeuner_fin">Reprise par défaut de l'après-midi</label>
|
|
<input id="pause_dejeuner_fin" class="login-input time-range-input" type="time" name="pause_dejeuner_fin" value="{{ plages.pause_dejeuner_fin }}">
|
|
<label class="login-label" for="arrivee_visee">Heures visées arrivée / départ (optionnel)</label>
|
|
<div class="settings-range">
|
|
<input id="arrivee_visee" class="login-input time-range-input" type="time" name="arrivee_visee" value="{{ plages.arrivee_visee }}">
|
|
<span class="settings-range-sep">→</span>
|
|
<input id="depart_vise" class="login-input time-range-input" type="time" name="depart_vise" value="{{ plages.depart_vise }}" aria-label="Départ visé le soir">
|
|
</div>
|
|
<button class="login-btn" type="submit">Enregistrer</button>
|
|
</form>
|
|
</div>
|
|
|
|
<div class="settings-card">
|
|
<span class="hist-label">Notifications (ntfy) <a href="/aide" class="settings-help-link">Aide</a></span>
|
|
<p class="settings-p">
|
|
Crée un topic sur ton serveur <a href="https://ntfy.sh" target="_blank" rel="noopener">ntfy</a>
|
|
(public ou auto-hébergé), un identifiant secret que toi seul connais, abonne-toi dessus avec
|
|
l'app ntfy sur ton téléphone, puis renseigne les deux champs ci-dessous. Guide complet sur
|
|
la page <a href="/aide">Aide</a>.
|
|
</p>
|
|
|
|
{% if saved %}
|
|
<div class="settings-saved">Enregistré.</div>
|
|
{% endif %}
|
|
|
|
<form method="post" action="/settings" class="settings-form">
|
|
<label class="login-label" for="ntfy_server">Serveur ntfy</label>
|
|
<input
|
|
id="ntfy_server"
|
|
class="login-input"
|
|
type="text"
|
|
name="ntfy_server"
|
|
value="{{ ntfy_server }}"
|
|
placeholder="https://ntfy.sh"
|
|
autocomplete="off"
|
|
>
|
|
<label class="login-label" for="ntfy_topic">Topic ntfy</label>
|
|
<input
|
|
id="ntfy_topic"
|
|
class="login-input"
|
|
type="text"
|
|
name="ntfy_topic"
|
|
value="{{ ntfy_topic }}"
|
|
placeholder="ex: antoine-pointeuse-x7f2"
|
|
autocomplete="off"
|
|
>
|
|
<label class="login-label" for="rappel_debut_h">Plage horaire des rappels</label>
|
|
<div class="settings-range">
|
|
<input
|
|
id="rappel_debut_h"
|
|
class="login-input settings-range-input"
|
|
type="number" min="0" max="23" name="rappel_debut_h"
|
|
value="{{ rappel_debut_h }}"
|
|
>
|
|
<span class="settings-range-sep">h → </span>
|
|
<input
|
|
id="rappel_fin_h"
|
|
class="login-input settings-range-input"
|
|
type="number" min="1" max="24" name="rappel_fin_h"
|
|
value="{{ rappel_fin_h }}"
|
|
>
|
|
<span class="settings-range-sep">h, jours ouvrés</span>
|
|
</div>
|
|
<button class="login-btn" type="submit">Enregistrer</button>
|
|
</form>
|
|
<div class="settings-test-row">
|
|
<button
|
|
class="login-btn settings-test-btn"
|
|
hx-post="/settings/test-ntfy"
|
|
hx-target="#ntfy-test-result"
|
|
hx-swap="innerHTML"
|
|
hx-disabled-elt="this"
|
|
>Tester la notification</button>
|
|
<span id="ntfy-test-result"></span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="settings-card">
|
|
<span class="hist-label">Détection de présence (Tasker) <a href="/aide" class="settings-help-link">Aide</a></span>
|
|
<p class="settings-p">
|
|
Crée une automatisation Tasker déclenchée par une géofence autour du bureau : à l'<b>entrée</b> de la
|
|
zone, appelle l'URL "arrivée" ; à la <b>sortie</b>, l'URL "départ". Tant que tu es détecté présent sans
|
|
avoir pointé l'entrée du matin, ou parti sans avoir pointé la sortie, tu reçois un rappel toutes les
|
|
5 minutes, dans la plage horaire réglée ci-dessus (jours ouvrés). Étapes détaillées sur la page
|
|
<a href="/aide">Aide</a>.
|
|
</p>
|
|
<div class="settings-urlrow">
|
|
<span class="settings-urllabel">Arrivée</span>
|
|
<code class="settings-url">{{ arrivee_url }}</code>
|
|
</div>
|
|
<div class="settings-urlrow">
|
|
<span class="settings-urllabel">Départ</span>
|
|
<code class="settings-url">{{ depart_url }}</code>
|
|
</div>
|
|
<p class="settings-hint">
|
|
Ces URLs sont secrètes (elles contiennent ton token) — ne les partage pas.
|
|
</p>
|
|
</div>
|
|
|
|
<style>
|
|
.settings-card {
|
|
background: var(--surface);
|
|
border: 1.5px solid var(--rule);
|
|
padding: 1.25rem 1.5rem;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: .75rem;
|
|
}
|
|
.settings-p { font-size: 13px; color: var(--text); line-height: 1.6; }
|
|
.settings-p a { color: var(--accent); }
|
|
.settings-form { display: flex; flex-direction: column; gap: .5rem; max-width: 420px; }
|
|
.settings-saved {
|
|
background: var(--pos-bg);
|
|
border-left: 3px solid var(--pos);
|
|
color: var(--pos);
|
|
font-size: 12px;
|
|
padding: .5rem .8rem;
|
|
font-family: var(--mono);
|
|
}
|
|
.settings-error {
|
|
background: var(--neg-bg);
|
|
border-left: 3px solid var(--neg);
|
|
color: var(--neg);
|
|
font-size: 12px;
|
|
padding: .5rem .8rem;
|
|
font-family: var(--mono);
|
|
}
|
|
.settings-urlrow { display: flex; align-items: center; gap: .75rem; flex-wrap: wrap; }
|
|
.settings-urllabel {
|
|
font-family: var(--mono);
|
|
font-size: 10px;
|
|
letter-spacing: .08em;
|
|
text-transform: uppercase;
|
|
color: var(--muted);
|
|
width: 70px;
|
|
flex-shrink: 0;
|
|
}
|
|
.settings-url {
|
|
font-family: var(--mono);
|
|
font-size: 12px;
|
|
color: var(--text);
|
|
background: var(--ground);
|
|
border: 1px solid var(--rule);
|
|
padding: .4rem .6rem;
|
|
word-break: break-all;
|
|
}
|
|
.settings-hint { font-size: 11px; color: var(--muted); }
|
|
.settings-range { display: flex; align-items: center; gap: .4rem; flex-wrap: wrap; }
|
|
.settings-range-input { width: 70px; text-align: center; }
|
|
.settings-range-sep { font-size: 12px; color: var(--muted); font-family: var(--mono); }
|
|
.time-range-input {
|
|
width: 128px;
|
|
text-align: left;
|
|
padding-right: .4rem;
|
|
}
|
|
.time-range-input::-webkit-calendar-picker-indicator {
|
|
margin-left: .5rem;
|
|
}
|
|
.settings-help-link {
|
|
font-family: var(--mono);
|
|
font-size: 10px;
|
|
letter-spacing: .04em;
|
|
color: var(--accent);
|
|
text-decoration: none;
|
|
border: 1px solid var(--rule);
|
|
padding: .1rem .4rem;
|
|
margin-left: .5rem;
|
|
vertical-align: middle;
|
|
transition: border-color .15s, background .15s;
|
|
}
|
|
.settings-help-link:hover {
|
|
border-color: var(--accent);
|
|
background: rgba(47,95,160,.06);
|
|
}
|
|
.settings-test-row {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: .75rem;
|
|
flex-wrap: wrap;
|
|
max-width: 420px;
|
|
}
|
|
.settings-test-btn {
|
|
flex-shrink: 0;
|
|
}
|
|
#ntfy-test-result {
|
|
flex: 1;
|
|
min-width: 0;
|
|
}
|
|
#ntfy-test-result:empty { display: none; }
|
|
#ntfy-test-result:not(:empty) {
|
|
font-family: var(--mono);
|
|
font-size: 12px;
|
|
padding: .5rem .8rem;
|
|
border-left: 3px solid var(--muted);
|
|
background: var(--ground);
|
|
line-height: 1.45;
|
|
}
|
|
</style>
|
|
{% endblock %}
|