feat: implement sorting and search with UI and logic enhancements

- Add global/group sorting with status bar
- Implement global search functionality
- Adjust sort/search layout and positioning
- Add certificate expiration label support
- Apply language adaptation and background styling
- Add canonical annotations
This commit is contained in:
Marshu 2025-04-09 19:20:25 +08:00 committed by ehaoyue
parent 4b0a3df226
commit 4fdeba8cb0
5 changed files with 1185 additions and 44 deletions

File diff suppressed because it is too large Load diff

View file

@ -20,8 +20,8 @@ import {
faTachometerAlt, faTachometerAlt,
faTimes, faTimes,
faTimesCircle, faTimesCircle,
faTrash,
faCheckCircle, faCheckCircle,
faTrash,
faStream, faStream,
faSave, faSave,
faExclamationCircle, faExclamationCircle,
@ -50,6 +50,8 @@ import {
faInfoCircle, faInfoCircle,
faClone, faClone,
faCertificate, faCertificate,
faArrowUp,
faArrowDown,
} from "@fortawesome/free-solid-svg-icons"; } from "@fortawesome/free-solid-svg-icons";
library.add( library.add(
@ -66,8 +68,8 @@ library.add(
faTachometerAlt, faTachometerAlt,
faTimes, faTimes,
faTimesCircle, faTimesCircle,
faTrash,
faCheckCircle, faCheckCircle,
faTrash,
faStream, faStream,
faSave, faSave,
faExclamationCircle, faExclamationCircle,
@ -97,6 +99,8 @@ library.add(
faInfoCircle, faInfoCircle,
faClone, faClone,
faCertificate, faCertificate,
faArrowUp,
faArrowDown,
); );
export { FontAwesomeIcon }; export { FontAwesomeIcon };

View file

@ -48,6 +48,7 @@
"Current": "Current", "Current": "Current",
"Uptime": "Uptime", "Uptime": "Uptime",
"Cert Exp.": "Cert Exp.", "Cert Exp.": "Cert Exp.",
"Sort By": "Sort By",
"Monitor": "Monitor | Monitors", "Monitor": "Monitor | Monitors",
"now": "now", "now": "now",
"time ago": "{0} ago", "time ago": "{0} ago",

View file

@ -27,6 +27,7 @@
"notificationDescription": "通知必须被分配给监控项才能正常工作。", "notificationDescription": "通知必须被分配给监控项才能正常工作。",
"keywordDescription": "在纯 HTML 或 JSON 响应中搜索关键字,区分大小写。", "keywordDescription": "在纯 HTML 或 JSON 响应中搜索关键字,区分大小写。",
"pauseDashboardHome": "暂停", "pauseDashboardHome": "暂停",
"Sort By": "排序方式",
"deleteMonitorMsg": "确定要删除此监控项吗?", "deleteMonitorMsg": "确定要删除此监控项吗?",
"deleteMaintenanceMsg": "确定要删除此维护吗?", "deleteMaintenanceMsg": "确定要删除此维护吗?",
"deleteNotificationMsg": "确定要为所有监控项删除此通知吗?", "deleteNotificationMsg": "确定要为所有监控项删除此通知吗?",
@ -1117,5 +1118,7 @@
"wayToGetWahaApiKey": "API 密钥是你用于运行 WAHA 的 WHATSAPP_API_KEY 环境变量值。", "wayToGetWahaApiKey": "API 密钥是你用于运行 WAHA 的 WHATSAPP_API_KEY 环境变量值。",
"telegramTemplateFormatDescription": "Telegram 允许在消息中使用不同的标记语言,具体细节请参见 Telegram {0}。", "telegramTemplateFormatDescription": "Telegram 允许在消息中使用不同的标记语言,具体细节请参见 Telegram {0}。",
"YZJ Webhook URL": "YZJ Webhook 地址", "YZJ Webhook URL": "YZJ Webhook 地址",
"YZJ Robot Token": "YZJ 机器人令牌" "YZJ Robot Token": "YZJ 机器人令牌",
"Search...": "搜索...",
"No services found": "未找到服务"
} }

View file

@ -328,7 +328,7 @@
👀 {{ $t("statusPageNothing") }} 👀 {{ $t("statusPageNothing") }}
</div> </div>
<PublicGroupList :edit-mode="enableEditMode" :show-tags="config.showTags" :show-certificate-expiry="config.showCertificateExpiry" /> <PublicGroupList :edit-mode="enableEditMode" :show-tags="config.showTags" :show-certificate-expiry="config.showCertificateExpiry" :slug="slug" />
</div> </div>
<footer class="mt-5 mb-4"> <footer class="mt-5 mb-4">
@ -773,10 +773,26 @@ export default {
if (! this.editMode) { if (! this.editMode) {
axios.get("/api/status-page/heartbeat/" + this.slug).then((res) => { axios.get("/api/status-page/heartbeat/" + this.slug).then((res) => {
const { heartbeatList, uptimeList } = res.data; const { heartbeatList, uptimeList } = res.data;
this.$root.heartbeatList = heartbeatList; this.$root.heartbeatList = heartbeatList;
this.$root.uptimeList = uptimeList; this.$root.uptimeList = uptimeList;
if (!this.enableEditMode) {
this.$root.publicGroupList.forEach((group) => {
const downs = [];
const others = [];
// Traverse all monitors in the current group
for (const monitor of group.monitorList) {
const hbArr = heartbeatList[monitor.id];
// Check if the last heartbeat status is Down (status === 0)
if (hbArr && hbArr.length > 0 && hbArr.at(-1).status === 0) {
downs.push(monitor);
} else {
others.push(monitor);
}
}
// Place Down monitors at the front, keep the original order for others
group.monitorList = downs.concat(others);
});
}
const heartbeatIds = Object.keys(heartbeatList); const heartbeatIds = Object.keys(heartbeatList);
const downMonitors = heartbeatIds.reduce((downMonitorsAmount, currentId) => { const downMonitors = heartbeatIds.reduce((downMonitorsAmount, currentId) => {
const monitorHeartbeats = heartbeatList[currentId]; const monitorHeartbeats = heartbeatList[currentId];