feat: add collapsible sections to agent healthcheck views (#652)
Wraps Healthy and Unhealthy agent sections in collapsible components to improve navigation when working with large numbers of agents. Both sections default to expanded state to maintain existing UX.
oliver-oat committed
Feb 3, 2026 at 16:59 UTC
b881e203ad15cc70e15c698419e90342f0af62d6
1 file changed
+45
-33
frontend/src/components/customers/healthcheck/CustomerHealthcheckList.vue
+45
-33
@@ -15,38 +15,50 @@
15
</div>
16
<n-spin :show="loading">
17
<div class="flex min-h-52 flex-col gap-6">
18
- <div v-if="healthyList.length" class="flex flex-col gap-2 not-last:mb-5">
19
- <div class="text-primary mb-2 flex items-center gap-2">
20
- <Icon :name="CheckIcon" :size="16" />
21
- Healthy
22
- <code>{{ healthyList.length }}</code>
23
- </div>
24
- <CustomerHealthcheckItem
25
- v-for="item of healthyList"
26
- :key="item.id"
27
- :health-data="item"
28
- :source="source"
29
- type="healthy"
30
- embedded
31
- class="item-appear item-appear-bottom item-appear-005"
32
- />
33
- </div>
34
- <div v-if="unhealthyList.length" class="flex flex-col gap-2 not-last:mb-5">
35
- <div class="text-warning mb-2 flex items-center gap-2">
36
- <Icon :name="AlertIcon" :size="16" />
37
- Unhealthy
38
- <code>{{ unhealthyList.length }}</code>
39
- </div>
40
- <CustomerHealthcheckItem
41
- v-for="item of unhealthyList"
42
- :key="item.id"
43
- :health-data="item"
44
- :source="source"
45
- type="unhealthy"
46
- embedded
47
- class="item-appear item-appear-bottom item-appear-005"
48
- />
49
- </div>
18
+ <n-collapse v-if="healthyList.length" :default-expanded-names="['healthy']">
19
+ <n-collapse-item name="healthy">
20
+ <template #header>
21
+ <div class="text-primary flex items-center gap-2">
22
+ <Icon :name="CheckIcon" :size="16" />
23
+ Healthy
24
+ <code>{{ healthyList.length }}</code>
25
+ </div>
26
+ </template>
27
+ <div class="flex flex-col gap-2">
28
+ <CustomerHealthcheckItem
29
+ v-for="item of healthyList"
30
+ :key="item.id"
31
+ :health-data="item"
32
+ :source="source"
33
+ type="healthy"
34
+ embedded
35
+ class="item-appear item-appear-bottom item-appear-005"
36
+ />
37
+ </div>
38
+ </n-collapse-item>
39
+ </n-collapse>
40
+ <n-collapse v-if="unhealthyList.length" :default-expanded-names="['unhealthy']">
41
+ <n-collapse-item name="unhealthy">
42
+ <template #header>
43
+ <div class="text-warning flex items-center gap-2">
44
+ <Icon :name="AlertIcon" :size="16" />
45
+ Unhealthy
46
+ <code>{{ unhealthyList.length }}</code>
47
+ </div>
48
+ </template>
49
+ <div class="flex flex-col gap-2">
50
+ <CustomerHealthcheckItem
51
+ v-for="item of unhealthyList"
52
+ :key="item.id"
53
+ :health-data="item"
54
+ :source="source"
55
+ type="unhealthy"
56
+ embedded
57
+ class="item-appear item-appear-bottom item-appear-005"
58
+ />
59
+ </div>
60
+ </n-collapse-item>
61
+ </n-collapse>
62
<n-empty v-if="!healthyList.length && !unhealthyList.length && !loading" class="h-48 justify-center" />
63
</div>
64
</n-spin>
@@ -57,7 +69,7 @@ import type { CustomerAgentsHealthcheckQuery } from "@/api/endpoints/customers"
69
import type { CustomerAgentHealth, CustomerHealthcheckSource } from "@/types/customers.d"
70
import { watchDebounced } from "@vueuse/core"
71
import _get from "lodash/get"
60
-import { NEmpty, NInputGroup, NInputNumber, NSelect, NSpin, useMessage } from "naive-ui"
72
+import { NCollapse, NCollapseItem, NEmpty, NInputGroup, NInputNumber, NSelect, NSpin, useMessage } from "naive-ui"
73
import { computed, onBeforeMount, ref, watch } from "vue"
74
import Api from "@/api"
75
import Icon from "@/components/common/Icon.vue"