diff --git a/apps/dokploy/__test__/traefik/traefik.test.ts b/apps/dokploy/__test__/traefik/traefik.test.ts index fe7d0ff9d..14d45f76c 100644 --- a/apps/dokploy/__test__/traefik/traefik.test.ts +++ b/apps/dokploy/__test__/traefik/traefik.test.ts @@ -424,6 +424,26 @@ test("Custom entrypoint with internalPath adds addprefix middleware", async () = expect(router.entryPoints).toEqual(["custom"]); }); +test("stripPath and internalPath together: stripprefix must come before addprefix", async () => { + const router = await createRouterConfig( + baseApp, + { + ...baseDomain, + path: "/public", + stripPath: true, + internalPath: "/app/v2", + }, + "web", + ); + + const stripIndex = router.middlewares?.indexOf("stripprefix--1") ?? -1; + const addIndex = router.middlewares?.indexOf("addprefix--1") ?? -1; + + expect(stripIndex).toBeGreaterThanOrEqual(0); + expect(addIndex).toBeGreaterThanOrEqual(0); + expect(stripIndex).toBeLessThan(addIndex); +}); + test("Custom entrypoint with https and custom cert resolver", async () => { const router = await createRouterConfig( baseApp, diff --git a/apps/dokploy/components/dashboard/docker/logs/analyze-logs.tsx b/apps/dokploy/components/dashboard/docker/logs/analyze-logs.tsx index f330c3fe2..267735eac 100644 --- a/apps/dokploy/components/dashboard/docker/logs/analyze-logs.tsx +++ b/apps/dokploy/components/dashboard/docker/logs/analyze-logs.tsx @@ -1,5 +1,6 @@ "use client"; -import { Bot, Loader2, RotateCcw, X } from "lucide-react"; +import { Bot, Loader2, RotateCcw, Settings, X } from "lucide-react"; +import Link from "next/link"; import { useState } from "react"; import ReactMarkdown from "react-markdown"; import { toast } from "sonner"; @@ -32,14 +33,13 @@ export function AnalyzeLogs({ logs, context }: Props) { const { data: providers } = api.ai.getEnabledProviders.useQuery(undefined, { enabled: open, }); - const { mutate, isPending, data, reset } = - api.ai.analyzeLogs.useMutation({ - onError: (error) => { - toast.error("Analysis failed", { - description: error.message, - }); - }, - }); + const { mutate, isPending, data, reset } = api.ai.analyzeLogs.useMutation({ + onError: (error) => { + toast.error("Analysis failed", { + description: error.message, + }); + }, + }); const handleAnalyze = () => { if (!aiId || logs.length === 0) return; @@ -92,38 +92,57 @@ export function AnalyzeLogs({ logs, context }: Props) {
{!data?.analysis ? ( - <> - - - + providers && providers.length === 0 ? ( +
+

+ No AI providers configured. Set up a provider to start + analyzing logs. +

+ +
+ ) : ( + <> + + + + ) ) : ( <>
diff --git a/apps/dokploy/components/dashboard/docker/logs/docker-logs-id.tsx b/apps/dokploy/components/dashboard/docker/logs/docker-logs-id.tsx index ace20b343..8d8842ac0 100644 --- a/apps/dokploy/components/dashboard/docker/logs/docker-logs-id.tsx +++ b/apps/dokploy/components/dashboard/docker/logs/docker-logs-id.tsx @@ -378,7 +378,7 @@ export const DockerLogsId: React.FC = ({ Download logs - +
{isPaused && ( diff --git a/apps/dokploy/components/dashboard/monitoring/free/container/show-free-container-monitoring.tsx b/apps/dokploy/components/dashboard/monitoring/free/container/show-free-container-monitoring.tsx index fd666255c..96cd41bdd 100644 --- a/apps/dokploy/components/dashboard/monitoring/free/container/show-free-container-monitoring.tsx +++ b/apps/dokploy/components/dashboard/monitoring/free/container/show-free-container-monitoring.tsx @@ -220,11 +220,11 @@ export const ContainerFreeMonitoring = ({
- Used: {currentData.cpu.value} + Used: {String(currentData.cpu.value ?? "0%")} { api.stripe.createCustomerPortalSession.useMutation(); const { mutateAsync: upgradeSubscription, isPending: isUpgrading } = api.stripe.upgradeSubscription.useMutation(); + const { mutateAsync: updateInvoiceNotifications } = + api.stripe.updateInvoiceNotifications.useMutation(); const utils = api.useUtils(); const [hobbyServerQuantity, setHobbyServerQuantity] = useState(1); @@ -151,14 +164,66 @@ export const ShowBilling = () => {
- - - - Billing - - - Manage your subscription and invoices - + +
+ + + Billing + + + Manage your subscription and invoices + +
+ {(admin?.user.stripeSubscriptionId || isEnterpriseCloud) && ( + + + + + + + Notification Settings + + Configure your billing email notifications. + + +
+
+ +

+ Receive email notifications for payments and failed + charges. +

+
+ { + await updateInvoiceNotifications({ + enabled: checked, + }) + .then(() => { + utils.user.get.invalidate(); + toast.success( + checked + ? "Invoice notifications enabled" + : "Invoice notifications disabled", + ); + }) + .catch(() => { + toast.error( + "Failed to update invoice notifications", + ); + }); + }} + /> +
+
+
+ )}