mirror of
https://github.com/okieselbach/AutopilotMonitor.git
synced 2026-10-24 12:42:38 +00:00
fix timestamp handling
fix design for config pages
This commit is contained in:
@@ -612,7 +612,10 @@ namespace AutopilotMonitor.Functions.Services
|
||||
EventId = entity.GetString("EventId") ?? string.Empty,
|
||||
SessionId = entity.GetString("SessionId") ?? string.Empty,
|
||||
TenantId = entity.PartitionKey,
|
||||
Timestamp = entity.GetDateTime("Timestamp") ?? DateTime.UtcNow,
|
||||
Timestamp = DateTime.SpecifyKind(
|
||||
entity.GetDateTimeOffset("Timestamp")?.UtcDateTime
|
||||
?? entity.GetDateTime("Timestamp")
|
||||
?? DateTime.UtcNow, DateTimeKind.Utc),
|
||||
EventType = entity.GetString("EventType") ?? string.Empty,
|
||||
Severity = (EventSeverity)(entity.GetInt32("Severity") ?? 0),
|
||||
Source = entity.GetString("Source") ?? string.Empty,
|
||||
|
||||
@@ -628,25 +628,22 @@ export default function AdminConfigurationPage() {
|
||||
|
||||
return (
|
||||
<ProtectedRoute>
|
||||
<div className="min-h-screen bg-gradient-to-br from-purple-50 to-violet-100">
|
||||
<div className="min-h-screen bg-gray-50">
|
||||
{/* Header */}
|
||||
<header className="bg-white shadow-sm border-b border-gray-200">
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4">
|
||||
<header className="bg-white shadow">
|
||||
<div className="max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center space-x-4">
|
||||
<div>
|
||||
<button
|
||||
onClick={() => router.push("/")}
|
||||
className="flex items-center space-x-2 text-gray-600 hover:text-gray-900 transition-colors"
|
||||
className="text-sm text-gray-600 hover:text-gray-900 mb-2 flex items-center"
|
||||
>
|
||||
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M10 19l-7-7m0 0l7-7m-7 7h18" />
|
||||
</svg>
|
||||
<span>Back to Dashboard</span>
|
||||
← Back to Dashboard
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<h1 className="text-2xl font-bold text-purple-900">Admin Configuration</h1>
|
||||
<p className="text-sm text-purple-600">Galactic Admin Operations</p>
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold text-gray-900">Admin Configuration</h1>
|
||||
<p className="text-sm text-gray-600 mt-1">Galactic Admin Operations</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -653,20 +653,19 @@ export default function AnalyzeRulesPage() {
|
||||
|
||||
return (
|
||||
<ProtectedRoute>
|
||||
<div className="min-h-screen bg-gradient-to-br from-blue-50 to-indigo-100">
|
||||
<div className="min-h-screen bg-gray-50">
|
||||
{/* Header */}
|
||||
<header className="bg-white shadow-sm border-b border-gray-200">
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4">
|
||||
<header className="bg-white shadow">
|
||||
<div className="max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center space-x-4">
|
||||
<button onClick={() => router.push("/")} className="flex items-center space-x-2 text-gray-600 hover:text-gray-900 transition-colors">
|
||||
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M10 19l-7-7m0 0l7-7m-7 7h18" /></svg>
|
||||
<span>Back to Dashboard</span>
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<h1 className="text-2xl font-bold text-gray-900">Analyze Rules</h1>
|
||||
<p className="text-sm text-gray-500">Manage event analysis rules for issue detection</p>
|
||||
<button onClick={() => router.push("/")} className="text-sm text-gray-600 hover:text-gray-900 mb-2 flex items-center">
|
||||
← Back to Dashboard
|
||||
</button>
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold text-gray-900">Analyze Rules</h1>
|
||||
<p className="text-sm text-gray-600 mt-1">Manage event analysis rules for issue detection</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -649,25 +649,22 @@ export default function GatherRulesPage() {
|
||||
|
||||
return (
|
||||
<ProtectedRoute>
|
||||
<div className="min-h-screen bg-gradient-to-br from-blue-50 to-indigo-100">
|
||||
<div className="min-h-screen bg-gray-50">
|
||||
{/* Header */}
|
||||
<header className="bg-white shadow-sm border-b border-gray-200">
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4">
|
||||
<header className="bg-white shadow">
|
||||
<div className="max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center space-x-4">
|
||||
<div>
|
||||
<button
|
||||
onClick={() => router.push("/")}
|
||||
className="flex items-center space-x-2 text-gray-600 hover:text-gray-900 transition-colors"
|
||||
className="text-sm text-gray-600 hover:text-gray-900 mb-2 flex items-center"
|
||||
>
|
||||
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M10 19l-7-7m0 0l7-7m-7 7h18" />
|
||||
</svg>
|
||||
<span>Back to Dashboard</span>
|
||||
← Back to Dashboard
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<h1 className="text-2xl font-bold text-gray-900">Gather Rules</h1>
|
||||
<p className="text-sm text-gray-500">Manage data collection rules for device enrollment</p>
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold text-gray-900">Gather Rules</h1>
|
||||
<p className="text-sm text-gray-600 mt-1">Manage data collection rules for device enrollment</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -369,7 +369,7 @@ export default function ProgressPortalPage() {
|
||||
|
||||
return (
|
||||
<ProtectedRoute>
|
||||
<div className="min-h-screen bg-gradient-to-b from-blue-50 to-white">
|
||||
<div className="min-h-screen bg-gray-50">
|
||||
<div className="max-w-2xl mx-auto px-4 py-6 sm:py-12">
|
||||
{/* Collapsible Header + Search */}
|
||||
{headerCollapsed && session ? (
|
||||
|
||||
@@ -1580,18 +1580,11 @@ function DeviceDetailsCard({ events }: { events: EnrollmentEvent[] }) {
|
||||
const agentStarted = getEventData("agent_started");
|
||||
const bootTime = getEventData("boot_time");
|
||||
|
||||
// Calculate boot time from first event timestamp minus uptimeMinutes.
|
||||
// The device-reported bootTimeUtc can be inconsistent with event timestamps due to
|
||||
// timezone handling on the device side. Using firstEvent - uptime gives a result
|
||||
// that is always consistent with the event timeline shown in the UI.
|
||||
const estimatedBootTime = (() => {
|
||||
const uptimeMinutes = bootTime?.uptimeMinutes ?? agentStarted?.uptimeMinutes;
|
||||
if (!uptimeMinutes) return null;
|
||||
const timestamps = events.map(e => new Date(e.timestamp).getTime()).filter(t => !isNaN(t));
|
||||
if (timestamps.length === 0) return null;
|
||||
const firstEventMs = Math.min(...timestamps);
|
||||
return new Date(firstEventMs - uptimeMinutes * 60 * 1000);
|
||||
})();
|
||||
// Boot time from bootTimeUtc (device-reported UTC with Z suffix, parsed correctly as UTC by browser).
|
||||
// Now that event timestamps are also serialized with Z suffix (Kind=Utc), both are consistent.
|
||||
const estimatedBootTime = (bootTime?.bootTimeUtc || bootTime?.bootTime)
|
||||
? new Date(bootTime?.bootTimeUtc ?? bootTime?.bootTime)
|
||||
: null;
|
||||
const osInfo = getEventData("os_info");
|
||||
const networkAdapters = getEventData("network_adapters");
|
||||
const dnsConfig = getEventData("dns_configuration");
|
||||
|
||||
Reference in New Issue
Block a user