dashboards/HerdManager/HerdManager.ps1
|
[CmdletBinding()] Param() begin { # Load centralized styles . "$PSScriptRoot/Styles.ps1" function Invoke-UniversalSQLiteQuery { <# .SYNOPSIS Execute SQLite queries using the sqlite3 command-line tool .DESCRIPTION A wrapper function that executes SQLite queries using the native sqlite3 CLI. This provides cross-platform compatibility without requiring PowerShell modules. .PARAMETER Path Path to the SQLite database file .PARAMETER Query SQL query to execute .EXAMPLE Invoke-UniversalSQLiteQuery -Path "./data/HerdManager.db" -Query "SELECT * FROM Cattle" .NOTES Requires sqlite3 to be installed and available in PATH #> [CmdletBinding()] param( [Parameter(Mandatory)] [string]$Path, [Parameter(Mandatory)] [string]$Query ) # Verify sqlite3 is available if (-not (Get-Command sqlite3 -ErrorAction SilentlyContinue)) { throw "sqlite3 command not found. Please install SQLite." } # Verify database exists if (-not (Test-Path $Path)) { throw "Database file not found: $Path" } # Resolve full path $dbPath = Resolve-Path $Path | Select-Object -ExpandProperty Path # Try JSON output first (best for structured data) $output = sqlite3 $dbPath -json $Query 2>&1 # Check for errors if ($LASTEXITCODE -ne 0) { throw "SQLite query failed: $output" } # Parse output if ($output) { try { # Try to parse as JSON $result = $output | ConvertFrom-Json return $result } catch { # JSON parsing failed, try CSV mode for better compatibility $csvOutput = sqlite3 $dbPath -csv -header $Query 2>&1 if ($LASTEXITCODE -eq 0 -and $csvOutput) { try { # Convert CSV to objects $result = $csvOutput | ConvertFrom-Csv return $result } catch { # If CSV also fails, return raw output return $csvOutput } } # Fallback to raw output return $output } } return $null } } end { $Navigation = New-UDList -Content { New-UDListItem -Label "Home" -Icon (New-UDIcon -Icon Home) -OnClick { Invoke-UDRedirect -Url '/Home' } New-UDListItem -Label "Notifications" -Icon (New-UDIcon -Icon Bell) -OnClick { Invoke-UDRedirect -Url '/notifications' } New-UDListItem -Label "Cattle Management" -Icon (New-UDIcon -Icon Cow) -OnClick { Invoke-UDRedirect -Url '/cattle' } New-UDListItem -Label "Weight Management" -Icon (New-UDIcon -Icon Weight) -OnClick { Invoke-UDRedirect -Url '/weights' } New-UDListItem -Label "Health Records" -Icon (New-UDIcon -Icon Heartbeat) -OnClick { Invoke-UDRedirect -Url '/health' } New-UDListItem -Label "Feed Records" -Icon (New-UDIcon -Icon Seedling) -OnClick { Invoke-UDRedirect -Url '/feedrecords' } New-UDListItem -Label "Farms" -Icon (New-UDIcon -Icon Tractor) -OnClick { Invoke-UDRedirect -Url '/farms' } New-UDListItem -Label "Rate of Gain" -Icon (New-UDIcon -Icon ChartLine) -OnClick { Invoke-UDRedirect -Url '/rog' } New-UDListItem -Label "Animal Report" -Icon (New-UDIcon -Icon FileAlt) -OnClick { Invoke-UDRedirect -Url '/animal-report' } New-UDListItem -Label "Accounting" -Icon (New-UDIcon -Icon Calculator) -OnClick { Invoke-UDRedirect -Url '/accounting' } New-UDListItem -Label "Reports" -Icon (New-UDIcon -Icon ChartBar) -OnClick { Invoke-UDRedirect -Url '/reports' } New-UDListItem -Label "Help" -Icon (New-UDIcon -Icon QuestionCircle) -OnClick { Invoke-UDRedirect -Url '/help' } New-UDListItem -Label "Setup" -Icon (New-UDIcon -Icon Tools) -OnClick { Invoke-UDRedirect -Url '/settings' } } $HeaderContent = { # Cross-platform path to database $moduleBase = (Get-Module PowerShellUniversal.Apps.HerdManager).ModuleBase $dbPath = Join-Path $moduleBase 'data' 'HerdManager.db' # Notification bell with badge New-UDDynamic -Content { $overdueQuery = "SELECT COUNT(*) as Count FROM HealthRecords hr INNER JOIN Cattle c ON hr.CattleID = c.CattleID WHERE hr.NextDueDate IS NOT NULL AND hr.NextDueDate < DATE('now') AND c.Status = 'Active'" $overdueCount = (Invoke-UniversalSQLiteQuery -Path $dbPath -Query $overdueQuery).Count if ($overdueCount -gt 0) { New-UDBadge -BadgeContent { $overdueCount } -Color error -Content { New-UDIconButton -Icon (New-UDIcon -Icon Bell -Size lg) -OnClick { Invoke-UDRedirect -Url '/notifications' } } } else { New-UDIconButton -Icon (New-UDIcon -Icon Bell -Size lg) -OnClick { Invoke-UDRedirect -Url '/notifications' } } } -AutoRefresh -AutoRefreshInterval 300 # First-run redirect: if SystemInfo is not configured, redirect users to the setup page using server-driven redirect try { $sysCheck = Get-SystemInfo } catch { $sysCheck = $null } # No forced redirect here — first-run banner is shown on the Home page instead # Delegated click handler for in-page help TOC links (data-toc-target) New-UDHtml -Markup "<script>(function(){function __herd_toc_handler(e){var el=e.target; while(el && el!==document){ try{ if(el.matches && el.matches('[data-toc-target]')){ e.preventDefault(); e.stopPropagation(); if (e.stopImmediatePropagation) { e.stopImmediatePropagation(); } var id=el.getAttribute('data-toc-target') || (el.dataset && el.dataset.tocTarget); if(!id && el.hasAttribute('href')){ var href=el.getAttribute('href'); if(href && href.indexOf('#')===0){ id=href.substring(1); } } if(id){ var t=document.getElementById(id); if(t){ t.scrollIntoView({behavior:'smooth', block:'start'}); try{ history.pushState(null, '', window.location.pathname + '#' + id); }catch(e){} } } break; } } catch(err){ console && console.debug && console.debug('TOC handler error', err); } el=el.parentNode;} } try{ document.addEventListener('pointerdown', __herd_toc_handler, true); document.addEventListener('click', __herd_toc_handler, true); window.__herd_toc_handler_attached = true; console && console.debug && console.debug('HerdManager TOC handler attached'); }catch(err){ console && console.debug && console.debug('Failed to attach TOC handler', err); } try{ window.addEventListener('hashchange', function(){ try{ var id = (window.location.hash && window.location.hash.length>1) ? window.location.hash.substring(1) : null; if(id){ var t = document.getElementById(id); if(t){ t.scrollIntoView({behavior:'smooth', block:'start'}); } } }catch(e){ console && console.debug && console.debug('hashchange handler error', e); } }, false); }catch(err){ console && console.debug && console.debug('Failed to attach hashchange handler', err); } try{ setTimeout(function(){ try{ var id = (window.location.hash && window.location.hash.length>1) ? window.location.hash.substring(1) : null; if(id){ var t = document.getElementById(id); if(t){ t.scrollIntoView({behavior:'smooth', block:'start'}); } } }catch(e){ console && console.debug && console.debug('initial hash scroll error', e); } }, 250); }catch(e){ console && console.debug && console.debug('Failed to schedule initial hash check', e); } })();</script>" }.GetNewClosure() $app = @{ Title = '🐄 Herd Manager' Pages = @($homepage, $notifications, $cattleMgmt, $weightMgmt, $healthMgmt, $feedRecords, $farmsPage, $rog, $reports, $animalreport, $accounting, $invoicePage, $systemSettings, $helpPage) Navigation = $Navigation NavigationLayout = 'Temporary' HeaderContent = $HeaderContent } New-UDApp @app } |