feat(dashboard): add expand/collapse all groups button (#6743)
Co-authored-by: Frank Elsinga <frank@elsinga.de>
This commit is contained in:
parent
a0d73aba1a
commit
bf9b734f6c
@ -35,7 +35,13 @@
|
|||||||
:aria-label="selectAll ? $t('deselectAllMonitorsAria') : $t('selectAllMonitorsAria')"
|
: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>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -100,8 +106,8 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<MonitorListItem
|
<MonitorListItem
|
||||||
v-for="(item, index) in sortedMonitorList"
|
v-for="item in sortedMonitorList"
|
||||||
:key="index"
|
:key="`${item.id}-${collapseKey}`"
|
||||||
:monitor="item"
|
:monitor="item"
|
||||||
:isSelectMode="selectMode"
|
:isSelectMode="selectMode"
|
||||||
:isSelected="isSelected"
|
:isSelected="isSelected"
|
||||||
@ -154,6 +160,7 @@ export default {
|
|||||||
active: null,
|
active: null,
|
||||||
tags: null,
|
tags: null,
|
||||||
},
|
},
|
||||||
|
collapseKey: 0,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@ -229,6 +236,38 @@ export default {
|
|||||||
this.searchText !== ""
|
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: {
|
watch: {
|
||||||
searchText() {
|
searchText() {
|
||||||
@ -303,6 +342,26 @@ export default {
|
|||||||
updateFilter(newFilter) {
|
updateFilter(newFilter) {
|
||||||
this.filterState = 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
|
* Deselect a monitor
|
||||||
* @param {number} id ID of monitor
|
* @param {number} id ID of monitor
|
||||||
@ -731,6 +790,7 @@ export default {
|
|||||||
.search-input {
|
.search-input {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding-right: 30px;
|
padding-right: 30px;
|
||||||
|
transition: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.monitor-item {
|
.monitor-item {
|
||||||
|
|||||||
@ -137,6 +137,15 @@
|
|||||||
</li>
|
</li>
|
||||||
</template>
|
</template>
|
||||||
</MonitorListFilterDropdown>
|
</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>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@ -155,8 +164,16 @@ export default {
|
|||||||
type: Object,
|
type: Object,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
|
allCollapsed: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
},
|
},
|
||||||
emits: ["updateFilter"],
|
hasGroups: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
emits: ["updateFilter", "toggle-collapse-all"],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
tagsList: [],
|
tagsList: [],
|
||||||
@ -322,4 +339,8 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.btn-collapse-all {
|
||||||
|
transition: none !important;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -53,6 +53,8 @@ import {
|
|||||||
faInfoCircle,
|
faInfoCircle,
|
||||||
faClone,
|
faClone,
|
||||||
faCertificate,
|
faCertificate,
|
||||||
|
faFolder,
|
||||||
|
faFolderOpen,
|
||||||
} from "@fortawesome/free-solid-svg-icons";
|
} from "@fortawesome/free-solid-svg-icons";
|
||||||
|
|
||||||
library.add(
|
library.add(
|
||||||
@ -103,6 +105,8 @@ library.add(
|
|||||||
faInfoCircle,
|
faInfoCircle,
|
||||||
faClone,
|
faClone,
|
||||||
faCertificate,
|
faCertificate,
|
||||||
|
faFolder,
|
||||||
|
faFolderOpen,
|
||||||
);
|
);
|
||||||
|
|
||||||
export { FontAwesomeIcon };
|
export { FontAwesomeIcon };
|
||||||
|
|||||||
@ -1368,5 +1368,7 @@
|
|||||||
"Expected TLS Alert": "Expected TLS Alert",
|
"Expected TLS Alert": "Expected TLS Alert",
|
||||||
"None (Successful Connection)": "None (Successful Connection)",
|
"None (Successful Connection)": "None (Successful Connection)",
|
||||||
"expectedTlsAlertDescription": "Select the TLS alert you expect the server to return. Use {code} to verify mTLS endpoints reject connections without client certificates. See {link} for details.",
|
"expectedTlsAlertDescription": "Select the TLS alert you expect the server to return. Use {code} to verify mTLS endpoints reject connections without client certificates. See {link} for details.",
|
||||||
"TLS Alert Spec": "RFC 8446"
|
"TLS Alert Spec": "RFC 8446",
|
||||||
|
"Expand All Groups": "Expand All Groups",
|
||||||
|
"Collapse All Groups": "Collapse All Groups"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div v-if="!$root.isMobile" class="col-12 col-md-5 col-xl-4">
|
<div v-if="!$root.isMobile" class="col-12 col-md-5 col-xl-4 ps-0">
|
||||||
<div>
|
<div>
|
||||||
<router-link to="/add" class="btn btn-primary mb-3">
|
<router-link to="/add" class="btn btn-primary mb-3">
|
||||||
<font-awesome-icon icon="plus" />
|
<font-awesome-icon icon="plus" />
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
{{ $t("Quick Stats") }}
|
{{ $t("Quick Stats") }}
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<div class="shadow-box big-padding text-center mb-4">
|
<div class="shadow-box big-padding text-center mb-3">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<h3>{{ $t("Up") }}</h3>
|
<h3>{{ $t("Up") }}</h3>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user