From 39da894598d83bc4bf80d6a34e582284464b39c8 Mon Sep 17 00:00:00 2001
From: Ionys <9364594+Ionys320@users.noreply.github.com>
Date: Sat, 14 Dec 2024 22:43:16 +0100
Subject: [PATCH 1/5] feat(search): Enhance search by filtering by URLs

---
 src/components/MonitorList.vue | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/components/MonitorList.vue b/src/components/MonitorList.vue
index a579316b3..a69389e54 100644
--- a/src/components/MonitorList.vue
+++ b/src/components/MonitorList.vue
@@ -327,6 +327,7 @@ export default {
                 const loweredSearchText = this.searchText.toLowerCase();
                 searchTextMatch =
                     monitor.name.toLowerCase().includes(loweredSearchText)
+                    || monitor.url?.toLowerCase().includes(loweredSearchText)
                     || monitor.tags.find(tag => tag.name.toLowerCase().includes(loweredSearchText)
                         || tag.value?.toLowerCase().includes(loweredSearchText));
             }

From 08a45637c8295caf16e542a0e547fea217e72015 Mon Sep 17 00:00:00 2001
From: Ionys <9364594+Ionys320@users.noreply.github.com>
Date: Sat, 14 Dec 2024 22:51:19 +0100
Subject: [PATCH 2/5] feat(search): Enhance search by filtering with `hostname`
 and `dns_resolve_server`

---
 src/components/MonitorList.vue | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/components/MonitorList.vue b/src/components/MonitorList.vue
index a69389e54..43196a11d 100644
--- a/src/components/MonitorList.vue
+++ b/src/components/MonitorList.vue
@@ -328,6 +328,8 @@ export default {
                 searchTextMatch =
                     monitor.name.toLowerCase().includes(loweredSearchText)
                     || monitor.url?.toLowerCase().includes(loweredSearchText)
+                    || monitor.hostname?.toLowerCase().includes(loweredSearchText)
+                    || monitor.dns_resolve_server?.toLowerCase().includes(loweredSearchText)
                     || monitor.tags.find(tag => tag.name.toLowerCase().includes(loweredSearchText)
                         || tag.value?.toLowerCase().includes(loweredSearchText));
             }

From 1e0342949fdec594838a212835cb6470879db5ec Mon Sep 17 00:00:00 2001
From: Ionys <9364594+Ionys320@users.noreply.github.com>
Date: Sun, 22 Dec 2024 10:40:33 +0100
Subject: [PATCH 3/5] feat(monitors search): Use regex instead of `LowerCase`

Except with less than 20 monitors, regex seems faster.
---
 src/components/MonitorList.vue | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/src/components/MonitorList.vue b/src/components/MonitorList.vue
index 43196a11d..9dab5e28a 100644
--- a/src/components/MonitorList.vue
+++ b/src/components/MonitorList.vue
@@ -324,14 +324,14 @@ export default {
             // finds monitor name, tag name or tag value
             let searchTextMatch = true;
             if (this.searchText !== "") {
-                const loweredSearchText = this.searchText.toLowerCase();
+                const regex = new RegExp(this.searchText, "i");
+
                 searchTextMatch =
-                    monitor.name.toLowerCase().includes(loweredSearchText)
-                    || monitor.url?.toLowerCase().includes(loweredSearchText)
-                    || monitor.hostname?.toLowerCase().includes(loweredSearchText)
-                    || monitor.dns_resolve_server?.toLowerCase().includes(loweredSearchText)
-                    || monitor.tags.find(tag => tag.name.toLowerCase().includes(loweredSearchText)
-                        || tag.value?.toLowerCase().includes(loweredSearchText));
+                    regex.test(monitor.name) ||
+                    regex.test(monitor.url) ||
+                    regex.test(monitor.hostname) ||
+                    regex.test(monitor.dns_resolve_server) ||
+                    monitor.tags.find((tag) => regex.test(tag.name) || regex.test(tag.value));
             }
 
             // filter by status

From d0d03c05d6a4fdd6bf7513f7470a6e7ac2ab2595 Mon Sep 17 00:00:00 2001
From: Ionys <9364594+Ionys320@users.noreply.github.com>
Date: Sun, 22 Dec 2024 11:24:36 +0100
Subject: [PATCH 4/5] fix(monitors search): Correctly handle
 null/undefined/empty values. Also optimize a bit search tags by replacing
 `.find` with `.some`.

Thanks @homelab-alpha
---
 src/components/MonitorList.vue | 21 ++++++++++++++-------
 1 file changed, 14 insertions(+), 7 deletions(-)

diff --git a/src/components/MonitorList.vue b/src/components/MonitorList.vue
index 9dab5e28a..34074afab 100644
--- a/src/components/MonitorList.vue
+++ b/src/components/MonitorList.vue
@@ -324,14 +324,21 @@ export default {
             // finds monitor name, tag name or tag value
             let searchTextMatch = true;
             if (this.searchText !== "") {
-                const regex = new RegExp(this.searchText, "i");
+                try {
+                    const regex = new RegExp(this.searchText, "i"); // "i" for case-insensitive matching
 
-                searchTextMatch =
-                    regex.test(monitor.name) ||
-                    regex.test(monitor.url) ||
-                    regex.test(monitor.hostname) ||
-                    regex.test(monitor.dns_resolve_server) ||
-                    monitor.tags.find((tag) => regex.test(tag.name) || regex.test(tag.value));
+                    const safeRegexTest = (str) => str && regex.test(str);
+
+                    searchTextMatch =
+                        regex.test(monitor.name) ||
+                        safeRegexTest(monitor.url) ||
+                        safeRegexTest(monitor.hostname) ||
+                        safeRegexTest(monitor.dns_resolve_server) ||
+                        monitor.tags.some(tag => regex.test(tag.name) || safeRegexTest(tag.value));
+                } catch (e) {
+                    console.error("Invalid regex pattern:", e);
+                    searchTextMatch = false;
+                }
             }
 
             // filter by status

From c0d7171dbf637f70694586bcb405841378392956 Mon Sep 17 00:00:00 2001
From: Ionys <9364594+Ionys320@users.noreply.github.com>
Date: Mon, 23 Dec 2024 12:08:35 +0100
Subject: [PATCH 5/5] fix(monitors search): Make sure regex expressions are
 escaped.

This can be reverted if the search should be regex friendly, but for the moment, it's not the case.
Thanks @homelab-alpha!
---
 src/components/MonitorList.vue | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/src/components/MonitorList.vue b/src/components/MonitorList.vue
index 34074afab..80a47ae6e 100644
--- a/src/components/MonitorList.vue
+++ b/src/components/MonitorList.vue
@@ -325,7 +325,11 @@ export default {
             let searchTextMatch = true;
             if (this.searchText !== "") {
                 try {
-                    const regex = new RegExp(this.searchText, "i"); // "i" for case-insensitive matching
+                    // Escape special characters for use in the regular expression
+                    const escapeRegExp = (string) => string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
+
+                    const escapedSearchText = escapeRegExp(this.searchText);
+                    const regex = new RegExp(escapedSearchText, "i");
 
                     const safeRegexTest = (str) => str && regex.test(str);