Fix the warning and error

This commit is contained in:
Marshu 2025-06-05 23:18:25 +08:00
parent f9bef48658
commit d6bfd9b952
2 changed files with 170 additions and 116 deletions

View file

@ -1,11 +1,15 @@
<template> <template>
<div v-if="group && group.monitorList && group.monitorList.length > 1" class="sort-dropdown"> <div v-if="group && group.monitorList && group.monitorList.length > 1" class="sort-dropdown">
<div class="dropdown"> <div class="dropdown">
<button :id="'sortDropdown' + groupIndex" type="button" class="btn btn-sm btn-outline-secondary dropdown-toggle sort-button" <button
data-bs-toggle="dropdown" :id="'sortDropdown' + groupIndex"
aria-expanded="false" type="button"
:aria-label="$t('Sort options')" class="btn btn-sm btn-outline-secondary dropdown-toggle sort-button"
:title="$t('Sort options')"> data-bs-toggle="dropdown"
aria-expanded="false"
:aria-label="$t('Sort options')"
:title="$t('Sort options')"
>
<div class="sort-arrows"> <div class="sort-arrows">
<font-awesome-icon <font-awesome-icon
icon="arrow-down" icon="arrow-down"
@ -25,9 +29,13 @@
</button> </button>
<ul class="dropdown-menu dropdown-menu-end sort-menu" :aria-labelledby="'sortDropdown' + groupIndex"> <ul class="dropdown-menu dropdown-menu-end sort-menu" :aria-labelledby="'sortDropdown' + groupIndex">
<li> <li>
<button class="dropdown-item sort-item" type="button" @click="setSort('status')" <button
:aria-label="$t('Sort by status')" class="dropdown-item sort-item"
:title="$t('Sort by status')"> type="button"
:aria-label="$t('Sort by status')"
:title="$t('Sort by status')"
@click="setSort('status')"
>
<div class="sort-item-content"> <div class="sort-item-content">
<span>{{ $t("Status") }}</span> <span>{{ $t("Status") }}</span>
<span v-if="getSortKey() === 'status'" class="sort-indicators"> <span v-if="getSortKey() === 'status'" class="sort-indicators">
@ -40,9 +48,13 @@
</button> </button>
</li> </li>
<li> <li>
<button class="dropdown-item sort-item" type="button" @click="setSort('name')" <button
:aria-label="$t('Sort by name')" class="dropdown-item sort-item"
:title="$t('Sort by name')"> type="button"
:aria-label="$t('Sort by name')"
:title="$t('Sort by name')"
@click="setSort('name')"
>
<div class="sort-item-content"> <div class="sort-item-content">
<span>{{ $t("Name") }}</span> <span>{{ $t("Name") }}</span>
<span v-if="getSortKey() === 'name'" class="sort-indicators"> <span v-if="getSortKey() === 'name'" class="sort-indicators">
@ -55,9 +67,13 @@
</button> </button>
</li> </li>
<li> <li>
<button class="dropdown-item sort-item" type="button" @click="setSort('uptime')" <button
:aria-label="$t('Sort by uptime')" class="dropdown-item sort-item"
:title="$t('Sort by uptime')"> type="button"
:aria-label="$t('Sort by uptime')"
:title="$t('Sort by uptime')"
@click="setSort('uptime')"
>
<div class="sort-item-content"> <div class="sort-item-content">
<span>{{ $t("Uptime") }}</span> <span>{{ $t("Uptime") }}</span>
<span v-if="getSortKey() === 'uptime'" class="sort-indicators"> <span v-if="getSortKey() === 'uptime'" class="sort-indicators">
@ -70,9 +86,13 @@
</button> </button>
</li> </li>
<li v-if="showCertificateExpiry"> <li v-if="showCertificateExpiry">
<button class="dropdown-item sort-item" type="button" @click="setSort('cert')" <button
:aria-label="$t('Sort by certificate expiry')" class="dropdown-item sort-item"
:title="$t('Sort by certificate expiry')"> type="button"
:aria-label="$t('Sort by certificate expiry')"
:title="$t('Sort by certificate expiry')"
@click="setSort('cert')"
>
<div class="sort-item-content"> <div class="sort-item-content">
<span>{{ $t("Cert Exp.") }}</span> <span>{{ $t("Cert Exp.") }}</span>
<span v-if="getSortKey() === 'cert'" class="sort-indicators"> <span v-if="getSortKey() === 'cert'" class="sort-indicators">
@ -109,6 +129,7 @@ export default {
default: false, default: false,
} }
}, },
emits: [ "update-group" ],
computed: { computed: {
/** /**
* Parse sort settings from URL query parameters * Parse sort settings from URL query parameters
@ -117,13 +138,16 @@ export default {
sortSettingsFromURL() { sortSettingsFromURL() {
const sortSettings = {}; const sortSettings = {};
if (this.$route && this.$route.query) { if (this.$route && this.$route.query) {
for (const [key, value] of Object.entries(this.$route.query)) { for (const [ key, value ] of Object.entries(this.$route.query)) {
if (key.startsWith('sort_') && typeof value === 'string') { if (key.startsWith("sort_") && typeof value === "string") {
const groupId = key.replace('sort_', ''); const groupId = key.replace("sort_", "");
const [sortKey, direction] = value.split('_'); const [ sortKey, direction ] = value.split("_");
if (sortKey && ['status', 'name', 'uptime', 'cert'].includes(sortKey) && if (sortKey && [ "status", "name", "uptime", "cert" ].includes(sortKey) &&
direction && ['asc', 'desc'].includes(direction)) { direction && [ "asc", "desc" ].includes(direction)) {
sortSettings[groupId] = { sortKey, direction }; sortSettings[ groupId ] = {
sortKey,
direction
};
} }
} }
} }
@ -153,21 +177,23 @@ export default {
handler(newSortSettings) { handler(newSortSettings) {
if (this.group) { if (this.group) {
const groupId = this.getGroupIdentifier(); const groupId = this.getGroupIdentifier();
const urlSetting = newSortSettings[groupId]; const urlSetting = newSortSettings[ groupId ];
if (urlSetting) { if (urlSetting) {
this.group.sortKey = urlSetting.sortKey; this.updateGroup({
this.group.sortDirection = urlSetting.direction; sortKey: urlSetting.sortKey,
sortDirection: urlSetting.direction
});
} else { } else {
// Set defaults if not in URL // Set defaults if not in URL
if (this.group.sortKey === undefined) { if (this.group.sortKey === undefined) {
this.group.sortKey = "status"; this.updateGroup({ sortKey: "status" });
} }
if (this.group.sortDirection === undefined) { if (this.group.sortDirection === undefined) {
this.group.sortDirection = "asc"; this.updateGroup({ sortDirection: "asc" });
} }
} }
this.applySort(); this.applySort();
} }
}, },
@ -184,6 +210,15 @@ export default {
return this.group.sortKey || "status"; return this.group.sortKey || "status";
}, },
/**
* Update group properties by emitting to parent
* @param {object} updates - object with properties to update
* @returns {void}
*/
updateGroup(updates) {
this.$emit("update-group", this.groupIndex, updates);
},
/** /**
* Set group sort key and direction, then apply sorting * Set group sort key and direction, then apply sorting
* @param {string} key - sort key ('status', 'name', 'uptime', 'cert') * @param {string} key - sort key ('status', 'name', 'uptime', 'cert')
@ -191,10 +226,14 @@ export default {
*/ */
setSort(key) { setSort(key) {
if (this.group.sortKey === key) { if (this.group.sortKey === key) {
this.group.sortDirection = this.group.sortDirection === "asc" ? "desc" : "asc"; this.updateGroup({
sortDirection: this.group.sortDirection === "asc" ? "desc" : "asc"
});
} else { } else {
this.group.sortKey = key; this.updateGroup({
this.group.sortDirection = "asc"; sortKey: key,
sortDirection: "asc"
});
} }
this.applySort(); this.applySort();
@ -206,15 +245,17 @@ export default {
* @returns {void} * @returns {void}
*/ */
updateRouterQuery() { updateRouterQuery() {
if (!this.$router) return; if (!this.$router) {
return;
}
const query = { ...this.$route.query }; const query = { ...this.$route.query };
const groupId = this.getGroupIdentifier(); const groupId = this.getGroupIdentifier();
if (this.group.sortKey && this.group.sortDirection) { if (this.group.sortKey && this.group.sortDirection) {
query[`sort_${groupId}`] = `${this.group.sortKey}_${this.group.sortDirection}`; query[ `sort_${ groupId }` ] = `${ this.group.sortKey }_${ this.group.sortDirection }`;
} else { } else {
delete query[`sort_${groupId}`]; delete query[ `sort_${ groupId }` ];
} }
this.$router.push({ query }).catch(() => {}); this.$router.push({ query }).catch(() => {});
@ -232,72 +273,74 @@ export default {
const sortKey = this.group.sortKey || "status"; const sortKey = this.group.sortKey || "status";
const sortDirection = this.group.sortDirection || "desc"; const sortDirection = this.group.sortDirection || "desc";
this.group.monitorList.sort((a, b) => { this.updateGroup({
if (!a || !b) { monitorList: [ ...this.group.monitorList ].sort((a, b) => {
return 0; if (!a || !b) {
} return 0;
}
let comparison = 0; let comparison = 0;
let valueA; let valueA;
let valueB; let valueB;
if (sortKey === "status") { if (sortKey === "status") {
// Sort by status // Sort by status
const getStatusPriority = (monitor) => { const getStatusPriority = (monitor) => {
if (!monitor || !monitor.id) { if (!monitor || !monitor.id) {
return 4; return 4;
} }
const hbList = this.$root.heartbeatList || {}; const hbList = this.$root.heartbeatList || {};
const hbArr = hbList[monitor.id]; const hbArr = hbList[ monitor.id ];
if (hbArr && hbArr.length > 0) { if (hbArr && hbArr.length > 0) {
const lastStatus = hbArr.at(-1).status; const lastStatus = hbArr.at(-1).status;
if (lastStatus === 0) { if (lastStatus === 0) {
return 0; return 0;
} // Down } // Down
if (lastStatus === 1) { if (lastStatus === 1) {
return 1; return 1;
} // Up } // Up
if (lastStatus === 2) { if (lastStatus === 2) {
return 2; return 2;
} // Pending } // Pending
if (lastStatus === 3) { if (lastStatus === 3) {
return 3; return 3;
} // Maintenance } // Maintenance
} }
return 4; // Unknown/No data return 4; // Unknown/No data
}; };
valueA = getStatusPriority(a); valueA = getStatusPriority(a);
valueB = getStatusPriority(b); valueB = getStatusPriority(b);
} else if (sortKey === "name") { } else if (sortKey === "name") {
// Sort alphabetically by name // Sort alphabetically by name
valueA = a.name ? a.name.toLowerCase() : ""; valueA = a.name ? a.name.toLowerCase() : "";
valueB = b.name ? b.name.toLowerCase() : ""; valueB = b.name ? b.name.toLowerCase() : "";
} else if (sortKey === "uptime") { } else if (sortKey === "uptime") {
// Sort by uptime // Sort by uptime
const uptimeList = this.$root.uptimeList || {}; const uptimeList = this.$root.uptimeList || {};
const uptimeA = a.id ? parseFloat(uptimeList[`${a.id}_24`]) || 0 : 0; const uptimeA = a.id ? parseFloat(uptimeList[ `${ a.id }_24` ]) || 0 : 0;
const uptimeB = b.id ? parseFloat(uptimeList[`${b.id}_24`]) || 0 : 0; const uptimeB = b.id ? parseFloat(uptimeList[ `${ b.id }_24` ]) || 0 : 0;
valueA = uptimeA; valueA = uptimeA;
valueB = uptimeB; valueB = uptimeB;
} else if (sortKey === "cert") { } else if (sortKey === "cert") {
// Sort by certificate expiry time // Sort by certificate expiry time
valueA = a.validCert && a.certExpiryDaysRemaining ? a.certExpiryDaysRemaining : -1; valueA = a.validCert && a.certExpiryDaysRemaining ? a.certExpiryDaysRemaining : -1;
valueB = b.validCert && b.certExpiryDaysRemaining ? b.certExpiryDaysRemaining : -1; valueB = b.validCert && b.certExpiryDaysRemaining ? b.certExpiryDaysRemaining : -1;
} }
if (valueA < valueB) { if (valueA < valueB) {
comparison = -1; comparison = -1;
} else if (valueA > valueB) { } else if (valueA > valueB) {
comparison = 1; comparison = 1;
} }
// Special handling for status sorting // Special handling for status sorting
if (sortKey === "status") { if (sortKey === "status") {
return sortDirection === "desc" ? (comparison * -1) : comparison; return sortDirection === "desc" ? (comparison * -1) : comparison;
} else { } else {
return sortDirection === "asc" ? comparison : (comparison * -1); return sortDirection === "asc" ? comparison : (comparison * -1);
} }
})
}); });
}, },
@ -313,7 +356,7 @@ export default {
return cleanName; return cleanName;
} }
// Fallback to ID or index // Fallback to ID or index
return this.group.id ? `group${this.group.id}` : `group${this.groupIndex}`; return this.group.id ? `group${ this.group.id }` : `group${ this.groupIndex }`;
} }
} }
}; };
@ -347,16 +390,16 @@ export default {
border: none; border: none;
outline: none; outline: none;
} }
.dark & { .dark & {
background-color: $dark-bg; background-color: $dark-bg;
color: $dark-font-color; color: $dark-font-color;
box-shadow: 0 15px 70px rgba(0, 0, 0, 0.3); box-shadow: 0 15px 70px rgba(0, 0, 0, 0.3);
&:hover { &:hover {
background-color: $dark-bg2; background-color: $dark-bg2;
} }
&:focus, &:active { &:focus, &:active {
box-shadow: 0 15px 70px rgba(0, 0, 0, 0.3); box-shadow: 0 15px 70px rgba(0, 0, 0, 0.3);
} }
@ -376,7 +419,7 @@ export default {
color: #aaa; color: #aaa;
font-size: 0.7rem; font-size: 0.7rem;
opacity: 0.5; opacity: 0.5;
.dark & { .dark & {
color: #6c757d; color: #6c757d;
} }
@ -385,7 +428,7 @@ export default {
.arrow-active { .arrow-active {
color: #4caf50; color: #4caf50;
font-size: 0.8rem; font-size: 0.8rem;
.dark & { .dark & {
color: $primary; color: $primary;
} }
@ -399,7 +442,7 @@ export default {
border: none; border: none;
box-shadow: 0 15px 70px rgba(0, 0, 0, 0.1); box-shadow: 0 15px 70px rgba(0, 0, 0, 0.1);
overflow: hidden; overflow: hidden;
.dark & { .dark & {
background-color: $dark-bg; background-color: $dark-bg;
color: $dark-font-color; color: $dark-font-color;
@ -419,10 +462,10 @@ export default {
&:hover { &:hover {
background-color: #f8f9fa; background-color: #f8f9fa;
} }
.dark & { .dark & {
color: $dark-font-color; color: $dark-font-color;
&:hover { &:hover {
background-color: $dark-bg2; background-color: $dark-bg2;
} }
@ -442,4 +485,4 @@ export default {
align-items: center; align-items: center;
margin-left: 10px; margin-left: 10px;
} }
</style> </style>

View file

@ -11,15 +11,16 @@
<!-- Group Title --> <!-- Group Title -->
<h2 class="group-title"> <h2 class="group-title">
<div class="title-section"> <div class="title-section">
<font-awesome-icon v-if="editMode && showGroupDrag" icon="arrows-alt-v" class="action drag me-3" /> <font-awesome-icon v-if="editMode && showGroupDrag" icon="arrows-alt-v" class="action drag me-3" />
<font-awesome-icon v-if="editMode" icon="times" class="action remove me-3" @click="removeGroup(group.index)" /> <font-awesome-icon v-if="editMode" icon="times" class="action remove me-3" @click="removeGroup(group.index)" />
<Editable v-model="group.element.name" :contenteditable="editMode" tag="span" data-testid="group-name" /> <Editable v-model="group.element.name" :contenteditable="editMode" tag="span" data-testid="group-name" />
</div> </div>
<GroupSortDropdown <GroupSortDropdown
:group="group.element" :group="group.element"
:group-index="group.index" :group-index="group.index"
:show-certificate-expiry="showCertificateExpiry" :show-certificate-expiry="showCertificateExpiry"
@update-group="updateGroup"
/> />
</h2> </h2>
@ -206,6 +207,16 @@ export default {
return "#DC2626"; return "#DC2626";
}, },
/**
* Update group properties
* @param {number} groupIndex Index of group to update
* @param {object} updates Object with properties to update
* @returns {void}
*/
updateGroup(groupIndex, updates) {
Object.assign(this.$root.publicGroupList[groupIndex], updates);
},
/** /**
* Get unique identifier for a group * Get unique identifier for a group
* @param {object} group object * @param {object} group object