Skip to content

Commit 77df9d8

Browse files
SteKoeulischulteerikpetzold
authored
chore: enhance ApplicationStatusHero (#3000)
* chore: fix ApplicationStatusHero * chore: add all up, all down and all unknown * Removed unused imports * fix tests for status check of 'some' instances * WIP * update icons and colors for unknown * update texts * update colors and remove old stuff --------- Co-authored-by: ulrichschulte <[email protected]> Co-authored-by: erik.petzold <[email protected]>
1 parent 200f3eb commit 77df9d8

File tree

14 files changed

+178
-22
lines changed

14 files changed

+178
-22
lines changed

spring-boot-admin-server-ui/src/main/frontend/services/application.ts

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import { Observable, concat, from, ignoreElements } from 'rxjs';
2020
import axios, { redirectOn401 } from '../utils/axios';
2121
import waitForPolyfill from '../utils/eventsource-polyfill';
2222
import uri from '../utils/uri';
23-
import Instance from './instance';
23+
import Instance, { DOWN_STATES, UNKNOWN_STATES, UP_STATES } from './instance';
2424

2525
const actuatorMimeTypes = [
2626
'application/vnd.spring-boot.actuator.v2+json',
@@ -46,6 +46,35 @@ export const convertBody = (responses) =>
4646
return res;
4747
});
4848

