From 1bda67fec680696edbc24a9a45a59b1d408efc6e Mon Sep 17 00:00:00 2001 From: Yinyin Liu Date: Tue, 5 May 2026 08:57:02 +0200 Subject: [PATCH] add assignee and category filter to ticket system --- csharp/App/Backend/Controller.cs | 21 +++++- .../content/dashboards/Tickets/TicketList.tsx | 74 ++++++++++++++++++- .../src/interfaces/TicketTypes.tsx | 2 + typescript/frontend-marios2/src/lang/de.json | 2 + typescript/frontend-marios2/src/lang/en.json | 2 + typescript/frontend-marios2/src/lang/fr.json | 2 + typescript/frontend-marios2/src/lang/it.json | 2 + 7 files changed, 103 insertions(+), 2 deletions(-) diff --git a/csharp/App/Backend/Controller.cs b/csharp/App/Backend/Controller.cs index 35105a84b..4fccc90a5 100644 --- a/csharp/App/Backend/Controller.cs +++ b/csharp/App/Backend/Controller.cs @@ -2591,19 +2591,38 @@ public class Controller : ControllerBase .ToList() .ToDictionary(i => i.Id); + var assigneeIds = tickets + .Where(t => t.AssigneeId.HasValue) + .Select(t => t.AssigneeId!.Value) + .Distinct() + .ToList(); + + var assigneesById = assigneeIds.Count == 0 + ? new Dictionary() + : Db.Users + .Where(u => assigneeIds.Contains(u.Id)) + .ToList() + .ToDictionary(u => u.Id); + var summaries = tickets.Select(t => { Installation? installation = null; if (t.InstallationId.HasValue) installationsById.TryGetValue(t.InstallationId.Value, out installation); + User? assignee = null; + if (t.AssigneeId.HasValue) + assigneesById.TryGetValue(t.AssigneeId.Value, out assignee); + return new { t.Id, t.Subject, t.Status, t.Priority, t.Category, t.SubCategory, t.InstallationId, t.CreatedAt, t.UpdatedAt, t.CustomSubCategory, t.CustomCategory, + t.AssigneeId, installationName = installation?.Name ?? (t.InstallationId.HasValue ? $"#{t.InstallationId}" : "No installation"), - distributionPartner = installation?.DistributionPartner ?? "" + distributionPartner = installation?.DistributionPartner ?? "", + assigneeName = assignee?.Name }; }); diff --git a/typescript/frontend-marios2/src/content/dashboards/Tickets/TicketList.tsx b/typescript/frontend-marios2/src/content/dashboards/Tickets/TicketList.tsx index 8abd24df6..c081da1c5 100644 --- a/typescript/frontend-marios2/src/content/dashboards/Tickets/TicketList.tsx +++ b/typescript/frontend-marios2/src/content/dashboards/Tickets/TicketList.tsx @@ -27,6 +27,7 @@ import { TicketSummary, TicketStatus, TicketPriority, + AdminUser, categoryKeys, subCategoryKeys, getCategoryDisplayLabel, @@ -53,9 +54,12 @@ function TicketList() { const navigate = useNavigate(); const intl = useIntl(); const [tickets, setTickets] = useState([]); + const [adminUsers, setAdminUsers] = useState([]); const [search, setSearch] = useState(''); const [statusFilter, setStatusFilter] = useState([]); const [partnerFilter, setPartnerFilter] = useState(''); + const [assigneeFilter, setAssigneeFilter] = useState(''); + const [categoryFilter, setCategoryFilter] = useState(''); const [createOpen, setCreateOpen] = useState(false); const [error, setError] = useState(''); @@ -68,12 +72,26 @@ function TicketList() { useEffect(() => { fetchTickets(); + axiosConfig + .get('/GetAdminUsers') + .then((res) => setAdminUsers(res.data)) + .catch(() => {}); }, []); const partnerOptions = Array.from( new Set(tickets.map((t) => t.distributionPartner).filter((p) => p && p.trim() !== '')) ).sort(); + const assigneeOptions = adminUsers + .filter((u) => { + const name = (u.name ?? '').toLowerCase(); + return ( + !name.includes('inesco energy master admin') && + !name.includes('paal myhre') + ); + }) + .sort((a, b) => (a.name ?? '').localeCompare(b.name ?? '')); + const filtered = tickets .filter((t) => { const matchesSearch = @@ -82,7 +100,14 @@ function TicketList() { t.installationName.toLowerCase().includes(search.toLowerCase()); const matchesStatus = statusFilter.length === 0 || statusFilter.includes(t.status); const matchesPartner = partnerFilter === '' || t.distributionPartner === partnerFilter; - return matchesSearch && matchesStatus && matchesPartner; + const matchesAssignee = + assigneeFilter === '' || + (assigneeFilter === '__unassigned__' + ? !t.assigneeId + : t.assigneeId === Number(assigneeFilter)); + const matchesCategory = + categoryFilter === '' || t.category === Number(categoryFilter); + return matchesSearch && matchesStatus && matchesPartner && matchesAssignee && matchesCategory; }) .sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()); @@ -176,6 +201,53 @@ function TicketList() { ))} + + + + + + + + + + + + {error && ( diff --git a/typescript/frontend-marios2/src/interfaces/TicketTypes.tsx b/typescript/frontend-marios2/src/interfaces/TicketTypes.tsx index ed205a2bd..4f694c43b 100644 --- a/typescript/frontend-marios2/src/interfaces/TicketTypes.tsx +++ b/typescript/frontend-marios2/src/interfaces/TicketTypes.tsx @@ -267,6 +267,8 @@ export type TicketSummary = { distributionPartner: string; customSubCategory: string | null; customCategory: string | null; + assigneeId: number | null; + assigneeName: string | null; }; export type AdminUser = { diff --git a/typescript/frontend-marios2/src/lang/de.json b/typescript/frontend-marios2/src/lang/de.json index 686c00705..a1b4c134a 100644 --- a/typescript/frontend-marios2/src/lang/de.json +++ b/typescript/frontend-marios2/src/lang/de.json @@ -588,6 +588,8 @@ "category": "Kategorie", "allStatuses": "Alle Status", "allPartners": "Alle Partner", + "allAssignees": "Alle Zuständigen", + "allCategories": "Alle Kategorien", "createdAt": "Erstellt", "noTickets": "Keine Tickets gefunden.", "backToTickets": "Zurück zu Tickets", diff --git a/typescript/frontend-marios2/src/lang/en.json b/typescript/frontend-marios2/src/lang/en.json index 592e64583..d0a83ae9a 100644 --- a/typescript/frontend-marios2/src/lang/en.json +++ b/typescript/frontend-marios2/src/lang/en.json @@ -336,6 +336,8 @@ "category": "Category", "allStatuses": "All Statuses", "allPartners": "All Partners", + "allAssignees": "All Assignees", + "allCategories": "All Categories", "createdAt": "Created", "noTickets": "No tickets found.", "backToTickets": "Back to Tickets", diff --git a/typescript/frontend-marios2/src/lang/fr.json b/typescript/frontend-marios2/src/lang/fr.json index 895199376..612637034 100644 --- a/typescript/frontend-marios2/src/lang/fr.json +++ b/typescript/frontend-marios2/src/lang/fr.json @@ -588,6 +588,8 @@ "category": "Catégorie", "allStatuses": "Tous les statuts", "allPartners": "Tous les partenaires", + "allAssignees": "Tous les responsables", + "allCategories": "Toutes les catégories", "createdAt": "Créé", "noTickets": "Aucun ticket trouvé.", "backToTickets": "Retour aux tickets", diff --git a/typescript/frontend-marios2/src/lang/it.json b/typescript/frontend-marios2/src/lang/it.json index 22fedbda9..ed9791520 100644 --- a/typescript/frontend-marios2/src/lang/it.json +++ b/typescript/frontend-marios2/src/lang/it.json @@ -588,6 +588,8 @@ "category": "Categoria", "allStatuses": "Tutti gli stati", "allPartners": "Tutti i partner", + "allAssignees": "Tutti gli assegnatari", + "allCategories": "Tutte le categorie", "createdAt": "Creato", "noTickets": "Nessun ticket trovato.", "backToTickets": "Torna ai ticket",