diff --git a/apps/dokploy/components/dashboard/application/advanced/show-resources.tsx b/apps/dokploy/components/dashboard/application/advanced/show-resources.tsx index 3beedcdbc..aea30e49b 100644 --- a/apps/dokploy/components/dashboard/application/advanced/show-resources.tsx +++ b/apps/dokploy/components/dashboard/application/advanced/show-resources.tsx @@ -21,7 +21,10 @@ import { FormLabel, FormMessage, } from "@/components/ui/form"; -import { Input } from "@/components/ui/input"; +import { + createConverter, + NumberInputWithSteps, +} from "@/components/ui/number-input"; import { Tooltip, TooltipContent, @@ -30,6 +33,23 @@ import { } from "@/components/ui/tooltip"; import { api } from "@/utils/api"; +const CPU_STEP = 0.25; +const MEMORY_STEP_MB = 256; + +const formatNumber = (value: number, decimals = 2): string => + Number.isInteger(value) ? String(value) : value.toFixed(decimals); + +const cpuConverter = createConverter(1_000_000_000, (cpu) => + cpu <= 0 ? "" : `${formatNumber(cpu)} CPU`, +); + +const memoryConverter = createConverter(1024 * 1024, (mb) => { + if (mb <= 0) return ""; + return mb >= 1024 + ? `${formatNumber(mb / 1024)} GB` + : `${formatNumber(mb)} MB`; +}); + const addResourcesSchema = z.object({ memoryReservation: z.string().optional(), cpuLimit: z.string().optional(), @@ -51,6 +71,7 @@ interface Props { } type AddResources = z.infer; + export const ShowResources = ({ id, type }: Props) => { const queryMap = { postgres: () => @@ -163,16 +184,20 @@ export const ShowResources = ({ id, type }: Props) => {

Memory hard limit in bytes. Example: 1GB = - 1073741824 bytes + 1073741824 bytes. Use +/- buttons to adjust by + 256 MB.

- @@ -198,16 +223,20 @@ export const ShowResources = ({ id, type }: Props) => {

Memory soft limit in bytes. Example: 256MB = - 268435456 bytes + 268435456 bytes. Use +/- buttons to adjust by 256 + MB.

- @@ -234,17 +263,20 @@ export const ShowResources = ({ id, type }: Props) => {

CPU quota in units of 10^-9 CPUs. Example: 2 - CPUs = 2000000000 + CPUs = 2000000000. Use +/- buttons to adjust by + 0.25 CPU.

- @@ -271,14 +303,21 @@ export const ShowResources = ({ id, type }: Props) => {

CPU shares (relative weight). Example: 1 CPU = - 1000000000 + 1000000000. Use +/- buttons to adjust by 0.25 + CPU.

- + diff --git a/apps/dokploy/components/ui/number-input.tsx b/apps/dokploy/components/ui/number-input.tsx new file mode 100644 index 000000000..511b6dc9f --- /dev/null +++ b/apps/dokploy/components/ui/number-input.tsx @@ -0,0 +1,84 @@ +import { MinusIcon, PlusIcon } from "lucide-react"; +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; + +export interface UnitConverter { + toValue: (raw: string | undefined) => number; + fromValue: (value: number) => string; + formatDisplay: (value: number) => string; +} + +export const createConverter = ( + multiplier: number, + formatDisplay: (value: number) => string, +): UnitConverter => ({ + toValue: (raw) => { + if (!raw) return 0; + const value = Number.parseInt(raw, 10); + return Number.isNaN(value) ? 0 : value / multiplier; + }, + fromValue: (value) => + value <= 0 ? "" : String(Math.round(value * multiplier)), + formatDisplay, +}); + +interface NumberInputWithStepsProps { + value: string | undefined; + onChange: (value: string) => void; + placeholder: string; + step: number; + converter: UnitConverter; +} + +export const NumberInputWithSteps = ({ + value, + onChange, + placeholder, + step, + converter, +}: NumberInputWithStepsProps) => { + const numericValue = converter.toValue(value); + const displayValue = converter.formatDisplay(numericValue); + + const handleIncrement = () => + onChange(converter.fromValue(numericValue + step)); + const handleDecrement = () => + onChange(converter.fromValue(Math.max(0, numericValue - step))); + + return ( +
+
+ + onChange(e.target.value)} + className="text-center" + /> + +
+ {displayValue && ( + + {displayValue} + + )} +
+ ); +};