Monitor update
Deploy / deploy (push) Successful in 8s

This commit is contained in:
2026-08-31 22:42:40 +05:00
parent 47ea18d020
commit 28702bd029
13 changed files with 434 additions and 217 deletions
+2 -2
View File
@@ -2,7 +2,7 @@ import { useCallback, useEffect, useState } from "preact/hooks";
import { createClient } from "@connectrpc/connect";
import { createConnectTransport } from "@connectrpc/connect-web";
import { BookOpen, Gauge, Link as LinkIcon, Play, Server } from "lucide-preact";
import type { Item, Link, Service } from "./gen/homelab/v1/homelab_pb";
import type { Item, Link, Service, Monitor } from "./gen/homelab/v1/homelab_pb";
import { HomelabService } from "./gen/homelab/v1/homelab_pb";
import { MonitorCard } from "./components/MonitorCard";
import { ScriptCard } from "./components/ScriptCard";
@@ -203,7 +203,7 @@ function MainScreen({
type Content = {
links: Link[];
monitors: Item[];
monitors: Monitor[];
exec: Item[];
services: Service[];
};
+29 -17
View File
@@ -1,24 +1,36 @@
import type { Item } from "../gen/homelab/v1/homelab_pb";
import type { Item, Monitor } from "../gen/homelab/v1/homelab_pb";
/** Карточка монитора: percentage → radial-progress, иначе текст. */
export function MonitorCard({ s }: { s: Item }) {
const pct = Number.parseInt(s.value, 10);
const isPct = s.data === "percentage" && !Number.isNaN(pct);
export function MonitorCard({ s }: { s: Monitor }) {
const pct = s.percentage;
const isPct = !Number.isNaN(pct);
return (
<div class="card bg-base-200 shadow">
<div class="card-body p-4">
<h2 class="card-title text-sm font-medium text-base-content/60">{s.name}</h2>
{isPct ? (
<div
class="radial-progress text-primary"
style={{ "--value": pct } as preact.JSX.CSSProperties}
role="progressbar"
>
{pct}%
</div>
) : (
<p class="font-mono text-lg break-all">{s.value || "…"}</p>
)}
<div class="card-body p-4 flex flex-row justify-between align-center">
<div>
<h2 class="card-title text-sm font-medium text-base-content/60">
{s.name}
</h2>
{isPct ? (
<div
class="radial-progress text-primary"
style={{ "--value": pct } as preact.JSX.CSSProperties}
role="progressbar"
>
{pct}%
</div>
) : (
<p class="font-mono text-lg break-all">{s.percentage || "…"}</p>
)}
</div>
<div class="flex flex-col gap-2">
{s.stats.map((it) => (
<div class="flex items-center gap-2 justify-end">
<span class="text-xs text-base-content/40">{it.name}</span>
<span class="font-mono text-lg break-all">{it.value}</span>
</div>
))}
</div>
</div>
</div>
);
+71 -34
View File
@@ -10,7 +10,7 @@ import type { Message } from "@bufbuild/protobuf";
* Describes the file homelab/v1/homelab.proto.
*/
export const file_homelab_v1_homelab: GenFile = /*@__PURE__*/
fileDesc("Chhob21lbGFiL3YxL2hvbWVsYWIucHJvdG8SCmhvbWVsYWIudjEiUgoESXRlbRIMCgRuYW1lGAEgASgJEgwKBGRhdGEYAiABKAkSDQoFdmFsdWUYAyABKAkSDAoEYXJncxgEIAEoBRIRCglhcmdfdHlwZXMYBSADKAkiIQoETGluaxIMCgRuYW1lGAEgASgJEgsKA3VybBgCIAEoCSIUChJMaXN0Q29udGVudFJlcXVlc3QioQEKE0xpc3RDb250ZW50UmVzcG9uc2USHwoFbGlua3MYASADKAsyEC5ob21lbGFiLnYxLkxpbmsSIgoIbW9uaXRvcnMYAiADKAsyEC5ob21lbGFiLnYxLkl0ZW0SHgoEZXhlYxgDIAMoCzIQLmhvbWVsYWIudjEuSXRlbRIlCghzZXJ2aWNlcxgEIAMoCzITLmhvbWVsYWIudjEuU2VydmljZSIlCgdEb2NNZXRhEgwKBG5hbWUYASABKAkSDAoEaGFzaBgCIAEoCSIRCg9MaXN0RG9jc1JlcXVlc3QiNQoQTGlzdERvY3NSZXNwb25zZRIhCgRkb2NzGAEgAygLMhMuaG9tZWxhYi52MS5Eb2NNZXRhIh0KDUdldERvY1JlcXVlc3QSDAoEbmFtZRgBIAEoCSIhCg5HZXREb2NSZXNwb25zZRIPCgdjb250ZW50GAEgASgJIi8KDlNhdmVEb2NSZXF1ZXN0EgwKBG5hbWUYASABKAkSDwoHY29udGVudBgCIAEoCSIfCg9TYXZlRG9jUmVzcG9uc2USDAoEaGFzaBgBIAEoCSKvAQoHU2VydmljZRIlCgRraW5kGAEgASgOMhcuaG9tZWxhYi52MS5TZXJ2aWNlS2luZBIMCgRuYW1lGAIgASgJEg0KBXN0YXRlGAMgASgJEhAKCHN1YnN0YXRlGAQgASgJEhIKCmxvYWRfc3RhdGUYBSABKAkSFwoPdW5pdF9maWxlX3N0YXRlGAYgASgJEhIKCmNvbnRhaW5lcnMYByADKAkSDQoFZXJyb3IYCCABKAkibgoUU2VydmljZUFjdGlvblJlcXVlc3QSDAoEbmFtZRgBIAEoCRIlCgRraW5kGAIgASgOMhcuaG9tZWxhYi52MS5TZXJ2aWNlS2luZBIhCgJvcBgDIAEoDjIVLmhvbWVsYWIudjEuU2VydmljZU9wIicKFVNlcnZpY2VBY3Rpb25SZXNwb25zZRIOCgZvdXRwdXQYASABKAkiSQoSU2VydmljZUluZm9SZXF1ZXN0EgwKBG5hbWUYASABKAkSJQoEa2luZBgCIAEoDjIXLmhvbWVsYWIudjEuU2VydmljZUtpbmQiJQoTU2VydmljZUluZm9SZXNwb25zZRIOCgZvdXRwdXQYASABKAkiLgoQUnVuU2NyaXB0UmVxdWVzdBIMCgRuYW1lGAEgASgJEgwKBGFyZ3MYAiADKAkiIwoRUnVuU2NyaXB0UmVzcG9uc2USDgoGb3V0cHV0GAEgASgJKiYKC1NlcnZpY2VLaW5kEgsKB1NZU1RFTUQQABIKCgZET0NLRVIQASotCglTZXJ2aWNlT3ASCQoFU1RBUlQQABIICgRTVE9QEAESCwoHUkVTVEFSVBACMpwECg5Ib21lbGFiU2VydmljZRJOCgtMaXN0Q29udGVudBIeLmhvbWVsYWIudjEuTGlzdENvbnRlbnRSZXF1ZXN0Gh8uaG9tZWxhYi52MS5MaXN0Q29udGVudFJlc3BvbnNlEkUKCExpc3REb2NzEhsuaG9tZWxhYi52MS5MaXN0RG9jc1JlcXVlc3QaHC5ob21lbGFiLnYxLkxpc3REb2NzUmVzcG9uc2USPwoGR2V0RG9jEhkuaG9tZWxhYi52MS5HZXREb2NSZXF1ZXN0GhouaG9tZWxhYi52MS5HZXREb2NSZXNwb25zZRJCCgdTYXZlRG9jEhouaG9tZWxhYi52MS5TYXZlRG9jUmVxdWVzdBobLmhvbWVsYWIudjEuU2F2ZURvY1Jlc3BvbnNlElQKDVNlcnZpY2VBY3Rpb24SIC5ob21lbGFiLnYxLlNlcnZpY2VBY3Rpb25SZXF1ZXN0GiEuaG9tZWxhYi52MS5TZXJ2aWNlQWN0aW9uUmVzcG9uc2USTgoLU2VydmljZUluZm8SHi5ob21lbGFiLnYxLlNlcnZpY2VJbmZvUmVxdWVzdBofLmhvbWVsYWIudjEuU2VydmljZUluZm9SZXNwb25zZRJICglSdW5TY3JpcHQSHC5ob21lbGFiLnYxLlJ1blNjcmlwdFJlcXVlc3QaHS5ob21lbGFiLnYxLlJ1blNjcmlwdFJlc3BvbnNlQipaKHB3YS1ob21lbGFiLW1vbi9nZW4vaG9tZWxhYi92MTtob21lbGFidjFiBnByb3RvMw");
fileDesc("Chhob21lbGFiL3YxL2hvbWVsYWIucHJvdG8SCmhvbWVsYWIudjEiNQoESXRlbRIMCgRuYW1lGAEgASgJEgwKBGFyZ3MYBCABKAUSEQoJYXJnX3R5cGVzGAUgAygJIiMKBFN0YXQSDAoEbmFtZRgBIAEoCRINCgV2YWx1ZRgCIAEoCSJMCgdNb25pdG9yEgwKBG5hbWUYASABKAkSEgoKcGVyY2VudGFnZRgCIAEoBRIfCgVzdGF0cxgDIAMoCzIQLmhvbWVsYWIudjEuU3RhdCIhCgRMaW5rEgwKBG5hbWUYASABKAkSCwoDdXJsGAIgASgJIhQKEkxpc3RDb250ZW50UmVxdWVzdCKkAQoTTGlzdENvbnRlbnRSZXNwb25zZRIfCgVsaW5rcxgBIAMoCzIQLmhvbWVsYWIudjEuTGluaxIlCghtb25pdG9ycxgCIAMoCzITLmhvbWVsYWIudjEuTW9uaXRvchIeCgRleGVjGAMgAygLMhAuaG9tZWxhYi52MS5JdGVtEiUKCHNlcnZpY2VzGAQgAygLMhMuaG9tZWxhYi52MS5TZXJ2aWNlIiUKB0RvY01ldGESDAoEbmFtZRgBIAEoCRIMCgRoYXNoGAIgASgJIhEKD0xpc3REb2NzUmVxdWVzdCI1ChBMaXN0RG9jc1Jlc3BvbnNlEiEKBGRvY3MYASADKAsyEy5ob21lbGFiLnYxLkRvY01ldGEiHQoNR2V0RG9jUmVxdWVzdBIMCgRuYW1lGAEgASgJIiEKDkdldERvY1Jlc3BvbnNlEg8KB2NvbnRlbnQYASABKAkiLwoOU2F2ZURvY1JlcXVlc3QSDAoEbmFtZRgBIAEoCRIPCgdjb250ZW50GAIgASgJIh8KD1NhdmVEb2NSZXNwb25zZRIMCgRoYXNoGAEgASgJIq8BCgdTZXJ2aWNlEiUKBGtpbmQYASABKA4yFy5ob21lbGFiLnYxLlNlcnZpY2VLaW5kEgwKBG5hbWUYAiABKAkSDQoFc3RhdGUYAyABKAkSEAoIc3Vic3RhdGUYBCABKAkSEgoKbG9hZF9zdGF0ZRgFIAEoCRIXCg91bml0X2ZpbGVfc3RhdGUYBiABKAkSEgoKY29udGFpbmVycxgHIAMoCRINCgVlcnJvchgIIAEoCSJuChRTZXJ2aWNlQWN0aW9uUmVxdWVzdBIMCgRuYW1lGAEgASgJEiUKBGtpbmQYAiABKA4yFy5ob21lbGFiLnYxLlNlcnZpY2VLaW5kEiEKAm9wGAMgASgOMhUuaG9tZWxhYi52MS5TZXJ2aWNlT3AiJwoVU2VydmljZUFjdGlvblJlc3BvbnNlEg4KBm91dHB1dBgBIAEoCSJJChJTZXJ2aWNlSW5mb1JlcXVlc3QSDAoEbmFtZRgBIAEoCRIlCgRraW5kGAIgASgOMhcuaG9tZWxhYi52MS5TZXJ2aWNlS2luZCIlChNTZXJ2aWNlSW5mb1Jlc3BvbnNlEg4KBm91dHB1dBgBIAEoCSIuChBSdW5TY3JpcHRSZXF1ZXN0EgwKBG5hbWUYASABKAkSDAoEYXJncxgCIAMoCSIjChFSdW5TY3JpcHRSZXNwb25zZRIOCgZvdXRwdXQYASABKAkqJgoLU2VydmljZUtpbmQSCwoHU1lTVEVNRBAAEgoKBkRPQ0tFUhABKi0KCVNlcnZpY2VPcBIJCgVTVEFSVBAAEggKBFNUT1AQARILCgdSRVNUQVJUEAIynAQKDkhvbWVsYWJTZXJ2aWNlEk4KC0xpc3RDb250ZW50Eh4uaG9tZWxhYi52MS5MaXN0Q29udGVudFJlcXVlc3QaHy5ob21lbGFiLnYxLkxpc3RDb250ZW50UmVzcG9uc2USRQoITGlzdERvY3MSGy5ob21lbGFiLnYxLkxpc3REb2NzUmVxdWVzdBocLmhvbWVsYWIudjEuTGlzdERvY3NSZXNwb25zZRI/CgZHZXREb2MSGS5ob21lbGFiLnYxLkdldERvY1JlcXVlc3QaGi5ob21lbGFiLnYxLkdldERvY1Jlc3BvbnNlEkIKB1NhdmVEb2MSGi5ob21lbGFiLnYxLlNhdmVEb2NSZXF1ZXN0GhsuaG9tZWxhYi52MS5TYXZlRG9jUmVzcG9uc2USVAoNU2VydmljZUFjdGlvbhIgLmhvbWVsYWIudjEuU2VydmljZUFjdGlvblJlcXVlc3QaIS5ob21lbGFiLnYxLlNlcnZpY2VBY3Rpb25SZXNwb25zZRJOCgtTZXJ2aWNlSW5mbxIeLmhvbWVsYWIudjEuU2VydmljZUluZm9SZXF1ZXN0Gh8uaG9tZWxhYi52MS5TZXJ2aWNlSW5mb1Jlc3BvbnNlEkgKCVJ1blNjcmlwdBIcLmhvbWVsYWIudjEuUnVuU2NyaXB0UmVxdWVzdBodLmhvbWVsYWIudjEuUnVuU2NyaXB0UmVzcG9uc2VCKloocHdhLWhvbWVsYWItbW9uL2dlbi9ob21lbGFiL3YxO2hvbWVsYWJ2MWIGcHJvdG8z");
/**
* @generated from message homelab.v1.Item
@@ -21,20 +21,6 @@ export type Item = Message<"homelab.v1.Item"> & {
*/
name: string;
/**
* monitor: text | percentage
*
* @generated from field: string data = 2;
*/
data: string;
/**
* monitor: last output
*
* @generated from field: string value = 3;
*/
value: string;
/**
* exec: arg count
*
@@ -57,6 +43,57 @@ export type Item = Message<"homelab.v1.Item"> & {
export const ItemSchema: GenMessage<Item> = /*@__PURE__*/
messageDesc(file_homelab_v1_homelab, 0);
/**
* @generated from message homelab.v1.Stat
*/
export type Stat = Message<"homelab.v1.Stat"> & {
/**
* @generated from field: string name = 1;
*/
name: string;
/**
* @generated from field: string value = 2;
*/
value: string;
};
/**
* Describes the message homelab.v1.Stat.
* Use `create(StatSchema)` to create a new message.
*/
export const StatSchema: GenMessage<Stat> = /*@__PURE__*/
messageDesc(file_homelab_v1_homelab, 1);
/**
* Карточка монитора: процент (-1 = скрипт не дал процент) + строки для подписей.
*
* @generated from message homelab.v1.Monitor
*/
export type Monitor = Message<"homelab.v1.Monitor"> & {
/**
* @generated from field: string name = 1;
*/
name: string;
/**
* @generated from field: int32 percentage = 2;
*/
percentage: number;
/**
* @generated from field: repeated homelab.v1.Stat stats = 3;
*/
stats: Stat[];
};
/**
* Describes the message homelab.v1.Monitor.
* Use `create(MonitorSchema)` to create a new message.
*/
export const MonitorSchema: GenMessage<Monitor> = /*@__PURE__*/
messageDesc(file_homelab_v1_homelab, 2);
/**
* @generated from message homelab.v1.Link
*/
@@ -77,7 +114,7 @@ export type Link = Message<"homelab.v1.Link"> & {
* Use `create(LinkSchema)` to create a new message.
*/
export const LinkSchema: GenMessage<Link> = /*@__PURE__*/
messageDesc(file_homelab_v1_homelab, 1);
messageDesc(file_homelab_v1_homelab, 3);
/**
* @generated from message homelab.v1.ListContentRequest
@@ -90,7 +127,7 @@ export type ListContentRequest = Message<"homelab.v1.ListContentRequest"> & {
* Use `create(ListContentRequestSchema)` to create a new message.
*/
export const ListContentRequestSchema: GenMessage<ListContentRequest> = /*@__PURE__*/
messageDesc(file_homelab_v1_homelab, 2);
messageDesc(file_homelab_v1_homelab, 4);
/**
* @generated from message homelab.v1.ListContentResponse
@@ -102,9 +139,9 @@ export type ListContentResponse = Message<"homelab.v1.ListContentResponse"> & {
links: Link[];
/**
* @generated from field: repeated homelab.v1.Item monitors = 2;
* @generated from field: repeated homelab.v1.Monitor monitors = 2;
*/
monitors: Item[];
monitors: Monitor[];
/**
* @generated from field: repeated homelab.v1.Item exec = 3;
@@ -122,7 +159,7 @@ export type ListContentResponse = Message<"homelab.v1.ListContentResponse"> & {
* Use `create(ListContentResponseSchema)` to create a new message.
*/
export const ListContentResponseSchema: GenMessage<ListContentResponse> = /*@__PURE__*/
messageDesc(file_homelab_v1_homelab, 3);
messageDesc(file_homelab_v1_homelab, 5);
/**
* @generated from message homelab.v1.DocMeta
@@ -146,7 +183,7 @@ export type DocMeta = Message<"homelab.v1.DocMeta"> & {
* Use `create(DocMetaSchema)` to create a new message.
*/
export const DocMetaSchema: GenMessage<DocMeta> = /*@__PURE__*/
messageDesc(file_homelab_v1_homelab, 4);
messageDesc(file_homelab_v1_homelab, 6);
/**
* @generated from message homelab.v1.ListDocsRequest
@@ -159,7 +196,7 @@ export type ListDocsRequest = Message<"homelab.v1.ListDocsRequest"> & {
* Use `create(ListDocsRequestSchema)` to create a new message.
*/
export const ListDocsRequestSchema: GenMessage<ListDocsRequest> = /*@__PURE__*/
messageDesc(file_homelab_v1_homelab, 5);
messageDesc(file_homelab_v1_homelab, 7);
/**
* @generated from message homelab.v1.ListDocsResponse
@@ -176,7 +213,7 @@ export type ListDocsResponse = Message<"homelab.v1.ListDocsResponse"> & {
* Use `create(ListDocsResponseSchema)` to create a new message.
*/
export const ListDocsResponseSchema: GenMessage<ListDocsResponse> = /*@__PURE__*/
messageDesc(file_homelab_v1_homelab, 6);
messageDesc(file_homelab_v1_homelab, 8);
/**
* @generated from message homelab.v1.GetDocRequest
@@ -193,7 +230,7 @@ export type GetDocRequest = Message<"homelab.v1.GetDocRequest"> & {
* Use `create(GetDocRequestSchema)` to create a new message.
*/
export const GetDocRequestSchema: GenMessage<GetDocRequest> = /*@__PURE__*/
messageDesc(file_homelab_v1_homelab, 7);
messageDesc(file_homelab_v1_homelab, 9);
/**
* @generated from message homelab.v1.GetDocResponse
@@ -210,7 +247,7 @@ export type GetDocResponse = Message<"homelab.v1.GetDocResponse"> & {
* Use `create(GetDocResponseSchema)` to create a new message.
*/
export const GetDocResponseSchema: GenMessage<GetDocResponse> = /*@__PURE__*/
messageDesc(file_homelab_v1_homelab, 8);
messageDesc(file_homelab_v1_homelab, 10);
/**
* @generated from message homelab.v1.SaveDocRequest
@@ -232,7 +269,7 @@ export type SaveDocRequest = Message<"homelab.v1.SaveDocRequest"> & {
* Use `create(SaveDocRequestSchema)` to create a new message.
*/
export const SaveDocRequestSchema: GenMessage<SaveDocRequest> = /*@__PURE__*/
messageDesc(file_homelab_v1_homelab, 9);
messageDesc(file_homelab_v1_homelab, 11);
/**
* @generated from message homelab.v1.SaveDocResponse
@@ -249,7 +286,7 @@ export type SaveDocResponse = Message<"homelab.v1.SaveDocResponse"> & {
* Use `create(SaveDocResponseSchema)` to create a new message.
*/
export const SaveDocResponseSchema: GenMessage<SaveDocResponse> = /*@__PURE__*/
messageDesc(file_homelab_v1_homelab, 10);
messageDesc(file_homelab_v1_homelab, 12);
/**
* @generated from message homelab.v1.Service
@@ -315,7 +352,7 @@ export type Service = Message<"homelab.v1.Service"> & {
* Use `create(ServiceSchema)` to create a new message.
*/
export const ServiceSchema: GenMessage<Service> = /*@__PURE__*/
messageDesc(file_homelab_v1_homelab, 11);
messageDesc(file_homelab_v1_homelab, 13);
/**
* @generated from message homelab.v1.ServiceActionRequest
@@ -342,7 +379,7 @@ export type ServiceActionRequest = Message<"homelab.v1.ServiceActionRequest"> &
* Use `create(ServiceActionRequestSchema)` to create a new message.
*/
export const ServiceActionRequestSchema: GenMessage<ServiceActionRequest> = /*@__PURE__*/
messageDesc(file_homelab_v1_homelab, 12);
messageDesc(file_homelab_v1_homelab, 14);
/**
* @generated from message homelab.v1.ServiceActionResponse
@@ -359,7 +396,7 @@ export type ServiceActionResponse = Message<"homelab.v1.ServiceActionResponse">
* Use `create(ServiceActionResponseSchema)` to create a new message.
*/
export const ServiceActionResponseSchema: GenMessage<ServiceActionResponse> = /*@__PURE__*/
messageDesc(file_homelab_v1_homelab, 13);
messageDesc(file_homelab_v1_homelab, 15);
/**
* @generated from message homelab.v1.ServiceInfoRequest
@@ -381,7 +418,7 @@ export type ServiceInfoRequest = Message<"homelab.v1.ServiceInfoRequest"> & {
* Use `create(ServiceInfoRequestSchema)` to create a new message.
*/
export const ServiceInfoRequestSchema: GenMessage<ServiceInfoRequest> = /*@__PURE__*/
messageDesc(file_homelab_v1_homelab, 14);
messageDesc(file_homelab_v1_homelab, 16);
/**
* @generated from message homelab.v1.ServiceInfoResponse
@@ -398,7 +435,7 @@ export type ServiceInfoResponse = Message<"homelab.v1.ServiceInfoResponse"> & {
* Use `create(ServiceInfoResponseSchema)` to create a new message.
*/
export const ServiceInfoResponseSchema: GenMessage<ServiceInfoResponse> = /*@__PURE__*/
messageDesc(file_homelab_v1_homelab, 15);
messageDesc(file_homelab_v1_homelab, 17);
/**
* @generated from message homelab.v1.RunScriptRequest
@@ -420,7 +457,7 @@ export type RunScriptRequest = Message<"homelab.v1.RunScriptRequest"> & {
* Use `create(RunScriptRequestSchema)` to create a new message.
*/
export const RunScriptRequestSchema: GenMessage<RunScriptRequest> = /*@__PURE__*/
messageDesc(file_homelab_v1_homelab, 16);
messageDesc(file_homelab_v1_homelab, 18);
/**
* @generated from message homelab.v1.RunScriptResponse
@@ -437,7 +474,7 @@ export type RunScriptResponse = Message<"homelab.v1.RunScriptResponse"> & {
* Use `create(RunScriptResponseSchema)` to create a new message.
*/
export const RunScriptResponseSchema: GenMessage<RunScriptResponse> = /*@__PURE__*/
messageDesc(file_homelab_v1_homelab, 17);
messageDesc(file_homelab_v1_homelab, 19);
/**
* One card in the Services view: a systemd user unit or a docker compose project.