Compare commits

..

4 Commits

Author SHA1 Message Date
Quentin Rouiller 86f52029f5 v5.0.4 — Améliorations admin/UX 2026-04-21 12:40:08 +02:00
Quentin Rouiller 984f326b39 v5.0.3 — Ajustements admin et stabilité 2026-04-20 14:03:34 +02:00
Quentin Rouiller 6d3058028f v5.0.1 — Refonte topbar : horloge HH:MM + compteur session EV + admin caché (5 clics titre) 2026-04-20 13:21:16 +02:00
Quentin Rouiller c59abbed23 v4.3.3 — Soft unpin popup + nettoyage tooltip persistance 2026-04-20 09:13:20 +02:00
14 changed files with 2923 additions and 10959 deletions
-40
View File
@@ -1,40 +0,0 @@
# OS
.DS_Store
Thumbs.db
desktop.ini
# Editors
.vscode/
.idea/
*.swp
*.swo
*~
# Backups
*.bak
*.bak-*
*.orig
*.old
# Build artifacts (les ZIP/XPI livrés ne sont pas dans le repo, ils sont buildés à la demande)
dist/
*.zip
*.xpi
*.crx
# Node (si jamais utilisé pour build)
node_modules/
package-lock.json
npm-debug.log*
# Logs
*.log
rebuild.log
# Dossiers de travail temporaires
extracted/
temp/
tmp/
# Tests
test-output/
-355
View File
@@ -1,355 +0,0 @@
# CHANGELOG — Extension Planification EasyVista Canton de Vaud
> Ce changelog documente l'évolution de l'extension Chrome/Firefox "Planification"
> développée par Quentin Rouiller pour les techniciens DGNSI (Canton de Vaud).
>
> Les versions documentées ci-dessous sont celles dont les détails sont connus.
> Pour les versions plus anciennes, Claude Code se basera sur l'analyse du code
> source pour déterminer un message de commit pertinent.
---
## v2026.5.41 — Suppression des hardcodes (groupe / domaines / équipe) → tout depuis l'admin
### Plus aucun hardcode au runtime
- Le groupe EasyVista, les domaines (interne/externe) et la liste des
techniciens ne sont **plus codés en dur** dans `background.js` /
`viewer.js`. Tout est lu depuis `admin_config` (chrome.storage.local),
alimenté par les onglets **Équipe** et **EasyVista** du panel admin.
- `chrome.storage.local` survit aux mises à jour d'extension → la
configuration de l'utilisateur (groupe, équipe, absences récurrentes,
domaines) est conservée d'une version à l'autre.
### Domaines EasyVista (interne / externe)
- Défaut hardcodé conservé comme **filet de sécurité** au 1er install
(`https://itsma.etat-de-vaud.ch` + `https://itsma.vd.ch`).
- L'utilisateur peut les remplacer dans Paramètres → EasyVista. Le
service worker (`findEasyVistaSession`, `evFetch`, etc.) lit la valeur
effective via `getEvOrigins()`.
### Group ID EasyVista
- Défaut hardcodé conservé comme filet de sécurité (`191` = SI-CSS).
- Lu via `getGroupId()` dans `fetchPlanningXml`, `detectTeamFromEV` et
partout où c'était hardcodé.
- Le sélecteur de Paramètres → Équipe alimente `cfg.groupId`.
### Liste des techniciens
- **Aucun défaut hardcodé**. Sur un install vierge, `cfg.team` est
vide → le service worker lève `no_team_configured` plutôt que de
fetcher avec une liste fictive.
- Le viewer affiche : *"Aucun technicien sélectionné. Ouvrez ⚙
Paramètres → Équipe pour choisir le groupe EasyVista et cocher les
techniciens à afficher."*
- Lu via `getSupportIds()` (CSV des clés de `cfg.team`).
- Côté `viewer.js` : `TEAM` et `RECURRING_ABSENCES` sont des `let`
vides au démarrage, repeuplés par `_initTeamFromConfig()` appelé tôt
dans `init()`.
### Coulisses
- Nouveau dans `background.js` : helpers `getAdminConfig()`,
`getEvOrigins()`, `getGroupId()`, `getSupportIds()`,
`getDayBounds()` qui centralisent la lecture de la config persistée.
- `fetchPlanningXml()` lève `Error("no_team_configured")` quand la
liste de techs est vide ; le handler `fetchPlanning` propage l'erreur
au viewer via `err.kind`.
- Toutes les anciennes constantes hardcodées (`EV_ORIGINS`,
`DEFAULT_SUPPORT_IDS` interne à `detectTeamFromEV`,
`isPillonelAbsentFriday`) ont été remplacées ou retirées.
### Conflits absence/réservation × intervention
- Nouveau code visuel : si une intervention est planifiée pendant
qu'un tech a une **absence** (toute la journée ou demi-journée) ou
une **réservation** sur le même créneau, sa carte (row classique +
mini-card en vue horizontale) est peinte en **rouge plein** avec
texte blanc. Logique : full-day → toutes les interv en rouge ;
partiel → seules celles en chevauchement.
### Synchronisation des heures EV ↔ admin
- Les paramètres `day_start_hour` / `day_end_hour` envoyés à
`planning_xhr.php` et `begin_hour` / `end_hour` envoyés à
`plan_set_holidays_popup.php` (création absence) et
`plan_set_tech_planif_popup.php` (douchette) lisent désormais
`cfg.dayStart` / `cfg.dayEnd` (Paramètres → Apparence → Heures de la
journée). Avant : `8` / `18` / `19` figés en dur, ce qui rendait le
réglage des heures côté UI partiellement effectif (la timeline se
redessinait, mais les requêtes EV continuaient sur la plage hardcodée).
### Édition des domaines EV → permissions runtime
- `manifest.json` : ajout de `"optional_host_permissions":
["https://*/*"]` pour permettre l'édition des domaines EasyVista
vers des origines non prévues à l'install.
- Quand l'utilisateur saisit un domaine custom dans Paramètres →
EasyVista et clique sur Enregistrer, l'extension appelle
`chrome.permissions.request()` pour demander la permission au
navigateur. Si refus → toast d'avertissement, les fetches échoueront
jusqu'à acceptation.
- Les deux domaines hardcodés (`itsma.etat-de-vaud.ch` +
`itsma.vd.ch`) restent dans `host_permissions` (toujours accordés à
l'install), pas besoin de redemander la permission pour eux.
## v2026.5.40 — Vue horizontale enrichie (ref + ville + barre couleur)
**Branche** : current
- En vue horizontale, chaque segment timeline d'intervention contient
désormais :
- Une **barre verticale couleur catégorie** à gauche (mêmes teintes que
les `.intervention-dot` de la vue classique : livraison/recup/
remplacement/incident/rollout/réservation/autre)
- La **référence** (ex: `SYYMMDD_NNNNN`) en gras
- La **ville** en gris muted
- Hauteur de la timeline en horizontale passée de 22px à 32px pour laisser
la place au texte
- Fond des segments d'intervention : `--bg-elevated` neutre + bordure 1px
pour que le texte reste lisible (la couleur catégorie n'est plus en fond
plein, juste en barre gauche)
- Vue classique inchangée
- Réorganisation interne du repo : `src/` pour les sources, `dist/`
généré, `Autres/` pour build.sh + meta files (LICENSE, README,
CHANGELOG)
## v2026.5.39 — Séparation Matin / Après-midi + Apparence (thème, zoom, cache)
### Séparation matin / après-midi
- Séparateur visuel "MATIN" / "APRÈS-MIDI" entre les interventions
dans la vue classique : pill grise neutre, ligne 3px épaisse.
- Affiché aussi entre les absences partielles (demi-journée).
- Si une période est vide, son séparateur n'est pas affiché.
- Caché en vue horizontale (les rows sont masquées de toute façon).
### Timeline — coupure midi très visible
- Bande verticale composée d'un trait massif central (couleur --text)
+ stripes diagonales en arrière-plan (effet "césure"). 6 px de large
(7 px en vue horizontale). Visible immédiatement, pas de label superflu.
### Vue horizontale (sidebar)
- Boutons (Absence, Douchette, Actualiser, Tout recharger, Vider cache,
Thème) maintenant **vraiment** poussés en bas via `min-height: 100vh`
sur la sidebar.
- Bouton "Aujourd'hui" : style cohérent avec les flèches ◀ ▶ (même
padding, font-size, hauteur), texte centré, libellé complet
"Aujourd'hui" (au lieu de "Auj.").
- Espace visuel entre `Actualisé à HH:MM` et le bouton Absence (fine
bordure top + padding).
### Vue classique (topbar)
- Ordre verrouillé via CSS `order` : badge user → titre → date-nav →
capture-info → refresh-check. Évite les déplacements au retour de
vue horizontale.
### Section Apparence (admin) — refondue + en première position
- **Thème** : sélecteur Auto / Clair / Sombre (s'enregistre direct).
- **Durée du cache (jours)** : configurable, défaut 7 jours, range 1-365.
Lue par viewer.js (purge auto) ET background.js (au boot).
- **Taille du texte** : 5 niveaux (-20%, -10%, 100%, +10%, +20%) via CSS
`zoom` sur body. Persisté dans admin_config.textZoom et appliqué dès
le boot.
- Section "Apparence" est maintenant **la première** dans le panel admin.
## v2026.5.38 — Attribution auteur + nettoyage code
**Branche** : current
### Attribution auteur
- Ajout en-têtes copyright dans tous les fichiers source
(viewer.js, viewer.html, viewer.css, background.js)
- Ajout `@author Quentin Rouiller` sur les fonctions principales
(loadForDate, buildCard, buildTooltipHTML, pinTooltip, _softUnpinPopup,
positionTooltipAnchored, _applyViewMode, _moveElementsToSidebar,
_restoreElementsToTopbar, fetchAndShowCurrentUser, _maybeRetryFetchUser,
initAppClock, initAppFooter, bindTimelinePopover,
openPersistentTimelinePopup, showTooltip, _findFreePopupPosition,
_clampPopupInSafeArea, findEasyVistaSession, fetchPlanningXml,
fetchCurrentUser, detectNetworkContext)
- Ajout signature "Développé par Quentin Rouiller" en bas du popup
user-badge (style cohérent avec footer version : 11px, italique,
gris atténué, séparateur fin)
- Mise à jour `description` du manifest pour mentionner DGNSI
### Nettoyage et optimisation
- Retrait fonction vide `initAdminMenu()` (inutile depuis v2026.5.25,
l'admin passe par le bouton ⚙ Paramètres du popup user-badge)
- Retrait classe CSS orpheline `.date-picker-day` (déjà remplacée par
`.date-custom` en v2026.5.17)
- Retrait anciens styles CSS `.intervention` (layout v1, jamais générés
depuis le passage à `.intervention-v2`)
- Retrait commentaire orphelin `.intervention-v2.is-ghost` (classe
retirée en v4.3.3)
- Retrait 14× `console.log("[viewMode]")` debug verbose (gardé
uniquement les `console.warn` utiles pour erreurs)
- Retrait 5× `console.log("[bg]")` debug verbose dans
fetchPlanningXml / fetchFicheHtml / fetchSessionTimeRemaining /
extendSessionKeepAlive (gardé warnings + logs critiques)
- Remplacement `extendBtn.onclick` par `addEventListener("click", ...)`
pour plus de cohérence
### Builds
- `dist/chromium/` et `dist/firefox/` prêts à charger en mode dev
- `planification-v2026.5.38-chromium.zip` (~144 Ko)
- `planification-v2026.5.38-firefox.xpi` (~144 Ko, à signer sur AMO)
## v2026.5.37 — Refonte vue horizontale (sidebar complète)
- Topbar en haut supprimée en vue horizontale
- User-badge + titre déplacés tout en haut de la sidebar
- Bouton "Aujourd'hui" pleine largeur avec icône ↺
- Date + heure centrés sous le bouton
- Séparateur visuel
- Sélecteur de date pleine largeur
- Flèches ◀ ▶ côte à côte (wrapper #sidebar-arrows)
- Stats empilées
- Synchronisé à HH:MM
- Espace vide intentionnel
- Boutons du bas vers le haut (margin-top: auto sur Absence)
- Barre de rafraîchissement en overlay top-left
- Banderole pompier masquée en vue horizontale (badge + barre rouge à gauche conservés)
## v2026.5.36 — Sidebar verticale en vue horizontale
- Création wrapper flex-row #horizontal-wrapper contenant [sidebar] + [main]
- Sidebar 200px (170px sur <1400px), sticky, bg-muted
- Déplacement physique des éléments via JS (ELEMENTS_TO_RELOCATE)
- Mémorisation parents d'origine (data-orig-parent + data-orig-index)
- Restauration propre en vue classique
- Zone nom tech : 140px → 120px
## v2026.5.35 — Fix popup épinglé position vue horizontale + stats gauche
- Fix popup épinglé qui partait en haut à gauche en vue horizontale
- Cause : rows .intervention-v2 cachées (display: none) → getBoundingClientRect (0,0,0,0)
- Solution : priorité 1 tooltip visible, priorité 2 segment timeline, fallback srcEl
- Stats globales en colonne verticale 200px à gauche en vue horizontale
- Position sticky, fond bg-muted, séparateurs · masqués
- Zone nom tech 200px → 140px (vue horizontale)
## v2026.5.34 — Bouton 📌 restauré + badge user cliquable
- HTML : badge user toujours visible avec "?" par défaut (retiré class hidden)
- _softUnpinPopup refait en 8 étapes loggées
- Popup reste visible après désépinglage (plus de suppression auto au mouseleave)
- Restauration du bouton 📌 dans .tooltip-actions
- Handler click ré-attaché : clic 📌 = ré-épingle, clic ↻ = recharge
- _ensureSoftUnpinnedCleanupHandler : handler global clic hors popup
- _maybeRetryFetchUser : relance opportuniste après succès planning et reconnexion session
- Logs abondants : [currentUser], [softUnpin], [positionTooltip], [persistentTimeline], [showTooltip]
- Fonction positionTooltipAnchored unifiée (4 candidats droite/gauche/dessous/dessus)
- popup._linkedIv stocké pour ré-épinglage
## v2026.5.33 — Interactions vue horizontale différenciées
- Hover segment timeline en vue horizontale → grande popup directement (openPersistentTimelinePopup)
- Clic segment timeline en vue horizontale → ouvre fiche EasyVista
- Popup absence en vue horizontale : hover uniquement sur badge .card-tech-badge (pas sur carte entière)
- Vue classique : comportement inchangé
## v2026.5.32 — Vue horizontale togglable
- Bouton ⊞ "Vue" dans popup user-badge (à côté ⚙ Paramètres)
- Toggle Vue classique ↔ Vue horizontale persisté localStorage "view_mode"
- HTML class "view-classic" ou "view-horizontal" sur <html>
- Chaque tech = 1 ligne horizontale compacte en mode horizontal
- Card header devient barre latérale gauche fixe 200px
- Interventions détaillées masquées (display: none)
- Timeline horizontale pleine largeur
- Stats rapides .tech-row-stats ajoutés au header (nb interv, Xm · Ya)
## v2026.5.31 — Sarcelle pour absence récurrente (REJETÉ par utilisateur)
- Couleur Pillonel vendredi : sarcelle foncée #0f766e / soft #ccfbf1
- Variables --c-recurring, --c-recurring-soft
- Layout 4 colonnes forcées + scroll interne cartes (REJETÉ : "scroll en continu")
## v2026.5.30 — Absence récurrente cyan + mode compact 24"
- Absence récurrente Pillonel vendredi en cyan
- Mode compact @media (max-width: 1920px) avec grid-template-columns: repeat(4, 1fr)
## v2026.5.29 — Contraste++ + footer
- Contrastes encore plus forts (text-muted #d0d5de dark, #2e3642 light)
- Footer QRO/version : 13px badge avec fond bg-muted + bordure
- Fix highlight row : selector .intervention-v2[data-iv-idx]
- Scroll-into-view automatique au hover segment timeline
## v2026.5.28 — Ajustements visuels absences
- Retrait pastille ronde (.tech-name-dot supprimée) — barre gauche + badge suffisent
- "Maladie" → "Maladie/Accident"
- Contraste textes secondaires +30%
- Popups épinglés width fixe 520px (ne rétrécit plus au resize fenêtre)
- _clampPopupInSafeArea ne rétrécit plus si popup > zone dispo
## v2026.5.27 — Classification absences (Maladie/Congé/Pompier)
- Topbar une ligne : "Jeudi 23.04.26 • 21:55" (gros point •, même taille 22px)
- Fermeture auto popups non-épinglés au survol autre popup/carte
- Texte +20% topbar/stats/boutons
- Icône thème ☀/🌙 plus contrastée (bordure 1.5px, fond bg-muted, ombre)
- Classification absences (ABSENCE_LABELS) + absenceCategory : "maladie"|"conge"|"pompier"|null
- Couleurs : Maladie #4338ca indigo foncé, Congé #06b6d4 cyan, Pompier #b03030 rouge
- Badge + barre gauche + dégradé fond pour catégorie
- Libellé "Absent du DD.MM au DD.MM — Maladie/Accident"
- Suffixe `s` adaptatif (Congé/Congés)
## v2026.5.26 — Badge user inconnu cliquable + retry
- En cas d'échec fetch user, afficher rond gris "?" cliquable
- Bouton ⚙ Paramètres accessible même quand user inconnu
- Retry automatique 60s (max 10 essais = 10 min)
- Reset compteur au succès
## v2026.5.25 — Bouton Paramètres dans popup user-badge
- Remplace les 5 clics sur le titre pour ouvrir admin
- Bouton ⚙ Paramètres explicite dans le popup user-badge
## v2026.5.16-v2026.5.24 — Évolutions diverses (à compléter)
- v2026.5.17 : popup user-badge avec ligne session (MM:SS), couleur selon seuil
- v2026.5.18 : dock pastilles popups épinglés avec couleur catégorie
- v2026.5.19 : drag popup épinglé
- v2026.5.20 : safe area popups (topbar + dock)
- v2026.5.22 : régénération tooltip hover après softUnpin
- v2026.5.23 : reset bulleState.pinned + iv._reloading
---
## Versions antérieures (v5.x et v4.x)
> Ces versions sont à analyser par Claude Code à partir des fichiers source.
> Indices clés à chercher dans le viewer.js :
>
> - Présence de `pinTooltip` → version >= v4.x
> - Présence de `_softUnpinPopup` → version >= v4.3.3
> - Présence de `initSessionTimer` → version >= v5.0.9
> - Présence de `initAppClock` → version >= v5.0.0
> - Présence de `_applyViewMode` → version >= v2026.5.32
> - Présence de `bindTimelinePopover` → version >= v4.2.3
> - Présence de `openPersistentTimelinePopup` → version >= v4.2.3
> - Commentaires `// vX.Y.Z` au-dessus des fonctions = version d'introduction
### v5.0.0 — Refonte topbar (horloge, menu admin)
- initAppClock : horloge HH:MM au milieu topbar
- initAdminMenu : menu admin caché (5 clics sur titre)
- initSessionTimer : compteur de session EV (tick 1s)
### v4.x — Fonctions tooltip avancées
- v4.1.12 : moveTooltip devenu no-op (popup statique)
- v4.1.15 : pendant épinglage, ne pas remplacer contenu sur hover autre iv
- v4.2.3 : grande popup timeline persistante (clic), suit-souris (hover)
- v4.2.3 : bindTimelinePopover, showTimelinePopover, moveTimelineTooltip
- v4.2.4 : setTooltipViewportPosition (détection auto fixed/abs)
- v4.2.9 : pied de page discret QRO/version
- v4.2.9 : initModalScrollLock (bloquer scroll arrière modal)
- v4.3.0 : tooltip live libéré après épinglage (réutilisable autres survols)
- v4.3.3 : _softUnpinPopup (désépinglage mou)
### v3.x et antérieures — Versions de base
- À analyser par Claude Code
---
## Notes techniques persistantes (toutes versions)
- 8 techs hardcodés : "76272,83725,66635,92235,90070,40944,72485,86874"
- Pillonel Olivier (ID 40944) absent tous les vendredis (hardcodé)
- Group ID EasyVista : 191
- Domaines cibles : itsma.etat-de-vaud.ch (interne), itsma.vd.ch (externe)
- SSO : Canton ForgeRock OpenAM
- ABSENCE_LABELS = /^(cong[ée]s|maladie|pompier)$/i
- ADMIN_CONFIG_KEY = "admin_config"
- VIEW_MODE_KEY = "view_mode" (depuis v2026.5.32)
- DAY_NAMES_FULL = ["Dimanche", "Lundi", ..., "Samedi"]
- GUIDs forms EV : S={C99ECD05-3D48-4C62-ABF0-66292053AED6} demande, I={07ED9C68-6172-48EA-8A58-90912B0A283E} incident
- Couleurs catégories : livraison #2563eb, recup #16a34a, remplacement #ea580c, incident #8b5cf6, rollout #92400e, reservation #f59e0b, autre #6b7280
## Auteur
**Quentin Rouiller** (QRO)
Technicien DGNSI — Canton de Vaud
Contact : `quentin.rouiller@vd.ch`
-21
View File
@@ -1,21 +0,0 @@
MIT License
Copyright (c) 2026 Quentin Rouiller
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+84 -231
View File
@@ -1,257 +1,110 @@
# Planification — Extension EasyVista Canton de Vaud
# Planning techniciens — Vue claire (v4.1.2)
Extension Chrome / Firefox pour visualiser de manière claire et rapide le planning des techniciens DGNSI (Canton de Vaud) dans EasyVista.
Extension Chrome/Brave/Edge pour afficher le planning techniciens EasyVista
(`itsma.etat-de-vaud.ch` / `itsma.vd.ch`) dans une vue plus lisible.
## Aperçu rapide
## Nouveautés v4.1.2
- **Auteur** : Quentin Rouiller (QRO)
- **Cible** : techniciens DGNSI (Canton de Vaud), EasyVista (`itsma.etat-de-vaud.ch` / `itsma.vd.ch`)
- **Démarrage projet** : jeudi 16 avril 2026
- **Version actuelle** : `v2026.5.41`
- **Contact** : `quentin.rouiller@vd.ch`
- **Manifest** : V3 (Chrome/Edge/Firefox)
- **Format** : `.zip` (Chromium) + `.xpi` signé (Firefox)
- **Vraies infos contact/lieu dans les cartes** : les attributs attr1/attr2 du
XML contiennent les infos saisies à la *planification*, qui ne sont pas
toujours à jour (le tech a pu corriger le contact/lieu avant intervention).
Désormais, pour chaque intervention, on fetch AUSSI le xhr2 en arrière-plan
(en plus de la fiche), ce qui apporte les **vraies** infos validées. La
carte se met à jour automatiquement quand elles arrivent.
- **Clic ouverture restauré** : retour à la logique v4 (fetch fiche à la volée
+ extraction checksum + construction URL avec sender adéquat). Le checksum
est pré-rempli pendant le fetch arrière-plan, donc au clic l'ouverture est
instantanée dans la plupart des cas.
## Fonctionnalités principales
## Nouveautés v4.1
### Vue planning
- Affichage des interventions et réservations groupées par technicien
- Horaires, contact, lieu, catégorie, statut visibles d'un coup d'œil
- Équipe configurable depuis le panel admin (détection automatique via EasyVista)
- Cache local pour réduire les requêtes serveur
- **Fetch des fiches séquentiel (1 par 1)** au lieu de 5 workers en parallèle.
Le serveur EasyVista sérialise les requêtes de toute façon, donc le parallélisme
n'apporte rien. Et surtout : quand tu changes de date pendant le fetch, l'abort
est **instantané** car il n'y a qu'une seule requête en vol au maximum.
- **Cache incrémental** : le cache est sauvé toutes les 5 fiches pendant le fetch,
pas juste à la fin. Si tu changes de date avant que tout soit fini, les statuts
déjà récupérés sont conservés.
### Modes d'affichage
- **Vue classique** (depuis v1.0.0) : cards en grille, mode compact écran 24" (depuis v2026.5.30)
- **Vue horizontale** (depuis v2026.5.32) : timeline par tech, sidebar verticale (depuis v2026.5.36)
- Depuis v2026.5.40 : barre couleur catégorie + référence + ville sur chaque segment timeline
- Toggle Vue classique ↔ Vue horizontale via bouton ⊞ dans popup user-badge
- Persistance localStorage (`view_mode`)
## Nouveautés v4
### Tooltips et popups
- Tooltips au survol (hover) sur chaque intervention
- Popups épinglables (📌) pour garder ouvert (depuis v4.1.3)
- Popups timeline persistantes au clic (depuis v4.2.3)
- Drag-and-drop des popups épinglés (depuis v2026.5.19)
- Safe area : popups jamais cachés sous topbar/dock (depuis v2026.5.20)
- Position auto adaptative (4 candidats : droite/gauche/dessous/dessus)
**Chargement ~50× plus rapide.** Le nombre de requêtes au serveur EasyVista passe
de ~100 par chargement à **1 seule requête** pour l'affichage principal.
### Classification des absences (depuis v2026.5.27)
- **Maladie/Accident** : indigo `#4338ca`
- **Congé / Congés** : cyan `#06b6d4` (suffixe `s` adaptatif)
- **Pompier** : rouge `#b03030`
- Badge + barre gauche colorée + dégradé fond
- Absence récurrente Pillonel vendredi : cyan (depuis v2026.5.30)
Concrètement, en v3 un chargement initial faisait :
- 1 fetch XML planning (`calendar_block`)
- ~40 fetches `planning_xhr_2.php` pour les lieux/contacts
- ~40 fetches de fiches HTML pour les catégories/refs/statuts
- jusqu'à ~40 fetches de l'API timeline
### User et session
- Badge user avec photo/initiales en topbar
- Badge cliquable (depuis v2026.5.26) : popup avec ⚙ Paramètres + ⊞ Vue + compteur session MM:SS
- Retry automatique en cas d'échec fetch user (60s, max 10 essais)
- Compteur de session EasyVista (tick 1s, depuis v5.0.0)
- Reconnexion automatique
Total : ~120 requêtes, 10+ Mo, 8 à 15 secondes selon la charge serveur.
### Admin et configuration
- Mode admin : bouton ⚙ Paramètres dans popup user-badge (depuis v2026.5.25)
- Configuration persistée dans `chrome.storage.local` (`admin_config`)
- Sélecteur de groupe EasyVista (SI-CSS, SI-EXT, …) en tête de l'onglet Équipe (depuis v2026.5.40) — détection automatique via le `<select id="plan_group_id">` de la page Planning EV, robuste aux ajouts/renommages côté EV
- Édition manuelle des domaines EasyVista interne / externe (depuis v2026.5.40)
- Tri des techniciens : actifs d'abord, puis exclus, alphabétique dans chaque groupe (depuis v2026.5.40)
En v4, on a découvert que le XML initial `calendar_block` contient **déjà**
dans ses attributs `attr1`/`attr2`/`attr3` le contact, le lieu et la catégorie
complète de chaque intervention, et la ref dans le textContent du nœud.
Toutes ces infos qu'on allait chercher ailleurs étaient en fait dans la toute
première réponse, ignorées par le code.
## Versionning — historique et conventions
Résultat : le premier rendu complet arrive en **moins d'une seconde**. Les
fiches individuelles ne sont plus fetchées qu'en arrière-plan, uniquement
pour le statut "Clôturé/Résolu" et le commentaire technicien.
L'extension a connu **3 systèmes de versionning successifs** :
**Lazy-load au survol.** Le texte détaillé d'une intervention (Problème, À faire,
Matériel, TFS ancien/nouveau poste...) n'est chargé qu'au premier survol de la
ligne, seulement pour l'intervention survolée. Imperceptible pour l'utilisateur,
énorme pour le serveur.
| Période | Format | Exemple |
|---|---|---|
| 16-17 avril 2026 | Versions de base | `1.0.0`, `2.0.0`, `3.0.0` |
| 18-20 avril 2026 | SemVer classique | `4.1.3`, `4.2.8`, `5.0.12` |
| 21 avril 2026 → maintenant | **`ANNÉE.MAJEURE.PATCH`** | `2026.5.16``2026.5.40` |
**Concurrence réduite.** Le pic de requêtes parallèles passe de 15 à 5 workers,
pour ménager le serveur EasyVista qui a tendance à saturer sous les rafales.
### Format actuel : `ANNÉE.MAJEURE.PATCH`
Toute l'interface utilisateur est **strictement identique** à la v3 — on n'a
changé que ce qu'il y a sous le capot.
À partir de la **v2026.5.16** (21 avril 2026), l'extension utilise le schéma suivant :
## Hérité des versions précédentes
| Position | Sens | Quand ça change |
|---|---|---|
| `2026` | **Année** | À chaque nouvelle année calendaire |
| `5` | **Majeure** | À chaque **gros changement / ajout important** (refonte, nouvelle feature majeure, bump volontaire) |
| `40` | **Patch** | À **chaque livraison** dans la majeure courante (corrections, ajustements, petites features) |
Exemples :
- `2026.5.16``2026.5.17` : petite correction ou ajustement (patch)
- `2026.5.40``2026.6.0` : refonte majeure (par exemple nouvelle vue, nouvelle architecture)
- `2026.x.y``2027.0.0` : passage à la nouvelle année
Le numéro de **majeure** n'est **pas** un mois et **pas** un chiffre lié au calendrier — c'est un compteur de versions importantes propre au projet (la `5` actuelle continue le `5.x` qui précédait, repris tel quel lors du passage au format annuel).
⚠️ **Important** : `v2026.5.16` succède chronologiquement à `v5.0.12`, malgré le numéro qui semble plus petit. Le préfixe `2026` indique l'année.
## Versions notables
### `v2026.5.41` (latest, 27 avril 2026) — Suppression des hardcodes + UX admin + thème unifié
- **Plus aucun hardcode runtime** pour le groupe EV, les domaines, la liste de techniciens ou les absences récurrentes. Tout est piloté par `admin_config` (chrome.storage.local), persisté entre les mises à jour.
- **Au 1er install** : aucun tech sélectionné, aucune absence récurrente. Le viewer affiche un message *"Aucun technicien sélectionné"* tant que l'utilisateur n'a rien configuré dans Paramètres → Équipe.
- **Édition des domaines** : `chrome.permissions.request()` au save quand l'utilisateur saisit un domaine custom (au-delà des 2 défauts). Manifest `optional_host_permissions: ["https://*/*"]` pour accepter n'importe quel domaine HTTPS après accord du navigateur.
- **Heures de la journée** : bouton ✓ Appliquer explicite (au lieu de save direct), toast de confirmation, refetch automatique du planning. Synchronisation effective avec les requêtes EV (`day_start_hour` / `day_end_hour` / `begin_hour` / `end_hour`) — avant, l'affichage changeait mais les requêtes restaient sur 8h-19h hardcodés.
- **Thème unifié** : le toggle 🌙 de la topbar et le sélecteur Apparence du panel admin écrivent dans la même clé (`cfg.theme`). Le mode "Automatique" est résolu en JS via `prefers-color-scheme` (le CSS n'avait pas de bloc `@media`, ce qui faisait retomber sur le clair même quand l'OS était en sombre). Listener `matchMedia` pour bascule live en mode auto.
- **Conflit absence/réservation × intervention** : si une intervention est planifiée pendant qu'un tech a une absence (toute la journée ou demi-journée) ou une réservation au même créneau, sa carte est peinte en **rouge plein** (intervention conflictuelle). Logique : full-day → toutes en rouge ; partiel → seules celles en chevauchement.
- **Pillonel & Cie** : suppression de la fonction hardcodée `isPillonelAbsentFriday()`. L'absence récurrente est désormais générique : `RECURRING_ABSENCES[tech.id]` lit `cfg.recurringAbsences` et le label "Absent le X" est calculé dynamiquement depuis le jour de la semaine.
- **Notifications au-dessus du flou** : z-index `.toast-stack` relevé à 11000 (le panel admin est à 10000) pour que les toasts de feedback restent visibles quand l'admin est ouvert.
- **Vue horizontale** : popups au survol/clic limités aux candidats `dessous`/`dessus` (la sidebar à gauche et la timeline pleine largeur rendent gauche/droite peu praticables).
- **Tri équipe** : inclus d'abord, puis exclus, alphabétique dans chaque sous-groupe (ne saute plus quand on coche/décoche).
- **Auto-refresh à l'enregistrement** : ajouter/retirer un tech, changer de groupe, modifier les domaines → le planning se met à jour immédiatement (plus besoin de recharger l'extension manuellement).
- **Onglet Statuts retiré** (placeholder lecture-seule, jamais utilisé).
- **Ménage de code** : suppression de `CACHE_DAYS` (inutilisée), `LS_THEME` (clé localStorage obsolète), commentaire historique sur `initAdminMenu()`. Aucun symbole orphelin restant.
### `v2026.5.40` — Sélection groupe EV + édition domaines + tri équipe + vue horizontale enrichie
- **Onglet Équipe** : sélecteur de groupe EasyVista (SI-CSS, SI-EXT, …) en tête de section, détecté automatiquement à l'ouverture du panel via le `<select id="plan_group_id">` de la page Planning EV. Robuste aux ajouts/renommages côté EV.
- **Onglet Équipe** : sélecteur de groupe EasyVista (SI-CSS, SI-EXT, …) en tête de section, détecté automatiquement à l'ouverture du panel via le `<select id="plan_group_id">` de la page Planning EV. Robuste aux ajouts/renommages côté EV.
- ID groupe affiché en italique (ex: `ID groupe : 191`).
- Quand on change de groupe, la liste d'équipe se rafraîchit automatiquement avec les membres du nouveau groupe.
- Plus de bouton "Détecter" : tout est auto à l'ouverture.
- Tri double des techniciens : inclus d'abord, puis exclus, alphabétique dans chaque sous-groupe.
- **Onglet EasyVista** : édition manuelle des deux domaines (interne DGNSI / externe Internet), bouton Réinitialiser, normalisation auto des URLs.
- **Onglet Statuts retiré** (placeholder lecture-seule).
- **Vue horizontale enrichie** : chaque segment timeline contient désormais une barre verticale couleur catégorie à gauche, la référence (ex: `SYYMMDD_NNNNN`) en gras, et la ville en gris muted. Hauteur passée de 22px à 32px.
- **Réorganisation interne du repo** : `src/` pour les sources, `dist/` généré, `Autres/` pour build.sh + meta files (LICENSE, README, CHANGELOG), `Builds/` pour les artefacts distribués.
### `v2026.5.39` — Séparation Matin / Après-midi + Apparence
- Pills "MATIN" / "APRÈS-MIDI" entre les interventions de chaque tech
- Section **Apparence** dans les paramètres : thème, taille du texte, durée du cache, heures de la journée
- Section **À propos** (version, auteur, licence)
### `v2026.5.38` — Attribution auteur + nettoyage + observabilité
- Module `LOG` unifié + handlers globaux d'erreur
- Toggle "Logs verbeux (debug)" dans le panel admin
- En-têtes copyright dans tous les fichiers source
### `v2026.5.37` — Refonte vue horizontale (sidebar complète)
- Topbar entièrement déplacée en sidebar verticale
### `v2026.5.36` — Sidebar verticale en vue horizontale
- Wrapper flex-row `#horizontal-wrapper` [sidebar 200px] + [main]
### `v2026.5.32` — Vue horizontale togglable
- Bouton ⊞ "Vue" dans popup user-badge
### `v2026.5.27` — Classification absences
- Maladie indigo, Congé cyan, Pompier rouge
### `v4.2.3` — Grande popup timeline persistante
- Clic segment timeline = popup persistante
### `v4.1.3` — Tooltips épinglables
- Introduction de `pinTooltip`
### `v1.0.0` (16 avril 2026) — Initiale
- Premier viewer EasyVista pour le canton
Voir [CHANGELOG.md](CHANGELOG.md) pour l'historique complet (40+ versions taggées).
## Architecture technique
```
Planning/
├── src/ # Sources de l'extension (chargées par le navigateur)
│ ├── manifest.json # Manifest V3 (Chrome) + gecko_settings (Firefox)
│ ├── background.js # Service worker : fetch planning XML, gestion session, fetch fiches
│ ├── viewer.html # Interface principale
│ ├── viewer.js # Logique (~9 500 lignes)
│ ├── viewer.css # Styles + thèmes clair/sombre
│ └── icons/ # icon16, icon48, icon128
├── Autres/ # Méta : build script + docs (depuis v2026.5.40)
│ ├── build.sh # Génère dist/chromium/, dist/firefox/, .zip, .xpi
│ ├── CHANGELOG.md
│ ├── LICENSE
│ └── README.md
├── Builds/ # Artefacts distribués aux techniciens
│ ├── Chromium/
│ ├── Firefox/
│ ├── planification-vYYYY.M.PATCH-chromium.zip
│ └── planification-vYYYY.M.PATCH-firefox.xpi
└── dist/ # Sortie de build (gitignoré)
```
### `viewer.js` — fonctions clés
| Fonction | Introduite | Rôle |
|---|---|---|
| `loadForDate` | v1.0.0 | Fetch + parse planning pour une date donnée |
| `buildTooltipHTML` | v1.0.0 | Construction HTML du tooltip d'intervention |
| `pinTooltip` | v4.1.3 | Épingler un tooltip (le rendre permanent) |
| `bindTimelinePopover` | v4.2.3 | Lier popover timeline aux segments |
| `showTimelinePopover` | v4.2.3 | Afficher popover persistante |
| `openPersistentTimelinePopup` | v4.2.3 | Grande popup détaillée |
| `setTooltipViewportPosition` | v4.2.4 | Détection auto fixed/abs |
| `_softUnpinPopup` | v4.3.3 | Désépinglage mou (popup reste visible) |
| `initAppClock` | v5.0.0 | Horloge HH:MM topbar |
| `initSessionTimer` | v5.0.0 | Compteur session EV (tick 1s) |
| `_applyViewMode` | v2026.5.32 | Toggle vue classique/horizontale |
| `_maybeRetryFetchUser` | v2026.5.34 | Relance opportuniste fetch user |
| `positionTooltipAnchored` | v2026.5.34 | Positionnement unifié (4 candidats) |
| `renderAdminSectionTeam` | v5.0.0 | Onglet admin Équipe (sélecteur groupe EV depuis v2026.5.40) |
| `renderAdminSectionEV` | v5.0.0 | Onglet admin EasyVista (édition domaines depuis v2026.5.40) |
### `background.js` — fonctions clés
| Fonction | Rôle |
|---|---|
| `findEasyVistaSession` | Trouve l'onglet EV ouvert + extrait PHPSESSID |
| `fetchPlanningXml` | Fetch XML calendar_block du planning |
| `fetchFicheHtml` | Fetch HTML d'une fiche EV (avec retry SSO) |
| `fetchCurrentUser` | Identifie l'user EV connecté |
| `detectGroupsFromEV` (v2026.5.40) | Parse le `<select id="plan_group_id">` → liste des groupes EV |
| `detectTeamFromEV` | Liste les membres d'un groupe (paramétrable depuis v2026.5.40) |
| `evFetch` | Wrapper fetch avec headers EV (Referer, X-Requested-With) |
### Constantes / valeurs hardcodées (toutes versions)
- Group ID EV par défaut : `191` (SI-CSS) — surchargeable via le sélecteur depuis v2026.5.40
- Pillonel Olivier (ID 40944) : absent tous les vendredis (récurrent)
- GUIDs forms EV :
- Demande : `S={C99ECD05-3D48-4C62-ABF0-66292053AED6}`
- Incident : `I={07ED9C68-6172-48EA-8A58-90912B0A283E}`
- SSO : Canton ForgeRock OpenAM
- Storage keys : `admin_config`, `view_mode`
- Domaines : `itsma.etat-de-vaud.ch` (interne), `itsma.vd.ch` (externe)
- Navigation par date : ◀ ▶ et sélecteur
- Détection automatique des interventions closes (✓ vert, fond vert)
- Cache persistant 7 jours
- Ghosts : les interventions disparues d'EasyVista restent visibles dans la vue
- Refresh auto 12h et 15h
- Annulation coopérative (bouton "Arrêter")
- Thème clair/sombre
## Installation
### Firefox
Télécharger le `.xpi` depuis `Builds/` ou le serveur de mises à jour interne, puis drag-and-drop dans `about:addons`.
1. Décompresser le zip
2. Ouvrir Chrome, `chrome://extensions/`
3. Activer **Mode développeur** (en haut à droite)
4. **Charger l'extension non empaquetée** → sélectionner le dossier `planning-extension-v4`
### Chrome / Edge
Mode développeur : décompresser `Builds/planification-vYYYY.M.PATCH-chromium.zip` (ou utiliser directement `dist/chromium/`) et charger en tant qu'extension non empaquetée.
Si tu avais déjà la v3 installée, tu peux la supprimer avant — les caches des
deux versions sont compatibles (même format).
## Développement
## Utilisation
```bash
git clone https://gitea.netaplaid.ch/FroSteel/Planification.git
cd Planification
1. Se connecter à EasyVista dans un onglet (`itsma.etat-de-vaud.ch` ou `itsma.vd.ch`)
2. Cliquer sur l'icône de l'extension (depuis n'importe quel onglet)
3. La vue claire s'ouvre dans un nouvel onglet
# Modifier les sources dans src/
# Bumper la version dans src/manifest.json + ajouter une entrée dans Autres/CHANGELOG.md
# Builder :
./Autres/build.sh
# → produit dist/chromium/, dist/firefox/, dist/*.zip, dist/*.xpi
## Comment ça marche techniquement
# Copier dans Builds/ pour distribution :
cp -r dist/chromium Builds/Chromium
cp -r dist/firefox Builds/Firefox
cp dist/*.zip dist/*.xpi Builds/
- `background.js` fait les fetches en arrière-plan (via le cookie de session EasyVista).
- L'extension détecte automatiquement le `PHPSESSID` depuis un onglet EasyVista ouvert.
- **v4 : le XML `planning_xhr.php?div=calendar_block` suffit à afficher tout
l'essentiel.** Les champs `attr1`/`attr2`/`attr3` contiennent contact, lieu
et catégorie. Le `textContent` du nœud contient la ref (S260.../I260...).
- Les fiches individuelles (`index.php?formEvent=...`) ne sont fetchées que pour
obtenir le statut Clôturé/Résolu et le commentaire technicien.
- Le texte d'action détaillé (Problème/À faire/Matériel/...) est récupéré en
lazy-load via `planning_xhr_2.php?id=ACTIONID` au premier survol.
- Le cache est stocké dans `chrome.storage.local` (local à ta machine).
- Aucune donnée n'est envoyée ailleurs que vers `itsma.etat-de-vaud.ch` et `itsma.vd.ch`.
git add -A
git commit -m "vYYYY.M.PATCH — description"
git tag vYYYY.M.PATCH
git push origin main
git push --tags
```
## Limitations connues
## Licence
[MIT License](LICENSE) — Copyright (c) 2026 Quentin Rouiller
## Auteur
**Quentin Rouiller** (QRO)
Technicien DGNSI — Canton de Vaud
Contact : `quentin.rouiller@vd.ch`
- Nécessite un onglet EasyVista ouvert (même en arrière-plan) pour fonctionner
- Fonctionne uniquement sur l'intranet cantonal (les fetches échoueront en externe)
- Les 8 IDs des techs sont en dur dans le code (si quelqu'un quitte/arrive dans
l'équipe, il faut mettre à jour `viewer.js` ligne ~22)
- Le statut "Clôturé/Résolu" met quelques secondes à apparaître après le
chargement initial (fetch des fiches en arrière-plan, concurrence 5)
File diff suppressed because it is too large Load Diff
-49
View File
@@ -1,49 +0,0 @@
#!/usr/bin/env bash
###############################################################################
# build.sh — génère dist/chromium/, dist/firefox/, et les archives .zip / .xpi
# à partir du code source dans src/.
#
# Usage : ./build.sh
###############################################################################
set -e
cd "$(dirname "$0")"
VERSION=$(python3 -c "import json; print(json.load(open('src/manifest.json'))['version'])")
echo "==> Build Planification v$VERSION"
rm -rf dist
mkdir -p dist/chromium dist/firefox
# ---- Chromium : copie src/ tel quel (manifest sans gecko_settings) ----
cp -r src/* dist/chromium/
echo " ✓ dist/chromium/ ($(du -sh dist/chromium | cut -f1))"
# ---- Firefox : copie src/ + manifest avec browser_specific_settings ----
cp -r src/* dist/firefox/
python3 - <<EOF
import json
with open('src/manifest.json', 'r') as f: m = json.load(f)
m['browser_specific_settings'] = {
'gecko': {
'id': 'planification@netaplaid.ch',
'strict_min_version': '140.0',
'update_url': 'https://gitea.netaplaid.ch/FroSteel/Planification/raw/branch/main/firefox-updates.json',
'data_collection_permissions': {'required': ['none']}
}
}
with open('dist/firefox/manifest.json', 'w') as f:
json.dump(m, f, indent=2, ensure_ascii=False)
f.write('\n')
EOF
echo " ✓ dist/firefox/ ($(du -sh dist/firefox | cut -f1))"
# ---- Archives ZIP / XPI prêtes à distribuer ----
cd dist/chromium && zip -rq "../planification-v${VERSION}-chromium.zip" . && cd ../..
cd dist/firefox && zip -rq "../planification-v${VERSION}-firefox.xpi" . && cd ../..
echo ""
echo "==> Builds prêts dans dist/"
ls -la dist/*.zip dist/*.xpi 2>/dev/null
echo ""
echo "Pour Chrome : charger dist/chromium/ en mode développeur"
echo "Pour Firefox : signer dist/planification-v${VERSION}-firefox.xpi sur AMO"

Before

Width:  |  Height:  |  Size: 444 B

After

Width:  |  Height:  |  Size: 444 B

Before

Width:  |  Height:  |  Size: 118 B

After

Width:  |  Height:  |  Size: 118 B

Before

Width:  |  Height:  |  Size: 207 B

After

Width:  |  Height:  |  Size: 207 B

+4 -17
View File
@@ -1,22 +1,13 @@
{
"manifest_version": 3,
"name": "Planification",
"version": "2026.5.41",
"description": "Vue claire et rapide du planning des techniciens EasyVista. Développé par Quentin Rouiller — DGNSI, Canton de Vaud.",
"permissions": [
"activeTab",
"scripting",
"storage",
"tabs",
"alarms"
],
"version": "5.0.4",
"description": "Vue claire et rapide du planning des techniciens EasyVista. Regroupe interventions et réservations par tech, affiche horaires, contact, lieu, catégorie et statut en un coup d'œil.",
"permissions": ["activeTab", "scripting", "storage", "tabs", "alarms"],
"host_permissions": [
"https://itsma.etat-de-vaud.ch/*",
"https://itsma.vd.ch/*"
],
"optional_host_permissions": [
"https://*/*"
],
"action": {
"default_title": "Ouvrir la Planification"
},
@@ -30,11 +21,7 @@
},
"web_accessible_resources": [
{
"resources": [
"viewer.html",
"viewer.js",
"viewer.css"
],
"resources": ["viewer.html", "viewer.js", "viewer.css"],
"matches": [
"https://itsma.etat-de-vaud.ch/*",
"https://itsma.vd.ch/*"
-4855
View File
File diff suppressed because it is too large Load Diff
+2219
View File
File diff suppressed because it is too large Load Diff
+6 -32
View File
@@ -1,13 +1,4 @@
<!doctype html>
<!--
Planification — Extension navigateur EasyVista (Canton de Vaud / DGNSI)
Copyright (c) 2026 Quentin Rouiller
Licensed under the MIT License — see LICENSE file in the project root.
@author Quentin Rouiller
@repository https://gitea.netaplaid.ch/FroSteel/Planification
-->
<html lang="fr">
<head>
<meta charset="utf-8">
@@ -18,39 +9,22 @@
<header class="topbar">
<div class="topbar-left">
<!-- v4.2.3 : pastille avec initiales de l'utilisateur connecté, avant
le titre. Clic → popup fixe avec nom complet juste en dessous.
v2026.5.34 : TOUJOURS visible d'office avec "?" (état user inconnu)
pour garantir l'accès au menu (⊞ Vue / ⚙ Paramètres) même si
la détection user échoue ou est en retard.
Le script JS mettra à jour le textContent + classes quand le
fetch aboutit. En cas d'échec persistant, reste sur "?". -->
<button id="user-badge" class="user-badge user-badge-unknown"
le titre. Clic → popup fixe avec nom complet juste en dessous. -->
<button id="user-badge" class="user-badge hidden"
type="button" aria-label="Utilisateur connecté"
title="Utilisateur — cliquer pour accéder aux paramètres">?</button>
title="Utilisateur connecté"></button>
<h1 id="app-title">Planification</h1>
<div class="date-nav">
<button id="nav-prev" class="btn btn-nav" title="Jour précédent" aria-label="Jour précédent"></button>
<!-- v2026.5.17 : input date custom qui affiche "Vendredi 24.04.2026" -->
<div class="date-custom-wrapper">
<div id="date-custom" class="date-custom" role="button" tabindex="0" title="Choisir une date">
<span id="date-custom-label"></span>
<span class="date-custom-icon">📅</span>
</div>
<input type="date" id="date-picker" class="date-input-hidden">
</div>
<input type="date" id="date-picker" class="date-input">
<button id="nav-next" class="btn btn-nav" title="Jour suivant" aria-label="Jour suivant"></button>
<button id="nav-today" class="btn btn-today" title="Aujourd'hui">Auj.</button>
</div>
<span id="capture-info" class="capture-info"></span>
<span id="refresh-check" class="refresh-check hidden" title="Mise à jour terminée"></span>
</div>
<!-- v2026.5.16 : date complète du jour au-dessus de l'heure dans la topbar -->
<div id="app-clock" class="app-clock" title="Date et heure actuelles">
<div id="app-clock-date" class="app-clock-date"></div>
<div id="app-clock-time" class="app-clock-time"></div>
</div>
<!-- v5.0.9 : compteur de session EasyVista (visible < 5 min restantes) -->
<div id="app-session" class="app-session hidden"></div>
<!-- v5.0.0 : horloge au milieu, format HH:MM, mise à jour toutes les min -->
<div id="app-clock" class="app-clock" title="Heure actuelle"></div>
<div class="topbar-right">
<!-- v4.2.6 : bouton créer une absence pour un ou plusieurs techs -->
<button id="absence-btn" class="btn btn-action" title="Créer une absence pour un ou plusieurs techniciens">
+471 -4542
View File
File diff suppressed because it is too large Load Diff