Public Access
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:
+38
-12
@@ -30,7 +30,7 @@
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$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
|
||||
# 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.
|
||||
@@ -155,18 +155,44 @@ function Read-Index([string]$share) {
|
||||
|
||||
function Update-Index([string]$share, [string]$date, [long]$savedAt) {
|
||||
$idx = Join-Path $share $INDEX_NAME
|
||||
$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 {}
|
||||
# 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 = @{}
|
||||
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) {
|
||||
|
||||
@@ -160,6 +160,35 @@ $ni.Icon = Get-TrayIcon
|
||||
$ni.Text = 'Planification - synchronisation active'
|
||||
$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
|
||||
$miLog = $menu.Items.Add('Voir le journal de synchronisation')
|
||||
$miLog.add_Click({ Show-LogWindow })
|
||||
|
||||
Reference in New Issue
Block a user