From 23498e41349be8f4739051e58e4e6e880657b0f1 Mon Sep 17 00:00:00 2001 From: Marshu Date: Sun, 23 Nov 2025 12:38:09 +0800 Subject: [PATCH] feat: add sorting to status pages (#5766) --- src/components/GroupSortDropdown.vue | 487 +++++++++++++++++++++++++++ src/components/PublicGroupList.vue | 71 +++- src/icon.js | 5 +- 3 files changed, 553 insertions(+), 10 deletions(-) create mode 100644 src/components/GroupSortDropdown.vue diff --git a/src/components/GroupSortDropdown.vue b/src/components/GroupSortDropdown.vue new file mode 100644 index 000000000..8ba224652 --- /dev/null +++ b/src/components/GroupSortDropdown.vue @@ -0,0 +1,487 @@ + + + + + diff --git a/src/components/PublicGroupList.vue b/src/components/PublicGroupList.vue index 2dd57e860..5b7e859fa 100644 --- a/src/components/PublicGroupList.vue +++ b/src/components/PublicGroupList.vue @@ -10,9 +10,18 @@

- - - +
+ + + +
+ +

@@ -87,6 +96,7 @@ import Draggable from "vuedraggable"; import HeartbeatBar from "./HeartbeatBar.vue"; import Uptime from "./Uptime.vue"; import Tag from "./Tag.vue"; +import GroupSortDropdown from "./GroupSortDropdown.vue"; export default { components: { @@ -95,6 +105,7 @@ export default { HeartbeatBar, Uptime, Tag, + GroupSortDropdown, }, props: { /** Are we in edit mode? */ @@ -113,7 +124,6 @@ export default { }, data() { return { - }; }, computed: { @@ -121,8 +131,11 @@ export default { return (this.$root.publicGroupList.length >= 2); } }, + watch: { + // No watchers needed - sorting is handled by GroupSortDropdown component + }, created() { - + // Sorting is now handled by GroupSortDropdown component }, methods: { /** @@ -136,8 +149,7 @@ export default { /** * Remove a monitor from a group - * @param {number} groupIndex Index of group to remove monitor - * from + * @param {number} groupIndex Index of group to remove monitor from * @param {number} index Index of monitor to remove * @returns {void} */ @@ -158,7 +170,9 @@ export default { // We must check if there are any elements in monitorList to // prevent undefined errors if it hasn't been loaded yet if (this.$parent.editMode && ignoreSendUrl && Object.keys(this.$root.monitorList).length) { - return this.$root.monitorList[monitor.element.id].type === "http" || this.$root.monitorList[monitor.element.id].type === "keyword" || this.$root.monitorList[monitor.element.id].type === "json-query"; + return this.$root.monitorList[monitor.element.id].type === "http" || + this.$root.monitorList[monitor.element.id].type === "keyword" || + this.$root.monitorList[monitor.element.id].type === "json-query"; } return monitor.element.sendUrl && monitor.element.url && monitor.element.url !== "https://"; }, @@ -189,6 +203,32 @@ export default { } 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 + * @param {object} group object + * @returns {string} group identifier + */ + getGroupIdentifier(group) { + // Use the name directly if available + if (group.name) { + // Only remove spaces and use encodeURIComponent for URL safety + const cleanName = group.name.replace(/\s+/g, ""); + return cleanName; + } + // Fallback to ID or index + return group.id ? `group${group.id}` : `group${this.$root.publicGroupList.indexOf(group)}`; + } } }; @@ -250,6 +290,15 @@ export default { } .group-title { + display: flex; + justify-content: space-between; + align-items: center; + + .title-section { + display: flex; + align-items: center; + } + span { display: inline-block; min-width: 15px; @@ -260,10 +309,14 @@ export default { .item { padding: 13px 0 10px; } + + .group-title { + flex-direction: column; + align-items: flex-start; + } } .bg-maintenance { background-color: $maintenance; } - diff --git a/src/icon.js b/src/icon.js index 7bdfe1ca0..fc50c8a1e 100644 --- a/src/icon.js +++ b/src/icon.js @@ -8,6 +8,8 @@ import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome"; // 2) add the icon name to the library.add() statement below. import { faArrowAltCircleUp, + faArrowDown, + faArrowUp, faCog, faEdit, faEye, @@ -54,6 +56,8 @@ import { library.add( faArrowAltCircleUp, + faArrowDown, + faArrowUp, faCog, faEdit, faEye, @@ -100,4 +104,3 @@ library.add( ); export { FontAwesomeIcon }; -