From 81b84a3c53ae89fae4a26b9f1e8026a18b3ead56 Mon Sep 17 00:00:00 2001 From: Nelson Chan <3271800+chakflying@users.noreply.github.com> Date: Tue, 5 Dec 2023 04:04:54 +0800 Subject: [PATCH] Fix: Filtering works with group monitors (again) (#3685) * Fix: Group monitors use nested filtering * Chore: Fix lint --- src/components/MonitorList.vue | 154 ++++++++++++++++------------- src/components/MonitorListItem.vue | 52 +++------- 2 files changed, 102 insertions(+), 104 deletions(-) diff --git a/src/components/MonitorList.vue b/src/components/MonitorList.vue index f8e699470..d662d2b03 100644 --- a/src/components/MonitorList.vue +++ b/src/components/MonitorList.vue @@ -51,11 +51,12 @@ v-for="(item, index) in sortedMonitorList" :key="index" :monitor="item" - :showPathName="filtersActive" :isSelectMode="selectMode" :isSelected="isSelected" :select="select" :deselect="deselect" + :filter-func="filterFunc" + :sort-func="sortFunc" /> @@ -126,75 +127,16 @@ export default { let result = Object.values(this.$root.monitorList); result = result.filter(monitor => { - // filter by search text - // finds monitor name, tag name or tag value - let searchTextMatch = true; - if (this.searchText !== "") { - const loweredSearchText = this.searchText.toLowerCase(); - searchTextMatch = - monitor.name.toLowerCase().includes(loweredSearchText) - || monitor.tags.find(tag => tag.name.toLowerCase().includes(loweredSearchText) - || tag.value?.toLowerCase().includes(loweredSearchText)); + // The root list does not show children + if (monitor.parent !== null) { + return false; } - - // filter by status - let statusMatch = true; - if (this.filterState.status != null && this.filterState.status.length > 0) { - if (monitor.id in this.$root.lastHeartbeatList && this.$root.lastHeartbeatList[monitor.id]) { - monitor.status = this.$root.lastHeartbeatList[monitor.id].status; - } - statusMatch = this.filterState.status.includes(monitor.status); - } - - // filter by active - let activeMatch = true; - if (this.filterState.active != null && this.filterState.active.length > 0) { - activeMatch = this.filterState.active.includes(monitor.active); - } - - // filter by tags - let tagsMatch = true; - if (this.filterState.tags != null && this.filterState.tags.length > 0) { - tagsMatch = monitor.tags.map(tag => tag.tag_id) // convert to array of tag IDs - .filter(monitorTagId => this.filterState.tags.includes(monitorTagId)) // perform Array Intersaction between filter and monitor's tags - .length > 0; - } - - // Hide children if not filtering - let showChild = true; - if (this.filterState.status == null && this.filterState.active == null && this.filterState.tags == null && this.searchText === "") { - if (monitor.parent !== null) { - showChild = false; - } - } - - return searchTextMatch && statusMatch && activeMatch && tagsMatch && showChild; + return true; }); - // Filter result by active state, weight and alphabetical - result.sort((m1, m2) => { - if (m1.active !== m2.active) { - if (m1.active === false) { - return 1; - } + result = result.filter(this.filterFunc); - if (m2.active === false) { - return -1; - } - } - - if (m1.weight !== m2.weight) { - if (m1.weight > m2.weight) { - return -1; - } - - if (m1.weight < m2.weight) { - return 1; - } - } - - return m1.name.localeCompare(m2.name); - }); + result.sort(this.sortFunc); return result; }, @@ -361,6 +303,85 @@ export default { this.cancelSelectMode(); }, + /** + * Whether a monitor should be displayed based on the filters + * @param {object} monitor Monitor to check + * @returns {boolean} Should the monitor be displayed + */ + filterFunc(monitor) { + // Group monitors bypass filter if at least 1 of children matched + if (monitor.type === "group") { + const children = Object.values(this.$root.monitorList).filter(m => m.parent === monitor.id); + if (children.some((child, index, children) => this.filterFunc(child))) { + return true; + } + } + + // filter by search text + // finds monitor name, tag name or tag value + let searchTextMatch = true; + if (this.searchText !== "") { + const loweredSearchText = this.searchText.toLowerCase(); + searchTextMatch = + monitor.name.toLowerCase().includes(loweredSearchText) + || monitor.tags.find(tag => tag.name.toLowerCase().includes(loweredSearchText) + || tag.value?.toLowerCase().includes(loweredSearchText)); + } + + // filter by status + let statusMatch = true; + if (this.filterState.status != null && this.filterState.status.length > 0) { + if (monitor.id in this.$root.lastHeartbeatList && this.$root.lastHeartbeatList[monitor.id]) { + monitor.status = this.$root.lastHeartbeatList[monitor.id].status; + } + statusMatch = this.filterState.status.includes(monitor.status); + } + + // filter by active + let activeMatch = true; + if (this.filterState.active != null && this.filterState.active.length > 0) { + activeMatch = this.filterState.active.includes(monitor.active); + } + + // filter by tags + let tagsMatch = true; + if (this.filterState.tags != null && this.filterState.tags.length > 0) { + tagsMatch = monitor.tags.map(tag => tag.tag_id) // convert to array of tag IDs + .filter(monitorTagId => this.filterState.tags.includes(monitorTagId)) // perform Array Intersaction between filter and monitor's tags + .length > 0; + } + + return searchTextMatch && statusMatch && activeMatch && tagsMatch; + }, + /** + * Function used in Array.sort to order monitors in a list. + * @param {*} m1 monitor 1 + * @param {*} m2 monitor 2 + * @returns {number} -1, 0 or 1 + */ + sortFunc(m1, m2) { + if (m1.active !== m2.active) { + if (m1.active === false) { + return 1; + } + + if (m2.active === false) { + return -1; + } + } + + if (m1.weight !== m2.weight) { + if (m1.weight > m2.weight) { + return -1; + } + + if (m1.weight < m2.weight) { + return 1; + } + } + + return m1.name.localeCompare(m2.name); + } }, }; @@ -458,5 +479,4 @@ export default { align-items: center; gap: 10px; } - diff --git a/src/components/MonitorListItem.vue b/src/components/MonitorListItem.vue index 5b8449686..9b45ae9f2 100644 --- a/src/components/MonitorListItem.vue +++ b/src/components/MonitorListItem.vue @@ -20,7 +20,7 @@ - {{ monitorName }} + {{ monitor.name }}
@@ -44,7 +44,6 @@ {} }, + /** Function to filter child monitors */ + filterFunc: { + type: Function, + default: () => {} + }, + /** Function to sort child monitors */ + sortFunc: { + type: Function, + default: () => {}, + } }, data() { return { @@ -115,32 +119,13 @@ export default { sortedChildMonitorList() { let result = Object.values(this.$root.monitorList); + // Get children result = result.filter(childMonitor => childMonitor.parent === this.monitor.id); - result.sort((m1, m2) => { + // Run filter on children + result = result.filter(this.filterFunc); - if (m1.active !== m2.active) { - if (m1.active === 0) { - return 1; - } - - if (m2.active === 0) { - return -1; - } - } - - if (m1.weight !== m2.weight) { - if (m1.weight > m2.weight) { - return -1; - } - - if (m1.weight < m2.weight) { - return 1; - } - } - - return m1.name.localeCompare(m2.name); - }); + result.sort(this.sortFunc); return result; }, @@ -152,13 +137,6 @@ export default { marginLeft: `${31 * this.depth}px`, }; }, - monitorName() { - if (this.showPathName) { - return this.monitor.pathName; - } else { - return this.monitor.name; - } - } }, watch: { isSelectMode() {