49+
export const getStatusInfo = (applications: Application[]) => {
50+
const instances = applications.flatMap(
51+
(application) => application.instances,
52+
);
53+
54+
const upCount = instances.filter((instance) =>
55+
UP_STATES.includes(instance.statusInfo.status),
56+
).length;
57+
58+
const downCount = instances.filter((instance) =>
59+
DOWN_STATES.includes(instance.statusInfo.status),
60+
).length;
61+
62+
const unknownCount = instances.filter((instance) =>
63+
UNKNOWN_STATES.includes(instance.statusInfo.status),
64+
).length;
65+
66+
return {
67+
upCount,
68+
downCount,
69+
unknownCount,
70+
allUp: upCount === instances.length,
71+
allDown: downCount === instances.length,
72+
allUnknown: unknownCount === instances.length,
73+
someUnknown: unknownCount > 0 && unknownCount < instances.length,
74+
someDown: downCount > 0 && downCount < instances.length,
75+
};
76+
};
77+
4978
class Application {
5079
public readonly name: string;
5180
public readonly instances: Instance[];

spring-boot-admin-server-ui/src/main/frontend/services/instance.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,17 @@ export type Registration = {
438438
};
439439

440440
type StatusInfo = {
441-
status: string;
441+
status:
442+
| 'UNKNOWN'
443+
| 'OUT_OF_SERVICE'
444+
| 'UP'
445+
| 'DOWN'
446+
| 'OFFLINE'
447+
| 'RESTRICTED'
448+
| string;
442449
details: { [key: string]: string };
443450
};
451+
452+
export const DOWN_STATES = ['OUT_OF_SERVICE', 'DOWN', 'OFFLINE', 'RESTRICTED'];
453+
export const UP_STATES = ['UP'];
454+
export const UNKNOWN_STATES = ['UNKNOWN'];
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import { screen } from '@testing-library/vue';
2+
import { beforeEach, describe, expect, it, vi } from 'vitest';
3+
import { Ref, ref } from 'vue';
4+
5+
import { useApplicationStore } from '@/composables/useApplicationStore';
6+
import Application from '@/services/application';
7+
import Instance from '@/services/instance';
8+
import { render } from '@/test-utils';
9+
import ApplicationStatusHero from '@/views/applications/ApplicationStatusHero.vue';
10+
11+
vi.mock('@/composables/useApplicationStore', () => ({
12+
useApplicationStore: vi.fn(),
13+
}));
14+
15+
describe('ApplicationStatusHero', () => {
16+
let applications: Ref<Application[]>;
17+
18+
beforeEach(async () => {
19+
applications = ref([]);
20+
21+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
22+
// @ts-ignore
23+
useApplicationStore.mockReturnValue({
24+
applicationsInitialized: ref(true),
25+
applications,
26+
error: ref(null),
27+
});
28+
});
29+
30+
it.each`
31+
instance1Status | instance2Status | expectedMessage
32+
${'UP'} | ${'UP'} | ${'all up'}
33+
${'OFFLINE'} | ${'OFFLINE'} | ${'all down'}
34+
${'UNKNOWN'} | ${'UNKNOWN'} | ${'all in unknown state'}
35+
${'UP'} | ${'UNKNOWN'} | ${'some instances are in unknown state'}
36+
${'UP'} | ${'DOWN'} | ${'some instances are down'}
37+
${'UP'} | ${'OFFLINE'} | ${'some instances are down'}
38+
${'DOWN'} | ${'UNKNOWN'} | ${'some instances are down'}
39+
${'DOWN'} | ${'OFFLINE'} | ${'all down'}
40+
${'OFFLINE'} | ${'UP'} | ${'some instances are down'}
41+
`(
42+
'`$expectedMessage` is shown when `$instance1Status` and `$instance2Status`',
43+
({ instance1Status, instance2Status, expectedMessage }) => {
44+
applications.value = [
45+
new Application({
46+
name: 'Test Application',
47+
statusTimestamp: Date.now(),
48+
instances: [
49+
new Instance({
50+
id: '4711',
51+
statusInfo: { status: instance1Status },
52+
}),
53+
new Instance({
54+
id: '4712',
55+
statusInfo: { status: instance2Status },
56+
}),
57+
],
58+
}),
59+
];
60+
61+
render(ApplicationStatusHero);
62+
63+
expect(screen.getByText(expectedMessage)).toBeVisible();
64+
},
65+
);
66+
});

spring-boot-admin-server-ui/src/main/frontend/views/applications/ApplicationStatusHero.vue

Lines changed: 54 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,56 @@
22
<sba-panel>
33
<template v-if="applicationsCount > 0">
44
<div class="flex flex-row md:flex-col items-center justify-center">
5-
<template v-if="downCount === 0">
5+
<template v-if="statusInfo.allUp">
66
<font-awesome-icon icon="check-circle" class="text-green-500 icon" />
77
<div class="text-center">
88
<h1 class="font-bold text-2xl" v-text="$t('applications.all_up')" />
99
<p class="text-gray-400" v-text="lastUpdate" />
1010
</div>
1111
</template>
12-
<template v-else>
12+
<template v-else-if="statusInfo.allDown">
13+
<font-awesome-icon icon="check-circle" class="text-green-500 icon" />
14+
<div class="text-center">
15+
<h1
16+
class="font-bold text-2xl"
17+
v-text="$t('applications.all_down')"
18+
/>
19+
<p class="text-gray-400" v-text="lastUpdate" />
20+
</div>
21+
</template>
22+
<template v-if="statusInfo.allUnknown">
23+
<font-awesome-icon
24+
icon="question-circle"
25+
class="text-gray-300 icon"
26+
/>
27+
<div class="text-center">
28+
<h1
29+
class="font-bold text-2xl"
30+
v-text="$t('applications.all_unknown')"
31+
/>
32+
<p class="text-gray-400" v-text="lastUpdate" />
33+
</div>
34+
</template>
35+
<template v-else-if="someInstancesDown">
1336
<font-awesome-icon icon="minus-circle" class="text-red-500 icon" />
1437
<div class="text-center">
1538
<h1
1639
class="font-bold text-2xl"
17-
v-text="$t('applications.instances_down')"
40+
v-text="$t('applications.some_down')"
41+
/>
42+
<p class="text-gray-400" v-text="lastUpdate" />
43+
</div>
44+
</template>
45+
46+
<template v-else-if="someInstancesUnknown">
47+
<font-awesome-icon
48+
icon="question-circle"
49+
class="text-gray-300 icon"
50+
/>
51+
<div class="text-center">
52+
<h1
53+
class="font-bold text-2xl"
54+
v-text="$t('applications.some_unknown')"
1855
/>
1956
<p class="text-gray-400" v-text="lastUpdate" />
2057
</div>
@@ -37,7 +74,10 @@
3774
</template>
3875

3976
<script>
77+
import { computed } from 'vue';
78+
4079
import { useApplicationStore } from '@/composables/useApplicationStore';
80+
import { getStatusInfo } from '@/services/application';
4181
4282
const options = {
4383
year: 'numeric',
@@ -51,7 +91,10 @@ const options = {
5191
export default {
5292
setup() {
5393
const { applications } = useApplicationStore();
54-
return { applications };
94+
95+
const statusInfo = computed(() => getStatusInfo(applications.value));
96+
97+
return { applications, statusInfo };
5598
},
5699
data() {
57100
return {
@@ -60,7 +103,13 @@ export default {
60103
};
61104
},
62105
computed: {
63-
downCount() {
106+
someInstancesDown() {
107+
return this.statusInfo.someDown;
108+
},
109+
someInstancesUnknown() {
110+
return this.statusInfo.someUnknown;
111+
},
112+
notUpCount() {
64113
return this.applications.reduce((current, next) => {
65114
return (
66115
current +
@@ -80,11 +129,6 @@ export default {
80129
);
81130
},
82131
},
83-
watch: {
84-
downCount() {
85-
this.updateLastUpdateTime();
86-
},
87-
},
88132
beforeMount() {
89133
this.updateLastUpdateTime();
90134
},

spring-boot-admin-server-ui/src/main/frontend/views/applications/i18n.de.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,17 @@
88
"restart": "Neu starten"
99
},
1010
"all_up": "Alle verfügbar",
11+
"all_down": "Alle Instanzen sind ausgefallen",
12+
"all_unknown": "Alle Instanzen haben unbekannten Status",
13+
"some_unknown": "Einige Instanzen haben unbekannten Status",
14+
"some_down": "Einige Instanzen sind ausgefallen",
1115
"applications": "Anwendungen",
1216
"fetching_notification_filters_failed": "Der Abruf der Benachrichtigungseinstellungen ist fehlgeschlagen.",
1317
"notification_filter": {
1418
"none": "Keine Benachrichtigungseinstellungen gesetzt.",
1519
"removed": "Benachrichtigungseinstellungen wurden geändert."
1620
},
1721
"instances": "Instanzen",
18-
"instances_down": "Einige Instanzen sind ausgefallen",
1922
"loading_applications": "Anwendungen werden geladen...",
2023
"no_applications_registered": "Keine Anwendungen registriert.",
2124
"notifications_suppressed_for": "Benachrichtigungen für <code>{name}</code> werden unterdrückt für",

spring-boot-admin-server-ui/src/main/frontend/views/applications/i18n.en.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,17 @@
88
"restart": "Restart"
99
},
1010
"all_up": "all up",
11+
"all_down": "all down",
12+
"all_unknown": "all in unknown state",
13+
"some_unknown": "some instances are in unknown state",
14+
"some_down": "some instances are down",
1115
"applications": "Applications",
1216
"fetching_notification_filters_failed": "Fetching notification filters failed.",
1317
"notification_filter": {
1418
"none": "No notification filters set.",
1519
"removed": "Notification filter removed."
1620
},
1721
"instances": "Instances",
18-
"instances_down": "Some instances are down",
1922
"loading_applications": "Loading applications...",
2023
"no_applications_registered": "No applications registered.",
2124
"notifications_suppressed_for": "Notifications on <code>{name}</code> are suppressed for",

spring-boot-admin-server-ui/src/main/frontend/views/applications/i18n.es.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"all_up": "Todo arriba",
44
"applications": "Aplicaciones",
55
"instances": "Instancias",
6-
"instances_down": "instancias caídas",
6+
"some_down": "instancias caídas",
77
"loading_applications": "Cargando aplicaciones...",
88
"no_applications_registered": "No hay aplicaciones registradas.",
99
"notifications_suppressed_for": "Notificaciones para <code>{name}</code> estás suspendidas por",

spring-boot-admin-server-ui/src/main/frontend/views/applications/i18n.fr.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"all_up": "tout est disponible",
44
"applications": "Applications",
55
"instances": "Instances",
6-
"instances_down": "instances inaccessibles",
6+
"some_down": "instances inaccessibles",
77
"loading_applications": "Chargement des applications...",
88
"no_applications_registered": "Aucune application enregistrée.",
99
"notifications_suppressed_for": "Les notifications sur <code>{name}</code> sont supprimées",

spring-boot-admin-server-ui/src/main/frontend/views/applications/i18n.is.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"all_up": "Öll fáanleg",
44
"applications": "Forrit",
55
"instances": "Eintök",
6-
"instances_down": "Eintök ekki fáanleg",
6+
"some_down": "Eintök ekki fáanleg",
77
"loading_applications": "Forrit eru að ræsa…",
88
"no_applications_registered": "Engin forrit skráð.",
99
"notifications_suppressed_for": "Tilkynningar fyrir <code>{name}</code> eru hunsuð fyrir",

spring-boot-admin-server-ui/src/main/frontend/views/applications/i18n.ko.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"all_up": "전체 정상",
44
"applications": "애플리케이션",
55
"instances": "인스턴스",
6-
"instances_down": "인스턴스 종료",
6+
"some_down": "인스턴스 종료",
77
"loading_applications": "애플리케이션 로딩..",
88
"no_applications_registered": "등록된 애플리케이션이 없습니다.",
99
"notifications_suppressed_for": "<code>{name}</code>에 대한 알림이 억제됩니다.",

0 commit comments

Comments
 (0)