feat(devices): implementa tabela separada para softwares instalados
- Cria tabela machineSoftware no schema com indices otimizados - Adiciona mutations para sincronizar softwares do heartbeat - Atualiza heartbeat para processar e salvar softwares - Cria componente DeviceSoftwareList com pesquisa e paginacao - Integra lista de softwares no drawer de detalhes do dispositivo feat(sla): transforma formulario em modal completo - Substitui formulario inline por modal guiado - Adiciona badge "Global" para indicar escopo da politica - Adiciona seletor de unidade de tempo (minutos, horas, dias) - Melhora textos e adiciona dica sobre hierarquia de SLAs fix(reports): ajusta altura do SearchableCombobox 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
ef2545221d
commit
23fe67e7d3
7 changed files with 741 additions and 205 deletions
|
|
@ -1,6 +1,6 @@
|
|||
// ci: trigger convex functions deploy (no-op)
|
||||
import { mutation, query } from "./_generated/server"
|
||||
import { api } from "./_generated/api"
|
||||
import { internal, api } from "./_generated/api"
|
||||
import { paginationOptsValidator } from "convex/server"
|
||||
import { ConvexError, v, Infer } from "convex/values"
|
||||
import { sha256 } from "@noble/hashes/sha2.js"
|
||||
|
|
@ -1010,6 +1010,34 @@ export const heartbeat = mutation({
|
|||
await upsertRemoteAccessSnapshotFromHeartbeat(ctx, machine, remoteAccessSnapshot, now)
|
||||
}
|
||||
|
||||
// Processar softwares instalados (armazenados em tabela separada)
|
||||
// Os dados de software sao extraidos ANTES de sanitizar o inventory
|
||||
const rawInventory = args.inventory ?? args.metadata?.inventory
|
||||
if (rawInventory && typeof rawInventory === "object") {
|
||||
const softwareArray = (rawInventory as Record<string, unknown>)["software"]
|
||||
if (Array.isArray(softwareArray) && softwareArray.length > 0) {
|
||||
const validSoftware = softwareArray
|
||||
.filter((item): item is Record<string, unknown> => item !== null && typeof item === "object")
|
||||
.map((item) => ({
|
||||
name: typeof item.name === "string" ? item.name : "",
|
||||
version: typeof item.version === "string" ? item.version : undefined,
|
||||
publisher: typeof item.publisher === "string" || typeof item.source === "string"
|
||||
? (item.publisher as string) || (item.source as string)
|
||||
: undefined,
|
||||
source: typeof item.source === "string" ? item.source : undefined,
|
||||
}))
|
||||
.filter((item) => item.name.length > 0)
|
||||
|
||||
if (validSoftware.length > 0) {
|
||||
await ctx.runMutation(internal.machineSoftware.syncFromHeartbeat, {
|
||||
tenantId: machine.tenantId,
|
||||
machineId: machine._id,
|
||||
software: validSoftware,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await ctx.db.patch(token._id, {
|
||||
lastUsedAt: now,
|
||||
usageCount: (token.usageCount ?? 0) + 1,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue