mirror of
https://github.com/Dokploy/dokploy.git
synced 2026-07-02 20:45:23 +02:00
* feat: update dependencies and enhance UI components in Dokploy - Updated various package versions in pnpm-lock.yaml to improve compatibility and performance, including React and Tailwind CSS. - Modified components.json to change the styling to "radix-nova" and added new properties for icon library and menu color. - Refactored multiple components to use updated class names for better styling consistency and responsiveness. - Removed unused Radix UI components from package.json to streamline dependencies. - Adjusted layout and styling in several dashboard components for improved user experience and visual appeal. - Enhanced tooltip and form item components for better accessibility and usability. * refactor: enhance UI components in HandleCertificate and SidebarLogo - Updated the HandleCertificate component to improve dialog content height and textarea styling for better usability. - Adjusted the SidebarLogo component layout to enhance alignment and spacing, ensuring a more consistent appearance across the sidebar. - Implemented responsive design adjustments to textarea elements, preventing overflow and improving user experience. * refactor: improve UI consistency and styling across dashboard components - Updated Card components in ShowDeployments, ShowSchedules, and ShowVolumeBackups to remove unnecessary border styles for a cleaner look. - Enhanced TabsList components in ShowProviderForm and ShowProviderFormCompose by adding a variant for improved visual distinction. - Adjusted spacing in AdvancedEnvironmentSelector for better layout and readability. - Removed redundant border classes in Service component for a more streamlined design. * [autofix.ci] apply automated fixes * chore: update package dependencies and refactor email rendering - Upgraded React and React DOM to version 19.2.7 across multiple packages for improved performance and compatibility. - Updated TSX to version 4.22.4 in various package.json files. - Refactored email rendering from `renderAsync` to `render` in notification utilities and email templates for consistency. - Adjusted Tailwind configuration usage in email templates to utilize a centralized configuration file. These changes enhance the overall stability and maintainability of the codebase. * refactor: update badge variants across dashboard components - Changed badge variant from "outline-solid" to "outline" in multiple components including columns, show-domains, and various deployment tables for consistency in styling. - Updated button variants in billing and project templates to align with the new badge styling. - Enhanced input components to support password generation and error messaging, improving user experience. These changes streamline the UI and ensure a cohesive design across the application. * refactor: clean up calendar component imports and structure - Removed redundant imports of icons from lucide-react and streamlined the import statements for better readability. - Adjusted the placement of type imports to enhance code organization. These changes improve the maintainability and clarity of the calendar component. * [autofix.ci] apply automated fixes --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
183 lines
4.5 KiB
TypeScript
183 lines
4.5 KiB
TypeScript
import { Loader2, RefreshCw } from "lucide-react";
|
|
import { useMemo } from "react";
|
|
import { Cell, Label, Pie, PieChart } from "recharts";
|
|
import { Button } from "@/components/ui/button";
|
|
import {
|
|
type ChartConfig,
|
|
ChartContainer,
|
|
ChartLegend,
|
|
ChartLegendContent,
|
|
ChartTooltip,
|
|
ChartTooltipContent,
|
|
} from "@/components/ui/chart";
|
|
import { api } from "@/utils/api";
|
|
|
|
const TYPE_TO_KEY: Record<string, string> = {
|
|
Images: "images",
|
|
Containers: "containers",
|
|
"Local Volumes": "volumes",
|
|
"Build Cache": "buildCache",
|
|
};
|
|
|
|
const chartConfig = {
|
|
value: {
|
|
label: "Size",
|
|
},
|
|
images: {
|
|
label: "Images",
|
|
color: "hsl(var(--chart-1))",
|
|
},
|
|
containers: {
|
|
label: "Containers",
|
|
color: "hsl(var(--chart-2))",
|
|
},
|
|
volumes: {
|
|
label: "Volumes",
|
|
color: "hsl(var(--chart-3))",
|
|
},
|
|
buildCache: {
|
|
label: "Build Cache",
|
|
color: "hsl(var(--chart-4))",
|
|
},
|
|
} satisfies ChartConfig;
|
|
|
|
const formatSize = (bytes: number): string => {
|
|
if (bytes >= 1024 ** 3) return `${(bytes / 1024 ** 3).toFixed(2)} GB`;
|
|
if (bytes >= 1024 ** 2) return `${(bytes / 1024 ** 2).toFixed(1)} MB`;
|
|
if (bytes >= 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
return `${bytes} B`;
|
|
};
|
|
|
|
export const DockerDiskUsageChart = () => {
|
|
const { data, isLoading, refetch, isRefetching } =
|
|
api.settings.getDockerDiskUsage.useQuery(undefined, {
|
|
refetchOnWindowFocus: false,
|
|
});
|
|
|
|
const { chartData, totalBytes } = useMemo(() => {
|
|
const items =
|
|
data
|
|
?.filter((item) => item.sizeBytes > 0)
|
|
.map((item) => {
|
|
const key = TYPE_TO_KEY[item.type] ?? item.type;
|
|
return {
|
|
name: key,
|
|
value: item.sizeBytes,
|
|
size: item.size,
|
|
active: item.active,
|
|
totalCount: item.totalCount,
|
|
reclaimable: item.reclaimable,
|
|
fill: `var(--color-${key})`,
|
|
};
|
|
}) ?? [];
|
|
return {
|
|
chartData: items,
|
|
totalBytes: items.reduce((sum, item) => sum + item.value, 0),
|
|
};
|
|
}, [data]);
|
|
|
|
if (isLoading) {
|
|
return (
|
|
<div className="flex items-center justify-center h-64">
|
|
<Loader2 className="size-5 animate-spin text-muted-foreground" />
|
|
</div>
|
|
);
|
|
}
|
|
|
|
if (chartData.length === 0) {
|
|
return (
|
|
<p className="text-xs text-muted-foreground mt-4">
|
|
No Docker disk usage data available.
|
|
</p>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className="flex flex-col gap-2 w-full">
|
|
<div className="flex items-center justify-between">
|
|
<span className="text-sm text-muted-foreground">
|
|
Total: {formatSize(totalBytes)}
|
|
</span>
|
|
<Button
|
|
variant="ghost"
|
|
size="icon"
|
|
className="h-7 w-7"
|
|
onClick={() => refetch()}
|
|
disabled={isRefetching}
|
|
>
|
|
<RefreshCw
|
|
className={`size-3.5 ${isRefetching ? "animate-spin" : ""}`}
|
|
/>
|
|
</Button>
|
|
</div>
|
|
<ChartContainer
|
|
config={chartConfig}
|
|
className="mx-auto w-full max-h-[250px] [&_.recharts-pie-label-text]:fill-foreground"
|
|
>
|
|
<PieChart>
|
|
<ChartTooltip
|
|
content={
|
|
<ChartTooltipContent
|
|
nameKey="name"
|
|
formatter={(value, name) => {
|
|
const item = chartData.find((d) => d.name === name);
|
|
if (!item) return [formatSize(value as number), name];
|
|
return [
|
|
`${item.size} — ${item.active} active / ${item.totalCount} total — Reclaimable: ${item.reclaimable}`,
|
|
chartConfig[name as keyof typeof chartConfig]?.label ??
|
|
name,
|
|
];
|
|
}}
|
|
/>
|
|
}
|
|
/>
|
|
<Pie
|
|
data={chartData}
|
|
dataKey="value"
|
|
nameKey="name"
|
|
innerRadius={60}
|
|
outerRadius={85}
|
|
strokeWidth={3}
|
|
stroke="hsl(var(--background))"
|
|
minAngle={15}
|
|
>
|
|
{chartData.map((entry) => (
|
|
<Cell key={entry.name} fill={entry.fill} />
|
|
))}
|
|
<Label
|
|
content={({ viewBox }) => {
|
|
if (viewBox && "cx" in viewBox && "cy" in viewBox) {
|
|
return (
|
|
<text
|
|
x={viewBox.cx}
|
|
y={viewBox.cy}
|
|
textAnchor="middle"
|
|
dominantBaseline="middle"
|
|
>
|
|
<tspan
|
|
x={viewBox.cx}
|
|
y={(viewBox.cy || 0) - 8}
|
|
className="fill-foreground text-2xl font-bold"
|
|
>
|
|
{formatSize(totalBytes)}
|
|
</tspan>
|
|
<tspan
|
|
x={viewBox.cx}
|
|
y={(viewBox.cy || 0) + 14}
|
|
className="fill-muted-foreground text-xs"
|
|
>
|
|
Docker Usage
|
|
</tspan>
|
|
</text>
|
|
);
|
|
}
|
|
}}
|
|
/>
|
|
</Pie>
|
|
<ChartLegend content={<ChartLegendContent nameKey="name" />} />
|
|
</PieChart>
|
|
</ChartContainer>
|
|
</div>
|
|
);
|
|
};
|