forked from FroSteel/Planification
v2026.5.47 — Vue « échelle de temps exacte » : aide à la saisie, erreurs mises en évidence, corrections de fiabilité
- Retour visuel au survol d'un créneau libre (zone surlignée + heure choisie qui suit la souris ; bulle fixe plage libre + durée disponible, jamais par-dessus un rendez-vous). - Rendez-vous en erreur (début = fin) affiché en rouge et visible en échelle exacte ; avertissement + blocage à la création par-dessus. Interventions courtes visibles. - Zone du nom du technicien pleine hauteur ; barre des heures collée sous la banderole. - Fiabilité : navigation rapide entre dates, technicien retiré, deadlock de synchro du dossier, jour lu depuis le dossier d'emblée, doublon d'absence, réservations multiples le même jour, barre de progression et message de reconnexion. - Synchro : bouton « Tester la communication », panneau réorganisé, script du poste 2026.1.8 (verrou d'index, icône persistante).
This commit is contained in:
@@ -9,6 +9,36 @@
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## 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.
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ Extension Chrome / Firefox pour visualiser de manière claire et rapide le plann
|
|||||||
- **Auteur** : Quentin Rouiller (QRO), Technicien DGNSI — Canton de Vaud
|
- **Auteur** : Quentin Rouiller (QRO), 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.47`](https://gitea.netaplaid.ch/FroSteel/Planification/releases/tag/v2026.5.47) (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)
|
||||||
|
|||||||
@@ -2,10 +2,15 @@
|
|||||||
"addons": {
|
"addons": {
|
||||||
"[email protected]": {
|
"[email protected]": {
|
||||||
"updates": [
|
"updates": [
|
||||||
|
{
|
||||||
|
"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:e97883102af2f00fd468c9be62deac6c1d2546ef3e25afe90d79a390bbd1f0bb"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"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",
|
||||||
|
|||||||
@@ -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,6 +155,29 @@ 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
|
||||||
|
# v2026.1.8 - verrou DEDIE a l'index. Plusieurs hotes (plusieurs onglets
|
||||||
|
# Planification ouverts, ou plusieurs postes) font un read-modify-write
|
||||||
|
# concurrent sur _index.json ; sans verrou, deux Move-Item se recouvrent et la
|
||||||
|
# maj d'un hote est perdue (lost update) -> l'index prend du retard sur les
|
||||||
|
# fichiers-jour -> conflits CAS a repetition ("refusion" en boucle). On
|
||||||
|
# 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 = @{}
|
$map = @{}
|
||||||
if (Test-Path -LiteralPath $idx) {
|
if (Test-Path -LiteralPath $idx) {
|
||||||
try {
|
try {
|
||||||
@@ -167,6 +190,9 @@ function Update-Index([string]$share, [string]$date, [long]$savedAt) {
|
|||||||
[System.IO.File]::WriteAllText($tmp, ($map | ConvertTo-Json -Compress -Depth 5), $Utf8NoBom)
|
[System.IO.File]::WriteAllText($tmp, ($map | ConvertTo-Json -Compress -Depth 5), $Utf8NoBom)
|
||||||
Move-Item -LiteralPath $tmp -Destination $idx -Force
|
Move-Item -LiteralPath $tmp -Destination $idx -Force
|
||||||
Write-Activity 'DEBUG' "Index du dossier mis a jour pour le $(Format-DateFR $date)"
|
Write-Activity 'DEBUG' "Index du dossier mis a jour pour le $(Format-DateFR $date)"
|
||||||
|
} finally {
|
||||||
|
Remove-Item -LiteralPath $lock -Force -ErrorAction SilentlyContinue
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function Get-SavedAt([string]$share, [string]$date, [string]$file) {
|
function Get-SavedAt([string]$share, [string]$date, [string]$file) {
|
||||||
|
|||||||
@@ -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 })
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"manifest_version": 3,
|
"manifest_version": 3,
|
||||||
"name": "Planification",
|
"name": "Planification",
|
||||||
"version": "2026.5.46",
|
"version": "2026.5.47",
|
||||||
"description": "Vue claire et rapide du planning des techniciens EasyVista. Développé par Quentin Rouiller — DGNSI, Canton de Vaud.",
|
"description": "Vue claire et rapide du planning des techniciens EasyVista. Développé par Quentin Rouiller — 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": [
|
||||||
|
|||||||
+155
-14
@@ -1130,6 +1130,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);
|
||||||
@@ -1549,6 +1561,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)
|
||||||
========================================================================== */
|
========================================================================== */
|
||||||
@@ -4352,6 +4393,16 @@ 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(--bg-elevated) 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 +4572,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 +5258,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 — Quentin : 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
|
||||||
@@ -7017,6 +7082,76 @@ html.view-horizontal .iv-exact-lane + .iv-exact-lane {
|
|||||||
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;
|
||||||
|
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.75);
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
/* 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 +7170,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 +7294,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
|
||||||
|
|||||||
+609
-153
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user