From 9c2359eee5227cda50206201f6086bd6489e25a2 Mon Sep 17 00:00:00 2001 From: Ralph Slooten Date: Sun, 22 Mar 2026 17:40:54 +1300 Subject: [PATCH] Feature: Add filter functionality to message headers tab This implementation is based on, and resolves, #626 --- .../components/message/MessageHeaders.vue | 72 +++++++++++++++++-- 1 file changed, 67 insertions(+), 5 deletions(-) diff --git a/server/ui-src/components/message/MessageHeaders.vue b/server/ui-src/components/message/MessageHeaders.vue index bb5e9d8..c128ee2 100644 --- a/server/ui-src/components/message/MessageHeaders.vue +++ b/server/ui-src/components/message/MessageHeaders.vue @@ -14,27 +14,89 @@ export default { data() { return { headers: false, + filter: "", }; }, + computed: { + filteredHeaders() { + if (this.filter === "") { + return this.headers; + } + const searchWords = this.filter + .toLowerCase() + .split(/\s+/) + .filter((x) => x.length > 0); + + const filtered = {}; + for (const k in this.headers) { + const values = this.headers[k]; + const kLower = k.toLowerCase(); + if (searchWords.every((w) => kLower.includes(w))) { + filtered[k] = values; + } else { + const matchingValues = values.filter((v) => { + const vLower = v.toLowerCase(); + return searchWords.every((w) => vLower.includes(w)); + }); + if (matchingValues.length > 0) { + filtered[k] = matchingValues; + } + } + } + + return filtered; + }, + }, + mounted() { const uri = this.resolve("/api/v1/message/" + this.message.ID + "/headers"); this.get(uri, false, (response) => { this.headers = response.data; }); }, + + methods: { + highlight(text) { + const escaped = text.replace(/&/g, "&").replace(//g, ">"); + if (!this.filter || this.filter.trim() === "") { + return escaped; + } + const words = this.filter + .trim() + .split(/\s+/) + .filter((w) => w.length > 0) + .map((w) => w.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")); + const regex = new RegExp(words.join("|"), "gi"); + return escaped.replace(regex, "$&"); + }, + }, }; -