[Front] Add basic status report

This commit is contained in:
SebClem 2024-04-18 13:42:49 +02:00
parent fe02131f74
commit 564cebc560
Signed by: sebclem
GPG Key ID: 5A4308F6A359EA50
11 changed files with 192 additions and 8 deletions

View File

@ -8,4 +8,5 @@
"javascript.inlayHints.propertyDeclarationTypes.enabled": true, "javascript.inlayHints.propertyDeclarationTypes.enabled": true,
"javascript.inlayHints.parameterNames.suppressWhenArgumentMatchesName": true, "javascript.inlayHints.parameterNames.suppressWhenArgumentMatchesName": true,
"javascript.inlayHints.parameterNames.enabled": "literals", "javascript.inlayHints.parameterNames.enabled": "literals",
} "editor.formatOnSave": true
}

View File

@ -1,3 +1,3 @@
{ {
"recommendations": ["Vue.volar", "Vue.vscode-typescript-vue-plugin"] "recommendations": ["Vue.volar"]
} }

View File

@ -26,6 +26,7 @@ declare module 'vue' {
NavbarComponent: typeof import('./src/components/NavbarComponent.vue')['default'] NavbarComponent: typeof import('./src/components/NavbarComponent.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink'] RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView'] RouterView: typeof import('vue-router')['RouterView']
StatusComponent: typeof import('./src/components/StatusComponent.vue')['default']
WebdavConfigForm: typeof import('./src/components/settings/WebdavConfigForm.vue')['default'] WebdavConfigForm: typeof import('./src/components/settings/WebdavConfigForm.vue')['default']
WebdavConfigMenu: typeof import('./src/components/settings/WebdavConfigMenu.vue')['default'] WebdavConfigMenu: typeof import('./src/components/settings/WebdavConfigMenu.vue')['default']
} }

View File

@ -21,6 +21,7 @@
}, },
"devDependencies": { "devDependencies": {
"@babel/types": "^7.23.0", "@babel/types": "^7.23.0",
"@types/luxon": "^3.4.2",
"@types/node": "^20.10.0", "@types/node": "^20.10.0",
"@vitejs/plugin-vue": "^4.5.0", "@vitejs/plugin-vue": "^4.5.0",
"@vue/eslint-config-typescript": "^12.0.0", "@vue/eslint-config-typescript": "^12.0.0",
@ -46,4 +47,4 @@
"vue-tsc": "^1.8.0" "vue-tsc": "^1.8.0"
}, },
"packageManager": "pnpm@8.15.3" "packageManager": "pnpm@8.15.3"
} }

View File

@ -37,6 +37,9 @@ devDependencies:
'@babel/types': '@babel/types':
specifier: ^7.23.0 specifier: ^7.23.0
version: 7.23.9 version: 7.23.9
'@types/luxon':
specifier: ^3.4.2
version: 3.4.2
'@types/node': '@types/node':
specifier: ^20.10.0 specifier: ^20.10.0
version: 20.11.19 version: 20.11.19
@ -526,6 +529,10 @@ packages:
resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==}
dev: true dev: true
/@types/luxon@3.4.2:
resolution: {integrity: sha512-TifLZlFudklWlMBfhubvgqTXRzLDI5pCbGa4P8a3wPyUQSW+1xQ5eDsreP9DWHX3tjq1ke96uYG/nwundroWcA==}
dev: true
/@types/node@20.11.19: /@types/node@20.11.19:
resolution: {integrity: sha512-7xMnVEcZFu0DikYjWOlRq7NTPETrm7teqUT2WkQjrTIkEgUyyGdWsj/Zg8bEJt5TNklzbPD1X3fqfsHw3SpapQ==} resolution: {integrity: sha512-7xMnVEcZFu0DikYjWOlRq7NTPETrm7teqUT2WkQjrTIkEgUyyGdWsj/Zg8bEJt5TNklzbPD1X3fqfsHw3SpapQ==}
dependencies: dependencies:

View File

@ -6,6 +6,11 @@
<backup-config-menu></backup-config-menu> <backup-config-menu></backup-config-menu>
<alert-manager></alert-manager> <alert-manager></alert-manager>
<v-main class="mx-12"> <v-main class="mx-12">
<v-row>
<v-col cols="4" offset="1">
<status-component></status-component>
</v-col>
</v-row>
<v-row> <v-row>
<v-col cols="6"> <v-col cols="6">
<ha-list></ha-list> <ha-list></ha-list>

View File

@ -11,9 +11,7 @@
class="mb-2" class="mb-2"
> >
<v-row dense> <v-row dense>
<v-col> <v-col v-html="alert.message"></v-col>
{{ alert.message }}
</v-col>
<v-col cols="2"> <v-col cols="2">
<v-btn <v-btn
class="d-inline" class="d-inline"
@ -54,4 +52,4 @@ const alertVisible = computed(() => alertList.value.length > 0);
z-index: 99999; z-index: 99999;
} }
</style> </style>
@/store/alert @/store/alert

