Add requester filter and improve error messages

- Add requester filter to device tickets history page
- Create listMachineRequesters query to list unique requesters
- Add friendly API error formatting in desktop agent
- Translate validation errors to user-friendly Portuguese messages

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
rever-tecnologia 2025-12-05 17:22:44 -03:00
parent bb82efa9d3
commit cf31e78edb
3 changed files with 140 additions and 5 deletions

View file

@ -134,6 +134,54 @@ function isTokenRevokedMessage(input: string) {
)
}
function formatApiError(responseText: string, statusCode: number): string {
try {
const json = JSON.parse(responseText)
if (json.error === "Payload invalido" || json.error === "Payload inválido") {
const details = typeof json.details === "string" ? JSON.parse(json.details) : json.details
if (Array.isArray(details) && details.length > 0) {
const fieldLabels: Record<string, string> = {
"collaborator.email": "E-mail",
"collaborator.name": "Nome",
email: "E-mail",
name: "Nome",
provisioningCode: "Código de ativação",
hostname: "Nome do computador",
}
const messages: string[] = []
for (const err of details) {
const path = Array.isArray(err.path) ? err.path.join(".") : String(err.path ?? "")
const fieldLabel = fieldLabels[path] || path || "Campo"
if (err.code === "invalid_format" && err.format === "email") {
messages.push(`${fieldLabel}: formato de e-mail inválido`)
} else if (err.code === "invalid_format") {
messages.push(`${fieldLabel}: formato inválido`)
} else if (err.code === "too_small" || err.code === "too_short") {
messages.push(`${fieldLabel}: muito curto`)
} else if (err.code === "too_big" || err.code === "too_long") {
messages.push(`${fieldLabel}: muito longo`)
} else if (err.code === "invalid_type") {
messages.push(`${fieldLabel}: valor inválido`)
} else if (err.message) {
messages.push(`${fieldLabel}: ${err.message}`)
} else {
messages.push(`${fieldLabel}: erro de validação`)
}
}
if (messages.length > 0) {
return messages.join("\n")
}
}
}
if (json.error) {
return json.error
}
} catch {
// Não é JSON, retorna o texto original
}
return `Erro no servidor (${statusCode})`
}
function buildRemoteAccessPayload(info: RustdeskInfo | null) {
if (!info) return null
const payload: Record<string, string | undefined> = {
@ -1038,7 +1086,7 @@ const resolvedAppUrl = useMemo(() => {
})
if (!res.ok) {
const text = await res.text()
throw new Error(`Falha no registro (${res.status}): ${text.slice(0, 300)}`)
throw new Error(formatApiError(text, res.status))
}
const data = (await res.json()) as MachineRegisterResponse
@ -1242,7 +1290,7 @@ const resolvedAppUrl = useMemo(() => {
})
if (!res.ok) {
const text = await res.text()
throw new Error(`Falha ao enviar inventário (${res.status}): ${text.slice(0, 200)}`)
throw new Error(formatApiError(text, res.status))
}
} catch (err) {
setError(err instanceof Error ? err.message : String(err))