From c2802b1a4d1a94cbd615059fa649ebbc46cd508c Mon Sep 17 00:00:00 2001 From: rever-tecnologia Date: Thu, 18 Dec 2025 10:39:39 -0300 Subject: [PATCH] feat(export): adiciona colunas bootInfo e remove Fleet do inventario MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Adiciona colunas lastBootTime, uptimeFormatted, bootCount30d - Remove colunas fleetId, fleetTeam, fleetUpdatedAt (nao utilizadas) - Adiciona funcao extractBootInfo() para extrair dados de extended.windows.bootInfo 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- src/lib/device-inventory-columns.ts | 6 +-- src/server/machines/inventory-export.ts | 57 +++++++++++++++++++++++-- 2 files changed, 56 insertions(+), 7 deletions(-) diff --git a/src/lib/device-inventory-columns.ts b/src/lib/device-inventory-columns.ts index 95f620a..10758f1 100644 --- a/src/lib/device-inventory-columns.ts +++ b/src/lib/device-inventory-columns.ts @@ -58,9 +58,9 @@ export const DEVICE_INVENTORY_COLUMN_METADATA: DeviceInventoryColumnMetadata[] = { key: "collaboratorName", label: "Colaborador (nome)", width: 24, default: true }, { key: "collaboratorEmail", label: "Colaborador (e-mail)", width: 26, default: true }, { key: "remoteAccessCount", label: "Acessos remotos", width: 18, default: true }, - { key: "fleetId", label: "Fleet ID", width: 18, default: true }, - { key: "fleetTeam", label: "Equipe Fleet", width: 18, default: true }, - { key: "fleetUpdatedAt", label: "Fleet atualizado em", width: 20, default: true }, + { key: "lastBootTime", label: "Último reinício", width: 20, default: true }, + { key: "uptimeFormatted", label: "Tempo ligado", width: 16, default: true }, + { key: "bootCount30d", label: "Reinícios (30d)", width: 16, default: true }, { key: "managementMode", label: "Modo de gestão", width: 20, default: false }, { key: "usbPolicy", label: "Política USB", width: 18, default: true }, { key: "usbPolicyStatus", label: "Status política USB", width: 18, default: true }, diff --git a/src/server/machines/inventory-export.ts b/src/server/machines/inventory-export.ts index a0acc90..1cbdfd9 100644 --- a/src/server/machines/inventory-export.ts +++ b/src/server/machines/inventory-export.ts @@ -94,6 +94,7 @@ type MachineDerivedData = { collaborator: ReturnType remoteAccessCount: number fleetInfo: ReturnType + bootInfo: BootInfo customFieldByKey: Record customFieldById: Record } @@ -145,10 +146,10 @@ const COLUMN_VALUE_RESOLVERS: Record derived.collaborator?.name ?? null, collaboratorEmail: (_machine, derived) => derived.collaborator?.email ?? null, remoteAccessCount: (_machine, derived) => derived.remoteAccessCount, - fleetId: (_machine, derived) => derived.fleetInfo?.id ?? null, - fleetTeam: (_machine, derived) => derived.fleetInfo?.team ?? null, - fleetUpdatedAt: (_machine, derived) => - derived.fleetInfo?.updatedAt ? formatDateTime(derived.fleetInfo.updatedAt) : null, + lastBootTime: (_machine, derived) => + derived.bootInfo.lastBootTime ? formatDateTime(derived.bootInfo.lastBootTime) : null, + uptimeFormatted: (_machine, derived) => derived.bootInfo.uptimeFormatted, + bootCount30d: (_machine, derived) => derived.bootInfo.bootCount30d, managementMode: (machine) => describeManagementMode(machine.managementMode), usbPolicy: (machine) => describeUsbPolicy(machine.usbPolicy), usbPolicyStatus: (machine) => describeUsbPolicyStatus(machine.usbPolicyStatus), @@ -186,6 +187,7 @@ function deriveMachineData(machine: MachineInventoryRecord): MachineDerivedData const collaborator = extractCollaborator(machine, inventory) const remoteAccessCount = collectRemoteAccessEntries(machine).length const fleetInfo = extractFleetInfo(inventory) + const bootInfo = extractBootInfo(inventory) const customFieldByKey: Record = {} const customFieldById: Record = {} for (const field of machine.customFields ?? []) { @@ -205,6 +207,7 @@ function deriveMachineData(machine: MachineInventoryRecord): MachineDerivedData collaborator, remoteAccessCount, fleetInfo, + bootInfo, customFieldByKey, customFieldById, } @@ -1561,6 +1564,52 @@ function extractSystemInfo(inventory: Record | null): SystemInf } } +type BootInfo = { + lastBootTime: number | null + uptimeSeconds: number | null + uptimeFormatted: string | null + bootCount30d: number | null +} + +function extractBootInfo(inventory: Record | null): BootInfo { + const result: BootInfo = { + lastBootTime: null, + uptimeSeconds: null, + uptimeFormatted: null, + bootCount30d: null, + } + if (!inventory) return result + + const extended = pickRecord(inventory, ["extended", "Extended"]) + const windows = pickRecord(extended, ["windows", "Windows"]) + const bootInfo = pickRecord(windows, ["bootInfo", "BootInfo"]) + + if (!bootInfo) return result + + result.lastBootTime = + parseDateish(bootInfo["lastBootTimeUTC"]) ?? + parseDateish(bootInfo["LastBootTimeUTC"]) ?? + parseDateish(bootInfo["lastBootTime"]) ?? + parseDateish(bootInfo["LastBootUpTime"]) + + const uptimeRaw = pickNumber(bootInfo, ["uptimeSeconds", "UptimeSeconds", "uptime"]) + result.uptimeSeconds = uptimeRaw + + const uptimeFmt = pickString(bootInfo, ["uptimeFormatted", "UptimeFormatted"]) + if (uptimeFmt) { + result.uptimeFormatted = uptimeFmt + } else if (uptimeRaw !== null && uptimeRaw >= 0) { + const days = Math.floor(uptimeRaw / 86400) + const hours = Math.floor((uptimeRaw % 86400) / 3600) + const minutes = Math.floor((uptimeRaw % 3600) / 60) + result.uptimeFormatted = `${days}d ${hours}h ${minutes}m` + } + + result.bootCount30d = pickNumber(bootInfo, ["bootCount30d", "BootCount30d", "bootCount"]) + + return result +} + type SoftwareEntryInternal = SoftwareEntry function extractSoftwareEntries(hostname: string, inventory: Record | null): SoftwareEntryInternal[] {