diff --git a/app/admin/sync/mimecast/page.tsx b/app/admin/sync/mimecast/page.tsx index 5fb4c8d..f509dc5 100644 --- a/app/admin/sync/mimecast/page.tsx +++ b/app/admin/sync/mimecast/page.tsx @@ -1107,7 +1107,12 @@ function analyzeDelivered(m: any): { headline: string; explanation: string; seve }; } -function DeliveredAnalysisDialog({ message, onClose }: { message: any; onClose: () => void }) { +function DeliveredAnalysisDialog({ message, onClose, onFindSimilar, allMessages }: { + message: any; + onClose: () => void; + onFindSimilar?: (type: 'sender' | 'ip' | 'subject', value: string) => void; + allMessages?: any[]; +}) { if (!message) return null; const analysis = analyzeDelivered(message); @@ -1214,6 +1219,58 @@ function DeliveredAnalysisDialog({ message, onClose }: { message: any; onClose: + {/* Cluster context — show how many other messages match sender/IP in current results */} + {onFindSimilar && allMessages && allMessages.length > 1 && (() => { + const sameFrom = allMessages.filter(x => x.from === message.from && x.id !== message.id); + const sameIP = message.senderIP ? allMessages.filter(x => x.senderIP === message.senderIP && x.id !== message.id) : []; + const subjectWords = (message.subject ?? '').split(/\s+/).slice(0, 5).join(' '); + const sameSubject = subjectWords.length > 8 ? allMessages.filter(x => x.id !== message.id && (x.subject ?? '').startsWith(subjectWords)) : []; + const hasClusters = sameFrom.length > 0 || sameIP.length > 0 || sameSubject.length > 0; + if (!hasClusters) return null; + return ( +
Pattern matches in current results
+Repeated senders
+Repeated sending IPs
+Repeated subject patterns
+