Compare commits

..
7 changed files with 1271 additions and 567 deletions
+35
View File
@@ -9,6 +9,41 @@
--- ---
## 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 ## 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. > 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.
+10 -2
View File
@@ -9,7 +9,7 @@ Extension Chrome / Firefox pour visualiser de manière claire et rapide le plann
- **Auteur** : FroSteel (FRS), Technicien DGNSI — Canton de Vaud - **Auteur** : FroSteel (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.48`](https://gitea.netaplaid.ch/FroSteel/Planification/releases/tag/v2026.5.48) (latest) - **Version actuelle** : [`v2026.5.49`](https://gitea.netaplaid.ch/FroSteel/Planification/releases/tag/v2026.5.49) (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)
@@ -121,7 +121,15 @@ Le numéro de **majeure** n'est **pas** un mois et **pas** un chiffre lié au ca
## Versions notables ## Versions notables
### `v2026.5.48` (latest, 24 juillet 2026) — Notification par email des déplacements, onglet Email, fiches réservation fiables entre postes ### `v2026.5.49` (latest, 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 - 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 - Adresses des techniciens depuis l'annuaire EasyVista, noms tronqués complétés, domaine configurable
+5
View File
@@ -2,6 +2,11 @@
"addons": { "addons": {
"[email protected]": { "[email protected]": {
"updates": [ "updates": [
{
"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", "version": "2026.5.48",
"update_link": "https://gitea.netaplaid.ch/FroSteel/Planification/releases/download/v2026.5.48/planification-v2026.5.48-firefox.xpi", "update_link": "https://gitea.netaplaid.ch/FroSteel/Planification/releases/download/v2026.5.48/planification-v2026.5.48-firefox.xpi",
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"manifest_version": 3, "manifest_version": 3,
"name": "Planification", "name": "Planification",
"version": "2026.5.48", "version": "2026.5.49",
"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 FroSteel — 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": [
+216 -28
View File
@@ -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);
} }
/* ========================================================================== /* ==========================================================================
@@ -1204,7 +1230,11 @@ html.view-horizontal .session-needed {
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;
} }
@@ -1219,6 +1249,40 @@ html.view-horizontal .session-needed {
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;
@@ -1276,6 +1340,41 @@ html.view-horizontal .session-needed {
.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 {
@@ -1606,12 +1705,18 @@ html.view-horizontal .iv-exact-card.iv-zero-duration {
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) */
@@ -1637,23 +1742,25 @@ html.view-horizontal .iv-exact-card.iv-zero-duration {
/* : 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);
@@ -3239,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;
@@ -4294,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 */
@@ -4387,10 +4536,10 @@ 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 /* v2026.5.46 — vue horizontale : en échelle exacte, la carte d'un tech
@@ -5259,7 +5408,7 @@ html.view-horizontal .horizontal-sidebar .date-custom {
} }
/* 13. Barre de rafraîchissement en vue horizontale. /* 13. Barre de rafraîchissement en vue horizontale.
v2026.5.47 — FroSteel : la barre doit RESTER dans la barre de gauche, v2026.5.47 — la barre doit RESTER dans la barre de gauche,
AU-DESSUS des initiales — pas dans le contenu où elle couvrait AU-DESSUS des initiales — pas dans le contenu où elle couvrait
les heures du mode « échelle exacte ». Elle repasse donc en overlay sur la 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 SIDEBAR (left:0, width = --sidebar-w) ; top suit --stack-top (sous la
@@ -5388,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;
@@ -5460,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. */
@@ -5471,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;
} }
@@ -5760,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);
@@ -5977,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;
} }
@@ -7071,13 +7244,20 @@ 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;
} }
@@ -7135,8 +7315,17 @@ html.view-horizontal .iv-exact-lane + .iv-exact-lane {
font-size: calc(10.5px * var(--text-scale, 1)); font-size: calc(10.5px * var(--text-scale, 1));
font-weight: 700; font-weight: 700;
color: #ffffff; color: #ffffff;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.75);
pointer-events: none; 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 /* 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 qu'on créerait : surbrillance ET bulle passent en rouge (le clic droit est
@@ -7348,8 +7537,7 @@ html.view-horizontal.horizontal-exact .cards {
} }
/* ── Puces de variables du modèle d'email (v2026.5.48) ─────────────── */ /* ── Puces de variables du modèle d'email (v2026.5.48) ─────────────── */
/* Interactives : grossissent au survol, s'enfoncent au clic (demande /* Interactives : grossissent au survol, s'enfoncent au clic. Le style de base vit ici (plus d'inline) pour que :hover et
FroSteel). Le style de base vit ici (plus d'inline) pour que :hover et
:active puissent surcharger la bordure. */ :active puissent surcharger la bordure. */
.admin-var-chip { .admin-var-chip {
font-family: monospace; font-family: monospace;
+16 -11
View File
@@ -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>
+988 -525
View File
File diff suppressed because it is too large Load Diff