Add global ticket search

This commit is contained in:
2026-08-11 07:57:58 +02:00
parent 4390f9a7da
commit dcc115a82c
4 changed files with 197 additions and 7 deletions
+56
View File
@@ -2681,6 +2681,62 @@ app.get("/api/tickets/lookup", requireUser, async (req, res) => {
});
});
app.get("/api/tickets/search", requireUser, async (req, res) => {
const user = currentUser(req);
const rawQuery = typeof req.query.q === "string" ? req.query.q.trim() : "";
if (rawQuery.length < 2) {
res.json({ tickets: [] });
return;
}
const normalizedTicketQuery = rawQuery.replace(/^ticket#/iu, "").trim();
const searchPattern = `%${rawQuery}%`;
const ticketNumberPattern = `%${normalizedTicketQuery || rawQuery}%`;
const result = await query(
`
SELECT
t.id AS ticket_id,
t.ticket_number,
t.organization_id,
COALESCE(o.name, t.customer_name, '') AS organization_name,
COALESCE(o.name, t.customer_name, '') AS customer_name,
t.work_type,
MAX(s.started_at) AS latest_started_at,
to_char(MAX(s.started_at) AT TIME ZONE 'Europe/Berlin', 'YYYY-MM') AS latest_period,
COUNT(s.id)::int AS session_count,
COALESCE(SUM(s.rounded_minutes), 0)::int AS total_minutes
FROM tickets t
JOIN sessions s ON s.ticket_id = t.id
LEFT JOIN organizations o ON o.id = t.organization_id
WHERE s.user_id = $1
AND (
t.ticket_number ILIKE $2
OR replace(t.ticket_number, 'Ticket#', '') ILIKE $3
OR COALESCE(o.name, '') ILIKE $2
OR COALESCE(t.customer_name, '') ILIKE $2
OR COALESCE(s.customer_name, '') ILIKE $2
OR s.activity ILIKE $2
)
GROUP BY t.id, t.ticket_number, t.organization_id, o.name, t.customer_name, t.work_type
ORDER BY
CASE
WHEN lower(t.ticket_number) = lower($4) THEN 0
WHEN lower(replace(t.ticket_number, 'Ticket#', '')) = lower($5) THEN 1
WHEN t.ticket_number ILIKE $3 THEN 2
ELSE 3
END,
MAX(s.started_at) DESC,
t.ticket_number ASC
LIMIT 12;
`,
[user.id, searchPattern, ticketNumberPattern, rawQuery, normalizedTicketQuery]
);
res.json({ tickets: result.rows });
});
app.patch("/api/tickets/:ticketId", requireUser, async (req, res) => {
const ticketId = parsePositiveInteger(req.params.ticketId, "ticketId");
const ticketNumber = parseTrackableTicketNumber(req.body.ticketNumber);