diff --git a/backend/src/routes/telephony.ts b/backend/src/routes/telephony.ts index 2546378..abd3dbf 100644 --- a/backend/src/routes/telephony.ts +++ b/backend/src/routes/telephony.ts @@ -3,7 +3,7 @@ import { promises as fs } from "node:fs" import net from "node:net" import path from "node:path" import { randomBytes } from "node:crypto" -import { and, desc, eq, inArray, ne } from "drizzle-orm" +import { and, desc, eq, ilike, inArray, ne, or } from "drizzle-orm" import { authProfileBranches, authProfiles, @@ -1347,15 +1347,44 @@ export default async function telephonyRoutes(server: FastifyInstance) { server.get("/telephony/calls", async (req) => { const tenantId = requireTenant(req.user.tenant_id) + const query = req.query as { + limit?: string + direction?: string + status?: string + search?: string + localExtension?: string + } const limit = Math.min( - Math.max(Number((req.query as { limit?: string })?.limit || 25), 1), + Math.max(Number(query?.limit || 25), 1), 100 ) + const filters = [eq(telephonyCalls.tenantId, tenantId)] + + if (query.direction === "incoming" || query.direction === "outgoing") { + filters.push(eq(telephonyCalls.direction, query.direction)) + } + + if (query.status && query.status !== "all") { + filters.push(eq(telephonyCalls.status, query.status)) + } + + if (query.localExtension) { + filters.push(eq(telephonyCalls.localExtension, query.localExtension)) + } + + if (query.search?.trim()) { + const search = `%${query.search.trim()}%` + filters.push(or( + ilike(telephonyCalls.remoteNumber, search), + ilike(telephonyCalls.remoteDisplayName, search), + ilike(telephonyCalls.localExtension, search) + )!) + } return await server.db .select() .from(telephonyCalls) - .where(eq(telephonyCalls.tenantId, tenantId)) + .where(and(...filters)) .orderBy(desc(telephonyCalls.startedAt)) .limit(limit) }) diff --git a/frontend/components/EntityShowSubInformation.vue b/frontend/components/EntityShowSubInformation.vue index a2bc7cc..4bd3366 100644 --- a/frontend/components/EntityShowSubInformation.vue +++ b/frontend/components/EntityShowSubInformation.vue @@ -60,6 +60,22 @@ const renderDatapointValue = (datapoint) => { return `${value}${datapoint.unit ? datapoint.unit : ""}` } +const isTelephonyDatapoint = (datapoint) => { + if (datapoint.telephonyCall) return true + + const key = String(datapoint.key || "").toLowerCase() + return [ + "phone", + "tel", + "mobile", + "mobiletel", + "phonemobile", + "phonehome", + "fixed_tel", + "mobile_tel", + ].some((part) => key.includes(part)) +} +