Feature: extended filter rules — attachment field + multi-value conditions
Adds an "Attachment" condition field (is present / of type <ext>) backed by the RFC 5703 Sieve mime extension, matching the filename in both Content-Disposition and Content-Type headers so real-world senders that only put the name in Content-Type (Microsoft SMTPSVC, etc.) are caught. Users type extensions (pdf, doc) not MIME types. Also makes each text condition accept comma-separated multiple values emitted as a Sieve string list (OR within the condition), so "(domain1 OR domain2) AND attachment pdf/xml" is expressible in one rule. value is now string | string[] (single-value rules stay strings -> backward compatible). New filter locale keys in all 17 locales.
This commit is contained in:
@@ -36,7 +36,17 @@ function RuleSummary({ rule }: { rule: FilterRule }) {
|
||||
const conditions = rule.conditions.slice(0, 2).map((c) => {
|
||||
const field = t(`condition_fields.${c.field}`);
|
||||
const comparator = t(`comparators.${c.comparator}`);
|
||||
return `${field} ${comparator} "${c.value}"`;
|
||||
// has_any is a no-value test ("attachment is present"); appending
|
||||
// `""` would look broken in the summary line.
|
||||
if (c.field === "attachment" && c.comparator === "has_any") {
|
||||
return `${field} ${comparator}`;
|
||||
}
|
||||
// Multi-value conditions render as "a" / "b" / "c" with the locale's
|
||||
// OR-glue between items so the line still reads as natural language.
|
||||
const valueStr = Array.isArray(c.value)
|
||||
? c.value.map((v) => `"${v}"`).join(` ${t("or")} `)
|
||||
: `"${c.value}"`;
|
||||
return `${field} ${comparator} ${valueStr}`;
|
||||
});
|
||||
|
||||
const joiner = rule.matchType === "all" ? t("and") : t("or");
|
||||
@@ -97,7 +107,22 @@ function VisualRuleSummary({ rule }: { rule: FilterRule }) {
|
||||
<span className="inline-flex items-baseline gap-1 px-1.5 py-px rounded-sm bg-muted/60 text-foreground">
|
||||
<span className="font-medium text-blue-600 dark:text-blue-400">{field}</span>
|
||||
<span className="text-muted-foreground">{comparator}</span>
|
||||
<span className="text-foreground">“{c.value}”</span>
|
||||
{!(c.field === "attachment" && c.comparator === "has_any") && (
|
||||
<span className="text-foreground">
|
||||
{Array.isArray(c.value)
|
||||
? c.value.map((v, k) => (
|
||||
<span key={k}>
|
||||
{k > 0 && (
|
||||
<span className="text-muted-foreground/70 italic mx-0.5">
|
||||
{t("or")}
|
||||
</span>
|
||||
)}
|
||||
“{v}”
|
||||
</span>
|
||||
))
|
||||
: <>“{c.value}”</>}
|
||||
</span>
|
||||
)}
|
||||
</span>
|
||||
</span>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user