From 3d4fb163d50a3e188d69f726ac74c9dc4f1b421e Mon Sep 17 00:00:00 2001
From: NihadBadalov <32594553+NihadBadalov@users.noreply.github.com>
Date: Sat, 17 Feb 2024 18:30:39 +0100
Subject: [PATCH] Feat: Handle monitor filter state in URL
---
src/components/MonitorList.vue | 104 +++++++++++++++-----------
src/components/MonitorListFilter.vue | 106 +++++++++++++++------------
2 files changed, 120 insertions(+), 90 deletions(-)
diff --git a/src/components/MonitorList.vue b/src/components/MonitorList.vue
index bdb2b7056..c790c4d95 100644
--- a/src/components/MonitorList.vue
+++ b/src/components/MonitorList.vue
@@ -26,7 +26,7 @@
@@ -95,11 +95,22 @@ export default {
disableSelectAllWatcher: false,
selectedMonitors: {},
windowTop: 0,
- filterState: {
- status: null,
- active: null,
- tags: null,
- }
+ statusStates: {
+ up: 1,
+ down: 0,
+ pending: 2,
+ maintenance: 3,
+ 1: 'up',
+ 0: 'down',
+ 2: 'pending',
+ 3: 'maintenance',
+ },
+ activeStates: {
+ running: true,
+ paused: false,
+ true: 'running',
+ false: 'paused',
+ },
};
},
computed: {
@@ -169,7 +180,7 @@ export default {
* @returns {boolean} True if any filter is active, false otherwise.
*/
filtersActive() {
- return this.filterState.status != null || this.filterState.active != null || this.filterState.tags != null || this.searchText !== "";
+ return this.$router.currentRoute.value.query?.status != null || this.$router.currentRoute.value.query?.active != null || this.$router.currentRoute.value.query?.tags != null || this.searchText !== "";
}
},
watch: {
@@ -207,21 +218,10 @@ export default {
async mounted() {
window.addEventListener("scroll", this.onScroll);
- const statusParams = this.$router.currentRoute.value.query["status"];
- const activeParams = this.$router.currentRoute.value.query["active"];
- const tagParams = this.$router.currentRoute.value.query["tags"];
-
- const statusStates = {
- up: 1,
- down: 0,
- pending: 2,
- maintenance: 3,
- };
-
- const activeStates = {
- running: true,
- paused: false,
- };
+ const queryParams = this.$router.currentRoute.value.query;
+ const statusParams = queryParams?.["status"];
+ const activeParams = queryParams?.["active"];
+ const tagParams = queryParams?.["tags"];
const tags = await (() => {
return new Promise((resolve) => {
@@ -233,24 +233,26 @@ export default {
});
})();
- const fetchedTagIDs = tagParams
- .split(",")
- .map(identifier => {
- const tagID = parseInt(identifier, 10);
- return tags
- .find(t => t.name === identifier || t.id === tagID)
- ?.id ?? 0;
- });
+ const fetchedTagNames = tagParams
+ ? tagParams
+ .split(",")
+ .map(identifier => {
+ const tagID = parseInt(identifier, 10);
+ return tags
+ .find(t => t.name === identifier || t.id === tagID)
+ ?.name ?? 0;
+ })
+ .filter(tagID => tagID !== 0)
+ : undefined;
this.updateFilter({
- ...this.filterState,
status: statusParams ? statusParams.split(",").map(
- status => statusStates[status.trim()]
- ) : this.filterState["status"],
+ status => this.statusStates[this.statusStates[status.trim()]]
+ ) : queryParams?.["status"],
active: activeParams ? activeParams.split(",").map(
- active => activeStates[active.trim()]
- ) : this.filterState["active"],
- tags: tagParams ? fetchedTagIDs : this.filterState["tags"],
+ active => this.activeStates[this.activeStates[active.trim()]]
+ ) : queryParams?.["active"],
+ tags: tagParams ? fetchedTagNames : queryParams?.["tags"],
});
},
beforeUnmount() {
@@ -289,7 +291,20 @@ export default {
* @returns {void}
*/
updateFilter(newFilter) {
- this.filterState = newFilter;
+ const newQuery = { ...this.$router.currentRoute.value.query };
+
+ for (const [key, value] of Object.entries(newFilter)) {
+ if (!value
+ || (value instanceof Array && value.length === 0)) {
+ delete newQuery[key];
+ continue
+ }
+
+ newQuery[key] = value instanceof Array
+ ? value.length > 0 ? value.join(",") : null
+ : value;
+ }
+ this.$router.push({ query: newQuery });
},
/**
* Deselect a monitor
@@ -379,24 +394,25 @@ export default {
// filter by status
let statusMatch = true;
- if (this.filterState.status != null && this.filterState.status.length > 0) {
+ if (this.$router.currentRoute.value.query?.status != null && this.$router.currentRoute.value.query?.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);
+ statusMatch = this.$router.currentRoute.value.query?.status.includes(this.statusStates[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);
+ if (this.$router.currentRoute.value.query?.active != null && this.$router.currentRoute.value.query?.active.length > 0) {
+ activeMatch = this.$router.currentRoute.value.query?.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
+ const tagsInURL = this.$router.currentRoute.value.query?.tags?.split(",") || [];
+ if (this.$router.currentRoute.value.query?.tags != null && this.$router.currentRoute.value.query?.tags.length > 0) {
+ tagsMatch = monitor.tags.map(tag => tag.name) // convert to array of tag names
+ .filter(monitorTagId => tagsInURL.includes(monitorTagId)) // perform Array Intersaction between filter and monitor's tags
.length > 0;
}
diff --git a/src/components/MonitorListFilter.vue b/src/components/MonitorListFilter.vue
index 330efc9be..8262af6b7 100644
--- a/src/components/MonitorListFilter.vue
+++ b/src/components/MonitorListFilter.vue
@@ -14,10 +14,10 @@
-
+
{{ $t('Status') }}
@@ -29,7 +29,7 @@
{{ $root.stats.up }}
-
+
@@ -42,7 +42,7 @@
{{ $root.stats.down }}
-
+
@@ -55,7 +55,7 @@
{{ $root.stats.pending }}
-
+
@@ -68,7 +68,7 @@
{{ $root.stats.maintenance }}
-
+
@@ -77,10 +77,10 @@
-
+
-
- {{ $t("Running") }}
+
+ {{ $t("Running") }}
{{ $t("filterActivePaused") }}
@@ -94,7 +94,7 @@
{{ $t("Running") }}
{{ $root.stats.active }}
-
+
@@ -107,7 +107,7 @@
{{ $t("filterActivePaused") }}
{{ $root.stats.pause }}
-
+
@@ -116,11 +116,11 @@
-
+
@@ -134,7 +134,7 @@
{{ getTaggedMonitorCount(tag) }}
-
+
@@ -162,23 +162,26 @@ export default {
Status,
Tag,
},
- props: {
- filterState: {
- type: Object,
- required: true,
- }
- },
emits: [ "updateFilter" ],
data() {
return {
tagsList: [],
+ filterNames: [
+ 'status',
+ 'active',
+ 'tags',
+ ],
};
},
computed: {
numFiltersActive() {
let num = 0;
- Object.values(this.filterState).forEach(item => {
+ Object.values(
+ Array.from(Object.entries(this.$router.currentRoute.value.query)).filter(
+ e => this.filterNames.includes(e[0])
+ )
+ ).forEach(item => {
if (item != null && item.length > 0) {
num += 1;
}
@@ -191,52 +194,63 @@ export default {
this.getExistingTags();
},
methods: {
+ getActiveFilters: function() {
+ const filters = Object.fromEntries(
+ Array.from(Object.entries(this.$router.currentRoute.value.query ?? {}))
+ );
+
+ return {
+ status: filters['status'] ? filters['status'].split(',') : [],
+ active: filters['active'] ? filters['active'].split(',') : [],
+ tags: filters['tags'] ? filters['tags'].split(',') : [],
+ };
+ },
toggleStatusFilter(status) {
let newFilter = {
- ...this.filterState
+ ...this.getActiveFilters(),
};
- if (newFilter.status == null) {
- newFilter.status = [ status ];
+ const statusStates = {
+ 1: 'up',
+ 0: 'down',
+ 2: 'pending',
+ 3: 'maintenance',
+ };
+
+ const finalStatus = statusStates[status];
+
+ if (newFilter.status.includes(''+finalStatus)) {
+ newFilter.status = newFilter.status.filter(item => item !== ''+finalStatus);
} else {
- if (newFilter.status.includes(status)) {
- newFilter.status = newFilter.status.filter(item => item !== status);
- } else {
- newFilter.status.push(status);
- }
+ newFilter.status.push(finalStatus);
}
+
this.$emit("updateFilter", newFilter);
},
toggleActiveFilter(active) {
let newFilter = {
- ...this.filterState
+ ...this.getActiveFilters(),
};
- if (newFilter.active == null) {
- newFilter.active = [ active ];
+ if (newFilter.active.includes(''+active)) {
+ newFilter.active = newFilter.active.filter(item => item !== ''+active);
} else {
- if (newFilter.active.includes(active)) {
- newFilter.active = newFilter.active.filter(item => item !== active);
- } else {
- newFilter.active.push(active);
- }
+ newFilter.active.push(active);
}
+
this.$emit("updateFilter", newFilter);
},
toggleTagFilter(tag) {
let newFilter = {
- ...this.filterState
+ ...this.getActiveFilters(),
};
- if (newFilter.tags == null) {
- newFilter.tags = [ tag.id ];
+ if (newFilter.tags.includes(''+tag.name)) {
+ newFilter.tags = newFilter.tags.filter(item => item !== ''+tag.name);
} else {
- if (newFilter.tags.includes(tag.id)) {
- newFilter.tags = newFilter.tags.filter(item => item !== tag.id);
- } else {
- newFilter.tags.push(tag.id);
- }
+ newFilter.tags.push(tag.name);
}
+
this.$emit("updateFilter", newFilter);
},
clearFilters() {