From b20ba9cfccd22159bf8263165cca76aab3147d9c Mon Sep 17 00:00:00 2001 From: Mohamed Bassem Date: Tue, 30 Dec 2025 13:29:03 +0200 Subject: feat: add "URL Does Not Contain" condition to rule engine (#2280) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: add "URL Does Not Contain" condition to rule engine Add a new condition type `urlDoesNotContain` that allows users to create rules based on URLs that do NOT contain specific strings. This enables more flexible rule configurations, such as: - Automatically adding bookmarks to a "Read Later" list if the URL does not contain "reddit.com" or "youtube.com" Changes: - Added `urlDoesNotContain` condition type to Zod schema - Implemented evaluation logic in RuleEngine - Added UI support in ConditionBuilder component - Added translation key for new condition type - Added test coverage for the new condition Fixes #2259 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Mohamed Bassem * fix type link --------- Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com> Co-authored-by: Mohamed Bassem --- .../dashboard/rules/RuleEngineConditionBuilder.tsx | 19 +++++++++++++++++++ apps/web/lib/i18n/locales/en/translation.json | 1 + 2 files changed, 20 insertions(+) (limited to 'apps') diff --git a/apps/web/components/dashboard/rules/RuleEngineConditionBuilder.tsx b/apps/web/components/dashboard/rules/RuleEngineConditionBuilder.tsx index 8faca013..a859a4cc 100644 --- a/apps/web/components/dashboard/rules/RuleEngineConditionBuilder.tsx +++ b/apps/web/components/dashboard/rules/RuleEngineConditionBuilder.tsx @@ -54,6 +54,9 @@ export function ConditionBuilder({ case "urlContains": onChange({ type: "urlContains", str: "" }); break; + case "urlDoesNotContain": + onChange({ type: "urlDoesNotContain", str: "" }); + break; case "importedFromFeed": onChange({ type: "importedFromFeed", feedId: "" }); break; @@ -88,6 +91,7 @@ export function ConditionBuilder({ const renderConditionIcon = (type: RuleEngineCondition["type"]) => { switch (type) { case "urlContains": + case "urlDoesNotContain": return ; case "importedFromFeed": return ; @@ -118,6 +122,18 @@ export function ConditionBuilder({ ); + case "urlDoesNotContain": + return ( +
+ onChange({ ...value, str: e.target.value })} + placeholder="URL does not contain..." + className="w-full" + /> +
+ ); + case "importedFromFeed": return (
@@ -235,6 +251,9 @@ export function ConditionBuilder({ {t("settings.rules.conditions_types.url_contains")} + + {t("settings.rules.conditions_types.url_does_not_contain")} + {t("settings.rules.conditions_types.imported_from_feed")} diff --git a/apps/web/lib/i18n/locales/en/translation.json b/apps/web/lib/i18n/locales/en/translation.json index 58e1af09..87851324 100644 --- a/apps/web/lib/i18n/locales/en/translation.json +++ b/apps/web/lib/i18n/locales/en/translation.json @@ -348,6 +348,7 @@ "conditions_types": { "always": "Always", "url_contains": "URL Contains", + "url_does_not_contain": "URL Does Not Contain", "imported_from_feed": "Imported From Feed", "bookmark_type_is": "Bookmark Type Is", "has_tag": "Has Tag", -- cgit v1.2.3-70-g09d2