mirror of
https://github.com/Dokploy/dokploy
synced 2025-06-26 18:27:59 +00:00
Merge branch 'canary' into alpha-grn/add-admin-and-edit-role
This commit is contained in:
@@ -1 +1 @@
|
||||
20.9.0
|
||||
20.16.0
|
||||
@@ -1,26 +0,0 @@
|
||||
FROM node:18-slim AS base
|
||||
ENV PNPM_HOME="/pnpm"
|
||||
ENV PATH="$PNPM_HOME:$PATH"
|
||||
RUN corepack enable
|
||||
|
||||
FROM base AS build
|
||||
COPY . /usr/src/app
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
|
||||
RUN apt-get update && apt-get install -y python3 make g++ git git-lfs && git lfs install && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Install dependencies
|
||||
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile
|
||||
|
||||
# Build only the dokploy app
|
||||
RUN pnpm run dokploy:build
|
||||
|
||||
# Deploy only the dokploy app
|
||||
RUN pnpm deploy --filter=dokploy --prod /prod/dokploy
|
||||
|
||||
FROM base AS dokploy
|
||||
COPY --from=build /prod/dokploy /prod/dokploy
|
||||
WORKDIR /prod/dokploy
|
||||
EXPOSE 3000
|
||||
CMD [ "pnpm", "start" ]
|
||||
@@ -105,6 +105,7 @@ const baseApp: ApplicationNested = {
|
||||
ports: [],
|
||||
projectId: "",
|
||||
publishDirectory: null,
|
||||
isStaticSpa: null,
|
||||
redirects: [],
|
||||
refreshToken: "",
|
||||
registry: null,
|
||||
@@ -149,67 +150,68 @@ describe("unzipDrop using real zip files", () => {
|
||||
} finally {
|
||||
}
|
||||
});
|
||||
|
||||
it("should correctly extract a zip with a single root folder and a subfolder", async () => {
|
||||
baseApp.appName = "folderwithfile";
|
||||
// const appName = "folderwithfile";
|
||||
const outputPath = path.join(APPLICATIONS_PATH, baseApp.appName, "code");
|
||||
const zip = new AdmZip("./__test__/drop/zips/folder-with-file.zip");
|
||||
|
||||
const zipBuffer = zip.toBuffer();
|
||||
const file = new File([zipBuffer], "single.zip");
|
||||
await unzipDrop(file, baseApp);
|
||||
|
||||
const files = await fs.readdir(outputPath, { withFileTypes: true });
|
||||
expect(files.some((f) => f.name === "folder1.txt")).toBe(true);
|
||||
});
|
||||
|
||||
it("should correctly extract a zip with multiple root folders", async () => {
|
||||
baseApp.appName = "two-folders";
|
||||
// const appName = "two-folders";
|
||||
const outputPath = path.join(APPLICATIONS_PATH, baseApp.appName, "code");
|
||||
const zip = new AdmZip("./__test__/drop/zips/two-folders.zip");
|
||||
|
||||
const zipBuffer = zip.toBuffer();
|
||||
const file = new File([zipBuffer], "single.zip");
|
||||
await unzipDrop(file, baseApp);
|
||||
|
||||
const files = await fs.readdir(outputPath, { withFileTypes: true });
|
||||
|
||||
expect(files.some((f) => f.name === "folder1")).toBe(true);
|
||||
expect(files.some((f) => f.name === "folder2")).toBe(true);
|
||||
});
|
||||
|
||||
it("should correctly extract a zip with a single root with a file", async () => {
|
||||
baseApp.appName = "nested";
|
||||
// const appName = "nested";
|
||||
const outputPath = path.join(APPLICATIONS_PATH, baseApp.appName, "code");
|
||||
const zip = new AdmZip("./__test__/drop/zips/nested.zip");
|
||||
|
||||
const zipBuffer = zip.toBuffer();
|
||||
const file = new File([zipBuffer], "single.zip");
|
||||
await unzipDrop(file, baseApp);
|
||||
|
||||
const files = await fs.readdir(outputPath, { withFileTypes: true });
|
||||
|
||||
expect(files.some((f) => f.name === "folder1")).toBe(true);
|
||||
expect(files.some((f) => f.name === "folder2")).toBe(true);
|
||||
expect(files.some((f) => f.name === "folder3")).toBe(true);
|
||||
});
|
||||
|
||||
it("should correctly extract a zip with a single root with a folder", async () => {
|
||||
baseApp.appName = "folder-with-sibling-file";
|
||||
// const appName = "folder-with-sibling-file";
|
||||
const outputPath = path.join(APPLICATIONS_PATH, baseApp.appName, "code");
|
||||
const zip = new AdmZip("./__test__/drop/zips/folder-with-sibling-file.zip");
|
||||
|
||||
const zipBuffer = zip.toBuffer();
|
||||
const file = new File([zipBuffer], "single.zip");
|
||||
await unzipDrop(file, baseApp);
|
||||
|
||||
const files = await fs.readdir(outputPath, { withFileTypes: true });
|
||||
|
||||
expect(files.some((f) => f.name === "folder1")).toBe(true);
|
||||
expect(files.some((f) => f.name === "test.txt")).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
// it("should correctly extract a zip with a single root folder and a subfolder", async () => {
|
||||
// baseApp.appName = "folderwithfile";
|
||||
// // const appName = "folderwithfile";
|
||||
// const outputPath = path.join(APPLICATIONS_PATH, baseApp.appName, "code");
|
||||
// const zip = new AdmZip("./__test__/drop/zips/folder-with-file.zip");
|
||||
|
||||
// const zipBuffer = zip.toBuffer();
|
||||
// const file = new File([zipBuffer], "single.zip");
|
||||
// await unzipDrop(file, baseApp);
|
||||
|
||||
// const files = await fs.readdir(outputPath, { withFileTypes: true });
|
||||
// expect(files.some((f) => f.name === "folder1.txt")).toBe(true);
|
||||
// });
|
||||
|
||||
// it("should correctly extract a zip with multiple root folders", async () => {
|
||||
// baseApp.appName = "two-folders";
|
||||
// // const appName = "two-folders";
|
||||
// const outputPath = path.join(APPLICATIONS_PATH, baseApp.appName, "code");
|
||||
// const zip = new AdmZip("./__test__/drop/zips/two-folders.zip");
|
||||
|
||||
// const zipBuffer = zip.toBuffer();
|
||||
// const file = new File([zipBuffer], "single.zip");
|
||||
// await unzipDrop(file, baseApp);
|
||||
|
||||
// const files = await fs.readdir(outputPath, { withFileTypes: true });
|
||||
|
||||
// expect(files.some((f) => f.name === "folder1")).toBe(true);
|
||||
// expect(files.some((f) => f.name === "folder2")).toBe(true);
|
||||
// });
|
||||
|
||||
// it("should correctly extract a zip with a single root with a file", async () => {
|
||||
// baseApp.appName = "nested";
|
||||
// // const appName = "nested";
|
||||
// const outputPath = path.join(APPLICATIONS_PATH, baseApp.appName, "code");
|
||||
// const zip = new AdmZip("./__test__/drop/zips/nested.zip");
|
||||
|
||||
// const zipBuffer = zip.toBuffer();
|
||||
// const file = new File([zipBuffer], "single.zip");
|
||||
// await unzipDrop(file, baseApp);
|
||||
|
||||
// const files = await fs.readdir(outputPath, { withFileTypes: true });
|
||||
|
||||
// expect(files.some((f) => f.name === "folder1")).toBe(true);
|
||||
// expect(files.some((f) => f.name === "folder2")).toBe(true);
|
||||
// expect(files.some((f) => f.name === "folder3")).toBe(true);
|
||||
// });
|
||||
|
||||
// it("should correctly extract a zip with a single root with a folder", async () => {
|
||||
// baseApp.appName = "folder-with-sibling-file";
|
||||
// // const appName = "folder-with-sibling-file";
|
||||
// const outputPath = path.join(APPLICATIONS_PATH, baseApp.appName, "code");
|
||||
// const zip = new AdmZip("./__test__/drop/zips/folder-with-sibling-file.zip");
|
||||
|
||||
// const zipBuffer = zip.toBuffer();
|
||||
// const file = new File([zipBuffer], "single.zip");
|
||||
// await unzipDrop(file, baseApp);
|
||||
|
||||
// const files = await fs.readdir(outputPath, { withFileTypes: true });
|
||||
|
||||
// expect(files.some((f) => f.name === "folder1")).toBe(true);
|
||||
// expect(files.some((f) => f.name === "test.txt")).toBe(true);
|
||||
// });
|
||||
// });
|
||||
|
||||
@@ -85,6 +85,7 @@ const baseApp: ApplicationNested = {
|
||||
ports: [],
|
||||
projectId: "",
|
||||
publishDirectory: null,
|
||||
isStaticSpa: null,
|
||||
redirects: [],
|
||||
refreshToken: "",
|
||||
registry: null,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { describe, expect, test } from "vitest";
|
||||
import { normalizeS3Path } from "@dokploy/server/utils/backups/utils";
|
||||
import { describe, expect, test } from "vitest";
|
||||
|
||||
describe("normalizeS3Path", () => {
|
||||
test("should handle empty and whitespace-only prefix", () => {
|
||||
|
||||
@@ -2,6 +2,7 @@ import { AlertBlock } from "@/components/shared/alert-block";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { Checkbox } from "@/components/ui/checkbox";
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
@@ -63,10 +64,11 @@ const mySchema = z.discriminatedUnion("buildType", [
|
||||
publishDirectory: z.string().optional(),
|
||||
}),
|
||||
z.object({
|
||||
buildType: z.literal(BuildType.static),
|
||||
buildType: z.literal(BuildType.railpack),
|
||||
}),
|
||||
z.object({
|
||||
buildType: z.literal(BuildType.railpack),
|
||||
buildType: z.literal(BuildType.static),
|
||||
isStaticSpa: z.boolean().default(false),
|
||||
}),
|
||||
]);
|
||||
|
||||
@@ -83,6 +85,7 @@ interface ApplicationData {
|
||||
dockerBuildStage?: string | null;
|
||||
herokuVersion?: string | null;
|
||||
publishDirectory?: string | null;
|
||||
isStaticSpa?: boolean | null;
|
||||
}
|
||||
|
||||
function isValidBuildType(value: string): value is BuildType {
|
||||
@@ -115,16 +118,18 @@ const resetData = (data: ApplicationData): AddTemplate => {
|
||||
case BuildType.static:
|
||||
return {
|
||||
buildType: BuildType.static,
|
||||
isStaticSpa: data.isStaticSpa ?? false,
|
||||
};
|
||||
case BuildType.railpack:
|
||||
return {
|
||||
buildType: BuildType.railpack,
|
||||
};
|
||||
default:
|
||||
default: {
|
||||
const buildType = data.buildType as BuildType;
|
||||
return {
|
||||
buildType,
|
||||
} as AddTemplate;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -174,6 +179,8 @@ export const ShowBuildChooseForm = ({ applicationId }: Props) => {
|
||||
data.buildType === BuildType.heroku_buildpacks
|
||||
? data.herokuVersion
|
||||
: null,
|
||||
isStaticSpa:
|
||||
data.buildType === BuildType.static ? data.isStaticSpa : null,
|
||||
})
|
||||
.then(async () => {
|
||||
toast.success("Build type saved");
|
||||
@@ -364,6 +371,30 @@ export const ShowBuildChooseForm = ({ applicationId }: Props) => {
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
{buildType === BuildType.static && (
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="isStaticSpa"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<div className="flex items-center gap-x-2 p-2">
|
||||
<Checkbox
|
||||
id="checkboxIsStaticSpa"
|
||||
value={String(field.value)}
|
||||
checked={field.value}
|
||||
onCheckedChange={field.onChange}
|
||||
/>
|
||||
<FormLabel htmlFor="checkboxIsStaticSpa">
|
||||
Single Page Application (SPA)
|
||||
</FormLabel>
|
||||
</div>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
<div className="flex w-full justify-end">
|
||||
<Button isLoading={isLoading} type="submit">
|
||||
Save
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { DateTooltip } from "@/components/shared/date-tooltip";
|
||||
import { StatusTooltip } from "@/components/shared/status-tooltip";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
Card,
|
||||
@@ -9,12 +10,11 @@ import {
|
||||
CardTitle,
|
||||
} from "@/components/ui/card";
|
||||
import { type RouterOutputs, api } from "@/utils/api";
|
||||
import { RocketIcon, Clock, Loader2 } from "lucide-react";
|
||||
import { Clock, Loader2, RocketIcon } from "lucide-react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { CancelQueues } from "./cancel-queues";
|
||||
import { RefreshToken } from "./refresh-token";
|
||||
import { ShowDeployment } from "./show-deployment";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
|
||||
interface Props {
|
||||
id: string;
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { AlertBlock } from "@/components/shared/alert-block";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
@@ -6,8 +8,6 @@ import {
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@/components/ui/dialog";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { AlertBlock } from "@/components/shared/alert-block";
|
||||
import { Copy, HelpCircle, Server } from "lucide-react";
|
||||
import { toast } from "sonner";
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { DialogAction } from "@/components/shared/dialog-action";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
Card,
|
||||
@@ -7,6 +8,12 @@ import {
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/components/ui/card";
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipProvider,
|
||||
TooltipTrigger,
|
||||
} from "@/components/ui/tooltip";
|
||||
import { api } from "@/utils/api";
|
||||
import {
|
||||
CheckCircle2,
|
||||
@@ -21,17 +28,10 @@ import {
|
||||
XCircle,
|
||||
} from "lucide-react";
|
||||
import Link from "next/link";
|
||||
import { toast } from "sonner";
|
||||
import { AddDomain } from "./handle-domain";
|
||||
import { useState } from "react";
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipProvider,
|
||||
TooltipTrigger,
|
||||
} from "@/components/ui/tooltip";
|
||||
import { toast } from "sonner";
|
||||
import { DnsHelperModal } from "./dns-helper-modal";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { AddDomain } from "./handle-domain";
|
||||
|
||||
export type ValidationState = {
|
||||
isLoading: boolean;
|
||||
|
||||
@@ -17,13 +17,13 @@ import {
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipProvider,
|
||||
TooltipTrigger,
|
||||
} from "@/components/ui/tooltip";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
import { api } from "@/utils/api";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { KeyRoundIcon, LockIcon, X } from "lucide-react";
|
||||
|
||||
@@ -24,9 +24,9 @@ import {
|
||||
} from "lucide-react";
|
||||
import { toast } from "sonner";
|
||||
import { ShowModalLogs } from "../../settings/web-server/show-modal-logs";
|
||||
import { ShowDeploymentsModal } from "../deployments/show-deployments-modal";
|
||||
import { AddPreviewDomain } from "./add-preview-domain";
|
||||
import { ShowPreviewSettings } from "./show-preview-settings";
|
||||
import { ShowDeploymentsModal } from "../deployments/show-deployments-modal";
|
||||
|
||||
interface Props {
|
||||
applicationId: string;
|
||||
|
||||
@@ -1,40 +1,6 @@
|
||||
import { AlertBlock } from "@/components/shared/alert-block";
|
||||
import { CodeEditor } from "@/components/shared/code-editor";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
FormDescription,
|
||||
} from "@/components/ui/form";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { api } from "@/utils/api";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { z } from "zod";
|
||||
import {
|
||||
Info,
|
||||
PlusCircle,
|
||||
PenBoxIcon,
|
||||
RefreshCw,
|
||||
DatabaseZap,
|
||||
} from "lucide-react";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipProvider,
|
||||
TooltipTrigger,
|
||||
} from "@/components/ui/tooltip";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
import { useEffect, useState } from "react";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
@@ -42,10 +8,44 @@ import {
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@/components/ui/dialog";
|
||||
import { toast } from "sonner";
|
||||
import { AlertBlock } from "@/components/shared/alert-block";
|
||||
import { CodeEditor } from "@/components/shared/code-editor";
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormDescription,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from "@/components/ui/form";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipProvider,
|
||||
TooltipTrigger,
|
||||
} from "@/components/ui/tooltip";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { api } from "@/utils/api";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import {
|
||||
DatabaseZap,
|
||||
Info,
|
||||
PenBoxIcon,
|
||||
PlusCircle,
|
||||
RefreshCw,
|
||||
} from "lucide-react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { toast } from "sonner";
|
||||
import { z } from "zod";
|
||||
import type { CacheType } from "../domains/handle-domain";
|
||||
|
||||
export const commonCronExpressions = [
|
||||
|
||||
@@ -1,14 +1,6 @@
|
||||
import { DialogAction } from "@/components/shared/dialog-action";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { api } from "@/utils/api";
|
||||
import { HandleSchedules } from "./handle-schedules";
|
||||
import {
|
||||
Clock,
|
||||
Play,
|
||||
Terminal,
|
||||
Trash2,
|
||||
ClipboardList,
|
||||
Loader2,
|
||||
} from "lucide-react";
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
@@ -16,16 +8,24 @@ import {
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/components/ui/card";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { toast } from "sonner";
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipProvider,
|
||||
TooltipTrigger,
|
||||
} from "@/components/ui/tooltip";
|
||||
import { DialogAction } from "@/components/shared/dialog-action";
|
||||
import { api } from "@/utils/api";
|
||||
import {
|
||||
ClipboardList,
|
||||
Clock,
|
||||
Loader2,
|
||||
Play,
|
||||
Terminal,
|
||||
Trash2,
|
||||
} from "lucide-react";
|
||||
import { toast } from "sonner";
|
||||
import { ShowDeploymentsModal } from "../deployments/show-deployments-modal";
|
||||
import { HandleSchedules } from "./handle-schedules";
|
||||
|
||||
interface Props {
|
||||
id: string;
|
||||
|
||||
@@ -39,6 +39,12 @@ import {
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipProvider,
|
||||
TooltipTrigger,
|
||||
} from "@/components/ui/tooltip";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { api } from "@/utils/api";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
@@ -48,9 +54,9 @@ import {
|
||||
CheckIcon,
|
||||
ChevronsUpDown,
|
||||
Copy,
|
||||
RotateCcw,
|
||||
RefreshCw,
|
||||
DatabaseZap,
|
||||
RefreshCw,
|
||||
RotateCcw,
|
||||
} from "lucide-react";
|
||||
import { useState } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
@@ -58,12 +64,6 @@ import { toast } from "sonner";
|
||||
import { z } from "zod";
|
||||
import type { ServiceType } from "../../application/advanced/show-resources";
|
||||
import { type LogLine, parseLogs } from "../../docker/logs/utils";
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipProvider,
|
||||
TooltipTrigger,
|
||||
} from "@/components/ui/tooltip";
|
||||
|
||||
type DatabaseType =
|
||||
| Exclude<ServiceType, "application" | "redis">
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
import {
|
||||
MariadbIcon,
|
||||
MongodbIcon,
|
||||
MysqlIcon,
|
||||
PostgresqlIcon,
|
||||
} from "@/components/icons/data-tools-icons";
|
||||
import { AlertBlock } from "@/components/shared/alert-block";
|
||||
import { DialogAction } from "@/components/shared/dialog-action";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
@@ -13,6 +20,7 @@ import {
|
||||
TooltipProvider,
|
||||
TooltipTrigger,
|
||||
} from "@/components/ui/tooltip";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { api } from "@/utils/api";
|
||||
import {
|
||||
ClipboardList,
|
||||
@@ -25,17 +33,9 @@ import Link from "next/link";
|
||||
import { useState } from "react";
|
||||
import { toast } from "sonner";
|
||||
import type { ServiceType } from "../../application/advanced/show-resources";
|
||||
import { RestoreBackup } from "./restore-backup";
|
||||
import { HandleBackup } from "./handle-backup";
|
||||
import { cn } from "@/lib/utils";
|
||||
import {
|
||||
MariadbIcon,
|
||||
MongodbIcon,
|
||||
MysqlIcon,
|
||||
PostgresqlIcon,
|
||||
} from "@/components/icons/data-tools-icons";
|
||||
import { AlertBlock } from "@/components/shared/alert-block";
|
||||
import { ShowDeploymentsModal } from "../../application/deployments/show-deployments-modal";
|
||||
import { HandleBackup } from "./handle-backup";
|
||||
import { RestoreBackup } from "./restore-backup";
|
||||
|
||||
interface Props {
|
||||
id: string;
|
||||
|
||||
@@ -1,24 +1,9 @@
|
||||
"use client";
|
||||
|
||||
import { authClient } from "@/lib/auth-client";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Logo } from "@/components/shared/logo";
|
||||
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
CheckIcon,
|
||||
ChevronsUpDown,
|
||||
Settings2,
|
||||
UserIcon,
|
||||
XIcon,
|
||||
Shield,
|
||||
Calendar,
|
||||
Key,
|
||||
Copy,
|
||||
Fingerprint,
|
||||
Building2,
|
||||
CreditCard,
|
||||
Server,
|
||||
} from "lucide-react";
|
||||
import { toast } from "sonner";
|
||||
import {
|
||||
Command,
|
||||
CommandEmpty,
|
||||
@@ -32,19 +17,34 @@ import {
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from "@/components/ui/popover";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { Logo } from "@/components/shared/logo";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipTrigger,
|
||||
TooltipProvider,
|
||||
TooltipTrigger,
|
||||
} from "@/components/ui/tooltip";
|
||||
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
|
||||
import { format } from "date-fns";
|
||||
import copy from "copy-to-clipboard";
|
||||
import { authClient } from "@/lib/auth-client";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { api } from "@/utils/api";
|
||||
import copy from "copy-to-clipboard";
|
||||
import { format } from "date-fns";
|
||||
import {
|
||||
Building2,
|
||||
Calendar,
|
||||
CheckIcon,
|
||||
ChevronsUpDown,
|
||||
Copy,
|
||||
CreditCard,
|
||||
Fingerprint,
|
||||
Key,
|
||||
Server,
|
||||
Settings2,
|
||||
Shield,
|
||||
UserIcon,
|
||||
XIcon,
|
||||
} from "lucide-react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { toast } from "sonner";
|
||||
|
||||
type User = typeof authClient.$Infer.Session.user;
|
||||
|
||||
|
||||
@@ -10,12 +10,12 @@ import {
|
||||
} from "@/components/ui/dialog";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
|
||||
import { api } from "@/utils/api";
|
||||
import { Copy, Loader2 } from "lucide-react";
|
||||
import { useRouter } from "next/router";
|
||||
import { useState } from "react";
|
||||
import { toast } from "sonner";
|
||||
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
|
||||
|
||||
export type Services = {
|
||||
appName: string;
|
||||
|
||||
@@ -18,6 +18,7 @@ import {
|
||||
} from "@/components/ui/form";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
import { generateSHA256Hash } from "@/lib/utils";
|
||||
import { api } from "@/utils/api";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
@@ -29,7 +30,6 @@ import { toast } from "sonner";
|
||||
import { z } from "zod";
|
||||
import { Disable2FA } from "./disable-2fa";
|
||||
import { Enable2FA } from "./enable-2fa";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
|
||||
const profileSchema = z.object({
|
||||
email: z.string(),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useState } from "react";
|
||||
import { ShowSchedules } from "@/components/dashboard/application/schedules/show-schedules";
|
||||
import { Dialog, DialogContent, DialogTrigger } from "@/components/ui/dialog";
|
||||
import { DropdownMenuItem } from "@/components/ui/dropdown-menu";
|
||||
import { ShowSchedules } from "@/components/dashboard/application/schedules/show-schedules";
|
||||
import { useState } from "react";
|
||||
|
||||
interface Props {
|
||||
serverId: string;
|
||||
|
||||
@@ -40,10 +40,10 @@ import { HandleServers } from "./handle-servers";
|
||||
import { SetupServer } from "./setup-server";
|
||||
import { ShowDockerContainersModal } from "./show-docker-containers-modal";
|
||||
import { ShowMonitoringModal } from "./show-monitoring-modal";
|
||||
import { ShowSchedulesModal } from "./show-schedules-modal";
|
||||
import { ShowSwarmOverviewModal } from "./show-swarm-overview-modal";
|
||||
import { ShowTraefikFileSystemModal } from "./show-traefik-file-system-modal";
|
||||
import { WelcomeSuscription } from "./welcome-stripe/welcome-suscription";
|
||||
import { ShowSchedulesModal } from "./show-schedules-modal";
|
||||
|
||||
export const ShowServers = () => {
|
||||
const { t } = useTranslation("settings");
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import Page from "./side";
|
||||
import { ImpersonationBar } from "../dashboard/impersonation/impersonation-bar";
|
||||
import { api } from "@/utils/api";
|
||||
import { ImpersonationBar } from "../dashboard/impersonation/impersonation-bar";
|
||||
import Page from "./side";
|
||||
import { ChatwootWidget } from "../shared/ChatwootWidget";
|
||||
|
||||
interface Props {
|
||||
children: React.ReactNode;
|
||||
@@ -9,10 +10,15 @@ interface Props {
|
||||
|
||||
export const DashboardLayout = ({ children }: Props) => {
|
||||
const { data: haveRootAccess } = api.user.haveRootAccess.useQuery();
|
||||
const { data: isCloud } = api.settings.isCloud.useQuery();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Page>{children}</Page>
|
||||
{isCloud === true && (
|
||||
<ChatwootWidget websiteToken="USCpQRKzHvFMssf3p6Eacae5" />
|
||||
)}
|
||||
|
||||
{haveRootAccess === true && <ImpersonationBar />}
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
import Page from "./side";
|
||||
|
||||
interface Props {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
export const ProjectLayout = ({ children }: Props) => {
|
||||
return <Page>{children}</Page>;
|
||||
};
|
||||
69
apps/dokploy/components/shared/ChatwootWidget.tsx
Normal file
69
apps/dokploy/components/shared/ChatwootWidget.tsx
Normal file
@@ -0,0 +1,69 @@
|
||||
import Script from "next/script";
|
||||
import { useEffect } from "react";
|
||||
|
||||
interface ChatwootWidgetProps {
|
||||
websiteToken: string;
|
||||
baseUrl?: string;
|
||||
settings?: {
|
||||
position?: "left" | "right";
|
||||
type?: "standard" | "expanded_bubble";
|
||||
launcherTitle?: string;
|
||||
darkMode?: boolean;
|
||||
hideMessageBubble?: boolean;
|
||||
placement?: "right" | "left";
|
||||
showPopoutButton?: boolean;
|
||||
widgetStyle?: "standard" | "bubble";
|
||||
};
|
||||
user?: {
|
||||
identifier: string;
|
||||
name?: string;
|
||||
email?: string;
|
||||
phoneNumber?: string;
|
||||
avatarUrl?: string;
|
||||
customAttributes?: Record<string, any>;
|
||||
identifierHash?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export const ChatwootWidget = ({
|
||||
websiteToken,
|
||||
baseUrl = "https://app.chatwoot.com",
|
||||
settings = {
|
||||
position: "right",
|
||||
type: "standard",
|
||||
launcherTitle: "Chat with us",
|
||||
},
|
||||
user,
|
||||
}: ChatwootWidgetProps) => {
|
||||
useEffect(() => {
|
||||
// Configurar los settings de Chatwoot
|
||||
window.chatwootSettings = {
|
||||
position: "right",
|
||||
};
|
||||
|
||||
(window as any).chatwootSDKReady = () => {
|
||||
window.chatwootSDK?.run({ websiteToken, baseUrl });
|
||||
|
||||
const trySetUser = () => {
|
||||
if (window.$chatwoot && user) {
|
||||
window.$chatwoot.setUser(user.identifier, {
|
||||
email: user.email,
|
||||
name: user.name,
|
||||
avatar_url: user.avatarUrl,
|
||||
phone_number: user.phoneNumber,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
trySetUser();
|
||||
};
|
||||
}, [websiteToken, baseUrl, user, settings]);
|
||||
|
||||
return (
|
||||
<Script
|
||||
src={`${baseUrl}/packs/js/sdk.js`}
|
||||
strategy="lazyOnload"
|
||||
onLoad={() => (window as any).chatwootSDKReady?.()}
|
||||
/>
|
||||
);
|
||||
};
|
||||
1
apps/dokploy/drizzle/0092_stiff_the_watchers.sql
Normal file
1
apps/dokploy/drizzle/0092_stiff_the_watchers.sql
Normal file
@@ -0,0 +1 @@
|
||||
ALTER TABLE "application" ADD COLUMN "isStaticSpa" boolean;
|
||||
5717
apps/dokploy/drizzle/meta/0092_snapshot.json
Normal file
5717
apps/dokploy/drizzle/meta/0092_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -645,6 +645,13 @@
|
||||
"when": 1746518402168,
|
||||
"tag": "0091_spotty_kulan_gath",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 92,
|
||||
"version": "7",
|
||||
"when": 1747713229160,
|
||||
"tag": "0092_stiff_the_watchers",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "dokploy",
|
||||
"version": "v0.22.6",
|
||||
"version": "v0.22.7",
|
||||
"private": true,
|
||||
"license": "Apache-2.0",
|
||||
"type": "module",
|
||||
@@ -36,6 +36,8 @@
|
||||
"test": "vitest --config __test__/vitest.config.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"pino": "9.4.0",
|
||||
"pino-pretty": "11.2.2",
|
||||
"@ai-sdk/anthropic": "^1.0.6",
|
||||
"@ai-sdk/azure": "^1.0.15",
|
||||
"@ai-sdk/cohere": "^1.0.6",
|
||||
@@ -186,7 +188,7 @@
|
||||
},
|
||||
"packageManager": "pnpm@9.5.0",
|
||||
"engines": {
|
||||
"node": "^20.9.0",
|
||||
"node": "^20.16.0",
|
||||
"pnpm": ">=9.5.0"
|
||||
},
|
||||
"lint-staged": {
|
||||
|
||||
@@ -17,7 +17,6 @@ const inter = Inter({ subsets: ["latin"] });
|
||||
|
||||
export type NextPageWithLayout<P = {}, IP = P> = NextPage<P, IP> & {
|
||||
getLayout?: (page: ReactElement) => ReactNode;
|
||||
// session: Session | null;
|
||||
theme?: string;
|
||||
};
|
||||
|
||||
@@ -33,11 +32,13 @@ const MyApp = ({
|
||||
|
||||
return (
|
||||
<>
|
||||
<style jsx global>{`
|
||||
:root {
|
||||
--font-inter: ${inter.style.fontFamily};
|
||||
}
|
||||
`}</style>
|
||||
<style jsx global>
|
||||
{`
|
||||
:root {
|
||||
--font-inter: ${inter.style.fontFamily};
|
||||
}
|
||||
`}
|
||||
</style>
|
||||
<Head>
|
||||
<title>Dokploy</title>
|
||||
</Head>
|
||||
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
PostgresqlIcon,
|
||||
RedisIcon,
|
||||
} from "@/components/icons/data-tools-icons";
|
||||
import { ProjectLayout } from "@/components/layouts/project-layout";
|
||||
import { DashboardLayout } from "@/components/layouts/dashboard-layout";
|
||||
import { BreadcrumbSidebar } from "@/components/shared/breadcrumb-sidebar";
|
||||
import { DateTooltip } from "@/components/shared/date-tooltip";
|
||||
import { DialogAction } from "@/components/shared/dialog-action";
|
||||
@@ -18,6 +18,7 @@ import { StatusTooltip } from "@/components/shared/status-tooltip";
|
||||
import { Button } from "@/components/ui/button";
|
||||
|
||||
import { AddAiAssistant } from "@/components/dashboard/project/add-ai-assistant";
|
||||
import { DuplicateProject } from "@/components/dashboard/project/duplicate-project";
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
@@ -93,7 +94,6 @@ import { useRouter } from "next/router";
|
||||
import { type ReactElement, useEffect, useMemo, useState } from "react";
|
||||
import { toast } from "sonner";
|
||||
import superjson from "superjson";
|
||||
import { DuplicateProject } from "@/components/dashboard/project/duplicate-project";
|
||||
|
||||
export type Services = {
|
||||
appName: string;
|
||||
@@ -1064,7 +1064,7 @@ const Project = (
|
||||
|
||||
export default Project;
|
||||
Project.getLayout = (page: ReactElement) => {
|
||||
return <ProjectLayout>{page}</ProjectLayout>;
|
||||
return <DashboardLayout>{page}</DashboardLayout>;
|
||||
};
|
||||
|
||||
export async function getServerSideProps(
|
||||
|
||||
@@ -17,7 +17,7 @@ import { UpdateApplication } from "@/components/dashboard/application/update-app
|
||||
import { DeleteService } from "@/components/dashboard/compose/delete-service";
|
||||
import { ContainerFreeMonitoring } from "@/components/dashboard/monitoring/free/container/show-free-container-monitoring";
|
||||
import { ContainerPaidMonitoring } from "@/components/dashboard/monitoring/paid/container/show-paid-container-monitoring";
|
||||
import { ProjectLayout } from "@/components/layouts/project-layout";
|
||||
import { DashboardLayout } from "@/components/layouts/dashboard-layout";
|
||||
import { BreadcrumbSidebar } from "@/components/shared/breadcrumb-sidebar";
|
||||
import { StatusTooltip } from "@/components/shared/status-tooltip";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
@@ -363,7 +363,7 @@ const Service = (
|
||||
|
||||
export default Service;
|
||||
Service.getLayout = (page: ReactElement) => {
|
||||
return <ProjectLayout>{page}</ProjectLayout>;
|
||||
return <DashboardLayout>{page}</DashboardLayout>;
|
||||
};
|
||||
|
||||
export async function getServerSideProps(
|
||||
|
||||
@@ -13,7 +13,7 @@ import { UpdateCompose } from "@/components/dashboard/compose/update-compose";
|
||||
import { ShowBackups } from "@/components/dashboard/database/backups/show-backups";
|
||||
import { ComposeFreeMonitoring } from "@/components/dashboard/monitoring/free/container/show-free-compose-monitoring";
|
||||
import { ComposePaidMonitoring } from "@/components/dashboard/monitoring/paid/container/show-paid-compose-monitoring";
|
||||
import { ProjectLayout } from "@/components/layouts/project-layout";
|
||||
import { DashboardLayout } from "@/components/layouts/dashboard-layout";
|
||||
import { BreadcrumbSidebar } from "@/components/shared/breadcrumb-sidebar";
|
||||
import { StatusTooltip } from "@/components/shared/status-tooltip";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
@@ -366,7 +366,7 @@ const Service = (
|
||||
|
||||
export default Service;
|
||||
Service.getLayout = (page: ReactElement) => {
|
||||
return <ProjectLayout>{page}</ProjectLayout>;
|
||||
return <DashboardLayout>{page}</DashboardLayout>;
|
||||
};
|
||||
|
||||
export async function getServerSideProps(
|
||||
|
||||
@@ -10,7 +10,7 @@ import { ContainerFreeMonitoring } from "@/components/dashboard/monitoring/free/
|
||||
import { ContainerPaidMonitoring } from "@/components/dashboard/monitoring/paid/container/show-paid-container-monitoring";
|
||||
import { ShowDatabaseAdvancedSettings } from "@/components/dashboard/shared/show-database-advanced-settings";
|
||||
import { MariadbIcon } from "@/components/icons/data-tools-icons";
|
||||
import { ProjectLayout } from "@/components/layouts/project-layout";
|
||||
import { DashboardLayout } from "@/components/layouts/dashboard-layout";
|
||||
import { BreadcrumbSidebar } from "@/components/shared/breadcrumb-sidebar";
|
||||
import { StatusTooltip } from "@/components/shared/status-tooltip";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
@@ -294,7 +294,7 @@ const Mariadb = (
|
||||
|
||||
export default Mariadb;
|
||||
Mariadb.getLayout = (page: ReactElement) => {
|
||||
return <ProjectLayout>{page}</ProjectLayout>;
|
||||
return <DashboardLayout>{page}</DashboardLayout>;
|
||||
};
|
||||
|
||||
export async function getServerSideProps(
|
||||
|
||||
@@ -10,7 +10,7 @@ import { ContainerFreeMonitoring } from "@/components/dashboard/monitoring/free/
|
||||
import { ContainerPaidMonitoring } from "@/components/dashboard/monitoring/paid/container/show-paid-container-monitoring";
|
||||
import { ShowDatabaseAdvancedSettings } from "@/components/dashboard/shared/show-database-advanced-settings";
|
||||
import { MongodbIcon } from "@/components/icons/data-tools-icons";
|
||||
import { ProjectLayout } from "@/components/layouts/project-layout";
|
||||
import { DashboardLayout } from "@/components/layouts/dashboard-layout";
|
||||
import { BreadcrumbSidebar } from "@/components/shared/breadcrumb-sidebar";
|
||||
import { StatusTooltip } from "@/components/shared/status-tooltip";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
@@ -296,7 +296,7 @@ const Mongo = (
|
||||
|
||||
export default Mongo;
|
||||
Mongo.getLayout = (page: ReactElement) => {
|
||||
return <ProjectLayout>{page}</ProjectLayout>;
|
||||
return <DashboardLayout>{page}</DashboardLayout>;
|
||||
};
|
||||
|
||||
export async function getServerSideProps(
|
||||
|
||||
@@ -10,7 +10,7 @@ import { ShowInternalMysqlCredentials } from "@/components/dashboard/mysql/gener
|
||||
import { UpdateMysql } from "@/components/dashboard/mysql/update-mysql";
|
||||
import { ShowDatabaseAdvancedSettings } from "@/components/dashboard/shared/show-database-advanced-settings";
|
||||
import { MysqlIcon } from "@/components/icons/data-tools-icons";
|
||||
import { ProjectLayout } from "@/components/layouts/project-layout";
|
||||
import { DashboardLayout } from "@/components/layouts/dashboard-layout";
|
||||
import { BreadcrumbSidebar } from "@/components/shared/breadcrumb-sidebar";
|
||||
import { StatusTooltip } from "@/components/shared/status-tooltip";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
@@ -280,7 +280,7 @@ const MySql = (
|
||||
|
||||
export default MySql;
|
||||
MySql.getLayout = (page: ReactElement) => {
|
||||
return <ProjectLayout>{page}</ProjectLayout>;
|
||||
return <DashboardLayout>{page}</DashboardLayout>;
|
||||
};
|
||||
|
||||
export async function getServerSideProps(
|
||||
|
||||
@@ -10,7 +10,7 @@ import { ShowInternalPostgresCredentials } from "@/components/dashboard/postgres
|
||||
import { UpdatePostgres } from "@/components/dashboard/postgres/update-postgres";
|
||||
import { ShowDatabaseAdvancedSettings } from "@/components/dashboard/shared/show-database-advanced-settings";
|
||||
import { PostgresqlIcon } from "@/components/icons/data-tools-icons";
|
||||
import { ProjectLayout } from "@/components/layouts/project-layout";
|
||||
import { DashboardLayout } from "@/components/layouts/dashboard-layout";
|
||||
import { BreadcrumbSidebar } from "@/components/shared/breadcrumb-sidebar";
|
||||
import { StatusTooltip } from "@/components/shared/status-tooltip";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
@@ -278,7 +278,7 @@ const Postgresql = (
|
||||
|
||||
export default Postgresql;
|
||||
Postgresql.getLayout = (page: ReactElement) => {
|
||||
return <ProjectLayout>{page}</ProjectLayout>;
|
||||
return <DashboardLayout>{page}</DashboardLayout>;
|
||||
};
|
||||
|
||||
export async function getServerSideProps(
|
||||
|
||||
@@ -9,7 +9,7 @@ import { ShowInternalRedisCredentials } from "@/components/dashboard/redis/gener
|
||||
import { UpdateRedis } from "@/components/dashboard/redis/update-redis";
|
||||
import { ShowDatabaseAdvancedSettings } from "@/components/dashboard/shared/show-database-advanced-settings";
|
||||
import { RedisIcon } from "@/components/icons/data-tools-icons";
|
||||
import { ProjectLayout } from "@/components/layouts/project-layout";
|
||||
import { DashboardLayout } from "@/components/layouts/dashboard-layout";
|
||||
import { BreadcrumbSidebar } from "@/components/shared/breadcrumb-sidebar";
|
||||
import { StatusTooltip } from "@/components/shared/status-tooltip";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
@@ -285,7 +285,7 @@ const Redis = (
|
||||
|
||||
export default Redis;
|
||||
Redis.getLayout = (page: ReactElement) => {
|
||||
return <ProjectLayout>{page}</ProjectLayout>;
|
||||
return <DashboardLayout>{page}</DashboardLayout>;
|
||||
};
|
||||
|
||||
export async function getServerSideProps(
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { DashboardLayout } from "@/components/layouts/dashboard-layout";
|
||||
import type { ReactElement } from "react";
|
||||
import type { GetServerSidePropsContext } from "next";
|
||||
import { validateRequest } from "@dokploy/server/lib/auth";
|
||||
import { IS_CLOUD } from "@dokploy/server/constants";
|
||||
import { api } from "@/utils/api";
|
||||
import { ShowSchedules } from "@/components/dashboard/application/schedules/show-schedules";
|
||||
import { DashboardLayout } from "@/components/layouts/dashboard-layout";
|
||||
import { Card } from "@/components/ui/card";
|
||||
import { api } from "@/utils/api";
|
||||
import { IS_CLOUD } from "@dokploy/server/constants";
|
||||
import { validateRequest } from "@dokploy/server/lib/auth";
|
||||
import type { GetServerSidePropsContext } from "next";
|
||||
import type { ReactElement } from "react";
|
||||
function SchedulesPage() {
|
||||
const { data: user } = api.user.get.useQuery();
|
||||
return (
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import { ShowBackups } from "@/components/dashboard/database/backups/show-backups";
|
||||
import { WebDomain } from "@/components/dashboard/settings/web-domain";
|
||||
import { WebServer } from "@/components/dashboard/settings/web-server";
|
||||
import { DashboardLayout } from "@/components/layouts/dashboard-layout";
|
||||
import { Card } from "@/components/ui/card";
|
||||
import { appRouter } from "@/server/api/root";
|
||||
import { api } from "@/utils/api";
|
||||
import { getLocale, serverSideTranslations } from "@/utils/i18n";
|
||||
import { IS_CLOUD, validateRequest } from "@dokploy/server";
|
||||
import { createServerSideHelpers } from "@trpc/react-query/server";
|
||||
import type { GetServerSidePropsContext } from "next";
|
||||
import type { ReactElement } from "react";
|
||||
import superjson from "superjson";
|
||||
import { api } from "@/utils/api";
|
||||
import { ShowBackups } from "@/components/dashboard/database/backups/show-backups";
|
||||
import { Card } from "@/components/ui/card";
|
||||
const Page = () => {
|
||||
const { data: user } = api.user.get.useQuery();
|
||||
return (
|
||||
|
||||
@@ -28,6 +28,7 @@ import { projectRouter } from "./routers/project";
|
||||
import { redirectsRouter } from "./routers/redirects";
|
||||
import { redisRouter } from "./routers/redis";
|
||||
import { registryRouter } from "./routers/registry";
|
||||
import { scheduleRouter } from "./routers/schedule";
|
||||
import { securityRouter } from "./routers/security";
|
||||
import { serverRouter } from "./routers/server";
|
||||
import { settingsRouter } from "./routers/settings";
|
||||
@@ -35,7 +36,6 @@ import { sshRouter } from "./routers/ssh-key";
|
||||
import { stripeRouter } from "./routers/stripe";
|
||||
import { swarmRouter } from "./routers/swarm";
|
||||
import { userRouter } from "./routers/user";
|
||||
import { scheduleRouter } from "./routers/schedule";
|
||||
/**
|
||||
* This is the primary router for your server.
|
||||
*
|
||||
|
||||
@@ -330,6 +330,7 @@ export const applicationRouter = createTRPCRouter({
|
||||
dockerContextPath: input.dockerContextPath,
|
||||
dockerBuildStage: input.dockerBuildStage,
|
||||
herokuVersion: input.herokuVersion,
|
||||
isStaticSpa: input.isStaticSpa,
|
||||
});
|
||||
|
||||
return true;
|
||||
|
||||
@@ -51,9 +51,9 @@ import { processTemplate } from "@dokploy/server/templates/processors";
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import { eq } from "drizzle-orm";
|
||||
import { dump } from "js-yaml";
|
||||
import { parse } from "toml";
|
||||
import _ from "lodash";
|
||||
import { nanoid } from "nanoid";
|
||||
import { parse } from "toml";
|
||||
import { z } from "zod";
|
||||
import { createTRPCRouter, protectedProcedure, publicProcedure } from "../trpc";
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { db } from "@/server/db";
|
||||
import {
|
||||
apiFindAllByApplication,
|
||||
apiFindAllByCompose,
|
||||
@@ -16,7 +17,6 @@ import {
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import { desc, eq } from "drizzle-orm";
|
||||
import { createTRPCRouter, protectedProcedure } from "../trpc";
|
||||
import { db } from "@/server/db";
|
||||
|
||||
export const deploymentRouter = createTRPCRouter({
|
||||
all: protectedProcedure
|
||||
|
||||
@@ -21,32 +21,32 @@ import {
|
||||
addNewProject,
|
||||
checkProjectAccess,
|
||||
createApplication,
|
||||
createBackup,
|
||||
createCompose,
|
||||
createDomain,
|
||||
createMariadb,
|
||||
createMongo,
|
||||
createMount,
|
||||
createMysql,
|
||||
createPort,
|
||||
createPostgres,
|
||||
createPreviewDeployment,
|
||||
createProject,
|
||||
createRedirect,
|
||||
createRedis,
|
||||
createSecurity,
|
||||
deleteProject,
|
||||
findApplicationById,
|
||||
findComposeById,
|
||||
findMongoById,
|
||||
findMariadbById,
|
||||
findMemberById,
|
||||
findRedisById,
|
||||
findMongoById,
|
||||
findMySqlById,
|
||||
findPostgresById,
|
||||
findProjectById,
|
||||
findRedisById,
|
||||
findUserById,
|
||||
updateProjectById,
|
||||
findPostgresById,
|
||||
findMariadbById,
|
||||
findMySqlById,
|
||||
createDomain,
|
||||
createPort,
|
||||
createMount,
|
||||
createRedirect,
|
||||
createPreviewDeployment,
|
||||
createBackup,
|
||||
createSecurity,
|
||||
} from "@dokploy/server";
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import { and, desc, eq, sql } from "drizzle-orm";
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import { z } from "zod";
|
||||
import { removeJob, schedule } from "@/server/utils/backup";
|
||||
import { IS_CLOUD, scheduleJob } from "@dokploy/server";
|
||||
import { removeScheduleJob } from "@dokploy/server";
|
||||
import { db } from "@dokploy/server/db";
|
||||
import { deployments } from "@dokploy/server/db/schema/deployment";
|
||||
import {
|
||||
createScheduleSchema,
|
||||
schedules,
|
||||
updateScheduleSchema,
|
||||
} from "@dokploy/server/db/schema/schedule";
|
||||
import { desc, eq } from "drizzle-orm";
|
||||
import { db } from "@dokploy/server/db";
|
||||
import { createTRPCRouter, protectedProcedure } from "../trpc";
|
||||
import { runCommand } from "@dokploy/server/index";
|
||||
import { deployments } from "@dokploy/server/db/schema/deployment";
|
||||
import {
|
||||
createSchedule,
|
||||
deleteSchedule,
|
||||
findScheduleById,
|
||||
createSchedule,
|
||||
updateSchedule,
|
||||
} from "@dokploy/server/services/schedule";
|
||||
import { IS_CLOUD, scheduleJob } from "@dokploy/server";
|
||||
import { removeJob, schedule } from "@/server/utils/backup";
|
||||
import { removeScheduleJob } from "@dokploy/server";
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import { desc, eq } from "drizzle-orm";
|
||||
import { z } from "zod";
|
||||
import { createTRPCRouter, protectedProcedure } from "../trpc";
|
||||
export const scheduleRouter = createTRPCRouter({
|
||||
create: protectedProcedure
|
||||
.input(createScheduleSchema)
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import type http from "node:http";
|
||||
import { validateRequest } from "@dokploy/server/lib/auth";
|
||||
import { applyWSSHandler } from "@trpc/server/adapters/ws";
|
||||
import { WebSocketServer } from "ws";
|
||||
import { appRouter } from "../api/root";
|
||||
import { createTRPCContext } from "../api/trpc";
|
||||
import { validateRequest } from "@dokploy/server/lib/auth";
|
||||
|
||||
export const setupDrawerLogsWebSocketServer = (
|
||||
server: http.Server<typeof http.IncomingMessage, typeof http.ServerResponse>,
|
||||
|
||||
39
apps/dokploy/types/chatwoot.d.ts
vendored
Normal file
39
apps/dokploy/types/chatwoot.d.ts
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
declare global {
|
||||
interface Window {
|
||||
chatwootSettings?: {
|
||||
hideMessageBubble?: boolean;
|
||||
showUnreadMessagesDialog?: boolean;
|
||||
position?: "left" | "right";
|
||||
locale?: string;
|
||||
useBrowserLanguage?: boolean;
|
||||
type?: "standard" | "expanded_bubble";
|
||||
darkMode?: "light" | "auto";
|
||||
launcherTitle?: string;
|
||||
showPopoutButton?: boolean;
|
||||
baseDomain?: string;
|
||||
};
|
||||
chatwootSDK?: {
|
||||
run: (config: {
|
||||
websiteToken: string;
|
||||
baseUrl: string;
|
||||
}) => void;
|
||||
};
|
||||
$chatwoot?: {
|
||||
setUser: (
|
||||
identifier: string,
|
||||
userAttributes: Record<string, any>,
|
||||
) => void;
|
||||
setCustomAttributes: (attributes: Record<string, any>) => void;
|
||||
reset: () => void;
|
||||
toggle: (state?: "open" | "close") => void;
|
||||
popoutChatWindow: () => void;
|
||||
toggleBubbleVisibility: (visibility: "show" | "hide") => void;
|
||||
setLocale: (locale: string) => void;
|
||||
setLabel: (label: string) => void;
|
||||
removeLabel: (label: string) => void;
|
||||
};
|
||||
chatwootSDKReady?: () => void;
|
||||
}
|
||||
}
|
||||
|
||||
export {};
|
||||
@@ -7,11 +7,11 @@ import {
|
||||
findServerById,
|
||||
keepLatestNBackups,
|
||||
runCommand,
|
||||
runComposeBackup,
|
||||
runMariadbBackup,
|
||||
runMongoBackup,
|
||||
runMySqlBackup,
|
||||
runPostgresBackup,
|
||||
runComposeBackup,
|
||||
} from "@dokploy/server";
|
||||
import { db } from "@dokploy/server/dist/db";
|
||||
import { backups, schedules, server } from "@dokploy/server/dist/db/schema";
|
||||
|
||||
Reference in New Issue
Block a user