From 91654c77d4065aadea82e3d9c2d8d75036cac30b Mon Sep 17 00:00:00 2001 From: biersoeckli Date: Thu, 12 Mar 2026 09:25:14 +0000 Subject: [PATCH] feat: add CPU and memory usage suggestions for pod resource limits --- .../app/[appId]/general/app-rate-limits.tsx | 57 ++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/src/app/project/app/[appId]/general/app-rate-limits.tsx b/src/app/project/app/[appId]/general/app-rate-limits.tsx index 4668655..29ee1e0 100644 --- a/src/app/project/app/[appId]/general/app-rate-limits.tsx +++ b/src/app/project/app/[appId]/general/app-rate-limits.tsx @@ -11,10 +11,14 @@ import { useFormState } from "react-dom"; import { ServerActionResult } from "@/shared/model/server-action-error-return.model"; import { Input } from "@/components/ui/input"; import { AppRateLimitsModel, appRateLimitsZodModel } from "@/shared/model/app-rate-limits.model"; -import { useEffect } from "react"; +import { useEffect, useState } from "react"; import { toast } from "sonner"; import { AppExtendedModel } from "@/shared/model/app-extended.model"; import { cn } from "@/frontend/utils/utils"; +import { getRessourceDataApp } from "../overview/actions"; +import { PodsResourceInfoModel } from "@/shared/model/pods-resource-info.model"; +import { KubeSizeConverter } from "@/shared/utils/kubernetes-size-converter.utils"; +import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip"; export default function GeneralAppRateLimits({ app, readonly }: { @@ -27,6 +31,23 @@ export default function GeneralAppRateLimits({ app, readonly }: { disabled: readonly }); + const [monitoringData, setMonitoringData] = useState(undefined); + + useEffect(() => { + getRessourceDataApp(app.projectId, app.id).then((res) => { + if (res.status === 'success' && res.data) { + setMonitoringData(res.data); + } + }).catch(() => { /* pod may not be running, silently ignore */ }); + }, [app.id, app.projectId]); + + const suggestedMemoryMb = monitoringData && monitoringData.ramAbsolutBytes + ? Math.ceil(KubeSizeConverter.fromBytesToMegabytes(monitoringData.ramAbsolutBytes)) + : undefined; + const suggestedCpuMillicores = monitoringData && monitoringData.cpuAbsolutCores + ? Math.max(1, Math.round(monitoringData.cpuAbsolutCores * 1000)) + : undefined; + const [state, formAction] = useFormState((state: ServerActionResult, payload: AppRateLimitsModel) => saveGeneralAppRateLimits(state, payload, app.id), FormUtils.getInitialFormState()); useEffect(() => { if (state.status === 'success') { @@ -90,6 +111,23 @@ export default function GeneralAppRateLimits({ app, readonly }: { + {!readonly && suggestedMemoryMb !== undefined && ( + + + + form.setValue('memoryReservation', suggestedMemoryMb)} + > + ~ {suggestedMemoryMb} MB + + + +

Suggestion based on current pod resource usage

+
+
+
+ )} )} /> @@ -118,6 +156,23 @@ export default function GeneralAppRateLimits({ app, readonly }: { + {!readonly && suggestedCpuMillicores !== undefined && ( + + + + form.setValue('cpuReservation', suggestedCpuMillicores)} + > + ~ {suggestedCpuMillicores} m + + + +

Suggestion based on current pod resource usage

+
+
+
+ )} )} />