mirror of
https://github.com/koichixD/uptime-kuma.git
synced 2026-09-04 09:13:21 +00:00
feat(dashboard): add expand/collapse all groups button (#6743)
Co-authored-by: Frank Elsinga <frank@elsinga.de>
This commit is contained in:
co-authored by
Frank Elsinga
parent
a0d73aba1a
commit
bf9b734f6c
@@ -35,7 +35,13 @@
|
||||
:aria-label="selectAll ? $t('deselectAllMonitorsAria') : $t('selectAllMonitorsAria')"
|
||||
/>
|
||||
|
||||
<MonitorListFilter :filterState="filterState" @update-filter="updateFilter" />
|
||||
<MonitorListFilter
|
||||
:filterState="filterState"
|
||||
:allCollapsed="allGroupsCollapsed"
|
||||
:hasGroups="groupMonitors.length >= 2"
|
||||
@update-filter="updateFilter"
|
||||
@toggle-collapse-all="toggleCollapseAll"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -100,8 +106,8 @@
|
||||
</div>
|
||||
|
||||
<MonitorListItem
|
||||
v-for="(item, index) in sortedMonitorList"
|
||||
:key="index"
|
||||
v-for="item in sortedMonitorList"
|
||||
:key="`${item.id}-${collapseKey}`"
|
||||
:monitor="item"
|
||||
:isSelectMode="selectMode"
|
||||
:isSelected="isSelected"
|
||||
@@ -154,6 +160,7 @@ export default {
|
||||
active: null,
|
||||
tags: null,
|
||||
},
|
||||
collapseKey: 0,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -229,6 +236,38 @@ export default {
|
||||
this.searchText !== ""
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets all group monitors at root level that have children
|
||||
* @returns {Array} Array of group monitors with children
|
||||
*/
|
||||
groupMonitors() {
|
||||
const monitors = Object.values(this.$root.monitorList);
|
||||
return monitors.filter(
|
||||
(m) => m.type === "group" && m.parent === null && monitors.some((child) => child.parent === m.id)
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Determines if all groups are collapsed.
|
||||
* Note: collapseKey is included to force re-computation when toggleCollapseAll()
|
||||
* updates localStorage, since Vue cannot detect localStorage changes.
|
||||
* @returns {boolean} True if all groups are collapsed
|
||||
*/
|
||||
allGroupsCollapsed() {
|
||||
// collapseKey forces this computed to re-evaluate after localStorage updates
|
||||
if (this.collapseKey < 0 || this.groupMonitors.length === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const storage = window.localStorage.getItem("monitorCollapsed");
|
||||
if (storage === null) {
|
||||
return true; // Default is collapsed
|
||||
}
|
||||
|
||||
const storageObject = JSON.parse(storage);
|
||||
return this.groupMonitors.every((group) => storageObject[`monitor_${group.id}`] !== false);
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
searchText() {
|
||||
@@ -303,6 +342,26 @@ export default {
|
||||
updateFilter(newFilter) {
|
||||
this.filterState = newFilter;
|
||||
},
|
||||
/**
|
||||
* Toggle collapse state for all group monitors
|
||||
* @returns {void}
|
||||
*/
|
||||
toggleCollapseAll() {
|
||||
const shouldCollapse = !this.allGroupsCollapsed;
|
||||
|
||||
let storageObject = {};
|
||||
const storage = window.localStorage.getItem("monitorCollapsed");
|
||||
if (storage !== null) {
|
||||
storageObject = JSON.parse(storage);
|
||||
}
|
||||
|
||||
this.groupMonitors.forEach((group) => {
|
||||
storageObject[`monitor_${group.id}`] = shouldCollapse;
|
||||
});
|
||||
|
||||
window.localStorage.setItem("monitorCollapsed", JSON.stringify(storageObject));
|
||||
this.collapseKey++;
|
||||
},
|
||||
/**
|
||||
* Deselect a monitor
|
||||
* @param {number} id ID of monitor
|
||||
@@ -731,6 +790,7 @@ export default {
|
||||
.search-input {
|
||||
width: 100%;
|
||||
padding-right: 30px;
|
||||
transition: none !important;
|
||||
}
|
||||
|
||||
.monitor-item {
|
||||
|
||||
@@ -137,6 +137,15 @@
|
||||
</li>
|
||||
</template>
|
||||
</MonitorListFilterDropdown>
|
||||
<button
|
||||
v-if="hasGroups"
|
||||
type="button"
|
||||
class="btn btn-outline-normal btn-collapse-all"
|
||||
:title="allCollapsed ? $t('Expand All Groups') : $t('Collapse All Groups')"
|
||||
@click="$emit('toggle-collapse-all')"
|
||||
>
|
||||
<font-awesome-icon :icon="allCollapsed ? 'folder' : 'folder-open'" fixed-width />
|
||||
</button>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@@ -155,8 +164,16 @@ export default {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
allCollapsed: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
hasGroups: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
emits: ["updateFilter"],
|
||||
emits: ["updateFilter", "toggle-collapse-all"],
|
||||
data() {
|
||||
return {
|
||||
tagsList: [],
|
||||
@@ -322,4 +339,8 @@ export default {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.btn-collapse-all {
|
||||
transition: none !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user