forked from FroSteel/Planification
197 lines
7.3 KiB
PowerShell
197 lines
7.3 KiB
PowerShell
# Planification - icone barre des taches (best-effort, optionnel) // 2026.1.4 - QRO
|
|
# Developpe par Quentin Rouiller (QRO) - DGNSI, Canton de Vaud.
|
|
# Licence MIT - voir le fichier LICENSE.
|
|
#
|
|
# Indique que le helper de sync est installe. Clic / menu -> fenetre du journal
|
|
# (aspect application : journal colore par niveau, auto-rafraichi, bouton
|
|
# "Tout afficher"). Lance par tray.vbs (fenetre masquee), au login.
|
|
|
|
$ErrorActionPreference = 'SilentlyContinue'
|
|
|
|
# Instance unique.
|
|
$mutex = New-Object System.Threading.Mutex($false, 'Local\PlanificationTraySingleton')
|
|
if (-not $mutex.WaitOne(0)) { exit }
|
|
|
|
Add-Type -AssemblyName System.Windows.Forms
|
|
Add-Type -AssemblyName System.Drawing
|
|
|
|
# tray.ps1 vit dans <install>\bin -> racine = parent ; assets et log a la racine.
|
|
$root = if ($PSScriptRoot) { Split-Path -Parent $PSScriptRoot } else { Join-Path $env:LOCALAPPDATA 'Planification' }
|
|
$logFile = Join-Path $root 'activity.log'
|
|
$iconPng = Join-Path (Join-Path $root 'assets') 'icon.png'
|
|
|
|
function Get-TrayIcon {
|
|
try {
|
|
if (Test-Path -LiteralPath $iconPng) {
|
|
$bmp = New-Object System.Drawing.Bitmap($iconPng)
|
|
return [System.Drawing.Icon]::FromHandle($bmp.GetHicon())
|
|
}
|
|
} catch {}
|
|
return [System.Drawing.SystemIcons]::Information
|
|
}
|
|
|
|
$script:logForm = $null
|
|
$script:logRtb = $null
|
|
$script:logChk = $null
|
|
$script:logSig = ''
|
|
|
|
$colInfo = [System.Drawing.Color]::FromArgb(40, 70, 120)
|
|
$colDebug = [System.Drawing.Color]::FromArgb(150, 150, 150)
|
|
$colErr = [System.Drawing.Color]::FromArgb(200, 40, 40)
|
|
$colTs = [System.Drawing.Color]::FromArgb(120, 120, 120)
|
|
|
|
function Update-LogText {
|
|
if (-not $script:logRtb -or $script:logRtb.IsDisposed) { return }
|
|
$lines = @()
|
|
if (Test-Path -LiteralPath $logFile) {
|
|
try {
|
|
$all = Get-Content -LiteralPath $logFile -Encoding UTF8 -ErrorAction SilentlyContinue
|
|
if ($all) {
|
|
if ($script:logChk -and -not $script:logChk.Checked) {
|
|
$all = $all | Where-Object { $_ -notmatch '\[DEBUG\]' }
|
|
}
|
|
$lines = @($all | Select-Object -Last 500)
|
|
}
|
|
} catch {}
|
|
}
|
|
$sig = ($lines -join "`n")
|
|
if ($sig -eq $script:logSig) { return }
|
|
$script:logSig = $sig
|
|
|
|
$rtb = $script:logRtb
|
|
$rtb.SuspendLayout()
|
|
$rtb.Clear()
|
|
if ($lines.Count -eq 0) {
|
|
$rtb.SelectionColor = $colDebug
|
|
$rtb.AppendText("(aucune activite de synchronisation pour le moment)")
|
|
} else {
|
|
foreach ($line in $lines) {
|
|
$col = $colInfo
|
|
if ($line -match '\[ERREUR\]') { $col = $colErr }
|
|
elseif ($line -match '\[DEBUG\]') { $col = $colDebug }
|
|
if ($line -match '^(\d{2}/\d{2}/\d{4} \d{2}:\d{2}:\d{2})(.*)$') {
|
|
$rtb.SelectionStart = $rtb.TextLength; $rtb.SelectionColor = $colTs
|
|
$rtb.AppendText($Matches[1])
|
|
$rtb.SelectionStart = $rtb.TextLength; $rtb.SelectionColor = $col
|
|
$rtb.AppendText($Matches[2] + "`n")
|
|
} else {
|
|
$rtb.SelectionStart = $rtb.TextLength; $rtb.SelectionColor = $col
|
|
$rtb.AppendText($line + "`n")
|
|
}
|
|
}
|
|
}
|
|
$rtb.ResumeLayout()
|
|
$rtb.SelectionStart = $rtb.TextLength; $rtb.ScrollToCaret()
|
|
}
|
|
|
|
function Show-LogWindow {
|
|
if ($script:logForm -and -not $script:logForm.IsDisposed) {
|
|
$script:logForm.WindowState = 'Normal'; $script:logForm.Activate(); return
|
|
}
|
|
$form = New-Object System.Windows.Forms.Form
|
|
$form.Text = 'Planification - journal de synchronisation'
|
|
$form.Size = New-Object System.Drawing.Size(760, 540)
|
|
$form.StartPosition = 'CenterScreen'
|
|
$form.BackColor = [System.Drawing.Color]::FromArgb(245, 246, 248)
|
|
try { $form.Icon = Get-TrayIcon } catch {}
|
|
|
|
# 1) zone de texte (Fill) ajoutee en premier
|
|
$rtb = New-Object System.Windows.Forms.RichTextBox
|
|
$rtb.Dock = 'Fill'
|
|
$rtb.ReadOnly = $true
|
|
$rtb.BorderStyle = 'None'
|
|
$rtb.BackColor = [System.Drawing.Color]::White
|
|
$rtb.Font = New-Object System.Drawing.Font('Consolas', 9.5)
|
|
$rtb.DetectUrls = $false
|
|
$form.Controls.Add($rtb)
|
|
|
|
# 2) barre d'outils claire avec le BOUTON bascule "Tout afficher" bien visible
|
|
$bar = New-Object System.Windows.Forms.Panel
|
|
$bar.Dock = 'Top'; $bar.Height = 40
|
|
$bar.BackColor = [System.Drawing.Color]::FromArgb(238, 240, 243)
|
|
$chk = New-Object System.Windows.Forms.CheckBox
|
|
$chk.Appearance = 'Button'
|
|
$chk.Text = 'Tout afficher (mode detaille)'
|
|
$chk.TextAlign = 'MiddleCenter'
|
|
$chk.AutoSize = $false
|
|
$chk.Size = New-Object System.Drawing.Size(200, 28)
|
|
$chk.Location = New-Object System.Drawing.Point(10, 6)
|
|
$chk.FlatStyle = 'System'
|
|
$chk.add_CheckedChanged({ $script:logSig = '~'; Update-LogText })
|
|
$bar.Controls.Add($chk)
|
|
$hint = New-Object System.Windows.Forms.Label
|
|
$hint.Text = 'Par defaut : l''essentiel. Activez pour voir tout le detail technique.'
|
|
$hint.ForeColor = [System.Drawing.Color]::FromArgb(90, 90, 90)
|
|
$hint.AutoSize = $true
|
|
$hint.Location = New-Object System.Drawing.Point(220, 12)
|
|
$bar.Controls.Add($hint)
|
|
$form.Controls.Add($bar)
|
|
|
|
# 3) bandeau titre (bleu) ajoute en dernier -> tout en haut
|
|
$hdrBar = New-Object System.Windows.Forms.Panel
|
|
$hdrBar.Dock = 'Top'; $hdrBar.Height = 32
|
|
$hdrBar.BackColor = [System.Drawing.Color]::FromArgb(40, 70, 120)
|
|
$hdr = New-Object System.Windows.Forms.Label
|
|
$hdr.Text = 'Activite de synchronisation - Planification'
|
|
$hdr.ForeColor = [System.Drawing.Color]::White
|
|
$hdr.Font = New-Object System.Drawing.Font('Segoe UI', 10, [System.Drawing.FontStyle]::Bold)
|
|
$hdr.AutoSize = $true
|
|
$hdr.Location = New-Object System.Drawing.Point(10, 7)
|
|
$hdrBar.Controls.Add($hdr)
|
|
$form.Controls.Add($hdrBar)
|
|
|
|
$script:logForm = $form
|
|
$script:logRtb = $rtb
|
|
$script:logChk = $chk
|
|
$script:logSig = ''
|
|
Update-LogText
|
|
|
|
$timer = New-Object System.Windows.Forms.Timer
|
|
$timer.Interval = 2000
|
|
$timer.add_Tick({ Update-LogText })
|
|
$timer.Start()
|
|
$form.add_FormClosed({ $timer.Stop(); $timer.Dispose() })
|
|
|
|
$form.Show(); $form.Activate()
|
|
}
|
|
|
|
$ni = New-Object System.Windows.Forms.NotifyIcon
|
|
$ni.Icon = Get-TrayIcon
|
|
$ni.Text = 'Planification - synchronisation active'
|
|
$ni.Visible = $true
|
|
|
|
$menu = New-Object System.Windows.Forms.ContextMenuStrip
|
|
$miLog = $menu.Items.Add('Voir le journal de synchronisation')
|
|
$miLog.add_Click({ Show-LogWindow })
|
|
$miQuit = $menu.Items.Add('Quitter')
|
|
$miQuit.add_Click({ $ni.Visible = $false; $ni.Dispose(); [System.Windows.Forms.Application]::Exit() })
|
|
$ni.ContextMenuStrip = $menu
|
|
$ni.add_MouseClick({ param($s, $e) if ($e.Button -eq [System.Windows.Forms.MouseButtons]::Left) { Show-LogWindow } })
|
|
|
|
# v2026.1.7 - auto-extinction apres 2 h SANS activite de synchronisation. On se
|
|
# base sur la date de derniere ecriture du journal (le host y ecrit a chaque
|
|
# operation). Le navigateur relancera le host a la prochaine activite, qui
|
|
# relancera ce tray. -> "de base eteint, s'active a l'usage, se ferme au repos".
|
|
$IDLE_LIMIT_MIN = 120
|
|
$idleTimer = New-Object System.Windows.Forms.Timer
|
|
$idleTimer.Interval = 300000 # verifie toutes les 5 min
|
|
$idleTimer.add_Tick({
|
|
try {
|
|
$age = $null
|
|
if (Test-Path -LiteralPath $logFile) {
|
|
$age = ((Get-Date) - (Get-Item -LiteralPath $logFile).LastWriteTime).TotalMinutes
|
|
}
|
|
# Pas de journal, ou journal inactif depuis >= 2 h -> on s'eteint.
|
|
if (($null -eq $age) -or ($age -ge $IDLE_LIMIT_MIN)) {
|
|
$ni.Visible = $false; $ni.Dispose()
|
|
[System.Windows.Forms.Application]::Exit()
|
|
}
|
|
} catch {}
|
|
})
|
|
$idleTimer.Start()
|
|
|
|
[System.Windows.Forms.Application]::EnableVisualStyles()
|
|
[System.Windows.Forms.Application]::Run()
|
|
$idleTimer.Stop()
|
|
$ni.Dispose()
|