View File

@ -0,0 +1,130 @@
<template>
<div>
<v-card class="mt-5" border elevation="10">
<v-card-title class="text-center">Status</v-card-title>
<v-divider></v-divider>
<v-card-text>
<v-row>
<v-col cols="6">
<v-card variant="elevated" border>
<v-card-text class="align-center d-flex justify-center">
<span class="me-auto">Home Assistant</span>
<v-tooltip content-class="bg-black">
<template v-slot:activator="{ props }">
<v-chip
v-bind="props"
variant="elevated"
:prepend-icon="hassProps.icon"
:color="hassProps.color"
:text="hassProps.text"
>
</v-chip>
</template>
Last check:
{{
status?.hass.last_check
? DateTime.fromISO(status.hass.last_check).toLocaleString(
DateTime.DATETIME_MED
)
: "UNKNOWN"
}}
</v-tooltip>
</v-card-text>
</v-card>
</v-col>
<v-col cols="6">
<v-card variant="elevated" border>
<v-card-text class="align-center d-flex justify-center">
<span class="me-auto">Cloud</span>
<v-tooltip content-class="bg-black">
<template v-slot:activator="{ props }">
<v-chip
v-bind="props"
variant="elevated"
:prepend-icon="webdavProps.icon"
:color="webdavProps.color"
:text="webdavProps.text"
>
</v-chip>
</template>
<span>Login: </span>
<span :class="'text-' + webdavLoggedProps.color">
{{ webdavLoggedProps.text }}
</span>
<br />
<span>Folder: </span>
<span :class="'text-' + webdavFolderProps.color">
{{ webdavFolderProps.text }}
</span>
<p>
Last check:
{{
status?.webdav.last_check
? DateTime.fromISO(
status.webdav.last_check
).toLocaleString(DateTime.DATETIME_MED)
: "UNKNOWN"
}}
</p>
</v-tooltip>
</v-card-text>
</v-card>
</v-col>
</v-row>
</v-card-text>
</v-card>
</div>
</template>
<script setup lang="ts">
import { getStatus } from "@/services/statusService";
import { Status } from "@/types/status";
import { computed, ref, onBeforeUnmount } from "vue";
import { DateTime } from "luxon";
const status = ref<Status | undefined>(undefined);
function refreshStatus() {
getStatus().then((data) => {
status.value = data;
});
}
const webdavProps = computed(() => {
if (status.value?.webdav.logged_in && status.value?.webdav.folder_created) {
return { icon: "mdi-check", text: "Ok", color: "green" };
} else {
return { icon: "mdi-alert", text: "Fail", color: "red" };
}
});
const webdavLoggedProps = computed(() => {
if (status.value?.webdav.logged_in) {
return { text: "Ok", color: "green" };
} else {
return { text: "Fail", color: "red" };
}
});
const webdavFolderProps = computed(() => {
if (status.value?.webdav.folder_created) {
return { text: "Ok", color: "green" };
} else {
return { text: "Fail", color: "red" };
}
});
const hassProps = computed(() => {
if (status.value?.hass.ok) {
return { icon: "mdi-check", text: "Ok", color: "green" };
} else {
return { icon: "mdi-alert", text: "Fail", color: "red" };
}
});
refreshStatus();
const interval = setInterval(refreshStatus, 2000);
onBeforeUnmount(() => {
clearInterval(interval);
});
</script>

View File

@ -63,7 +63,9 @@ function refreshBackup() {
getBackups().then((value) => { getBackups().then((value) => {
backups.value = value; backups.value = value;
loading.value = false; loading.value = false;
}); }).catch(()=> {
loading.value = false;
})
} }
refreshBackup(); refreshBackup();

View File

@ -0,0 +1,7 @@
import type { WebdavBackup } from "@/types/webdav";
import kyClient from "./kyClient";
import { Status } from "@/types/status";
export function getStatus() {
return kyClient.get("status").json<Status>();
}

View File

@ -0,0 +1,32 @@
import type { DateTime } from "luxon";
export enum States {
IDLE = "IDLE",
BKUP_CREATION = "BKUP_CREATION",
BKUP_DOWNLOAD_HA = "BKUP_DOWNLOAD_HA",
BKUP_DOWNLOAD_CLOUD = "BKUP_DOWNLOAD_CLOUD",
BKUP_UPLOAD_HA = "BKUP_UPLOAD_HA",
BKUP_UPLOAD_CLOUD = "BKUP_UPLOAD_CLOUD",
STOP_ADDON = "STOP_ADDON",
START_ADDON = "START_ADDON",
}
export interface Status {
status: States;
progress?: number;
last_backup: {
success?: boolean;
last_success?: string;
message?: string;
};
next_backup?: string;
webdav: {
logged_in: boolean;
folder_created: boolean;
last_check: string;
};
hass: {
ok: boolean;
last_check: string;
};
}