Public Access
Compare commits
7
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a37b90aa13 | ||
|
|
a1c7f45b03 | ||
|
|
cd106484d5 | ||
|
|
e846e90bb8 | ||
|
|
519fca42ce | ||
|
|
5f72228f13 | ||
|
|
cb3b7cb643 |
+118
-5
@@ -1,7 +1,7 @@
|
|||||||
# CHANGELOG — Extension Planification EasyVista Canton de Vaud
|
# CHANGELOG — Extension Planification EasyVista Canton de Vaud
|
||||||
|
|
||||||
> Ce changelog documente l'évolution de l'extension Chrome/Firefox "Planification"
|
> Ce changelog documente l'évolution de l'extension Chrome/Firefox "Planification"
|
||||||
> développée par FroSteel pour les coordinateurs DGNSI (Canton de Vaud).
|
> développée par Quentin pour les coordinateurs DGNSI (Canton de Vaud).
|
||||||
>
|
>
|
||||||
> Les versions documentées ci-dessous sont celles dont les détails sont connus.
|
> Les versions documentées ci-dessous sont celles dont les détails sont connus.
|
||||||
> Pour les versions plus anciennes, l'analyse du code source permet de
|
> Pour les versions plus anciennes, l'analyse du code source permet de
|
||||||
@@ -9,6 +9,119 @@
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## v2026.5.50 — Texte des actions rétabli (format EasyVista du 29.09.2026), catégories Roll Out et Déménagement
|
||||||
|
|
||||||
|
> Correctif urgent : depuis le 29 septembre 2026, le texte complet des actions ne s'affichait plus. EasyVista renvoie désormais les actions avec une cellule de moins, et l'extension les lisait par position. Elle les retrouve maintenant par leur contenu. Cette version ajoute aussi deux catégories de réservation.
|
||||||
|
|
||||||
|
### Texte des actions
|
||||||
|
|
||||||
|
- **Texte complet des actions rétabli** dans les bulles et les fiches, avec l'ancien comme avec le nouveau format d'EasyVista.
|
||||||
|
- **Plus robuste aux prochains changements** : la description est repérée par le nom de sa colonne, et l'identifiant de l'action par son contenu, plus par leur position.
|
||||||
|
- **Changement de format signalé** : si EasyVista modifie encore la structure au point qu'aucune action ne soit lisible, un avertissement apparaît dans la console (une seule fois, sans aucune donnée personnelle). Les fiches ou historiques qui ne se chargent pas sont aussi signalés dans la console.
|
||||||
|
|
||||||
|
### Réservations
|
||||||
|
|
||||||
|
- **Deux nouvelles catégories : Roll Out et Déménagement.** Elles sont propres à la Planification : dans EasyVista, la réservation reste « Evènements spéciaux ». Elles sont partagées entre tous les postes par le dossier partagé, comme le n°, la ville et la rue.
|
||||||
|
- **Catégorie proposée à la saisie du n°** : le n° d'une intervention Roll Out propose Roll Out.
|
||||||
|
- **Catégorie inconnue conservée** : une catégorie posée par une version plus récente n'est plus effacée quand on modifie la réservation.
|
||||||
|
|
||||||
|
### Déploiement
|
||||||
|
|
||||||
|
- **Mettre à jour tous les postes le même jour.** Un poste resté en 2026.5.49 qui modifie une réservation Roll Out ou Déménagement effacerait cette catégorie sur tous les postes.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## v2026.5.49 — Sécurité hors session, onglet Email clarifié, lecture au défilement, affichage et synchronisation fiabilisés
|
||||||
|
|
||||||
|
> Cette version renforce la **sécurité** quand aucune session EasyVista n'est active, clarifie l'**onglet Email** (déplacement et annulation bien séparés, aperçu de la copie), améliore la **lecture du planning au défilement** (le nom du technicien, son compteur et la frise horaire restent visibles), et corrige en profondeur l'**affichage de la reconnexion** ainsi que plusieurs comportements de la synchronisation et des réservations.
|
||||||
|
|
||||||
|
### Sécurité et confidentialité (sans session EasyVista)
|
||||||
|
|
||||||
|
- **Aucune écriture dans le dossier partagé sans session active** : tant que vous n'êtes pas identifié dans EasyVista, l'extension travaille sur le **cache local seul** et ne touche plus au dossier partagé. Un ancien cache reste consultable, mais il n'est plus alimenté ni relu depuis le partage.
|
||||||
|
- **Aucune modification sans session active** : déplacement d'intervention, suppression, création ou édition d'absence, réservation — tout est bloqué proprement tant que la session n'est pas rétablie, avec un message clair. Cela évite d'écrire des données incohérentes qui seraient ensuite propagées aux autres postes.
|
||||||
|
|
||||||
|
### Onglet Email clarifié
|
||||||
|
|
||||||
|
- **Déplacement et annulation séparés** : l'onglet Email présente désormais deux sections distinctes (déplacement d'une intervention / annulation-suppression), chacune avec sa case d'activation et son propre modèle de message.
|
||||||
|
- **Copie (CC) commune avec aperçu en direct** : un bloc « Copie (CC) » en tête montre, sous forme de puces, les adresses effectivement retenues (les adresses invalides sont barrées) — vous voyez immédiatement à qui la copie sera envoyée.
|
||||||
|
- **Variables cliquables en colonnes** pour les deux modèles (déplacement et annulation), rangées par thème pour une insertion rapide.
|
||||||
|
|
||||||
|
### Lecture du planning au défilement (vue classique)
|
||||||
|
|
||||||
|
- **En-tête de carte collant** : quand vous faites défiler une carte, le **nom du technicien**, son **nombre d'interventions** et la **frise horaire** restent visibles en haut — plus besoin de remonter pour savoir de qui il s'agit.
|
||||||
|
- **Survol d'une pause** : passer la souris sur une pause met la **frise horaire en évidence** (sans faner les interventions), pour bien distinguer le créneau libre.
|
||||||
|
|
||||||
|
### Affichage et reconnexion fiabilisés
|
||||||
|
|
||||||
|
- La bannière **« Session EasyVista expirée »** s'affiche au bon endroit (dans le corps, sous la barre de recherche) et **uniquement quand de vraies cartes sont affichées** ; sinon un message centré prend la place du planning. Plus de fausse bannière au-dessus d'un écran vide.
|
||||||
|
- **Plus de bulles de techniciens vides** : lors d'un rafraîchissement automatique alors que la session est morte, l'extension détecte la page de connexion EasyVista et évite d'afficher une équipe vide.
|
||||||
|
- La **barre de progression** ne recouvre plus le nom du technicien pendant un rafraîchissement lorsqu'on a fait défiler.
|
||||||
|
|
||||||
|
### Corrections
|
||||||
|
|
||||||
|
- **Noms de contact nettoyés** : les caractères parasites (« ? » et caractères de remplacement) parfois collés aux noms venant d'EasyVista sont retirés.
|
||||||
|
- **Deux interventions du même technicien le même jour** (deux actions distinctes) s'affichent désormais chacune sur sa propre carte, sans en perdre.
|
||||||
|
- **Caractères parasités depuis EasyVista** (dans les libellés d'intervention, contacts, lieux) corrigés à la source.
|
||||||
|
- **Indicateur d'écart d'adresse** remis à jour après correction : actualiser une intervention dont l'adresse a été corrigée retire bien l'alerte.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## v2026.5.48 — Notification par email des déplacements, onglet Email, fiches réservation fiables entre postes, recherche et reconnexion durcies
|
||||||
|
|
||||||
|
> Cette version apporte une vraie nouveauté : après le déplacement d'une intervention (autre jour ou autre technicien), l'extension peut ouvrir un **brouillon d'email pré-rempli** dans votre application mail pour prévenir les techniciens concernés — l'envoi reste un geste manuel. Elle corrige aussi en profondeur la circulation des informations de réservation entre postes, le bouton de reconnexion quand il n'y a aucun cache, et plusieurs comportements de la recherche.
|
||||||
|
|
||||||
|
### Email après un déplacement (nouveau)
|
||||||
|
|
||||||
|
- **Brouillon automatique** : après un déplacement vers un **autre jour** ou un **autre technicien** (fenêtre de modification ou glisser-déposer), un brouillon pré-adressé aux deux techniciens s'ouvre dans l'application mail (ex. Outlook). Un simple ajustement d'heures n'ouvre rien. **Rien n'est envoyé automatiquement.**
|
||||||
|
- **Case « Prévenir les techniciens par email »** dans les fenêtres de déplacement : quand l'option est active, la décocher ne vaut que pour **ce déplacement-là** — le prochain déplacement la retrouve cochée. L'option ne se désactive durablement que dans les Paramètres.
|
||||||
|
- **Destinataires** séparés par « ; » (compatibilité Outlook) ; si une adresse manque, le brouillon s'ouvre quand même, à compléter directement dans l'email (une notification indique qui manque).
|
||||||
|
- **Nouvel onglet « Email »** dans les Paramètres : option, et **modèle du message** entièrement personnalisable (sujet + texte), avec **variables cliquables** rangées par thème (Intervention / Avant / Après) et **aperçu en direct** sur un exemple. Le modèle de base présente le déplacement en deux blocs AVANT / APRÈS bien lisibles.
|
||||||
|
- **Adresses des techniciens** dans l'onglet Équipe (colonne Email, boutons au-dessus de la liste) : bouton « **Récupérer les emails** » qui remplit les adresses manquantes depuis l'annuaire EasyVista — et **complète au passage un nom affiché tronqué** (ex. « Martins » → « De Almeida Martins »), avec un garde-fou contre les homonymes. Une adresse saisie à la main n'est jamais écrasée. Champ vide = adresse proposée `prenom.nom@domaine` (domaine réglable au même endroit, appliqué à tous).
|
||||||
|
|
||||||
|
### Informations de réservation fiables entre postes
|
||||||
|
|
||||||
|
- Les informations saisies sur une réservation (n° d'intervention, ville, rue, catégorie) **voyagent désormais avec la réservation** dans le dossier partagé, horodatées : la modification la plus récente gagne, sur tous les postes.
|
||||||
|
- Fin des « fuites » d'informations : une réservation posée par un autre coordinateur ne récupère plus les infos d'une réservation précédente au même créneau, un identifiant recyclé par EasyVista ne fait plus hériter les infos d'un autre technicien, et un champ volontairement vidé ne « ressuscite » plus.
|
||||||
|
- Une réservation **re-planifiée directement dans EasyVista** conserve ses informations quand le rapprochement est sans ambiguïté.
|
||||||
|
- Divers : le pompier du jour n'est plus compté en double dans les statistiques ; « réservé toute la journée » se calcule sur les heures affichées ; les champs pré-remplis du formulaire ne sont plus écrasés par le remplissage automatique.
|
||||||
|
|
||||||
|
### Reconnexion et recherche
|
||||||
|
|
||||||
|
- **Bouton « Ouvrir EasyVista »** (écran « Session expirée » sans aucun cache) : après la reconnexion, l'écran se ferme réellement et le planning s'affiche ; re-cliquer relance le chargement au lieu d'être ignoré.
|
||||||
|
- **Recherche** : la recherche part de façon fiable quand on arrête de taper (les relances au survol ne l'interrompent plus), **Entrée** lance la recherche immédiatement, la roue de chargement est visible dès le début, déplier « Planifiée (passé) » ne ferme plus la zone de résultats, et seuls les statuts **Clôturé / Fait** sont affichés sur les résultats.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## v2026.5.47 — Vue « échelle de temps exacte » : aide à la saisie, erreurs mises en évidence, corrections de fiabilité
|
||||||
|
|
||||||
|
> Cette version peaufine la vue horizontale « échelle de temps exacte » : un vrai retour visuel accompagne la pose d'un rendez-vous ou d'une absence, et les erreurs de saisie (rendez-vous dont le début est égal à la fin) sont désormais bien visibles et signalées. Elle corrige aussi plusieurs problèmes de navigation entre dates et de synchronisation du dossier partagé, réorganise le panneau de synchronisation, et ajoute un bouton de test de la communication avec le script du poste.
|
||||||
|
|
||||||
|
### Vue « échelle de temps exacte » — aide à la saisie
|
||||||
|
|
||||||
|
- **Retour visuel au survol d'un créneau libre** : une zone surlignée suit la souris et affiche **l'heure exacte** (début → fin) du rendez-vous ou de l'absence qu'un clic droit poserait. Une bulle fixe, en haut de la ligne, rappelle la **plage libre et la durée disponible** du créneau (« Libre 12:00–18:00 / 6 h disponible »). Elle se place toujours sur un espace libre — jamais par-dessus un rendez-vous — et ne masque pas l'heure choisie.
|
||||||
|
- **Erreurs de saisie mises en évidence** : un rendez-vous dont le **début est égal à la fin** (ex. 10:00 → 10:00) est désormais affiché en **rouge** et reste **visible** (avant, il disparaissait sur l'échelle exacte). Survoler une telle zone pour en poser un autre affiche un **avertissement** et **empêche** la création tant que l'erreur n'est pas corrigée.
|
||||||
|
- **Interventions courtes visibles** : une intervention de 1 à 5 minutes garde une largeur minimale et reste visible.
|
||||||
|
- **Zone du nom** : le fond du nom du technicien remplit toute la hauteur de la ligne (nom centré).
|
||||||
|
- **Barre des heures** : reste collée en haut au défilement et passe sous la banderole de reconnexion (au lieu de disparaître derrière).
|
||||||
|
|
||||||
|
### Corrections de fiabilité
|
||||||
|
|
||||||
|
- **Navigation rapide entre dates** : le jour que l'on quitte ne peut plus écraser le jour qui vient de s'afficher.
|
||||||
|
- **Technicien retiré de l'équipe** : n'apparaît plus sur les jours relus depuis le dossier partagé.
|
||||||
|
- **Synchronisation du dossier partagé** : correction d'un blocage où l'écriture n'aboutissait jamais (conflit permanent entre l'index et le fichier relu) ; l'index se répare de lui-même.
|
||||||
|
- **Jour présent au dossier mais pas en local** : lu depuis le dossier d'emblée — plus de re-remplissage visible inutile.
|
||||||
|
- **Absences** : plus de doublon « absence récurrente » + « vraie absence » le même jour ; le fond des cartes d'absence remplit toute la carte en échelle exacte.
|
||||||
|
- **Réservations multiples le même jour** : les deux créneaux coexistent ; saisir le n° d'intervention dans le formulaire remplit automatiquement ville, rue et catégorie.
|
||||||
|
- **Barre de progression** et **message de reconnexion** : bien positionnés en vue horizontale (barre en haut de la sidebar, message centré dans le contenu).
|
||||||
|
|
||||||
|
### Synchronisation multi-postes
|
||||||
|
|
||||||
|
- **Nouveau bouton « Tester la communication »** (onglet Synchro) : diagnostic de bout en bout extension → script du poste → dossier partagé.
|
||||||
|
- **Panneau Synchro réorganisé** en sections claires : état de la synchro, dossier partagé, script sur le poste, journal d'activité.
|
||||||
|
- **Script du poste (native messaging host) 2026.1.8** : verrou dédié sur l'index du dossier partagé (protège l'écriture simultanée par plusieurs postes ou onglets) et icône de la zone de notification ré-affichée au redémarrage de l'explorateur Windows. Le bouton « Télécharger le script » récupère cette version.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## v2026.5.46 — Refonte de la couche données, vue « échelle de temps exacte », session fiabilisée, réservations enrichies
|
## v2026.5.46 — Refonte de la couche données, vue « échelle de temps exacte », session fiabilisée, réservations enrichies
|
||||||
|
|
||||||
> Version majeure par son contenu : la couche données est entièrement refondue (store unifié par jour, un seul verdict par intervention, synchronisation du dossier partagé en sous-dossier `v2`), une nouvelle disposition « échelle de temps exacte » s'ajoute à la vue horizontale, la détection de session EasyVista est fiabilisée de bout en bout, et les réservations portent enfin leurs informations (n°, lieu, catégorie) sur tous les postes. Le script PowerShell du dossier partagé est désormais publié avec l'extension et téléchargeable depuis les Paramètres.
|
> Version majeure par son contenu : la couche données est entièrement refondue (store unifié par jour, un seul verdict par intervention, synchronisation du dossier partagé en sous-dossier `v2`), une nouvelle disposition « échelle de temps exacte » s'ajoute à la vue horizontale, la détection de session EasyVista est fiabilisée de bout en bout, et les réservations portent enfin leurs informations (n°, lieu, catégorie) sur tous les postes. Le script PowerShell du dossier partagé est désormais publié avec l'extension et téléchargeable depuis les Paramètres.
|
||||||
@@ -31,7 +144,7 @@
|
|||||||
- **Règle des heures fixe** en haut (reste collée au défilement), **lignes verticales continues** sur toute la hauteur du tableau : trait net à chaque heure, pointillé discret aux demi-heures, césure rayée à midi ; les traits passent derrière les bulles et sautent les techniciens absents.
|
- **Règle des heures fixe** en haut (reste collée au défilement), **lignes verticales continues** sur toute la hauteur du tableau : trait net à chaque heure, pointillé discret aux demi-heures, césure rayée à midi ; les traits passent derrière les bulles et sautent les techniciens absents.
|
||||||
- **Ligne rouge « maintenant »** continue sur toute la hauteur (jour courant), reposée instantanément à chaque rendu ; elle saute aussi les absents.
|
- **Ligne rouge « maintenant »** continue sur toute la hauteur (jour courant), reposée instantanément à chaque rendu ; elle saute aussi les absents.
|
||||||
- **Chevauchements** : les éléments qui se recouvrent s'empilent en sous-lignes de même hauteur — la zone du technicien s'agrandit seulement dans ce cas ; tolérance de 10 minutes pour ne pas empiler de simples enchaînements.
|
- **Chevauchements** : les éléments qui se recouvrent s'empilent en sous-lignes de même hauteur — la zone du technicien s'agrandit seulement dans ce cas ; tolérance de 10 minutes pour ne pas empiler de simples enchaînements.
|
||||||
- **Cartes** : fond neutre, le bord gauche porte la couleur de catégorie et sert de **poignée** (cliquer = fenêtre de modification, glisser = déplacer ; présente sur toutes les cartes, déplacement bloqué pour les faites/clôturées, réservations et absences). Numéro d'intervention en tête, ville + adresse groupées ; cartes étroites : texte compact (ville + fin d'adresse, « Rue de l'Exemple 5 » → « Université 5 »), jamais vides tant qu'il reste de la place.
|
- **Cartes** : fond neutre, le bord gauche porte la couleur de catégorie et sert de **poignée** (cliquer = fenêtre de modification, glisser = déplacer ; présente sur toutes les cartes, déplacement bloqué pour les faites/clôturées, réservations et absences). Numéro d'intervention en tête, ville + adresse groupées ; cartes étroites : texte compact (ville + fin d'adresse, « Rue de l'Exemple 5 » → « Exemple 5 »), jamais vides tant qu'il reste de la place.
|
||||||
- **Réservations** : affichent sous l'intitulé le lieu renseigné à la création, sinon le nom de la personne qui a réservé.
|
- **Réservations** : affichent sous l'intitulé le lieu renseigné à la création, sinon le nom de la personne qui a réservé.
|
||||||
- **Zones libres** : survol = « Libre HH:MM–HH:MM » (y compris sur les journées totalement vides), clic droit = Réservation/Absence à l'heure du curseur, dépôt du drag précis (pas de 30 min) avec marqueur vert sur toute la bande.
|
- **Zones libres** : survol = « Libre HH:MM–HH:MM » (y compris sur les journées totalement vides), clic droit = Réservation/Absence à l'heure du curseur, dépôt du drag précis (pas de 30 min) avec marqueur vert sur toute la bande.
|
||||||
- Alignement règle/cartes mesuré au pixel réel (indépendant du zoom et de la taille de texte).
|
- Alignement règle/cartes mesuré au pixel réel (indépendant du zoom et de la taille de texte).
|
||||||
@@ -449,7 +562,7 @@ Une intervention terminée par le tech mais dont la fiche était passée en stat
|
|||||||
### Attribution auteur
|
### Attribution auteur
|
||||||
- Ajout en-têtes copyright dans tous les fichiers source
|
- Ajout en-têtes copyright dans tous les fichiers source
|
||||||
(viewer.js, viewer.html, viewer.css, background.js)
|
(viewer.js, viewer.html, viewer.css, background.js)
|
||||||
- Ajout `@author FroSteel` sur les fonctions principales
|
- Ajout `@author Quentin` sur les fonctions principales
|
||||||
(loadForDate, buildCard, buildTooltipHTML, pinTooltip, _softUnpinPopup,
|
(loadForDate, buildCard, buildTooltipHTML, pinTooltip, _softUnpinPopup,
|
||||||
positionTooltipAnchored, _applyViewMode, _moveElementsToSidebar,
|
positionTooltipAnchored, _applyViewMode, _moveElementsToSidebar,
|
||||||
_restoreElementsToTopbar, fetchAndShowCurrentUser, _maybeRetryFetchUser,
|
_restoreElementsToTopbar, fetchAndShowCurrentUser, _maybeRetryFetchUser,
|
||||||
@@ -457,7 +570,7 @@ Une intervention terminée par le tech mais dont la fiche était passée en stat
|
|||||||
openPersistentTimelinePopup, showTooltip, _findFreePopupPosition,
|
openPersistentTimelinePopup, showTooltip, _findFreePopupPosition,
|
||||||
_clampPopupInSafeArea, findEasyVistaSession, fetchPlanningXml,
|
_clampPopupInSafeArea, findEasyVistaSession, fetchPlanningXml,
|
||||||
fetchCurrentUser, detectNetworkContext)
|
fetchCurrentUser, detectNetworkContext)
|
||||||
- Ajout signature "Développé par FroSteel" en bas du popup
|
- Ajout signature "Développé par Quentin" en bas du popup
|
||||||
user-badge (style cohérent avec footer version : 11px, italique,
|
user-badge (style cohérent avec footer version : 11px, italique,
|
||||||
gris atténué, séparateur fin)
|
gris atténué, séparateur fin)
|
||||||
- Mise à jour `description` du manifest pour mentionner DGNSI
|
- Mise à jour `description` du manifest pour mentionner DGNSI
|
||||||
@@ -649,6 +762,6 @@ Une intervention terminée par le tech mais dont la fiche était passée en stat
|
|||||||
|
|
||||||
## Auteur
|
## Auteur
|
||||||
|
|
||||||
**FroSteel** (FRS)
|
**Quentin** (FRS)
|
||||||
Technicien DGNSI — Canton de Vaud
|
Technicien DGNSI — Canton de Vaud
|
||||||
Contact : voir [page wiki Contact](https://gitea.netaplaid.ch/FroSteel/Planification/wiki/Contact)
|
Contact : voir [page wiki Contact](https://gitea.netaplaid.ch/FroSteel/Planification/wiki/Contact)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2026 FroSteel
|
Copyright (c) 2026 Quentin
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|||||||
@@ -6,10 +6,10 @@ Extension Chrome / Firefox pour visualiser de manière claire et rapide le plann
|
|||||||
|
|
||||||
## Aperçu rapide
|
## Aperçu rapide
|
||||||
|
|
||||||
- **Auteur** : FroSteel (FRS), Technicien DGNSI — Canton de Vaud
|
- **Auteur** : Quentin (FRS), Technicien DGNSI — Canton de Vaud
|
||||||
- **Public cible** : coordinateurs DGNSI qui pilotent dans EasyVista (`itsma.etat-de-vaud.ch` / `itsma.vd.ch`) le planning de l'équipe technicienne
|
- **Public cible** : coordinateurs DGNSI qui pilotent dans EasyVista (`itsma.etat-de-vaud.ch` / `itsma.vd.ch`) le planning de l'équipe technicienne
|
||||||
- **Démarrage projet** : jeudi 16 avril 2026
|
- **Démarrage projet** : jeudi 16 avril 2026
|
||||||
- **Version actuelle** : [`v2026.5.45`](https://gitea.netaplaid.ch/FroSteel/Planification/releases/tag/v2026.5.45) (latest)
|
- **Version actuelle** : [`v2026.5.50`](https://gitea.netaplaid.ch/FroSteel/Planification/releases/tag/v2026.5.50) (latest)
|
||||||
- **Contact** : voir [page wiki Contact](https://gitea.netaplaid.ch/FroSteel/Planification/wiki/Contact) ou [ouvrir une issue](https://gitea.netaplaid.ch/FroSteel/Planification/issues/new)
|
- **Contact** : voir [page wiki Contact](https://gitea.netaplaid.ch/FroSteel/Planification/wiki/Contact) ou [ouvrir une issue](https://gitea.netaplaid.ch/FroSteel/Planification/issues/new)
|
||||||
- **Manifest** : V3 (Chrome/Edge/Firefox 140+)
|
- **Manifest** : V3 (Chrome/Edge/Firefox 140+)
|
||||||
- **Format** : `.zip` (Chromium) + `.xpi` signé Mozilla (Firefox)
|
- **Format** : `.zip` (Chromium) + `.xpi` signé Mozilla (Firefox)
|
||||||
@@ -66,6 +66,12 @@ Les mises à jour sont **manuelles** : à chaque nouvelle release, retélécharg
|
|||||||
- Badge + barre gauche colorée + dégradé fond
|
- Badge + barre gauche colorée + dégradé fond
|
||||||
- Absences récurrentes (configurées par tech) : cyan (depuis v2026.5.30)
|
- Absences récurrentes (configurées par tech) : cyan (depuis v2026.5.30)
|
||||||
|
|
||||||
|
### Email après un déplacement (depuis v2026.5.48)
|
||||||
|
- Brouillon d'email pré-adressé aux deux techniciens après un déplacement vers un autre jour ou un autre technicien (fenêtre de modification ou glisser-déposer) — l'envoi reste manuel, rien ne part automatiquement
|
||||||
|
- Case « Prévenir les techniciens par email » dans les fenêtres de déplacement : la décocher ne vaut que pour ce déplacement-là
|
||||||
|
- Onglet Paramètres → Email : option et modèle du message personnalisable (variables cliquables par thème, aperçu en direct)
|
||||||
|
- Adresses des techniciens dans l'onglet Équipe : récupération depuis l'annuaire EasyVista (complète aussi un nom affiché tronqué), déduction `prenom.nom@domaine` sinon
|
||||||
|
|
||||||
### User et session
|
### User et session
|
||||||
- Badge user avec photo/initiales en topbar
|
- Badge user avec photo/initiales en topbar
|
||||||
- Badge cliquable (depuis v2026.5.26) : popup avec ⚙ Paramètres + ⊞ Vue + compteur session MM:SS
|
- Badge cliquable (depuis v2026.5.26) : popup avec ⚙ Paramètres + ⊞ Vue + compteur session MM:SS
|
||||||
@@ -115,7 +121,35 @@ Le numéro de **majeure** n'est **pas** un mois et **pas** un chiffre lié au ca
|
|||||||
|
|
||||||
## Versions notables
|
## Versions notables
|
||||||
|
|
||||||
### `v2026.5.46` (latest, 9 juillet 2026) — Couche données v2, vue « échelle de temps exacte », session fiabilisée, réservations partagées
|
### `v2026.5.50` (latest, 29 septembre 2026) — Texte des actions rétabli, catégories Roll Out et Déménagement
|
||||||
|
|
||||||
|
- Correctif : depuis le 29 septembre 2026, EasyVista renvoie les actions avec une cellule de moins et le texte complet des actions ne s'affichait plus ; l'extension retrouve désormais ces informations par leur contenu et par le nom des colonnes, pour tenir aux prochains changements de format
|
||||||
|
- Si EasyVista change encore de format, un avertissement clair apparaît dans la console (une seule fois)
|
||||||
|
- Réservations : deux nouvelles catégories, Roll Out et Déménagement, propres à la Planification (dans EasyVista, la réservation reste « Evènements spéciaux ») ; partagées entre postes comme les autres informations de réservation
|
||||||
|
- Mettre à jour tous les postes le même jour : un poste resté en 2026.5.49 effacerait ces catégories en modifiant la réservation
|
||||||
|
|
||||||
|
### `v2026.5.49` (1 septembre 2026) — Sécurité hors session, onglet Email clarifié, lecture au défilement, affichage fiabilisé
|
||||||
|
|
||||||
|
- Sans session EasyVista active : plus d'écriture dans le dossier partagé (cache local seul) ni de modification (déplacement, suppression, absence, réservation bloqués proprement)
|
||||||
|
- Onglet Email séparé en deux sections (déplacement / annulation), copie (CC) commune avec aperçu en direct des adresses retenues, variables en colonnes
|
||||||
|
- Vue classique : nom du technicien, compteur et frise horaire restent visibles au défilement ; survol d'une pause qui met la frise en évidence
|
||||||
|
- Bannière « Session expirée » bien positionnée et affichée uniquement sur du vrai contenu ; plus de bulles de techniciens vides quand la session est morte
|
||||||
|
- Corrections : noms de contact nettoyés, deux interventions d'un même technicien le même jour affichées séparément, caractères parasités depuis EasyVista, indicateur d'écart d'adresse remis à jour après correction
|
||||||
|
|
||||||
|
### `v2026.5.48` (24 juillet 2026) — Notification par email des déplacements, onglet Email, fiches réservation fiables entre postes
|
||||||
|
|
||||||
|
- Brouillon d'email pré-rempli après un déplacement (autre jour ou autre technicien), modèle personnalisable avec variables et aperçu, case par déplacement
|
||||||
|
- Adresses des techniciens depuis l'annuaire EasyVista, noms tronqués complétés, domaine configurable
|
||||||
|
- Les informations de réservation voyagent avec la réservation entre les postes (horodatées, plus de fuites entre créneaux ou techniciens)
|
||||||
|
- Bouton « Ouvrir EasyVista » fiable sans cache ; recherche durcie (Entrée immédiate, plus d'interruptions au survol, statuts finals seulement)
|
||||||
|
|
||||||
|
### `v2026.5.47` (18 juillet 2026) — Vue « échelle de temps exacte » : aide à la saisie, erreurs mises en évidence
|
||||||
|
|
||||||
|
- Retour visuel de pose (zone + heure choisie + bulle « temps disponible »), rendez-vous à durée nulle visibles en rouge et bloquants, interventions courtes visibles
|
||||||
|
- Corrections : navigation rapide entre dates, synchro du dossier partagé (conflit d'index), doublons d'absences, réservations multiples le même jour
|
||||||
|
- Panneau Synchro réorganisé + bouton « Tester la communication » ; script du poste 2026.1.8
|
||||||
|
|
||||||
|
### `v2026.5.46` (9 juillet 2026) — Couche données v2, vue « échelle de temps exacte », session fiabilisée, réservations partagées
|
||||||
|
|
||||||
- Refonte complète de la couche données : store unifié par jour, un seul verdict par intervention, synchronisation du dossier partagé en sous-dossier v2
|
- Refonte complète de la couche données : store unifié par jour, un seul verdict par intervention, synchronisation du dossier partagé en sous-dossier v2
|
||||||
- Nouvelle disposition « échelle de temps exacte » pour la vue horizontale (option Apparence)
|
- Nouvelle disposition « échelle de temps exacte » pour la vue horizontale (option Apparence)
|
||||||
@@ -236,10 +270,10 @@ de cette version dans `firefox-updates.json`.
|
|||||||
|
|
||||||
## Licence
|
## Licence
|
||||||
|
|
||||||
[MIT License](LICENSE) — Copyright (c) 2026 FroSteel
|
[MIT License](LICENSE) — Copyright (c) 2026 Quentin
|
||||||
|
|
||||||
## Auteur
|
## Auteur
|
||||||
|
|
||||||
**FroSteel** (FRS)
|
**Quentin** (FRS)
|
||||||
Technicien DGNSI — Canton de Vaud
|
Technicien DGNSI — Canton de Vaud
|
||||||
Contact : voir [page wiki Contact](https://gitea.netaplaid.ch/FroSteel/Planification/wiki/Contact)
|
Contact : voir [page wiki Contact](https://gitea.netaplaid.ch/FroSteel/Planification/wiki/Contact)
|
||||||
|
|||||||
+21
-1
@@ -2,10 +2,30 @@
|
|||||||
"addons": {
|
"addons": {
|
||||||
"[email protected]": {
|
"[email protected]": {
|
||||||
"updates": [
|
"updates": [
|
||||||
|
{
|
||||||
|
"version": "2026.5.50",
|
||||||
|
"update_link": "https://gitea.netaplaid.ch/FroSteel/Planification/releases/download/v2026.5.50/planification-v2026.5.50-firefox.xpi",
|
||||||
|
"update_hash": "sha256:314ae3cba7e31d1f6eb89c419a666d49d156cd78a83c116de03f5e48b8a094df"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"version": "2026.5.49",
|
||||||
|
"update_link": "https://gitea.netaplaid.ch/FroSteel/Planification/releases/download/v2026.5.49/planification-v2026.5.49-firefox.xpi",
|
||||||
|
"update_hash": "sha256:73ac4e44e9fdfb1c3c179c7cc5d2e497b5cf27d207947cc559ab620bddd09fa1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"version": "2026.5.48",
|
||||||
|
"update_link": "https://gitea.netaplaid.ch/FroSteel/Planification/releases/download/v2026.5.48/planification-v2026.5.48-firefox.xpi",
|
||||||
|
"update_hash": "sha256:be687aa2795649d7f1f9883f3384365bd224e0ab94987ff852b0901f5554a51a"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"version": "2026.5.47",
|
||||||
|
"update_link": "https://gitea.netaplaid.ch/FroSteel/Planification/releases/download/v2026.5.47/planification-v2026.5.47-firefox.xpi",
|
||||||
|
"update_hash": "sha256:0418062357b7c29bdd7a01b6d6e06eeb20e2ee419c67684a84855862af113cc2"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"version": "2026.5.46",
|
"version": "2026.5.46",
|
||||||
"update_link": "https://gitea.netaplaid.ch/FroSteel/Planification/releases/download/v2026.5.46/planification-v2026.5.46-firefox.xpi",
|
"update_link": "https://gitea.netaplaid.ch/FroSteel/Planification/releases/download/v2026.5.46/planification-v2026.5.46-firefox.xpi",
|
||||||
"update_hash": "sha256:052cac5d79a8ec9f1eeb7172e8491f2e2a82b5937622131905cfcaa3eba4737b"
|
"update_hash": "sha256:673dc0527073523750de348414ae1d3b5c0cb42cc8128a7839bbb09bffb6242c"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"version": "2026.5.45",
|
"version": "2026.5.45",
|
||||||
|
|||||||
+39
-13
@@ -1,5 +1,5 @@
|
|||||||
# Planification - native messaging host // 2026.1.4 - FRS
|
# Planification - native messaging host // 2026.1.4 - FRS
|
||||||
# Developpe par FroSteel (FRS) - DGNSI, Canton de Vaud.
|
# Developpe par Quentin (FRS) - DGNSI, Canton de Vaud.
|
||||||
# Licence MIT - voir le fichier LICENSE.
|
# Licence MIT - voir le fichier LICENSE.
|
||||||
#
|
#
|
||||||
# Pont entre l'extension et un dossier reseau partage pour le cache du planning.
|
# Pont entre l'extension et un dossier reseau partage pour le cache du planning.
|
||||||
@@ -30,7 +30,7 @@
|
|||||||
$ErrorActionPreference = 'Stop'
|
$ErrorActionPreference = 'Stop'
|
||||||
$ProgressPreference = 'SilentlyContinue'
|
$ProgressPreference = 'SilentlyContinue'
|
||||||
|
|
||||||
$HOST_VERSION = '2026.1.7'
|
$HOST_VERSION = '2026.1.8'
|
||||||
# v2026.1.7 - le host n'est plus persistant a vie : s'il ne recoit AUCUN message
|
# v2026.1.7 - le host n'est plus persistant a vie : s'il ne recoit AUCUN message
|
||||||
# pendant ce delai, il se ferme proprement (le navigateur le relance a la
|
# pendant ce delai, il se ferme proprement (le navigateur le relance a la
|
||||||
# prochaine activite de l'extension). Il lance aussi le tray a la demande.
|
# prochaine activite de l'extension). Il lance aussi le tray a la demande.
|
||||||
@@ -155,18 +155,44 @@ function Read-Index([string]$share) {
|
|||||||
|
|
||||||
function Update-Index([string]$share, [string]$date, [long]$savedAt) {
|
function Update-Index([string]$share, [string]$date, [long]$savedAt) {
|
||||||
$idx = Join-Path $share $INDEX_NAME
|
$idx = Join-Path $share $INDEX_NAME
|
||||||
$map = @{}
|
# v2026.1.8 - verrou DEDIE a l'index. Plusieurs hotes (plusieurs onglets
|
||||||
if (Test-Path -LiteralPath $idx) {
|
# Planification ouverts, ou plusieurs postes) font un read-modify-write
|
||||||
try {
|
# concurrent sur _index.json ; sans verrou, deux Move-Item se recouvrent et la
|
||||||
$existing = Get-Content -LiteralPath $idx -Raw -Encoding UTF8 | ConvertFrom-Json
|
# maj d'un hote est perdue (lost update) -> l'index prend du retard sur les
|
||||||
foreach ($p in $existing.PSObject.Properties) { $map[$p.Name] = $p.Value }
|
# fichiers-jour -> conflits CAS a repetition ("refusion" en boucle). On
|
||||||
} catch {}
|
# serialise donc la sequence lecture->modif->ecriture. Vol du verrou perime
|
||||||
|
# (> 10 s) comme pour les fichiers-jour. Best-effort : si on n'obtient pas le
|
||||||
|
# verrou, on renonce (la prochaine ecriture reussie remettra l'index a jour).
|
||||||
|
$lock = $idx + '.lock'
|
||||||
|
$haveLock = $false
|
||||||
|
for ($i = 0; $i -lt 20 -and -not $haveLock; $i++) {
|
||||||
|
try { [System.IO.File]::Open($lock, [System.IO.FileMode]::CreateNew, [System.IO.FileAccess]::Write).Close(); $haveLock = $true }
|
||||||
|
catch {
|
||||||
|
try {
|
||||||
|
$age = ((Get-Date) - (Get-Item -LiteralPath $lock).LastWriteTime).TotalSeconds
|
||||||
|
if ($age -gt 10) { Remove-Item -LiteralPath $lock -Force -ErrorAction SilentlyContinue }
|
||||||
|
else { Start-Sleep -Milliseconds 50 }
|
||||||
|
} catch { Start-Sleep -Milliseconds 50 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (-not $haveLock) { Write-Activity 'DEBUG' "Index non mis a jour pour le $(Format-DateFR $date) (verrou index indisponible)"; return }
|
||||||
|
try {
|
||||||
|
# lecture DANS le verrou -> on part toujours de la derniere version.
|
||||||
|
$map = @{}
|
||||||
|
if (Test-Path -LiteralPath $idx) {
|
||||||
|
try {
|
||||||
|
$existing = Get-Content -LiteralPath $idx -Raw -Encoding UTF8 | ConvertFrom-Json
|
||||||
|
foreach ($p in $existing.PSObject.Properties) { $map[$p.Name] = $p.Value }
|
||||||
|
} catch {}
|
||||||
|
}
|
||||||
|
$map[$date] = $savedAt
|
||||||
|
$tmp = $idx + '.tmp'
|
||||||
|
[System.IO.File]::WriteAllText($tmp, ($map | ConvertTo-Json -Compress -Depth 5), $Utf8NoBom)
|
||||||
|
Move-Item -LiteralPath $tmp -Destination $idx -Force
|
||||||
|
Write-Activity 'DEBUG' "Index du dossier mis a jour pour le $(Format-DateFR $date)"
|
||||||
|
} finally {
|
||||||
|
Remove-Item -LiteralPath $lock -Force -ErrorAction SilentlyContinue
|
||||||
}
|
}
|
||||||
$map[$date] = $savedAt
|
|
||||||
$tmp = $idx + '.tmp'
|
|
||||||
[System.IO.File]::WriteAllText($tmp, ($map | ConvertTo-Json -Compress -Depth 5), $Utf8NoBom)
|
|
||||||
Move-Item -LiteralPath $tmp -Destination $idx -Force
|
|
||||||
Write-Activity 'DEBUG' "Index du dossier mis a jour pour le $(Format-DateFR $date)"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function Get-SavedAt([string]$share, [string]$date, [string]$file) {
|
function Get-SavedAt([string]$share, [string]$date, [string]$file) {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Planification - gestionnaire graphique du helper de sync. // 2026.1.5 - FRS
|
# Planification - gestionnaire graphique du helper de sync. // 2026.1.5 - FRS
|
||||||
# Developpe par FroSteel (FRS) - DGNSI, Canton de Vaud.
|
# Developpe par Quentin (FRS) - DGNSI, Canton de Vaud.
|
||||||
# Licence MIT - voir le fichier LICENSE.
|
# Licence MIT - voir le fichier LICENSE.
|
||||||
#
|
#
|
||||||
# Fenetre avec : Installer / Mettre a jour, Reparer, Desinstaller.
|
# Fenetre avec : Installer / Mettre a jour, Reparer, Desinstaller.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Planification - icone barre des taches (best-effort, optionnel) // 2026.1.4 - FRS
|
# Planification - icone barre des taches (best-effort, optionnel) // 2026.1.4 - FRS
|
||||||
# Developpe par FroSteel (FRS) - DGNSI, Canton de Vaud.
|
# Developpe par Quentin (FRS) - DGNSI, Canton de Vaud.
|
||||||
# Licence MIT - voir le fichier LICENSE.
|
# Licence MIT - voir le fichier LICENSE.
|
||||||
#
|
#
|
||||||
# Indique que le helper de sync est installe. Clic / menu -> fenetre du journal
|
# Indique que le helper de sync est installe. Clic / menu -> fenetre du journal
|
||||||
@@ -160,6 +160,35 @@ $ni.Icon = Get-TrayIcon
|
|||||||
$ni.Text = 'Planification - synchronisation active'
|
$ni.Text = 'Planification - synchronisation active'
|
||||||
$ni.Visible = $true
|
$ni.Visible = $true
|
||||||
|
|
||||||
|
# v2026.1.8 - "toujours present si actif" : le NotifyIcon disparait quand
|
||||||
|
# explorer.exe redemarre (Windows rediffuse alors le message "TaskbarCreated").
|
||||||
|
# Sans le traiter, l'icone ne revient JAMAIS tant que le tray tourne. On ecoute
|
||||||
|
# ce message via une petite fenetre native et on re-affiche l'icone.
|
||||||
|
try {
|
||||||
|
Add-Type -ReferencedAssemblies System.Windows.Forms -TypeDefinition @'
|
||||||
|
using System;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
public class PlanifTrayWatcher : NativeWindow {
|
||||||
|
[DllImport("user32.dll", CharSet = CharSet.Auto)]
|
||||||
|
static extern uint RegisterWindowMessage(string lpString);
|
||||||
|
public static readonly uint TaskbarCreated = RegisterWindowMessage("TaskbarCreated");
|
||||||
|
private NotifyIcon _icon;
|
||||||
|
public PlanifTrayWatcher(NotifyIcon icon) {
|
||||||
|
_icon = icon;
|
||||||
|
this.CreateHandle(new CreateParams());
|
||||||
|
}
|
||||||
|
protected override void WndProc(ref Message m) {
|
||||||
|
if (m.Msg == TaskbarCreated && _icon != null) {
|
||||||
|
try { _icon.Visible = false; _icon.Visible = true; } catch {}
|
||||||
|
}
|
||||||
|
base.WndProc(ref m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'@ -ErrorAction Stop
|
||||||
|
$script:trayWatcher = New-Object PlanifTrayWatcher($ni)
|
||||||
|
} catch {}
|
||||||
|
|
||||||
$menu = New-Object System.Windows.Forms.ContextMenuStrip
|
$menu = New-Object System.Windows.Forms.ContextMenuStrip
|
||||||
$miLog = $menu.Items.Add('Voir le journal de synchronisation')
|
$miLog = $menu.Items.Add('Voir le journal de synchronisation')
|
||||||
$miLog.add_Click({ Show-LogWindow })
|
$miLog.add_Click({ Show-LogWindow })
|
||||||
|
|||||||
+8
-8
@@ -4,13 +4,13 @@
|
|||||||
* Service worker (Manifest V3) : récupération session EV, fetch planning XML,
|
* Service worker (Manifest V3) : récupération session EV, fetch planning XML,
|
||||||
* fetch fiches détaillées, gestion cache.
|
* fetch fiches détaillées, gestion cache.
|
||||||
*
|
*
|
||||||
* Copyright (c) 2026 FroSteel
|
* Copyright (c) 2026 Quentin
|
||||||
* Licensed under the MIT License — see LICENSE file in the project root.
|
* Licensed under the MIT License — see LICENSE file in the project root.
|
||||||
*
|
*
|
||||||
* @author FroSteel
|
* @author Quentin
|
||||||
* @repository https://gitea.netaplaid.ch/FroSteel/Planification
|
* @repository https://gitea.netaplaid.ch/FroSteel/Planification
|
||||||
*
|
*
|
||||||
* Développé par FroSteel (FRS) — DGNSI, Canton de Vaud. Licence MIT.
|
* Développé par Quentin (FRS) — DGNSI, Canton de Vaud. Licence MIT.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// background.js — Service worker (Manifest V3) — v4
|
// background.js — Service worker (Manifest V3) — v4
|
||||||
@@ -262,7 +262,7 @@ chrome.action.onClicked.addListener(async () => {
|
|||||||
* dans l'URL des onglets historiques après un relog. Sinon, fallback sur
|
* dans l'URL des onglets historiques après un relog. Sinon, fallback sur
|
||||||
* l'ancienne logique URL (compat sans la permission).
|
* l'ancienne logique URL (compat sans la permission).
|
||||||
*
|
*
|
||||||
* @author FroSteel
|
* @author Quentin
|
||||||
*/
|
*/
|
||||||
async function _hasCookiesPermission() {
|
async function _hasCookiesPermission() {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
@@ -423,7 +423,7 @@ async function findEasyVistaSession() {
|
|||||||
* Ce n'est PAS le HTML de la page Planning — le serveur ne rend pas les données
|
* Ce n'est PAS le HTML de la page Planning — le serveur ne rend pas les données
|
||||||
* dans le HTML, elles arrivent via cet endpoint AJAX.
|
* dans le HTML, elles arrivent via cet endpoint AJAX.
|
||||||
*
|
*
|
||||||
* @author FroSteel
|
* @author Quentin
|
||||||
*/
|
*/
|
||||||
async function fetchPlanningXml(origin, phpsessid, unixDate) {
|
async function fetchPlanningXml(origin, phpsessid, unixDate) {
|
||||||
// v2026.5.41 : groupId vient de admin_config (défaut SI-CSS).
|
// v2026.5.41 : groupId vient de admin_config (défaut SI-CSS).
|
||||||
@@ -781,7 +781,7 @@ async function extendSessionKeepAlive(origin, phpsessid) {
|
|||||||
* @param {boolean} force - si true, ignore le cache et refait le test
|
* @param {boolean} force - si true, ignore le cache et refait le test
|
||||||
* @returns {Promise<"internal"|"external">}
|
* @returns {Promise<"internal"|"external">}
|
||||||
*
|
*
|
||||||
* @author FroSteel
|
* @author Quentin
|
||||||
*/
|
*/
|
||||||
async function detectNetworkContext(force = false) {
|
async function detectNetworkContext(force = false) {
|
||||||
const CACHE_KEY = "network_context_v2"; // v5.0.12 : nouvelle clé pour invalider le cache fautif v5.0.11
|
const CACHE_KEY = "network_context_v2"; // v5.0.12 : nouvelle clé pour invalider le cache fautif v5.0.11
|
||||||
@@ -921,7 +921,7 @@ function watchReconnectTabForIamLogin(tabId) {
|
|||||||
* Retourne { name: "Nom Prénom" | null, login: "..." | null } ou null si
|
* Retourne { name: "Nom Prénom" | null, login: "..." | null } ou null si
|
||||||
* tout a échoué.
|
* tout a échoué.
|
||||||
*
|
*
|
||||||
* @author FroSteel
|
* @author Quentin
|
||||||
*/
|
*/
|
||||||
async function fetchCurrentUser(origin, phpsessid) {
|
async function fetchCurrentUser(origin, phpsessid) {
|
||||||
const url = `${origin}/index.php?PHPSESSID=${encodeURIComponent(phpsessid)}`;
|
const url = `${origin}/index.php?PHPSESSID=${encodeURIComponent(phpsessid)}`;
|
||||||
@@ -1306,7 +1306,7 @@ async function deletePlanningItem(origin, phpsessid, actionId, kind) {
|
|||||||
* Retourne { groups: [{id, name}, ...] }. Liste vide si le fetch échoue ou
|
* Retourne { groups: [{id, name}, ...] }. Liste vide si le fetch échoue ou
|
||||||
* si EV renvoie une page de login / redirection JS.
|
* si EV renvoie une page de login / redirection JS.
|
||||||
*
|
*
|
||||||
* @author FroSteel
|
* @author Quentin
|
||||||
*/
|
*/
|
||||||
async function detectGroupsFromEV(origin, phpsessid) {
|
async function detectGroupsFromEV(origin, phpsessid) {
|
||||||
const url = `${origin}/index.php?eventName=HelpDesk_PlanningItem&PHPSESSID=${encodeURIComponent(phpsessid)}`;
|
const url = `${origin}/index.php?eventName=HelpDesk_PlanningItem&PHPSESSID=${encodeURIComponent(phpsessid)}`;
|
||||||
|
|||||||
+2
-2
@@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"manifest_version": 3,
|
"manifest_version": 3,
|
||||||
"name": "Planification",
|
"name": "Planification",
|
||||||
"version": "2026.5.46",
|
"version": "2026.5.50",
|
||||||
"description": "Vue claire et rapide du planning des techniciens EasyVista. Développé par FroSteel — DGNSI, Canton de Vaud.",
|
"description": "Vue claire et rapide du planning des techniciens EasyVista. Développé par Quentin — DGNSI, Canton de Vaud.",
|
||||||
"key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAl/El4I9gxcZkp5bnheg4ZBCKxckRLt9xQ5x+i6phEPYlydl6NapWlkbOyycUaeTZcpoEh/tKQnpMpoEc5jY8zCoRTwh/vfejVBZE6ANDG/dc3iix/1Z8OhRI4zMaRYQ+DQTjS5Q6l6wkcwzbQB85HZNhke/k1qIW6RCuBjeJYmES5WVDwzfCNVvaF6uQvdOCpLjrA3+LI6vUBEwaMg1hM42mC3dU0z9p7qzAby/dH3XpZD9HTFXLJL9/1zryN9rXNDpvZwYWnJ0hLTu5tfmURkvgKOwquX1KJy9vupmhUALRtS08Fplx/e3kUH3LD+coS1ExLwoOZ+1ORBUE9JCB8wIDAQAB",
|
"key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAl/El4I9gxcZkp5bnheg4ZBCKxckRLt9xQ5x+i6phEPYlydl6NapWlkbOyycUaeTZcpoEh/tKQnpMpoEc5jY8zCoRTwh/vfejVBZE6ANDG/dc3iix/1Z8OhRI4zMaRYQ+DQTjS5Q6l6wkcwzbQB85HZNhke/k1qIW6RCuBjeJYmES5WVDwzfCNVvaF6uQvdOCpLjrA3+LI6vUBEwaMg1hM42mC3dU0z9p7qzAby/dH3XpZD9HTFXLJL9/1zryN9rXNDpvZwYWnJ0hLTu5tfmURkvgKOwquX1KJy9vupmhUALRtS08Fplx/e3kUH3LD+coS1ExLwoOZ+1ORBUE9JCB8wIDAQAB",
|
||||||
"permissions": [
|
"permissions": [
|
||||||
"activeTab",
|
"activeTab",
|
||||||
|
|||||||
+395
-40
@@ -1,10 +1,10 @@
|
|||||||
/**
|
/**
|
||||||
* Planification — Extension navigateur EasyVista (Canton de Vaud / DGNSI)
|
* Planification — Extension navigateur EasyVista (Canton de Vaud / DGNSI)
|
||||||
*
|
*
|
||||||
* Copyright (c) 2026 FroSteel
|
* Copyright (c) 2026 Quentin
|
||||||
* Licensed under the MIT License — see LICENSE file in the project root.
|
* Licensed under the MIT License — see LICENSE file in the project root.
|
||||||
*
|
*
|
||||||
* @author FroSteel
|
* @author Quentin
|
||||||
* @repository https://gitea.netaplaid.ch/FroSteel/Planification
|
* @repository https://gitea.netaplaid.ch/FroSteel/Planification
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -64,6 +64,22 @@
|
|||||||
|
|
||||||
--shadow: 0 1px 3px rgba(20, 30, 50, 0.06), 0 1px 2px rgba(20, 30, 50, 0.04);
|
--shadow: 0 1px 3px rgba(20, 30, 50, 0.06), 0 1px 2px rgba(20, 30, 50, 0.04);
|
||||||
--shadow-hover: 0 2px 8px rgba(20, 30, 50, 0.08);
|
--shadow-hover: 0 2px 8px rgba(20, 30, 50, 0.08);
|
||||||
|
/* v2026.5.49 — relief des interventions : elles se posent en surface
|
||||||
|
claire (--bg-elevated) sur le corps de carte, qui recule (--iv-canvas).
|
||||||
|
Ombre un cran au-dessus de --shadow (qui porte les cartes elles-mêmes)
|
||||||
|
pour que la hiérarchie carte < intervention se voie sans devenir
|
||||||
|
tape-à-l'oeil. --iv-canvas est un gris un peu plus soutenu que
|
||||||
|
--bg-muted : sur du blanc, l'écart de --bg-muted se voyait à peine. */
|
||||||
|
--iv-canvas: #eaecf1;
|
||||||
|
--iv-relief: 0 1px 2px rgba(20, 30, 50, 0.10), 0 2px 5px rgba(20, 30, 50, 0.07);
|
||||||
|
/* v2026.5.49 — fond des plages LIBRES (pauses affichées, créneaux du mode
|
||||||
|
heure exacte). HACHURES claires plutôt qu'un voile uni : un aplat
|
||||||
|
légèrement plus clair se voyait à peine, et monter son contraste le
|
||||||
|
rapprochait des tuiles d'intervention. Le rayé reprend le langage des
|
||||||
|
trous de la timeline (45°) — impossible à confondre avec une surface
|
||||||
|
pleine, et lisible de loin. */
|
||||||
|
--iv-libre: repeating-linear-gradient(45deg,
|
||||||
|
var(--bg-elevated) 0 7px, var(--iv-canvas) 7px 14px);
|
||||||
--radius: 8px;
|
--radius: 8px;
|
||||||
--font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
|
--font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
|
||||||
--mono: ui-monospace, SFMono-Regular, "SF Mono", Consolas, "Liberation Mono", monospace;
|
--mono: ui-monospace, SFMono-Regular, "SF Mono", Consolas, "Liberation Mono", monospace;
|
||||||
@@ -112,6 +128,16 @@
|
|||||||
|
|
||||||
--shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
|
--shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
|
||||||
--shadow-hover: 0 2px 10px rgba(0, 0, 0, 0.4);
|
--shadow-hover: 0 2px 10px rgba(0, 0, 0, 0.4);
|
||||||
|
/* v2026.5.49 — sur fond sombre l'ombre porte moins : elle est plus dense
|
||||||
|
et c'est surtout l'écart de clarté (corps --iv-canvas / intervention
|
||||||
|
--bg-elevated #21242b) qui fait le relief. */
|
||||||
|
--iv-canvas: #191c21;
|
||||||
|
--iv-relief: 0 1px 2px rgba(0, 0, 0, 0.45), 0 2px 6px rgba(0, 0, 0, 0.30);
|
||||||
|
/* v2026.5.49 — en sombre, éclaircir veut dire monter vers la lumière :
|
||||||
|
les hachures partent de --bg-hover, sinon elles se confondaient avec le
|
||||||
|
fond. */
|
||||||
|
--iv-libre: repeating-linear-gradient(45deg,
|
||||||
|
var(--bg-hover) 0 7px, var(--iv-canvas) 7px 14px);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ==========================================================================
|
/* ==========================================================================
|
||||||
@@ -1130,6 +1156,18 @@ html.view-classic .error-box.error-box-centered {
|
|||||||
box-shadow: var(--shadow);
|
box-shadow: var(--shadow);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
/* v2026.5.47 — message de reconnexion EasyVista (#session-needed /
|
||||||
|
#ev-unreachable) CENTRÉ dans la zone de contenu en vue horizontale (avant :
|
||||||
|
posé en haut, comme un item flex de main#main). main#main est
|
||||||
|
position:relative en horizontal ; on centre dans le contenu (à droite de la
|
||||||
|
sidebar) via left = 50% + --sidebar-w/2. */
|
||||||
|
html.view-horizontal .session-needed {
|
||||||
|
position: absolute !important;
|
||||||
|
top: 50% !important;
|
||||||
|
left: calc(50% + var(--sidebar-w, 200px) / 2) !important;
|
||||||
|
transform: translate(-50%, -50%) !important;
|
||||||
|
margin: 0 !important;
|
||||||
|
}
|
||||||
.session-needed h2 {
|
.session-needed h2 {
|
||||||
margin: 0 0 12px 0;
|
margin: 0 0 12px 0;
|
||||||
color: var(--text);
|
color: var(--text);
|
||||||
@@ -1192,7 +1230,11 @@ html.view-classic .error-box.error-box-centered {
|
|||||||
border: 1px solid var(--border);
|
border: 1px solid var(--border);
|
||||||
border-radius: var(--radius);
|
border-radius: var(--radius);
|
||||||
box-shadow: var(--shadow);
|
box-shadow: var(--shadow);
|
||||||
overflow: hidden;
|
/* v2026.5.49 — `clip` au lieu de `hidden` : coupe le débordement (coins
|
||||||
|
arrondis) SANS créer de conteneur de défilement, sinon l'en-tête sticky
|
||||||
|
(ci-dessous) se collerait à la carte au lieu de la fenêtre (même piège que
|
||||||
|
body { overflow-x: clip }). */
|
||||||
|
overflow: clip;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
@@ -1207,6 +1249,40 @@ html.view-classic .error-box.error-box-centered {
|
|||||||
gap: 10px;
|
gap: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* v2026.5.49 — VUE CLASSIQUE : l'en-tête de carte (nom du tech + badges)
|
||||||
|
suit le scroll et reste collé sous l'empilement du haut (topbar + bandeaux
|
||||||
|
session + ligne stats/recherche), tant que sa carte est à l'écran. Sinon le
|
||||||
|
nom disparaissait dès qu'on scrollait une carte haute. Même offset que la
|
||||||
|
barre de progression (--stack-top + --topline-h, mesurés en JS). En vue
|
||||||
|
horizontale, l'en-tête fait partie de la ligne : pas de sticky. */
|
||||||
|
html:not(.view-horizontal) .card-header {
|
||||||
|
position: sticky;
|
||||||
|
/* v2026.5.49 — pendant un rafraîchissement, la barre de progression est
|
||||||
|
sticky au MÊME offset (--stack-top + --topline-h) avec un z-index supérieur :
|
||||||
|
elle recouvrait le nom du tech collé quand on avait scrollé. On ajoute donc
|
||||||
|
--progress-h (hauteur réelle de la barre, mesurée en JS ; 0 hors refresh)
|
||||||
|
pour caler l'en-tête JUSTE SOUS la barre. */
|
||||||
|
top: calc(var(--stack-top, 56px) + var(--topline-h, 0px) + var(--progress-h, 0px));
|
||||||
|
/* au-dessus du contenu de la frise qui défile dessous (slot hover z2, midi
|
||||||
|
z3, trou survolé z6) ; reste sous la banderole session (z8) et la barre de
|
||||||
|
progression (z9), qui sont dans un autre contexte d'empilement. */
|
||||||
|
z-index: 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* v2026.5.49 — VUE CLASSIQUE : la frise horaire (.timeline) reste collée JUSTE
|
||||||
|
SOUS l'en-tête du tech quand on scrolle, tant que la carte est à l'écran —
|
||||||
|
pour garder le repère horaire ET le total d'interventions visibles (le total
|
||||||
|
vit dans l'en-tête .tech-row-stats, déjà collant). Elle se cale sous l'en-tête
|
||||||
|
via --card-header-h (hauteur RÉELLE de l'en-tête de CETTE carte, mesurée en JS
|
||||||
|
car un nom long fait 2-3 lignes). Fond opaque (--bg-muted) : le contenu défile
|
||||||
|
dessous sans transparence. z-index 6 : sous l'en-tête (7), au-dessus du corps
|
||||||
|
qui défile. */
|
||||||
|
html:not(.view-horizontal) .card-body > .timeline {
|
||||||
|
position: sticky;
|
||||||
|
top: calc(var(--stack-top, 56px) + var(--topline-h, 0px) + var(--progress-h, 0px) + var(--card-header-h, 0px));
|
||||||
|
z-index: 6;
|
||||||
|
}
|
||||||
|
|
||||||
.card-tech-name {
|
.card-tech-name {
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
@@ -1264,6 +1340,41 @@ html.view-classic .error-box.error-box-centered {
|
|||||||
.card-body {
|
.card-body {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
/* v2026.5.49 — le corps de la carte RECULE (fond en retrait) pour que
|
||||||
|
les interventions posées dessus ressortent. Avant, corps et interventions
|
||||||
|
partageaient le même blanc : tout le contenu se lisait comme un seul
|
||||||
|
aplat, séparé par des filets de 1 px. */
|
||||||
|
background: var(--iv-canvas);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* v2026.5.49 — vue classique, option « Afficher les pauses » ACTIVE : les
|
||||||
|
plages libres REMPLISSENT le vide de la carte au lieu de rester des bandes
|
||||||
|
de 44 px suivies d'un grand aplat gris. Les cartes d'une même ligne ont la
|
||||||
|
hauteur de la plus chargée : tout ce qui dépasse le contenu est du temps
|
||||||
|
disponible, il se lit donc comme tel. Le corps passe en colonne flex et
|
||||||
|
chaque pause reçoit le MÊME flex-grow (posé par _buildGapPlaceholder ;
|
||||||
|
v2026.5.49) : toutes les plages ont la même taille. Les autres
|
||||||
|
éléments gardent leur taille (flex-shrink: 0) — sans cela, un contenu plus
|
||||||
|
haut que la carte comprimerait les interventions. Option inactive ou vue
|
||||||
|
horizontale : rien ne change (les pauses y sont masquées ou gérées par les
|
||||||
|
règles .gap-placeholder-mini). */
|
||||||
|
html.show-iv-gaps:not(.view-horizontal) .card-body {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
html.show-iv-gaps:not(.view-horizontal) .card-body > *:not(.gap-placeholder) {
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* v2026.5.49 — cartes d'absence : leur couleur de catégorie est peinte sur
|
||||||
|
la CARTE (dégradé vers --iv-canvas) ; un fond opaque sur le corps la
|
||||||
|
masquerait. Le corps se contente donc de laisser passer, et les
|
||||||
|
interventions éventuelles gardent leur relief (tuile claire sur le
|
||||||
|
dégradé, qui finit sur la même teinte de retrait). */
|
||||||
|
.card.absence-cat-maladie .card-body,
|
||||||
|
.card.absence-cat-conge .card-body,
|
||||||
|
.card.absence-cat-recurring .card-body {
|
||||||
|
background: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-empty {
|
.card-empty {
|
||||||
@@ -1549,6 +1660,35 @@ html.view-horizontal .timeline-noon {
|
|||||||
background: #c44040 !important;
|
background: #c44040 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* v2026.5.47 — intervention à DURÉE NULLE (début == fin, ex. 10:00→10:00 :
|
||||||
|
erreur de saisie EV). Même rouge plein que les conflits ci-dessus, pour la
|
||||||
|
repérer d'un coup d'oeil dans toutes les vues. */
|
||||||
|
.iv-mini-card.iv-zero-duration {
|
||||||
|
background: #b03030 !important;
|
||||||
|
color: #ffffff !important;
|
||||||
|
border-color: #7a1f1f !important;
|
||||||
|
}
|
||||||
|
.iv-mini-card.iv-zero-duration .iv-mini-card-bar,
|
||||||
|
.iv-mini-card.iv-zero-duration .iv-mini-time-vertical,
|
||||||
|
.iv-mini-card.iv-zero-duration .iv-mini-card-text {
|
||||||
|
color: #ffffff !important;
|
||||||
|
background: transparent !important;
|
||||||
|
}
|
||||||
|
/* Vue exacte : la bulle est très fine (min-width) → le bord gauche (poignée)
|
||||||
|
doit être rouge lui aussi, sinon on ne verrait que sa couleur de catégorie. */
|
||||||
|
html.view-horizontal .iv-exact-card.iv-zero-duration .iv-exact-handle {
|
||||||
|
background-color: #7a1f1f !important;
|
||||||
|
background-image: none !important;
|
||||||
|
}
|
||||||
|
/* v2026.5.47 — durée nulle PLUS VISIBLE en vue exacte : un peu plus large
|
||||||
|
que les interventions courtes (11 px vs 6 px) + hachures rouges pour attirer
|
||||||
|
l'oeil sur l'erreur. */
|
||||||
|
html.view-horizontal .iv-exact-card.iv-zero-duration {
|
||||||
|
min-width: 11px !important;
|
||||||
|
background-image: repeating-linear-gradient(
|
||||||
|
45deg, #b03030 0 4px, #7a1f1f 4px 8px) !important;
|
||||||
|
}
|
||||||
|
|
||||||
/* ==========================================================================
|
/* ==========================================================================
|
||||||
Interventions — layout v2 (heures verticales)
|
Interventions — layout v2 (heures verticales)
|
||||||
========================================================================== */
|
========================================================================== */
|
||||||
@@ -1565,12 +1705,18 @@ html.view-horizontal .timeline-noon {
|
|||||||
gap: 2px 10px;
|
gap: 2px 10px;
|
||||||
align-items: start;
|
align-items: start;
|
||||||
padding: 10px 12px 12px 8px;
|
padding: 10px 12px 12px 8px;
|
||||||
border-top: 1px solid var(--border);
|
|
||||||
cursor: default;
|
cursor: default;
|
||||||
transition: background 0.08s;
|
transition: background 0.08s;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
/* v2026.5.49 — tuile posée sur le corps de carte en retrait : surface
|
||||||
|
claire, contour et ombre. Remplace le simple filet border-top, qui ne
|
||||||
|
distinguait rien (même fond de part et d'autre du trait). */
|
||||||
|
background: var(--bg-elevated);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: 6px;
|
||||||
|
box-shadow: var(--iv-relief);
|
||||||
|
margin: 6px 8px;
|
||||||
}
|
}
|
||||||
.intervention-v2:first-child { border-top: none; }
|
|
||||||
.intervention-v2:hover { background: var(--bg-hover); }
|
.intervention-v2:hover { background: var(--bg-hover); }
|
||||||
|
|
||||||
/* Pastille colorée (barre verticale) */
|
/* Pastille colorée (barre verticale) */
|
||||||
@@ -1596,23 +1742,25 @@ html.view-horizontal .timeline-noon {
|
|||||||
/* : on GARDE la couleur de catégorie visible (.intervention-dot reste
|
/* : on GARDE la couleur de catégorie visible (.intervention-dot reste
|
||||||
en couleur de catégorie + fond neutre). Le statut clos/résolu/terminé est
|
en couleur de catégorie + fond neutre). Le statut clos/résolu/terminé est
|
||||||
signalé par un bandeau vert sur la DROITE de la carte (inset shadow) +
|
signalé par un bandeau vert sur la DROITE de la carte (inset shadow) +
|
||||||
le ✓✓ ou ✓ existant. */
|
le ✓✓ ou ✓ existant.
|
||||||
|
v2026.5.49 — ce bandeau se COMPOSE avec le relief de la tuile : une
|
||||||
|
box-shadow unique aurait effacé l'ombre. */
|
||||||
.intervention-v2.status-closed {
|
.intervention-v2.status-closed {
|
||||||
box-shadow: inset -4px 0 0 var(--c-closed);
|
box-shadow: inset -4px 0 0 var(--c-closed), var(--iv-relief);
|
||||||
}
|
}
|
||||||
.intervention-v2.status-closed:hover {
|
.intervention-v2.status-closed:hover {
|
||||||
filter: brightness(0.96);
|
filter: brightness(0.96);
|
||||||
}
|
}
|
||||||
|
|
||||||
.intervention-v2.status-resolved {
|
.intervention-v2.status-resolved {
|
||||||
box-shadow: inset -4px 0 0 var(--c-resolved);
|
box-shadow: inset -4px 0 0 var(--c-resolved), var(--iv-relief);
|
||||||
}
|
}
|
||||||
.intervention-v2.status-resolved:hover {
|
.intervention-v2.status-resolved:hover {
|
||||||
filter: brightness(0.96);
|
filter: brightness(0.96);
|
||||||
}
|
}
|
||||||
|
|
||||||
.intervention-v2.status-terminated {
|
.intervention-v2.status-terminated {
|
||||||
box-shadow: inset -4px 0 0 var(--c-terminated, #16a34a);
|
box-shadow: inset -4px 0 0 var(--c-terminated, #16a34a), var(--iv-relief);
|
||||||
}
|
}
|
||||||
.intervention-v2.status-terminated:hover {
|
.intervention-v2.status-terminated:hover {
|
||||||
filter: brightness(0.96);
|
filter: brightness(0.96);
|
||||||
@@ -3198,6 +3346,48 @@ header.topbar::before {
|
|||||||
color: var(--text-muted);
|
color: var(--text-muted);
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
}
|
}
|
||||||
|
/* v2026.5.49 — chaque type d'email (déplacement / annulation) est une
|
||||||
|
SECTION visuellement délimitée : encadré léger + liseré d'accent à gauche,
|
||||||
|
pour qu'on distingue d'un coup d'oeil les deux zones. */
|
||||||
|
.admin-email-section {
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-left: 3px solid var(--accent);
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 12px 14px 14px;
|
||||||
|
margin: 18px 0 0;
|
||||||
|
}
|
||||||
|
.admin-email-section .admin-email-section-titre {
|
||||||
|
margin-top: 0;
|
||||||
|
font-size: 17px;
|
||||||
|
}
|
||||||
|
/* v2026.5.49 — aperçu en direct des adresses en COPIE (CC) sous le champ :
|
||||||
|
une puce par adresse retenue, pour VOIR ce qui sera ajouté ; les saisies
|
||||||
|
invalides sont barrées en rouge. */
|
||||||
|
.cc-apercu {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
margin-top: 8px;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
.cc-apercu-intro { color: var(--text-muted); }
|
||||||
|
.cc-apercu-vide { color: var(--text-faint); font-style: italic; }
|
||||||
|
.cc-apercu-chip {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 2px 8px;
|
||||||
|
border-radius: 10px;
|
||||||
|
background: var(--accent-soft);
|
||||||
|
color: var(--accent);
|
||||||
|
border: 1px solid color-mix(in srgb, var(--accent) 30%, transparent);
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
.cc-apercu-chip-invalide {
|
||||||
|
background: var(--danger-soft);
|
||||||
|
color: var(--danger);
|
||||||
|
border-color: color-mix(in srgb, var(--danger) 35%, transparent);
|
||||||
|
text-decoration: line-through;
|
||||||
|
}
|
||||||
.admin-team-table {
|
.admin-team-table {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
@@ -4253,18 +4443,18 @@ html.theme-dark {
|
|||||||
/* Carte entière : couleur de fond + barre gauche épaisse pour absence */
|
/* Carte entière : couleur de fond + barre gauche épaisse pour absence */
|
||||||
.card.absence-cat-maladie {
|
.card.absence-cat-maladie {
|
||||||
border-left: 4px solid var(--c-maladie);
|
border-left: 4px solid var(--c-maladie);
|
||||||
background: linear-gradient(to bottom, var(--c-maladie-soft) 0%, var(--bg-elevated) 40%);
|
background: linear-gradient(to bottom, var(--c-maladie-soft) 0%, var(--iv-canvas) 40%);
|
||||||
}
|
}
|
||||||
html.theme-dark .card.absence-cat-maladie {
|
html.theme-dark .card.absence-cat-maladie {
|
||||||
background: linear-gradient(to bottom, rgba(67, 56, 202, 0.12) 0%, var(--bg-elevated) 40%);
|
background: linear-gradient(to bottom, rgba(67, 56, 202, 0.12) 0%, var(--iv-canvas) 40%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.card.absence-cat-conge {
|
.card.absence-cat-conge {
|
||||||
border-left: 4px solid var(--c-conge);
|
border-left: 4px solid var(--c-conge);
|
||||||
background: linear-gradient(to bottom, var(--c-conge-soft) 0%, var(--bg-elevated) 40%);
|
background: linear-gradient(to bottom, var(--c-conge-soft) 0%, var(--iv-canvas) 40%);
|
||||||
}
|
}
|
||||||
html.theme-dark .card.absence-cat-conge {
|
html.theme-dark .card.absence-cat-conge {
|
||||||
background: linear-gradient(to bottom, rgba(6, 182, 212, 0.12) 0%, var(--bg-elevated) 40%);
|
background: linear-gradient(to bottom, rgba(6, 182, 212, 0.12) 0%, var(--iv-canvas) 40%);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Pompier — on reprend le style existant mais on accentue le border-left */
|
/* Pompier — on reprend le style existant mais on accentue le border-left */
|
||||||
@@ -4346,12 +4536,22 @@ html.theme-dark .card.absence-cat-conge {
|
|||||||
/* Carte entière : bordure gauche cyan + fond dégradé */
|
/* Carte entière : bordure gauche cyan + fond dégradé */
|
||||||
.card.absence-cat-recurring {
|
.card.absence-cat-recurring {
|
||||||
border-left: 4px solid var(--c-conge);
|
border-left: 4px solid var(--c-conge);
|
||||||
background: linear-gradient(to bottom, var(--c-conge-soft) 0%, var(--bg-elevated) 40%);
|
background: linear-gradient(to bottom, var(--c-conge-soft) 0%, var(--iv-canvas) 40%);
|
||||||
}
|
}
|
||||||
html.theme-dark .card.absence-cat-recurring {
|
html.theme-dark .card.absence-cat-recurring {
|
||||||
background: linear-gradient(to bottom, rgba(6, 182, 212, 0.12) 0%, var(--bg-elevated) 40%);
|
background: linear-gradient(to bottom, rgba(6, 182, 212, 0.12) 0%, var(--iv-canvas) 40%);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* v2026.5.46 — vue horizontale : en échelle exacte, la carte d'un tech
|
||||||
|
absent est HAUTE (elle s'étire sur toute la frise) alors que son contenu est
|
||||||
|
court. Le dégradé « couleur → neutre à 40 % » (pensé pour les cartes courtes
|
||||||
|
de la vue classique) laissait tout le bas de la carte en neutre. En vue
|
||||||
|
horizontale on remplit donc TOUTE la carte de la couleur douce (theme-aware
|
||||||
|
via --c-*-soft) ; la vue classique garde le dégradé. */
|
||||||
|
html.view-horizontal .card.absence-cat-maladie { background: var(--c-maladie-soft); }
|
||||||
|
html.view-horizontal .card.absence-cat-conge,
|
||||||
|
html.view-horizontal .card.absence-cat-recurring { background: var(--c-conge-soft); }
|
||||||
|
|
||||||
/* Message "Absent le vendredi" (ou autre récurrence) en cyan.
|
/* Message "Absent le vendredi" (ou autre récurrence) en cyan.
|
||||||
Règle UNIQUE — les bordures haut/bas (qui venaient d'un 2e bloc plus
|
Règle UNIQUE — les bordures haut/bas (qui venaient d'un 2e bloc plus
|
||||||
haut, v4.1.20) sont repliées ici ; le bloc dupliqué a été retiré. */
|
haut, v4.1.20) sont repliées ici ; le bloc dupliqué a été retiré. */
|
||||||
@@ -4521,6 +4721,14 @@ html.view-horizontal .card-header {
|
|||||||
padding: 6px 10px !important;
|
padding: 6px 10px !important;
|
||||||
gap: 3px !important;
|
gap: 3px !important;
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
|
/* v2026.5.47 — le fond de la zone nom remplit TOUTE la hauteur de la
|
||||||
|
ligne (nom toujours centré via justify-content:center). En mode normal le
|
||||||
|
parent .card est déjà align-items:stretch, mais en mode heure exacte il
|
||||||
|
passe à align-items:center (pour centrer les bulles du corps), ce qui
|
||||||
|
laissait le header en bandeau fixe plus court que la ligne, avec du fond de
|
||||||
|
carte visible au-dessus/en dessous. align-self:stretch force le header à
|
||||||
|
s'étirer dans les deux modes ; le corps garde son propre centrage. */
|
||||||
|
align-self: stretch !important;
|
||||||
}
|
}
|
||||||
/* v2026.5.40 : nom du tech complet (jusqu'à 3 lignes). Si vraiment
|
/* v2026.5.40 : nom du tech complet (jusqu'à 3 lignes). Si vraiment
|
||||||
trop long, .card-tech-name-tight est appliqué dynamiquement par le JS
|
trop long, .card-tech-name-tight est appliqué dynamiquement par le JS
|
||||||
@@ -5199,23 +5407,29 @@ html.view-horizontal .horizontal-sidebar .date-custom {
|
|||||||
justify-content: center !important;
|
justify-content: center !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 13. Barre de rafraîchissement en vue horizontale : overlay par-dessus
|
/* 13. Barre de rafraîchissement en vue horizontale.
|
||||||
user-badge + titre (zone haut de sidebar). */
|
v2026.5.47 — la barre doit RESTER dans la barre de gauche,
|
||||||
|
AU-DESSUS des initiales — pas dans le contenu où elle couvrait
|
||||||
|
les heures du mode « échelle exacte ». Elle repasse donc en overlay sur la
|
||||||
|
SIDEBAR (left:0, width = --sidebar-w) ; top suit --stack-top (sous la
|
||||||
|
banderole de session/reco si présente). Pour NE PAS recouvrir les
|
||||||
|
initiales, le contenu de la sidebar est poussé vers le bas pendant le
|
||||||
|
rafraîchissement (classe .planif-refreshing sur <html>, cf. showProgressBar). */
|
||||||
html.view-horizontal #progress-bar {
|
html.view-horizontal #progress-bar {
|
||||||
position: fixed !important;
|
position: fixed !important;
|
||||||
top: 0 !important;
|
top: var(--stack-top, 0px) !important;
|
||||||
left: 0 !important;
|
left: 0 !important;
|
||||||
width: 200px !important; /* largeur de la sidebar */
|
width: var(--sidebar-w, 200px) !important;
|
||||||
|
right: auto !important;
|
||||||
z-index: 9999 !important;
|
z-index: 9999 !important;
|
||||||
border-radius: 0 !important;
|
border-radius: 0 !important;
|
||||||
margin: 0 !important;
|
margin: 0 !important;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
/* Sur breakpoint étroit (sidebar 170px) */
|
/* Réserve la hauteur de la barre en haut de la sidebar pendant un
|
||||||
@media (max-width: 1400px) {
|
rafraîchissement → les initiales / le titre passent SOUS la barre. */
|
||||||
html.view-horizontal #progress-bar {
|
html.planif-refreshing.view-horizontal .horizontal-sidebar {
|
||||||
width: 170px !important;
|
padding-top: 34px !important;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* v2026.5.40 : banderole "En pompier du..." en vue HORIZONTALE
|
/* v2026.5.40 : banderole "En pompier du..." en vue HORIZONTALE
|
||||||
@@ -5323,10 +5537,14 @@ html:not(.show-iv-gaps) .gap-placeholder:not(.gap-placeholder-full) {
|
|||||||
margin: 6px 0;
|
margin: 6px 0;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: var(--text-faint);
|
color: var(--text-muted);
|
||||||
border: 1px dashed var(--border);
|
border: 1px dashed var(--border-strong);
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
background: transparent;
|
/* v2026.5.49 — plage libre VISIBLE : sur le fond de retrait des cartes
|
||||||
|
(--iv-canvas), un rectangle transparent au contour pâle se voyait à
|
||||||
|
peine. Voile clair + contour tireté = « emplacement disponible », sans
|
||||||
|
atteindre la surface pleine d'une intervention. */
|
||||||
|
background: var(--iv-libre);
|
||||||
cursor: help;
|
cursor: help;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
transition: background 0.12s ease, border-color 0.12s ease, color 0.12s ease;
|
transition: background 0.12s ease, border-color 0.12s ease, color 0.12s ease;
|
||||||
@@ -5395,6 +5613,21 @@ html.view-horizontal .gap-placeholder:not(.gap-placeholder-mini) {
|
|||||||
z-index: 6;
|
z-index: 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* v2026.5.49 — survol d'une PAUSE : on fane (désature + assombrit) les
|
||||||
|
interventions de la FRISE (.timeline-slot) uniquement, pour que la plage
|
||||||
|
libre survolée — qui garde sa couleur vive et son contour accent — ressorte,
|
||||||
|
même collée à une installation bleue (les deux se confondaient). La frise
|
||||||
|
existe dans les deux vues (classique et horizontale), donc l'effet vaut pour
|
||||||
|
les deux. On NE fane PAS les cartes d'intervention en dessous (.iv-mini-card,
|
||||||
|
.intervention-v2) : seule la timeline s'assombrit. La pause
|
||||||
|
elle-même (.timeline-hole / .gap-placeholder) n'est jamais ciblée. .gap-dimming
|
||||||
|
est posée par highlightGap sur la carte (classique) ou la ligne (horizontal). */
|
||||||
|
.gap-dimming .timeline-slot {
|
||||||
|
filter: saturate(0.3) brightness(0.82);
|
||||||
|
opacity: 0.45;
|
||||||
|
transition: filter 0.12s ease, opacity 0.12s ease;
|
||||||
|
}
|
||||||
|
|
||||||
/* : placeholder "—" sous le séparateur d'une période vide, dans
|
/* : placeholder "—" sous le séparateur d'une période vide, dans
|
||||||
la vue classique. Reprend le même design que .iv-mini-block-empty
|
la vue classique. Reprend le même design que .iv-mini-block-empty
|
||||||
en vue horizontale : encadré dashed, "—" centré, hauteur fixe. */
|
en vue horizontale : encadré dashed, "—" centré, hauteur fixe. */
|
||||||
@@ -5406,10 +5639,11 @@ html.view-horizontal .gap-placeholder:not(.gap-placeholder-mini) {
|
|||||||
margin: 6px 0;
|
margin: 6px 0;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: var(--text-faint);
|
color: var(--text-muted);
|
||||||
border: 1px dashed var(--border);
|
border: 1px dashed var(--border-strong);
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
background: transparent;
|
/* v2026.5.49 — même éclaircissement que .gap-placeholder. */
|
||||||
|
background: var(--iv-libre);
|
||||||
user-select: none;
|
user-select: none;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
@@ -5695,6 +5929,9 @@ html.view-horizontal .iv-mini-cards {
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: background 0.1s, border-color 0.1s, box-shadow 0.1s;
|
transition: background 0.1s, border-color 0.1s, box-shadow 0.1s;
|
||||||
|
/* v2026.5.49 — même relief qu'en vue classique : la mini-carte est
|
||||||
|
posée sur le corps de carte, qui est en retrait. */
|
||||||
|
box-shadow: var(--iv-relief);
|
||||||
}
|
}
|
||||||
.iv-mini-card:hover {
|
.iv-mini-card:hover {
|
||||||
background: var(--bg-hover);
|
background: var(--bg-hover);
|
||||||
@@ -5912,10 +6149,11 @@ html.view-horizontal .pinned-popups-dock {
|
|||||||
min-height: 36px;
|
min-height: 36px;
|
||||||
font-size: calc(14px * var(--text-scale));
|
font-size: calc(14px * var(--text-scale));
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: var(--text-faint);
|
color: var(--text-muted);
|
||||||
border: 1px dashed var(--border);
|
border: 1px dashed var(--border-strong);
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
background: transparent;
|
/* v2026.5.49 — même éclaircissement que .gap-placeholder. */
|
||||||
|
background: var(--iv-libre);
|
||||||
user-select: none;
|
user-select: none;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
@@ -7006,17 +7244,103 @@ html.view-horizontal .iv-exact-lane + .iv-exact-lane {
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
background: transparent;
|
/* v2026.5.49 — le créneau libre se VOIT sans qu'il faille le survoler :
|
||||||
|
voile clair sur la bande en retrait, contour tireté discret. Même langage
|
||||||
|
que les pauses de la vue classique (clair + tireté = disponible). */
|
||||||
|
background: var(--iv-libre);
|
||||||
|
border: 1px dashed var(--border-strong);
|
||||||
|
border-radius: 4px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
z-index: 0;
|
z-index: 0;
|
||||||
}
|
}
|
||||||
.iv-exact-hole:hover,
|
.iv-exact-hole:hover,
|
||||||
.iv-exact-hole.highlight {
|
.iv-exact-hole.highlight {
|
||||||
background: rgba(127, 127, 127, 0.12);
|
/* v2026.5.49 — le survol reste plus marqué que l'état de repos, qui
|
||||||
|
n'est plus transparent : teinte d'accent au lieu d'un gris. */
|
||||||
|
background: var(--accent-soft);
|
||||||
outline: 1px dashed var(--accent, #3b82f6);
|
outline: 1px dashed var(--accent, #3b82f6);
|
||||||
outline-offset: -2px;
|
outline-offset: -2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* v2026.5.47 — surbrillance de survol : la ZONE (1 h par défaut) qu'un clic
|
||||||
|
droit poserait en rendez-vous/absence, calée sous la souris à l'heure snappée
|
||||||
|
(créneau libre, mode heure exacte). Plus marquée que le survol gris du trou,
|
||||||
|
pour qu'on VOIE clairement la zone visée. Purement visuelle. */
|
||||||
|
.iv-exact-selpreview {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border-radius: 4px;
|
||||||
|
border: 2px solid var(--accent, #3b82f6);
|
||||||
|
background: rgba(94, 168, 232, 0.28);
|
||||||
|
background: color-mix(in srgb, var(--accent, #3b82f6) 28%, transparent);
|
||||||
|
}
|
||||||
|
/* v2026.5.47 — bulle « temps disponible » FIXE en haut de la bande (elle ne
|
||||||
|
suit PLUS la souris) : plage libre du créneau survolé, ou avertissement rouge
|
||||||
|
si erreur. Seule la zone de sélection (.iv-exact-selpreview) suit le curseur. */
|
||||||
|
.iv-exact-selinfo {
|
||||||
|
position: absolute;
|
||||||
|
top: 3px;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
white-space: nowrap;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 1.25;
|
||||||
|
font-size: calc(11px * var(--text-scale, 1));
|
||||||
|
padding: 3px 10px;
|
||||||
|
border-radius: 6px;
|
||||||
|
background: var(--bg-elevated, #21242b);
|
||||||
|
color: var(--text, #e8eaed);
|
||||||
|
border: 1px solid var(--accent, #3b82f6);
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.35);
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 3;
|
||||||
|
}
|
||||||
|
.iv-exact-selinfo-main { font-weight: 700; }
|
||||||
|
.iv-exact-selinfo-sub { font-size: 0.9em; opacity: 0.8; font-weight: 500; }
|
||||||
|
.iv-exact-selinfo.danger .iv-exact-selinfo-sub { opacity: 0.95; }
|
||||||
|
/* v2026.5.47 — heure choisie (début–fin) affichée DANS le rectangle de
|
||||||
|
sélection mobile ; suit le curseur, lisible sur le fond translucide.
|
||||||
|
v2026.5.47 — placée EN BAS du rectangle (la bulle fixe est en haut) → la
|
||||||
|
bulle ne cache jamais l'heure quand la souris passe dessous. */
|
||||||
|
.iv-exact-selpreview-hour {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 3px;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
white-space: nowrap;
|
||||||
|
font-size: calc(10.5px * var(--text-scale, 1));
|
||||||
|
font-weight: 700;
|
||||||
|
color: #ffffff;
|
||||||
|
pointer-events: none;
|
||||||
|
/* v2026.5.49 — la zone est désormais bornée au prochain rendez-vous : sur
|
||||||
|
un créneau de 30 min l'heure déborde du rectangle. Pastille opaque (au lieu
|
||||||
|
d'un simple texte ombré) pour qu'elle reste lisible hors de la zone, sur
|
||||||
|
les hachures d'un créneau libre comme sur le fond de la bande. */
|
||||||
|
padding: 1px 5px;
|
||||||
|
border-radius: 5px;
|
||||||
|
background: var(--accent, #3b82f6);
|
||||||
|
}
|
||||||
|
.iv-exact-selpreview.danger .iv-exact-selpreview-hour {
|
||||||
|
background: #b03030;
|
||||||
|
}
|
||||||
|
/* v2026.5.47 — un rendez-vous en ERREUR (début == fin) tombe dans la zone
|
||||||
|
qu'on créerait : surbrillance ET bulle passent en rouge (le clic droit est
|
||||||
|
par ailleurs bloqué, cf. disabledReason). */
|
||||||
|
.iv-exact-selpreview.danger {
|
||||||
|
border-color: #b03030;
|
||||||
|
background: rgba(176, 48, 48, 0.30);
|
||||||
|
background: color-mix(in srgb, #b03030 32%, transparent);
|
||||||
|
}
|
||||||
|
.iv-exact-selinfo.danger {
|
||||||
|
background: #b03030;
|
||||||
|
color: #ffffff;
|
||||||
|
border-color: #7a1f1f;
|
||||||
|
}
|
||||||
|
|
||||||
/* ── Les cartes posées (héritent de .iv-mini-card : anatomie, conflits
|
/* ── Les cartes posées (héritent de .iv-mini-card : anatomie, conflits
|
||||||
rouges !important, liseré clos/résolu, tooltips, reschedule) ────────── */
|
rouges !important, liseré clos/résolu, tooltips, reschedule) ────────── */
|
||||||
html.view-horizontal .iv-exact-card {
|
html.view-horizontal .iv-exact-card {
|
||||||
@@ -7035,7 +7359,11 @@ html.view-horizontal .iv-exact-card {
|
|||||||
height: auto !important;
|
height: auto !important;
|
||||||
pointer-events: auto;
|
pointer-events: auto;
|
||||||
flex: none;
|
flex: none;
|
||||||
min-width: 0;
|
/* v2026.5.47 — largeur MINIMALE visible : une intervention très courte
|
||||||
|
(1-5 min) ou à durée nulle (10:00→10:00) a une largeur proportionnelle
|
||||||
|
quasi nulle → elle disparaissait. Ce plancher la garde visible (très fine),
|
||||||
|
sans élargir les bulles normales (plus larges que ce plancher). */
|
||||||
|
min-width: 6px;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
container-type: inline-size;
|
container-type: inline-size;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
@@ -7155,10 +7483,12 @@ html.view-horizontal .iv-exact-card .iv-mini-card-text-mini .iv-mini-mini-ville
|
|||||||
html.view-horizontal.horizontal-exact .exact-hours-ruler {
|
html.view-horizontal.horizontal-exact .exact-hours-ruler {
|
||||||
display: block;
|
display: block;
|
||||||
position: sticky;
|
position: sticky;
|
||||||
/* v2026.5.46 — top:0 : en vue horizontale la barre du haut est
|
/* v2026.5.47 — top suit --stack-top : la règle des heures reste collée en
|
||||||
masquée, donc --stack-top (calé sur elle) envoyait la règle hors écran.
|
haut au scroll, ET passe SOUS la banderole de session/reconnexion quand il y
|
||||||
La sidebar utilise déjà top:0 dans la même structure et tient. */
|
en a une (au lieu de disparaître derrière), 0 sinon. (--stack-top = topbar
|
||||||
top: 0;
|
masquée en horizontal + hauteur des banderoles visibles ; corrigé depuis
|
||||||
|
des ajustements précédents, il ne sort plus la règle de l'écran.) */
|
||||||
|
top: var(--stack-top, 0px);
|
||||||
z-index: 20;
|
z-index: 20;
|
||||||
background: var(--bg);
|
background: var(--bg);
|
||||||
/* v2026.5.46 — l'alignement n'est PLUS un calcul théorique (faux au
|
/* v2026.5.46 — l'alignement n'est PLUS un calcul théorique (faux au
|
||||||
@@ -7205,3 +7535,28 @@ html.view-horizontal.horizontal-exact .cards {
|
|||||||
.reschedule-timeline-mark.reschedule-exact-mark {
|
.reschedule-timeline-mark.reschedule-exact-mark {
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ── Puces de variables du modèle d'email (v2026.5.48) ─────────────── */
|
||||||
|
/* Interactives : grossissent au survol, s'enfoncent au clic. Le style de base vit ici (plus d'inline) pour que :hover et
|
||||||
|
:active puissent surcharger la bordure. */
|
||||||
|
.admin-var-chip {
|
||||||
|
font-family: monospace;
|
||||||
|
font-size: 12px;
|
||||||
|
padding: 2px 8px;
|
||||||
|
align-self: flex-start;
|
||||||
|
border: 1px solid var(--border, #888);
|
||||||
|
border-radius: 6px;
|
||||||
|
background: transparent;
|
||||||
|
color: inherit;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: transform 0.09s ease, border-color 0.09s ease,
|
||||||
|
background-color 0.09s ease;
|
||||||
|
}
|
||||||
|
.admin-var-chip:hover {
|
||||||
|
transform: scale(1.07);
|
||||||
|
border-color: var(--accent, #4a90d9);
|
||||||
|
background: rgba(127, 127, 127, 0.12);
|
||||||
|
}
|
||||||
|
.admin-var-chip:active {
|
||||||
|
transform: scale(0.92);
|
||||||
|
}
|
||||||
|
|||||||
+18
-13
@@ -2,10 +2,10 @@
|
|||||||
<!--
|
<!--
|
||||||
Planification — Extension navigateur EasyVista (Canton de Vaud / DGNSI)
|
Planification — Extension navigateur EasyVista (Canton de Vaud / DGNSI)
|
||||||
|
|
||||||
Copyright (c) 2026 FroSteel
|
Copyright (c) 2026 Quentin
|
||||||
Licensed under the MIT License — see LICENSE file in the project root.
|
Licensed under the MIT License — see LICENSE file in the project root.
|
||||||
|
|
||||||
@author FroSteel
|
@author Quentin
|
||||||
@repository https://gitea.netaplaid.ch/FroSteel/Planification
|
@repository https://gitea.netaplaid.ch/FroSteel/Planification
|
||||||
-->
|
-->
|
||||||
<html lang="fr">
|
<html lang="fr">
|
||||||
@@ -118,17 +118,6 @@
|
|||||||
|
|
||||||
<main id="main">
|
<main id="main">
|
||||||
<div id="error-box" class="error-box hidden"></div>
|
<div id="error-box" class="error-box hidden"></div>
|
||||||
<div id="session-needed" class="session-needed hidden">
|
|
||||||
<h2>Session EasyVista expirée</h2>
|
|
||||||
<p>Reconnectez-vous à EasyVista pour continuer.</p>
|
|
||||||
<button id="open-ev-btn" class="btn btn-primary">Ouvrir EasyVista</button>
|
|
||||||
</div>
|
|
||||||
<div id="ev-unreachable" class="session-needed hidden">
|
|
||||||
<h2>EasyVista est inaccessible pour le moment.</h2>
|
|
||||||
<p>Réessayez dans quelques instants, ou ouvrez EasyVista directement.</p>
|
|
||||||
<button id="open-ev-btn-2" class="btn btn-primary">Ouvrir EasyVista</button>
|
|
||||||
<button id="retry-btn" class="btn btn-subtle">Réessayer</button>
|
|
||||||
</div>
|
|
||||||
<!-- v2026.5.46 — ligne collante (sticky) EN PREMIER : stats + barre de
|
<!-- v2026.5.46 — ligne collante (sticky) EN PREMIER : stats + barre de
|
||||||
recherche sur la même hauteur, toujours visibles au scroll. En vue
|
recherche sur la même hauteur, toujours visibles au scroll. En vue
|
||||||
horizontale, les deux enfants sont relocalisés dans la sidebar
|
horizontale, les deux enfants sont relocalisés dans la sidebar
|
||||||
@@ -160,6 +149,22 @@
|
|||||||
<!-- v2026.5.46 — le « Chargement… » vit DANS la zone des cartes
|
<!-- v2026.5.46 — le « Chargement… » vit DANS la zone des cartes
|
||||||
(sous la ligne stats+recherche), jamais en haut de page. -->
|
(sous la ligne stats+recherche), jamais en haut de page. -->
|
||||||
<div id="loading" class="loading">Chargement…</div>
|
<div id="loading" class="loading">Chargement…</div>
|
||||||
|
<!-- v2026.5.49 — les messages « session expirée » / « EV inaccessible »
|
||||||
|
CENTRÉS vivent DANS la zone de contenu (sous la barre de recherche, à
|
||||||
|
la place des cartes), pas en haut de #main : sinon ils s'affichaient
|
||||||
|
au-dessus de la ligne stats+recherche. showSessionNeeded/showEvUnreachable
|
||||||
|
vident #cards et affichent le message ici. -->
|
||||||
|
<div id="session-needed" class="session-needed hidden">
|
||||||
|
<h2>Session EasyVista expirée</h2>
|
||||||
|
<p>Reconnectez-vous à EasyVista pour continuer.</p>
|
||||||
|
<button id="open-ev-btn" class="btn btn-primary">Ouvrir EasyVista</button>
|
||||||
|
</div>
|
||||||
|
<div id="ev-unreachable" class="session-needed hidden">
|
||||||
|
<h2>EasyVista est inaccessible pour le moment.</h2>
|
||||||
|
<p>Réessayez dans quelques instants, ou ouvrez EasyVista directement.</p>
|
||||||
|
<button id="open-ev-btn-2" class="btn btn-primary">Ouvrir EasyVista</button>
|
||||||
|
<button id="retry-btn" class="btn btn-subtle">Réessayer</button>
|
||||||
|
</div>
|
||||||
<div id="cards" class="cards"></div>
|
<div id="cards" class="cards"></div>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
|
|||||||
+2696
-539
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user